Unverified Commit 22a77460 authored by Matteo Bigoi's avatar Matteo Bigoi Committed by GitHub
Browse files

Deduplicate server input / output / error structures by storing what has been...

Deduplicate server input / output / error structures by storing what has been already rendered. (#747)

* Deduplicate server input / output / error structures by storing what has
been already rendered.

* Add ebs test model and enable generation of enums and unions also for
the server types.
parent c41abde4
Loading
Loading
Loading
Loading
+9 −6
Original line number Diff line number Diff line
@@ -22,7 +22,10 @@ dependencies {

data class CodegenTest(val service: String, val module: String, val extraConfig: String? = null)

val CodegenTests = listOf(CodegenTest("com.amazonaws.simple#SimpleService", "simple"))
val CodegenTests = listOf(
    CodegenTest("com.amazonaws.simple#SimpleService", "simple"),
    CodegenTest("com.amazonaws.ebs#Ebs", "ebs")
)

fun generateSmithyBuild(tests: List<CodegenTest>): String {
    val projections =
+1 −0
Original line number Diff line number Diff line
../../codegen-test/model/ebs.json
 No newline at end of file
+37 −6
Original line number Diff line number Diff line
@@ -9,11 +9,15 @@ import software.amazon.smithy.aws.traits.protocols.RestJson1Trait
import software.amazon.smithy.build.PluginContext
import software.amazon.smithy.model.Model
import software.amazon.smithy.model.neighbor.Walker
import software.amazon.smithy.model.shapes.MemberShape
import software.amazon.smithy.model.shapes.OperationShape
import software.amazon.smithy.model.shapes.ServiceShape
import software.amazon.smithy.model.shapes.Shape
import software.amazon.smithy.model.shapes.ShapeVisitor
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.rustlang.RustMetadata
import software.amazon.smithy.rust.codegen.rustlang.RustModule
import software.amazon.smithy.rust.codegen.rustlang.RustWriter
@@ -29,10 +33,12 @@ import software.amazon.smithy.rust.codegen.smithy.RustSymbolProvider
import software.amazon.smithy.rust.codegen.smithy.SymbolVisitorConfig
import software.amazon.smithy.rust.codegen.smithy.customize.RustCodegenDecorator
import software.amazon.smithy.rust.codegen.smithy.generators.BuilderGenerator
import software.amazon.smithy.rust.codegen.smithy.generators.EnumGenerator
import software.amazon.smithy.rust.codegen.smithy.generators.HttpProtocolGenerator
import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolConfig
import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolGeneratorFactory
import software.amazon.smithy.rust.codegen.smithy.generators.StructureGenerator
import software.amazon.smithy.rust.codegen.smithy.generators.UnionGenerator
import software.amazon.smithy.rust.codegen.smithy.generators.implBlock
import software.amazon.smithy.rust.codegen.smithy.letIf
import software.amazon.smithy.rust.codegen.smithy.protocols.HttpBindingResolver
@@ -49,6 +55,7 @@ import software.amazon.smithy.rust.codegen.smithy.transformers.OperationNormaliz
import software.amazon.smithy.rust.codegen.smithy.transformers.RecursiveShapeBoxer
import software.amazon.smithy.rust.codegen.smithy.transformers.RemoveEventStreamOperations
import software.amazon.smithy.rust.codegen.util.CommandFailed
import software.amazon.smithy.rust.codegen.util.getTrait
import software.amazon.smithy.rust.codegen.util.hasTrait
import software.amazon.smithy.rust.codegen.util.inputShape
import software.amazon.smithy.rust.codegen.util.outputShape
@@ -74,6 +81,7 @@ class CodegenVisitor(context: PluginContext, private val codegenDecorator: RustC
    private val httpSerializerGenerator: ServerGenerator
    private val httpDeserializerGenerator: ServerGenerator
    private val httpBindingResolver: HttpBindingResolver
    private val renderedStructures = mutableSetOf<StructureShape>()

    init {
        val symbolVisitorConfig =
@@ -165,6 +173,18 @@ class CodegenVisitor(context: PluginContext, private val codegenDecorator: RustC
        logger.info("[rust-server-codegen] Rust server generation complete!")
    }

    private fun renderStructure(
        writer: RustWriter,
        structureShape: StructureShape,
        includedMembers: List<MemberShape>,
    ) {
        // TODO: review this deduplication mechanism as it doesn't feel very ergonomic
        if (renderedStructures.add(structureShape)) {
            serializerGenerator.renderStructure(writer, structureShape, includedMembers)
            deserializerGenerator.renderStructure(writer, structureShape, includedMembers)
        }
    }

    override fun getDefault(shape: Shape?) {}

    override fun operationShape(shape: OperationShape?) {
@@ -178,14 +198,11 @@ class CodegenVisitor(context: PluginContext, private val codegenDecorator: RustC
                shape.let {
                    httpDeserializerGenerator.render(writer, it)
                    httpSerializerGenerator.render(writer, it)
                    serializerGenerator.renderStructure(writer, shape.inputShape(model), inputHttpDocumentMembers)
                    serializerGenerator.renderStructure(writer, shape.outputShape(model), outputHttpDocumentMembers)
                    deserializerGenerator.renderStructure(writer, shape.inputShape(model), inputHttpDocumentMembers)
                    deserializerGenerator.renderStructure(writer, shape.outputShape(model), outputHttpDocumentMembers)
                    renderStructure(writer, shape.inputShape(model), inputHttpDocumentMembers)
                    renderStructure(writer, shape.outputShape(model), outputHttpDocumentMembers)
                    shape.errors.forEach { error ->
                        val errorShape = model.expectShape(error, StructureShape::class.java)
                        serializerGenerator.renderStructure(writer, errorShape, errorShape.members().toList())
                        deserializerGenerator.renderStructure(writer, errorShape, errorShape.members().toList())
                        renderStructure(writer, errorShape, errorShape.members().toList())
                    }
                }
            }
@@ -207,6 +224,20 @@ class CodegenVisitor(context: PluginContext, private val codegenDecorator: RustC
        }
    }

    override fun stringShape(shape: StringShape) {
        shape.getTrait<EnumTrait>()?.also { enum ->
            rustCrate.useShapeWriter(shape) { writer ->
                EnumGenerator(model, symbolProvider, writer, shape, enum).render()
            }
        }
    }

    override fun unionShape(shape: UnionShape) {
        rustCrate.useShapeWriter(shape) {
            UnionGenerator(model, symbolProvider, it, shape).render()
        }
    }

    override fun serviceShape(shape: ServiceShape) {
        ServiceGenerator(
            rustCrate,

codegen-test/model/simple.smithy

deleted100644 → 0
+1 −78
Original line number Diff line number Diff line
$version: "1.0"

namespace com.amazonaws.simple

use aws.protocols#restJson1

@restJson1
@title("SimpleService")
@documentation("A simple service example, with a Service resource that can be registered and a readonly healthcheck")
service SimpleService {
    version: "2022-01-01",
    resources: [
        Service,
    ],
    operations: [
        Healthcheck,
    ],
}

@documentation("Id of the service that will be registered")
string ServiceId

@error("client")
@documentation(
    """
    Returned when a new resource cannot be created because one already exists.
    """
)
structure ResourceAlreadyExists {
    @required
    message: String
}

@documentation("A resource that can register services")
resource Service {
    identifiers: { id: ServiceId },
    put: RegisterService,
}

@idempotent
@http(method: "PUT", uri: "/service/{id}")
@documentation("Service register operation")
operation RegisterService {
    input: RegisterServiceInput,
    output: RegisterServiceOutput,
    errors: [ResourceAlreadyExists]
}

@documentation("Service register input structure")
structure RegisterServiceInput {
    @required
    @httpLabel
    id: ServiceId,
}

@documentation("Service register output structure")
structure RegisterServiceOutput {
    @required
    id: ServiceId
}

@readonly
@http(uri: "/healthcheck", method: "GET")
@documentation("Read-only healthcheck operation")
operation Healthcheck {
    input: HealthcheckInput,
    output: HealthcheckOutput
}

@documentation("Service healthcheck output structure")
structure HealthcheckInput {

}

@documentation("Service healthcheck input structure")
structure HealthcheckOutput {

}
+1 −78
Original line number Diff line number Diff line
../../codegen-server-test/model/simple.smithy
 No newline at end of file
+1 −78

File changed.File mode changed from 100644 to 120000.

Contains only whitespace changes.