From 1e2c03c9d1ce62daafbd9d8ec5bba8be1f250db7 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 15 Jun 2023 02:32:22 +0900 Subject: [PATCH] Add send_with method to fluent builders (#2652) ## Motivation and Context This is a child PR of https://github.com/awslabs/smithy-rs/pull/2615. ## Description - Adds `send_with` method to Fluent Builder. ## Prerequisite PRs You can merge this first too reduce diffs. - https://github.com/awslabs/smithy-rs/pull/2651 ## Testing NA ## Checklist NA ---- _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: John DiSanti Co-authored-by: John DiSanti --- CHANGELOG.next.toml | 40 +++++++++++++++++-- .../client/FluentClientGenerator.kt | 39 ++++++++++++++++-- .../generators/client/FluentClientGenerics.kt | 22 ++++++++-- .../codegen/core/rustlang/CargoDependency.kt | 4 ++ .../rust/codegen/core/rustlang/RustType.kt | 20 ++++++++++ .../rust/codegen/core/smithy/RuntimeType.kt | 5 +++ 6 files changed, 120 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index b7349422a4..7c40272066 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -15,7 +15,7 @@ message = "Fix bug in AWS JSON 1.x routers where, if a service had more than 14 operations, the router was created without the route for the 15th operation." author = "thor-bjorgvinsson" references = ["smithy-rs#2733"] -meta = { "breaking" = false, "tada" = false, "bug" = true, "target" ="server" } +meta = { "breaking" = false, "tada" = false, "bug" = true, "target" = "server" } [[aws-sdk-rust]] message = "Remove native-tls and add a migration guide." @@ -66,7 +66,7 @@ author = "jdisanti" [[smithy-rs]] message = "For event stream operations, the `EventStreamSender` in inputs/outputs now requires the passed in `Stream` impl to implement `Sync`." references = ["smithy-rs#2673"] -meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "all"} +meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "all" } author = "jdisanti" [[aws-sdk-rust]] @@ -143,7 +143,7 @@ author = "jdisanti" [[smithy-rs]] message = "Update MSRV to Rust 1.68.2" references = ["smithy-rs#2745"] -meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "all"} +meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "all" } author = "jdisanti" [[smithy-rs]] @@ -408,3 +408,37 @@ let scoped_plugin = Scoped::new::(plugin); references = ["smithy-rs#2740", "smithy-rs#2759"] meta = { "breaking" = true, "tada" = false, "bug" = false } author = "hlbarber" + +[[smithy-rs]] +message = "Implement unstable serde support for the `Number`, `Blob`, `Document`, `DateTime` primitives" +author = "thomas-k-cameron" +meta = { "breaking" = false, "tada" = true, "bug" = false, target = "all" } +references = [ + "smithy-rs#2647", + "smithy-rs#2645", + "smithy-rs#2646", + "smithy-rs#2616", +] + +[[aws-sdk-rust]] +message = "Implement unstable serde support for the `Number`, `Blob`, `Document`, `DateTime` primitives" +author = "thomas-k-cameron" +meta = { "breaking" = false, "tada" = true, "bug" = false } +references = [ + "smithy-rs#2647", + "smithy-rs#2645", + "smithy-rs#2646", + "smithy-rs#2616", +] + +[[smithy-rs]] +message = "Add a `send_with` function on `-Input` types for sending requests without fluent builders" +author = "thomas-k-cameron" +references = ["smithy-rs#2652"] +meta = { "breaking" = false, "tada" = true, "bug" = false, target = "client" } + +[[aws-sdk-rust]] +message = "Add a `send_with` function on `-Input` types for sending requests without fluent builders" +author = "thomas-k-cameron" +references = ["smithy-rs#2652"] +meta = { "breaking" = false, "tada" = true, "bug" = false } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 801bb1da1d..6e562b3317 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -30,6 +30,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.docLink import software.amazon.smithy.rust.codegen.core.rustlang.docs import software.amazon.smithy.rust.codegen.core.rustlang.documentShape import software.amazon.smithy.rust.codegen.core.rustlang.escape +import software.amazon.smithy.rust.codegen.core.rustlang.implBlock import software.amazon.smithy.rust.codegen.core.rustlang.normalizeHtml import software.amazon.smithy.rust.codegen.core.rustlang.qualifiedName import software.amazon.smithy.rust.codegen.core.rustlang.render @@ -315,10 +316,44 @@ class FluentClientGenerator( } private fun RustWriter.renderFluentBuilder(operation: OperationShape) { + val outputType = symbolProvider.toSymbol(operation.outputShape(model)) + val errorType = symbolProvider.symbolForOperationError(operation) val operationSymbol = symbolProvider.toSymbol(operation) + val input = operation.inputShape(model) val baseDerives = symbolProvider.toSymbol(input).expectRustMetadata().derives // Filter out any derive that isn't Clone. Then add a Debug derive + // input name + val fnName = clientOperationFnName(operation, symbolProvider) + implBlock(symbolProvider.symbolForBuilder(input)) { + rustTemplate( + """ + /// Sends a request with this input using the given client. + pub async fn send_with${generics.inst}(self, client: &crate::Client${generics.inst}) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}, #{RawResponseType}>> + #{send_bounds:W} + #{boundsWithoutWhereClause:W} + { + let mut fluent_builder = client.$fnName(); + fluent_builder.inner = self; + fluent_builder.send().await + } + """, + *preludeScope, + "RawResponseType" to if (codegenContext.smithyRuntimeMode.defaultToMiddleware) { + RuntimeType.smithyHttp(runtimeConfig).resolve("operation::Response") + } else { + RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("client::orchestrator::HttpResponse") + }, + "Operation" to operationSymbol, + "OperationError" to errorType, + "OperationOutput" to outputType, + "SdkError" to RuntimeType.sdkError(runtimeConfig), + "SdkSuccess" to RuntimeType.sdkSuccess(runtimeConfig), + "boundsWithoutWhereClause" to generics.boundsWithoutWhereClause, + "send_bounds" to generics.sendBounds(operationSymbol, outputType, errorType, retryClassifier), + ) + } + val derives = baseDerives.filter { it == RuntimeType.Clone } + RuntimeType.Debug docs("Fluent builder constructing a request to `${operationSymbol.name}`.\n") @@ -350,9 +385,6 @@ class FluentClientGenerator( "client" to RuntimeType.smithyClient(runtimeConfig), "bounds" to generics.bounds, ) { - val outputType = symbolProvider.toSymbol(operation.outputShape(model)) - val errorType = symbolProvider.symbolForOperationError(operation) - rust("/// Creates a new `${operationSymbol.name}`.") withBlockTemplate( "pub(crate) fn new(handle: #{Arc}) -> Self {", @@ -370,6 +402,7 @@ class FluentClientGenerator( } } } + if (smithyRuntimeMode.generateMiddleware) { val middlewareScope = arrayOf( *preludeScope, diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerics.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerics.kt index d37fb89057..a0b9f15c1a 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerics.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerics.kt @@ -34,6 +34,9 @@ interface FluentClientGenerics { /** Convert this `FluentClientGenerics` into the more general `RustGenerics` */ fun toRustGenerics(): RustGenerics + + /** bounds without where clause. If bounds does is not prefixed with `where\n`, then it gets the same value. **/ + val boundsWithoutWhereClause: Writable } class NoClientGenerics(private val runtimeConfig: RuntimeConfig) : FluentClientGenerics { @@ -55,6 +58,8 @@ class NoClientGenerics(private val runtimeConfig: RuntimeConfig) : FluentClientG /** Trait bounds */ override val bounds = writable { } + override val boundsWithoutWhereClause = writable {} + /** Bounds for generated `send()` functions */ override fun sendBounds( operation: Symbol, @@ -94,9 +99,18 @@ data class FlexibleClientGenerics( rustTemplate( """ where - C: #{client}::bounds::SmithyConnector, - M: #{client}::bounds::SmithyMiddleware, - R: #{client}::retry::NewRequestPolicy, + #{bounds} + """, + "bounds" to boundsWithoutWhereClause, + ) + } + + override val boundsWithoutWhereClause = writable { + rustTemplate( + """ + C: #{client}::bounds::SmithyConnector, + M: #{client}::bounds::SmithyMiddleware, + R: #{client}::retry::NewRequestPolicy, """, "client" to client, ) @@ -112,7 +126,7 @@ data class FlexibleClientGenerics( #{OperationOutput}, #{OperationError}, #{RetryClassifier} - > + >, """, "client" to client, "Operation" to operation, diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt index 72eba06a7d..952e3bb0ae 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt @@ -16,6 +16,7 @@ import java.nio.file.Path sealed class DependencyScope { object Dev : DependencyScope() object Compile : DependencyScope() + object CfgUnstable : DependencyScope() object Build : DependencyScope() } @@ -283,5 +284,8 @@ data class CargoDependency( fun smithyRuntimeApi(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-runtime-api") fun smithyTypes(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-types") fun smithyXml(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-xml") + + // behind feature-gate + val Serde = CargoDependency("serde", CratesIo("1.0"), features = setOf("derive"), scope = DependencyScope.CfgUnstable) } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt index 6d010089d2..6fc9ca7adf 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt @@ -475,6 +475,23 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { } } + // These were supposed to be a part of companion object but we decided to move it out to here to avoid NPE + // You can find the discussion here. + // https://github.com/awslabs/smithy-rs/discussions/2248 + public fun SerdeSerialize(): Attribute { + return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-serialize")), derive(RuntimeType.SerdeSerialize))) + } + public fun SerdeDeserialize(): Attribute { + return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-deserialize")), derive(RuntimeType.SerdeDeserialize))) + } + public fun SerdeSkip(): Attribute { + return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), any(feature("serde-serialize"), feature("serde-deserialize"))), serde("skip"))) + } + + public fun SerdeSerializeOrDeserialize(): Attribute { + return Attribute(cfg(all(writable("aws_sdk_unstable"), any(feature("serde-serialize"), feature("serde-deserialize"))))) + } + companion object { val AllowClippyBoxedLocal = Attribute(allow("clippy::boxed_local")) val AllowClippyLetAndReturn = Attribute(allow("clippy::let_and_return")) @@ -504,6 +521,7 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { val Test = Attribute("test") val TokioTest = Attribute(RuntimeType.Tokio.resolve("test").writable) + val AwsSdkUnstableAttribute = Attribute(cfg("aws_sdk_unstable")) /** * [non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute) @@ -532,10 +550,12 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { } fun all(vararg attrMacros: Writable): Writable = macroWithArgs("all", *attrMacros) + fun cfgAttr(vararg attrMacros: Writable): Writable = macroWithArgs("cfg_attr", *attrMacros) fun allow(lints: Collection): Writable = macroWithArgs("allow", *lints.toTypedArray()) fun allow(vararg lints: String): Writable = macroWithArgs("allow", *lints) fun deny(vararg lints: String): Writable = macroWithArgs("deny", *lints) + fun serde(vararg lints: String): Writable = macroWithArgs("serde", *lints) fun any(vararg attrMacros: Writable): Writable = macroWithArgs("any", *attrMacros) fun cfg(vararg attrMacros: Writable): Writable = macroWithArgs("cfg", *attrMacros) fun cfg(vararg attrMacros: String): Writable = macroWithArgs("cfg", *attrMacros) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt index 6e5b5ee8ff..0a25844584 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt @@ -301,6 +301,11 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) val ConstrainedTrait = RuntimeType("crate::constrained::Constrained", InlineDependency.constrained()) val MaybeConstrained = RuntimeType("crate::constrained::MaybeConstrained", InlineDependency.constrained()) + // serde types. Gated behind `CfgUnstable`. + val Serde = CargoDependency.Serde.toType() + val SerdeSerialize = Serde.resolve("Serialize") + val SerdeDeserialize = Serde.resolve("Deserialize") + // smithy runtime types fun smithyAsync(runtimeConfig: RuntimeConfig) = CargoDependency.smithyAsync(runtimeConfig).toType() fun smithyChecksums(runtimeConfig: RuntimeConfig) = CargoDependency.smithyChecksums(runtimeConfig).toType()