From 32017446fd448b232e6d9b9d39f898acc4f3d3b8 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Fri, 25 Oct 2024 13:51:15 -0400 Subject: [PATCH] Fix serde on constrained blobs --- .changelog/1729878769.md | 9 +++ .../codegen/serde/SerializeImplGenerator.kt | 8 +-- .../rust/codegen/serde/SerdeDecoratorTest.kt | 57 ++++++++++++++++--- 3 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 .changelog/1729878769.md diff --git a/.changelog/1729878769.md b/.changelog/1729878769.md new file mode 100644 index 0000000000..6b4366dc8d --- /dev/null +++ b/.changelog/1729878769.md @@ -0,0 +1,9 @@ +--- +applies_to: ["server"] +authors: ["rcoh"] +references: ["smithy-rs#3890"] +breaking: false +new_feature: false +bug_fix: true +--- +Fix bug in `serde` decorator that generated non-compiling code on some models diff --git a/codegen-serde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/SerializeImplGenerator.kt b/codegen-serde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/SerializeImplGenerator.kt index 3db8d0086c..b35e59ac5b 100644 --- a/codegen-serde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/SerializeImplGenerator.kt +++ b/codegen-serde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/SerializeImplGenerator.kt @@ -462,8 +462,8 @@ class SerializeImplGenerator(private val codegenContext: CodegenContext) { } private fun serializeBlob(shape: BlobShape): RuntimeType = - RuntimeType.forInlineFun("SerializeBlob", Companion.PrimitiveShapesModule) { - implSerializeConfigured(codegenContext.symbolProvider.toSymbol(shape)) { + RuntimeType.forInlineFun("SerializeBlob", PrimitiveShapesModule) { + implSerializeConfigured(RuntimeType.blob(codegenContext.runtimeConfig).toSymbol()) { rustTemplate( """ if serializer.is_human_readable() { @@ -478,7 +478,7 @@ class SerializeImplGenerator(private val codegenContext: CodegenContext) { } private fun serializeByteStream(shape: BlobShape): RuntimeType = - RuntimeType.forInlineFun("SerializeByteStream", Companion.PrimitiveShapesModule) { + RuntimeType.forInlineFun("SerializeByteStream", PrimitiveShapesModule) { implSerializeConfigured(RuntimeType.byteStream(codegenContext.runtimeConfig).toSymbol()) { // This doesn't work yet—there is no way to get data out of a ByteStream from a sync context rustTemplate( @@ -498,7 +498,7 @@ class SerializeImplGenerator(private val codegenContext: CodegenContext) { } private fun serializeDocument(shape: DocumentShape): RuntimeType = - RuntimeType.forInlineFun("SerializeDocument", Companion.PrimitiveShapesModule) { + RuntimeType.forInlineFun("SerializeDocument", PrimitiveShapesModule) { implSerializeConfigured(codegenContext.symbolProvider.toSymbol(shape)) { rustTemplate( """ diff --git a/codegen-serde/src/test/kotlin/software/amazon/smithy/rust/codegen/serde/SerdeDecoratorTest.kt b/codegen-serde/src/test/kotlin/software/amazon/smithy/rust/codegen/serde/SerdeDecoratorTest.kt index 47907d4323..fd186dd97f 100644 --- a/codegen-serde/src/test/kotlin/software/amazon/smithy/rust/codegen/serde/SerdeDecoratorTest.kt +++ b/codegen-serde/src/test/kotlin/software/amazon/smithy/rust/codegen/serde/SerdeDecoratorTest.kt @@ -6,6 +6,7 @@ package software.amazon.smithy.rust.codegen.serde import org.junit.jupiter.api.Test +import software.amazon.smithy.model.node.Node import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.cfg @@ -190,22 +191,22 @@ class SerdeDecoratorTest { namespace com.example use smithy.rust#serde use aws.protocols#awsJson1_0 - + @awsJson1_0 @serde service MyResourceService { resources: [MyResource] } - + resource MyResource { read: ReadMyResource } - + @readonly operation ReadMyResource { input := { } } - """.asSmithyModel(smithyVersion = "2") + """.asSmithyModel(smithyVersion = "2") val params = IntegrationTestParams(cargoCommand = "cargo test --all-features", service = "com.example#MyResourceService") @@ -241,14 +242,14 @@ class SerdeDecoratorTest { """ namespace com.example use aws.protocols#awsJson1_0 - + @awsJson1_0 service MyService { operations: [MyOperation] } - + operation MyOperation { } - """.asSmithyModel(smithyVersion = "2") + """.asSmithyModel(smithyVersion = "2") val params = IntegrationTestParams(cargoCommand = "cargo test --all-features", service = "com.example#MyService") @@ -261,6 +262,48 @@ class SerdeDecoratorTest { } } + val onlyConstrained = + """ + namespace com.example + use smithy.rust#serde + use aws.protocols#awsJson1_0 + use smithy.framework#ValidationException + @awsJson1_0 + service HelloService { + operations: [SayHello], + version: "1" + } + @serde + operation SayHello { + input: TestInput + errors: [ValidationException] + } + structure TestInput { + @length(max: 10) + shortBlob: Blob + } + """.asSmithyModel(smithyVersion = "2") + + // There is a "race condition" where if the first blob shape serialized is constrained, it triggered unexpected + // behavior where the constrained shape was used instead. This test verifies the fix. + // Fixes https://github.com/smithy-lang/smithy-rs/issues/3890 + @Test + fun compilesOnlyConstrainedModel() { + val constrainedShapesSettings = + Node.objectNodeBuilder().withMember( + "codegen", + Node.objectNodeBuilder() + .withMember("publicConstrainedTypes", true) + .withMember("includeFluentClient", false) + .build(), + ).build() + serverIntegrationTest( + onlyConstrained, + params.copy(additionalSettings = constrainedShapesSettings), + ) { clientCodegenContext, rustCrate -> + } + } + @Test fun generateSerializersThatWorkServer() { serverIntegrationTest(simpleModel, params = params) { ctx, crate ->