diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index e6887075b2..b8715335d9 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -23,6 +23,12 @@ references = ["smithy-rs#2904"] meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client" } author = "jdisanti" +[[smithy-rs]] +message = "It's now possible to nest runtime components with the `RuntimePlugin` trait. A `current_components` argument was added to the `runtime_components` method so that components configured from previous runtime plugins can be referenced in the current runtime plugin. Ordering of runtime plugins was also introduced via a new `RuntimePlugin::order` method." +references = ["smithy-rs#2909"] +meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "client"} +author = "jdisanti" + [[smithy-rs]] message = "Fix incorrect summary docs for builders" references = ["smithy-rs#2914", "aws-sdk-rust#825"] diff --git a/aws/rust-runtime/aws-inlineable/src/presigning_interceptors.rs b/aws/rust-runtime/aws-inlineable/src/presigning_interceptors.rs index 3ded9fcd68..7a477925f0 100644 --- a/aws/rust-runtime/aws-inlineable/src/presigning_interceptors.rs +++ b/aws/rust-runtime/aws-inlineable/src/presigning_interceptors.rs @@ -118,7 +118,10 @@ impl RuntimePlugin for SigV4PresigningRuntimePlugin { Some(layer.freeze()) } - fn runtime_components(&self) -> Cow<'_, RuntimeComponentsBuilder> { + fn runtime_components( + &self, + _: &RuntimeComponentsBuilder, + ) -> Cow<'_, RuntimeComponentsBuilder> { Cow::Borrowed(&self.runtime_components) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGenerator.kt index 0e595065f9..6dfd83c5b3 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGenerator.kt @@ -73,7 +73,7 @@ class ConfigOverrideRuntimePluginGenerator( Some(self.config.clone()) } - fn runtime_components(&self) -> #{Cow}<'_, #{RuntimeComponentsBuilder}> { + fn runtime_components(&self, _: &#{RuntimeComponentsBuilder}) -> #{Cow}<'_, #{RuntimeComponentsBuilder}> { #{Cow}::Borrowed(&self.components) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationRuntimePluginGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationRuntimePluginGenerator.kt index 73d6756072..d76f083eef 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationRuntimePluginGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationRuntimePluginGenerator.kt @@ -76,7 +76,7 @@ class OperationRuntimePluginGenerator( #{Some}(cfg.freeze()) } - fn runtime_components(&self) -> #{Cow}<'_, #{RuntimeComponentsBuilder}> { + fn runtime_components(&self, _: &#{RuntimeComponentsBuilder}) -> #{Cow}<'_, #{RuntimeComponentsBuilder}> { // Retry classifiers are operation-specific because they need to downcast operation-specific error types. let retry_classifiers = #{RetryClassifiers}::new() #{retry_classifier_customizations}; diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt index 86a2d4d63d..555ea7e035 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt @@ -121,7 +121,7 @@ class ServiceRuntimePluginGenerator( self.config.clone() } - fn runtime_components(&self) -> #{Cow}<'_, #{RuntimeComponentsBuilder}> { + fn runtime_components(&self, _: &#{RuntimeComponentsBuilder}) -> #{Cow}<'_, #{RuntimeComponentsBuilder}> { #{Cow}::Borrowed(&self.runtime_components) } } diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGeneratorTest.kt index 671f622497..9534f7a79e 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGeneratorTest.kt @@ -44,6 +44,7 @@ internal class ConfigOverrideRuntimePluginGeneratorTest { "EndpointResolverParams" to RuntimeType.smithyRuntimeApi(runtimeConfig) .resolve("client::endpoint::EndpointResolverParams"), "RuntimePlugin" to RuntimeType.runtimePlugin(runtimeConfig), + "RuntimeComponentsBuilder" to RuntimeType.runtimeComponentsBuilder(runtimeConfig), ) rustCrate.testModule { addDependency(CargoDependency.Tokio.toDevDependency().withFeature("test-util")) @@ -62,7 +63,8 @@ internal class ConfigOverrideRuntimePluginGeneratorTest { client_config.config, &client_config.runtime_components, ); - let sut_components = sut.runtime_components(); + let prev = #{RuntimeComponentsBuilder}::new("prev"); + let sut_components = sut.runtime_components(&prev); let endpoint_resolver = sut_components.endpoint_resolver().unwrap(); let endpoint = endpoint_resolver .resolve_endpoint(&#{EndpointResolverParams}::new(crate::config::endpoint::Params {})) diff --git a/rust-runtime/aws-smithy-runtime-api/Cargo.toml b/rust-runtime/aws-smithy-runtime-api/Cargo.toml index 426c449ccc..e9b4c0bc61 100644 --- a/rust-runtime/aws-smithy-runtime-api/Cargo.toml +++ b/rust-runtime/aws-smithy-runtime-api/Cargo.toml @@ -25,6 +25,9 @@ tokio = { version = "1.25", features = ["sync"] } tracing = "0.1" zeroize = { version = "1", optional = true } +[dev-dependencies] +tokio = { version = "1.25", features = ["rt", "macros"] } + [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_plugin.rs b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_plugin.rs index abc687ca66..b41a0048a3 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_plugin.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_plugin.rs @@ -27,12 +27,52 @@ use std::borrow::Cow; use std::fmt::Debug; use std::sync::Arc; +/// Runtime plugin ordering. +/// +/// There are two runtime plugin "levels" that run in the following order: +/// 1. Service runtime plugins - runtime plugins that pertain to the entire service. +/// 2. Operation runtime plugins - runtime plugins relevant only to a single operation. +/// +/// This enum is used to determine runtime plugin order within those levels. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub enum Order { + /// Runtime plugins with `Defaults` order are executed first within their level. + /// + /// Runtime plugins with this order should only be used for registering default components and config. + Defaults, + + /// Runtime plugins with `Overrides` order are executed after `Defaults` within their level. + /// + /// This is the default order. + Overrides, + + /// Runtime plugins with `NestedComponents` order are executed after `Overrides` within their level. + /// + /// This level is intended to be used for wrapping components configured in previous runtime plugins. + NestedComponents, +} + /// Runtime plugin trait /// /// A `RuntimePlugin` is the unit of configuration for augmenting the SDK with new behavior. /// /// Runtime plugins can register interceptors, set runtime components, and modify configuration. pub trait RuntimePlugin: Debug + Send + Sync { + /// Runtime plugin ordering. + /// + /// There are two runtime plugin "levels" that run in the following order: + /// 1. Service runtime plugins - runtime plugins that pertain to the entire service. + /// 2. Operation runtime plugins - runtime plugins relevant only to a single operation. + /// + /// This function is used to determine runtime plugin order within those levels. So + /// regardless of this `Order` value, service runtime plugins will still always execute before + /// operation runtime plugins. However, [`Defaults`](Order::Defaults) + /// service runtime plugins will run before [`Overrides`](Order::Overrides) + /// service runtime plugins. + fn order(&self) -> Order { + Order::Overrides + } + /// Optionally returns additional config that should be added to the [`ConfigBag`](aws_smithy_types::config_bag::ConfigBag). /// /// As a best practice, a frozen layer should be stored on the runtime plugin instance as @@ -52,7 +92,14 @@ pub trait RuntimePlugin: Debug + Send + Sync { /// This method returns a [`Cow`] for flexibility. Some implementers may want to store the components builder /// as a member and return a reference to it, while others may need to create the builder every call. If possible, /// returning a reference is preferred for performance. - fn runtime_components(&self) -> Cow<'_, RuntimeComponentsBuilder> { + /// + /// Components configured by previous runtime plugins are in the `current_components` argument, and can be used + /// to create nested/wrapped components, such as a connector calling into an inner (customer provided) connector. + fn runtime_components( + &self, + current_components: &RuntimeComponentsBuilder, + ) -> Cow<'_, RuntimeComponentsBuilder> { + let _ = current_components; Cow::Borrowed(&EMPTY_RUNTIME_COMPONENTS_BUILDER) } } @@ -71,12 +118,19 @@ impl SharedRuntimePlugin { } impl RuntimePlugin for SharedRuntimePlugin { + fn order(&self) -> Order { + self.0.order() + } + fn config(&self) -> Option { self.0.config() } - fn runtime_components(&self) -> Cow<'_, RuntimeComponentsBuilder> { - self.0.runtime_components() + fn runtime_components( + &self, + current_components: &RuntimeComponentsBuilder, + ) -> Cow<'_, RuntimeComponentsBuilder> { + self.0.runtime_components(current_components) } } @@ -111,14 +165,50 @@ impl RuntimePlugin for StaticRuntimePlugin { self.config.clone() } - fn runtime_components(&self) -> Cow<'_, RuntimeComponentsBuilder> { + fn runtime_components( + &self, + _current_components: &RuntimeComponentsBuilder, + ) -> Cow<'_, RuntimeComponentsBuilder> { self.runtime_components .as_ref() .map(Cow::Borrowed) - .unwrap_or_else(|| RuntimePlugin::runtime_components(self)) + .unwrap_or_else(|| RuntimePlugin::runtime_components(self, _current_components)) } } +macro_rules! insert_plugin { + ($vec:expr, $plugin:ident, $create_rp:expr) => {{ + // Insert the plugin in the correct order + let mut insert_index = 0; + let order = $plugin.order(); + for (index, other_plugin) in $vec.iter().enumerate() { + let other_order = other_plugin.order(); + if other_order <= order { + insert_index = index + 1; + } else if other_order > order { + break; + } + } + $vec.insert(insert_index, $create_rp); + }}; +} + +macro_rules! apply_plugins { + ($name:ident, $plugins:expr, $cfg:ident) => {{ + tracing::trace!(concat!("applying ", stringify!($name), " runtime plugins")); + let mut merged = + RuntimeComponentsBuilder::new(concat!("apply_", stringify!($name), "_configuration")); + for plugin in &$plugins { + if let Some(layer) = plugin.config() { + $cfg.push_shared_layer(layer); + } + let next = plugin.runtime_components(&merged); + merged = merged.merge_from(&next); + } + Ok(merged) + }}; +} + /// Used internally in the orchestrator implementation and in the generated code. Not intended to be used elsewhere. #[doc(hidden)] #[derive(Default, Clone, Debug)] @@ -133,13 +223,20 @@ impl RuntimePlugins { } pub fn with_client_plugin(mut self, plugin: impl RuntimePlugin + 'static) -> Self { - self.client_plugins.push(SharedRuntimePlugin::new(plugin)); + insert_plugin!( + self.client_plugins, + plugin, + SharedRuntimePlugin::new(plugin) + ); self } pub fn with_operation_plugin(mut self, plugin: impl RuntimePlugin + 'static) -> Self { - self.operation_plugins - .push(SharedRuntimePlugin::new(plugin)); + insert_plugin!( + self.operation_plugins, + plugin, + SharedRuntimePlugin::new(plugin) + ); self } @@ -147,36 +244,28 @@ impl RuntimePlugins { &self, cfg: &mut ConfigBag, ) -> Result { - tracing::trace!("applying client runtime plugins"); - let mut builder = RuntimeComponentsBuilder::new("apply_client_configuration"); - for plugin in self.client_plugins.iter() { - if let Some(layer) = plugin.config() { - cfg.push_shared_layer(layer); - } - builder = builder.merge_from(&plugin.runtime_components()); - } - Ok(builder) + apply_plugins!(client, self.client_plugins, cfg) } pub fn apply_operation_configuration( &self, cfg: &mut ConfigBag, ) -> Result { - tracing::trace!("applying operation runtime plugins"); - let mut builder = RuntimeComponentsBuilder::new("apply_operation_configuration"); - for plugin in self.operation_plugins.iter() { - if let Some(layer) = plugin.config() { - cfg.push_shared_layer(layer); - } - builder = builder.merge_from(&plugin.runtime_components()); - } - Ok(builder) + apply_plugins!(operation, self.operation_plugins, cfg) } } #[cfg(test)] mod tests { use super::{RuntimePlugin, RuntimePlugins}; + use crate::client::connectors::{HttpConnector, SharedHttpConnector}; + use crate::client::orchestrator::{BoxFuture, HttpRequest, HttpResponse}; + use crate::client::runtime_components::RuntimeComponentsBuilder; + use crate::client::runtime_plugin::Order; + use aws_smithy_http::body::SdkBody; + use aws_smithy_types::config_bag::ConfigBag; + use http::HeaderValue; + use std::borrow::Cow; #[derive(Debug)] struct SomeStruct; @@ -193,4 +282,157 @@ mod tests { fn assert_send_sync() {} assert_send_sync::(); } + + #[test] + fn insert_plugin() { + #[derive(Debug)] + struct RP(isize, Order); + impl RuntimePlugin for RP { + fn order(&self) -> Order { + self.1 + } + } + + fn insert_plugin(vec: &mut Vec, plugin: RP) { + insert_plugin!(vec, plugin, plugin); + } + + let mut vec = Vec::new(); + insert_plugin(&mut vec, RP(5, Order::NestedComponents)); + insert_plugin(&mut vec, RP(3, Order::Overrides)); + insert_plugin(&mut vec, RP(1, Order::Defaults)); + insert_plugin(&mut vec, RP(6, Order::NestedComponents)); + insert_plugin(&mut vec, RP(2, Order::Defaults)); + insert_plugin(&mut vec, RP(4, Order::Overrides)); + insert_plugin(&mut vec, RP(7, Order::NestedComponents)); + assert_eq!( + vec![1, 2, 3, 4, 5, 6, 7], + vec.iter().map(|rp| rp.0).collect::>() + ); + + let mut vec = Vec::new(); + insert_plugin(&mut vec, RP(3, Order::Overrides)); + insert_plugin(&mut vec, RP(4, Order::Overrides)); + insert_plugin(&mut vec, RP(5, Order::NestedComponents)); + insert_plugin(&mut vec, RP(6, Order::NestedComponents)); + insert_plugin(&mut vec, RP(7, Order::NestedComponents)); + insert_plugin(&mut vec, RP(1, Order::Defaults)); + insert_plugin(&mut vec, RP(2, Order::Defaults)); + assert_eq!( + vec![1, 2, 3, 4, 5, 6, 7], + vec.iter().map(|rp| rp.0).collect::>() + ); + + let mut vec = Vec::new(); + insert_plugin(&mut vec, RP(1, Order::Defaults)); + insert_plugin(&mut vec, RP(2, Order::Defaults)); + insert_plugin(&mut vec, RP(3, Order::Overrides)); + insert_plugin(&mut vec, RP(4, Order::Overrides)); + insert_plugin(&mut vec, RP(5, Order::NestedComponents)); + insert_plugin(&mut vec, RP(6, Order::NestedComponents)); + assert_eq!( + vec![1, 2, 3, 4, 5, 6], + vec.iter().map(|rp| rp.0).collect::>() + ); + } + + #[tokio::test] + async fn components_can_wrap_components() { + // CN1, the inner connector, creates a response with a `rp1` header + #[derive(Debug)] + struct CN1; + impl HttpConnector for CN1 { + fn call(&self, _: HttpRequest) -> BoxFuture { + Box::pin(async { + Ok(http::Response::builder() + .status(200) + .header("rp1", "1") + .body(SdkBody::empty()) + .unwrap()) + }) + } + } + + // CN2, the outer connector, calls the inner connector and adds the `rp2` header to the response + #[derive(Debug)] + struct CN2(SharedHttpConnector); + impl HttpConnector for CN2 { + fn call(&self, request: HttpRequest) -> BoxFuture { + let inner = self.0.clone(); + Box::pin(async move { + let mut resp = inner.call(request).await.unwrap(); + resp.headers_mut() + .append("rp2", HeaderValue::from_static("1")); + Ok(resp) + }) + } + } + + // RP1 registers CN1 + #[derive(Debug)] + struct RP1; + impl RuntimePlugin for RP1 { + fn order(&self) -> Order { + Order::Overrides + } + + fn runtime_components( + &self, + _: &RuntimeComponentsBuilder, + ) -> Cow<'_, RuntimeComponentsBuilder> { + Cow::Owned( + RuntimeComponentsBuilder::new("RP1") + .with_http_connector(Some(SharedHttpConnector::new(CN1))), + ) + } + } + + // RP2 registers CN2 + #[derive(Debug)] + struct RP2; + impl RuntimePlugin for RP2 { + fn order(&self) -> Order { + Order::NestedComponents + } + + fn runtime_components( + &self, + current_components: &RuntimeComponentsBuilder, + ) -> Cow<'_, RuntimeComponentsBuilder> { + Cow::Owned( + RuntimeComponentsBuilder::new("RP2").with_http_connector(Some( + SharedHttpConnector::new(CN2(current_components.http_connector().unwrap())), + )), + ) + } + } + + // Emulate assembling a full runtime plugins list and using it to apply configuration + let plugins = RuntimePlugins::new() + // intentionally configure the plugins in the reverse order + .with_client_plugin(RP2) + .with_client_plugin(RP1); + let mut cfg = ConfigBag::base(); + let components = plugins.apply_client_configuration(&mut cfg).unwrap(); + + // Use the resulting HTTP connector to make a response + let resp = components + .http_connector() + .unwrap() + .call( + http::Request::builder() + .method("GET") + .uri("/") + .body(SdkBody::empty()) + .unwrap(), + ) + .await + .unwrap(); + dbg!(&resp); + + // Verify headers from both connectors are present, + // which will only be possible if they were run in the correct order + assert_eq!("1", resp.headers().get("rp1").unwrap()); + assert_eq!("1", resp.headers().get("rp2").unwrap()); + } } diff --git a/rust-runtime/aws-smithy-runtime/src/client/auth/no_auth.rs b/rust-runtime/aws-smithy-runtime/src/client/auth/no_auth.rs index ebda0f6943..f201cff585 100644 --- a/rust-runtime/aws-smithy-runtime/src/client/auth/no_auth.rs +++ b/rust-runtime/aws-smithy-runtime/src/client/auth/no_auth.rs @@ -51,7 +51,10 @@ impl NoAuthRuntimePlugin { } impl RuntimePlugin for NoAuthRuntimePlugin { - fn runtime_components(&self) -> Cow<'_, RuntimeComponentsBuilder> { + fn runtime_components( + &self, + _: &RuntimeComponentsBuilder, + ) -> Cow<'_, RuntimeComponentsBuilder> { Cow::Borrowed(&self.0) } } diff --git a/rust-runtime/aws-smithy-runtime/src/client/orchestrator.rs b/rust-runtime/aws-smithy-runtime/src/client/orchestrator.rs index 22bee36367..93112317f5 100644 --- a/rust-runtime/aws-smithy-runtime/src/client/orchestrator.rs +++ b/rust-runtime/aws-smithy-runtime/src/client/orchestrator.rs @@ -531,7 +531,10 @@ mod tests { Some(layer.freeze()) } - fn runtime_components(&self) -> Cow<'_, RuntimeComponentsBuilder> { + fn runtime_components( + &self, + _: &RuntimeComponentsBuilder, + ) -> Cow<'_, RuntimeComponentsBuilder> { Cow::Borrowed(&self.builder) } } @@ -600,7 +603,7 @@ mod tests { } } impl RuntimePlugin for FailingInterceptorsClientRuntimePlugin { - fn runtime_components(&self) -> Cow<'_, RuntimeComponentsBuilder> { + fn runtime_components(&self, _: &RuntimeComponentsBuilder) -> Cow<'_, RuntimeComponentsBuilder> { Cow::Borrowed(&self.0) } } @@ -617,7 +620,7 @@ mod tests { } } impl RuntimePlugin for FailingInterceptorsOperationRuntimePlugin { - fn runtime_components(&self) -> Cow<'_, RuntimeComponentsBuilder> { + fn runtime_components(&self, _: &RuntimeComponentsBuilder) -> Cow<'_, RuntimeComponentsBuilder> { Cow::Borrowed(&self.0) } } @@ -901,7 +904,7 @@ mod tests { } } impl RuntimePlugin for InterceptorsTestOperationRuntimePlugin { - fn runtime_components(&self) -> Cow<'_, RuntimeComponentsBuilder> { + fn runtime_components(&self, _: &RuntimeComponentsBuilder) -> Cow<'_, RuntimeComponentsBuilder> { Cow::Borrowed(&self.0) } } @@ -1240,7 +1243,10 @@ mod tests { builder: RuntimeComponentsBuilder, } impl RuntimePlugin for TestInterceptorRuntimePlugin { - fn runtime_components(&self) -> Cow<'_, RuntimeComponentsBuilder> { + fn runtime_components( + &self, + _: &RuntimeComponentsBuilder, + ) -> Cow<'_, RuntimeComponentsBuilder> { Cow::Borrowed(&self.builder) } } diff --git a/rust-runtime/inlineable/src/client_http_checksum_required.rs b/rust-runtime/inlineable/src/client_http_checksum_required.rs index 10c129b3bf..05de9601f8 100644 --- a/rust-runtime/inlineable/src/client_http_checksum_required.rs +++ b/rust-runtime/inlineable/src/client_http_checksum_required.rs @@ -30,7 +30,10 @@ impl HttpChecksumRequiredRuntimePlugin { } impl RuntimePlugin for HttpChecksumRequiredRuntimePlugin { - fn runtime_components(&self) -> Cow<'_, RuntimeComponentsBuilder> { + fn runtime_components( + &self, + _: &RuntimeComponentsBuilder, + ) -> Cow<'_, RuntimeComponentsBuilder> { Cow::Borrowed(&self.runtime_components) } } diff --git a/rust-runtime/inlineable/src/client_idempotency_token.rs b/rust-runtime/inlineable/src/client_idempotency_token.rs index 778fc1133b..31768d68e8 100644 --- a/rust-runtime/inlineable/src/client_idempotency_token.rs +++ b/rust-runtime/inlineable/src/client_idempotency_token.rs @@ -37,7 +37,10 @@ impl IdempotencyTokenRuntimePlugin { } impl RuntimePlugin for IdempotencyTokenRuntimePlugin { - fn runtime_components(&self) -> Cow<'_, RuntimeComponentsBuilder> { + fn runtime_components( + &self, + _: &RuntimeComponentsBuilder, + ) -> Cow<'_, RuntimeComponentsBuilder> { Cow::Borrowed(&self.runtime_components) } }