From 8e10f8e6895eaa8347d03a239a5211967fb7b31f Mon Sep 17 00:00:00 2001 From: 82marbag <69267416+82marbag@users.noreply.github.com> Date: Fri, 18 Nov 2022 16:37:07 +0100 Subject: [PATCH 1/5] ModelTransformer for EnumShape Signed-off-by: Daniele Ahmed --- .../amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt | 2 ++ .../smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt index 6d335929a7..fdf1b2a9ef 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt @@ -106,6 +106,8 @@ class CodegenVisitor( */ internal fun baselineTransform(model: Model) = model + // Convert string shapes with an @enum trait to an enum shape + .let { ModelTransformer.create().changeStringEnumsToEnumShapes(model, true) } // Flattens mixins out of the model and removes them from the model .let { ModelTransformer.create().flattenAndRemoveMixins(it) } // Add errors attached at the service level to the models diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt index 8a3c5649bc..4a44d773e2 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt @@ -148,6 +148,8 @@ open class ServerCodegenVisitor( */ protected fun baselineTransform(model: Model) = model + // Convert string shapes with an @enum trait to an enum shape + .let { ModelTransformer.create().changeStringEnumsToEnumShapes(model, true) } // Flattens mixins out of the model and removes them from the model .let { ModelTransformer.create().flattenAndRemoveMixins(it) } // Add errors attached at the service level to the models From 5d096382f244031c0db8f85ddfe537c86219df4c Mon Sep 17 00:00:00 2001 From: 82marbag <69267416+82marbag@users.noreply.github.com> Date: Fri, 18 Nov 2022 17:03:54 +0100 Subject: [PATCH 2/5] Update EnumGenerator Signed-off-by: Daniele Ahmed --- .../codegen/client/smithy/CodegenVisitor.kt | 16 ++++-- .../core/smithy/generators/EnumGenerator.kt | 53 +++++++++++-------- .../smithy/PythonServerCodegenVisitor.kt | 15 ++++-- .../server/smithy/ServerCodegenVisitor.kt | 37 ++++--------- .../smithy/generators/ServerEnumGenerator.kt | 9 ++-- 5 files changed, 68 insertions(+), 62 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt index fdf1b2a9ef..43fce179ae 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt @@ -6,9 +6,11 @@ package software.amazon.smithy.rust.codegen.client.smithy import software.amazon.smithy.build.PluginContext +import software.amazon.smithy.codegen.core.CodegenException import software.amazon.smithy.model.Model import software.amazon.smithy.model.knowledge.NullableIndex import software.amazon.smithy.model.neighbor.Walker +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.model.shapes.ShapeVisitor @@ -39,7 +41,6 @@ import software.amazon.smithy.rust.codegen.core.smithy.transformers.EventStreamN import software.amazon.smithy.rust.codegen.core.smithy.transformers.OperationNormalizer import software.amazon.smithy.rust.codegen.core.smithy.transformers.RecursiveShapeBoxer import software.amazon.smithy.rust.codegen.core.util.CommandFailed -import software.amazon.smithy.rust.codegen.core.util.getTrait import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.letIf import software.amazon.smithy.rust.codegen.core.util.runCommand @@ -211,10 +212,15 @@ class CodegenVisitor( * Although raw strings require no code generation, enums are actually `EnumTrait` applied to string shapes. */ override fun stringShape(shape: StringShape) { - shape.getTrait()?.also { enum -> - rustCrate.useShapeWriter(shape) { - EnumGenerator(model, symbolProvider, this, shape, enum).render() - } + if (shape.hasTrait()) { + throw CodegenException("Unnamed @enum shapes are unsupported: $shape") + } + super.stringShape(shape) + } + + override fun enumShape(shape: EnumShape) { + rustCrate.useShapeWriter(shape) { + EnumGenerator(model, symbolProvider, this, shape).render() } } 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 0acfe2641d..7417b913db 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 @@ -7,10 +7,10 @@ package software.amazon.smithy.rust.codegen.core.smithy.generators import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.Model -import software.amazon.smithy.model.shapes.StringShape +import software.amazon.smithy.model.shapes.EnumShape +import software.amazon.smithy.model.traits.DeprecatedTrait import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.model.traits.EnumDefinition -import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter @@ -29,6 +29,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.expectRustMetadata import software.amazon.smithy.rust.codegen.core.util.doubleQuote import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.getTrait +import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.orNull /** Model that wraps [EnumDefinition] to calculate and cache values required to generate the Rust enum source. */ @@ -86,14 +87,26 @@ open class EnumGenerator( private val model: Model, private val symbolProvider: RustSymbolProvider, private val writer: RustWriter, - protected val shape: StringShape, - protected val enumTrait: EnumTrait, + protected val shape: EnumShape, ) { protected val symbol: Symbol = symbolProvider.toSymbol(shape) protected val enumName: String = symbol.name protected val meta = symbol.expectRustMetadata() protected val sortedMembers: List = - enumTrait.values.sortedBy { it.value }.map { EnumMemberModel(it, symbolProvider) } + shape.allMembers.entries.sortedBy { it.key }.map { + val builder = EnumDefinition.builder() + .name(it.key) + .value(shape.enumValues[it.key]) + .deprecated(it.value.getTrait() != null) + .tags(it.value.tags) + if (it.value.hasTrait()) { + builder.documentation(it.value.expectTrait(DocumentationTrait::class.java).value) + } + EnumMemberModel( + builder.build(), + symbolProvider, + ) + } protected open var target: CodegenTarget = CodegenTarget.CLIENT companion object { @@ -108,24 +121,20 @@ open class EnumGenerator( } open fun render() { - if (enumTrait.hasNames()) { - // pub enum Blah { V1, V2, .. } - renderEnum() - writer.insertTrailingNewline() - // impl From for Blah { ... } - renderFromForStr() - // impl FromStr for Blah { ... } - renderFromStr() - writer.insertTrailingNewline() - // impl Blah { pub fn as_str(&self) -> &str - implBlock() - writer.rustBlock("impl AsRef for $enumName") { - rustBlock("fn as_ref(&self) -> &str") { - rust("self.as_str()") - } + // pub enum Blah { V1, V2, .. } + renderEnum() + writer.insertTrailingNewline() + // impl From for Blah { ... } + renderFromForStr() + // impl FromStr for Blah { ... } + renderFromStr() + writer.insertTrailingNewline() + // impl Blah { pub fn as_str(&self) -> &str + implBlock() + writer.rustBlock("impl AsRef for $enumName") { + rustBlock("fn as_ref(&self) -> &str") { + rust("self.as_str()") } - } else { - renderUnnamedEnum() } } diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt index 0eac9dd196..4356c58c02 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt @@ -10,13 +10,13 @@ import software.amazon.smithy.build.PluginContext import software.amazon.smithy.codegen.core.CodegenException import software.amazon.smithy.model.Model import software.amazon.smithy.model.knowledge.NullableIndex +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.rust.codegen.client.smithy.customize.RustCodegenDecorator -import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitorConfig @@ -27,6 +27,7 @@ import software.amazon.smithy.rust.codegen.server.smithy.DefaultServerPublicModu import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenVisitor import software.amazon.smithy.rust.codegen.server.smithy.ServerSymbolProviders +import software.amazon.smithy.rust.codegen.server.smithy.generators.ConstrainedTraitForEnumGenerator import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocol import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocolGenerator import software.amazon.smithy.rust.codegen.server.smithy.protocols.ServerProtocolLoader @@ -130,9 +131,15 @@ class PythonServerCodegenVisitor( * Although raw strings require no code generation, enums are actually [EnumTrait] applied to string shapes. */ override fun stringShape(shape: StringShape) { - fun pythonServerEnumGeneratorFactory(codegenContext: ServerCodegenContext, writer: RustWriter, shape: StringShape) = - PythonServerEnumGenerator(codegenContext, writer, shape) - stringShape(shape, ::pythonServerEnumGeneratorFactory) + super.stringShape(shape) + } + + override fun enumShape(shape: EnumShape) { + logger.info("[rust-server-codegen] Generating an enum $shape") + rustCrate.useShapeWriter(shape) { + PythonServerEnumGenerator(codegenContext, this, shape).render() + ConstrainedTraitForEnumGenerator(model, codegenContext.symbolProvider, this, shape).render() + } } /** diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt index 4a44d773e2..6933d36112 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt @@ -11,6 +11,7 @@ import software.amazon.smithy.model.Model import software.amazon.smithy.model.knowledge.NullableIndex import software.amazon.smithy.model.neighbor.Walker import software.amazon.smithy.model.shapes.CollectionShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.ListShape import software.amazon.smithy.model.shapes.MapShape import software.amazon.smithy.model.shapes.ServiceShape @@ -21,7 +22,6 @@ import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape import software.amazon.smithy.model.traits.EnumTrait -import software.amazon.smithy.model.traits.LengthTrait import software.amazon.smithy.model.transform.ModelTransformer import software.amazon.smithy.rust.codegen.client.smithy.customize.RustCodegenDecorator import software.amazon.smithy.rust.codegen.core.rustlang.RustModule @@ -359,33 +359,10 @@ open class ServerCodegenVisitor( * Although raw strings require no code generation, enums are actually [EnumTrait] applied to string shapes. */ override fun stringShape(shape: StringShape) { - fun serverEnumGeneratorFactory(codegenContext: ServerCodegenContext, writer: RustWriter, shape: StringShape) = - ServerEnumGenerator(codegenContext, writer, shape) - stringShape(shape, ::serverEnumGeneratorFactory) - } - - protected fun stringShape( - shape: StringShape, - enumShapeGeneratorFactory: (codegenContext: ServerCodegenContext, writer: RustWriter, shape: StringShape) -> ServerEnumGenerator, - ) { if (shape.hasTrait()) { - logger.info("[rust-server-codegen] Generating an enum $shape") - rustCrate.useShapeWriter(shape) { - enumShapeGeneratorFactory(codegenContext, this, shape).render() - ConstrainedTraitForEnumGenerator(model, codegenContext.symbolProvider, this, shape).render() - } + throw CodegenException("Unnamed @enum shapes are unsupported: $shape") } - - if (shape.hasTrait() && shape.hasTrait()) { - logger.warning( - """ - String shape $shape has an `enum` trait and the `length` trait. This is valid according to the Smithy - IDL v1 spec, but it's unclear what the semantics are. In any case, the Smithy core libraries should enforce the - constraints (which it currently does not), not each code generator. - See https://github.com/awslabs/smithy/issues/1121f for more information. - """.trimIndent().replace("\n", " "), - ) - } else if (!shape.hasTrait() && shape.isDirectlyConstrained(codegenContext.symbolProvider)) { + if (shape.isDirectlyConstrained(codegenContext.symbolProvider)) { logger.info("[rust-server-codegen] Generating a constrained string $shape") rustCrate.withModule(ModelsModule) { ConstrainedStringGenerator(codegenContext, this, shape).render() @@ -393,6 +370,14 @@ open class ServerCodegenVisitor( } } + override fun enumShape(shape: EnumShape) { + logger.info("[rust-server-codegen] Generating an enum $shape") + rustCrate.useShapeWriter(shape) { + ServerEnumGenerator(codegenContext, this, shape).render() + ConstrainedTraitForEnumGenerator(model, codegenContext.symbolProvider, this, shape).render() + } + } + /** * Union Shape Visitor * diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt index 1514750cda..b994870cc6 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt @@ -4,7 +4,7 @@ */ package software.amazon.smithy.rust.codegen.server.smithy.generators -import software.amazon.smithy.model.shapes.StringShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.rust @@ -14,7 +14,6 @@ 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.generators.EnumGenerator import software.amazon.smithy.rust.codegen.core.util.dq -import software.amazon.smithy.rust.codegen.core.util.expectTrait import software.amazon.smithy.rust.codegen.server.smithy.PubCrateConstraintViolationSymbolProvider import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.traits.isReachableFromOperationInput @@ -22,8 +21,8 @@ import software.amazon.smithy.rust.codegen.server.smithy.traits.isReachableFromO open class ServerEnumGenerator( val codegenContext: ServerCodegenContext, private val writer: RustWriter, - shape: StringShape, -) : EnumGenerator(codegenContext.model, codegenContext.symbolProvider, writer, shape, shape.expectTrait()) { + shape: EnumShape, +) : EnumGenerator(codegenContext.model, codegenContext.symbolProvider, writer, shape) { override var target: CodegenTarget = CodegenTarget.SERVER private val publicConstrainedTypes = codegenContext.settings.codegenConfig.publicConstrainedTypes @@ -54,7 +53,7 @@ open class ServerEnumGenerator( ) if (shape.isReachableFromOperationInput()) { - val enumValueSet = enumTrait.enumDefinitionValues.joinToString(", ") + val enumValueSet = sortedMembers.joinToString(", ") { it.value } val message = "Value {} at '{}' failed to satisfy constraint: Member must satisfy enum value set: [$enumValueSet]" rustTemplate( From bd524e87a4f1b3b2ac9befc39b2c9458c53b00e9 Mon Sep 17 00:00:00 2001 From: 82marbag <69267416+82marbag@users.noreply.github.com> Date: Fri, 18 Nov 2022 17:11:15 +0100 Subject: [PATCH 3/5] Remove EnumTrait Signed-off-by: Daniele Ahmed --- .../codegen/client/smithy/CodegenVisitor.kt | 5 +- .../client/smithy/CodegenVisitorTest.kt | 39 +++++++ .../generators/ClientInstantiatorTest.kt | 32 +---- .../core/smithy/SymbolMetadataProvider.kt | 8 +- .../rust/codegen/core/smithy/SymbolVisitor.kt | 13 +-- .../core/smithy/generators/Instantiator.kt | 4 +- .../generators/http/HttpBindingGenerator.kt | 4 +- .../HttpBoundProtocolPayloadGenerator.kt | 16 ++- .../protocols/parse/JsonParserGenerator.kt | 4 +- .../parse/XmlBindingTraitParserGenerator.kt | 6 +- .../serialize/QuerySerializerGenerator.kt | 16 +-- .../rust/codegen/core/testutil/TestHelpers.kt | 2 + .../smithy/rust/codegen/core/util/Smithy.kt | 6 +- .../smithy/generators/EnumGeneratorTest.kt | 110 ++++++------------ .../parse/JsonParserGeneratorTest.kt | 7 +- .../XmlBindingTraitParserGeneratorTest.kt | 7 +- .../AwsQuerySerializerGeneratorTest.kt | 7 +- .../Ec2QuerySerializerGeneratorTest.kt | 7 +- .../serialize/JsonSerializerGeneratorTest.kt | 7 +- .../XmlBindingTraitSerializerGeneratorTest.kt | 7 +- .../smithy/PythonServerCodegenVisitor.kt | 10 +- .../rust/codegen/server/smithy/Constraints.kt | 10 +- .../server/smithy/ServerCodegenVisitor.kt | 7 +- .../smithy/ValidateUnsupportedConstraints.kt | 24 ++-- .../ConstrainedTraitForEnumGenerator.kt | 7 +- .../generators/UnconstrainedUnionGenerator.kt | 8 +- .../generators/ServerInstantiatorTest.kt | 32 +---- 27 files changed, 168 insertions(+), 237 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt index 43fce179ae..530eaab2f2 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt @@ -209,7 +209,7 @@ class CodegenVisitor( /** * String Shape Visitor * - * Although raw strings require no code generation, enums are actually `EnumTrait` applied to string shapes. + * Unnamed @enum shapes are not supported. If they could not be converted to EnumShape, this will fail. */ override fun stringShape(shape: StringShape) { if (shape.hasTrait()) { @@ -218,6 +218,9 @@ class CodegenVisitor( super.stringShape(shape) } + /** + * Enum Shape Visitor + */ override fun enumShape(shape: EnumShape) { rustCrate.useShapeWriter(shape) { EnumGenerator(model, symbolProvider, this, shape).render() diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitorTest.kt index eccb9058d5..4f95cf2e0a 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitorTest.kt @@ -8,6 +8,7 @@ package software.amazon.smithy.rust.codegen.client.smithy import io.kotest.matchers.shouldBe import org.junit.jupiter.api.Test import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.rust.codegen.client.smithy.customizations.ClientCustomizations import software.amazon.smithy.rust.codegen.client.smithy.customize.CombinedCodegenDecorator import software.amazon.smithy.rust.codegen.client.smithy.customize.NoOpEventStreamSigningDecorator @@ -62,4 +63,42 @@ class CodegenVisitorTest { val baselineModel = visitor.baselineTransform(model) baselineModel.getShapesWithTrait(ShapeId.from("smithy.api#mixin")).isEmpty() shouldBe true } + + @Test + fun `baseline transform verify string enum converted to EnumShape`() { + val model = """ + namespace com.example + use aws.protocols#restJson1 + @restJson1 + service Example { + operations: [ BasicOperation ] + } + operation BasicOperation { + input: Shape + } + structure Shape { + enum: BasicEnum + } + @enum([ + { + value: "a0", + }, + { + value: "a1", + } + ]) + string BasicEnum + """.asSmithyModel(smithyVersion = "2.0") + val (ctx, testDir) = generatePluginContext(model) + testDir.resolve("src").createDirectory() + testDir.resolve("src/main.rs").writeText("fn main() {}") + val codegenDecorator = + CombinedCodegenDecorator.fromClasspath( + ctx, + ClientCustomizations(), + ) + val visitor = CodegenVisitor(ctx, codegenDecorator) + val baselineModel = visitor.baselineTransform(model) + baselineModel.getShapesWithTrait(EnumTrait.ID).isEmpty() shouldBe true + } } diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientInstantiatorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientInstantiatorTest.kt index f507ba2d4c..525c5356c4 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientInstantiatorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientInstantiatorTest.kt @@ -7,7 +7,7 @@ package software.amazon.smithy.rust.codegen.client.smithy.generators import org.junit.jupiter.api.Test import software.amazon.smithy.model.node.Node -import software.amazon.smithy.model.shapes.StringShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.rust.codegen.client.testutil.testCodegenContext import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.rust @@ -18,19 +18,12 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest import software.amazon.smithy.rust.codegen.core.testutil.unitTest import software.amazon.smithy.rust.codegen.core.util.dq -import software.amazon.smithy.rust.codegen.core.util.expectTrait import software.amazon.smithy.rust.codegen.core.util.lookup internal class ClientInstantiatorTest { private val model = """ namespace com.test - @enum([ - { value: "t2.nano" }, - { value: "t2.micro" }, - ]) - string UnnamedEnum - @enum([ { value: "t2.nano", @@ -49,13 +42,13 @@ internal class ClientInstantiatorTest { @Test fun `generate named enums`() { - val shape = model.lookup("com.test#NamedEnum") + val shape = model.lookup("com.test#NamedEnum") val sut = clientInstantiator(codegenContext) val data = Node.parse("t2.nano".dq()) val project = TestWorkspace.testProject() project.withModule(RustModule.Model) { - EnumGenerator(model, symbolProvider, this, shape, shape.expectTrait()).render() + EnumGenerator(model, symbolProvider, this, shape).render() unitTest("generate_named_enums") { withBlock("let result = ", ";") { sut.render(this, shape, data) @@ -65,23 +58,4 @@ internal class ClientInstantiatorTest { } project.compileAndTest() } - - @Test - fun `generate unnamed enums`() { - val shape = model.lookup("com.test#UnnamedEnum") - val sut = clientInstantiator(codegenContext) - val data = Node.parse("t2.nano".dq()) - - val project = TestWorkspace.testProject() - project.withModule(RustModule.Model) { - EnumGenerator(model, symbolProvider, this, shape, shape.expectTrait()).render() - unitTest("generate_unnamed_enums") { - withBlock("let result = ", ";") { - sut.render(this, shape, data) - } - rust("""assert_eq!(result, UnnamedEnum("t2.nano".to_owned()));""") - } - } - project.compileAndTest() - } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolMetadataProvider.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolMetadataProvider.kt index e8fa8b06e0..1786b46d4f 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolMetadataProvider.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolMetadataProvider.kt @@ -8,18 +8,17 @@ package software.amazon.smithy.rust.codegen.core.smithy import software.amazon.smithy.codegen.core.CodegenException import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape import software.amazon.smithy.model.traits.EnumDefinition -import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.model.traits.StreamingTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.RustMetadata import software.amazon.smithy.rust.codegen.core.rustlang.Visibility -import software.amazon.smithy.rust.codegen.core.util.hasTrait /** * Default delegator to enable easily decorating another symbol provider. @@ -54,9 +53,8 @@ abstract class SymbolMetadataProvider(private val base: RustSymbolProvider) : Wr is MemberShape -> memberMeta(shape) is StructureShape -> structureMeta(shape) is UnionShape -> unionMeta(shape) - is StringShape -> if (shape.hasTrait()) { - enumMeta(shape) - } else null + is EnumShape -> enumMeta(shape) + is StringShape -> null else -> null } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitor.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitor.kt index 1ca4c2ebf2..d39e8ff893 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitor.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitor.kt @@ -17,6 +17,7 @@ import software.amazon.smithy.model.shapes.BooleanShape import software.amazon.smithy.model.shapes.ByteShape import software.amazon.smithy.model.shapes.DocumentShape import software.amazon.smithy.model.shapes.DoubleShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.FloatShape import software.amazon.smithy.model.shapes.IntegerShape import software.amazon.smithy.model.shapes.ListShape @@ -36,7 +37,6 @@ import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.TimestampShape import software.amazon.smithy.model.shapes.UnionShape import software.amazon.smithy.model.traits.EnumDefinition -import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.model.traits.ErrorTrait import software.amazon.smithy.rust.codegen.core.rustlang.RustType import software.amazon.smithy.rust.codegen.core.rustlang.stripOuter @@ -271,14 +271,11 @@ open class SymbolVisitor( override fun longShape(shape: LongShape): Symbol = simpleShape(shape) override fun floatShape(shape: FloatShape): Symbol = simpleShape(shape) override fun doubleShape(shape: DoubleShape): Symbol = simpleShape(shape) - override fun stringShape(shape: StringShape): Symbol { - return if (shape.hasTrait()) { - val rustType = RustType.Opaque(shape.contextName(serviceShape).toPascalCase()) - symbolBuilder(shape, rustType).locatedIn(Models).build() - } else { - simpleShape(shape) - } + override fun enumShape(shape: EnumShape): Symbol { + val rustType = RustType.Opaque(shape.contextName(serviceShape).toPascalCase()) + return symbolBuilder(shape, rustType).locatedIn(Models).build() } + override fun stringShape(shape: StringShape): Symbol = simpleShape(shape) override fun listShape(shape: ListShape): Symbol { val inner = this.toSymbol(shape.member) 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 ece470137d..1fa353054a 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 @@ -18,6 +18,7 @@ import software.amazon.smithy.model.shapes.BlobShape import software.amazon.smithy.model.shapes.BooleanShape import software.amazon.smithy.model.shapes.CollectionShape import software.amazon.smithy.model.shapes.DocumentShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.ListShape import software.amazon.smithy.model.shapes.MapShape import software.amazon.smithy.model.shapes.MemberShape @@ -28,7 +29,6 @@ import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.TimestampShape import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.model.traits.HttpPrefixHeadersTrait import software.amazon.smithy.model.traits.StreamingTrait import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency @@ -279,7 +279,7 @@ open class Instantiator( private fun renderString(writer: RustWriter, shape: StringShape, arg: StringNode) { val data = writer.escape(arg.value).dq() - if (!shape.hasTrait()) { + if (shape !is EnumShape) { writer.rust("$data.to_owned()") } else { val enumSymbol = symbolProvider.toSymbol(shape) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/http/HttpBindingGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/http/HttpBindingGenerator.kt index 219784eff3..f5e39fe662 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/http/HttpBindingGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/http/HttpBindingGenerator.kt @@ -13,6 +13,7 @@ import software.amazon.smithy.model.knowledge.HttpBindingIndex import software.amazon.smithy.model.shapes.BlobShape import software.amazon.smithy.model.shapes.CollectionShape import software.amazon.smithy.model.shapes.DocumentShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.ListShape import software.amazon.smithy.model.shapes.MapShape import software.amazon.smithy.model.shapes.MemberShape @@ -22,7 +23,6 @@ import software.amazon.smithy.model.shapes.SimpleShape import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.model.traits.MediaTypeTrait import software.amazon.smithy.model.traits.TimestampFormatTrait import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency @@ -303,7 +303,7 @@ class HttpBindingGenerator( rust("let body_str = std::str::from_utf8(body)?;") } } - if (targetShape.hasTrait()) { + if (targetShape is EnumShape) { if (codegenTarget == CodegenTarget.SERVER) { rust( "Ok(#T::try_from(body_str)?)", diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBoundProtocolPayloadGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBoundProtocolPayloadGenerator.kt index 4c6d614139..ba33e5bb60 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBoundProtocolPayloadGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBoundProtocolPayloadGenerator.kt @@ -8,12 +8,12 @@ package software.amazon.smithy.rust.codegen.core.smithy.protocols import software.amazon.smithy.codegen.core.CodegenException import software.amazon.smithy.model.shapes.BlobShape import software.amazon.smithy.model.shapes.DocumentShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter @@ -35,7 +35,6 @@ import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.Struc import software.amazon.smithy.rust.codegen.core.util.PANIC import software.amazon.smithy.rust.codegen.core.util.UNREACHABLE import software.amazon.smithy.rust.codegen.core.util.expectMember -import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.inputShape import software.amazon.smithy.rust.codegen.core.util.isEventStream import software.amazon.smithy.rust.codegen.core.util.isInputEventStream @@ -291,15 +290,14 @@ class HttpBoundProtocolPayloadGenerator( serializer: StructuredDataSerializerGenerator, ) { when (val targetShape = model.expectShape(member.target)) { + is EnumShape -> { + // Convert an enum to `&str` then to `&[u8]` then to `Vec`. + rust("$payloadName.as_str().as_bytes().to_vec()") + } is StringShape -> { // Write the raw string to the payload. - if (targetShape.hasTrait()) { - // Convert an enum to `&str` then to `&[u8]` then to `Vec`. - rust("$payloadName.as_str().as_bytes().to_vec()") - } else { - // Convert a `String` to `Vec`. - rust("$payloadName.into_bytes()") - } + // Convert a `String` to `Vec`. + rust("$payloadName.into_bytes()") } is BlobShape -> { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGenerator.kt index 1d7a099272..1676fca1b8 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGenerator.kt @@ -10,6 +10,7 @@ import software.amazon.smithy.model.shapes.BlobShape import software.amazon.smithy.model.shapes.BooleanShape import software.amazon.smithy.model.shapes.CollectionShape import software.amazon.smithy.model.shapes.DocumentShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.MapShape import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.NumberShape @@ -19,7 +20,6 @@ import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.TimestampShape import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.model.traits.SparseTrait import software.amazon.smithy.model.traits.TimestampFormatTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute @@ -303,7 +303,7 @@ class JsonParserGenerator( private fun RustWriter.deserializeStringInner(target: StringShape, escapedStrName: String) { withBlock("$escapedStrName.to_unescaped().map(|u|", ")") { - when (target.hasTrait()) { + when (target is EnumShape) { true -> { if (returnSymbolToParse(target).isUnconstrained) { rust("u.into_owned()") diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGenerator.kt index 5f685fbc29..41d53e0ad7 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGenerator.kt @@ -14,6 +14,7 @@ import software.amazon.smithy.model.knowledge.HttpBindingIndex import software.amazon.smithy.model.shapes.BlobShape import software.amazon.smithy.model.shapes.BooleanShape import software.amazon.smithy.model.shapes.CollectionShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.MapShape import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.NumberShape @@ -22,7 +23,6 @@ import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.TimestampShape import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.model.traits.TimestampFormatTrait import software.amazon.smithy.model.traits.XmlFlattenedTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute @@ -658,7 +658,7 @@ class XmlBindingTraitParserGenerator( private fun RustWriter.parseStringInner(shape: StringShape, provider: Writable) { withBlock("Result::<#T, #T>::Ok(", ")", symbolProvider.toSymbol(shape), xmlDecodeError) { - if (shape.hasTrait()) { + if (shape is EnumShape) { val enumSymbol = symbolProvider.toSymbol(shape) if (convertsToEnumInServer(shape)) { withBlock("#T::try_from(", ")", enumSymbol) { @@ -678,7 +678,7 @@ class XmlBindingTraitParserGenerator( } } - private fun convertsToEnumInServer(shape: StringShape) = target == CodegenTarget.SERVER && shape.hasTrait() + private fun convertsToEnumInServer(shape: StringShape) = target == CodegenTarget.SERVER && shape is EnumShape private fun MemberShape.xmlName(): XmlName { return XmlName(xmlIndex.memberName(this)) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/QuerySerializerGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/QuerySerializerGenerator.kt index 9e4eded243..1029d9941c 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/QuerySerializerGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/QuerySerializerGenerator.kt @@ -8,6 +8,7 @@ package software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize import software.amazon.smithy.model.shapes.BlobShape import software.amazon.smithy.model.shapes.BooleanShape import software.amazon.smithy.model.shapes.CollectionShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.MapShape import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.NumberShape @@ -17,7 +18,6 @@ import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.TimestampShape import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.model.traits.TimestampFormatTrait import software.amazon.smithy.model.traits.XmlNameTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute @@ -41,7 +41,6 @@ import software.amazon.smithy.rust.codegen.core.smithy.protocols.serializeFuncti import software.amazon.smithy.rust.codegen.core.smithy.rustType import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.getTrait -import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.inputShape import software.amazon.smithy.rust.codegen.core.util.orNull @@ -204,10 +203,8 @@ abstract class QuerySerializerGenerator(codegenContext: CodegenContext) : Struct val writer = context.writerExpression val value = context.valueExpression when (target) { - is StringShape -> when (target.hasTrait()) { - true -> rust("$writer.string(${value.name}.as_str());") - false -> rust("$writer.string(${value.name});") - } + is EnumShape -> rust("$writer.string(${value.name}.as_str());") + is StringShape -> rust("$writer.string(${value.name});") is BooleanShape -> rust("$writer.boolean(${value.asValue()});") is NumberShape -> { val numberType = when (symbolProvider.toSymbol(target).rustType()) { @@ -285,12 +282,11 @@ abstract class QuerySerializerGenerator(codegenContext: CodegenContext) : Struct val valueName = safeName("value") rust("let mut $mapName = ${context.writerExpression}.start_map($flat, $entryKeyName, $entryValueName);") rustBlock("for ($keyName, $valueName) in ${context.valueExpression.asRef()}") { - val keyTarget = model.expectShape(context.shape.key.target) - val keyExpression = when (keyTarget.hasTrait()) { - true -> "$keyName.as_str()" + val entryName = safeName("entry") + val keyExpression = when (model.expectShape(context.shape.key.target)) { + is EnumShape -> "$keyName.as_str()" else -> keyName } - val entryName = safeName("entry") Attribute.AllowUnusedMut.render(this) rust("let mut $entryName = $mapName.entry($keyExpression);") serializeMember(MemberContext(entryName, ValueExpression.Reference(valueName), context.shape.value)) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt index 2e5fb3a0d0..96c799179d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt @@ -10,6 +10,7 @@ import software.amazon.smithy.model.knowledge.NullableIndex import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.model.transform.ModelTransformer import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.CratesIo @@ -70,6 +71,7 @@ fun String.asSmithyModel(sourceLocation: String? = null, smithyVersion: String = val processed = letIf(!this.startsWith("\$version")) { "\$version: ${smithyVersion.dq()}\n$it" } return Model.assembler().discoverModels().addUnparsedModel(sourceLocation ?: "test.smithy", processed).assemble() .unwrap() + .let { ModelTransformer.create().changeStringEnumsToEnumShapes(it, true) } } // Intentionally only visible to codegen-core since the other modules have their own symbol providers diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Smithy.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Smithy.kt index 291dd30e31..13912cff7f 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Smithy.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Smithy.kt @@ -116,13 +116,13 @@ inline fun UnionShape.findMemberWithTrait(model: Model): Mem return this.members().find { it.getMemberTrait(model, T::class.java).isPresent } } -/** Kotlin sugar for hasTrait() check. e.g. shape.hasTrait() instead of shape.hasTrait(EnumTrait::class.java) */ +/** Kotlin sugar for hasTrait() check. e.g. shape.hasTrait() instead of shape.hasTrait(HttpTrait::class.java) */ inline fun Shape.hasTrait(): Boolean = hasTrait(T::class.java) -/** Kotlin sugar for expectTrait() check. e.g. shape.expectTrait() instead of shape.expectTrait(EnumTrait::class.java) */ +/** Kotlin sugar for expectTrait() check. e.g. shape.expectTrait() instead of shape.expectTrait(HttpTrait::class.java) */ inline fun Shape.expectTrait(): T = expectTrait(T::class.java) -/** Kotlin sugar for getTrait() check. e.g. shape.getTrait() instead of shape.getTrait(EnumTrait::class.java) */ +/** Kotlin sugar for getTrait() check. e.g. shape.getTrait() instead of shape.getTrait(HttpTrait::class.java) */ inline fun Shape.getTrait(): T? = getTrait(T::class.java).orNull() fun Shape.isPrimitive(): Boolean { diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt index 963a436d08..308d6ccb31 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt @@ -10,8 +10,10 @@ import io.kotest.matchers.string.shouldContain import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import software.amazon.smithy.model.Model -import software.amazon.smithy.model.shapes.StringShape -import software.amazon.smithy.model.traits.EnumTrait +import software.amazon.smithy.model.shapes.EnumShape +import software.amazon.smithy.model.traits.DeprecatedTrait +import software.amazon.smithy.model.traits.DocumentationTrait +import software.amazon.smithy.model.traits.EnumDefinition import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.rust @@ -21,8 +23,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest import software.amazon.smithy.rust.codegen.core.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.testutil.unitTest import software.amazon.smithy.rust.codegen.core.util.expectTrait +import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.lookup -import software.amazon.smithy.rust.codegen.core.util.orNull class EnumGeneratorTest { @Nested @@ -44,10 +46,23 @@ class EnumGeneratorTest { """.asSmithyModel() private val symbolProvider = testSymbolProvider(testModel) - private val enumTrait = testModel.lookup("test#EnumWithUnknown").expectTrait() + private val enum = testModel.lookup("test#EnumWithUnknown") - private fun model(name: String): EnumMemberModel = - EnumMemberModel(enumTrait.values.first { it.name.orNull() == name }, symbolProvider) + private fun model(name: String): EnumMemberModel { + val entry = enum.allMembers.entries.first { it.key == name } + val builder = EnumDefinition.builder() + .name(entry.key) + .value(entry.value.memberName) + .deprecated(entry.value.getTrait(DeprecatedTrait::class.java) != null) + .tags(entry.value.tags) + if (entry.value.hasTrait()) { + builder.documentation(entry.value.expectTrait().value) + } + return EnumMemberModel( + builder.build(), + symbolProvider, + ) + } @Test fun `it converts enum names to PascalCase and renames any named Unknown to UnknownValue`() { @@ -111,13 +126,12 @@ class EnumGeneratorTest { string InstanceType """.asSmithyModel() - val shape = model.lookup("test#InstanceType") - val trait = shape.expectTrait() val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) project.withModule(RustModule.Model) { rust("##![allow(deprecated)]") - val generator = EnumGenerator(model, provider, this, shape, trait) + val shape = model.lookup("test#InstanceType") + val generator = EnumGenerator(model, provider, this, shape) generator.render() unitTest( "it_generates_named_enums", @@ -156,12 +170,11 @@ class EnumGeneratorTest { string FooEnum """.asSmithyModel() - val shape = model.lookup("test#FooEnum") - val trait = shape.expectTrait() val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) project.withModule(RustModule.Model) { - val generator = EnumGenerator(model, provider, this, shape, trait) + val shape = model.lookup("test#FooEnum") + val generator = EnumGenerator(model, provider, this, shape) generator.render() unitTest( "named_enums_implement_eq_and_hash", @@ -191,13 +204,12 @@ class EnumGeneratorTest { string FooEnum """.asSmithyModel() - val shape = model.lookup("test#FooEnum") - val trait = shape.expectTrait() val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) project.withModule(RustModule.Model) { rust("##![allow(deprecated)]") - val generator = EnumGenerator(model, provider, this, shape, trait) + val shape = model.lookup("test#FooEnum") + val generator = EnumGenerator(model, provider, this, shape) generator.render() unitTest( "unnamed_enums_implement_eq_and_hash", @@ -212,49 +224,6 @@ class EnumGeneratorTest { project.compileAndTest() } - @Test - fun `it generates unnamed enums`() { - val model = """ - namespace test - @enum([ - { - value: "Foo", - }, - { - value: "Baz", - }, - { - value: "Bar", - }, - { - value: "1", - }, - { - value: "0", - }, - ]) - string FooEnum - """.asSmithyModel() - - val shape = model.lookup("test#FooEnum") - val trait = shape.expectTrait() - val provider = testSymbolProvider(model) - val project = TestWorkspace.testProject(provider) - project.withModule(RustModule.Model) { - rust("##![allow(deprecated)]") - val generator = EnumGenerator(model, provider, this, shape, trait) - generator.render() - unitTest( - "it_generates_unnamed_enums", - """ - // Values should be sorted - assert_eq!(FooEnum::${EnumGenerator.Values}(), ["0", "1", "Bar", "Baz", "Foo"]); - """.trimIndent(), - ) - } - project.compileAndTest() - } - @Test fun `it escapes the Unknown variant if the enum has an unknown value in the model`() { val model = """ @@ -267,12 +236,11 @@ class EnumGeneratorTest { string SomeEnum """.asSmithyModel() - val shape = model.lookup("test#SomeEnum") - val trait = shape.expectTrait() val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) project.withModule(RustModule.Model) { - val generator = EnumGenerator(model, provider, this, shape, trait) + val shape = model.lookup("test#SomeEnum") + val generator = EnumGenerator(model, provider, this, shape) generator.render() unitTest( "it_escapes_the_unknown_variant_if_the_enum_has_an_unknown_value_in_the_model", @@ -299,12 +267,11 @@ class EnumGeneratorTest { string SomeEnum """.asSmithyModel() - val shape = model.lookup("test#SomeEnum") - val trait = shape.expectTrait() val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) project.withModule(RustModule.Model) { - val generator = EnumGenerator(model, provider, this, shape, trait) + val shape = model.lookup("test#SomeEnum") + val generator = EnumGenerator(model, provider, this, shape) generator.render() val rendered = toString() rendered shouldContain @@ -330,12 +297,11 @@ class EnumGeneratorTest { string SomeEnum """.asSmithyModel() - val shape = model.lookup("test#SomeEnum") - val trait = shape.expectTrait() val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) project.withModule(RustModule.Model) { - val generator = EnumGenerator(model, provider, this, shape, trait) + val shape = model.lookup("test#SomeEnum") + val generator = EnumGenerator(model, provider, this, shape) generator.render() val rendered = toString() rendered shouldContain @@ -358,12 +324,11 @@ class EnumGeneratorTest { string SomeEnum """.asSmithyModel() - val shape = model.lookup("test#SomeEnum") - val trait = shape.expectTrait() val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) project.withModule(RustModule.Model) { - val generator = EnumGenerator(model, provider, this, shape, trait) + val shape = model.lookup("test#SomeEnum") + val generator = EnumGenerator(model, provider, this, shape) generator.render() unitTest( "it_handles_variants_that_clash_with_rust_reserved_words", @@ -379,12 +344,11 @@ class EnumGeneratorTest { @Test fun `matching on enum should be forward-compatible`() { fun expectMatchExpressionCompiles(model: Model, shapeId: String, enumToMatchOn: String) { - val shape = model.lookup(shapeId) - val trait = shape.expectTrait() val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) project.withModule(RustModule.Model) { - val generator = EnumGenerator(model, provider, this, shape, trait) + val shape = model.lookup(shapeId) + val generator = EnumGenerator(model, provider, this, shape) generator.render() unitTest( "matching_on_enum_should_be_forward_compatible", diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGeneratorTest.kt index 5cd898a29f..e56fc7e985 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGeneratorTest.kt @@ -7,8 +7,8 @@ package software.amazon.smithy.rust.codegen.core.smithy.protocols.parse import org.junit.jupiter.api.Test import software.amazon.smithy.codegen.core.Symbol +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.smithy.generators.EnumGenerator @@ -26,7 +26,6 @@ import software.amazon.smithy.rust.codegen.core.testutil.renderWithModelBuilder import software.amazon.smithy.rust.codegen.core.testutil.testCodegenContext import software.amazon.smithy.rust.codegen.core.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.testutil.unitTest -import software.amazon.smithy.rust.codegen.core.util.expectTrait import software.amazon.smithy.rust.codegen.core.util.lookup import software.amazon.smithy.rust.codegen.core.util.outputShape @@ -197,8 +196,8 @@ class JsonParserGeneratorTest { model.lookup("test#Top").renderWithModelBuilder(model, symbolProvider, this) model.lookup("test#EmptyStruct").renderWithModelBuilder(model, symbolProvider, this) UnionGenerator(model, symbolProvider, this, model.lookup("test#Choice")).render() - val enum = model.lookup("test#FooEnum") - EnumGenerator(model, symbolProvider, this, enum, enum.expectTrait()).render() + val enum = model.lookup("test#FooEnum") + EnumGenerator(model, symbolProvider, this, enum).render() } project.withModule(RustModule.public("output")) { diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGeneratorTest.kt index 52bb4e1e7e..538a1d66a3 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGeneratorTest.kt @@ -6,8 +6,8 @@ package software.amazon.smithy.rust.codegen.core.smithy.protocols.parse import org.junit.jupiter.api.Test +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType @@ -24,7 +24,6 @@ import software.amazon.smithy.rust.codegen.core.testutil.renderWithModelBuilder import software.amazon.smithy.rust.codegen.core.testutil.testCodegenContext import software.amazon.smithy.rust.codegen.core.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.testutil.unitTest -import software.amazon.smithy.rust.codegen.core.util.expectTrait import software.amazon.smithy.rust.codegen.core.util.lookup import software.amazon.smithy.rust.codegen.core.util.outputShape @@ -197,8 +196,8 @@ internal class XmlBindingTraitParserGeneratorTest { project.withModule(RustModule.public("model")) { model.lookup("test#Top").renderWithModelBuilder(model, symbolProvider, this) UnionGenerator(model, symbolProvider, this, model.lookup("test#Choice")).render() - val enum = model.lookup("test#FooEnum") - EnumGenerator(model, symbolProvider, this, enum, enum.expectTrait()).render() + val enum = model.lookup("test#FooEnum") + EnumGenerator(model, symbolProvider, this, enum).render() } project.withModule(RustModule.public("output")) { diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/AwsQuerySerializerGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/AwsQuerySerializerGeneratorTest.kt index 890acec9e7..4089364222 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/AwsQuerySerializerGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/AwsQuerySerializerGeneratorTest.kt @@ -7,8 +7,8 @@ package software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.CsvSource +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget @@ -22,7 +22,6 @@ import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest import software.amazon.smithy.rust.codegen.core.testutil.renderWithModelBuilder import software.amazon.smithy.rust.codegen.core.testutil.testCodegenContext import software.amazon.smithy.rust.codegen.core.testutil.unitTest -import software.amazon.smithy.rust.codegen.core.util.expectTrait import software.amazon.smithy.rust.codegen.core.util.inputShape import software.amazon.smithy.rust.codegen.core.util.lookup @@ -135,8 +134,8 @@ class AwsQuerySerializerGeneratorTest { project.withModule(RustModule.public("model")) { model.lookup("test#Top").renderWithModelBuilder(model, symbolProvider, this) UnionGenerator(model, symbolProvider, this, model.lookup("test#Choice"), renderUnknownVariant = generateUnknownVariant).render() - val enum = model.lookup("test#FooEnum") - EnumGenerator(model, symbolProvider, this, enum, enum.expectTrait()).render() + val enum = model.lookup("test#FooEnum") + EnumGenerator(model, symbolProvider, this, enum).render() } project.withModule(RustModule.public("input")) { diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/Ec2QuerySerializerGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/Ec2QuerySerializerGeneratorTest.kt index 1c8889c74f..ef7c5be521 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/Ec2QuerySerializerGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/Ec2QuerySerializerGeneratorTest.kt @@ -6,8 +6,8 @@ package software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize import org.junit.jupiter.api.Test +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.smithy.generators.EnumGenerator @@ -21,7 +21,6 @@ import software.amazon.smithy.rust.codegen.core.testutil.renderWithModelBuilder import software.amazon.smithy.rust.codegen.core.testutil.testCodegenContext import software.amazon.smithy.rust.codegen.core.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.testutil.unitTest -import software.amazon.smithy.rust.codegen.core.util.expectTrait import software.amazon.smithy.rust.codegen.core.util.inputShape import software.amazon.smithy.rust.codegen.core.util.lookup @@ -128,8 +127,8 @@ class Ec2QuerySerializerGeneratorTest { project.withModule(RustModule.public("model")) { model.lookup("test#Top").renderWithModelBuilder(model, symbolProvider, this) UnionGenerator(model, symbolProvider, this, model.lookup("test#Choice")).render() - val enum = model.lookup("test#FooEnum") - EnumGenerator(model, symbolProvider, this, enum, enum.expectTrait()).render() + val enum = model.lookup("test#FooEnum") + EnumGenerator(model, symbolProvider, this, enum).render() } project.withModule(RustModule.public("input")) { diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/JsonSerializerGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/JsonSerializerGeneratorTest.kt index fa0f4f9e67..d6cb7f9e71 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/JsonSerializerGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/JsonSerializerGeneratorTest.kt @@ -6,8 +6,8 @@ package software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize import org.junit.jupiter.api.Test +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.smithy.generators.EnumGenerator @@ -24,7 +24,6 @@ import software.amazon.smithy.rust.codegen.core.testutil.renderWithModelBuilder import software.amazon.smithy.rust.codegen.core.testutil.testCodegenContext import software.amazon.smithy.rust.codegen.core.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.testutil.unitTest -import software.amazon.smithy.rust.codegen.core.util.expectTrait import software.amazon.smithy.rust.codegen.core.util.inputShape import software.amazon.smithy.rust.codegen.core.util.lookup @@ -144,8 +143,8 @@ class JsonSerializerGeneratorTest { project.withModule(RustModule.public("model")) { model.lookup("test#Top").renderWithModelBuilder(model, symbolProvider, this) UnionGenerator(model, symbolProvider, this, model.lookup("test#Choice")).render() - val enum = model.lookup("test#FooEnum") - EnumGenerator(model, symbolProvider, this, enum, enum.expectTrait()).render() + val enum = model.lookup("test#FooEnum") + EnumGenerator(model, symbolProvider, this, enum).render() } project.withModule(RustModule.public("input")) { diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/XmlBindingTraitSerializerGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/XmlBindingTraitSerializerGeneratorTest.kt index 73c43b2e30..2e528ff75b 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/XmlBindingTraitSerializerGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/XmlBindingTraitSerializerGeneratorTest.kt @@ -6,8 +6,8 @@ package software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize import org.junit.jupiter.api.Test +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.smithy.generators.EnumGenerator @@ -23,7 +23,6 @@ import software.amazon.smithy.rust.codegen.core.testutil.renderWithModelBuilder import software.amazon.smithy.rust.codegen.core.testutil.testCodegenContext import software.amazon.smithy.rust.codegen.core.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.testutil.unitTest -import software.amazon.smithy.rust.codegen.core.util.expectTrait import software.amazon.smithy.rust.codegen.core.util.inputShape import software.amazon.smithy.rust.codegen.core.util.lookup @@ -147,8 +146,8 @@ internal class XmlBindingTraitSerializerGeneratorTest { project.withModule(RustModule.public("model")) { model.lookup("test#Top").renderWithModelBuilder(model, symbolProvider, this) UnionGenerator(model, symbolProvider, this, model.lookup("test#Choice")).render() - val enum = model.lookup("test#FooEnum") - EnumGenerator(model, symbolProvider, this, enum, enum.expectTrait()).render() + val enum = model.lookup("test#FooEnum") + EnumGenerator(model, symbolProvider, this, enum).render() } project.withModule(RustModule.public("input")) { diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt index 4356c58c02..a69446d2ad 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt @@ -12,10 +12,8 @@ import software.amazon.smithy.model.Model import software.amazon.smithy.model.knowledge.NullableIndex import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.ServiceShape -import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.rust.codegen.client.smithy.customize.RustCodegenDecorator import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget import software.amazon.smithy.rust.codegen.core.smithy.RustCrate @@ -126,14 +124,8 @@ class PythonServerCodegenVisitor( } /** - * String Shape Visitor - * - * Although raw strings require no code generation, enums are actually [EnumTrait] applied to string shapes. + * Enum Shape Visitor */ - override fun stringShape(shape: StringShape) { - super.stringShape(shape) - } - override fun enumShape(shape: EnumShape) { logger.info("[rust-server-codegen] Generating an enum $shape") rustCrate.useShapeWriter(shape) { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt index 82102be18a..5a97ae8073 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt @@ -9,6 +9,7 @@ import software.amazon.smithy.codegen.core.SymbolProvider import software.amazon.smithy.model.Model import software.amazon.smithy.model.neighbor.Walker import software.amazon.smithy.model.shapes.CollectionShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.MapShape import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.Shape @@ -16,7 +17,6 @@ import software.amazon.smithy.model.shapes.SimpleShape import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.model.traits.LengthTrait import software.amazon.smithy.model.traits.PatternTrait import software.amazon.smithy.model.traits.RangeTrait @@ -36,11 +36,11 @@ import software.amazon.smithy.rust.codegen.core.util.hasTrait */ fun Shape.hasConstraintTrait() = hasTrait() || - hasTrait() || hasTrait() || hasTrait() || hasTrait() || - hasTrait() + hasTrait() || + this is EnumShape /** * We say a shape is _directly_ constrained if: @@ -66,7 +66,7 @@ fun Shape.isDirectlyConstrained(symbolProvider: SymbolProvider): Boolean = when this.members().map { symbolProvider.toSymbol(it) }.any { !it.isOptional() } } is MapShape -> this.hasTrait() - is StringShape -> this.hasTrait() || this.hasTrait() + is StringShape -> this is EnumShape || this.hasTrait() else -> false } @@ -91,7 +91,7 @@ fun MemberShape.targetCanReachConstrainedShape(model: Model, symbolProvider: Sym fun Shape.hasPublicConstrainedWrapperTupleType(model: Model, publicConstrainedTypes: Boolean): Boolean = when (this) { is MapShape -> publicConstrainedTypes && this.hasTrait() - is StringShape -> !this.hasTrait() && (publicConstrainedTypes && this.hasTrait()) + is StringShape -> this !is EnumShape && (publicConstrainedTypes && this.hasTrait()) is MemberShape -> model.expectShape(this.target).hasPublicConstrainedWrapperTupleType(model, publicConstrainedTypes) else -> false } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt index 6933d36112..c3e603163e 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt @@ -354,9 +354,9 @@ open class ServerCodegenVisitor( } /** - * Enum Shape Visitor + * String Shape Visitor * - * Although raw strings require no code generation, enums are actually [EnumTrait] applied to string shapes. + * Unnamed @enum shapes are not supported. If they could not be converted to EnumShape, this will fail. */ override fun stringShape(shape: StringShape) { if (shape.hasTrait()) { @@ -370,6 +370,9 @@ open class ServerCodegenVisitor( } } + /** + * Enum Shape Visitor + */ override fun enumShape(shape: EnumShape) { logger.info("[rust-server-codegen] Generating an enum $shape") rustCrate.useShapeWriter(shape) { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ValidateUnsupportedConstraints.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ValidateUnsupportedConstraints.kt index d487689b20..ace34cce65 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ValidateUnsupportedConstraints.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ValidateUnsupportedConstraints.kt @@ -18,7 +18,6 @@ import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.model.traits.LengthTrait import software.amazon.smithy.model.traits.PatternTrait import software.amazon.smithy.model.traits.RangeTrait @@ -113,7 +112,6 @@ private val allConstraintTraits = setOf( PatternTrait::class.java, RangeTrait::class.java, UniqueItemsTrait::class.java, - EnumTrait::class.java, RequiredTrait::class.java, ) private val unsupportedConstraintsOnMemberShapes = allConstraintTraits - RequiredTrait::class.java @@ -141,20 +139,20 @@ fun validateOperationsWithConstrainedInputHaveValidationExceptionAttached(model: LogMessage( Level.SEVERE, """ - Operation ${it.shape.id} takes in input that is constrained - (https://awslabs.github.io/smithy/2.0/spec/constraint-traits.html), and as such can fail with a validation + Operation ${it.shape.id} takes in input that is constrained + (https://awslabs.github.io/smithy/2.0/spec/constraint-traits.html), and as such can fail with a validation exception. You must model this behavior in the operation shape in your model file. """.trimIndent().replace("\n", "") + """ - - ```smithy - use smithy.framework#ValidationException - - operation ${it.shape.id.name} { - ... - errors: [..., ValidationException] // <-- Add this. - } - ``` + + ```smithy + use smithy.framework#ValidationException + + operation ${it.shape.id.name} { + ... + errors: [..., ValidationException] // <-- Add this. + } + ``` """.trimIndent(), ) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedTraitForEnumGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedTraitForEnumGenerator.kt index 288065d75c..b16d3a651a 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedTraitForEnumGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedTraitForEnumGenerator.kt @@ -6,14 +6,13 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.StringShape -import software.amazon.smithy.model.traits.EnumTrait 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.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.makeMaybeConstrained -import software.amazon.smithy.rust.codegen.core.util.expectTrait /** * [ConstrainedTraitForEnumGenerator] generates code that implements the [RuntimeType.ConstrainedTrait] trait on an @@ -26,7 +25,7 @@ class ConstrainedTraitForEnumGenerator( val shape: StringShape, ) { fun render() { - shape.expectTrait() + check(shape is EnumShape) val symbol = symbolProvider.toSymbol(shape) val name = symbol.name @@ -37,7 +36,7 @@ class ConstrainedTraitForEnumGenerator( impl #{ConstrainedTrait} for $name { type Unconstrained = $unconstrainedType; } - + impl From<$unconstrainedType> for #{MaybeConstrained} { fn from(value: $unconstrainedType) -> Self { Self::Unconstrained(value) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedUnionGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedUnionGenerator.kt index dd470daf9e..975c54b50b 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedUnionGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedUnionGenerator.kt @@ -5,10 +5,10 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape -import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.RustMetadata import software.amazon.smithy.rust.codegen.core.rustlang.RustModule @@ -97,7 +97,7 @@ class UnconstrainedUnionGenerator( """ impl #{TryFrom}<$name> for #{ConstrainedSymbol} { type Error = #{ConstraintViolationSymbol}; - + fn try_from(value: $name) -> Result { #{body:W} } @@ -115,7 +115,7 @@ class UnconstrainedUnionGenerator( impl #{ConstrainedTrait} for #{ConstrainedSymbol} { type Unconstrained = #{UnconstrainedSymbol}; } - + impl From<#{UnconstrainedSymbol}> for #{MaybeConstrained} { fn from(value: #{UnconstrainedSymbol}) -> Self { Self::Unconstrained(value) @@ -201,7 +201,7 @@ class UnconstrainedUnionGenerator( } else { val targetShape = model.expectShape(member.target) val resolveToNonPublicConstrainedType = - targetShape !is StructureShape && targetShape !is UnionShape && !targetShape.hasTrait() && + targetShape !is StructureShape && targetShape !is UnionShape && targetShape !is EnumShape && (!publicConstrainedTypes || !targetShape.isDirectlyConstrained(symbolProvider)) val (unconstrainedVar, boxIt) = if (member.hasTrait()) { diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiatorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiatorTest.kt index 1bfbd26e2f..5c68b1d376 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiatorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiatorTest.kt @@ -7,7 +7,7 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import org.junit.jupiter.api.Test import software.amazon.smithy.model.node.Node -import software.amazon.smithy.model.shapes.StringShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape import software.amazon.smithy.rust.codegen.core.rustlang.RustModule @@ -21,7 +21,6 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest import software.amazon.smithy.rust.codegen.core.testutil.unitTest import software.amazon.smithy.rust.codegen.core.util.dq -import software.amazon.smithy.rust.codegen.core.util.expectTrait import software.amazon.smithy.rust.codegen.core.util.lookup import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverRenderWithModelBuilder import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestCodegenContext @@ -106,12 +105,6 @@ class ServerInstantiatorTest { doc: Document } - @enum([ - { value: "t2.nano" }, - { value: "t2.micro" }, - ]) - string UnnamedEnum - @enum([ { value: "t2.nano", @@ -182,13 +175,13 @@ class ServerInstantiatorTest { @Test fun `generate named enums`() { - val shape = model.lookup("com.test#NamedEnum") + val shape = model.lookup("com.test#NamedEnum") val sut = serverInstantiator(codegenContext) val data = Node.parse("t2.nano".dq()) val project = TestWorkspace.testProject() project.withModule(RustModule.Model) { - EnumGenerator(model, symbolProvider, this, shape, shape.expectTrait()).render() + EnumGenerator(model, symbolProvider, this, shape).render() unitTest("generate_named_enums") { withBlock("let result = ", ";") { sut.render(this, shape, data) @@ -198,23 +191,4 @@ class ServerInstantiatorTest { } project.compileAndTest() } - - @Test - fun `generate unnamed enums`() { - val shape = model.lookup("com.test#UnnamedEnum") - val sut = serverInstantiator(codegenContext) - val data = Node.parse("t2.nano".dq()) - - val project = TestWorkspace.testProject() - project.withModule(RustModule.Model) { - EnumGenerator(model, symbolProvider, this, shape, shape.expectTrait()).render() - unitTest("generate_unnamed_enums") { - withBlock("let result = ", ";") { - sut.render(this, shape, data) - } - rust("""assert_eq!(result, UnnamedEnum("t2.nano".to_owned()));""") - } - } - project.compileAndTest() - } } From 3df6ad2c16107a6f9bfcff41ff21a7ca9f08101c Mon Sep 17 00:00:00 2001 From: 82marbag <69267416+82marbag@users.noreply.github.com> Date: Fri, 18 Nov 2022 21:10:04 +0100 Subject: [PATCH 4/5] Fix tests Signed-off-by: Daniele Ahmed --- .../python/smithy/generators/PythonServerEnumGenerator.kt | 4 ++-- .../server/smithy/generators/ServerEnumGeneratorTest.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEnumGenerator.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEnumGenerator.kt index c4542c1025..979e9da7e8 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEnumGenerator.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEnumGenerator.kt @@ -5,7 +5,7 @@ package software.amazon.smithy.rust.codegen.server.python.smithy.generators -import software.amazon.smithy.model.shapes.StringShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Writable @@ -26,7 +26,7 @@ import software.amazon.smithy.rust.codegen.server.smithy.generators.ServerEnumGe class PythonServerEnumGenerator( codegenContext: ServerCodegenContext, private val writer: RustWriter, - shape: StringShape, + shape: EnumShape, ) : ServerEnumGenerator(codegenContext, writer, shape) { private val pyo3Symbols = listOf(PythonServerCargoDependency.PyO3.toType()) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGeneratorTest.kt index 0e813cebbd..710534c0d5 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGeneratorTest.kt @@ -7,7 +7,7 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import io.kotest.matchers.string.shouldNotContain import org.junit.jupiter.api.Test -import software.amazon.smithy.model.shapes.StringShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest @@ -36,7 +36,7 @@ class ServerEnumGeneratorTest { private val codegenContext = serverTestCodegenContext(model) private val writer = RustWriter.forModule("model") - private val shape = model.lookup("test#InstanceType") + private val shape = model.lookup("test#InstanceType") @Test fun `it generates TryFrom, FromStr and errors for enums`() { From 077d44dbf252e5fc6ced3d4cf9ad2eaac309836d Mon Sep 17 00:00:00 2001 From: 82marbag <69267416+82marbag@users.noreply.github.com> Date: Thu, 1 Dec 2022 15:48:56 +0100 Subject: [PATCH 5/5] Address comments Signed-off-by: Daniele Ahmed --- .../codegen/client/smithy/CodegenVisitor.kt | 5 ++- .../client/smithy/CodegenVisitorTest.kt | 37 +++++++++++++++++-- .../core/smithy/generators/EnumGenerator.kt | 30 +-------------- .../core/smithy/generators/Instantiator.kt | 14 ++++--- .../rust/codegen/core/testutil/TestHelpers.kt | 2 - .../smithy/generators/EnumGeneratorTest.kt | 15 +++++++- .../rust/codegen/server/smithy/Constraints.kt | 3 +- .../server/smithy/ServerCodegenVisitor.kt | 5 ++- ...rGeneratorWithoutPublicConstrainedTypes.kt | 6 +-- 9 files changed, 69 insertions(+), 48 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt index 530eaab2f2..daacdf1119 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitor.kt @@ -213,7 +213,10 @@ class CodegenVisitor( */ override fun stringShape(shape: StringShape) { if (shape.hasTrait()) { - throw CodegenException("Unnamed @enum shapes are unsupported: $shape") + throw CodegenException( + "Code generation has failed because this unnamed @enum could not be converted to an enum shape: $shape." + + "For more info, look above at the logs from awslabs/smithy.", + ) } super.stringShape(shape) } diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitorTest.kt index 4f95cf2e0a..234f0782f6 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/CodegenVisitorTest.kt @@ -89,9 +89,7 @@ class CodegenVisitorTest { ]) string BasicEnum """.asSmithyModel(smithyVersion = "2.0") - val (ctx, testDir) = generatePluginContext(model) - testDir.resolve("src").createDirectory() - testDir.resolve("src/main.rs").writeText("fn main() {}") + val (ctx, _) = generatePluginContext(model) val codegenDecorator = CombinedCodegenDecorator.fromClasspath( ctx, @@ -101,4 +99,37 @@ class CodegenVisitorTest { val baselineModel = visitor.baselineTransform(model) baselineModel.getShapesWithTrait(EnumTrait.ID).isEmpty() shouldBe true } + + @Test + fun `baseline transform verify bad string enum throws if not converted to EnumShape`() { + val model = """ + namespace com.example + use aws.protocols#restJson1 + @restJson1 + service Example { + operations: [ BasicOperation ] + } + operation BasicOperation { + input: Shape + } + structure Shape { + enum: BasicEnum + } + @enum([ + { + value: "$ a/0", + }, + ]) + string BasicEnum + """.asSmithyModel(smithyVersion = "2.0") + val (ctx, _) = generatePluginContext(model) + val codegenDecorator = + CombinedCodegenDecorator.fromClasspath( + ctx, + ClientCustomizations(), + ) + val visitor = CodegenVisitor(ctx, codegenDecorator) + val baselineModel = visitor.baselineTransform(model) + baselineModel.getShapesWithTrait(EnumTrait.ID).isEmpty() shouldBe false + } } 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 7417b913db..5780776a91 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 @@ -16,7 +16,6 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter 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.escape import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock @@ -97,7 +96,7 @@ open class EnumGenerator( val builder = EnumDefinition.builder() .name(it.key) .value(shape.enumValues[it.key]) - .deprecated(it.value.getTrait() != null) + .deprecated(it.value.hasTrait()) .tags(it.value.tags) if (it.value.hasTrait()) { builder.documentation(it.value.expectTrait(DocumentationTrait::class.java).value) @@ -138,33 +137,6 @@ open class EnumGenerator( } } - private fun renderUnnamedEnum() { - writer.documentShape(shape, model) - writer.deprecatedShape(shape) - meta.render(writer) - writer.write("struct $enumName(String);") - writer.rustBlock("impl $enumName") { - docs("Returns the `&str` value of the enum member.") - rustBlock("pub fn as_str(&self) -> &str") { - rust("&self.0") - } - - docs("Returns all the `&str` representations of the enum members.") - rustBlock("pub fn $Values() -> &'static [&'static str]") { - withBlock("&[", "]") { - val memberList = sortedMembers.joinToString(", ") { it.value.dq() } - rust(memberList) - } - } - } - - writer.rustBlock("impl #T for $enumName where T: #T", RuntimeType.From, RuntimeType.AsRef) { - rustBlock("fn from(s: T) -> Self") { - rust("$enumName(s.as_ref().to_owned())") - } - } - } - private fun renderEnum() { target.ifClient { writer.renderForwardCompatibilityNote(enumName, sortedMembers, UnknownVariant, UnknownVariantValue) 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 1fa353054a..da2480d6bf 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 @@ -129,6 +129,7 @@ open class Instantiator( } // Simple Shapes + is EnumShape -> renderEnum(writer, shape, data as StringNode) is StringShape -> renderString(writer, shape, data as StringNode) is NumberShape -> when (data) { is StringNode -> { @@ -279,12 +280,13 @@ open class Instantiator( private fun renderString(writer: RustWriter, shape: StringShape, arg: StringNode) { val data = writer.escape(arg.value).dq() - if (shape !is EnumShape) { - writer.rust("$data.to_owned()") - } else { - val enumSymbol = symbolProvider.toSymbol(shape) - writer.rustTemplate("#{EnumFromStringFn:W}", "EnumFromStringFn" to enumFromStringFn(enumSymbol, data)) - } + writer.rust("$data.to_owned()") + } + + private fun renderEnum(writer: RustWriter, shape: EnumShape, arg: StringNode) { + val enumSymbol = symbolProvider.toSymbol(shape) + val data = writer.escape(arg.value).dq() + writer.rustTemplate("#{EnumFromStringFn:W}", "EnumFromStringFn" to enumFromStringFn(enumSymbol, data)) } /** diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt index 96c799179d..2e5fb3a0d0 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt @@ -10,7 +10,6 @@ import software.amazon.smithy.model.knowledge.NullableIndex import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.shapes.StructureShape -import software.amazon.smithy.model.transform.ModelTransformer import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.CratesIo @@ -71,7 +70,6 @@ fun String.asSmithyModel(sourceLocation: String? = null, smithyVersion: String = val processed = letIf(!this.startsWith("\$version")) { "\$version: ${smithyVersion.dq()}\n$it" } return Model.assembler().discoverModels().addUnparsedModel(sourceLocation ?: "test.smithy", processed).assemble() .unwrap() - .let { ModelTransformer.create().changeStringEnumsToEnumShapes(it, true) } } // Intentionally only visible to codegen-core since the other modules have their own symbol providers diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt index 308d6ccb31..0e5fef72d2 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt @@ -14,6 +14,7 @@ import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.traits.DeprecatedTrait import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.model.traits.EnumDefinition +import software.amazon.smithy.model.transform.ModelTransformer import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.rust @@ -44,6 +45,7 @@ class EnumGeneratorTest { ]) string EnumWithUnknown """.asSmithyModel() + .let { ModelTransformer.create().changeStringEnumsToEnumShapes(it, true) } private val symbolProvider = testSymbolProvider(testModel) private val enum = testModel.lookup("test#EnumWithUnknown") @@ -83,7 +85,7 @@ class EnumGeneratorTest { rendered shouldContain """ /// Some documentation. - SomeName1, + #[deprecated]SomeName1, """.trimIndent() } @@ -96,7 +98,7 @@ class EnumGeneratorTest { /// It has some docs that #need to be escaped /// /// _Note: `::Unknown` has been renamed to `::UnknownValue`._ - UnknownValue, + #[deprecated]UnknownValue, """.trimIndent() } } @@ -125,6 +127,7 @@ class EnumGeneratorTest { @deprecated(since: "1.2.3") string InstanceType """.asSmithyModel() + .let { ModelTransformer.create().changeStringEnumsToEnumShapes(it, true) } val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) @@ -169,6 +172,7 @@ class EnumGeneratorTest { }]) string FooEnum """.asSmithyModel() + .let { ModelTransformer.create().changeStringEnumsToEnumShapes(it, true) } val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) @@ -203,6 +207,7 @@ class EnumGeneratorTest { @deprecated string FooEnum """.asSmithyModel() + .let { ModelTransformer.create().changeStringEnumsToEnumShapes(it, true) } val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) @@ -235,6 +240,7 @@ class EnumGeneratorTest { ]) string SomeEnum """.asSmithyModel() + .let { ModelTransformer.create().changeStringEnumsToEnumShapes(it, true) } val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) @@ -266,6 +272,7 @@ class EnumGeneratorTest { ]) string SomeEnum """.asSmithyModel() + .let { ModelTransformer.create().changeStringEnumsToEnumShapes(it, true) } val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) @@ -296,6 +303,7 @@ class EnumGeneratorTest { ]) string SomeEnum """.asSmithyModel() + .let { ModelTransformer.create().changeStringEnumsToEnumShapes(it, true) } val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) @@ -323,6 +331,7 @@ class EnumGeneratorTest { ]) string SomeEnum """.asSmithyModel() + .let { ModelTransformer.create().changeStringEnumsToEnumShapes(it, true) } val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) @@ -374,6 +383,7 @@ class EnumGeneratorTest { ]) string SomeEnum """.asSmithyModel() + .let { ModelTransformer.create().changeStringEnumsToEnumShapes(it, true) } val variant3AsUnknown = """SomeEnum::from("Variant3")""" expectMatchExpressionCompiles(modelV1, "test#SomeEnum", variant3AsUnknown) @@ -387,6 +397,7 @@ class EnumGeneratorTest { ]) string SomeEnum """.asSmithyModel() + .let { ModelTransformer.create().changeStringEnumsToEnumShapes(it, true) } val variant3AsVariant3 = "SomeEnum::Variant3" expectMatchExpressionCompiles(modelV2, "test#SomeEnum", variant3AsVariant3) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt index 5a97ae8073..2f946d3600 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt @@ -66,7 +66,8 @@ fun Shape.isDirectlyConstrained(symbolProvider: SymbolProvider): Boolean = when this.members().map { symbolProvider.toSymbol(it) }.any { !it.isOptional() } } is MapShape -> this.hasTrait() - is StringShape -> this is EnumShape || this.hasTrait() + is EnumShape -> true + is StringShape -> this.hasTrait() else -> false } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt index c3e603163e..8630951e10 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt @@ -360,7 +360,10 @@ open class ServerCodegenVisitor( */ override fun stringShape(shape: StringShape) { if (shape.hasTrait()) { - throw CodegenException("Unnamed @enum shapes are unsupported: $shape") + throw CodegenException( + "Code generation has failed because this unnamed @enum could not be converted to an enum shape: $shape." + + "For more info, look above at the logs from awslabs/smithy.", + ) } if (shape.isDirectlyConstrained(codegenContext.symbolProvider)) { logger.info("[rust-server-codegen] Generating a constrained string $shape") diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorWithoutPublicConstrainedTypes.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorWithoutPublicConstrainedTypes.kt index 897bdc1166..07de8cffa0 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorWithoutPublicConstrainedTypes.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorWithoutPublicConstrainedTypes.kt @@ -138,10 +138,10 @@ class ServerBuilderGeneratorWithoutPublicConstrainedTypes( """, "ReturnType" to buildFnReturnType(isBuilderFallible, structureSymbol), ) - renderBuildEnforcingRequiredAndEnumTraitsFn(implBlockWriter) + renderBuildEnforcingRequiredTraitAndEnumValuesFn(implBlockWriter) } - private fun renderBuildEnforcingRequiredAndEnumTraitsFn(implBlockWriter: RustWriter) { + private fun renderBuildEnforcingRequiredTraitAndEnumValuesFn(implBlockWriter: RustWriter) { implBlockWriter.rustBlockTemplate( "fn build_enforcing_required_and_enum_traits(self) -> #{ReturnType:W}", "ReturnType" to buildFnReturnType(isBuilderFallible, structureSymbol), @@ -208,7 +208,7 @@ class ServerBuilderGeneratorWithoutPublicConstrainedTypes( """ impl #{TryFrom} for #{Structure} { type Error = ConstraintViolation; - + fn try_from(builder: Builder) -> Result { builder.build() }