mirror of https://github.com/smithy-lang/smithy-rs
Make service config just contain a `FrozenLayer` in the orchestrator mode (#2762)
## Motivation and Context Service config structs now only contain a `aws_smithy_types::config_bag::FrozenLayer` in the orchestrator mode (no changes for the middleware mode). ## Description This PR reduces the individual fields of service configs to contain just `FrozenLayer`. This makes service configs work more seamlessly with runtime plugins in the orchestrator mode. Note that service config _builder_ s still contain individual fields. We're planning to make them just contain `aws_smithy_types::config_bag::Layer`. To do that, though, we need to make `Layer` cloneable and that will be handled in a separate PR. For builders, the only change you will in the PR is that their `build` method will put fields into a `Layer`, freeze it, and pass it to service configs. This PR is marked as a breaking change because it's based on [another PR](https://github.com/awslabs/smithy-rs/pull/2728) that's also breaking change. ## Testing - [x] Passed tests in CI ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._ --------- Co-authored-by: Yuki Saito <awsaito@amazon.com> Co-authored-by: Zelda Hessler <zhessler@amazon.com>
This commit is contained in:
parent
b2bdcba57a
commit
2e472d068e
|
@ -1,3 +1,6 @@
|
|||
allowed_external_types = [
|
||||
"aws_smithy_async::rt::sleep::SharedAsyncSleep",
|
||||
"aws_smithy_types::config_bag::storable::Storable",
|
||||
"aws_smithy_types::config_bag::storable::StoreReplace",
|
||||
"aws_smithy_types::config_bag::storable::Storer",
|
||||
]
|
||||
|
|
|
@ -14,6 +14,7 @@ pub use lazy_caching::Builder as LazyBuilder;
|
|||
use no_caching::NoCredentialsCache;
|
||||
|
||||
use crate::provider::{future, SharedCredentialsProvider};
|
||||
use aws_smithy_types::config_bag::{Storable, StoreReplace};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Asynchronous Cached Credentials Provider
|
||||
|
@ -62,6 +63,10 @@ impl ProvideCachedCredentials for SharedCredentialsCache {
|
|||
}
|
||||
}
|
||||
|
||||
impl Storable for SharedCredentialsCache {
|
||||
type Storer = StoreReplace<SharedCredentialsCache>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum Inner {
|
||||
Lazy(lazy_caching::Builder),
|
||||
|
@ -122,3 +127,7 @@ impl CredentialsCache {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Storable for CredentialsCache {
|
||||
type Storer = StoreReplace<CredentialsCache>;
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ construct credentials from hardcoded values.
|
|||
//! ```
|
||||
|
||||
use crate::Credentials;
|
||||
use aws_smithy_types::config_bag::{Storable, StoreReplace};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Credentials provider errors
|
||||
|
@ -350,3 +351,7 @@ impl ProvideCredentials for SharedCredentialsProvider {
|
|||
self.0.provide_credentials()
|
||||
}
|
||||
}
|
||||
|
||||
impl Storable for SharedCredentialsProvider {
|
||||
type Storer = StoreReplace<SharedCredentialsProvider>;
|
||||
}
|
||||
|
|
|
@ -2,13 +2,16 @@ allowed_external_types = [
|
|||
"aws_credential_types::cache::CredentialsCache",
|
||||
"aws_credential_types::provider::SharedCredentialsProvider",
|
||||
"aws_smithy_async::rt::sleep::SharedAsyncSleep",
|
||||
"aws_smithy_async::time::TimeSource",
|
||||
"aws_smithy_async::time::SharedTimeSource",
|
||||
"aws_smithy_async::time::TimeSource",
|
||||
"aws_smithy_client::http_connector",
|
||||
"aws_smithy_client::http_connector::HttpConnector",
|
||||
"aws_smithy_http::endpoint::Endpoint",
|
||||
"aws_smithy_http::endpoint::EndpointPrefix",
|
||||
"aws_smithy_http::endpoint::error::InvalidEndpointError",
|
||||
"aws_smithy_types::config_bag::storable::Storable",
|
||||
"aws_smithy_types::config_bag::storable::StoreReplace",
|
||||
"aws_smithy_types::config_bag::storable::Storer",
|
||||
"aws_smithy_types::retry::RetryConfig",
|
||||
"aws_smithy_types::timeout::TimeoutConfig",
|
||||
"http::uri::Uri",
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
//! New-type for a configurable app name.
|
||||
|
||||
use aws_smithy_types::config_bag::{Storable, StoreReplace};
|
||||
use std::borrow::Cow;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
@ -38,6 +39,10 @@ impl fmt::Display for AppName {
|
|||
}
|
||||
}
|
||||
|
||||
impl Storable for AppName {
|
||||
type Storer = StoreReplace<AppName>;
|
||||
}
|
||||
|
||||
impl AppName {
|
||||
/// Creates a new app name.
|
||||
///
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
//! Newtypes for endpoint-related parameters
|
||||
//!
|
||||
//! Parameters require newtypes so they have distinct types when stored in layers in config bag.
|
||||
|
||||
use aws_smithy_types::config_bag::{Storable, StoreReplace};
|
||||
|
||||
/// Newtype for `use_fips`
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UseFips(pub bool);
|
||||
impl Storable for UseFips {
|
||||
type Storer = StoreReplace<UseFips>;
|
||||
}
|
||||
|
||||
/// Newtype for `use_dual_stack`
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct UseDualStack(pub bool);
|
||||
impl Storable for UseDualStack {
|
||||
type Storer = StoreReplace<UseDualStack>;
|
||||
}
|
||||
|
||||
/// Newtype for `endpoint_url`
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EndpointUrl(pub String);
|
||||
impl Storable for EndpointUrl {
|
||||
type Storer = StoreReplace<EndpointUrl>;
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
pub mod app_name;
|
||||
pub mod build_metadata;
|
||||
pub mod endpoint_config;
|
||||
#[doc(hidden)]
|
||||
pub mod os_shim_internal;
|
||||
pub mod region;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
//! Region type for determining the endpoint to send requests to.
|
||||
|
||||
use aws_smithy_types::config_bag::{Storable, StoreReplace};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
|
@ -35,6 +36,10 @@ impl Display for Region {
|
|||
}
|
||||
}
|
||||
|
||||
impl Storable for Region {
|
||||
type Storer = StoreReplace<Region>;
|
||||
}
|
||||
|
||||
impl Region {
|
||||
/// Creates a new `Region` from the given string.
|
||||
pub fn new(region: impl Into<Cow<'static, str>>) -> Self {
|
||||
|
|
|
@ -27,7 +27,7 @@ class CredentialsCacheDecorator : ClientCodegenDecorator {
|
|||
codegenContext: ClientCodegenContext,
|
||||
baseCustomizations: List<ConfigCustomization>,
|
||||
): List<ConfigCustomization> {
|
||||
return baseCustomizations + CredentialCacheConfig(codegenContext.runtimeConfig)
|
||||
return baseCustomizations + CredentialCacheConfig(codegenContext)
|
||||
}
|
||||
|
||||
override fun operationCustomizations(
|
||||
|
@ -49,44 +49,65 @@ class CredentialsCacheDecorator : ClientCodegenDecorator {
|
|||
/**
|
||||
* Add a `.credentials_cache` field and builder to the `Config` for a given service
|
||||
*/
|
||||
class CredentialCacheConfig(runtimeConfig: RuntimeConfig) : ConfigCustomization() {
|
||||
class CredentialCacheConfig(codegenContext: ClientCodegenContext) : ConfigCustomization() {
|
||||
private val runtimeConfig = codegenContext.runtimeConfig
|
||||
private val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
private val codegenScope = arrayOf(
|
||||
"cache" to AwsRuntimeType.awsCredentialTypes(runtimeConfig).resolve("cache"),
|
||||
"provider" to AwsRuntimeType.awsCredentialTypes(runtimeConfig).resolve("provider"),
|
||||
"CredentialsCache" to AwsRuntimeType.awsCredentialTypes(runtimeConfig).resolve("cache::CredentialsCache"),
|
||||
"DefaultProvider" to defaultProvider(),
|
||||
"SharedCredentialsCache" to AwsRuntimeType.awsCredentialTypes(runtimeConfig).resolve("cache::SharedCredentialsCache"),
|
||||
"SharedCredentialsProvider" to AwsRuntimeType.awsCredentialTypes(runtimeConfig).resolve("provider::SharedCredentialsProvider"),
|
||||
)
|
||||
|
||||
override fun section(section: ServiceConfig) = writable {
|
||||
when (section) {
|
||||
ServiceConfig.ConfigStruct -> rustTemplate(
|
||||
"""pub(crate) credentials_cache: #{cache}::SharedCredentialsCache,""",
|
||||
*codegenScope,
|
||||
)
|
||||
|
||||
ServiceConfig.ConfigImpl -> rustTemplate(
|
||||
"""
|
||||
/// Returns the credentials cache.
|
||||
pub fn credentials_cache(&self) -> #{cache}::SharedCredentialsCache {
|
||||
self.credentials_cache.clone()
|
||||
ServiceConfig.ConfigStruct -> {
|
||||
if (runtimeMode.defaultToMiddleware) {
|
||||
rustTemplate(
|
||||
"""pub(crate) credentials_cache: #{SharedCredentialsCache},""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
|
||||
ServiceConfig.ConfigImpl -> {
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns the credentials cache.
|
||||
pub fn credentials_cache(&self) -> #{SharedCredentialsCache} {
|
||||
self.inner.load::<#{SharedCredentialsCache}>().expect("credentials cache should be set").clone()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns the credentials cache.
|
||||
pub fn credentials_cache(&self) -> #{SharedCredentialsCache} {
|
||||
self.credentials_cache.clone()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ServiceConfig.BuilderStruct ->
|
||||
rustTemplate("credentials_cache: Option<#{cache}::CredentialsCache>,", *codegenScope)
|
||||
rustTemplate("credentials_cache: Option<#{CredentialsCache}>,", *codegenScope)
|
||||
|
||||
ServiceConfig.BuilderImpl -> {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Sets the credentials cache for this service
|
||||
pub fn credentials_cache(mut self, credentials_cache: #{cache}::CredentialsCache) -> Self {
|
||||
pub fn credentials_cache(mut self, credentials_cache: #{CredentialsCache}) -> Self {
|
||||
self.set_credentials_cache(Some(credentials_cache));
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the credentials cache for this service
|
||||
pub fn set_credentials_cache(&mut self, credentials_cache: Option<#{cache}::CredentialsCache>) -> &mut Self {
|
||||
pub fn set_credentials_cache(&mut self, credentials_cache: Option<#{CredentialsCache}>) -> &mut Self {
|
||||
self.credentials_cache = credentials_cache;
|
||||
self
|
||||
}
|
||||
|
@ -95,29 +116,56 @@ class CredentialCacheConfig(runtimeConfig: RuntimeConfig) : ConfigCustomization(
|
|||
)
|
||||
}
|
||||
|
||||
ServiceConfig.BuilderBuild -> rustTemplate(
|
||||
"""
|
||||
credentials_cache: self
|
||||
.credentials_cache
|
||||
.unwrap_or_else({
|
||||
let sleep = self.sleep_impl.clone();
|
||||
|| match sleep {
|
||||
Some(sleep) => {
|
||||
#{cache}::CredentialsCache::lazy_builder()
|
||||
.sleep(sleep)
|
||||
.into_credentials_cache()
|
||||
}
|
||||
None => #{cache}::CredentialsCache::lazy(),
|
||||
}
|
||||
})
|
||||
.create_cache(
|
||||
self.credentials_provider.unwrap_or_else(|| {
|
||||
#{provider}::SharedCredentialsProvider::new(#{DefaultProvider})
|
||||
})
|
||||
),
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
ServiceConfig.BuilderBuild -> {
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
layer.store_put(
|
||||
self.credentials_cache
|
||||
.unwrap_or_else({
|
||||
let sleep = self.sleep_impl.clone();
|
||||
|| match sleep {
|
||||
Some(sleep) => {
|
||||
#{CredentialsCache}::lazy_builder()
|
||||
.sleep(sleep)
|
||||
.into_credentials_cache()
|
||||
}
|
||||
None => #{CredentialsCache}::lazy(),
|
||||
}
|
||||
})
|
||||
.create_cache(self.credentials_provider.unwrap_or_else(|| {
|
||||
#{SharedCredentialsProvider}::new(#{DefaultProvider})
|
||||
})),
|
||||
);
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
"""
|
||||
credentials_cache: self
|
||||
.credentials_cache
|
||||
.unwrap_or_else({
|
||||
let sleep = self.sleep_impl.clone();
|
||||
|| match sleep {
|
||||
Some(sleep) => {
|
||||
#{CredentialsCache}::lazy_builder()
|
||||
.sleep(sleep)
|
||||
.into_credentials_cache()
|
||||
}
|
||||
None => #{CredentialsCache}::lazy(),
|
||||
}
|
||||
})
|
||||
.create_cache(
|
||||
self.credentials_provider.unwrap_or_else(|| {
|
||||
#{SharedCredentialsProvider}::new(#{DefaultProvider})
|
||||
})
|
||||
),
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
else -> emptySection
|
||||
}
|
||||
|
|
|
@ -22,18 +22,21 @@ import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointRulese
|
|||
import software.amazon.smithy.rust.codegen.client.smithy.endpoint.rustName
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigParam
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.configParamNewtype
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.standardConfigParam
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.Writable
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.docs
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rust
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.writable
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.customize.AdHocCustomization
|
||||
import software.amazon.smithy.rust.codegen.core.util.PANIC
|
||||
import software.amazon.smithy.rust.codegen.core.util.dq
|
||||
import software.amazon.smithy.rust.codegen.core.util.extendIf
|
||||
import software.amazon.smithy.rust.codegen.core.util.orNull
|
||||
import software.amazon.smithy.rust.codegen.core.util.toPascalCase
|
||||
import java.util.Optional
|
||||
|
||||
/** load a builtIn parameter from a ruleset by name */
|
||||
|
@ -48,14 +51,27 @@ fun ClientCodegenContext.getBuiltIn(builtIn: String): Parameter? {
|
|||
return rules.getBuiltIn(builtIn)
|
||||
}
|
||||
|
||||
private fun toConfigParam(parameter: Parameter): ConfigParam = ConfigParam(
|
||||
parameter.name.rustName(),
|
||||
when (parameter.type!!) {
|
||||
ParameterType.STRING -> RuntimeType.String.toSymbol()
|
||||
ParameterType.BOOLEAN -> RuntimeType.Bool.toSymbol()
|
||||
},
|
||||
parameter.documentation.orNull()?.let { writable { docs(it) } },
|
||||
)
|
||||
private fun promotedBuiltins(parameter: Parameter) =
|
||||
parameter == Builtins.FIPS || parameter == Builtins.DUALSTACK || parameter == Builtins.SDK_ENDPOINT
|
||||
|
||||
private fun ConfigParam.Builder.toConfigParam(parameter: Parameter, runtimeConfig: RuntimeConfig): ConfigParam =
|
||||
this.name(this.name ?: parameter.name.rustName())
|
||||
.type(
|
||||
when (parameter.type!!) {
|
||||
ParameterType.STRING -> RuntimeType.String.toSymbol()
|
||||
ParameterType.BOOLEAN -> RuntimeType.Bool.toSymbol()
|
||||
},
|
||||
)
|
||||
.newtype(
|
||||
when (promotedBuiltins(parameter)) {
|
||||
true -> AwsRuntimeType.awsTypes(runtimeConfig)
|
||||
.resolve("endpoint_config::${this.name!!.toPascalCase()}")
|
||||
|
||||
false -> configParamNewtype(this.name!!.toPascalCase(), this.type!!, runtimeConfig)
|
||||
},
|
||||
)
|
||||
.setterDocs(this.setterDocs ?: parameter.documentation.orNull()?.let { writable { docs(it) } })
|
||||
.build()
|
||||
|
||||
fun Model.loadBuiltIn(serviceId: ShapeId, builtInSrc: Parameter): Parameter? {
|
||||
val model = this
|
||||
|
@ -82,14 +98,14 @@ fun Model.sdkConfigSetter(
|
|||
}
|
||||
|
||||
/**
|
||||
* Create a client codegen decorator that creates bindings for a builtIn parameter. Optionally, you can provide [clientParam]
|
||||
* which allows control over the config parameter that will be generated.
|
||||
* Create a client codegen decorator that creates bindings for a builtIn parameter. Optionally, you can provide
|
||||
* [clientParam.Builder] which allows control over the config parameter that will be generated.
|
||||
*/
|
||||
fun decoratorForBuiltIn(
|
||||
builtIn: Parameter,
|
||||
clientParam: ConfigParam? = null,
|
||||
clientParamBuilder: ConfigParam.Builder? = null,
|
||||
): ClientCodegenDecorator {
|
||||
val nameOverride = clientParam?.name
|
||||
val nameOverride = clientParamBuilder?.name
|
||||
val name = nameOverride ?: builtIn.name.rustName()
|
||||
return object : ClientCodegenDecorator {
|
||||
override val name: String = "Auto${builtIn.builtIn.get()}"
|
||||
|
@ -100,7 +116,7 @@ fun decoratorForBuiltIn(
|
|||
|
||||
override fun extraSections(codegenContext: ClientCodegenContext): List<AdHocCustomization> {
|
||||
return listOfNotNull(
|
||||
codegenContext.model.sdkConfigSetter(codegenContext.serviceShape.id, builtIn, clientParam?.name),
|
||||
codegenContext.model.sdkConfigSetter(codegenContext.serviceShape.id, builtIn, clientParamBuilder?.name),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -110,7 +126,9 @@ fun decoratorForBuiltIn(
|
|||
): List<ConfigCustomization> {
|
||||
return baseCustomizations.extendIf(rulesetContainsBuiltIn(codegenContext)) {
|
||||
standardConfigParam(
|
||||
clientParam ?: toConfigParam(builtIn),
|
||||
clientParamBuilder?.toConfigParam(builtIn, codegenContext.runtimeConfig) ?: ConfigParam.Builder()
|
||||
.toConfigParam(builtIn, codegenContext.runtimeConfig),
|
||||
codegenContext,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -120,11 +138,16 @@ fun decoratorForBuiltIn(
|
|||
override fun loadBuiltInFromServiceConfig(parameter: Parameter, configRef: String): Writable? =
|
||||
when (parameter.builtIn) {
|
||||
builtIn.builtIn -> writable {
|
||||
rust("$configRef.$name")
|
||||
if (codegenContext.smithyRuntimeMode.defaultToOrchestrator) {
|
||||
rust("$configRef.$name()")
|
||||
} else {
|
||||
rust("$configRef.$name")
|
||||
}
|
||||
if (parameter.type == ParameterType.STRING) {
|
||||
rust(".clone()")
|
||||
}
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
@ -173,6 +196,6 @@ val PromotedBuiltInsDecorators =
|
|||
decoratorForBuiltIn(Builtins.DUALSTACK),
|
||||
decoratorForBuiltIn(
|
||||
Builtins.SDK_ENDPOINT,
|
||||
ConfigParam("endpoint_url", RuntimeType.String.toSymbol(), endpointUrlDocs),
|
||||
ConfigParam.Builder().name("endpoint_url").type(RuntimeType.String.toSymbol()).setterDocs(endpointUrlDocs),
|
||||
),
|
||||
).toTypedArray()
|
||||
|
|
|
@ -13,7 +13,6 @@ import software.amazon.smithy.rust.codegen.core.rustlang.Writable
|
|||
import software.amazon.smithy.rust.codegen.core.rustlang.rust
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.writable
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
|
||||
import software.amazon.smithy.rust.codegen.core.util.letIf
|
||||
|
||||
|
@ -32,9 +31,10 @@ class HttpConnectorDecorator : ClientCodegenDecorator {
|
|||
}
|
||||
|
||||
class HttpConnectorConfigCustomization(
|
||||
codegenContext: CodegenContext,
|
||||
codegenContext: ClientCodegenContext,
|
||||
) : ConfigCustomization() {
|
||||
private val runtimeConfig = codegenContext.runtimeConfig
|
||||
private val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
private val moduleUseName = codegenContext.moduleUseName()
|
||||
private val codegenScope = arrayOf(
|
||||
"HttpConnector" to RuntimeType.smithyClient(runtimeConfig).resolve("http_connector::HttpConnector"),
|
||||
|
@ -43,18 +43,32 @@ class HttpConnectorConfigCustomization(
|
|||
override fun section(section: ServiceConfig): Writable {
|
||||
return when (section) {
|
||||
is ServiceConfig.ConfigStruct -> writable {
|
||||
rustTemplate("http_connector: Option<#{HttpConnector}>,", *codegenScope)
|
||||
if (runtimeMode.defaultToMiddleware) {
|
||||
rustTemplate("http_connector: Option<#{HttpConnector}>,", *codegenScope)
|
||||
}
|
||||
}
|
||||
is ServiceConfig.ConfigImpl -> writable {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Return an [`HttpConnector`](#{HttpConnector}) to use when making requests, if any.
|
||||
pub fn http_connector(&self) -> Option<&#{HttpConnector}> {
|
||||
self.http_connector.as_ref()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Return an [`HttpConnector`](#{HttpConnector}) to use when making requests, if any.
|
||||
pub fn http_connector(&self) -> Option<&#{HttpConnector}> {
|
||||
self.inner.load::<#{HttpConnector}>()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Return an [`HttpConnector`](#{HttpConnector}) to use when making requests, if any.
|
||||
pub fn http_connector(&self) -> Option<&#{HttpConnector}> {
|
||||
self.http_connector.as_ref()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
is ServiceConfig.BuilderStruct -> writable {
|
||||
rustTemplate("http_connector: Option<#{HttpConnector}>,", *codegenScope)
|
||||
|
@ -145,7 +159,11 @@ class HttpConnectorConfigCustomization(
|
|||
)
|
||||
}
|
||||
is ServiceConfig.BuilderBuild -> writable {
|
||||
rust("http_connector: self.http_connector,")
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rust("layer.store_or_unset(self.http_connector);")
|
||||
} else {
|
||||
rust("http_connector: self.http_connector,")
|
||||
}
|
||||
}
|
||||
else -> emptySection
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import software.amazon.smithy.rust.codegen.core.rustlang.Writable
|
|||
import software.amazon.smithy.rust.codegen.core.rustlang.rust
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.writable
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RustCrate
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.customize.AdHocCustomization
|
||||
|
@ -131,7 +130,11 @@ class RegionDecorator : ClientCodegenDecorator {
|
|||
override fun loadBuiltInFromServiceConfig(parameter: Parameter, configRef: String): Writable? {
|
||||
return when (parameter.builtIn) {
|
||||
Builtins.REGION.builtIn -> writable {
|
||||
rust("$configRef.region.as_ref().map(|r|r.as_ref().to_owned())")
|
||||
if (codegenContext.smithyRuntimeMode.defaultToOrchestrator) {
|
||||
rust("$configRef.region().as_ref().map(|r|r.as_ref().to_owned())")
|
||||
} else {
|
||||
rust("$configRef.region.as_ref().map(|r|r.as_ref().to_owned())")
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
@ -153,22 +156,41 @@ class RegionDecorator : ClientCodegenDecorator {
|
|||
}
|
||||
}
|
||||
|
||||
class RegionProviderConfig(codegenContext: CodegenContext) : ConfigCustomization() {
|
||||
class RegionProviderConfig(codegenContext: ClientCodegenContext) : ConfigCustomization() {
|
||||
private val region = region(codegenContext.runtimeConfig)
|
||||
private val moduleUseName = codegenContext.moduleUseName()
|
||||
private val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
private val codegenScope = arrayOf("Region" to region.resolve("Region"))
|
||||
override fun section(section: ServiceConfig) = writable {
|
||||
when (section) {
|
||||
ServiceConfig.ConfigStruct -> rustTemplate("pub(crate) region: Option<#{Region}>,", *codegenScope)
|
||||
ServiceConfig.ConfigImpl -> rustTemplate(
|
||||
"""
|
||||
/// Returns the AWS region, if it was provided.
|
||||
pub fn region(&self) -> Option<&#{Region}> {
|
||||
self.region.as_ref()
|
||||
ServiceConfig.ConfigStruct -> {
|
||||
if (runtimeMode.defaultToMiddleware) {
|
||||
rustTemplate("pub(crate) region: Option<#{Region}>,", *codegenScope)
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
ServiceConfig.ConfigImpl -> {
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns the AWS region, if it was provided.
|
||||
pub fn region(&self) -> Option<&#{Region}> {
|
||||
self.inner.load::<#{Region}>()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns the AWS region, if it was provided.
|
||||
pub fn region(&self) -> Option<&#{Region}> {
|
||||
self.region.as_ref()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ServiceConfig.BuilderStruct ->
|
||||
rustTemplate("pub(crate) region: Option<#{Region}>,", *codegenScope)
|
||||
|
@ -201,10 +223,13 @@ class RegionProviderConfig(codegenContext: CodegenContext) : ConfigCustomization
|
|||
*codegenScope,
|
||||
)
|
||||
|
||||
ServiceConfig.BuilderBuild -> rustTemplate(
|
||||
"""region: self.region,""",
|
||||
*codegenScope,
|
||||
)
|
||||
ServiceConfig.BuilderBuild -> {
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rust("layer.store_or_unset(self.region);")
|
||||
} else {
|
||||
rust("region: self.region,")
|
||||
}
|
||||
}
|
||||
|
||||
else -> emptySection
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.Writable
|
|||
import software.amazon.smithy.rust.codegen.core.rustlang.rust
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.writable
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RustCrate
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.customizations.CrateVersionCustomization
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.customize.AdHocCustomization
|
||||
|
@ -40,7 +40,7 @@ class UserAgentDecorator : ClientCodegenDecorator {
|
|||
codegenContext: ClientCodegenContext,
|
||||
baseCustomizations: List<ConfigCustomization>,
|
||||
): List<ConfigCustomization> {
|
||||
return baseCustomizations + AppNameCustomization(codegenContext.runtimeConfig)
|
||||
return baseCustomizations + AppNameCustomization(codegenContext)
|
||||
}
|
||||
|
||||
override fun operationCustomizations(
|
||||
|
@ -149,15 +149,18 @@ class UserAgentDecorator : ClientCodegenDecorator {
|
|||
}
|
||||
}
|
||||
|
||||
private class AppNameCustomization(runtimeConfig: RuntimeConfig) : ConfigCustomization() {
|
||||
private class AppNameCustomization(codegenContext: ClientCodegenContext) : ConfigCustomization() {
|
||||
private val runtimeConfig = codegenContext.runtimeConfig
|
||||
private val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
private val codegenScope = arrayOf(
|
||||
*preludeScope,
|
||||
"AppName" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("app_name::AppName"),
|
||||
)
|
||||
|
||||
override fun section(section: ServiceConfig): Writable =
|
||||
when (section) {
|
||||
is ServiceConfig.BuilderStruct -> writable {
|
||||
rustTemplate("app_name: Option<#{AppName}>,", *codegenScope)
|
||||
rustTemplate("app_name: #{Option}<#{AppName}>,", *codegenScope)
|
||||
}
|
||||
|
||||
is ServiceConfig.BuilderImpl -> writable {
|
||||
|
@ -176,7 +179,7 @@ class UserAgentDecorator : ClientCodegenDecorator {
|
|||
///
|
||||
/// This _optional_ name is used to identify the application in the user agent that
|
||||
/// gets sent along with requests.
|
||||
pub fn set_app_name(&mut self, app_name: Option<#{AppName}>) -> &mut Self {
|
||||
pub fn set_app_name(&mut self, app_name: #{Option}<#{AppName}>) -> &mut Self {
|
||||
self.app_name = app_name;
|
||||
self
|
||||
}
|
||||
|
@ -186,26 +189,47 @@ class UserAgentDecorator : ClientCodegenDecorator {
|
|||
}
|
||||
|
||||
is ServiceConfig.BuilderBuild -> writable {
|
||||
rust("app_name: self.app_name,")
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rust("layer.store_or_unset(self.app_name);")
|
||||
} else {
|
||||
rust("app_name: self.app_name,")
|
||||
}
|
||||
}
|
||||
|
||||
is ServiceConfig.ConfigStruct -> writable {
|
||||
rustTemplate("app_name: Option<#{AppName}>,", *codegenScope)
|
||||
if (runtimeMode.defaultToMiddleware) {
|
||||
rustTemplate("app_name: #{Option}<#{AppName}>,", *codegenScope)
|
||||
}
|
||||
}
|
||||
|
||||
is ServiceConfig.ConfigImpl -> writable {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns the name of the app that is using the client, if it was provided.
|
||||
///
|
||||
/// This _optional_ name is used to identify the application in the user agent that
|
||||
/// gets sent along with requests.
|
||||
pub fn app_name(&self) -> Option<&#{AppName}> {
|
||||
self.app_name.as_ref()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns the name of the app that is using the client, if it was provided.
|
||||
///
|
||||
/// This _optional_ name is used to identify the application in the user agent that
|
||||
/// gets sent along with requests.
|
||||
pub fn app_name(&self) -> #{Option}<&#{AppName}> {
|
||||
self.inner.load::<#{AppName}>()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns the name of the app that is using the client, if it was provided.
|
||||
///
|
||||
/// This _optional_ name is used to identify the application in the user agent that
|
||||
/// gets sent along with requests.
|
||||
pub fn app_name(&self) -> #{Option}<&#{AppName}> {
|
||||
self.app_name.as_ref()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
else -> emptySection
|
||||
|
|
|
@ -52,6 +52,7 @@ class TimestreamDecorator : ClientCodegenDecorator {
|
|||
Visibility.PUBLIC,
|
||||
CargoDependency.Tokio.copy(scope = DependencyScope.Compile, features = setOf("sync")),
|
||||
)
|
||||
val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
rustCrate.lib {
|
||||
// helper function to resolve an endpoint given a base client
|
||||
rustTemplate(
|
||||
|
@ -62,7 +63,7 @@ class TimestreamDecorator : ClientCodegenDecorator {
|
|||
#{ResolveEndpointError}::from_source("failed to call describe_endpoints", e)
|
||||
})?;
|
||||
let endpoint = describe_endpoints.endpoints().unwrap().get(0).unwrap();
|
||||
let expiry = client.conf().time_source.now() + #{Duration}::from_secs(endpoint.cache_period_in_minutes() as u64 * 60);
|
||||
let expiry = client.conf().time_source().now() + #{Duration}::from_secs(endpoint.cache_period_in_minutes() as u64 * 60);
|
||||
Ok((
|
||||
#{Endpoint}::builder()
|
||||
.url(format!("https://{}", endpoint.address().unwrap()))
|
||||
|
@ -78,7 +79,7 @@ class TimestreamDecorator : ClientCodegenDecorator {
|
|||
pub async fn enable_endpoint_discovery(self) -> #{Result}<(Self, #{endpoint_discovery}::ReloadEndpoint), #{ResolveEndpointError}> {
|
||||
let mut new_conf = self.conf().clone();
|
||||
let sleep = self.conf().sleep_impl().expect("sleep impl must be provided");
|
||||
let time = self.conf().time_source.clone();
|
||||
let time = self.conf().time_source();
|
||||
let (resolver, reloader) = #{endpoint_discovery}::create_cache(
|
||||
move || {
|
||||
let client = self.clone();
|
||||
|
@ -92,7 +93,6 @@ class TimestreamDecorator : ClientCodegenDecorator {
|
|||
Ok((Self::from_conf(new_conf), reloader))
|
||||
}
|
||||
}
|
||||
|
||||
""",
|
||||
"endpoint_discovery" to endpointDiscovery.toType(),
|
||||
"SystemTime" to RuntimeType.std.resolve("time::SystemTime"),
|
||||
|
|
|
@ -5,12 +5,18 @@
|
|||
|
||||
package software.amazon.smithy.rustsdk
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.SmithyRuntimeMode
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.validateConfigCustomizations
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.withSmithyRuntimeMode
|
||||
|
||||
internal class CredentialProviderConfigTest {
|
||||
@Test
|
||||
fun `generates a valid config`() {
|
||||
validateConfigCustomizations(CredentialProviderConfig(AwsTestRuntimeConfig))
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = ["middleware", "orchestrator"])
|
||||
fun `generates a valid config`(smithyRuntimeModeStr: String) {
|
||||
val smithyRuntimeMode = SmithyRuntimeMode.fromString(smithyRuntimeModeStr)
|
||||
val codegenContext = awsTestCodegenContext().withSmithyRuntimeMode(smithyRuntimeMode)
|
||||
validateConfigCustomizations(codegenContext, CredentialProviderConfig(codegenContext.runtimeConfig))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,15 +5,20 @@
|
|||
|
||||
package software.amazon.smithy.rustsdk
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.SmithyRuntimeMode
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.validateConfigCustomizations
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.withSmithyRuntimeMode
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace
|
||||
|
||||
class HttpConnectorConfigCustomizationTest {
|
||||
@Test
|
||||
fun `generates a valid config`() {
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = ["middleware", "orchestrator"])
|
||||
fun `generates a valid config`(smithyRuntimeModeStr: String) {
|
||||
val project = TestWorkspace.testProject()
|
||||
val codegenContext = awsTestCodegenContext()
|
||||
validateConfigCustomizations(HttpConnectorConfigCustomization(codegenContext), project)
|
||||
val smithyRuntimeMode = SmithyRuntimeMode.fromString(smithyRuntimeModeStr)
|
||||
val codegenContext = awsTestCodegenContext().withSmithyRuntimeMode(smithyRuntimeMode)
|
||||
validateConfigCustomizations(codegenContext, HttpConnectorConfigCustomization(codegenContext), project)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,22 +5,27 @@
|
|||
|
||||
package software.amazon.smithy.rustsdk
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.SmithyRuntimeMode
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.testClientRustSettings
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.validateConfigCustomizations
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.withSmithyRuntimeMode
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.rustSettings
|
||||
|
||||
internal class RegionProviderConfigTest {
|
||||
@Test
|
||||
fun `generates a valid config`() {
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = ["middleware", "orchestrator"])
|
||||
fun `generates a valid config`(smithyRuntimeModeStr: String) {
|
||||
val project = TestWorkspace.testProject()
|
||||
val smithyRuntimeMode = SmithyRuntimeMode.fromString(smithyRuntimeModeStr)
|
||||
val codegenContext = awsTestCodegenContext(
|
||||
settings = testClientRustSettings(
|
||||
moduleName = project.rustSettings().moduleName,
|
||||
runtimeConfig = AwsTestRuntimeConfig,
|
||||
),
|
||||
)
|
||||
validateConfigCustomizations(RegionProviderConfig(codegenContext), project)
|
||||
).withSmithyRuntimeMode(smithyRuntimeMode)
|
||||
validateConfigCustomizations(codegenContext, RegionProviderConfig(codegenContext), project)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,19 +5,31 @@
|
|||
|
||||
package software.amazon.smithy.rustsdk
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import software.amazon.smithy.aws.traits.auth.SigV4Trait
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.SmithyRuntimeMode
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.stubConfigProject
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.testClientRustSettings
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.withSmithyRuntimeMode
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.unitTest
|
||||
|
||||
internal class SigV4SigningDecoratorTest {
|
||||
@Test
|
||||
fun `generates a valid config`() {
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = ["middleware", "orchestrator"])
|
||||
fun `generates a valid config`(smithyRuntimeModeStr: String) {
|
||||
val smithyRuntimeMode = SmithyRuntimeMode.fromString(smithyRuntimeModeStr)
|
||||
val codegenContext = awsTestCodegenContext(
|
||||
settings = testClientRustSettings(
|
||||
runtimeConfig = AwsTestRuntimeConfig,
|
||||
),
|
||||
).withSmithyRuntimeMode(smithyRuntimeMode)
|
||||
val project = stubConfigProject(
|
||||
codegenContext,
|
||||
SigV4SigningConfig(
|
||||
AwsTestRuntimeConfig,
|
||||
codegenContext.runtimeConfig,
|
||||
true,
|
||||
SigV4Trait.builder().name("test-service").build(),
|
||||
),
|
||||
|
|
|
@ -25,6 +25,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
|
|||
import software.amazon.smithy.rust.codegen.core.rustlang.writable
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RustCrate
|
||||
import software.amazon.smithy.rust.codegen.core.util.letIf
|
||||
|
||||
|
@ -46,7 +47,7 @@ class ApiKeyAuthDecorator : ClientCodegenDecorator {
|
|||
baseCustomizations: List<ConfigCustomization>,
|
||||
): List<ConfigCustomization> {
|
||||
return baseCustomizations.letIf(applies(codegenContext)) { customizations ->
|
||||
customizations + ApiKeyConfigCustomization(codegenContext.runtimeConfig)
|
||||
customizations + ApiKeyConfigCustomization(codegenContext)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,15 +157,18 @@ private class ApiKeyOperationCustomization(private val runtimeConfig: RuntimeCon
|
|||
}
|
||||
}
|
||||
|
||||
private class ApiKeyConfigCustomization(runtimeConfig: RuntimeConfig) : ConfigCustomization() {
|
||||
private class ApiKeyConfigCustomization(codegenContext: ClientCodegenContext) : ConfigCustomization() {
|
||||
val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
val runtimeConfig = codegenContext.runtimeConfig
|
||||
private val codegenScope = arrayOf(
|
||||
*preludeScope,
|
||||
"ApiKey" to apiKey(runtimeConfig),
|
||||
)
|
||||
|
||||
override fun section(section: ServiceConfig): Writable =
|
||||
when (section) {
|
||||
is ServiceConfig.BuilderStruct -> writable {
|
||||
rustTemplate("api_key: Option<#{ApiKey}>,", *codegenScope)
|
||||
rustTemplate("api_key: #{Option}<#{ApiKey}>,", *codegenScope)
|
||||
}
|
||||
is ServiceConfig.BuilderImpl -> writable {
|
||||
rustTemplate(
|
||||
|
@ -176,7 +180,7 @@ private class ApiKeyConfigCustomization(runtimeConfig: RuntimeConfig) : ConfigCu
|
|||
}
|
||||
|
||||
/// Sets the API key that will be used by the client.
|
||||
pub fn set_api_key(&mut self, api_key: Option<#{ApiKey}>) -> &mut Self {
|
||||
pub fn set_api_key(&mut self, api_key: #{Option}<#{ApiKey}>) -> &mut Self {
|
||||
self.api_key = api_key;
|
||||
self
|
||||
}
|
||||
|
@ -185,21 +189,39 @@ private class ApiKeyConfigCustomization(runtimeConfig: RuntimeConfig) : ConfigCu
|
|||
)
|
||||
}
|
||||
is ServiceConfig.BuilderBuild -> writable {
|
||||
rust("api_key: self.api_key,")
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rust("layer.store_or_unset(self.api_key);")
|
||||
} else {
|
||||
rust("api_key: self.api_key,")
|
||||
}
|
||||
}
|
||||
is ServiceConfig.ConfigStruct -> writable {
|
||||
rustTemplate("api_key: Option<#{ApiKey}>,", *codegenScope)
|
||||
if (runtimeMode.defaultToMiddleware) {
|
||||
rustTemplate("api_key: #{Option}<#{ApiKey}>,", *codegenScope)
|
||||
}
|
||||
}
|
||||
is ServiceConfig.ConfigImpl -> writable {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns API key used by the client, if it was provided.
|
||||
pub fn api_key(&self) -> Option<&#{ApiKey}> {
|
||||
self.api_key.as_ref()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns API key used by the client, if it was provided.
|
||||
pub fn api_key(&self) -> #{Option}<&#{ApiKey}> {
|
||||
self.inner.load::<#{ApiKey}>()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns API key used by the client, if it was provided.
|
||||
pub fn api_key(&self) -> #{Option}<&#{ApiKey}> {
|
||||
self.api_key.as_ref()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> emptySection
|
||||
}
|
||||
|
|
|
@ -237,6 +237,7 @@ private class HttpAuthConfigCustomization(
|
|||
private val authSchemes: HttpAuthSchemes,
|
||||
) : ConfigCustomization() {
|
||||
private val codegenScope = codegenScope(codegenContext.runtimeConfig)
|
||||
private val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
|
||||
override fun section(section: ServiceConfig): Writable = writable {
|
||||
when (section) {
|
||||
|
@ -324,7 +325,9 @@ private class HttpAuthConfigCustomization(
|
|||
}
|
||||
|
||||
is ServiceConfig.BuilderBuild -> {
|
||||
rust("identity_resolvers: self.identity_resolvers,")
|
||||
if (runtimeMode.defaultToMiddleware) {
|
||||
rust("identity_resolvers: self.identity_resolvers,")
|
||||
}
|
||||
}
|
||||
|
||||
is ServiceConfig.ConfigStruct -> {
|
||||
|
@ -343,6 +346,10 @@ private class HttpAuthConfigCustomization(
|
|||
)
|
||||
}
|
||||
|
||||
is ServiceConfig.BuilderBuildExtras -> {
|
||||
rust("identity_resolvers: self.identity_resolvers,")
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import software.amazon.smithy.rust.codegen.core.rustlang.Writable
|
|||
import software.amazon.smithy.rust.codegen.core.rustlang.rust
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.writable
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
|
||||
import software.amazon.smithy.rust.codegen.core.util.letIf
|
||||
|
||||
|
@ -31,9 +30,10 @@ class HttpConnectorConfigDecorator : ClientCodegenDecorator {
|
|||
}
|
||||
|
||||
private class HttpConnectorConfigCustomization(
|
||||
codegenContext: CodegenContext,
|
||||
codegenContext: ClientCodegenContext,
|
||||
) : ConfigCustomization() {
|
||||
private val runtimeConfig = codegenContext.runtimeConfig
|
||||
private val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
private val moduleUseName = codegenContext.moduleUseName()
|
||||
private val codegenScope = arrayOf(
|
||||
"HttpConnector" to RuntimeType.smithyClient(runtimeConfig).resolve("http_connector::HttpConnector"),
|
||||
|
@ -42,19 +42,33 @@ private class HttpConnectorConfigCustomization(
|
|||
override fun section(section: ServiceConfig): Writable {
|
||||
return when (section) {
|
||||
is ServiceConfig.ConfigStruct -> writable {
|
||||
rustTemplate("http_connector: Option<#{HttpConnector}>,", *codegenScope)
|
||||
if (runtimeMode.defaultToMiddleware) {
|
||||
rustTemplate("http_connector: Option<#{HttpConnector}>,", *codegenScope)
|
||||
}
|
||||
}
|
||||
|
||||
is ServiceConfig.ConfigImpl -> writable {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Return an [`HttpConnector`](#{HttpConnector}) to use when making requests, if any.
|
||||
pub fn http_connector(&self) -> Option<&#{HttpConnector}> {
|
||||
self.http_connector.as_ref()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Return an [`HttpConnector`](#{HttpConnector}) to use when making requests, if any.
|
||||
pub fn http_connector(&self) -> Option<&#{HttpConnector}> {
|
||||
self.inner.load::<#{HttpConnector}>()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Return an [`HttpConnector`](#{HttpConnector}) to use when making requests, if any.
|
||||
pub fn http_connector(&self) -> Option<&#{HttpConnector}> {
|
||||
self.http_connector.as_ref()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is ServiceConfig.BuilderStruct -> writable {
|
||||
|
@ -147,7 +161,11 @@ private class HttpConnectorConfigCustomization(
|
|||
}
|
||||
|
||||
is ServiceConfig.BuilderBuild -> writable {
|
||||
rust("http_connector: self.http_connector,")
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rust("self.http_connector.map(|c| layer.store_put(c));")
|
||||
} else {
|
||||
rust("http_connector: self.http_connector,")
|
||||
}
|
||||
}
|
||||
|
||||
else -> emptySection
|
||||
|
|
|
@ -26,17 +26,13 @@ class InterceptorConfigCustomization(codegenContext: CodegenContext) : ConfigCus
|
|||
writable {
|
||||
when (section) {
|
||||
ServiceConfig.ConfigStruct -> rustTemplate(
|
||||
"""
|
||||
pub(crate) interceptors: Vec<#{SharedInterceptor}>,
|
||||
""",
|
||||
"pub(crate) interceptors: Vec<#{SharedInterceptor}>,",
|
||||
*codegenScope,
|
||||
)
|
||||
|
||||
ServiceConfig.BuilderStruct ->
|
||||
rustTemplate(
|
||||
"""
|
||||
interceptors: Vec<#{SharedInterceptor}>,
|
||||
""",
|
||||
"interceptors: Vec<#{SharedInterceptor}>,",
|
||||
*codegenScope,
|
||||
)
|
||||
|
||||
|
@ -171,18 +167,14 @@ class InterceptorConfigCustomization(codegenContext: CodegenContext) : ConfigCus
|
|||
*codegenScope,
|
||||
)
|
||||
|
||||
ServiceConfig.BuilderBuild -> rust(
|
||||
"""
|
||||
interceptors: self.interceptors,
|
||||
""",
|
||||
)
|
||||
|
||||
is ServiceConfig.RuntimePluginInterceptors -> rust(
|
||||
"""
|
||||
${section.interceptors}.extend(self.interceptors.iter().cloned());
|
||||
""",
|
||||
)
|
||||
|
||||
is ServiceConfig.BuilderBuildExtras -> rust("interceptors: self.interceptors,")
|
||||
|
||||
else -> emptySection
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
package software.amazon.smithy.rust.codegen.client.smithy.customizations
|
||||
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginSection
|
||||
|
@ -14,13 +15,13 @@ import software.amazon.smithy.rust.codegen.core.rustlang.Writable
|
|||
import software.amazon.smithy.rust.codegen.core.rustlang.rust
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.writable
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RustCrate
|
||||
|
||||
class ResiliencyConfigCustomization(codegenContext: CodegenContext) : ConfigCustomization() {
|
||||
class ResiliencyConfigCustomization(codegenContext: ClientCodegenContext) : ConfigCustomization() {
|
||||
private val runtimeConfig = codegenContext.runtimeConfig
|
||||
private val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
private val retryConfig = RuntimeType.smithyTypes(runtimeConfig).resolve("retry")
|
||||
private val sleepModule = RuntimeType.smithyAsync(runtimeConfig).resolve("rt::sleep")
|
||||
private val timeoutModule = RuntimeType.smithyTypes(runtimeConfig).resolve("timeout")
|
||||
|
@ -35,38 +36,64 @@ class ResiliencyConfigCustomization(codegenContext: CodegenContext) : ConfigCust
|
|||
override fun section(section: ServiceConfig) =
|
||||
writable {
|
||||
when (section) {
|
||||
is ServiceConfig.ConfigStruct -> rustTemplate(
|
||||
"""
|
||||
retry_config: Option<#{RetryConfig}>,
|
||||
sleep_impl: Option<#{SharedAsyncSleep}>,
|
||||
timeout_config: Option<#{TimeoutConfig}>,
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
|
||||
is ServiceConfig.ConfigImpl -> {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Return a reference to the retry configuration contained in this config, if any.
|
||||
pub fn retry_config(&self) -> Option<&#{RetryConfig}> {
|
||||
self.retry_config.as_ref()
|
||||
}
|
||||
|
||||
/// Return a cloned shared async sleep implementation from this config, if any.
|
||||
pub fn sleep_impl(&self) -> Option<#{SharedAsyncSleep}> {
|
||||
self.sleep_impl.clone()
|
||||
}
|
||||
|
||||
/// Return a reference to the timeout configuration contained in this config, if any.
|
||||
pub fn timeout_config(&self) -> Option<&#{TimeoutConfig}> {
|
||||
self.timeout_config.as_ref()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
is ServiceConfig.ConfigStruct -> {
|
||||
if (runtimeMode.defaultToMiddleware) {
|
||||
rustTemplate(
|
||||
"""
|
||||
retry_config: Option<#{RetryConfig}>,
|
||||
sleep_impl: Option<#{SharedAsyncSleep}>,
|
||||
timeout_config: Option<#{TimeoutConfig}>,
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is ServiceConfig.BuilderStruct ->
|
||||
is ServiceConfig.ConfigImpl -> {
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Return a reference to the retry configuration contained in this config, if any.
|
||||
pub fn retry_config(&self) -> Option<&#{RetryConfig}> {
|
||||
self.inner.load::<#{RetryConfig}>()
|
||||
}
|
||||
|
||||
/// Return a cloned shared async sleep implementation from this config, if any.
|
||||
pub fn sleep_impl(&self) -> Option<#{SharedAsyncSleep}> {
|
||||
self.inner.load::<#{SharedAsyncSleep}>().cloned()
|
||||
}
|
||||
|
||||
/// Return a reference to the timeout configuration contained in this config, if any.
|
||||
pub fn timeout_config(&self) -> Option<&#{TimeoutConfig}> {
|
||||
self.inner.load::<#{TimeoutConfig}>()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Return a reference to the retry configuration contained in this config, if any.
|
||||
pub fn retry_config(&self) -> Option<&#{RetryConfig}> {
|
||||
self.retry_config.as_ref()
|
||||
}
|
||||
|
||||
/// Return a cloned shared async sleep implementation from this config, if any.
|
||||
pub fn sleep_impl(&self) -> Option<#{SharedAsyncSleep}> {
|
||||
self.sleep_impl.clone()
|
||||
}
|
||||
|
||||
/// Return a reference to the timeout configuration contained in this config, if any.
|
||||
pub fn timeout_config(&self) -> Option<&#{TimeoutConfig}> {
|
||||
self.timeout_config.as_ref()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is ServiceConfig.BuilderStruct -> {
|
||||
rustTemplate(
|
||||
"""
|
||||
retry_config: Option<#{RetryConfig}>,
|
||||
|
@ -75,6 +102,7 @@ class ResiliencyConfigCustomization(codegenContext: CodegenContext) : ConfigCust
|
|||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
|
||||
ServiceConfig.BuilderImpl ->
|
||||
rustTemplate(
|
||||
|
@ -216,21 +244,30 @@ class ResiliencyConfigCustomization(codegenContext: CodegenContext) : ConfigCust
|
|||
*codegenScope,
|
||||
)
|
||||
|
||||
ServiceConfig.BuilderBuild -> rustTemplate(
|
||||
// We call clone on sleep_impl because the field is used by
|
||||
// initializing the credentials_cache field later in the build
|
||||
// method of a Config builder.
|
||||
// We could rearrange the order of decorators so that AwsCodegenDecorator
|
||||
// runs before RequiredCustomizations, which in turns renders
|
||||
// CredentialsCacheDecorator before this class, but that is a bigger
|
||||
// change than adding a call to the clone method on sleep_impl.
|
||||
"""
|
||||
retry_config: self.retry_config,
|
||||
sleep_impl: self.sleep_impl.clone(),
|
||||
timeout_config: self.timeout_config,
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
ServiceConfig.BuilderBuild -> {
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
self.retry_config.map(|r| layer.store_put(r));
|
||||
self.sleep_impl.clone().map(|s| layer.store_put(s));
|
||||
self.timeout_config.map(|t| layer.store_put(t));
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
// We call clone on sleep_impl because the field is used by
|
||||
// initializing the credentials_cache field later in the build
|
||||
// method of a Config builder.
|
||||
"""
|
||||
retry_config: self.retry_config,
|
||||
sleep_impl: self.sleep_impl.clone(),
|
||||
timeout_config: self.timeout_config,
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
else -> emptySection
|
||||
}
|
||||
|
@ -276,7 +313,7 @@ class ResiliencyServiceRuntimePluginCustomization : ServiceRuntimePluginCustomiz
|
|||
if let Some(timeout_config) = self.handle.conf.timeout_config() {
|
||||
${section.newLayerName}.put(timeout_config.clone());
|
||||
}
|
||||
${section.newLayerName}.put(self.handle.conf.time_source.clone());
|
||||
${section.newLayerName}.put(self.handle.conf.time_source().clone());
|
||||
""",
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package software.amazon.smithy.rust.codegen.client.smithy.customizations
|
||||
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.Writable
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rust
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rustBlockTemplate
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.writable
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope
|
||||
|
||||
class TimeSourceCustomization(codegenContext: ClientCodegenContext) : ConfigCustomization() {
|
||||
private val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
private val codegenScope = arrayOf(
|
||||
*preludeScope,
|
||||
"SharedTimeSource" to RuntimeType.smithyAsync(codegenContext.runtimeConfig).resolve("time::SharedTimeSource"),
|
||||
)
|
||||
|
||||
override fun section(section: ServiceConfig) =
|
||||
writable {
|
||||
when (section) {
|
||||
is ServiceConfig.ConfigStruct -> {
|
||||
if (runtimeMode.defaultToMiddleware) {
|
||||
rustTemplate(
|
||||
"""
|
||||
pub(crate) time_source: #{SharedTimeSource},
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is ServiceConfig.ConfigImpl -> {
|
||||
rust("/// Return time source used for this service.")
|
||||
rustBlockTemplate(
|
||||
"pub fn time_source(&self) -> #{SharedTimeSource}",
|
||||
*codegenScope,
|
||||
) {
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""self.inner.load::<#{SharedTimeSource}>().expect("time source should be set").clone()""",
|
||||
*codegenScope,
|
||||
)
|
||||
} else {
|
||||
rust("self.time_source.clone()")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is ServiceConfig.BuilderStruct ->
|
||||
rustTemplate(
|
||||
"""
|
||||
time_source: #{Option}<#{SharedTimeSource}>,
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
|
||||
ServiceConfig.BuilderImpl ->
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Sets the time source used for this service
|
||||
pub fn time_source(
|
||||
mut self,
|
||||
time_source: impl #{Into}<#{SharedTimeSource}>,
|
||||
) -> Self {
|
||||
self.time_source = Some(time_source.into());
|
||||
self
|
||||
}
|
||||
/// Sets the time source used for this service
|
||||
pub fn set_time_source(
|
||||
&mut self,
|
||||
time_source: #{Option}<#{SharedTimeSource}>,
|
||||
) -> &mut Self {
|
||||
self.time_source = time_source;
|
||||
self
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
|
||||
ServiceConfig.BuilderBuild -> {
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
layer.store_put(self.time_source.unwrap_or_default());
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
"""
|
||||
time_source: self.time_source.unwrap_or_default(),
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
else -> emptySection
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TimeSourceOperationCustomization : OperationCustomization() {
|
||||
override fun section(section: OperationSection): Writable {
|
||||
return when (section) {
|
||||
is OperationSection.MutateRequest -> writable {
|
||||
rust(
|
||||
"""
|
||||
${section.request}.properties_mut().insert(${section.config}.time_source.clone());
|
||||
""",
|
||||
)
|
||||
}
|
||||
|
||||
else -> emptySection
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,11 +16,11 @@ import software.amazon.smithy.rust.codegen.client.smithy.customizations.Intercep
|
|||
import software.amazon.smithy.rust.codegen.client.smithy.customizations.ResiliencyConfigCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.customizations.ResiliencyReExportCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.customizations.ResiliencyServiceRuntimePluginCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.customizations.TimeSourceCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.customizations.TimeSourceOperationCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.TimeSourceOperationCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.timeSourceCustomization
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.Feature
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RustCrate
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.customizations.AllowLintsCustomization
|
||||
|
@ -59,9 +59,9 @@ class RequiredCustomizations : ClientCodegenDecorator {
|
|||
if (codegenContext.smithyRuntimeMode.generateOrchestrator) {
|
||||
baseCustomizations + ResiliencyConfigCustomization(codegenContext) + InterceptorConfigCustomization(
|
||||
codegenContext,
|
||||
) + timeSourceCustomization(codegenContext)
|
||||
) + TimeSourceCustomization(codegenContext)
|
||||
} else {
|
||||
baseCustomizations + ResiliencyConfigCustomization(codegenContext) + timeSourceCustomization(codegenContext)
|
||||
baseCustomizations + ResiliencyConfigCustomization(codegenContext) + TimeSourceCustomization(codegenContext)
|
||||
}
|
||||
|
||||
override fun libRsCustomizations(
|
||||
|
|
|
@ -11,19 +11,22 @@ import software.amazon.smithy.model.shapes.ShapeType
|
|||
import software.amazon.smithy.model.shapes.StringShape
|
||||
import software.amazon.smithy.rulesengine.traits.ClientContextParamDefinition
|
||||
import software.amazon.smithy.rulesengine.traits.ClientContextParamsTrait
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigParam
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.configParamNewtype
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.standardConfigParam
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWords
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.Writable
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.docs
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.join
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.writable
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider
|
||||
import software.amazon.smithy.rust.codegen.core.util.getTrait
|
||||
import software.amazon.smithy.rust.codegen.core.util.orNull
|
||||
import software.amazon.smithy.rust.codegen.core.util.toPascalCase
|
||||
import software.amazon.smithy.rust.codegen.core.util.toSnakeCase
|
||||
|
||||
/**
|
||||
|
@ -32,10 +35,11 @@ import software.amazon.smithy.rust.codegen.core.util.toSnakeCase
|
|||
* This handles injecting parameters like `s3::Accelerate` or `s3::ForcePathStyle`. The resulting parameters become
|
||||
* setters on the config builder object.
|
||||
*/
|
||||
class ClientContextConfigCustomization(ctx: CodegenContext) : ConfigCustomization() {
|
||||
class ClientContextConfigCustomization(ctx: ClientCodegenContext) : ConfigCustomization() {
|
||||
private val runtimeConfig = ctx.runtimeConfig
|
||||
private val configParams = ctx.serviceShape.getTrait<ClientContextParamsTrait>()?.parameters.orEmpty().toList()
|
||||
.map { (key, value) -> fromClientParam(key, value, ctx.symbolProvider) }
|
||||
private val decorators = configParams.map { standardConfigParam(it) }
|
||||
.map { (key, value) -> fromClientParam(key, value, ctx.symbolProvider, runtimeConfig) }
|
||||
private val decorators = configParams.map { standardConfigParam(it, ctx) }
|
||||
|
||||
companion object {
|
||||
fun toSymbol(shapeType: ShapeType, symbolProvider: RustSymbolProvider): Symbol =
|
||||
|
@ -51,10 +55,13 @@ class ClientContextConfigCustomization(ctx: CodegenContext) : ConfigCustomizatio
|
|||
name: String,
|
||||
definition: ClientContextParamDefinition,
|
||||
symbolProvider: RustSymbolProvider,
|
||||
runtimeConfig: RuntimeConfig,
|
||||
): ConfigParam {
|
||||
val inner = toSymbol(definition.type, symbolProvider)
|
||||
return ConfigParam(
|
||||
RustReservedWords.escapeIfNeeded(name.toSnakeCase()),
|
||||
toSymbol(definition.type, symbolProvider),
|
||||
inner,
|
||||
configParamNewtype(RustReservedWords.escapeIfNeeded(name.toPascalCase()), inner, runtimeConfig),
|
||||
definition.documentation.orNull()?.let { writable { docs(it) } },
|
||||
)
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ internal class EndpointConfigCustomization(
|
|||
ConfigCustomization() {
|
||||
private val runtimeConfig = codegenContext.runtimeConfig
|
||||
private val moduleUseName = codegenContext.moduleUseName()
|
||||
private val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
private val types = Types(runtimeConfig)
|
||||
|
||||
override fun section(section: ServiceConfig): Writable {
|
||||
|
@ -38,21 +39,38 @@ internal class EndpointConfigCustomization(
|
|||
"Params" to typesGenerator.paramsStruct(),
|
||||
)
|
||||
when (section) {
|
||||
is ServiceConfig.ConfigStruct -> rustTemplate(
|
||||
"pub (crate) endpoint_resolver: $sharedEndpointResolver,",
|
||||
*codegenScope,
|
||||
)
|
||||
is ServiceConfig.ConfigStruct -> {
|
||||
if (runtimeMode.defaultToMiddleware) {
|
||||
rustTemplate(
|
||||
"pub (crate) endpoint_resolver: $sharedEndpointResolver,",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is ServiceConfig.ConfigImpl ->
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns the endpoint resolver.
|
||||
pub fn endpoint_resolver(&self) -> $sharedEndpointResolver {
|
||||
self.endpoint_resolver.clone()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
is ServiceConfig.ConfigImpl -> {
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns the endpoint resolver.
|
||||
pub fn endpoint_resolver(&self) -> $sharedEndpointResolver {
|
||||
self.inner.load::<$sharedEndpointResolver>().expect("endpoint resolver should be set").clone()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns the endpoint resolver.
|
||||
pub fn endpoint_resolver(&self) -> $sharedEndpointResolver {
|
||||
self.endpoint_resolver.clone()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is ServiceConfig.BuilderStruct ->
|
||||
rustTemplate(
|
||||
|
@ -123,15 +141,27 @@ internal class EndpointConfigCustomization(
|
|||
ServiceConfig.BuilderBuild -> {
|
||||
val defaultResolver = typesGenerator.defaultResolver()
|
||||
if (defaultResolver != null) {
|
||||
rustTemplate(
|
||||
"""
|
||||
endpoint_resolver: self.endpoint_resolver.unwrap_or_else(||
|
||||
#{SharedEndpointResolver}::new(#{DefaultResolver}::new())
|
||||
),
|
||||
""",
|
||||
*codegenScope,
|
||||
"DefaultResolver" to defaultResolver,
|
||||
)
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
layer.store_put(self.endpoint_resolver.unwrap_or_else(||
|
||||
#{SharedEndpointResolver}::new(#{DefaultResolver}::new())
|
||||
));
|
||||
""",
|
||||
*codegenScope,
|
||||
"DefaultResolver" to defaultResolver,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
"""
|
||||
endpoint_resolver: self.endpoint_resolver.unwrap_or_else(||
|
||||
#{SharedEndpointResolver}::new(#{DefaultResolver}::new())
|
||||
),
|
||||
""",
|
||||
*codegenScope,
|
||||
"DefaultResolver" to defaultResolver,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val alwaysFailsResolver =
|
||||
RuntimeType.forInlineFun("MissingResolver", ClientRustModule.Endpoint) {
|
||||
|
@ -152,13 +182,23 @@ internal class EndpointConfigCustomization(
|
|||
}
|
||||
// To keep this diff under control, rather than `.expect` here, insert a resolver that will
|
||||
// always fail. In the future, this will be changed to an `expect()`
|
||||
rustTemplate(
|
||||
"""
|
||||
endpoint_resolver: self.endpoint_resolver.unwrap_or_else(||#{SharedEndpointResolver}::new(#{FailingResolver})),
|
||||
""",
|
||||
*codegenScope,
|
||||
"FailingResolver" to alwaysFailsResolver,
|
||||
)
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
layer.store_put(self.endpoint_resolver.unwrap_or_else(||#{SharedEndpointResolver}::new(#{FailingResolver})));
|
||||
""",
|
||||
*codegenScope,
|
||||
"FailingResolver" to alwaysFailsResolver,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
"""
|
||||
endpoint_resolver: self.endpoint_resolver.unwrap_or_else(||#{SharedEndpointResolver}::new(#{FailingResolver})),
|
||||
""",
|
||||
*codegenScope,
|
||||
"FailingResolver" to alwaysFailsResolver,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -119,9 +119,9 @@ class EndpointParamsInterceptorGenerator(
|
|||
val paramName = EndpointParamsGenerator.memberName(name)
|
||||
val setterName = EndpointParamsGenerator.setterName(name)
|
||||
if (param.type == ShapeType.BOOLEAN) {
|
||||
rust(".$setterName(_config.$paramName)")
|
||||
rust(".$setterName(_config.$paramName())")
|
||||
} else {
|
||||
rust(".$setterName(_config.$paramName.clone())")
|
||||
rust(".$setterName(_config.$paramName().clone())")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ class ServiceRuntimePluginGenerator(
|
|||
}
|
||||
|
||||
fn interceptors(&self, interceptors: &mut #{InterceptorRegistrar}) {
|
||||
interceptors.extend(self.handle.conf.interceptors.iter().cloned());
|
||||
interceptors.extend(self.handle.conf.interceptors().cloned());
|
||||
#{additional_interceptors}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,62 +5,98 @@
|
|||
|
||||
package software.amazon.smithy.rust.codegen.client.smithy.generators.config
|
||||
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.Writable
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rust
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.writable
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.customize.NamedCustomization
|
||||
|
||||
/**
|
||||
* Add a `make_token` field to Service config. See below for the resulting generated code.
|
||||
*/
|
||||
class IdempotencyTokenProviderCustomization : NamedCustomization<ServiceConfig>() {
|
||||
class IdempotencyTokenProviderCustomization(codegenContext: ClientCodegenContext) : NamedCustomization<ServiceConfig>() {
|
||||
private val runtimeConfig = codegenContext.runtimeConfig
|
||||
private val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
private val codegenScope = arrayOf(
|
||||
*preludeScope,
|
||||
"default_provider" to RuntimeType.idempotencyToken(runtimeConfig).resolve("default_provider"),
|
||||
"IdempotencyTokenProvider" to RuntimeType.idempotencyToken(runtimeConfig).resolve("IdempotencyTokenProvider"),
|
||||
)
|
||||
|
||||
override fun section(section: ServiceConfig): Writable {
|
||||
return when (section) {
|
||||
is ServiceConfig.ConfigStruct -> writable {
|
||||
rust("pub (crate) make_token: #T::IdempotencyTokenProvider,", RuntimeType.IdempotencyToken)
|
||||
if (runtimeMode.defaultToMiddleware) {
|
||||
rustTemplate("pub (crate) make_token: #{IdempotencyTokenProvider},", *codegenScope)
|
||||
}
|
||||
}
|
||||
|
||||
ServiceConfig.ConfigImpl -> writable {
|
||||
rust(
|
||||
"""
|
||||
/// Returns a copy of the idempotency token provider.
|
||||
/// If a random token provider was configured,
|
||||
/// a newly-randomized token provider will be returned.
|
||||
pub fn make_token(&self) -> #T::IdempotencyTokenProvider {
|
||||
self.make_token.clone()
|
||||
}
|
||||
""",
|
||||
RuntimeType.IdempotencyToken,
|
||||
)
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns a copy of the idempotency token provider.
|
||||
/// If a random token provider was configured,
|
||||
/// a newly-randomized token provider will be returned.
|
||||
pub fn make_token(&self) -> #{IdempotencyTokenProvider} {
|
||||
self.inner.load::<#{IdempotencyTokenProvider}>().expect("the idempotency provider should be set").clone()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Returns a copy of the idempotency token provider.
|
||||
/// If a random token provider was configured,
|
||||
/// a newly-randomized token provider will be returned.
|
||||
pub fn make_token(&self) -> #{IdempotencyTokenProvider} {
|
||||
self.make_token.clone()
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ServiceConfig.BuilderStruct -> writable {
|
||||
rust("make_token: Option<#T::IdempotencyTokenProvider>,", RuntimeType.IdempotencyToken)
|
||||
rustTemplate("make_token: #{Option}<#{IdempotencyTokenProvider}>,", *codegenScope)
|
||||
}
|
||||
|
||||
ServiceConfig.BuilderImpl -> writable {
|
||||
rustTemplate(
|
||||
"""
|
||||
/// Sets the idempotency token provider to use for service calls that require tokens.
|
||||
pub fn make_token(mut self, make_token: impl Into<#{TokenProvider}>) -> Self {
|
||||
self.set_make_token(Some(make_token.into()));
|
||||
pub fn make_token(mut self, make_token: impl #{Into}<#{IdempotencyTokenProvider}>) -> Self {
|
||||
self.set_make_token(#{Some}(make_token.into()));
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the idempotency token provider to use for service calls that require tokens.
|
||||
pub fn set_make_token(&mut self, make_token: Option<#{TokenProvider}>) -> &mut Self {
|
||||
pub fn set_make_token(&mut self, make_token: #{Option}<#{IdempotencyTokenProvider}>) -> &mut Self {
|
||||
self.make_token = make_token;
|
||||
self
|
||||
}
|
||||
""",
|
||||
"TokenProvider" to RuntimeType.IdempotencyToken.resolve("IdempotencyTokenProvider"),
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
|
||||
ServiceConfig.BuilderBuild -> writable {
|
||||
rust("make_token: self.make_token.unwrap_or_else(#T::default_provider),", RuntimeType.IdempotencyToken)
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"layer.store_put(self.make_token.unwrap_or_else(#{default_provider}));",
|
||||
*codegenScope,
|
||||
)
|
||||
} else {
|
||||
rustTemplate(
|
||||
"make_token: self.make_token.unwrap_or_else(#{default_provider}),",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
is ServiceConfig.DefaultForTests -> writable {
|
||||
|
@ -71,41 +107,3 @@ class IdempotencyTokenProviderCustomization : NamedCustomization<ServiceConfig>(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Generated Code
|
||||
pub struct Config {
|
||||
pub(crate) make_token: Box<dyn crate::idempotency_token::MakeIdempotencyToken>,
|
||||
}
|
||||
impl Config {
|
||||
pub fn builder() -> Builder {
|
||||
Builder::default()
|
||||
}
|
||||
}
|
||||
#[derive(Default)]
|
||||
pub struct Builder {
|
||||
#[allow(dead_code)]
|
||||
make_token: Option<Box<dyn crate::idempotency_token::MakeIdempotencyToken>>,
|
||||
}
|
||||
impl Builder {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Sets the idempotency token provider to use for service calls that require tokens.
|
||||
pub fn make_token(
|
||||
mut self,
|
||||
make_token: impl crate::idempotency_token::MakeIdempotencyToken + 'static,
|
||||
) -> Self {
|
||||
self.make_token = Some(Box::new(make_token));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Config {
|
||||
Config {
|
||||
make_token: self
|
||||
.make_token
|
||||
.unwrap_or_else(|| Box::new(crate::idempotency_token::default_provider())),
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -11,6 +11,9 @@ import software.amazon.smithy.model.knowledge.OperationIndex
|
|||
import software.amazon.smithy.model.knowledge.TopDownIndex
|
||||
import software.amazon.smithy.model.shapes.ServiceShape
|
||||
import software.amazon.smithy.model.traits.IdempotencyTokenTrait
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.customizations.codegenScope
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.customize.TestUtilFeature
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.Attribute
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter
|
||||
|
@ -22,7 +25,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.rust
|
|||
import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.writable
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.customize.NamedCustomization
|
||||
|
@ -89,6 +92,14 @@ sealed class ServiceConfig(name: String) : Section(name) {
|
|||
*/
|
||||
object BuilderBuild : ServiceConfig("BuilderBuild")
|
||||
|
||||
// TODO(enableNewSmithyRuntime): This is temporary until config builder is backed by a CloneableLayer.
|
||||
// It is needed because certain config fields appear explicitly regardless of the smithy runtime mode, e.g.
|
||||
// interceptors. The [BuilderBuild] section is bifurcated depending on the runtime mode (in the orchestrator mode,
|
||||
// storing a field into a frozen layer and in the middleware moving it into a corresponding service config field)
|
||||
// so we need a different temporary section to always move a field from a builder to service config within the
|
||||
// build method.
|
||||
object BuilderBuildExtras : ServiceConfig("BuilderBuildExtras")
|
||||
|
||||
/**
|
||||
* A section for setting up a field to be used by RuntimePlugin
|
||||
*/
|
||||
|
@ -110,10 +121,53 @@ sealed class ServiceConfig(name: String) : Section(name) {
|
|||
data class ConfigParam(
|
||||
val name: String,
|
||||
val type: Symbol,
|
||||
val newtype: RuntimeType?,
|
||||
val setterDocs: Writable?,
|
||||
val getterDocs: Writable? = null,
|
||||
val optional: Boolean = true,
|
||||
)
|
||||
) {
|
||||
|
||||
data class Builder(
|
||||
var name: String? = null,
|
||||
var type: Symbol? = null,
|
||||
var newtype: RuntimeType? = null,
|
||||
var setterDocs: Writable? = null,
|
||||
var getterDocs: Writable? = null,
|
||||
var optional: Boolean = true,
|
||||
) {
|
||||
fun name(name: String) = apply { this.name = name }
|
||||
fun type(type: Symbol) = apply { this.type = type }
|
||||
fun newtype(newtype: RuntimeType) = apply { this.newtype = newtype }
|
||||
fun setterDocs(setterDocs: Writable?) = apply { this.setterDocs = setterDocs }
|
||||
fun getterDocs(getterDocs: Writable?) = apply { this.getterDocs = getterDocs }
|
||||
fun optional(optional: Boolean) = apply { this.optional = optional }
|
||||
fun build() = ConfigParam(name!!, type!!, newtype, setterDocs, getterDocs, optional)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a [RuntimeType] for a newtype whose name is [newtypeName] that wraps [inner].
|
||||
*
|
||||
* When config parameters are stored in a config map in Rust, stored parameters are keyed by type.
|
||||
* Therefore, primitive types, such as bool and String, need to be wrapped in newtypes to make them distinct.
|
||||
*/
|
||||
fun configParamNewtype(newtypeName: String, inner: Symbol, runtimeConfig: RuntimeConfig) =
|
||||
RuntimeType.forInlineFun(newtypeName, ClientRustModule.Config) {
|
||||
val codegenScope = arrayOf(
|
||||
"Storable" to RuntimeType.smithyTypes(runtimeConfig).resolve("config_bag::Storable"),
|
||||
"StoreReplace" to RuntimeType.smithyTypes(runtimeConfig).resolve("config_bag::StoreReplace"),
|
||||
)
|
||||
rustTemplate(
|
||||
"""
|
||||
##[derive(Debug, Clone)]
|
||||
pub(crate) struct $newtypeName($inner);
|
||||
impl #{Storable} for $newtypeName {
|
||||
type Storer = #{StoreReplace}<$newtypeName>;
|
||||
}
|
||||
""",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Config customization for a config param with no special behavior:
|
||||
|
@ -121,19 +175,47 @@ data class ConfigParam(
|
|||
* 2. convenience setter (non-optional)
|
||||
* 3. standard setter (&mut self)
|
||||
*/
|
||||
fun standardConfigParam(param: ConfigParam): ConfigCustomization = object : ConfigCustomization() {
|
||||
fun standardConfigParam(param: ConfigParam, codegenContext: ClientCodegenContext): ConfigCustomization = object : ConfigCustomization() {
|
||||
private val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
|
||||
override fun section(section: ServiceConfig): Writable {
|
||||
return when (section) {
|
||||
is ServiceConfig.ConfigStruct -> writable {
|
||||
docsOrFallback(param.getterDocs)
|
||||
val t = when (param.optional) {
|
||||
true -> param.type.makeOptional()
|
||||
false -> param.type
|
||||
ServiceConfig.ConfigStruct -> writable {
|
||||
if (runtimeMode.defaultToMiddleware) {
|
||||
docsOrFallback(param.getterDocs)
|
||||
val t = when (param.optional) {
|
||||
true -> param.type.makeOptional()
|
||||
false -> param.type
|
||||
}
|
||||
rust("pub (crate) ${param.name}: #T,", t)
|
||||
}
|
||||
}
|
||||
|
||||
ServiceConfig.ConfigImpl -> writable {
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
pub(crate) fn ${param.name}(&self) -> #{output} {
|
||||
self.inner.load::<#{newtype}>().map(#{f})
|
||||
}
|
||||
""",
|
||||
"f" to writable {
|
||||
if (param.type.name == "bool") {
|
||||
rust("|ty| ty.0")
|
||||
} else {
|
||||
rust("|ty| ty.0.clone()")
|
||||
}
|
||||
},
|
||||
"newtype" to param.newtype!!,
|
||||
"output" to if (param.optional) {
|
||||
param.type.makeOptional()
|
||||
} else {
|
||||
param.type
|
||||
},
|
||||
)
|
||||
}
|
||||
rust("pub (crate) ${param.name}: #T,", t)
|
||||
}
|
||||
|
||||
ServiceConfig.ConfigImpl -> emptySection
|
||||
ServiceConfig.BuilderStruct -> writable {
|
||||
rust("${param.name}: #T,", param.type.makeOptional())
|
||||
}
|
||||
|
@ -162,8 +244,15 @@ fun standardConfigParam(param: ConfigParam): ConfigCustomization = object : Conf
|
|||
}
|
||||
|
||||
ServiceConfig.BuilderBuild -> writable {
|
||||
val default = "".letIf(!param.optional) { ".unwrap_or_default() " }
|
||||
rust("${param.name}: self.${param.name}$default,")
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"layer.store_or_unset(self.${param.name}.map(#{newtype}));",
|
||||
"newtype" to param.newtype!!,
|
||||
)
|
||||
} else {
|
||||
val default = "".letIf(!param.optional) { ".unwrap_or_default() " }
|
||||
rust("${param.name}: self.${param.name}$default,")
|
||||
}
|
||||
}
|
||||
|
||||
is ServiceConfig.RuntimePluginConfig -> emptySection
|
||||
|
@ -199,19 +288,19 @@ typealias ConfigCustomization = NamedCustomization<ServiceConfig>
|
|||
* // builder implementation
|
||||
* }
|
||||
*/
|
||||
|
||||
class ServiceConfigGenerator(
|
||||
private val codegenContext: CodegenContext,
|
||||
private val codegenContext: ClientCodegenContext,
|
||||
private val customizations: List<ConfigCustomization> = listOf(),
|
||||
) {
|
||||
|
||||
companion object {
|
||||
fun withBaseBehavior(
|
||||
codegenContext: CodegenContext,
|
||||
codegenContext: ClientCodegenContext,
|
||||
extraCustomizations: List<ConfigCustomization>,
|
||||
): ServiceConfigGenerator {
|
||||
val baseFeatures = mutableListOf<ConfigCustomization>()
|
||||
if (codegenContext.serviceShape.needsIdempotencyToken(codegenContext.model)) {
|
||||
baseFeatures.add(IdempotencyTokenProviderCustomization())
|
||||
baseFeatures.add(IdempotencyTokenProviderCustomization(codegenContext))
|
||||
}
|
||||
return ServiceConfigGenerator(codegenContext, baseFeatures + extraCustomizations)
|
||||
}
|
||||
|
@ -228,6 +317,8 @@ class ServiceConfigGenerator(
|
|||
"RuntimePlugin" to runtimeApi.resolve("client::runtime_plugin::RuntimePlugin"),
|
||||
*preludeScope,
|
||||
)
|
||||
private val moduleUseName = codegenContext.moduleUseName()
|
||||
private val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
|
||||
fun render(writer: RustWriter) {
|
||||
writer.docs("Service config.\n")
|
||||
|
@ -236,6 +327,12 @@ class ServiceConfigGenerator(
|
|||
}
|
||||
Attribute(Attribute.derive(RuntimeType.Clone)).render(writer)
|
||||
writer.rustBlock("pub struct Config") {
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"inner: #{FrozenLayer},",
|
||||
*codegenScope,
|
||||
)
|
||||
}
|
||||
customizations.forEach {
|
||||
it.section(ServiceConfig.ConfigStruct)(this)
|
||||
}
|
||||
|
@ -287,7 +384,7 @@ class ServiceConfigGenerator(
|
|||
|
||||
writer.rustBlock("impl Builder") {
|
||||
writer.docs("Constructs a config builder.")
|
||||
writer.rustTemplate("pub fn new() -> Self { Self::default() }")
|
||||
writer.rust("pub fn new() -> Self { Self::default() }")
|
||||
customizations.forEach {
|
||||
it.section(ServiceConfig.BuilderImpl)(this)
|
||||
}
|
||||
|
@ -312,15 +409,31 @@ class ServiceConfigGenerator(
|
|||
|
||||
docs("Builds a [`Config`].")
|
||||
rustBlock("pub fn build(self) -> Config") {
|
||||
rustBlock("Config") {
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""let mut layer = #{Layer}::new("$moduleUseName::Config");""",
|
||||
*codegenScope,
|
||||
)
|
||||
customizations.forEach {
|
||||
it.section(ServiceConfig.BuilderBuild)(this)
|
||||
}
|
||||
rustBlock("Config") {
|
||||
customizations.forEach {
|
||||
it.section(ServiceConfig.BuilderBuildExtras)(this)
|
||||
}
|
||||
rust("inner: layer.freeze(),")
|
||||
}
|
||||
} else {
|
||||
rustBlock("Config") {
|
||||
customizations.forEach {
|
||||
it.section(ServiceConfig.BuilderBuild)(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
customizations.forEach {
|
||||
it.section(ServiceConfig.Extras)(writer)
|
||||
customizations.forEach {
|
||||
it.section(ServiceConfig.Extras)(writer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package software.amazon.smithy.rust.codegen.client.smithy.generators.config
|
||||
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.Writable
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.docs
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rust
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.writable
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
|
||||
|
||||
fun timeSourceCustomization(codegenContext: ClientCodegenContext) = standardConfigParam(
|
||||
ConfigParam(
|
||||
"time_source",
|
||||
RuntimeType.smithyAsync(codegenContext.runtimeConfig).resolve("time::SharedTimeSource").toSymbol(),
|
||||
setterDocs = writable { docs("""Sets the time source used for this service""") },
|
||||
optional = false,
|
||||
),
|
||||
)
|
||||
|
||||
class TimeSourceOperationCustomization : OperationCustomization() {
|
||||
override fun section(section: OperationSection): Writable {
|
||||
return when (section) {
|
||||
is OperationSection.MutateRequest -> writable {
|
||||
rust(
|
||||
"""
|
||||
${section.request}.properties_mut().insert(${section.config}.time_source.clone());
|
||||
""",
|
||||
)
|
||||
}
|
||||
|
||||
else -> emptySection
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,36 +5,61 @@
|
|||
|
||||
package software.amazon.smithy.rust.codegen.client.testutil
|
||||
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfigGenerator
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.configParamNewtype
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.Writable
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rust
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.writable
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.TestWriterDelegator
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.unitTest
|
||||
import software.amazon.smithy.rust.codegen.core.util.toPascalCase
|
||||
|
||||
/**
|
||||
* Test helper to produce a valid config customization to test that a [ConfigCustomization] can be used in conjunction
|
||||
* with other [ConfigCustomization]s.
|
||||
*/
|
||||
fun stubConfigCustomization(name: String): ConfigCustomization {
|
||||
fun stubConfigCustomization(name: String, codegenContext: ClientCodegenContext): ConfigCustomization {
|
||||
return object : ConfigCustomization() {
|
||||
override fun section(section: ServiceConfig): Writable = writable {
|
||||
when (section) {
|
||||
ServiceConfig.ConfigStruct -> rust("_$name: u64,")
|
||||
ServiceConfig.ConfigImpl -> rust(
|
||||
"""
|
||||
##[allow(missing_docs)]
|
||||
pub fn $name(&self) -> u64 {
|
||||
self._$name
|
||||
ServiceConfig.ConfigStruct -> {
|
||||
if (codegenContext.smithyRuntimeMode.defaultToMiddleware) {
|
||||
rust("_$name: u64,")
|
||||
}
|
||||
""",
|
||||
)
|
||||
}
|
||||
ServiceConfig.ConfigImpl -> {
|
||||
if (codegenContext.smithyRuntimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
##[allow(missing_docs)]
|
||||
pub fn $name(&self) -> u64 {
|
||||
self.inner.load::<#{T}>().map(|u| u.0).unwrap()
|
||||
}
|
||||
""",
|
||||
"T" to configParamNewtype(
|
||||
"_$name".toPascalCase(), RuntimeType.U64.toSymbol(),
|
||||
codegenContext.runtimeConfig,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
rust(
|
||||
"""
|
||||
##[allow(missing_docs)]
|
||||
pub fn $name(&self) -> u64 {
|
||||
self._$name
|
||||
}
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
ServiceConfig.BuilderStruct -> rust("_$name: Option<u64>,")
|
||||
ServiceConfig.BuilderImpl -> rust(
|
||||
"""
|
||||
|
@ -45,11 +70,25 @@ fun stubConfigCustomization(name: String): ConfigCustomization {
|
|||
}
|
||||
""",
|
||||
)
|
||||
ServiceConfig.BuilderBuild -> rust(
|
||||
"""
|
||||
_$name: self._$name.unwrap_or(123),
|
||||
""",
|
||||
)
|
||||
ServiceConfig.BuilderBuild -> {
|
||||
if (codegenContext.smithyRuntimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
layer.store_or_unset(self._$name.map(#{T}));
|
||||
""",
|
||||
"T" to configParamNewtype(
|
||||
"_$name".toPascalCase(), RuntimeType.U64.toSymbol(),
|
||||
codegenContext.runtimeConfig,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
rust(
|
||||
"""
|
||||
_$name: self._$name.unwrap_or(123),
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> emptySection
|
||||
}
|
||||
}
|
||||
|
@ -63,18 +102,19 @@ fun stubConfigCustomization(name: String): ConfigCustomization {
|
|||
* */
|
||||
@Suppress("NAME_SHADOWING")
|
||||
fun validateConfigCustomizations(
|
||||
codegenContext: ClientCodegenContext,
|
||||
customization: ConfigCustomization,
|
||||
project: TestWriterDelegator? = null,
|
||||
): TestWriterDelegator {
|
||||
val project = project ?: TestWorkspace.testProject()
|
||||
stubConfigProject(customization, project)
|
||||
stubConfigProject(codegenContext, customization, project)
|
||||
project.compileAndTest()
|
||||
return project
|
||||
}
|
||||
|
||||
fun stubConfigProject(customization: ConfigCustomization, project: TestWriterDelegator): TestWriterDelegator {
|
||||
val customizations = listOf(stubConfigCustomization("a")) + customization + stubConfigCustomization("b")
|
||||
val generator = ServiceConfigGenerator(testClientCodegenContext("namespace test".asSmithyModel()), customizations = customizations.toList())
|
||||
fun stubConfigProject(codegenContext: ClientCodegenContext, customization: ConfigCustomization, project: TestWriterDelegator): TestWriterDelegator {
|
||||
val customizations = listOf(stubConfigCustomization("a", codegenContext)) + customization + stubConfigCustomization("b", codegenContext)
|
||||
val generator = ServiceConfigGenerator(codegenContext, customizations = customizations.toList())
|
||||
project.withModule(ClientRustModule.Config) {
|
||||
generator.render(this)
|
||||
unitTest(
|
||||
|
|
|
@ -15,6 +15,7 @@ import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
|
|||
import software.amazon.smithy.rust.codegen.client.smithy.ClientModuleProvider
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.ClientRustSettings
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.RustClientCodegenPlugin
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.SmithyRuntimeMode
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.customize.CombinedClientCodegenDecorator
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig
|
||||
|
@ -90,6 +91,9 @@ fun testClientCodegenContext(
|
|||
rootDecorator ?: CombinedClientCodegenDecorator(emptyList()),
|
||||
)
|
||||
|
||||
fun ClientCodegenContext.withSmithyRuntimeMode(smithyRuntimeMode: SmithyRuntimeMode): ClientCodegenContext =
|
||||
copy(settings = settings.copy(codegenConfig = settings.codegenConfig.copy(enableNewSmithyRuntime = smithyRuntimeMode)))
|
||||
|
||||
fun TestWriterDelegator.clientRustSettings() =
|
||||
testClientRustSettings(
|
||||
service = ShapeId.from("fake#Fake"),
|
||||
|
|
|
@ -39,7 +39,7 @@ internal class ResiliencyConfigCustomizationTest {
|
|||
val project = TestWorkspace.testProject(model, ClientCodegenConfig())
|
||||
val codegenContext = testClientCodegenContext(model, settings = project.clientRustSettings())
|
||||
|
||||
stubConfigProject(ResiliencyConfigCustomization(codegenContext), project)
|
||||
stubConfigProject(codegenContext, ResiliencyConfigCustomization(codegenContext), project)
|
||||
ResiliencyReExportCustomization(codegenContext.runtimeConfig).extras(project)
|
||||
project.compileAndTest()
|
||||
}
|
||||
|
|
|
@ -5,9 +5,12 @@
|
|||
|
||||
package software.amazon.smithy.rust.codegen.client.smithy.endpoint
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.SmithyRuntimeMode
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.testClientCodegenContext
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.validateConfigCustomizations
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.withSmithyRuntimeMode
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rust
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel
|
||||
|
@ -29,28 +32,51 @@ class ClientContextConfigCustomizationTest {
|
|||
service TestService { operations: [] }
|
||||
""".asSmithyModel()
|
||||
|
||||
@Test
|
||||
fun `client params generate a valid customization`() {
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = ["middleware", "orchestrator"])
|
||||
fun `client params generate a valid customization`(smithyRuntimeModeStr: String) {
|
||||
val project = TestWorkspace.testProject()
|
||||
val smithyRuntimeMode = SmithyRuntimeMode.fromString(smithyRuntimeModeStr)
|
||||
project.unitTest {
|
||||
rust(
|
||||
"""
|
||||
let conf = crate::Config::builder().a_string_param("hello!").a_bool_param(true).build();
|
||||
assert_eq!(conf.a_string_param.unwrap(), "hello!");
|
||||
assert_eq!(conf.a_bool_param, Some(true));
|
||||
""",
|
||||
)
|
||||
if (smithyRuntimeMode.defaultToOrchestrator) {
|
||||
rust(
|
||||
"""
|
||||
let conf = crate::Config::builder().a_string_param("hello!").a_bool_param(true).build();
|
||||
assert_eq!(conf.a_string_param().unwrap(), "hello!");
|
||||
assert_eq!(conf.a_bool_param(), Some(true));
|
||||
""",
|
||||
)
|
||||
} else {
|
||||
rust(
|
||||
"""
|
||||
let conf = crate::Config::builder().a_string_param("hello!").a_bool_param(true).build();
|
||||
assert_eq!(conf.a_string_param.unwrap(), "hello!");
|
||||
assert_eq!(conf.a_bool_param, Some(true));
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
// unset fields
|
||||
project.unitTest {
|
||||
rust(
|
||||
"""
|
||||
let conf = crate::Config::builder().a_string_param("hello!").build();
|
||||
assert_eq!(conf.a_string_param.unwrap(), "hello!");
|
||||
assert_eq!(conf.a_bool_param, None);
|
||||
""",
|
||||
)
|
||||
if (smithyRuntimeMode.defaultToOrchestrator) {
|
||||
rust(
|
||||
"""
|
||||
let conf = crate::Config::builder().a_string_param("hello!").build();
|
||||
assert_eq!(conf.a_string_param().unwrap(), "hello!");
|
||||
assert_eq!(conf.a_bool_param(), None);
|
||||
""",
|
||||
)
|
||||
} else {
|
||||
rust(
|
||||
"""
|
||||
let conf = crate::Config::builder().a_string_param("hello!").build();
|
||||
assert_eq!(conf.a_string_param.unwrap(), "hello!");
|
||||
assert_eq!(conf.a_bool_param, None);
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
validateConfigCustomizations(ClientContextConfigCustomization(testClientCodegenContext(model)), project)
|
||||
val context = testClientCodegenContext(model).withSmithyRuntimeMode(smithyRuntimeMode)
|
||||
validateConfigCustomizations(context, ClientContextConfigCustomization(context), project)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,24 @@
|
|||
|
||||
package software.amazon.smithy.rust.codegen.client.smithy.generators.config
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.SmithyRuntimeMode
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.testClientCodegenContext
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.validateConfigCustomizations
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.withSmithyRuntimeMode
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel
|
||||
|
||||
class IdempotencyTokenProviderCustomizationTest {
|
||||
@Test
|
||||
fun `generates a valid config`() {
|
||||
validateConfigCustomizations(IdempotencyTokenProviderCustomization())
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = ["middleware", "orchestrator"])
|
||||
fun `generates a valid config`(smithyRuntimeModeStr: String) {
|
||||
val smithyRuntimeMode = SmithyRuntimeMode.fromString(smithyRuntimeModeStr)
|
||||
val model = "namespace test".asSmithyModel()
|
||||
val codegenContext = testClientCodegenContext(model).withSmithyRuntimeMode(smithyRuntimeMode)
|
||||
validateConfigCustomizations(
|
||||
codegenContext,
|
||||
IdempotencyTokenProviderCustomization(codegenContext),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,18 +7,26 @@ package software.amazon.smithy.rust.codegen.client.smithy.generators.config
|
|||
|
||||
import io.kotest.matchers.shouldBe
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import software.amazon.smithy.model.shapes.ServiceShape
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule
|
||||
import software.amazon.smithy.rust.codegen.client.smithy.SmithyRuntimeMode
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.testClientCodegenContext
|
||||
import software.amazon.smithy.rust.codegen.client.testutil.withSmithyRuntimeMode
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.Writable
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rust
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
|
||||
import software.amazon.smithy.rust.codegen.core.rustlang.writable
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.customize.NamedCustomization
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.unitTest
|
||||
import software.amazon.smithy.rust.codegen.core.util.lookup
|
||||
import software.amazon.smithy.rust.codegen.core.util.toPascalCase
|
||||
|
||||
internal class ServiceConfigGeneratorTest {
|
||||
@Test
|
||||
|
@ -76,46 +84,98 @@ internal class ServiceConfigGeneratorTest {
|
|||
model.lookup<ServiceShape>("com.example#ResourceService").needsIdempotencyToken(model) shouldBe true
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `generate customizations as specified`() {
|
||||
class ServiceCustomizer : NamedCustomization<ServiceConfig>() {
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = ["middleware", "orchestrator"])
|
||||
fun `generate customizations as specified`(smithyRuntimeModeStr: String) {
|
||||
class ServiceCustomizer(private val codegenContext: ClientCodegenContext) :
|
||||
NamedCustomization<ServiceConfig>() {
|
||||
private val runtimeMode = codegenContext.smithyRuntimeMode
|
||||
|
||||
override fun section(section: ServiceConfig): Writable {
|
||||
return when (section) {
|
||||
ServiceConfig.ConfigStructAdditionalDocs -> emptySection
|
||||
ServiceConfig.ConfigStruct -> writable { rust("config_field: u64,") }
|
||||
ServiceConfig.ConfigImpl -> writable {
|
||||
rust(
|
||||
"""
|
||||
pub fn config_field(&self) -> u64 {
|
||||
self.config_field
|
||||
}
|
||||
""",
|
||||
)
|
||||
ServiceConfig.ConfigStruct -> writable {
|
||||
if (runtimeMode.defaultToMiddleware) {
|
||||
rust("config_field: u64,")
|
||||
}
|
||||
}
|
||||
|
||||
ServiceConfig.ConfigImpl -> writable {
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"""
|
||||
##[allow(missing_docs)]
|
||||
pub fn config_field(&self) -> u64 {
|
||||
self.inner.load::<#{T}>().map(|u| u.0).unwrap()
|
||||
}
|
||||
""",
|
||||
"T" to configParamNewtype(
|
||||
"config_field".toPascalCase(), RuntimeType.U64.toSymbol(),
|
||||
codegenContext.runtimeConfig,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
rust(
|
||||
"""
|
||||
##[allow(missing_docs)]
|
||||
pub fn config_field(&self) -> u64 {
|
||||
self.config_field
|
||||
}
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ServiceConfig.BuilderStruct -> writable { rust("config_field: Option<u64>") }
|
||||
ServiceConfig.BuilderImpl -> emptySection
|
||||
ServiceConfig.BuilderBuild -> writable {
|
||||
rust("config_field: self.config_field.unwrap_or_default(),")
|
||||
if (runtimeMode.defaultToOrchestrator) {
|
||||
rustTemplate(
|
||||
"layer.store_or_unset(self.config_field.map(#{T}));",
|
||||
"T" to configParamNewtype(
|
||||
"config_field".toPascalCase(), RuntimeType.U64.toSymbol(),
|
||||
codegenContext.runtimeConfig,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
rust("config_field: self.config_field.unwrap_or_default(),")
|
||||
}
|
||||
}
|
||||
|
||||
else -> emptySection
|
||||
}
|
||||
}
|
||||
}
|
||||
val ctx = testClientCodegenContext()
|
||||
val sut = ServiceConfigGenerator(ctx, listOf(ServiceCustomizer()))
|
||||
val symbolProvider = ctx.symbolProvider
|
||||
|
||||
val model = "namespace empty".asSmithyModel()
|
||||
val smithyRuntimeMode = SmithyRuntimeMode.fromString(smithyRuntimeModeStr)
|
||||
val codegenContext = testClientCodegenContext(model).withSmithyRuntimeMode(smithyRuntimeMode)
|
||||
val sut = ServiceConfigGenerator(codegenContext, listOf(ServiceCustomizer(codegenContext)))
|
||||
val symbolProvider = codegenContext.symbolProvider
|
||||
val project = TestWorkspace.testProject(symbolProvider)
|
||||
project.withModule(ClientRustModule.Config) {
|
||||
sut.render(this)
|
||||
unitTest(
|
||||
"set_config_fields",
|
||||
"""
|
||||
let mut builder = Config::builder();
|
||||
builder.config_field = Some(99);
|
||||
let config = builder.build();
|
||||
assert_eq!(config.config_field, 99);
|
||||
""",
|
||||
)
|
||||
if (smithyRuntimeMode.defaultToOrchestrator) {
|
||||
unitTest(
|
||||
"set_config_fields",
|
||||
"""
|
||||
let mut builder = Config::builder();
|
||||
builder.config_field = Some(99);
|
||||
let config = builder.build();
|
||||
assert_eq!(config.config_field(), 99);
|
||||
""",
|
||||
)
|
||||
} else {
|
||||
unitTest(
|
||||
"set_config_fields",
|
||||
"""
|
||||
let mut builder = Config::builder();
|
||||
builder.config_field = Some(99);
|
||||
let config = builder.build();
|
||||
assert_eq!(config.config_field, 99);
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
project.compileAndTest()
|
||||
}
|
||||
|
|
|
@ -104,8 +104,12 @@ class InlineDependency(
|
|||
CargoDependency.Http,
|
||||
)
|
||||
|
||||
fun idempotencyToken() =
|
||||
forInlineableRustFile("idempotency_token", CargoDependency.FastRand)
|
||||
fun idempotencyToken(runtimeConfig: RuntimeConfig) =
|
||||
forInlineableRustFile(
|
||||
"idempotency_token",
|
||||
CargoDependency.FastRand,
|
||||
CargoDependency.smithyTypes(runtimeConfig),
|
||||
)
|
||||
|
||||
fun ec2QueryErrors(runtimeConfig: RuntimeConfig): InlineDependency =
|
||||
forInlineableRustFile("ec2_query_errors", CargoDependency.smithyXml(runtimeConfig))
|
||||
|
@ -232,7 +236,8 @@ data class CargoDependency(
|
|||
val AsyncStream: CargoDependency = CargoDependency("async-stream", CratesIo("0.3.0"), DependencyScope.Dev)
|
||||
val Criterion: CargoDependency = CargoDependency("criterion", CratesIo("0.4.0"), DependencyScope.Dev)
|
||||
val FuturesCore: CargoDependency = CargoDependency("futures-core", CratesIo("0.3.25"), DependencyScope.Dev)
|
||||
val FuturesUtil: CargoDependency = CargoDependency("futures-util", CratesIo("0.3.25"), DependencyScope.Dev, defaultFeatures = false)
|
||||
val FuturesUtil: CargoDependency =
|
||||
CargoDependency("futures-util", CratesIo("0.3.25"), DependencyScope.Dev, defaultFeatures = false)
|
||||
val HdrHistogram: CargoDependency = CargoDependency("hdrhistogram", CratesIo("7.5.2"), DependencyScope.Dev)
|
||||
val Hound: CargoDependency = CargoDependency("hound", CratesIo("3.4.0"), DependencyScope.Dev)
|
||||
val PrettyAssertions: CargoDependency =
|
||||
|
|
|
@ -274,6 +274,7 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null)
|
|||
val String = std.resolve("string::String")
|
||||
val Sync = std.resolve("marker::Sync")
|
||||
val TryFrom = stdConvert.resolve("TryFrom")
|
||||
val U64 = std.resolve("primitive::u64")
|
||||
val Vec = std.resolve("vec::Vec")
|
||||
|
||||
// external cargo dependency types
|
||||
|
@ -431,7 +432,8 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null)
|
|||
fun unwrappedXmlErrors(runtimeConfig: RuntimeConfig) =
|
||||
forInlineDependency(InlineDependency.unwrappedXmlErrors(runtimeConfig))
|
||||
|
||||
val IdempotencyToken by lazy { forInlineDependency(InlineDependency.idempotencyToken()) }
|
||||
fun idempotencyToken(runtimeConfig: RuntimeConfig) =
|
||||
forInlineDependency(InlineDependency.idempotencyToken(runtimeConfig))
|
||||
|
||||
fun runtimePlugin(runtimeConfig: RuntimeConfig) =
|
||||
RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("client::runtime_plugin::RuntimePlugin")
|
||||
|
|
|
@ -10,6 +10,7 @@ import io.kotest.matchers.shouldBe
|
|||
import io.kotest.matchers.shouldNotBe
|
||||
import org.junit.jupiter.api.Test
|
||||
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.TestRuntimeConfig
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest
|
||||
import software.amazon.smithy.rust.codegen.core.testutil.unitTest
|
||||
|
@ -32,20 +33,23 @@ internal class InlineDependencyTest {
|
|||
|
||||
@Test
|
||||
fun `locate dependencies from the inlineable module`() {
|
||||
val dep = InlineDependency.idempotencyToken()
|
||||
val runtimeConfig = TestRuntimeConfig
|
||||
val dep = InlineDependency.serializationSettings(runtimeConfig)
|
||||
val testProject = TestWorkspace.testProject()
|
||||
testProject.lib {
|
||||
rustTemplate(
|
||||
"""
|
||||
|
||||
##[test]
|
||||
fn idempotency_works() {
|
||||
use #{idempotency}::uuid_v4;
|
||||
let res = uuid_v4(0);
|
||||
assert_eq!(res, "00000000-0000-4000-8000-000000000000");
|
||||
fn header_serialization_settings_can_be_constructed() {
|
||||
use #{serialization_settings}::HeaderSerializationSettings;
|
||||
use #{aws_smithy_http}::header::set_request_header_if_absent;
|
||||
let _settings = HeaderSerializationSettings::default();
|
||||
}
|
||||
|
||||
""",
|
||||
"idempotency" to dep.toType(),
|
||||
"serialization_settings" to dep.toType(),
|
||||
"aws_smithy_http" to RuntimeType.smithyHttp(runtimeConfig),
|
||||
)
|
||||
}
|
||||
testProject.compileAndTest()
|
||||
|
|
|
@ -12,6 +12,7 @@ rt-tokio = ["tokio/time"]
|
|||
test-util = []
|
||||
|
||||
[dependencies]
|
||||
aws-smithy-types = { path = "../aws-smithy-types" }
|
||||
pin-project-lite = "0.2"
|
||||
tokio = { version = "1.23.1", features = ["sync"] }
|
||||
tokio-stream = { version = "0.1.5", default-features = false }
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
allowed_external_types = [
|
||||
"aws_smithy_types::config_bag::storable::Storable",
|
||||
"aws_smithy_types::config_bag::storable::StoreReplace",
|
||||
"aws_smithy_types::config_bag::storable::Storer",
|
||||
|
||||
# TODO(https://github.com/awslabs/smithy-rs/issues/1193): Switch to AsyncIterator once standardized
|
||||
"futures_core::stream::Stream",
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//! Provides an [`AsyncSleep`] trait that returns a future that sleeps for a given duration,
|
||||
//! and implementations of `AsyncSleep` for different async runtimes.
|
||||
|
||||
use aws_smithy_types::config_bag::{Storable, StoreReplace};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
@ -68,6 +69,10 @@ impl AsyncSleep for SharedAsyncSleep {
|
|||
}
|
||||
}
|
||||
|
||||
impl Storable for SharedAsyncSleep {
|
||||
type Storer = StoreReplace<SharedAsyncSleep>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "rt-tokio")]
|
||||
/// Returns a default sleep implementation based on the features enabled
|
||||
pub fn default_async_sleep() -> Option<SharedAsyncSleep> {
|
||||
|
|
|
@ -24,7 +24,7 @@ pub struct ManualTimeSource {
|
|||
|
||||
impl TimeSource for ManualTimeSource {
|
||||
fn now(&self) -> SystemTime {
|
||||
self.start_time + self.log.lock().unwrap().iter().sum()
|
||||
self.start_time + self.log.lock().unwrap().iter().sum::<Duration>()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
//! Time source abstraction to support WASM and testing
|
||||
use aws_smithy_types::config_bag::{Storable, StoreReplace};
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
use std::time::SystemTime;
|
||||
|
@ -86,3 +87,7 @@ impl TimeSource for SharedTimeSource {
|
|||
self.0.now()
|
||||
}
|
||||
}
|
||||
|
||||
impl Storable for SharedTimeSource {
|
||||
type Storer = StoreReplace<SharedTimeSource>;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
use crate::erase::DynConnector;
|
||||
use aws_smithy_async::rt::sleep::SharedAsyncSleep;
|
||||
use aws_smithy_types::config_bag::{Storable, StoreReplace};
|
||||
use aws_smithy_types::timeout::TimeoutConfig;
|
||||
use std::time::Duration;
|
||||
use std::{fmt::Debug, sync::Arc};
|
||||
|
@ -41,6 +42,10 @@ impl Debug for HttpConnector {
|
|||
}
|
||||
}
|
||||
|
||||
impl Storable for HttpConnector {
|
||||
type Storer = StoreReplace<HttpConnector>;
|
||||
}
|
||||
|
||||
impl HttpConnector {
|
||||
/// If `HttpConnector` is `Prebuilt`, return a clone of that connector.
|
||||
/// If `HttpConnector` is `ConnectorFn`, generate a new connector from settings and return it.
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
use crate::endpoint::error::InvalidEndpointError;
|
||||
use crate::operation::error::BuildError;
|
||||
use aws_smithy_types::config_bag::{Storable, StoreReplace};
|
||||
use http::uri::{Authority, Uri};
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
@ -66,6 +67,10 @@ impl<T> From<Arc<dyn ResolveEndpoint<T>>> for SharedEndpointResolver<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> Storable for SharedEndpointResolver<T> {
|
||||
type Storer = StoreReplace<SharedEndpointResolver<T>>;
|
||||
}
|
||||
|
||||
impl<T> ResolveEndpoint<T> for SharedEndpointResolver<T> {
|
||||
fn resolve_endpoint(&self, params: &T) -> Result {
|
||||
self.0.resolve_endpoint(params)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
use crate::client::auth::AuthSchemeId;
|
||||
use crate::client::orchestrator::Future;
|
||||
use aws_smithy_types::config_bag::ConfigBag;
|
||||
use aws_smithy_types::config_bag::{ConfigBag, Storable, StoreReplace};
|
||||
use std::any::Any;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
@ -23,6 +23,10 @@ pub struct IdentityResolvers {
|
|||
identity_resolvers: Vec<(AuthSchemeId, Arc<dyn IdentityResolver>)>,
|
||||
}
|
||||
|
||||
impl Storable for IdentityResolvers {
|
||||
type Storer = StoreReplace<IdentityResolvers>;
|
||||
}
|
||||
|
||||
impl IdentityResolvers {
|
||||
pub fn builder() -> builders::IdentityResolversBuilder {
|
||||
builders::IdentityResolversBuilder::new()
|
||||
|
|
|
@ -9,7 +9,7 @@ pub mod error;
|
|||
use crate::client::interceptors::context::wrappers::{
|
||||
FinalizerInterceptorContextMut, FinalizerInterceptorContextRef,
|
||||
};
|
||||
use aws_smithy_types::config_bag::ConfigBag;
|
||||
use aws_smithy_types::config_bag::{ConfigBag, Storable, StoreAppend};
|
||||
use aws_smithy_types::error::display::DisplayErrorContext;
|
||||
pub use context::{
|
||||
wrappers::{
|
||||
|
@ -635,6 +635,10 @@ impl Deref for SharedInterceptor {
|
|||
}
|
||||
}
|
||||
|
||||
impl Storable for SharedInterceptor {
|
||||
type Storer = StoreAppend<SharedInterceptor>;
|
||||
}
|
||||
|
||||
/// Collection of [`SharedInterceptor`] that allows for only registration
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct InterceptorRegistrar {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
//! This module defines types that describe when to retry given a response.
|
||||
|
||||
use crate::config_bag::{Storable, StoreReplace};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
@ -278,6 +279,10 @@ pub struct RetryConfig {
|
|||
reconnect_mode: ReconnectMode,
|
||||
}
|
||||
|
||||
impl Storable for RetryConfig {
|
||||
type Storer = StoreReplace<RetryConfig>;
|
||||
}
|
||||
|
||||
/// Mode for connection re-establishment
|
||||
///
|
||||
/// By default, when a transient error is encountered, the connection in use will be poisoned. This
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//! This module defines types that describe timeouts that can be applied to various stages of the
|
||||
//! Smithy networking stack.
|
||||
|
||||
use crate::config_bag::{Storable, StoreReplace};
|
||||
use std::time::Duration;
|
||||
|
||||
/// Builder for [`TimeoutConfig`].
|
||||
|
@ -208,6 +209,10 @@ pub struct TimeoutConfig {
|
|||
operation_attempt_timeout: Option<Duration>,
|
||||
}
|
||||
|
||||
impl Storable for TimeoutConfig {
|
||||
type Storer = StoreReplace<TimeoutConfig>;
|
||||
}
|
||||
|
||||
impl TimeoutConfig {
|
||||
/// Returns a builder to create a `TimeoutConfig`.
|
||||
pub fn builder() -> TimeoutConfigBuilder {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
use aws_smithy_types::config_bag::{Storable, StoreReplace};
|
||||
use std::sync::Mutex;
|
||||
|
||||
pub(crate) fn uuid_v4(input: u128) -> String {
|
||||
|
@ -58,6 +59,10 @@ impl From<&'static str> for IdempotencyTokenProvider {
|
|||
}
|
||||
}
|
||||
|
||||
impl Storable for IdempotencyTokenProvider {
|
||||
type Storer = StoreReplace<IdempotencyTokenProvider>;
|
||||
}
|
||||
|
||||
impl IdempotencyTokenProvider {
|
||||
pub fn make_idempotency_token(&self) -> String {
|
||||
match &self.inner {
|
||||
|
|
Loading…
Reference in New Issue