From 17d4b717172f42f3a1da785af8d813339c9ab4d4 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Thu, 11 May 2023 17:12:57 -0700 Subject: [PATCH] Fix client operation name collisions with the standard library prelude Operations named `Send` or `Sync` (and probably others) were colliding with the types in the standard library prelude and causing compiler errors. This PR adds tests that include all the type names from the Rust prelude, and fixes the compiler errors they cause. In the future, the `no_implicit_prelude` attribute can be added to certain code generated modules to better enforce that there can't be name collisions, but for now, the `tokio::test` macro doesn't compile with that attribute enabled (and likely other macros from other libraries). --- .../rustsdk/AwsFluentClientDecorator.kt | 9 +- .../smithy/rustsdk/AwsPresigningDecorator.kt | 3 +- .../rustsdk/customize/s3/S3Decorator.kt | 3 +- codegen-client-test/build.gradle.kts | 16 +++ .../codegen/client/smithy/ClientRustModule.kt | 8 +- .../IdempotencyTokenGenerator.kt | 8 +- .../smithy/endpoint/EndpointsDecorator.kt | 14 +- .../smithy/generators/ClientEnumGenerator.kt | 14 +- .../generators/NestedAccessorGenerator.kt | 10 +- .../smithy/generators/PaginatorGenerator.kt | 28 ++-- .../ServiceRuntimePluginGenerator.kt | 15 ++- .../client/CustomizableOperationGenerator.kt | 58 ++++---- .../client/FluentClientGenerator.kt | 43 +++--- .../error/OperationErrorGenerator.kt | 44 ++++-- .../http/RequestBindingGenerator.kt | 24 ++-- .../protocol/MakeOperationGenerator.kt | 13 +- .../protocol/ProtocolTestGenerator.kt | 2 +- .../protocols/HttpBoundProtocolGenerator.kt | 14 +- .../naming-obstacle-course-prelude-ops.smithy | 92 +++++++++++++ ...ing-obstacle-course-prelude-structs.smithy | 125 ++++++++++++++++++ .../codegen/core/rustlang/CargoDependency.kt | 2 +- .../rust/codegen/core/rustlang/RustModule.kt | 21 +-- .../rust/codegen/core/rustlang/RustType.kt | 3 +- .../rust/codegen/core/rustlang/RustWriter.kt | 24 +++- .../rust/codegen/core/smithy/RuntimeType.kt | 56 +++++++- .../smithy/generators/BuilderGenerator.kt | 23 ++-- .../core/smithy/generators/EnumGenerator.kt | 2 +- .../core/smithy/generators/Instantiator.kt | 13 +- .../core/smithy/generators/UnionGenerator.kt | 18 ++- .../generators/error/ErrorImplGenerator.kt | 6 +- .../parse/EventStreamUnmarshallerGenerator.kt | 2 +- 31 files changed, 540 insertions(+), 173 deletions(-) create mode 100644 codegen-core/common-test-models/naming-obstacle-course-prelude-ops.smithy create mode 100644 codegen-core/common-test-models/naming-obstacle-course-prelude-structs.smithy diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsFluentClientDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsFluentClientDecorator.kt index cca5c9f910..fa9c5ed63f 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsFluentClientDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsFluentClientDecorator.kt @@ -223,6 +223,7 @@ private fun renderCustomizableOperationSendMethod( val combinedGenerics = operationGenerics + handleGenerics val codegenScope = arrayOf( + *RuntimeType.preludeScope, "combined_generics_decl" to combinedGenerics.declaration(), "handle_generics_bounds" to handleGenerics.bounds(), "SdkSuccess" to RuntimeType.sdkSuccess(runtimeConfig), @@ -238,11 +239,11 @@ private fun renderCustomizableOperationSendMethod( #{handle_generics_bounds:W} { /// Sends this operation's request - pub async fn send(self) -> Result> + pub async fn send(self) -> #{Result}> where - E: std::error::Error + Send + Sync + 'static, - O: #{ParseHttpResponse}> + Send + Sync + Clone + 'static, - Retry: #{ClassifyRetry}<#{SdkSuccess}, #{SdkError}> + Send + Sync + Clone, + E: std::error::Error + #{Send} + #{Sync} + 'static, + O: #{ParseHttpResponse}> + #{Send} + #{Sync} + #{Clone} + 'static, + Retry: #{ClassifyRetry}<#{SdkSuccess}, #{SdkError}> + #{Send} + #{Sync} + #{Clone}, { self.handle.client.call(self.operation).await } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecorator.kt index 20d280ddf9..f6a3cd889c 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecorator.kt @@ -250,6 +250,7 @@ class AwsPresignedFluentBuilderMethod( ) : FluentClientCustomization() { private val codegenScope = ( presigningTypes + arrayOf( + *RuntimeType.preludeScope, "Error" to AwsRuntimeType.presigning().resolve("config::Error"), "SdkError" to RuntimeType.sdkError(runtimeConfig), ) @@ -264,7 +265,7 @@ class AwsPresignedFluentBuilderMethod( pub async fn presigned( self, presigning_config: #{PresigningConfig}, - ) -> Result<#{PresignedRequest}, #{SdkError}<#{OpError}>> + ) -> #{Result}<#{PresignedRequest}, #{SdkError}<#{OpError}>> """, *codegenScope, "OpError" to section.operationErrorType, diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt index 664494d021..0a2bd05212 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt @@ -131,6 +131,7 @@ class FilterEndpointTests( class S3ProtocolOverride(codegenContext: CodegenContext) : RestXml(codegenContext) { private val runtimeConfig = codegenContext.runtimeConfig private val errorScope = arrayOf( + *RuntimeType.preludeScope, "Bytes" to RuntimeType.Bytes, "ErrorMetadata" to RuntimeType.errorMetadata(runtimeConfig), "ErrorBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), @@ -143,7 +144,7 @@ class S3ProtocolOverride(codegenContext: CodegenContext) : RestXml(codegenContex override fun parseHttpErrorMetadata(operationShape: OperationShape): RuntimeType { return ProtocolFunctions.crossOperationFn("parse_http_error_metadata") { fnName -> rustBlockTemplate( - "pub fn $fnName(response_status: u16, _response_headers: &#{HeaderMap}, response_body: &[u8]) -> Result<#{ErrorBuilder}, #{XmlDecodeError}>", + "pub fn $fnName(response_status: u16, _response_headers: &#{HeaderMap}, response_body: &[u8]) -> #{Result}<#{ErrorBuilder}, #{XmlDecodeError}>", *errorScope, ) { rustTemplate( diff --git a/codegen-client-test/build.gradle.kts b/codegen-client-test/build.gradle.kts index f3796a6911..b833bfb195 100644 --- a/codegen-client-test/build.gradle.kts +++ b/codegen-client-test/build.gradle.kts @@ -92,6 +92,22 @@ val allCodegenTests = "../codegen-core/common-test-models".let { commonModels -> """.trimIndent(), imports = listOf("$commonModels/naming-obstacle-course-structs.smithy"), ), + CodegenTest( + "crate#Config", + "naming_test_prelude_ops", + """ + , "codegen": { "renameErrors": false } + """.trimIndent(), + imports = listOf("$commonModels/naming-obstacle-course-prelude-ops.smithy"), + ), + CodegenTest( + "crate#Config", + "naming_test_prelude_structs", + """ + , "codegen": { "renameErrors": false } + """.trimIndent(), + imports = listOf("$commonModels/naming-obstacle-course-prelude-structs.smithy"), + ), CodegenTest("aws.protocoltests.json#TestService", "endpoint-rules"), CodegenTest("com.aws.example.rust#PokemonService", "pokemon-service-client", imports = listOf("$commonModels/pokemon.smithy", "$commonModels/pokemon-common.smithy")), CodegenTest("com.aws.example.rust#PokemonService", "pokemon-service-awsjson-client", imports = listOf("$commonModels/pokemon-awsjson.smithy", "$commonModels/pokemon-common.smithy")), diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustModule.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustModule.kt index aa1f547dc4..988cac62f4 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustModule.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustModule.kt @@ -26,6 +26,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.ModuleDocProvider import software.amazon.smithy.rust.codegen.core.smithy.ModuleProvider import software.amazon.smithy.rust.codegen.core.smithy.ModuleProviderContext +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.contextName import software.amazon.smithy.rust.codegen.core.smithy.module import software.amazon.smithy.rust.codegen.core.smithy.traits.SyntheticInputTrait @@ -122,7 +123,7 @@ class ClientModuleDocProvider( operation call. For example, this can be used to add an additional HTTP header: ```ignore - ## async fn wrapper() -> Result<(), $moduleUseName::Error> { + ## async fn wrapper() -> #{Result}<(), $moduleUseName::Error> { ## let client: $moduleUseName::Client = unimplemented!(); use #{http}::header::{HeaderName, HeaderValue}; @@ -142,6 +143,7 @@ class ClientModuleDocProvider( ## } ``` """.trimIndent(), + *RuntimeType.preludeScope, "http" to CargoDependency.Http.toDevDependency().toType(), ) } @@ -194,6 +196,10 @@ object ClientModuleProvider : ModuleProvider { operationModuleName, parent = ClientRustModule.Operation, documentationOverride = "Types for the `$contextName` operation.", + // TODO(https://github.com/tokio-rs/tokio/issues/5683): Uncomment the NoImplicitPrelude attribute once this Tokio issue is resolved + // // Disable the Rust prelude since every prelude type should be referenced with its + // // fully qualified name to avoid name collisions with the generated operation shapes. + // additionalAttributes = listOf(Attribute.NoImplicitPrelude) ) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenGenerator.kt index 8dd67bb9fe..24738036e1 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenGenerator.kt @@ -8,9 +8,10 @@ package software.amazon.smithy.rust.codegen.client.smithy.customizations import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.traits.IdempotencyTokenTrait 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.Companion.preludeScope import software.amazon.smithy.rust.codegen.core.smithy.customize.OperationCustomization import software.amazon.smithy.rust.codegen.core.smithy.customize.OperationSection import software.amazon.smithy.rust.codegen.core.util.findMemberWithTrait @@ -28,12 +29,13 @@ class IdempotencyTokenGenerator(codegenContext: CodegenContext, operationShape: val memberName = symbolProvider.toMemberName(idempotencyTokenMember) return when (section) { is OperationSection.MutateInput -> writable { - rust( + rustTemplate( """ if ${section.input}.$memberName.is_none() { - ${section.input}.$memberName = Some(${section.config}.make_token.make_idempotency_token()); + ${section.input}.$memberName = #{Some}(${section.config}.make_token.make_idempotency_token()); } """, + *preludeScope, ) } else -> emptySection diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt index bc101412af..0678a4db40 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt @@ -25,6 +25,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.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.customize.OperationCustomization import software.amazon.smithy.rust.codegen.core.smithy.customize.OperationSection @@ -166,6 +167,7 @@ class EndpointsDecorator : ClientCodegenDecorator { override fun section(section: OperationSection): Writable { val codegenScope = arrayOf( + *RuntimeType.preludeScope, "Params" to typesGenerator.paramsStruct(), "ResolveEndpointError" to types.resolveEndpointError, ) @@ -174,10 +176,10 @@ class EndpointsDecorator : ClientCodegenDecorator { rustTemplate( """ let params_result = #{Params}::builder()#{builderFields:W}.build() - .map_err(|err|#{ResolveEndpointError}::from_source("could not construct endpoint parameters", err)); + .map_err(|err| #{ResolveEndpointError}::from_source("could not construct endpoint parameters", err)); let (endpoint_result, params) = match params_result { - Ok(params) => (${section.config}.endpoint_resolver.resolve_endpoint(¶ms), Some(params)), - Err(e) => (Err(e), None) + #{Ok}(params) => (${section.config}.endpoint_resolver.resolve_endpoint(¶ms), #{Some}(params)), + #{Err}(e) => (#{Err}(e), #{None}) }; """, "builderFields" to builderFields(typesGenerator.params, section), @@ -188,7 +190,7 @@ class EndpointsDecorator : ClientCodegenDecorator { is OperationSection.MutateRequest -> writable { // insert the endpoint the bag rustTemplate("${section.request}.properties_mut().insert(endpoint_result);") - rustTemplate("""if let Some(params) = params { ${section.request}.properties_mut().insert(params); }""") + rustTemplate("""if let #{Some}(params) = params { ${section.request}.properties_mut().insert(params); }""", *codegenScope) } else -> emptySection @@ -199,8 +201,8 @@ class EndpointsDecorator : ClientCodegenDecorator { val node = this return writable { when (node) { - is StringNode -> rust("Some(${node.value.dq()}.to_string())") - is BooleanNode -> rust("Some(${node.value})") + is StringNode -> rustTemplate("#{Some}(${node.value.dq()}.to_string())", *RuntimeType.preludeScope) + is BooleanNode -> rustTemplate("#{Some}(${node.value})", *RuntimeType.preludeScope) else -> PANIC("unsupported default value: $node") } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt index d1b87591cb..538e1df83b 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt @@ -17,6 +17,7 @@ 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.RuntimeType +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope import software.amazon.smithy.rust.codegen.core.smithy.generators.EnumGenerator import software.amazon.smithy.rust.codegen.core.smithy.generators.EnumGeneratorContext import software.amazon.smithy.rust.codegen.core.smithy.generators.EnumMemberModel @@ -60,16 +61,17 @@ data class InfallibleEnumType( } override fun implFromStr(context: EnumGeneratorContext): Writable = writable { - rust( + rustTemplate( """ - impl std::str::FromStr for ${context.enumName} { - type Err = std::convert::Infallible; + impl ::std::str::FromStr for ${context.enumName} { + type Err = ::std::convert::Infallible; - fn from_str(s: &str) -> std::result::Result { - Ok(${context.enumName}::from(s)) + fn from_str(s: &str) -> #{Result} { + #{Ok}(${context.enumName}::from(s)) } } """, + *preludeScope, ) } @@ -98,7 +100,7 @@ data class InfallibleEnumType( """.trimIndent(), ) context.enumMeta.render(this) - rust("struct $UnknownVariantValue(pub(crate) String);") + rustTemplate("struct $UnknownVariantValue(pub(crate) #{String});", *preludeScope) rustBlock("impl $UnknownVariantValue") { // The generated as_str is not pub as we need to prevent users from calling it on this opaque struct. rustBlock("pub(crate) fn as_str(&self) -> &str") { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/NestedAccessorGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/NestedAccessorGenerator.kt index 2c752814be..138c7eb123 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/NestedAccessorGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/NestedAccessorGenerator.kt @@ -15,6 +15,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.CodegenContext 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.isOptional import software.amazon.smithy.rust.codegen.core.smithy.makeOptional import software.amazon.smithy.rust.codegen.core.smithy.mapRustType @@ -72,17 +73,18 @@ class NestedAccessorGenerator(private val codegenContext: CodegenContext) { "" } if (path.isEmpty()) { - rust("Some(input)") + rustTemplate("#{Some}(input)", *preludeScope) } else { val head = path.first() if (symbolProvider.toSymbol(head).isOptional()) { - rust( + rustTemplate( """ let input = match ${ref}input.${symbolProvider.toMemberName(head)} { - None => return None, - Some(t) => t + #{None} => return #{None}, + #{Some}(t) => t }; """, + *preludeScope, ) } else { rust("let input = input.${symbolProvider.toMemberName(head)};") diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGenerator.kt index a20a33ecb0..d9709f5ff0 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGenerator.kt @@ -16,11 +16,11 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustType import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.render -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.stripOuter 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.rustType import software.amazon.smithy.rust.codegen.core.util.PANIC import software.amazon.smithy.rust.codegen.core.util.findMemberWithTrait @@ -86,6 +86,7 @@ class PaginatorGenerator private constructor( ) private val codegenScope = arrayOf( + *preludeScope, "generics" to generics.decl, "bounds" to generics.bounds, "page_size_setter" to pageSizeSetter(), @@ -158,31 +159,31 @@ class PaginatorGenerator private constructor( /// Create the pagination stream /// /// _Note:_ No requests will be dispatched until the stream is used (eg. with [`.next().await`](tokio_stream::StreamExt::next)). - pub fn send(self) -> impl #{Stream}>> + Unpin + pub fn send(self) -> impl #{Stream}>> + #{Unpin} #{send_bounds:W} { // Move individual fields out of self for the borrow checker let builder = self.builder; let handle = self.handle; - #{fn_stream}::FnStream::new(move |tx| Box::pin(async move { + #{fn_stream}::FnStream::new(move |tx| #{Box}::pin(async move { // Build the input for the first time. If required fields are missing, this is where we'll produce an early error. let mut input = match builder.build().map_err(#{SdkError}::construction_failure) { - Ok(input) => input, - Err(e) => { let _ = tx.send(Err(e)).await; return; } + #{Ok}(input) => input, + #{Err}(e) => { let _ = tx.send(#{Err}(e)).await; return; } }; loop { let op = match input.make_operation(&handle.conf) .await .map_err(#{SdkError}::construction_failure) { - Ok(op) => op, - Err(e) => { - let _ = tx.send(Err(e)).await; + #{Ok}(op) => op, + #{Err}(e) => { + let _ = tx.send(#{Err}(e)).await; return; } }; let resp = handle.client.call(op).await; // If the input member is None or it was an error let done = match resp { - Ok(ref resp) => { + #{Ok}(ref resp) => { let new_token = #{output_token}(resp); let is_empty = new_token.map(|token| token.is_empty()).unwrap_or(true); if !is_empty && new_token == input.$inputTokenMember.as_ref() && self.stop_on_duplicate_token { @@ -192,7 +193,7 @@ class PaginatorGenerator private constructor( is_empty } }, - Err(_) => true, + #{Err}(_) => true, }; if tx.send(resp).await.is_err() { // receiving end was dropped @@ -263,7 +264,7 @@ class PaginatorGenerator private constructor( /// _Note: No requests will be dispatched until the stream is used (eg. with [`.next().await`](tokio_stream::StreamExt::next))._ /// /// To read the entirety of the paginator, use [`.collect::, _>()`](tokio_stream::StreamExt::collect). - pub fn send(self) -> impl #{Stream}>> + Unpin + pub fn send(self) -> impl #{Stream}>> + #{Unpin} #{send_bounds:W} { #{fn_stream}::TryFlatMap::new(self.0.send()).flat_map(|page| #{extract_items}(page).unwrap_or_default().into_iter()) } @@ -284,16 +285,17 @@ class PaginatorGenerator private constructor( val memberName = symbolProvider.toMemberName(it) val pageSizeT = symbolProvider.toSymbol(it).rustType().stripOuter().render(true) - rust( + rustTemplate( """ /// Set the page size /// /// _Note: this method will override any previously set value for `$memberName`_ pub fn page_size(mut self, limit: $pageSizeT) -> Self { - self.builder.$memberName = Some(limit); + self.builder.$memberName = #{Some}(limit); self } """, + *preludeScope, ) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt index 25f9a19a5f..a5a0edca2c 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt @@ -14,6 +14,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.customize.NamedCustomization import software.amazon.smithy.rust.codegen.core.smithy.customize.Section import software.amazon.smithy.rust.codegen.core.smithy.customize.writeCustomizations @@ -67,6 +68,8 @@ class ServiceRuntimePluginGenerator( val runtime = RuntimeType.smithyRuntime(rc) val runtimeApi = RuntimeType.smithyRuntimeApi(rc) arrayOf( + *preludeScope, + "Arc" to RuntimeType.Arc, "AnonymousIdentityResolver" to runtimeApi.resolve("client::identity::AnonymousIdentityResolver"), "BoxError" to runtimeApi.resolve("client::runtime_plugin::BoxError"), "ConfigBag" to runtimeApi.resolve("config_bag::ConfigBag"), @@ -92,17 +95,17 @@ class ServiceRuntimePluginGenerator( """ ##[derive(Debug)] pub(crate) struct ServiceRuntimePlugin { - handle: std::sync::Arc, + handle: #{Arc}, } impl ServiceRuntimePlugin { - pub fn new(handle: std::sync::Arc) -> Self { + pub fn new(handle: #{Arc}) -> Self { Self { handle } } } impl #{RuntimePlugin} for ServiceRuntimePlugin { - fn configure(&self, cfg: &mut #{ConfigBag}, _interceptors: &mut #{Interceptors}) -> Result<(), #{BoxError}> { + fn configure(&self, cfg: &mut #{ConfigBag}, _interceptors: &mut #{Interceptors}) -> #{Result}<(), #{BoxError}> { use #{ConfigBagAccessors}; // HACK: Put the handle into the config bag to work around config not being fully implemented yet @@ -114,7 +117,7 @@ class ServiceRuntimePluginGenerator( cfg.set_http_auth_schemes(http_auth_schemes); // Set an empty auth option resolver to be overridden by operations that need auth. - cfg.set_auth_option_resolver(#{StaticAuthOptionResolver}::new(Vec::new())); + cfg.set_auth_option_resolver(#{StaticAuthOptionResolver}::new(#{Vec}::new())); let endpoint_resolver = #{DefaultEndpointResolver}::<#{Params}>::new( #{SharedEndpointResolver}::from(self.handle.conf.endpoint_resolver())); @@ -125,9 +128,9 @@ class ServiceRuntimePluginGenerator( // TODO(RuntimePlugins): Replace this with the correct long-term solution let sleep_impl = self.handle.conf.sleep_impl(); - let connection: Box = self.handle.conf.http_connector() + let connection: #{Box} = self.handle.conf.http_connector() .and_then(move |c| c.connector(&#{ConnectorSettings}::default(), sleep_impl)) - .map(|c| Box::new(#{DynConnectorAdapter}::new(c)) as _) + .map(|c| #{Box}::new(#{DynConnectorAdapter}::new(c)) as _) .expect("connection set"); cfg.set_connection(connection); diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGenerator.kt index a45bad43d0..d16d927d7f 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGenerator.kt @@ -14,6 +14,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate 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 /** @@ -54,33 +55,27 @@ class CustomizableOperationGenerator( val combinedGenerics = operationGenerics + handleGenerics val codegenScope = arrayOf( + *preludeScope, + "Arc" to RuntimeType.Arc, + "Infallible" to RuntimeType.stdConvert.resolve("Infallible"), // SDK Types - "http_result" to smithyHttp.resolve("result"), - "http_body" to smithyHttp.resolve("body"), "HttpRequest" to RuntimeType.HttpRequest, "handle_generics_decl" to handleGenerics.declaration(), "handle_generics_bounds" to handleGenerics.bounds(), "operation_generics_decl" to operationGenerics.declaration(), "combined_generics_decl" to combinedGenerics.declaration(), "customize_module" to ClientRustModule.Client.customize, + "SdkBody" to RuntimeType.sdkBody(runtimeConfig), ) writer.rustTemplate( """ - use crate::client::Handle; - - use #{http_body}::SdkBody; - use #{http_result}::SdkError; - - use std::convert::Infallible; - use std::sync::Arc; - /// A wrapper type for [`Operation`](aws_smithy_http::operation::Operation)s that allows for /// customization of the operation before it is sent. A `CustomizableOperation` may be sent /// by calling its [`.send()`][#{customize_module}::CustomizableOperation::send] method. ##[derive(Debug)] pub struct CustomizableOperation#{combined_generics_decl:W} { - pub(crate) handle: Arc, + pub(crate) handle: #{Arc}, pub(crate) operation: Operation#{operation_generics_decl:W}, } @@ -91,19 +86,19 @@ class CustomizableOperationGenerator( /// Allows for customizing the operation's request pub fn map_request( mut self, - f: impl FnOnce(#{HttpRequest}) -> Result<#{HttpRequest}, E>, - ) -> Result { + f: impl #{FnOnce}(#{HttpRequest}<#{SdkBody}>) -> #{Result}<#{HttpRequest}<#{SdkBody}>, E>, + ) -> #{Result} { let (request, response) = self.operation.into_request_response(); let request = request.augment(|req, _props| f(req))?; self.operation = Operation::from_parts(request, response); - Ok(self) + #{Ok}(self) } /// Convenience for `map_request` where infallible direct mutation of request is acceptable - pub fn mutate_request(self, f: impl FnOnce(&mut #{HttpRequest})) -> Self { + pub fn mutate_request(self, f: impl #{FnOnce}(&mut #{HttpRequest}<#{SdkBody}>)) -> Self { self.map_request(|mut req| { f(&mut req); - Result::<_, Infallible>::Ok(req) + #{Result}::<_, #{Infallible}>::Ok(req) }) .expect("infallible") } @@ -111,19 +106,19 @@ class CustomizableOperationGenerator( /// Allows for customizing the entire operation pub fn map_operation( mut self, - f: impl FnOnce(Operation#{operation_generics_decl:W}) -> Result, - ) -> Result { + f: impl #{FnOnce}(Operation#{operation_generics_decl:W}) -> #{Result}, + ) -> #{Result} { self.operation = f(self.operation)?; - Ok(self) + #{Ok}(self) } /// Direct access to read the HTTP request - pub fn request(&self) -> &#{HttpRequest} { + pub fn request(&self) -> &#{HttpRequest}<#{SdkBody}> { self.operation.request() } /// Direct access to mutate the HTTP request - pub fn request_mut(&mut self) -> &mut #{HttpRequest} { + pub fn request_mut(&mut self) -> &mut #{HttpRequest}<#{SdkBody}> { self.operation.request_mut() } } @@ -142,6 +137,7 @@ fun renderCustomizableOperationSend(runtimeConfig: RuntimeConfig, generics: Flue val combinedGenerics = operationGenerics + handleGenerics val codegenScope = arrayOf( + *preludeScope, "combined_generics_decl" to combinedGenerics.declaration(), "handle_generics_bounds" to handleGenerics.bounds(), "ParseHttpResponse" to smithyHttp.resolve("response::ParseHttpResponse"), @@ -160,13 +156,13 @@ fun renderCustomizableOperationSend(runtimeConfig: RuntimeConfig, generics: Flue #{handle_generics_bounds:W} { /// Sends this operation's request - pub async fn send(self) -> Result> + pub async fn send(self) -> #{Result}> where - E: std::error::Error + Send + Sync + 'static, - O: #{ParseHttpResponse}> + Send + Sync + Clone + 'static, - Retry: Send + Sync + Clone, - Retry: #{ClassifyRetry}<#{SdkSuccess}, #{SdkError}> + Send + Sync + Clone, - ::Policy: #{SmithyRetryPolicy} + Clone, + E: std::error::Error + #{Send} + #{Sync} + 'static, + O: #{ParseHttpResponse}> + #{Send} + #{Sync} + #{Clone} + 'static, + Retry: #{Send} + #{Sync} + #{Clone}, + Retry: #{ClassifyRetry}<#{SdkSuccess}, #{SdkError}> + #{Send} + #{Sync} + #{Clone}, + ::Policy: #{SmithyRetryPolicy} + #{Clone}, { self.handle.client.call(self.operation).await } @@ -182,11 +178,11 @@ fun renderCustomizableOperationSend(runtimeConfig: RuntimeConfig, generics: Flue #{handle_generics_bounds:W} { /// Sends this operation's request - pub async fn send(self) -> Result> + pub async fn send(self) -> #{Result}> where - E: std::error::Error + Send + Sync + 'static, - O: #{ParseHttpResponse}> + Send + Sync + Clone + 'static, - Retry: #{ClassifyRetry}<#{SdkSuccess}, #{SdkError}> + Send + Sync + Clone, + E: std::error::Error + #{Send} + #{Sync} + 'static, + O: #{ParseHttpResponse}> + #{Send} + #{Sync} + #{Clone} + 'static, + Retry: #{ClassifyRetry}<#{SdkSuccess}, #{SdkError}> + #{Send} + #{Sync} + #{Clone}, { self.handle.client.call(self.operation).await } 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 551a33a14a..10a4f0c02f 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 @@ -41,6 +41,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.stripOuter import software.amazon.smithy.rust.codegen.core.rustlang.withBlockTemplate 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.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.customize.writeCustomizations @@ -112,12 +113,12 @@ class FluentClientGenerator( } #{client_docs:W} - ##[derive(std::fmt::Debug)] + ##[derive(::std::fmt::Debug)] pub struct Client#{generics_decl:W} { - handle: std::sync::Arc + handle: #{Arc} } - impl${generics.inst} std::clone::Clone for Client${generics.inst} { + impl${generics.inst} #{Clone} for Client${generics.inst} { fn clone(&self) -> Self { Self { handle: self.handle.clone() } } @@ -133,7 +134,7 @@ class FluentClientGenerator( /// Creates a client with the given service configuration. pub fn with_config(client: #{client}::Client#{smithy_inst:W}, conf: crate::Config) -> Self { Self { - handle: std::sync::Arc::new(Handle { + handle: #{Arc}::new(Handle { client, conf, }) @@ -146,6 +147,8 @@ class FluentClientGenerator( } } """, + *preludeScope, + "Arc" to RuntimeType.Arc, "generics_decl" to generics.decl, "smithy_inst" to generics.smithyInst, "client" to RuntimeType.smithyClient(runtimeConfig), @@ -249,14 +252,15 @@ class FluentClientGenerator( ) { rustTemplate( """ - handle: std::sync::Arc, + handle: #{Arc}, inner: #{Inner}, """, "Inner" to symbolProvider.symbolForBuilder(input), + "Arc" to RuntimeType.Arc, "generics" to generics.decl, ) if (smithyRuntimeMode.generateOrchestrator) { - rust("config_override: std::option::Option,") + rustTemplate("config_override: #{Option},", *preludeScope) } } @@ -270,21 +274,23 @@ class FluentClientGenerator( rust("/// Creates a new `${operationSymbol.name}`.") withBlockTemplate( - "pub(crate) fn new(handle: std::sync::Arc) -> Self {", + "pub(crate) fn new(handle: #{Arc}) -> Self {", "}", + "Arc" to RuntimeType.Arc, "generics" to generics.decl, ) { withBlockTemplate( "Self {", "}", ) { - rust("handle, inner: Default::default(),") + rustTemplate("handle, inner: #{Default}::default(),", *preludeScope) if (smithyRuntimeMode.generateOrchestrator) { - rust("config_override: None,") + rustTemplate("config_override: #{None},", *preludeScope) } } } val middlewareScope = arrayOf( + *preludeScope, "CustomizableOperation" to ClientRustModule.Client.customize.toType() .resolve("CustomizableOperation"), "ClassifyRetry" to RuntimeType.classifyRetry(runtimeConfig), @@ -303,7 +309,7 @@ class FluentClientGenerator( """ /// Consume this builder, creating a customizable operation that can be modified before being /// sent. The operation's inner [http::Request] can be modified as well. - pub async fn customize(self) -> std::result::Result< + pub async fn customize(self) -> #{Result}< #{CustomizableOperation}#{customizable_op_type_params:W}, #{SdkError}<#{OperationError}> > #{send_bounds:W} { @@ -312,12 +318,12 @@ class FluentClientGenerator( .make_operation(&handle.conf) .await .map_err(#{SdkError}::construction_failure)?; - Ok(#{CustomizableOperation} { handle, operation }) + #{Ok}(#{CustomizableOperation} { handle, operation }) } // This function will go away in the near future. Do not rely on it. ##[doc(hidden)] - pub async fn send_middleware(self) -> std::result::Result<#{OperationOutput}, #{SdkError}<#{OperationError}>> + pub async fn send_middleware(self) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> #{send_bounds:W} { let op = self.inner.build().map_err(#{SdkError}::construction_failure)? .make_operation(&self.handle.conf) @@ -339,7 +345,7 @@ class FluentClientGenerator( /// By default, any retryable failures will be retried twice. Retry behavior /// is configurable with the [RetryConfig](aws_smithy_types::retry::RetryConfig), which can be /// set when configuring the client. - pub async fn send(self) -> std::result::Result<#{OperationOutput}, #{SdkError}<#{OperationError}>> + pub async fn send(self) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> #{send_bounds:W} { self.send_middleware().await } @@ -350,6 +356,7 @@ class FluentClientGenerator( if (smithyRuntimeMode.generateOrchestrator) { val orchestratorScope = arrayOf( + *preludeScope, "HttpResponse" to RuntimeType.smithyRuntimeApi(runtimeConfig) .resolve("client::orchestrator::HttpResponse"), "OperationError" to errorType, @@ -365,14 +372,14 @@ class FluentClientGenerator( rustTemplate( """ ##[doc(hidden)] - pub async fn send_orchestrator(self) -> std::result::Result<#{OperationOutput}, #{SdkError}<#{OperationError}, #{HttpResponse}>> { - self.send_orchestrator_with_plugin(Option::>::None).await + pub async fn send_orchestrator(self) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}, #{HttpResponse}>> { + self.send_orchestrator_with_plugin(#{Option}::>::None).await } ##[doc(hidden)] // TODO(enableNewSmithyRuntime): Delete when unused /// Equivalent to [`Self::send_orchestrator`] but adds a final runtime plugin to shim missing behavior - pub async fn send_orchestrator_with_plugin(self, final_plugin: Option) -> std::result::Result<#{OperationOutput}, #{SdkError}<#{OperationError}, #{HttpResponse}>> { + pub async fn send_orchestrator_with_plugin(self, final_plugin: #{Option}) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}, #{HttpResponse}>> { let mut runtime_plugins = #{RuntimePlugins}::new() .with_client_plugin(crate::config::ServiceRuntimePlugin::new(self.handle.clone())); if let Some(config_override) = self.config_override { @@ -393,7 +400,7 @@ class FluentClientGenerator( .unwrap() }) })?; - Ok(#{TypedBox}::<#{OperationOutput}>::assume_from(output).expect("correct output type").unwrap()) + #{Ok}(#{TypedBox}::<#{OperationOutput}>::assume_from(output).expect("correct output type").unwrap()) } """, *orchestratorScope, @@ -409,7 +416,7 @@ class FluentClientGenerator( /// By default, any retryable failures will be retried twice. Retry behavior /// is configurable with the [RetryConfig](aws_smithy_types::retry::RetryConfig), which can be /// set when configuring the client. - pub async fn send(self) -> std::result::Result<#{OperationOutput}, #{SdkError}<#{OperationError}, #{HttpResponse}>> { + pub async fn send(self) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}, #{HttpResponse}>> { self.send_orchestrator().await } """, diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/OperationErrorGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/OperationErrorGenerator.kt index 26d926a78d..8e17d5bd9d 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/OperationErrorGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/OperationErrorGenerator.kt @@ -22,10 +22,12 @@ 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.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock +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.errorMetadata +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.unhandledError import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.customize.Section @@ -107,14 +109,16 @@ class OperationErrorGenerator( ) } writer.rustBlock("impl #T for ${errorSymbol.name}", createUnhandledError) { - rustBlock( + rustBlockTemplate( """ fn create_unhandled_error( - source: Box, - meta: std::option::Option<#T> + source: #{Box}, + meta: #{Option}<#{ErrorMeta}> ) -> Self """, - errorMetadata, + *preludeScope, + "StdError" to RuntimeType.StdError, + "ErrorMeta" to errorMetadata, ) { rust( """ @@ -129,7 +133,7 @@ class OperationErrorGenerator( } } writer.rustBlock("impl #T for ${errorSymbol.name}", RuntimeType.Display) { - rustBlock("fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result") { + rustBlock("fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result") { delegateToVariants(errors) { writable { rust("_inner.fmt(f)") } } @@ -152,21 +156,28 @@ class OperationErrorGenerator( "impl #T for ${errorSymbol.name}", RuntimeType.provideErrorKind(symbolProvider.config.runtimeConfig), ) { - rustBlock("fn code(&self) -> std::option::Option<&str>") { + rustBlockTemplate("fn code(&self) -> #{Option}<&str>", *preludeScope) { rust("#T::code(self)", RuntimeType.provideErrorMetadataTrait(runtimeConfig)) } - rustBlock("fn retryable_error_kind(&self) -> std::option::Option<#T>", retryErrorKindT) { + rustBlockTemplate( + "fn retryable_error_kind(&self) -> #{Option}<#{ErrorKind}>", + "ErrorKind" to retryErrorKindT, + *preludeScope, + ) { val retryableVariants = errors.filter { it.hasTrait() } if (retryableVariants.isEmpty()) { - rust("None") + rustTemplate("#{None}", *preludeScope) } else { rustBlock("match self") { retryableVariants.forEach { val errorVariantSymbol = symbolProvider.toSymbol(it) - rust("Self::${errorVariantSymbol.name}(inner) => Some(inner.retryable_error_kind()),") + rustTemplate( + "Self::${errorVariantSymbol.name}(inner) => #{Some}(inner.retryable_error_kind()),", + *preludeScope, + ) } - rust("_ => None") + rustTemplate("_ => #{None}", *preludeScope) } } } @@ -176,7 +187,7 @@ class OperationErrorGenerator( writer.rustTemplate( """ /// Creates the `${errorSymbol.name}::Unhandled` variant from any error type. - pub fn unhandled(err: impl Into>) -> Self { + pub fn unhandled(err: impl #{Into}<#{Box}>) -> Self { Self::Unhandled(#{Unhandled}::builder().source(err).build()) } @@ -185,8 +196,9 @@ class OperationErrorGenerator( Self::Unhandled(#{Unhandled}::builder().source(err.clone()).meta(err).build()) } """, + *preludeScope, "error_metadata" to errorMetadata, - "std_error" to RuntimeType.StdError, + "StdError" to RuntimeType.StdError, "Unhandled" to unhandledError(runtimeConfig), ) writer.docs( @@ -216,10 +228,14 @@ class OperationErrorGenerator( } writer.rustBlock("impl #T for ${errorSymbol.name}", RuntimeType.StdError) { - rustBlock("fn source(&self) -> std::option::Option<&(dyn #T + 'static)>", RuntimeType.StdError) { + rustBlockTemplate( + "fn source(&self) -> #{Option}<&(dyn #{StdError} + 'static)>", + *preludeScope, + "StdError" to RuntimeType.StdError, + ) { delegateToVariants(errors) { writable { - rust("Some(_inner)") + rustTemplate("#{Some}(_inner)", *preludeScope) } } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGenerator.kt index 148a09d4bd..0a4e5fb09b 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGenerator.kt @@ -23,6 +23,7 @@ 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.smithy.CodegenContext 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.generators.OperationBuildError import software.amazon.smithy.rust.codegen.core.smithy.generators.http.HttpBindingGenerator import software.amazon.smithy.rust.codegen.core.smithy.generators.operationBuildError @@ -71,6 +72,7 @@ class RequestBindingGenerator( private val encoder = RuntimeType.smithyTypes(runtimeConfig).resolve("primitive::Encoder") private val codegenScope = arrayOf( + *preludeScope, "BuildError" to runtimeConfig.operationBuildError(), "HttpRequestBuilder" to RuntimeType.HttpRequestBuilder, "Input" to symbolProvider.toSymbol(inputShape), @@ -90,11 +92,11 @@ class RequestBindingGenerator( fn update_http_builder( input: &#{Input}, builder: #{HttpRequestBuilder} - ) -> std::result::Result<#{HttpRequestBuilder}, #{BuildError}> + ) -> #{Result}<#{HttpRequestBuilder}, #{BuildError}> """, *codegenScope, ) { - write("let mut uri = String::new();") + rustTemplate("let mut uri = #{String}::new();", *preludeScope) write("uri_base(input, &mut uri)?;") if (hasQuery) { write("uri_query(input, &mut uri)?;") @@ -107,7 +109,7 @@ class RequestBindingGenerator( addHeadersFn, ) } - write("Ok(builder.method(${httpTrait.method.dq()}).uri(uri))") + rustTemplate("#{Ok}(builder.method(${httpTrait.method.dq()}).uri(uri))", *preludeScope) } } @@ -126,7 +128,7 @@ class RequestBindingGenerator( } val combinedArgs = listOf(formatString, *args.toTypedArray()) writer.rustBlockTemplate( - "fn uri_base(_input: &#{Input}, output: &mut String) -> std::result::Result<(), #{BuildError}>", + "fn uri_base(_input: &#{Input}, output: &mut #{String}) -> #{Result}<(), #{BuildError}>", *codegenScope, ) { rust("use #T as _;", RuntimeType.stdFmt.resolve("Write")) @@ -134,8 +136,8 @@ class RequestBindingGenerator( val member = inputShape.expectMember(label.content) serializeLabel(member, label, local(member)) } - rust("""write!(output, ${combinedArgs.joinToString(", ")}).expect("formatting should succeed");""") - rust("Ok(())") + rust("""::std::write!(output, ${combinedArgs.joinToString(", ")}).expect("formatting should succeed");""") + rustTemplate("#{Ok}(())", *codegenScope) } } @@ -165,7 +167,7 @@ class RequestBindingGenerator( } val preloadedParams = literalParams.keys + dynamicParams.map { it.locationName } writer.rustBlockTemplate( - "fn uri_query(_input: &#{Input}, mut output: &mut String) -> Result<(), #{BuildError}>", + "fn uri_query(_input: &#{Input}, mut output: &mut #{String}) -> #{Result}<(), #{BuildError}>", *codegenScope, ) { write("let mut query = #T::new(output);", RuntimeType.queryFormat(runtimeConfig, "Writer")) @@ -212,6 +214,7 @@ class RequestBindingGenerator( if (memberShape.isRequired) { val codegenScope = arrayOf( + *preludeScope, "BuildError" to OperationBuildError(runtimeConfig).missingField( memberName, "cannot be empty or unset", @@ -229,7 +232,7 @@ class RequestBindingGenerator( // Strings that aren't enums must be checked to see if they're empty if (target.isStringShape && !target.hasTrait()) { rustBlock("if $derefName.is_empty()") { - rustTemplate("return Err(#{BuildError:W});", *codegenScope) + rustTemplate("return #{Err}(#{BuildError:W});", *codegenScope) } } @@ -241,7 +244,7 @@ class RequestBindingGenerator( } } } - writer.rust("Ok(())") + writer.rustTemplate("#{Ok}(())", *codegenScope) } return true } @@ -329,9 +332,10 @@ class RequestBindingGenerator( rustTemplate( """ if $outputVar.is_empty() { - return Err(#{buildError:W}) + return #{Err}(#{buildError:W}) } """, + *preludeScope, "buildError" to buildError, ) } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/MakeOperationGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/MakeOperationGenerator.kt index 5d206d47e8..8f2dcda292 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/MakeOperationGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/MakeOperationGenerator.kt @@ -20,6 +20,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.withBlock import software.amazon.smithy.rust.codegen.core.rustlang.withBlockTemplate 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.smithy.RuntimeType.Companion.preludeScope import software.amazon.smithy.rust.codegen.core.smithy.customize.OperationCustomization import software.amazon.smithy.rust.codegen.core.smithy.customize.OperationSection import software.amazon.smithy.rust.codegen.core.smithy.customize.writeCustomizations @@ -56,13 +57,15 @@ open class MakeOperationGenerator( ?: codegenContext.serviceShape.id.getName(codegenContext.serviceShape) private val codegenScope = arrayOf( + *preludeScope, "config" to ClientRustModule.Config, "header_util" to RuntimeType.smithyHttp(runtimeConfig).resolve("header"), "http" to RuntimeType.Http, + "operation" to RuntimeType.operationModule(runtimeConfig), "HttpRequestBuilder" to RuntimeType.HttpRequestBuilder, "OpBuildError" to runtimeConfig.operationBuildError(), - "operation" to RuntimeType.operationModule(runtimeConfig), "SdkBody" to RuntimeType.sdkBody(runtimeConfig), + "SharedPropertyBag" to RuntimeType.smithyHttp(runtimeConfig).resolve("property_bag::SharedPropertyBag"), ) fun generateMakeOperation( @@ -73,7 +76,7 @@ open class MakeOperationGenerator( val operationName = symbolProvider.toSymbol(shape).name val baseReturnType = buildOperationType(implBlockWriter, shape, customizations) val returnType = - "std::result::Result<$baseReturnType, ${implBlockWriter.format(runtimeConfig.operationBuildError())}>" + "#{Result}<$baseReturnType, ${implBlockWriter.format(runtimeConfig.operationBuildError())}>" val outputSymbol = symbolProvider.toSymbol(shape) val takesOwnership = bodyGenerator.payloadMetadata(shape).takesOwnership @@ -99,7 +102,7 @@ open class MakeOperationGenerator( withBlock("let mut request = {", "};") { createHttpRequest(this, shape) } - rust("let mut properties = aws_smithy_http::property_bag::SharedPropertyBag::new();") + rustTemplate("let mut properties = #{SharedPropertyBag}::new();", *codegenScope) // When the payload is a `ByteStream`, `into_inner()` already returns an `SdkBody`, so we mute this // Clippy warning to make the codegen a little simpler in that case. @@ -116,7 +119,7 @@ open class MakeOperationGenerator( if (includeDefaultPayloadHeaders && needsContentLength(shape)) { rustTemplate( """ - if let Some(content_length) = body.content_length() { + if let #{Some}(content_length) = body.content_length() { request = #{header_util}::set_request_header_if_absent(request, #{http}::header::CONTENT_LENGTH, content_length); } """, @@ -140,7 +143,7 @@ open class MakeOperationGenerator( "OperationType" to symbolProvider.toSymbol(shape), ) writeCustomizations(customizations, OperationSection.FinalizeOperation(customizations, "op", "_config")) - rust("Ok(op)") + rustTemplate("#{Ok}(op)", *codegenScope) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt index 5a1c4993b0..cafefc1179 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt @@ -351,7 +351,7 @@ class ProtocolTestGenerator( rustWriter.rustTemplate( """ // No body - #{AssertEq}(std::str::from_utf8(body).unwrap(), ""); + #{AssertEq}(::std::str::from_utf8(body).unwrap(), ""); """, *codegenScope, ) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt index 83578b2ac5..ae83e78cfe 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt @@ -19,6 +19,7 @@ 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 import software.amazon.smithy.rust.codegen.core.smithy.customize.OperationCustomization import software.amazon.smithy.rust.codegen.core.smithy.customize.OperationSection import software.amazon.smithy.rust.codegen.core.smithy.customize.writeCustomizations @@ -61,6 +62,7 @@ open class HttpBoundProtocolTraitImplGenerator( private val parserGenerator = ProtocolParserGenerator(codegenContext, protocol) private val codegenScope = arrayOf( + *preludeScope, "ParseStrict" to RuntimeType.parseStrictResponse(runtimeConfig), "ParseResponse" to RuntimeType.parseHttpResponse(runtimeConfig), "http" to RuntimeType.Http, @@ -114,7 +116,7 @@ open class HttpBoundProtocolTraitImplGenerator( rustTemplate( """ impl #{ParseStrict} for $operationName { - type Output = std::result::Result<#{O}, #{E}>; + type Output = #{Result}<#{O}, #{E}>; fn parse(&self, response: &#{http}::Response<#{Bytes}>) -> Self::Output { let (success, status) = (response.status().is_success(), response.status().as_u16()); let headers = response.headers(); @@ -144,14 +146,14 @@ open class HttpBoundProtocolTraitImplGenerator( rustTemplate( """ impl #{ParseResponse} for $operationName { - type Output = std::result::Result<#{O}, #{E}>; - fn parse_unloaded(&self, response: &mut #{operation}::Response) -> Option { + type Output = #{Result}<#{O}, #{E}>; + fn parse_unloaded(&self, response: &mut #{operation}::Response) -> #{Option} { #{BeforeParseResponse} // This is an error, defer to the non-streaming parser if !response.http().status().is_success() && response.http().status().as_u16() != $successCode { - return None; + return #{None}; } - Some(#{parse_streaming_response}(response)) + #{Some}(#{parse_streaming_response}(response)) } fn parse_loaded(&self, response: &#{http}::Response<#{Bytes}>) -> Self::Output { // if streaming, we only hit this case if its an error @@ -180,7 +182,7 @@ open class HttpBoundProtocolTraitImplGenerator( return protocolFunctions.deserializeFn(operationShape, fnNameSuffix = "op_response") { fnName -> Attribute.AllowClippyUnnecessaryWraps.render(this) rustBlockTemplate( - "pub fn $fnName(op_response: &mut #{operation}::Response) -> std::result::Result<#{O}, #{E}>", + "pub fn $fnName(op_response: &mut #{operation}::Response) -> #{Result}<#{O}, #{E}>", *codegenScope, "O" to outputSymbol, "E" to errorSymbol, diff --git a/codegen-core/common-test-models/naming-obstacle-course-prelude-ops.smithy b/codegen-core/common-test-models/naming-obstacle-course-prelude-ops.smithy new file mode 100644 index 0000000000..36b7ee61d3 --- /dev/null +++ b/codegen-core/common-test-models/naming-obstacle-course-prelude-ops.smithy @@ -0,0 +1,92 @@ +$version: "1.0" +namespace crate + +use smithy.test#httpRequestTests +use smithy.test#httpResponseTests +use aws.protocols#awsJson1_1 +use aws.api#service +use smithy.framework#ValidationException + +/// Confounds model generation machinery by using operations named after every item in the Rust prelude +@awsJson1_1 +@service(sdkId: "Config") +service Config { + version: "2006-03-01", + operations: [ + // Rust Prelude + Copy, + Send, + Sized, + Sync, + Unpin, + Drop, + Fn, + FnMut, + FnOnce, + Box, + ToOwned, + Clone, + PartialEq, + PartialOrd, + Eq, + Ord, + AsRef, + AsMut, + Into, + From, + Default, + Iterator, + Extend, + IntoIterator, + DoubleEndedIterator, + ExactSizeIterator, + Option, + Some, + None, + Result, + Ok, + Err, + String, + ToString, + Vec, + ] +} + +structure Input {} +structure Output {} + +operation Copy { input: Input, output: Output } +operation Send { input: Input, output: Output } +operation Sized { input: Input, output: Output } +operation Sync { input: Input, output: Output } +operation Unpin { input: Input, output: Output } +operation Drop { input: Input, output: Output } +operation Fn { input: Input, output: Output } +operation FnMut { input: Input, output: Output } +operation FnOnce { input: Input, output: Output } +operation Box { input: Input, output: Output } +operation ToOwned { input: Input, output: Output } +operation Clone { input: Input, output: Output } +operation PartialEq { input: Input, output: Output } +operation PartialOrd { input: Input, output: Output } +operation Eq { input: Input, output: Output } +operation Ord { input: Input, output: Output } +operation AsRef { input: Input, output: Output } +operation AsMut { input: Input, output: Output } +operation Into { input: Input, output: Output } +operation From { input: Input, output: Output } +operation Default { input: Input, output: Output } +operation Iterator { input: Input, output: Output } +operation Extend { input: Input, output: Output } +operation IntoIterator { input: Input, output: Output } +operation DoubleEndedIterator { input: Input, output: Output } +operation ExactSizeIterator { input: Input, output: Output } +operation Option { input: Input, output: Output } +operation Some { input: Input, output: Output } +operation None { input: Input, output: Output } +operation Result { input: Input, output: Output } +operation Ok { input: Input, output: Output } +operation Err { input: Input, output: Output } +operation String { input: Input, output: Output } +operation ToString { input: Input, output: Output } +operation Vec { input: Input, output: Output } diff --git a/codegen-core/common-test-models/naming-obstacle-course-prelude-structs.smithy b/codegen-core/common-test-models/naming-obstacle-course-prelude-structs.smithy new file mode 100644 index 0000000000..0047c182c3 --- /dev/null +++ b/codegen-core/common-test-models/naming-obstacle-course-prelude-structs.smithy @@ -0,0 +1,125 @@ +$version: "1.0" +namespace crate + +use smithy.test#httpRequestTests +use smithy.test#httpResponseTests +use aws.protocols#awsJson1_1 +use aws.api#service +use smithy.framework#ValidationException + +/// Confounds model generation machinery by using structs named after every item in the Rust prelude +@awsJson1_1 +@service(sdkId: "Config") +service Config { + version: "2006-03-01", + operations: [ + UseCopy, + UseSend, + UseSized, + UseSync, + UseUnpin, + UseDrop, + UseFn, + UseFnMut, + UseFnOnce, + UseBox, + UseToOwned, + UseClone, + UsePartialEq, + UsePartialOrd, + UseEq, + UseOrd, + UseAsRef, + UseAsMut, + UseInto, + UseFrom, + UseDefault, + UseIterator, + UseExtend, + UseIntoIterator, + UseDoubleEndedIterator, + UseExactSizeIterator, + UseOption, + UseSome, + UseNone, + UseResult, + UseOk, + UseErr, + UseString, + UseToString, + UseVec, + ] +} + +// Rust Prelude +structure Copy {} +structure Send {} +structure Sized {} +structure Sync {} +structure Unpin {} +structure Drop {} +structure Fn {} +structure FnMut {} +structure FnOnce {} +structure Box {} +structure ToOwned {} +structure Clone {} +structure PartialEq {} +structure PartialOrd {} +structure Eq {} +structure Ord {} +structure AsRef {} +structure AsMut {} +structure Into {} +structure From {} +structure Default {} +structure Iterator {} +structure Extend {} +structure IntoIterator {} +structure DoubleEndedIterator {} +structure ExactSizeIterator {} +structure Option {} +structure Some {} +structure None {} +structure Result {} +structure Ok {} +structure Err {} +structure String {} +structure ToString {} +structure Vec {} + +operation UseCopy { input: Copy, output: Copy } +operation UseSend { input: Send, output: Send } +operation UseSized { input: Sized, output: Sized } +operation UseSync { input: Sync, output: Sync } +operation UseUnpin { input: Unpin, output: Unpin } +operation UseDrop { input: Drop, output: Drop } +operation UseFn { input: Fn, output: Fn } +operation UseFnMut { input: FnMut, output: FnMut } +operation UseFnOnce { input: FnOnce, output: FnOnce } +operation UseBox { input: Box, output: Box } +operation UseToOwned { input: ToOwned, output: ToOwned } +operation UseClone { input: Clone, output: Clone } +operation UsePartialEq { input: PartialEq, output: PartialEq } +operation UsePartialOrd { input: PartialOrd, output: PartialOrd } +operation UseEq { input: Eq, output: Eq } +operation UseOrd { input: Ord, output: Ord } +operation UseAsRef { input: AsRef, output: AsRef } +operation UseAsMut { input: AsMut, output: AsMut } +operation UseInto { input: Into, output: Into } +operation UseFrom { input: From, output: From } +operation UseDefault { input: Default, output: Default } +operation UseIterator { input: Iterator, output: Iterator } +operation UseExtend { input: Extend, output: Extend } +operation UseIntoIterator { input: IntoIterator, output: IntoIterator } +operation UseDoubleEndedIterator { input: DoubleEndedIterator, output: DoubleEndedIterator } +operation UseExactSizeIterator { input: ExactSizeIterator, output: ExactSizeIterator } +operation UseOption { input: Option, output: Option } +operation UseSome { input: Some, output: Some } +operation UseNone { input: None, output: None } +operation UseResult { input: Result, output: Result } +operation UseOk { input: Ok, output: Ok } +operation UseErr { input: Err, output: Err } +operation UseString { input: String, output: String } +operation UseToString { input: ToString, output: ToString } +operation UseVec { input: Vec, output: Vec } 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 2e372b4989..6976236d85 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 @@ -197,7 +197,7 @@ data class CargoDependency( } fun toType(): RuntimeType { - return RuntimeType(rustName, this) + return RuntimeType("::$rustName", this) } companion object { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustModule.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustModule.kt index b8c3237e41..78dee92dae 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustModule.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustModule.kt @@ -79,14 +79,19 @@ sealed class RustModule { } /** Creates a new public module */ - fun public(name: String, parent: RustModule = LibRs, documentationOverride: String? = null): LeafModule = - new( - name, - visibility = Visibility.PUBLIC, - inline = false, - parent = parent, - documentationOverride = documentationOverride, - ) + fun public( + name: String, + parent: RustModule = LibRs, + documentationOverride: String? = null, + additionalAttributes: List = emptyList(), + ): LeafModule = new( + name, + visibility = Visibility.PUBLIC, + inline = false, + parent = parent, + documentationOverride = documentationOverride, + additionalAttributes = additionalAttributes, + ) /** Creates a new private module */ fun private(name: String, parent: RustModule = LibRs): LeafModule = 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 79dde7de12..6d010089d2 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 @@ -199,7 +199,7 @@ fun RustType.qualifiedName(): String { /** Format this Rust type as an `impl Into` */ fun RustType.implInto(fullyQualified: Boolean = true): String { - return "impl Into<${this.render(fullyQualified)}>" + return "impl ${RuntimeType.Into.fullyQualifiedName()}<${this.render(fullyQualified)}>" } /** Format this Rust type so that it may be used as an argument type in a function definition */ @@ -498,6 +498,7 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { val DenyMissingDocs = Attribute(deny("missing_docs")) val DocHidden = Attribute(doc("hidden")) val DocInline = Attribute(doc("inline")) + val NoImplicitPrelude = Attribute("no_implicit_prelude") fun shouldPanic(expectedMessage: String) = Attribute(macroWithArgs("should_panic", "expected = ${expectedMessage.dq()}")) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt index 61f219488a..5781a3404e 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt @@ -26,6 +26,7 @@ import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.deprecated import software.amazon.smithy.rust.codegen.core.smithy.ModuleDocProvider 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.isOptional import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.ValueExpression import software.amazon.smithy.rust.codegen.core.smithy.rustType @@ -142,6 +143,27 @@ fun > T.conditionalBlock( return this } +fun RustWriter.conditionalBlockTemplate( + textBeforeNewLine: String, + textAfterNewLine: String, + conditional: Boolean = true, + vararg args: Pair, + block: RustWriter.() -> Unit, +): RustWriter { + if (conditional) { + withTemplate(textBeforeNewLine.trim(), args) { text -> + openBlock(text) + } + } + block(this) + if (conditional) { + withTemplate(textAfterNewLine.trim(), args) { text -> + closeBlock(text) + } + } + return this +} + /** * Convenience wrapper that tells Intellij that the contents of this block are Rust */ @@ -608,7 +630,7 @@ class RustWriter private constructor( when { member.isOptional() -> { val innerValue = ValueExpression.Reference(safeName("inner")) - rustBlock("if let Some(${innerValue.name}) = ${value.asRef()}") { + rustBlockTemplate("if let #{Some}(${innerValue.name}) = ${value.asRef()}", *preludeScope) { block(innerValue) } } 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 f8c656c08e..6616fdd96f 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 @@ -193,14 +193,57 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) * The companion object contains commonly used RuntimeTypes */ companion object { + /** Scope that contains all Rust prelude types, but not macros or functions */ + val preludeScope by lazy { + arrayOf( + "Copy" to std.resolve("marker::Copy"), + "Send" to Send, + "Sized" to std.resolve("marker::Sized"), + "Sync" to Sync, + "Unpin" to std.resolve("marker::Unpin"), + "Drop" to std.resolve("ops::Drop"), + "Fn" to std.resolve("ops::Fn"), + "FnMut" to std.resolve("ops::FnMut"), + "FnOnce" to std.resolve("ops::FnOnce"), + "Box" to Box, + "ToOwned" to std.resolve("borrow::ToOwned"), + "Clone" to Clone, + "PartialEq" to std.resolve("cmp::PartialEq"), + "PartialOrd" to std.resolve("cmp::PartialOrd"), + "Eq" to Eq, + "Ord" to Ord, + "AsRef" to AsRef, + "AsMut" to std.resolve("convert::AsMut"), + "Into" to Into, + "From" to From, + "Default" to Default, + "Iterator" to std.resolve("iter::Iterator"), + "Extend" to std.resolve("iter::Extend"), + "IntoIterator" to std.resolve("iter::IntoIterator"), + "DoubleEndedIterator" to std.resolve("iter::DoubleEndedIterator"), + "ExactSizeIterator" to std.resolve("iter::ExactSizeIterator"), + "Option" to Option, + "Some" to Option.resolve("Some"), + "None" to Option.resolve("None"), + "Result" to std.resolve("result::Result"), + "Ok" to std.resolve("result::Result::Ok"), + "Err" to std.resolve("result::Result::Err"), + "String" to String, + "ToString" to std.resolve("string::ToString"), + "Vec" to Vec, + ) + } + // stdlib types - val std = RuntimeType("std") + val std = RuntimeType("::std") val stdCmp = std.resolve("cmp") val stdFmt = std.resolve("fmt") val stdConvert = std.resolve("convert") + val Arc = std.resolve("sync::Arc") val AsRef = stdConvert.resolve("AsRef") - val ByteSlab = std.resolve("vec::Vec") + val Bool = std.resolve("primitive::bool") val Box = std.resolve("boxed::Box") + val ByteSlab = std.resolve("vec::Vec") val Clone = std.resolve("clone::Clone") val Cow = std.resolve("borrow::Cow") val Debug = stdFmt.resolve("Debug") @@ -210,19 +253,18 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) val From = stdConvert.resolve("From") val Hash = std.resolve("hash::Hash") val HashMap = std.resolve("collections::HashMap") - val Ord = stdCmp.resolve("Ord") + val Into = stdConvert.resolve("Into") val Option = std.resolve("option::Option") + val Ord = stdCmp.resolve("Ord") val PartialEq = stdCmp.resolve("PartialEq") val PartialOrd = stdCmp.resolve("PartialOrd") val Phantom = std.resolve("marker::PhantomData") + val Send = std.resolve("marker::Send") val StdError = std.resolve("error::Error") val String = std.resolve("string::String") - val Bool = std.resolve("primitive::bool") + val Sync = std.resolve("marker::Sync") val TryFrom = stdConvert.resolve("TryFrom") val Vec = std.resolve("vec::Vec") - val Arc = std.resolve("sync::Arc") - val Send = std.resolve("marker::Send") - val Sync = std.resolve("marker::Sync") // external cargo dependency types val Bytes = CargoDependency.Bytes.toType().resolve("Bytes") diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt index 16cb28b803..da008a6bee 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt @@ -17,13 +17,14 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.asArgument import software.amazon.smithy.rust.codegen.core.rustlang.asOptional -import software.amazon.smithy.rust.codegen.core.rustlang.conditionalBlock +import software.amazon.smithy.rust.codegen.core.rustlang.conditionalBlockTemplate import software.amazon.smithy.rust.codegen.core.rustlang.deprecatedShape 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.render 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.rustBlockTemplate import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.stripOuter import software.amazon.smithy.rust.codegen.core.rustlang.withBlock @@ -31,6 +32,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.Default 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.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.canUseDefault import software.amazon.smithy.rust.codegen.core.smithy.customize.NamedCustomization @@ -126,7 +128,6 @@ class BuilderGenerator( private val runtimeConfig = symbolProvider.config.runtimeConfig private val members: List = shape.allMembers.values.toList() private val structureSymbol = symbolProvider.toSymbol(shape) - private val builderSymbol = symbolProvider.symbolForBuilder(shape) private val metadata = structureSymbol.expectRustMetadata() // Filter out any derive that isn't Debug, PartialEq, or Clone. Then add a Default derive @@ -147,12 +148,12 @@ class BuilderGenerator( val fallibleBuilder = hasFallibleBuilder(shape, symbolProvider) val outputSymbol = symbolProvider.toSymbol(shape) val returnType = when (fallibleBuilder) { - true -> "Result<${implBlockWriter.format(outputSymbol)}, ${implBlockWriter.format(runtimeConfig.operationBuildError())}>" + true -> "#{Result}<${implBlockWriter.format(outputSymbol)}, ${implBlockWriter.format(runtimeConfig.operationBuildError())}>" false -> implBlockWriter.format(outputSymbol) } implBlockWriter.docs("Consumes the builder and constructs a #D.", outputSymbol) - implBlockWriter.rustBlock("pub fn build(self) -> $returnType") { - conditionalBlock("Ok(", ")", conditional = fallibleBuilder) { + implBlockWriter.rustBlockTemplate("pub fn build(self) -> $returnType", *preludeScope) { + conditionalBlockTemplate("#{Ok}(", ")", conditional = fallibleBuilder, *preludeScope) { // If a wrapper is specified, use the `::new` associated function to construct the wrapper coreBuilder(this) } @@ -182,7 +183,7 @@ class BuilderGenerator( writer.documentShape(member, model) writer.deprecatedShape(member) writer.rustBlock("pub fn $memberName(mut self, ${input.argument}) -> Self") { - write("self.$memberName = Some(${input.value});") + rustTemplate("self.$memberName = #{Some}(${input.value});", *preludeScope) write("self") } } @@ -273,13 +274,14 @@ class BuilderGenerator( val input = coreType.member.asArgument("input") rustBlock("pub fn $memberName(mut self, ${input.argument}) -> Self") { - rust( + rustTemplate( """ let mut v = self.$memberName.unwrap_or_default(); v.push(${input.value}); - self.$memberName = Some(v); + self.$memberName = #{Some}(v); self """, + *preludeScope, ) } } @@ -297,13 +299,14 @@ class BuilderGenerator( rustBlock( "pub fn $memberName(mut self, ${k.argument}, ${v.argument}) -> Self", ) { - rust( + rustTemplate( """ let mut hash_map = self.$memberName.unwrap_or_default(); hash_map.insert(${k.value}, ${v.value}); - self.$memberName = Some(hash_map); + self.$memberName = #{Some}(hash_map); self """, + *preludeScope, ) } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt index 379a6982da..d5565880f1 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt @@ -295,7 +295,7 @@ open class EnumGenerator( """ impl #{Debug} for ${context.enumName} { fn fmt(&self, f: &mut #{StdFmt}::Formatter<'_>) -> #{StdFmt}::Result { - write!(f, $REDACTION) + ::std::write!(f, $REDACTION) } } """, diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/Instantiator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/Instantiator.kt index e77f942a29..089143feea 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/Instantiator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/Instantiator.kt @@ -37,7 +37,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.RustType import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Writable -import software.amazon.smithy.rust.codegen.core.rustlang.conditionalBlock +import software.amazon.smithy.rust.codegen.core.rustlang.conditionalBlockTemplate import software.amazon.smithy.rust.codegen.core.rustlang.escape import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock @@ -47,6 +47,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.withBlock 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.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.customize.NamedCustomization import software.amazon.smithy.rust.codegen.core.smithy.customize.Section @@ -208,17 +209,19 @@ open class Instantiator( } else { // Structure builder setters for structure shape members _always_ take in `Option`. // Other aggregate shapes' members are optional only when their symbol is. - writer.conditionalBlock( - "Some(", + writer.conditionalBlockTemplate( + "#{Some}(", ")", // The conditions are not commutative: note client builders always take in `Option`. conditional = symbol.isOptional() || (model.expectShape(memberShape.container) is StructureShape && builderKindBehavior.doesSetterTakeInOption(memberShape)), + *preludeScope, ) { - writer.conditionalBlock( - "Box::new(", + writer.conditionalBlockTemplate( + "#{Box}::new(", ")", conditional = symbol.rustType().stripOuter() is RustType.Box, + *preludeScope, ) { render( this, diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt index 39b191ba96..3f7927d728 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt @@ -19,9 +19,11 @@ import software.amazon.smithy.rust.codegen.core.rustlang.documentShape import software.amazon.smithy.rust.codegen.core.rustlang.render 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.rustBlockTemplate import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget 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.expectRustMetadata import software.amazon.smithy.rust.codegen.core.smithy.renamedFrom import software.amazon.smithy.rust.codegen.core.smithy.rustType @@ -134,7 +136,7 @@ open class UnionGenerator( """ impl #{Debug} for ${unionSymbol.name} { fn fmt(&self, f: &mut #{StdFmt}::Formatter<'_>) -> #{StdFmt}::Result { - write!(f, $REDACTION) + ::std::write!(f, $REDACTION) } } """, @@ -197,8 +199,11 @@ private fun RustWriter.renderAsVariant( "/// Tries to convert the enum instance into [`$variantName`], extracting the inner `()`.", ) rust("/// Returns `Err(&Self)` if it can't be converted.") - rustBlock("pub fn as_$funcNamePart(&self) -> std::result::Result<(), &Self>") { - rust("if let ${unionSymbol.name}::$variantName = &self { Ok(()) } else { Err(self) }") + rustBlockTemplate("pub fn as_$funcNamePart(&self) -> #{Result}<(), &Self>", *preludeScope) { + rustTemplate( + "if let ${unionSymbol.name}::$variantName = &self { #{Ok}(()) } else { #{Err}(self) }", + *preludeScope, + ) } } else { val memberSymbol = symbolProvider.toSymbol(member) @@ -209,8 +214,11 @@ private fun RustWriter.renderAsVariant( targetSymbol, ) rust("/// Returns `Err(&Self)` if it can't be converted.") - rustBlock("pub fn as_$funcNamePart(&self) -> std::result::Result<&${memberSymbol.rustType().render()}, &Self>") { - rust("if let ${unionSymbol.name}::$variantName(val) = &self { Ok(val) } else { Err(self) }") + rustBlockTemplate("pub fn as_$funcNamePart(&self) -> #{Result}<&${memberSymbol.rustType().render()}, &Self>", *preludeScope) { + rustTemplate( + "if let ${unionSymbol.name}::$variantName(val) = &self { #{Ok}(val) } else { #{Err}(self) }", + *preludeScope, + ) } } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/ErrorImplGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/ErrorImplGenerator.kt index 692bf32aab..049933bc45 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/ErrorImplGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/ErrorImplGenerator.kt @@ -156,13 +156,13 @@ class ErrorImplGenerator( val errorDesc = symbol.name.letIf(symbol.name != shape.id.name) { symbolName -> "$symbolName [${shape.id.name}]" } - write("write!(f, ${errorDesc.dq()})?;") + write("::std::write!(f, ${errorDesc.dq()})?;") messageShape?.let { if (it.shouldRedact(model)) { - write("""write!(f, ": {}", $REDACTION)?;""") + write("""::std::write!(f, ": {}", $REDACTION)?;""") } else { ifSet(it, symbolProvider.toSymbol(it), ValueExpression.Reference("&self.message")) { field -> - write("""write!(f, ": {}", ${field.asRef()})?;""") + write("""::std::write!(f, ": {}", ${field.asRef()})?;""") } } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/EventStreamUnmarshallerGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/EventStreamUnmarshallerGenerator.kt index 6e9826f054..6b706a1e09 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/EventStreamUnmarshallerGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/EventStreamUnmarshallerGenerator.kt @@ -276,7 +276,7 @@ class EventStreamUnmarshallerGenerator( is StringShape -> { rustTemplate( """ - std::str::from_utf8(message.payload()) + ::std::str::from_utf8(message.payload()) .map_err(|_| #{Error}::unmarshalling("message payload is not valid UTF-8"))? .to_owned() """,