diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 790bd8f7676495073cefd3b2bc4f9645321f3ae8..e495c15fbd315b33e88cd9949830e4465e4b2bdb 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -58,3 +58,9 @@ message = "Update urlencoding crate to v2.1.0" references = ["smithy-rs#1301"] meta = { "breaking" = false, "tada" = false, "bug" = false } author = "benesch" + +[[aws-sdk-rust]] +message = "Add endpoint resolver to SdkConfig. This enables overriding the endpoint resolver for all services build from a single SdkConfig." +references = ["smithy-rs#1300"] +meta = { "breaking" = false, "tada" = false, "bug" = false } +author = "benesch" diff --git a/aws/rust-runtime/aws-config/src/lib.rs b/aws/rust-runtime/aws-config/src/lib.rs index 08b9249525c9795e19c6d1f497743be3383f1863..1a08afae5aa8f0ff54611f26bb1c7da3c04ab9c0 100644 --- a/aws/rust-runtime/aws-config/src/lib.rs +++ b/aws/rust-runtime/aws-config/src/lib.rs @@ -165,6 +165,7 @@ mod loader { use aws_smithy_types::timeout; use aws_types::app_name::AppName; use aws_types::credentials::{ProvideCredentials, SharedCredentialsProvider}; + use aws_types::endpoint::ResolveAwsEndpoint; use aws_types::SdkConfig; use crate::default_provider::{app_name, credentials, region, retry_config, timeout_config}; @@ -181,6 +182,7 @@ mod loader { pub struct ConfigLoader { app_name: Option, credentials_provider: Option, + endpoint_resolver: Option>, region: Option>, retry_config: Option, sleep: Option>, @@ -285,6 +287,30 @@ mod loader { self } + /// Override the endpoint resolver used for **all** AWS Services + /// + /// This method will override the endpoint resolver used for **all** AWS services. This mainly + /// exists to set a static endpoint for tools like `LocalStack`. For live traffic, AWS services + /// require the service-specific endpoint resolver they load by default. + /// + /// # Examples + /// + /// Use a static endpoint for all services + /// ```no_run + /// # async fn doc() { + /// use aws_smithy_http::endpoint::Endpoint; + /// let sdk_config = aws_config::from_env() + /// .endpoint_resolver(Endpoint::immutable("http://localhost:1234".parse().expect("valid URI"))) + /// .load().await; + /// # } + pub fn endpoint_resolver( + mut self, + endpoint_resolver: impl ResolveAwsEndpoint + 'static, + ) -> Self { + self.endpoint_resolver = Some(Arc::new(endpoint_resolver)); + self + } + /// Set configuration for all sub-loaders (credentials, region etc.) /// /// Update the `ProviderConfig` used for all nested loaders. This can be used to override @@ -390,6 +416,8 @@ mod loader { SharedCredentialsProvider::new(builder.build().await) }; + let endpoint_resolver = self.endpoint_resolver; + let mut builder = SdkConfig::builder() .region(region) .retry_config(retry_config) @@ -397,6 +425,7 @@ mod loader { .credentials_provider(credentials_provider) .http_connector(http_connector); + builder.set_endpoint_resolver(endpoint_resolver); builder.set_app_name(app_name); builder.set_sleep_impl(sleep_impl); builder.build() diff --git a/aws/rust-runtime/aws-endpoint/src/lib.rs b/aws/rust-runtime/aws-endpoint/src/lib.rs index 2a3d63d96325bfbc0c7aef274b3d85905e29d7f6..ba382d34944408a44cbca5583c96db0575bc2e65 100644 --- a/aws/rust-runtime/aws-endpoint/src/lib.rs +++ b/aws/rust-runtime/aws-endpoint/src/lib.rs @@ -11,7 +11,7 @@ pub use partition::Partition; #[doc(hidden)] pub use partition::PartitionResolver; -use aws_smithy_http::endpoint::{Endpoint, EndpointPrefix}; +use aws_smithy_http::endpoint::EndpointPrefix; use aws_smithy_http::middleware::MapRequest; use aws_smithy_http::operation::Request; use aws_smithy_http::property_bag::PropertyBag; @@ -22,122 +22,7 @@ use std::fmt; use std::fmt::{Debug, Display, Formatter}; use std::sync::Arc; -/// Endpoint to connect to an AWS Service -/// -/// An `AwsEndpoint` captures all necessary information needed to connect to an AWS service, including: -/// - The URI of the endpoint (needed to actually send the request) -/// - The name of the service (needed downstream for signing) -/// - The signing region (which may differ from the actual region) -#[derive(Clone, Debug)] -pub struct AwsEndpoint { - endpoint: Endpoint, - credential_scope: CredentialScope, -} - -impl AwsEndpoint { - pub fn set_endpoint(&self, mut uri: &mut http::Uri, endpoint_prefix: Option<&EndpointPrefix>) { - self.endpoint.set_endpoint(&mut uri, endpoint_prefix); - } -} - -pub type BoxError = Box; - -/// Resolve the AWS Endpoint for a given region -/// -/// To provide a static endpoint, [`Endpoint`](aws_smithy_http::endpoint::Endpoint) implements this trait. -/// Example usage: -/// ```rust -/// # mod dynamodb { -/// # use aws_endpoint::ResolveAwsEndpoint; -/// # pub struct ConfigBuilder; -/// # impl ConfigBuilder { -/// # pub fn endpoint(&mut self, resolver: impl ResolveAwsEndpoint + 'static) { -/// # // ... -/// # } -/// # } -/// # pub struct Config; -/// # impl Config { -/// # pub fn builder() -> ConfigBuilder { -/// # ConfigBuilder -/// # } -/// # } -/// # } -/// use aws_smithy_http::endpoint::Endpoint; -/// use http::Uri; -/// let config = dynamodb::Config::builder() -/// .endpoint( -/// Endpoint::immutable(Uri::from_static("http://localhost:8080")) -/// ); -/// ``` -/// In the future, each AWS service will generate their own implementation of `ResolveAwsEndpoint`. This implementation -/// may use endpoint discovery. The list of supported regions for a given service -/// will be codegenerated from `endpoints.json`. -pub trait ResolveAwsEndpoint: Send + Sync { - // TODO(https://github.com/awslabs/smithy-rs/issues/866): Create `ResolveEndpointError` - fn resolve_endpoint(&self, region: &Region) -> Result; -} - -#[derive(Clone, Default, Debug)] -pub struct CredentialScope { - region: Option, - service: Option, -} - -impl CredentialScope { - pub fn builder() -> credential_scope::Builder { - credential_scope::Builder::default() - } -} - -pub mod credential_scope { - use crate::CredentialScope; - use aws_types::region::SigningRegion; - use aws_types::SigningService; - - #[derive(Debug, Default)] - pub struct Builder { - region: Option, - service: Option, - } - - impl Builder { - pub fn region(mut self, region: &'static str) -> Self { - self.region = Some(SigningRegion::from_static(region)); - self - } - - pub fn service(mut self, service: &'static str) -> Self { - self.service = Some(SigningService::from_static(service)); - self - } - - pub fn build(self) -> CredentialScope { - CredentialScope { - region: self.region, - service: self.service, - } - } - } -} - -impl CredentialScope { - pub fn merge(&self, other: &CredentialScope) -> CredentialScope { - CredentialScope { - region: self.region.clone().or_else(|| other.region.clone()), - service: self.service.clone().or_else(|| other.service.clone()), - } - } -} - -/// An `Endpoint` can be its own resolver to support static endpoints -impl ResolveAwsEndpoint for Endpoint { - fn resolve_endpoint(&self, _region: &Region) -> Result { - Ok(AwsEndpoint { - endpoint: self.clone(), - credential_scope: Default::default(), - }) - } -} +pub use aws_types::endpoint::{AwsEndpoint, BoxError, CredentialScope, ResolveAwsEndpoint}; type AwsEndpointResolver = Arc; pub fn get_endpoint_resolver(properties: &PropertyBag) -> Option<&AwsEndpointResolver> { @@ -188,16 +73,15 @@ impl MapRequest for AwsEndpointStage { .map_err(AwsEndpointStageError::EndpointResolutionError)?; tracing::debug!(endpoint = ?endpoint, base_region = ?region, "resolved endpoint"); let signing_region = endpoint - .credential_scope - .region + .credential_scope() + .region() + .cloned() .unwrap_or_else(|| region.clone().into()); props.insert::(signing_region); - if let Some(signing_service) = endpoint.credential_scope.service { - props.insert::(signing_service); + if let Some(signing_service) = endpoint.credential_scope().service() { + props.insert::(signing_service.clone()); } - endpoint - .endpoint - .set_endpoint(http_req.uri_mut(), props.get::()); + endpoint.set_endpoint(http_req.uri_mut(), props.get::()); Ok(http_req) }) } @@ -257,8 +141,8 @@ mod test { uri_template: "www.service.com", protocol: Protocol::Http, credential_scope: CredentialScope::builder() - .service("qldb-override") - .region("us-east-override") + .service(SigningService::from_static("qldb-override")) + .region(SigningRegion::from_static("us-east-override")) .build(), signature_versions: SignatureVersion::V4, }); diff --git a/aws/rust-runtime/aws-endpoint/src/partition/endpoint.rs b/aws/rust-runtime/aws-endpoint/src/partition/endpoint.rs index 3f8e1bd30181546e4733ecb324d7acf2eee512ab..3f448c723f136cf929eed52497b8df00e5ce5821 100644 --- a/aws/rust-runtime/aws-endpoint/src/partition/endpoint.rs +++ b/aws/rust-runtime/aws-endpoint/src/partition/endpoint.rs @@ -3,8 +3,8 @@ * SPDX-License-Identifier: Apache-2.0. */ -use crate::{AwsEndpoint, BoxError, CredentialScope, ResolveAwsEndpoint}; use aws_smithy_http::endpoint::Endpoint; +use aws_types::endpoint::{AwsEndpoint, BoxError, CredentialScope, ResolveAwsEndpoint}; use aws_types::region::Region; /// Endpoint metadata @@ -55,17 +55,15 @@ impl ResolveAwsEndpoint for Metadata { let uri = self.uri_template.replace("{region}", region.as_ref()); let uri = format!("{}://{}", self.protocol.as_str(), uri); let endpoint = Endpoint::mutable(uri.parse()?); - let ep = AwsEndpoint { - endpoint, - credential_scope: CredentialScope { - service: self.credential_scope.service.clone(), - region: self - .credential_scope - .region - .clone() - .or_else(|| Some(region.clone().into())), - }, - }; - Ok(ep) + let mut credential_scope = CredentialScope::builder().region( + self.credential_scope + .region() + .cloned() + .unwrap_or_else(|| region.clone().into()), + ); + if let Some(service) = self.credential_scope.service() { + credential_scope = credential_scope.service(service.clone()); + } + Ok(AwsEndpoint::new(endpoint, credential_scope.build())) } } diff --git a/aws/rust-runtime/aws-endpoint/src/partition/mod.rs b/aws/rust-runtime/aws-endpoint/src/partition/mod.rs index 92baf4c8926eb290ec64c45991d1608af7e40836..0d357563928af233ad04f8fe7260292eae9c68ef 100644 --- a/aws/rust-runtime/aws-endpoint/src/partition/mod.rs +++ b/aws/rust-runtime/aws-endpoint/src/partition/mod.rs @@ -5,7 +5,7 @@ pub mod endpoint; -use crate::{AwsEndpoint, BoxError, ResolveAwsEndpoint}; +use aws_types::endpoint::{AwsEndpoint, BoxError, ResolveAwsEndpoint}; use aws_types::region::Region; use regex::Regex; use std::collections::HashMap; @@ -19,6 +19,7 @@ use std::iter; /// /// Once a partition has been identified, endpoint resolution is delegated to the underlying /// partition. +#[derive(Debug)] pub struct PartitionResolver { /// Base partition used if no partitions match the region regex base: Partition, @@ -200,10 +201,10 @@ mod test { Metadata { uri_template: "service-alt.us-west-1.amazonaws.com", protocol: Http, - credential_scope: CredentialScope { - region: Some(SigningRegion::from_static("us-west-1")), - service: Some(SigningService::from_static("foo")), - }, + credential_scope: CredentialScope::builder() + .region(SigningRegion::from_static("us-west-1")) + .service(SigningService::from_static("foo")) + .build(), signature_versions: V4, }, ) @@ -218,10 +219,9 @@ mod test { .default_endpoint(Metadata { uri_template: "service.{region}.amazonaws.com", protocol: Https, - credential_scope: CredentialScope { - service: Some(SigningService::from_static("foo")), - ..Default::default() - }, + credential_scope: CredentialScope::builder() + .service(SigningService::from_static("foo")) + .build(), signature_versions: SignatureVersion::V4, }) .partition_endpoint("partition") @@ -231,10 +231,10 @@ mod test { Metadata { uri_template: "some-global-thing.amazonaws.cn", protocol: Https, - credential_scope: CredentialScope { - region: Some(SigningRegion::from_static("cn-east-1")), - service: Some(SigningService::from_static("foo")), - }, + credential_scope: CredentialScope::builder() + .region(SigningRegion::from_static("cn-east-1")) + .service(SigningService::from_static("foo")) + .build(), signature_versions: SignatureVersion::V4, }, ) @@ -243,10 +243,9 @@ mod test { Metadata { uri_template: "fips.amazonaws.cn", protocol: Https, - credential_scope: CredentialScope { - region: Some(SigningRegion::from_static("cn-fips")), - service: None, - }, + credential_scope: CredentialScope::builder() + .region(SigningRegion::from_static("cn-fips")) + .build(), signature_versions: SignatureVersion::V4, }, ) @@ -269,10 +268,9 @@ mod test { uri_template: "service.{region}.amazonaws.com", protocol: Https, signature_versions: V4, - credential_scope: CredentialScope { - service: Some(SigningService::from_static("foo")), - ..Default::default() - }, + credential_scope: CredentialScope::builder() + .service(SigningService::from_static("foo")) + .build(), }) .build() .expect("valid partition") @@ -378,12 +376,15 @@ mod test { endpoint.set_endpoint(&mut test_uri, None); assert_eq!(test_uri, Uri::from_static(test_case.uri)); assert_eq!( - endpoint.credential_scope.region, - Some(SigningRegion::from_static(test_case.signing_region)) + endpoint.credential_scope().region(), + Some(&SigningRegion::from_static(test_case.signing_region)) ); assert_eq!( - endpoint.credential_scope.service, - test_case.signing_service.map(SigningService::from_static) + endpoint.credential_scope().service(), + test_case + .signing_service + .map(SigningService::from_static) + .as_ref() ) } } diff --git a/aws/rust-runtime/aws-types/Cargo.toml b/aws/rust-runtime/aws-types/Cargo.toml index d5b7a0d875e4069dd74ae9b527203c39da739b59..86c2293b309e2c45be1135ae030c35373fa6176d 100644 --- a/aws/rust-runtime/aws-types/Cargo.toml +++ b/aws/rust-runtime/aws-types/Cargo.toml @@ -14,11 +14,14 @@ hardcoded-credentials = [] aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async" } aws-smithy-types = { path = "../../../rust-runtime/aws-smithy-types" } aws-smithy-client = { path = "../../../rust-runtime/aws-smithy-client" } +aws-smithy-http = { path = "../../../rust-runtime/aws-smithy-http" } tracing = "0.1" zeroize = "1.4.1" +http = "0.2.6" [dev-dependencies] futures-util = "0.3.16" +http = "0.2.4" tracing-test = "0.2.1" [build-dependencies] diff --git a/aws/rust-runtime/aws-types/src/endpoint.rs b/aws/rust-runtime/aws-types/src/endpoint.rs new file mode 100644 index 0000000000000000000000000000000000000000..6284d55f0c520197e95fac79899fbd9c4171a7c3 --- /dev/null +++ b/aws/rust-runtime/aws-types/src/endpoint.rs @@ -0,0 +1,187 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +//! AWS SDK endpoint support. + +use crate::region::{Region, SigningRegion}; +use crate::SigningService; +use aws_smithy_http::endpoint::{Endpoint, EndpointPrefix}; +use std::error::Error; +use std::fmt::Debug; + +/// Endpoint to connect to an AWS Service +/// +/// An `AwsEndpoint` captures all necessary information needed to connect to an AWS service, including: +/// - The URI of the endpoint (needed to actually send the request) +/// - The name of the service (needed downstream for signing) +/// - The signing region (which may differ from the actual region) +#[derive(Clone, Debug)] +pub struct AwsEndpoint { + endpoint: Endpoint, + credential_scope: CredentialScope, +} + +impl AwsEndpoint { + /// Constructs a new AWS endpoint. + pub fn new(endpoint: Endpoint, credential_scope: CredentialScope) -> AwsEndpoint { + AwsEndpoint { + endpoint, + credential_scope, + } + } + + /// Returns the underlying endpoint. + pub fn endpoint(&self) -> &Endpoint { + &self.endpoint + } + + /// Returns the credential scope. + pub fn credential_scope(&self) -> &CredentialScope { + &self.credential_scope + } + + /// Sets the endpoint on a given `uri` based on this endpoint + pub fn set_endpoint(&self, uri: &mut http::Uri, endpoint_prefix: Option<&EndpointPrefix>) { + self.endpoint.set_endpoint(uri, endpoint_prefix); + } +} + +/// A boxed error. +pub type BoxError = Box; + +/// Resolve the AWS Endpoint for a given region +/// +/// To provide a static endpoint, [`Endpoint`](aws_smithy_http::endpoint::Endpoint) implements this trait. +/// Example usage: +/// ```rust +/// # mod dynamodb { +/// # use aws_types::endpoint::ResolveAwsEndpoint; +/// # pub struct ConfigBuilder; +/// # impl ConfigBuilder { +/// # pub fn endpoint(&mut self, resolver: impl ResolveAwsEndpoint + 'static) { +/// # // ... +/// # } +/// # } +/// # pub struct Config; +/// # impl Config { +/// # pub fn builder() -> ConfigBuilder { +/// # ConfigBuilder +/// # } +/// # } +/// # } +/// use aws_smithy_http::endpoint::Endpoint; +/// use http::Uri; +/// let config = dynamodb::Config::builder() +/// .endpoint( +/// Endpoint::immutable(Uri::from_static("http://localhost:8080")) +/// ); +/// ``` +/// Each AWS service generates their own implementation of `ResolveAwsEndpoint`. +pub trait ResolveAwsEndpoint: Send + Sync + Debug { + /// Resolves the AWS endpoint for a given region. + // TODO(https://github.com/awslabs/smithy-rs/issues/866): Create `ResolveEndpointError` + fn resolve_endpoint(&self, region: &Region) -> Result; +} + +/// The scope for AWS credentials. +#[derive(Clone, Default, Debug)] +pub struct CredentialScope { + region: Option, + service: Option, +} + +impl CredentialScope { + /// Creates a builder for [`CredentialScope`]. + pub fn builder() -> credential_scope::Builder { + credential_scope::Builder::default() + } +} + +/// Types associated with [`CredentialScope`]. +pub mod credential_scope { + use crate::endpoint::CredentialScope; + use crate::region::SigningRegion; + use crate::SigningService; + + /// A builder for [`CredentialScope`]. + #[derive(Debug, Default)] + pub struct Builder { + region: Option, + service: Option, + } + + impl Builder { + /// Sets the signing region. + pub fn region(mut self, region: impl Into) -> Self { + self.region = Some(region.into()); + self + } + + /// Sets the signing service. + pub fn service(mut self, service: impl Into) -> Self { + self.service = Some(service.into()); + self + } + + /// Constructs a [`CredentialScope`] from the builder. + pub fn build(self) -> CredentialScope { + CredentialScope { + region: self.region, + service: self.service, + } + } + } +} + +impl CredentialScope { + /// Returns the signing region. + pub fn region(&self) -> Option<&SigningRegion> { + self.region.as_ref() + } + + /// Returns the signing service. + pub fn service(&self) -> Option<&SigningService> { + self.service.as_ref() + } + + /// Uses the values from `other` to fill in unconfigured parameters on this + /// credential scope object. + pub fn merge(&self, other: &CredentialScope) -> CredentialScope { + CredentialScope { + region: self.region.clone().or_else(|| other.region.clone()), + service: self.service.clone().or_else(|| other.service.clone()), + } + } +} + +/// An `Endpoint` can be its own resolver to support static endpoints +impl ResolveAwsEndpoint for Endpoint { + fn resolve_endpoint(&self, _region: &Region) -> Result { + Ok(AwsEndpoint { + endpoint: self.clone(), + credential_scope: Default::default(), + }) + } +} + +#[cfg(test)] +mod test { + use crate::endpoint::CredentialScope; + use crate::region::SigningRegion; + use crate::SigningService; + + #[test] + fn create_credentials_scope_from_strs() { + let scope = CredentialScope::builder() + .service("s3") + .region("us-east-1") + .build(); + assert_eq!(scope.service(), Some(&SigningService::from_static("s3"))); + assert_eq!( + scope.region(), + Some(&SigningRegion::from_static("us-east-1")) + ); + } +} diff --git a/aws/rust-runtime/aws-types/src/lib.rs b/aws/rust-runtime/aws-types/src/lib.rs index db34a295568f99a073461418b1e85c4f2729f183..7ec48116e59618d53d279be1347f34257cd8ce36 100644 --- a/aws/rust-runtime/aws-types/src/lib.rs +++ b/aws/rust-runtime/aws-types/src/lib.rs @@ -18,6 +18,7 @@ pub mod build_metadata; #[deprecated(since = "0.9.0", note = "renamed to sdk_config")] pub mod config; pub mod credentials; +pub mod endpoint; #[doc(hidden)] pub mod os_shim_internal; pub mod region; @@ -52,3 +53,9 @@ impl From for SigningService { SigningService(Cow::Owned(service)) } } + +impl From<&'static str> for SigningService { + fn from(service: &'static str) -> Self { + Self::from_static(service) + } +} diff --git a/aws/rust-runtime/aws-types/src/region.rs b/aws/rust-runtime/aws-types/src/region.rs index acb1c1a85cd8dd10856d66fd8c64e7ca53758fb5..ade133277f48b85a57ad230e67ffe96ab4f8f515 100644 --- a/aws/rust-runtime/aws-types/src/region.rs +++ b/aws/rust-runtime/aws-types/src/region.rs @@ -65,6 +65,12 @@ impl From for SigningRegion { } } +impl From<&'static str> for SigningRegion { + fn from(region: &'static str) -> Self { + Self::from_static(region) + } +} + impl SigningRegion { /// Creates a `SigningRegion` from a static str. pub const fn from_static(region: &'static str) -> Self { diff --git a/aws/rust-runtime/aws-types/src/sdk_config.rs b/aws/rust-runtime/aws-types/src/sdk_config.rs index a76651d5762add5443a2702765646009cc214544..59c91fca38876ff181542350cef8c49d4aad7211 100644 --- a/aws/rust-runtime/aws-types/src/sdk_config.rs +++ b/aws/rust-runtime/aws-types/src/sdk_config.rs @@ -18,6 +18,7 @@ use aws_smithy_types::timeout; use crate::app_name::AppName; use crate::credentials::SharedCredentialsProvider; +use crate::endpoint::ResolveAwsEndpoint; use crate::region::Region; /// AWS Shared Configuration @@ -26,6 +27,7 @@ pub struct SdkConfig { app_name: Option, credentials_provider: Option, region: Option, + endpoint_resolver: Option>, retry_config: Option, sleep_impl: Option>, timeout_config: Option, @@ -38,6 +40,7 @@ pub struct Builder { app_name: Option, credentials_provider: Option, region: Option, + endpoint_resolver: Option>, retry_config: Option, sleep_impl: Option>, timeout_config: Option, @@ -79,6 +82,49 @@ impl Builder { self } + /// Set the endpoint resolver to use when making requests + /// + /// # Examples + /// ``` + /// use std::sync::Arc; + /// use aws_types::SdkConfig; + /// use aws_smithy_http::endpoint::Endpoint; + /// use http::Uri; + /// let config = SdkConfig::builder().endpoint_resolver( + /// Endpoint::immutable(Uri::from_static("http://localhost:8080")) + /// ).build(); + /// ``` + pub fn endpoint_resolver( + mut self, + endpoint_resolver: impl ResolveAwsEndpoint + 'static, + ) -> Self { + self.set_endpoint_resolver(Some(Arc::new(endpoint_resolver))); + self + } + + /// Set the endpoint resolver to use when making requests + /// + /// # Examples + /// ``` + /// use std::sync::Arc; + /// use aws_types::SdkConfig; + /// use aws_types::endpoint::ResolveAwsEndpoint; + /// fn endpoint_resolver_override() -> Option> { + /// // ... + /// # None + /// } + /// let mut config = SdkConfig::builder(); + /// config.set_endpoint_resolver(endpoint_resolver_override()); + /// config.build(); + /// ``` + pub fn set_endpoint_resolver( + &mut self, + endpoint_resolver: Option>, + ) -> &mut Self { + self.endpoint_resolver = endpoint_resolver; + self + } + /// Set the retry_config for the builder /// /// # Examples @@ -309,6 +355,7 @@ impl Builder { app_name: self.app_name, credentials_provider: self.credentials_provider, region: self.region, + endpoint_resolver: self.endpoint_resolver, retry_config: self.retry_config, sleep_impl: self.sleep_impl, timeout_config: self.timeout_config, @@ -323,6 +370,11 @@ impl SdkConfig { self.region.as_ref() } + /// Configured endpoint resolver + pub fn endpoint_resolver(&self) -> Option> { + self.endpoint_resolver.clone() + } + /// Configured retry config pub fn retry_config(&self) -> Option<&RetryConfig> { self.retry_config.as_ref() diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsEndpointDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsEndpointDecorator.kt index 8a9fe776650ae14bb55334f09db3de707843558f..0c15447c37091d7926c17d1b16be8c33ccc592b4 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsEndpointDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsEndpointDecorator.kt @@ -72,6 +72,7 @@ class EndpointConfigCustomization(private val codegenContext: CodegenContext, pr ConfigCustomization() { private val runtimeConfig = codegenContext.runtimeConfig private val resolveAwsEndpoint = runtimeConfig.awsEndpoint().asType().copy(name = "ResolveAwsEndpoint") + private val moduleUseName = codegenContext.moduleUseName() override fun section(section: ServiceConfig): Writable = writable { when (section) { is ServiceConfig.ConfigStruct -> rust( @@ -82,16 +83,37 @@ class EndpointConfigCustomization(private val codegenContext: CodegenContext, pr is ServiceConfig.BuilderStruct -> rust("endpoint_resolver: Option<::std::sync::Arc>,", resolveAwsEndpoint) ServiceConfig.BuilderImpl -> - rust( + rustTemplate( """ - // TODO(docs): include an example of using a static endpoint - /// Sets the endpoint resolver to use when making requests. - pub fn endpoint_resolver(mut self, endpoint_resolver: impl #T + 'static) -> Self { + /// Overrides the endpoint resolver to use when making requests. + /// + /// When unset, the client will used a generated endpoint resolver based on the endpoint metadata + /// for `$moduleUseName`. + /// + /// ## Examples + /// ```no_run + /// use #{aws_types}::region::Region; + /// use $moduleUseName::config::{Builder, Config}; + /// use $moduleUseName::Endpoint; + /// + /// let config = $moduleUseName::Config::builder() + /// .endpoint_resolver( + /// Endpoint::immutable("http://localhost:8080".parse().expect("valid URI")) + /// ).build(); + /// ``` + pub fn endpoint_resolver(mut self, endpoint_resolver: impl #{ResolveAwsEndpoint} + 'static) -> Self { self.endpoint_resolver = Some(::std::sync::Arc::new(endpoint_resolver)); self } + + /// Sets the endpoint resolver to use when making requests. + pub fn set_endpoint_resolver(&mut self, endpoint_resolver: Option>) -> &mut Self { + self.endpoint_resolver = endpoint_resolver; + self + } """, - resolveAwsEndpoint + "ResolveAwsEndpoint" to resolveAwsEndpoint, + "aws_types" to awsTypes(runtimeConfig).asType() ) ServiceConfig.BuilderBuild -> { val resolverGenerator = EndpointResolverGenerator(codegenContext, endpointData) @@ -145,6 +167,7 @@ class EndpointResolverGenerator(codegenContext: CodegenContext, private val endp private val runtimeConfig = codegenContext.runtimeConfig private val endpointPrefix = codegenContext.serviceShape.expectTrait().endpointPrefix private val awsEndpoint = runtimeConfig.awsEndpoint().asType() + private val awsTypes = runtimeConfig.awsTypes().asType() private val codegenScope = arrayOf( "Partition" to awsEndpoint.member("Partition"), @@ -154,7 +177,9 @@ class EndpointResolverGenerator(codegenContext: CodegenContext, private val endp "Protocol" to awsEndpoint.member("partition::endpoint::Protocol"), "SignatureVersion" to awsEndpoint.member("partition::endpoint::SignatureVersion"), "PartitionResolver" to awsEndpoint.member("PartitionResolver"), - "ResolveAwsEndpoint" to awsEndpoint.member("ResolveAwsEndpoint") + "ResolveAwsEndpoint" to awsEndpoint.member("ResolveAwsEndpoint"), + "SigningService" to awsTypes.member("SigningService"), + "SigningRegion" to awsTypes.member("region::SigningRegion") ) fun resolver(): RuntimeType { @@ -338,10 +363,16 @@ class EndpointResolverGenerator(codegenContext: CodegenContext, private val endp *codegenScope ) objectNode.getStringMember("service").map { - rust(".service(${it.value.dq()})") + rustTemplate( + ".service(${it.value.dq()})", + *codegenScope, + ) } objectNode.getStringMember("region").map { - rust(".region(${it.value.dq()})") + rustTemplate( + ".region(${it.value.dq()})", + *codegenScope, + ) } rust(".build()") } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SdkConfigDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SdkConfigDecorator.kt index f63e4bae21bed9bfb34c0388297e4efae06e5e36..28d5a704fd16659036cdc3a0c03c727617dfe588 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SdkConfigDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SdkConfigDecorator.kt @@ -46,6 +46,7 @@ class SdkConfigDecorator : RustCodegenDecorator { fn from(input: &#{SdkConfig}) -> Self { let mut builder = Builder::default(); builder = builder.region(input.region().cloned()); + builder.set_endpoint_resolver(input.endpoint_resolver().clone()); builder.set_retry_config(input.retry_config().cloned()); builder.set_timeout_config(input.timeout_config().cloned()); builder.set_sleep_impl(input.sleep_impl().clone()); diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/EndpointConfigCustomizationTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/EndpointConfigCustomizationTest.kt index cbc90a1a58d78956dd8453a87ee92a5f198a4c4f..51ec893c88ef81634537778129e01f49fb2d9967 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/EndpointConfigCustomizationTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/EndpointConfigCustomizationTest.kt @@ -8,32 +8,51 @@ package software.amazon.smithy.rustsdk import org.junit.jupiter.api.Test import software.amazon.smithy.model.node.ObjectNode import software.amazon.smithy.rust.codegen.rustlang.CargoDependency -import software.amazon.smithy.rust.codegen.testutil.TestWorkspace +import software.amazon.smithy.rust.codegen.smithy.CodegenContext +import software.amazon.smithy.rust.codegen.smithy.CodegenVisitor +import software.amazon.smithy.rust.codegen.smithy.RustCrate +import software.amazon.smithy.rust.codegen.smithy.customizations.AllowLintsGenerator +import software.amazon.smithy.rust.codegen.smithy.customize.CombinedCodegenDecorator +import software.amazon.smithy.rust.codegen.smithy.customize.RequiredCustomizations +import software.amazon.smithy.rust.codegen.smithy.customize.RustCodegenDecorator +import software.amazon.smithy.rust.codegen.smithy.generators.LibRsCustomization +import software.amazon.smithy.rust.codegen.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.testutil.asSmithyModel -import software.amazon.smithy.rust.codegen.testutil.compileAndTest -import software.amazon.smithy.rust.codegen.testutil.stubConfigProject -import software.amazon.smithy.rust.codegen.testutil.testCodegenContext +import software.amazon.smithy.rust.codegen.testutil.generatePluginContext +import software.amazon.smithy.rust.codegen.testutil.stubConfigCustomization import software.amazon.smithy.rust.codegen.testutil.unitTest -import software.amazon.smithy.rust.codegen.testutil.validateConfigCustomizations -import software.amazon.smithy.rust.codegen.util.lookup +import software.amazon.smithy.rust.codegen.util.runCommand internal class EndpointConfigCustomizationTest { private val model = """ namespace test + use aws.protocols#restJson1 + + @title("test") + @restJson1 @aws.api#service(sdkId: "Test", endpointPrefix: "service-with-prefix") service TestService { - version: "123" + version: "123", + operations: [Nop] + } + + @http(uri: "/foo", method: "GET") + operation Nop { } @aws.api#service(sdkId: "Test", endpointPrefix: "iam") + @restJson1 service NoRegions { - version: "123" + version: "123", + operations: [Nop] } @aws.api#service(sdkId: "Test") + @restJson1 service NoEndpointPrefix { - version: "123" + version: "123", + operations: [Nop] } """.asSmithyModel() @@ -97,76 +116,98 @@ internal class EndpointConfigCustomizationTest { } """.let { ObjectNode.parse(it).expectObjectNode() } - fun endpointCustomization(service: String) = - EndpointConfigCustomization( - testCodegenContext( - model, - model.lookup(service) - ).copy(runtimeConfig = AwsTestRuntimeConfig), - endpointConfig - ) + private fun validateEndpointCustomizationForService(service: String, test: ((RustCrate) -> Unit)? = null) { + val (context, testDir) = generatePluginContext(model, service = service, runtimeConfig = AwsTestRuntimeConfig) + val codegenDecorator = object : RustCodegenDecorator { + override val name: String = "tests and config" + override val order: Byte = 0 + override fun configCustomizations( + codegenContext: CodegenContext, + baseCustomizations: List + ): List { + return baseCustomizations + stubConfigCustomization("a") + EndpointConfigCustomization( + codegenContext, + endpointConfig + ) + stubConfigCustomization("b") + } + + override fun libRsCustomizations( + codegenContext: CodegenContext, + baseCustomizations: List + ): List { + return baseCustomizations + PubUseEndpoint(AwsTestRuntimeConfig) + AllowLintsGenerator(listOf("dead_code"), listOf(), listOf()) + } + + override fun extras(codegenContext: CodegenContext, rustCrate: RustCrate) { + if (test != null) { + test(rustCrate) + } + } + } + val customization = CombinedCodegenDecorator(listOf(RequiredCustomizations(), codegenDecorator)) + CodegenVisitor(context, customization).execute() + "cargo test".runCommand(testDir) + } @Test fun `generates valid code`() { - validateConfigCustomizations(endpointCustomization("test#TestService")) + validateEndpointCustomizationForService("test#TestService") } @Test fun `generates valid code when no endpoint prefix is provided`() { - validateConfigCustomizations(endpointCustomization("test#NoEndpointPrefix")) + validateEndpointCustomizationForService("test#NoEndpointPrefix") } @Test fun `support region-specific endpoint overrides`() { - val project = - stubConfigProject(endpointCustomization("test#TestService"), TestWorkspace.testProject()) - project.lib { - it.addDependency(awsTypes(AwsTestRuntimeConfig)) - it.addDependency(CargoDependency.Http) - it.unitTest( - "region_override", - """ - use aws_types::region::Region; - use http::Uri; - let conf = crate::config::Config::builder().build(); - let endpoint = conf.endpoint_resolver - .resolve_endpoint(&Region::new("fips-ca-central-1")).expect("default resolver produces a valid endpoint"); - let mut uri = Uri::from_static("/?k=v"); - endpoint.set_endpoint(&mut uri, None); - assert_eq!(uri, Uri::from_static("https://access-analyzer-fips.ca-central-1.amazonaws.com/?k=v")); - """ - ) + validateEndpointCustomizationForService("test#TestService") { crate -> + crate.lib { + it.addDependency(awsTypes(AwsTestRuntimeConfig)) + it.addDependency(CargoDependency.Http) + it.unitTest( + "region_override", + """ + use aws_types::region::Region; + use http::Uri; + let conf = crate::config::Config::builder().build(); + let endpoint = conf.endpoint_resolver + .resolve_endpoint(&Region::new("fips-ca-central-1")).expect("default resolver produces a valid endpoint"); + let mut uri = Uri::from_static("/?k=v"); + endpoint.set_endpoint(&mut uri, None); + assert_eq!(uri, Uri::from_static("https://access-analyzer-fips.ca-central-1.amazonaws.com/?k=v")); + """ + ) + } } - project.compileAndTest() } @Test fun `support region-agnostic services`() { - val project = - stubConfigProject(endpointCustomization("test#NoRegions"), TestWorkspace.testProject()) - project.lib { - it.addDependency(awsTypes(AwsTestRuntimeConfig)) - it.addDependency(CargoDependency.Http) - it.unitTest( - "global_services", - """ - use aws_types::region::Region; - use http::Uri; - let conf = crate::config::Config::builder().build(); - let endpoint = conf.endpoint_resolver - .resolve_endpoint(&Region::new("us-east-1")).expect("default resolver produces a valid endpoint"); - let mut uri = Uri::from_static("/?k=v"); - endpoint.set_endpoint(&mut uri, None); - assert_eq!(uri, Uri::from_static("https://iam.amazonaws.com/?k=v")); - - let endpoint = conf.endpoint_resolver - .resolve_endpoint(&Region::new("iam-fips")).expect("default resolver produces a valid endpoint"); - let mut uri = Uri::from_static("/?k=v"); - endpoint.set_endpoint(&mut uri, None); - assert_eq!(uri, Uri::from_static("https://iam-fips.amazonaws.com/?k=v")); - """ - ) + validateEndpointCustomizationForService("test#NoRegions") { crate -> + crate.lib { + it.addDependency(awsTypes(AwsTestRuntimeConfig)) + it.addDependency(CargoDependency.Http) + it.unitTest( + "global_services", + """ + use aws_types::region::Region; + use http::Uri; + let conf = crate::config::Config::builder().build(); + let endpoint = conf.endpoint_resolver + .resolve_endpoint(&Region::new("us-east-1")).expect("default resolver produces a valid endpoint"); + let mut uri = Uri::from_static("/?k=v"); + endpoint.set_endpoint(&mut uri, None); + assert_eq!(uri, Uri::from_static("https://iam.amazonaws.com/?k=v")); + + let endpoint = conf.endpoint_resolver + .resolve_endpoint(&Region::new("iam-fips")).expect("default resolver produces a valid endpoint"); + let mut uri = Uri::from_static("/?k=v"); + endpoint.set_endpoint(&mut uri, None); + assert_eq!(uri, Uri::from_static("https://iam-fips.amazonaws.com/?k=v")); + """ + ) + } } - project.compileAndTest() } } diff --git a/aws/sdk/integration-tests/iam/Cargo.toml b/aws/sdk/integration-tests/iam/Cargo.toml index 6e3621f4dcd37a673b44b7b543593b740c4f988c..498c8dce1d27a2b5b16edb348ffa20547e10e45d 100644 --- a/aws/sdk/integration-tests/iam/Cargo.toml +++ b/aws/sdk/integration-tests/iam/Cargo.toml @@ -8,7 +8,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dev-dependencies] -aws-endpoint = { path = "../../build/aws-sdk/sdk/aws-endpoint" } aws-http = { path = "../../build/aws-sdk/sdk/aws-http"} aws-sdk-iam = { path = "../../build/aws-sdk/sdk/iam" } aws-smithy-client = { path = "../../build/aws-sdk/sdk/aws-smithy-client", features = ["test-util", "rustls"] } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RustSettings.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RustSettings.kt index f53c1245a81442903af62985590055c8bec4f296..c7f6dbe824d6a9fae9b8f4a07ce6b9cf26bb6b3c 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RustSettings.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/RustSettings.kt @@ -78,8 +78,7 @@ class RustSettings( val runtimeConfig: RuntimeConfig, val codegenConfig: CodegenConfig, val license: String?, - val examplesUri: String? = null, - private val model: Model + val examplesUri: String? = null ) { /** @@ -152,8 +151,7 @@ class RustSettings( runtimeConfig = RuntimeConfig.fromNode(runtimeConfig), codegenConfig, license = config.getStringMember(LICENSE).orNull()?.value, - examplesUri = config.getStringMember(EXAMPLES).orNull()?.value, - model = model + examplesUri = config.getStringMember(EXAMPLES).orNull()?.value ) } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/customizations/AllowLintsGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/customizations/AllowLintsGenerator.kt index 06c5afb2fea882594d17d3d485b8976a9a27dfd2..b80c5b0c25b161d760f5dc5ae3e8b1ba14341cb6 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/customizations/AllowLintsGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/customizations/AllowLintsGenerator.kt @@ -39,13 +39,16 @@ val AllowDocsLints = listOf( "bare_urls" ) -class AllowLintsGenerator : LibRsCustomization() { +class AllowLintsGenerator(private val bareLints: List = listOf(), private val clippyLints: List = ClippyAllowLints, private val docsLints: List = AllowDocsLints) : LibRsCustomization() { override fun section(section: LibRsSection) = when (section) { is LibRsSection.Attributes -> writable { - ClippyAllowLints.forEach { + bareLints.forEach { + Attribute.Custom("allow($it)", container = true).render(this) + } + clippyLints.forEach { Attribute.Custom("allow(clippy::$it)", container = true).render(this) } - AllowDocsLints.forEach { + docsLints.forEach { Attribute.Custom("allow(rustdoc::$it)", container = true).render(this) } // add a newline at the end diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/Rust.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/Rust.kt index bea78fe4ce9b1a66f8da2f4e7dfdd5423546c752..122d0b8626669a7656a974c06ec846bcec7f84b2 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/Rust.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/Rust.kt @@ -24,10 +24,12 @@ import software.amazon.smithy.rust.codegen.rustlang.rustBlock import software.amazon.smithy.rust.codegen.smithy.CodegenConfig import software.amazon.smithy.rust.codegen.smithy.DefaultPublicModules import software.amazon.smithy.rust.codegen.smithy.MaybeRenamed +import software.amazon.smithy.rust.codegen.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.smithy.RustCrate import software.amazon.smithy.rust.codegen.smithy.RustSettings import software.amazon.smithy.rust.codegen.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.smithy.SymbolVisitorConfig +import software.amazon.smithy.rust.codegen.smithy.letIf import software.amazon.smithy.rust.codegen.util.CommandFailed import software.amazon.smithy.rust.codegen.util.PANIC import software.amazon.smithy.rust.codegen.util.dq @@ -122,7 +124,7 @@ object TestWorkspace { * "cargo test".runCommand(path) * ``` */ -fun generatePluginContext(model: Model, additionalSettings: ObjectNode = ObjectNode.builder().build(), addModuleToEventStreamAllowList: Boolean = false): Pair { +fun generatePluginContext(model: Model, additionalSettings: ObjectNode = ObjectNode.builder().build(), addModuleToEventStreamAllowList: Boolean = false, service: String? = null, runtimeConfig: RuntimeConfig? = null): Pair { val testDir = TestWorkspace.subproject() val moduleName = "test_${testDir.nameWithoutExtension}" val testPath = testDir.toPath() @@ -132,11 +134,12 @@ fun generatePluginContext(model: Model, additionalSettings: ObjectNode = ObjectN .withMember("moduleVersion", Node.from("1.0.0")) .withMember("moduleDescription", Node.from("test")) .withMember("moduleAuthors", Node.fromStrings("testgenerator@smithy.com")) + .letIf(service != null) { it.withMember("service", service) } .withMember( "runtimeConfig", Node.objectNodeBuilder().withMember( "relativePath", - Node.from((TestRuntimeConfig.runtimeCrateLocation).path) + Node.from(((runtimeConfig ?: TestRuntimeConfig).runtimeCrateLocation).path) ).build() ) @@ -177,6 +180,11 @@ class TestWriterDelegator(private val fileManifest: FileManifest, symbolProvider val baseDir: Path = fileManifest.baseDir fun generatedFiles(): List = fileManifest.files.toList().sorted() + fun printGeneratedFiles() { + generatedFiles().forEach { path -> + println("file:///$path") + } + } } /** @@ -192,15 +200,13 @@ fun TestWriterDelegator.compileAndTest(runClippy: Boolean = false) { } """.asSmithyModel() this.finalize( - rustSettings(stubModel), + rustSettings(), stubModel, manifestCustomizations = emptyMap(), libRsCustomizations = listOf(), ) println("Generated files:") - generatedFiles().forEach { path -> - println("file:///$path") - } + printGeneratedFiles() try { "cargo fmt".runCommand(baseDir) } catch (e: Exception) { @@ -213,7 +219,7 @@ fun TestWriterDelegator.compileAndTest(runClippy: Boolean = false) { } } -fun TestWriterDelegator.rustSettings(stubModel: Model = "namespace test".asSmithyModel()) = +fun TestWriterDelegator.rustSettings() = RustSettings( ShapeId.from("fake#Fake"), "test_${baseDir.toFile().nameWithoutExtension}", @@ -223,8 +229,7 @@ fun TestWriterDelegator.rustSettings(stubModel: Model = "namespace test".asSmith moduleRepository = null, runtimeConfig = TestRuntimeConfig, codegenConfig = CodegenConfig(), - license = null, - model = stubModel + license = null ) fun String.shouldParseAsRust() { diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/TestConfigCustomization.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/TestConfigCustomization.kt index dcec996df19114e5427eb06915c8e5da46527d63..97809d08c49b1f788bbbe85eee062b7545e84606 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/TestConfigCustomization.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/TestConfigCustomization.kt @@ -21,20 +21,21 @@ fun stubConfigCustomization(name: String): ConfigCustomization { return object : ConfigCustomization() { override fun section(section: ServiceConfig): Writable = writable { when (section) { - ServiceConfig.ConfigStruct -> rust("$name: u64,") + ServiceConfig.ConfigStruct -> rust("_$name: u64,") ServiceConfig.ConfigImpl -> emptySection - ServiceConfig.BuilderStruct -> rust("$name: Option,") + ServiceConfig.BuilderStruct -> rust("_$name: Option,") ServiceConfig.BuilderImpl -> rust( """ + /// docs! pub fn $name(mut self, $name: u64) -> Self { - self.$name = Some($name); + self._$name = Some($name); self } """ ) ServiceConfig.BuilderBuild -> rust( """ - $name: self.$name.unwrap_or(123), + _$name: self._$name.unwrap_or(123), """ ) else -> emptySection diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/TestHelpers.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/TestHelpers.kt index 0612116e6cc2a9c7abb2f08f0ad5ab9fd3befccf..da7f5d2284cd9b2456ceb5031330858d19342e62 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/TestHelpers.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/TestHelpers.kt @@ -41,7 +41,6 @@ val TestSymbolVisitorConfig = SymbolVisitorConfig( ) fun testRustSettings( - model: Model, service: ShapeId = ShapeId.from("notrelevant#notrelevant"), moduleName: String = "test-module", moduleVersion: String = "notrelevant", @@ -62,8 +61,7 @@ fun testRustSettings( runtimeConfig, codegenConfig, license, - examplesUri, - model + examplesUri ) fun testSymbolProvider(model: Model, serviceShape: ServiceShape? = null): RustSymbolProvider = @@ -76,7 +74,7 @@ fun testSymbolProvider(model: Model, serviceShape: ServiceShape? = null): RustSy fun testCodegenContext( model: Model, serviceShape: ServiceShape? = null, - settings: RustSettings = testRustSettings(model), + settings: RustSettings = testRustSettings(), mode: CodegenMode = CodegenMode.Client ): CodegenContext = CodegenContext( model, diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/customizations/RetryConfigDecoratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/customizations/RetryConfigDecoratorTest.kt index ae791120625052686a66500c5fbf75e03c606902..f3e3a97d40e75797ea2c3c0bb315c09b60096394 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/customizations/RetryConfigDecoratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/customizations/RetryConfigDecoratorTest.kt @@ -36,7 +36,7 @@ internal class RetryConfigDecoratorTest { fun `generates a valid config`() { val model = RecursiveShapeBoxer.transform(OperationNormalizer.transform(baseModel)) val project = TestWorkspace.testProject() - val codegenContext = testCodegenContext(model, settings = project.rustSettings(model)) + val codegenContext = testCodegenContext(model, settings = project.rustSettings()) validateConfigCustomizations(RetryConfigProviderConfig(codegenContext), project) } diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/customizations/SleepImplDecoratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/customizations/SleepImplDecoratorTest.kt index cbb658dc81c3979724ed5b5787959fa1182cbcd7..ef020b64762281896b495569b647f1d8ba0b32d3 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/customizations/SleepImplDecoratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/customizations/SleepImplDecoratorTest.kt @@ -36,7 +36,7 @@ internal class SleepImplDecoratorTest { fun `generates a valid config`() { val model = RecursiveShapeBoxer.transform(OperationNormalizer.transform(baseModel)) val project = TestWorkspace.testProject() - val codegenContext = testCodegenContext(model, settings = project.rustSettings(model)) + val codegenContext = testCodegenContext(model, settings = project.rustSettings()) validateConfigCustomizations(SleepImplProviderConfig(codegenContext), project) } diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/customizations/TimeoutConfigDecoratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/customizations/TimeoutConfigDecoratorTest.kt index c194d5175434beaacec790d0d575c569c284b16a..fac3c44041992f91788269303366661b66c9a3f1 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/customizations/TimeoutConfigDecoratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/customizations/TimeoutConfigDecoratorTest.kt @@ -36,7 +36,7 @@ internal class TimeoutConfigDecoratorTest { fun `generates a valid config`() { val model = RecursiveShapeBoxer.transform(OperationNormalizer.transform(baseModel)) val project = TestWorkspace.testProject() - val codegenContext = testCodegenContext(model, settings = project.rustSettings(model)) + val codegenContext = testCodegenContext(model, settings = project.rustSettings()) validateConfigCustomizations(TimeoutConfigProviderConfig(codegenContext), project) } diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt index f3e27fa0dab1f136130d99794b1eee0f09cf5031..839c07d18b69a9e97e049e1bc4e83c1c41f11d68 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/EventStreamUnmarshallerGeneratorTest.kt @@ -30,7 +30,7 @@ class EventStreamUnmarshallerGeneratorTest { TestRuntimeConfig, test.serviceShape, ShapeId.from(testCase.protocolShapeId), - testRustSettings(test.model), + testRustSettings(), mode = testCase.mode ) val protocol = testCase.protocolBuilder(codegenContext) diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt index 504d493e4203bff1af3b606b827ff4f13f6a9447..3e2170e7783662f748b0daf199fdbff126912eac 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/EventStreamMarshallerGeneratorTest.kt @@ -32,7 +32,7 @@ class EventStreamMarshallerGeneratorTest { TestRuntimeConfig, test.serviceShape, ShapeId.from(testCase.protocolShapeId), - testRustSettings(test.model), + testRustSettings(), mode = testCase.mode ) val protocol = testCase.protocolBuilder(codegenContext) diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/transformers/RemoveEventStreamOperationsTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/transformers/RemoveEventStreamOperationsTest.kt index c7e13ea1bff6c034041cb569daf08cd284ec7971..97dc0049ee8b8b17b72e4a42cd80f60c97783463 100644 --- a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/transformers/RemoveEventStreamOperationsTest.kt +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/transformers/RemoveEventStreamOperationsTest.kt @@ -50,7 +50,6 @@ internal class RemoveEventStreamOperationsTest { val transformed = RemoveEventStreamOperations.transform( model, testRustSettings( - model, codegenConfig = CodegenConfig(eventStreamAllowList = setOf("not-test-module")), ) ) @@ -63,7 +62,6 @@ internal class RemoveEventStreamOperationsTest { val transformed = RemoveEventStreamOperations.transform( model, testRustSettings( - model, codegenConfig = CodegenConfig(eventStreamAllowList = setOf("test-module")), ) ) diff --git a/rust-runtime/aws-smithy-types/src/date_time/format.rs b/rust-runtime/aws-smithy-types/src/date_time/format.rs index cbecc559dbf49ccc36f37ff9d0b4a441f4429fdb..b102f137a48e037b3427abc18b049dff6471f7b7 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/format.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/format.rs @@ -467,7 +467,9 @@ mod tests { struct TestCase { canonical_seconds: String, canonical_nanos: u32, + #[allow(dead_code)] iso8601: String, + #[allow(dead_code)] error: bool, smithy_format_value: Option, }