From 85c413f75fb2f9f2a1da08025133ae3c45fc345d Mon Sep 17 00:00:00 2001 From: Matteo Bigoi <1781140+crisidev@users.noreply.github.com> Date: Thu, 21 Oct 2021 17:37:20 +0100 Subject: [PATCH] Fix #793. Generate all input/output/error serde helpers in server codegen (#794) --- codegen-server-test/build.gradle.kts | 7 +- .../server/smithy/protocols/RestJson1.kt | 64 ++++++++----------- .../protocols/parse/JsonParserGenerator.kt | 18 ++++-- .../parse/StructuredDataParserGenerator.kt | 2 +- .../parse/XmlBindingTraitParserGenerator.kt | 2 +- .../serialize/AwsQuerySerializerGenerator.kt | 4 +- .../serialize/Ec2QuerySerializerGenerator.kt | 4 +- .../serialize/JsonSerializerGenerator.kt | 15 +++-- .../StructuredDataSerializerGenerator.kt | 4 +- .../XmlBindingTraitSerializerGenerator.kt | 4 +- 10 files changed, 63 insertions(+), 61 deletions(-) diff --git a/codegen-server-test/build.gradle.kts b/codegen-server-test/build.gradle.kts index a22d7df03..e61c0a9e3 100644 --- a/codegen-server-test/build.gradle.kts +++ b/codegen-server-test/build.gradle.kts @@ -27,6 +27,11 @@ val CodegenTests = listOf( CodegenTest("com.amazonaws.ebs#Ebs", "ebs") ) +/** + * The fluent client is generated to prevent warnings in RustDoc since the client is + * referenced by multiple documentations. + * TODO: review client generation in the future. + */ fun generateSmithyBuild(tests: List): String { val projections = tests.joinToString(",\n") { @@ -35,7 +40,7 @@ fun generateSmithyBuild(tests: List): String { "plugins": { "rust-server-codegen": { "codegen": { - "includeFluentClient": false + "includeFluentClient": true }, "runtimeConfig": { "relativePath": "${rootProject.projectDir.absolutePath}/rust-runtime" diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/RestJson1.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/RestJson1.kt index 6e80fd9e3..ab32d0490 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/RestJson1.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/RestJson1.kt @@ -102,9 +102,6 @@ class RestJson1HttpSerializerGenerator( return } val serializerSymbol = jsonSerializerGenerator.serverOutputSerializer(operationShape) - if (serializerSymbol == null) { - return - } val outputSymbol = symbolProvider.toSymbol(outputShape) writer.write("") writer.rustBlockTemplate( @@ -169,44 +166,38 @@ class RestJson1HttpSerializerGenerator( val variantSymbol = symbolProvider.toSymbol(variantShape) val data = safeName("var") val serializerSymbol = jsonSerializerGenerator.serverErrorSerializer(it) - if (serializerSymbol != null) { - rustBlock("#TKind::${variantSymbol.name}($data) =>", errorSymbol) { + rustBlock("#TKind::${variantSymbol.name}($data) =>", errorSymbol) { + rust( + """ + #T(&$data)?; + object.key(${"code".dq()}).string(${httpBindingResolver.errorCode(variantShape).dq()}); + """.trimIndent(), + serializerSymbol + ) + if (variantShape.errorMessageMember() != null) { rust( """ - #T(&$data)?; - object.key(${"code".dq()}).string(${httpBindingResolver.errorCode(variantShape).dq()}); - """.trimIndent(), - serializerSymbol - ) - if (variantShape.errorMessageMember() != null) { - rust( - """ - if let Some(message) = $data.message() { - object.key(${"message".dq()}).string(message); - } - """.trimIndent() - ) - } - val bindings = httpBindingResolver.errorResponseBindings(it) - bindings.forEach { binding -> - when (val location = binding.location) { - HttpLocation.RESPONSE_CODE, HttpLocation.DOCUMENT -> {} - else -> { - logger.warning( - "$operationShape: response serialization does not currently support $location bindings" - ) + if let Some(message) = $data.message() { + object.key(${"message".dq()}).string(message); } + """.trimIndent() + ) + } + val bindings = httpBindingResolver.errorResponseBindings(it) + bindings.forEach { binding -> + when (val location = binding.location) { + HttpLocation.RESPONSE_CODE, HttpLocation.DOCUMENT -> {} + else -> { + logger.warning( + "$operationShape: response serialization does not currently support $location bindings" + ) } } - val status = - variantShape.getTrait()?.let { trait -> trait.code } - ?: errorTrait.defaultHttpStatusCode - rust("response = response.status($status);") } - } else { - logger.warning( - "[rust-server-codegen] $variantShape: response error serialization does not contain any member" - ) + val status = + variantShape.getTrait()?.let { trait -> trait.code } + ?: errorTrait.defaultHttpStatusCode + rust("response = response.status($status);") } } rust( @@ -369,9 +360,6 @@ class RestJson1HttpDeserializerGenerator( return } val deserializerSymbol = jsonParserGenerator.serverInputParser(operationShape) - if (deserializerSymbol == null) { - return - } val inputSymbol = symbolProvider.toSymbol(inputShape) writer.write("") writer.rustBlockTemplate( diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/JsonParserGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/JsonParserGenerator.kt index 2fbec3134..0dbb0f6d7 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/JsonParserGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/JsonParserGenerator.kt @@ -83,14 +83,14 @@ class JsonParserGenerator( /** * Reusable structure parser implementation that can be used to generate parsing code for * operation, error and structure shapes. + * We still generate the parser symbol even if there are no included members because the server + * generation requires parsers for all input structures. */ - private fun structureParser(fnName: String, structureShape: StructureShape, includedMembers: List): RuntimeType? { - if (includedMembers.isEmpty()) { - return null - } + private fun structureParser(fnName: String, structureShape: StructureShape, includedMembers: List): RuntimeType { + val unusedMut = if (includedMembers.isEmpty()) "##[allow(unused_mut)] " else "" return RuntimeType.forInlineFun(fnName, jsonDeserModule) { it.rustBlockTemplate( - "pub fn $fnName(value: &[u8], mut builder: #{Builder}) -> Result<#{Builder}, #{Error}>", + "pub fn $fnName(value: &[u8], ${unusedMut}mut builder: #{Builder}) -> Result<#{Builder}, #{Error}>", "Builder" to structureShape.builderSymbol(symbolProvider), *codegenScope ) { @@ -138,12 +138,18 @@ class JsonParserGenerator( override fun operationParser(operationShape: OperationShape): RuntimeType? { // Don't generate an operation JSON deserializer if there is no JSON body val httpDocumentMembers = httpBindingResolver.responseMembers(operationShape, HttpLocation.DOCUMENT) + if (httpDocumentMembers.isEmpty()) { + return null + } val outputShape = operationShape.outputShape(model) val fnName = symbolProvider.deserializeFunctionName(operationShape) return structureParser(fnName, outputShape, httpDocumentMembers) } override fun errorParser(errorShape: StructureShape): RuntimeType? { + if (errorShape.members().isEmpty()) { + return null + } val fnName = symbolProvider.deserializeFunctionName(errorShape) + "_json_err" return structureParser(fnName, errorShape, errorShape.members().toList()) } @@ -184,7 +190,7 @@ class JsonParserGenerator( ) } - override fun serverInputParser(operationShape: OperationShape): RuntimeType? { + override fun serverInputParser(operationShape: OperationShape): RuntimeType { val inputShape = operationShape.inputShape(model) val includedMembers = httpBindingResolver.requestMembers(operationShape, HttpLocation.DOCUMENT) val fnName = symbolProvider.deserializeFunctionName(inputShape) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/StructuredDataParserGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/StructuredDataParserGenerator.kt index dd9b6f8c9..fbd36f7a8 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/StructuredDataParserGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/StructuredDataParserGenerator.kt @@ -66,5 +66,5 @@ interface StructuredDataParserGenerator { * } * ``` */ - fun serverInputParser(operationShape: OperationShape): RuntimeType? + fun serverInputParser(operationShape: OperationShape): RuntimeType } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/XmlBindingTraitParserGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/XmlBindingTraitParserGenerator.kt index ee53e03c4..7648bbed4 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/XmlBindingTraitParserGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/parse/XmlBindingTraitParserGenerator.kt @@ -241,7 +241,7 @@ class XmlBindingTraitParserGenerator( TODO("Document shapes are not supported by rest XML") } - override fun serverInputParser(operationShape: OperationShape): RuntimeType? { + override fun serverInputParser(operationShape: OperationShape): RuntimeType { TODO("Not yet implemented") } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/AwsQuerySerializerGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/AwsQuerySerializerGenerator.kt index 9bd3b342d..6f8cf6fcc 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/AwsQuerySerializerGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/AwsQuerySerializerGenerator.kt @@ -22,11 +22,11 @@ class AwsQuerySerializerGenerator(codegenContext: CodegenContext) : QuerySeriali override fun MemberShape.isFlattened(): Boolean = getTrait() != null - override fun serverOutputSerializer(operationShape: OperationShape): RuntimeType? { + override fun serverOutputSerializer(operationShape: OperationShape): RuntimeType { TODO("Not yet implemented") } - override fun serverErrorSerializer(shape: ShapeId): RuntimeType? { + override fun serverErrorSerializer(shape: ShapeId): RuntimeType { TODO("Not yet implemented") } } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/Ec2QuerySerializerGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/Ec2QuerySerializerGenerator.kt index e36d92e09..cfcd4fde4 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/Ec2QuerySerializerGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/Ec2QuerySerializerGenerator.kt @@ -25,11 +25,11 @@ class Ec2QuerySerializerGenerator(codegenContext: CodegenContext) : QuerySeriali override fun MemberShape.isFlattened(): Boolean = true - override fun serverOutputSerializer(operationShape: OperationShape): RuntimeType? { + override fun serverOutputSerializer(operationShape: OperationShape): RuntimeType { TODO("Not yet implemented") } - override fun serverErrorSerializer(shape: ShapeId): RuntimeType? { + override fun serverErrorSerializer(shape: ShapeId): RuntimeType { TODO("Not yet implemented") } } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/JsonSerializerGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/JsonSerializerGenerator.kt index 7d403d4c1..5dd82db96 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/JsonSerializerGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/JsonSerializerGenerator.kt @@ -141,10 +141,13 @@ class JsonSerializerGenerator( private val operationSerModule = RustModule.private("operation_ser") private val jsonSerModule = RustModule.private("json_ser") - private fun structureSerializer(fnName: String, structureShape: StructureShape, includedMembers: List): RuntimeType? { - if (includedMembers.isEmpty()) { - return null - } + /** + * Reusable structure serializer implementation that can be used to generate serializing code for + * operation, error and structure shapes. + * We still generate the serializer symbol even if there are no included members because the server + * generation requires serializers for all output/error structures. + */ + private fun structureSerializer(fnName: String, structureShape: StructureShape, includedMembers: List): RuntimeType { return RuntimeType.forInlineFun(fnName, operationSerModule) { it.rustBlockTemplate( "pub fn $fnName(value: &#{target}) -> Result", @@ -220,14 +223,14 @@ class JsonSerializerGenerator( } } - override fun serverOutputSerializer(operationShape: OperationShape): RuntimeType? { + override fun serverOutputSerializer(operationShape: OperationShape): RuntimeType { val outputShape = operationShape.outputShape(model) val includedMembers = httpBindingResolver.responseMembers(operationShape, HttpLocation.DOCUMENT) val fnName = symbolProvider.serializeFunctionName(outputShape) return structureSerializer(fnName, outputShape, includedMembers) } - override fun serverErrorSerializer(shape: ShapeId): RuntimeType? { + override fun serverErrorSerializer(shape: ShapeId): RuntimeType { val errorShape = model.expectShape(shape, StructureShape::class.java) val includedMembers = httpBindingResolver.errorResponseBindings(shape).filter { it.location == HttpLocation.DOCUMENT }.map { it.member } val fnName = symbolProvider.serializeFunctionName(errorShape) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/StructuredDataSerializerGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/StructuredDataSerializerGenerator.kt index 5c97f9058..881e94ea5 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/StructuredDataSerializerGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/StructuredDataSerializerGenerator.kt @@ -49,7 +49,7 @@ interface StructuredDataSerializerGenerator { * } * ``` */ - fun serverOutputSerializer(operationShape: OperationShape): RuntimeType? + fun serverOutputSerializer(operationShape: OperationShape): RuntimeType /** * Generate a serializer for a server operation error structure @@ -59,5 +59,5 @@ interface StructuredDataSerializerGenerator { * } * ``` */ - fun serverErrorSerializer(shape: ShapeId): RuntimeType? + fun serverErrorSerializer(shape: ShapeId): RuntimeType } diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/XmlBindingTraitSerializerGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/XmlBindingTraitSerializerGenerator.kt index 014e1f78b..c1dd54964 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/XmlBindingTraitSerializerGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/XmlBindingTraitSerializerGenerator.kt @@ -177,11 +177,11 @@ class XmlBindingTraitSerializerGenerator( } } - override fun serverOutputSerializer(operationShape: OperationShape): RuntimeType? { + override fun serverOutputSerializer(operationShape: OperationShape): RuntimeType { TODO("Not yet implemented") } - override fun serverErrorSerializer(shape: ShapeId): RuntimeType? { + override fun serverErrorSerializer(shape: ShapeId): RuntimeType { TODO("Not yet implemented") } -- GitLab