Unverified Commit 1e2c03c9 authored by Thomas Cameron's avatar Thomas Cameron Committed by GitHub
Browse files

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: default avatarJohn DiSanti <johndisanti@gmail.com>
Co-authored-by: default avatarJohn DiSanti <jdisanti@amazon.com>
parent 45f27111
Loading
Loading
Loading
Loading
+37 −3
Original line number Diff line number Diff line
@@ -408,3 +408,37 @@ let scoped_plugin = Scoped::new::<SomeScope>(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 }
+36 −3
Original line number Diff line number Diff line
@@ -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}<crate::client::Handle${generics.inst}>) -> Self {",
@@ -370,6 +402,7 @@ class FluentClientGenerator(
                    }
                }
            }

            if (smithyRuntimeMode.generateMiddleware) {
                val middlewareScope = arrayOf(
                    *preludeScope,
+18 −4
Original line number Diff line number Diff line
@@ -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,6 +99,15 @@ data class FlexibleClientGenerics(
        rustTemplate(
            """
            where
                #{bounds}
            """,
            "bounds" to boundsWithoutWhereClause,
        )
    }

    override val boundsWithoutWhereClause = writable {
        rustTemplate(
            """
            C: #{client}::bounds::SmithyConnector,
            M: #{client}::bounds::SmithyMiddleware<C>,
            R: #{client}::retry::NewRequestPolicy,
@@ -112,7 +126,7 @@ data class FlexibleClientGenerics(
                #{OperationOutput},
                #{OperationError},
                #{RetryClassifier}
            >
            >,
            """,
            "client" to client,
            "Operation" to operation,
+4 −0
Original line number Diff line number Diff line
@@ -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)
    }
}
+20 −0
Original line number Diff line number Diff line
@@ -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<String>): 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)
Loading