From 9ac6968a7e17b10aedf4cfdf5bda893c5ff63553 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 31 Aug 2022 23:23:56 +0000 Subject: [PATCH 01/73] Add version getter to AwsJson --- .../amazon/smithy/rust/codegen/smithy/protocols/AwsJson.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson.kt index 5750b04ebe..4f25b82f00 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson.kt @@ -143,6 +143,8 @@ open class AwsJson( ) private val jsonDeserModule = RustModule.private("json_deser") + val version: AwsJsonVersion get() = awsJsonVersion + override val httpBindingResolver: HttpBindingResolver = AwsJsonHttpBindingResolver(coreCodegenContext.model, awsJsonVersion) From 4c1b6ed6c58835605139a851d92f149caad3e709 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 31 Aug 2022 23:24:30 +0000 Subject: [PATCH 02/73] Add ServerProtocol interface and implement it --- .../generators/protocol/ServerProtocol.kt | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt new file mode 100644 index 0000000000..933db8fc39 --- /dev/null +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -0,0 +1,76 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.server.smithy.generators.protocol + +import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency +import software.amazon.smithy.rust.codegen.smithy.RuntimeConfig +import software.amazon.smithy.rust.codegen.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.smithy.protocols.AwsJson +import software.amazon.smithy.rust.codegen.smithy.protocols.AwsJsonVersion +import software.amazon.smithy.rust.codegen.smithy.protocols.Protocol +import software.amazon.smithy.rust.codegen.smithy.protocols.RestJson + +interface ServerProtocol { + fun coreProtocol(): Protocol + + fun markerStruct(): RuntimeType + + fun routerType(): RuntimeType + + companion object { + fun fromCoreProtocol(runtimeConfig: RuntimeConfig, protocol: Protocol): ServerProtocol { + val serverProtocol = when (protocol) { + is AwsJson -> AwsJsonServerProtocol(runtimeConfig, protocol) + is RestJson -> RestJsonServerProtocol(runtimeConfig, protocol) + else -> throw IllegalStateException("unsupported protocol") + } + return serverProtocol + } + } +} + +class AwsJsonServerProtocol( + private val runtimeConfig: RuntimeConfig, + private val coreProtocol: AwsJson, +) : ServerProtocol { + override fun coreProtocol(): Protocol { + return coreProtocol + } + + override fun markerStruct(): RuntimeType { + val name = when (coreProtocol.version) { + is AwsJsonVersion.Json10 -> { + "AwsJson10" + } + is AwsJsonVersion.Json11 -> { + "AwsJson11" + } + else -> throw IllegalStateException() + } + return RuntimeType(name, ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") + } + + override fun routerType(): RuntimeType { + return RuntimeType("AwsJsonRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing") + } +} + +class RestJsonServerProtocol( + private val runtimeConfig: RuntimeConfig, + private val coreProtocol: RestJson, +) : ServerProtocol { + override fun coreProtocol(): Protocol { + return coreProtocol + } + + override fun markerStruct(): RuntimeType { + return RuntimeType("AwsRestJson1", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") + } + + override fun routerType(): RuntimeType { + return RuntimeType("RestRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::rest") + } +} From 1c9511441c8096dc64814dab35f3143cb8c9eabd Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 31 Aug 2022 23:26:26 +0000 Subject: [PATCH 03/73] Add ServerOperationGenerator --- .../generators/ServerOperationGenerator.kt | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt new file mode 100644 index 0000000000..9f7d7fb710 --- /dev/null +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt @@ -0,0 +1,89 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.server.smithy.generators + +import software.amazon.smithy.model.shapes.OperationShape +import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.model.traits.DocumentationTrait +import software.amazon.smithy.rust.codegen.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.rustlang.Writable +import software.amazon.smithy.rust.codegen.rustlang.asType +import software.amazon.smithy.rust.codegen.rustlang.rust +import software.amazon.smithy.rust.codegen.rustlang.rustTemplate +import software.amazon.smithy.rust.codegen.rustlang.writable +import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency +import software.amazon.smithy.rust.codegen.smithy.CoreCodegenContext +import software.amazon.smithy.rust.codegen.util.getTrait +import software.amazon.smithy.rust.codegen.util.toPascalCase + +private fun shapeToStructName(shapeId: ShapeId): String { + return shapeId.name.toPascalCase() +} + +class ServerOperationGenerator( + coreCodegenContext: CoreCodegenContext, + private val operation: OperationShape, +) { + private val runtimeConfig = coreCodegenContext.runtimeConfig + private val codegenScope = + arrayOf( + "SmithyHttpServer" to + ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType(), + ) + + private val operationId = operation.id + + private fun renderStructDef(): Writable = writable { + val documentationLines = operation.getTrait()?.value?.lines() + if (documentationLines != null) { + for (documentation in documentationLines) { + rust("/// $documentation") + } + } + + rust("pub struct ${shapeToStructName(operationId)};") + } + + private fun operationError(): Writable = writable { + if (operation.errors.isEmpty()) { + rust("std::convert::Infallible") + } else { + val operationStructName = shapeToStructName(operationId) + rust("crate::error::${operationStructName}Error") + } + } + + private fun renderImpl(): Writable = writable { + val operationStructName = shapeToStructName(operationId) + rustTemplate( + """ + impl #{SmithyHttpServer}::operation::OperationShape for $operationStructName { + const NAME: &'static str = "${operationId.toString().replace("#", "##")}"; + + type Input = crate::input::${operationStructName}Input; + type Output = crate::output::${operationStructName}Output; + type Error = #{Error:W}; + } + """, + "Error" to operationError(), + *codegenScope, + ) + } + + fun render(writer: RustWriter) { + writer.rustTemplate( + """ + #{Struct:W} + + #{Impl:W} + """, + "Struct" to renderStructDef(), + "Impl" to renderImpl(), + ) + // Adds newline to end of render + writer.rust("") + } +} From 568972739aef0de03d71d899ab694fe0f0f770dc Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 31 Aug 2022 23:27:31 +0000 Subject: [PATCH 04/73] Make routing machinery public --- .../aws-smithy-http-server/src/routing/mod.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/rust-runtime/aws-smithy-http-server/src/routing/mod.rs b/rust-runtime/aws-smithy-http-server/src/routing/mod.rs index 0c65e4aff9..d977d25d37 100644 --- a/rust-runtime/aws-smithy-http-server/src/routing/mod.rs +++ b/rust-runtime/aws-smithy-http-server/src/routing/mod.rs @@ -7,17 +7,18 @@ //! //! [Smithy specification]: https://awslabs.github.io/smithy/1.0/spec/core/http-traits.html +use std::{ + convert::Infallible, + task::{Context, Poll}, +}; + use self::request_spec::RequestSpec; -use self::routers::{aws_json::AwsJsonRouter, rest::RestRouter, RoutingService}; +use self::routers::{aws_json::AwsJsonRouter, rest::RestRouter}; use crate::body::{boxed, Body, BoxBody, HttpBody}; use crate::error::BoxError; use crate::protocols::{AwsJson10, AwsJson11, AwsRestJson1, AwsRestXml}; use http::{Request, Response}; -use std::{ - convert::Infallible, - task::{Context, Poll}, -}; use tower::layer::Layer; use tower::{Service, ServiceBuilder}; use tower_http::map_response_body::MapResponseBodyLayer; @@ -35,6 +36,7 @@ mod tiny_map; pub use self::lambda_handler::LambdaHandler; pub use self::{future::RouterFuture, into_make_service::IntoMakeService, route::Route}; +pub use routers::*; /// The router is a [`tower::Service`] that routes incoming requests to other `Service`s /// based on the request's URI and HTTP method or on some specific header setting the target operation. From 2269aef4a0f1f2b5955e9eb2b67511ba6bc67e65 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 31 Aug 2022 23:40:50 +0000 Subject: [PATCH 05/73] Add basic ServerServiceGeneratorV2 --- .../generators/ServerServiceGeneratorV2.kt | 220 ++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt new file mode 100644 index 0000000000..c813c93ee9 --- /dev/null +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -0,0 +1,220 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.server.smithy.generators + +import software.amazon.smithy.model.shapes.ServiceShape +import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.model.traits.DocumentationTrait +import software.amazon.smithy.rust.codegen.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.rustlang.Writable +import software.amazon.smithy.rust.codegen.rustlang.asType +import software.amazon.smithy.rust.codegen.rustlang.rust +import software.amazon.smithy.rust.codegen.rustlang.rustTemplate +import software.amazon.smithy.rust.codegen.rustlang.writable +import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency +import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocol +import software.amazon.smithy.rust.codegen.smithy.RuntimeConfig +import software.amazon.smithy.rust.codegen.util.getTrait +import software.amazon.smithy.rust.codegen.util.toPascalCase +import software.amazon.smithy.rust.codegen.util.toSnakeCase + +private fun shapeToStructName(shapeId: ShapeId): String { + return shapeId.name.toPascalCase() +} + +private fun shapeToFieldName(shapeId: ShapeId): String { + return shapeId.name.toSnakeCase() +} + +class ServerServiceGeneratorV2( + runtimeConfig: RuntimeConfig, + private val service: ServiceShape, + private val protocol: ServerProtocol, +) { + private val codegenScope = + arrayOf( + "SmithyHttpServer" to + ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType(), + ) + + private val serviceId = service.id + + private fun builderName(): String { + return "${shapeToStructName(serviceId)}Builder" + } + + private fun builderGenerics(): Sequence { + return sequence { + for (index in 1..service.operations.size) { + yield("Op$index") + } + } + } + + private fun builderFieldNames(): Sequence { + return sequence { + for (operation in service.operations) { + yield(shapeToFieldName(operation)) + } + } + } + + private fun operationStructNames(): Sequence { + return sequence { + for (operation in service.operations) { + yield(shapeToStructName(operation)) + } + } + } + + private fun builderFields(): Writable = writable { + val zipped = builderFieldNames().zip(builderGenerics()) + for ((name, type) in zipped) { + rust("$name: $type,") + } + } + + private fun builderDef(): Writable = writable { + rustTemplate( + """ + /// The service builder for [`${shapeToStructName(serviceId)}`]. + /// + /// Constructed via [`${shapeToStructName(serviceId)}::builder`]. + pub struct ${builderName()}<${builderGenerics().joinToString(",")}> { + #{Fields:W} + } + """, + "Fields" to builderFields(), + ) + } + + private fun builderSetters(): Writable = writable { + for ((index, pair) in builderFieldNames().zip(operationStructNames()).withIndex()) { + val (fieldName, structName) = pair + val replacedGenerics = builderGenerics().withIndex().map { (innerIndex, item) -> + if (innerIndex == index) { + "NewOp" + } else { + item + } + } + + val switchedFields = writable { + for ((innerIndex, innerFieldName) in builderFieldNames().withIndex()) { + if (index == innerIndex) { + rust("$innerFieldName: value,") + } else { + rust("$innerFieldName: self.$innerFieldName,") + } + } + } + + rustTemplate( + """ + /// Sets the `$structName` operation. + /// + /// This should be an [`Operation`](#{SmithyHttpServer}::operation::Operation) created from [`$structName`](crate::operations::$structName) + /// using either [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationExt::from_handler) or + /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationExt::from_handler). + pub fn $fieldName(self, value: NewOp) -> ${builderName()}<${ + replacedGenerics.joinToString( + ",", + ) + }> { + ${builderName()} { + #{SwitchedFields:W} + } + } + """, + "SwitchedFields" to switchedFields, + *codegenScope, + ) + + // Adds newline to between setters + rust("") + } + } + + private fun builderImpl(): Writable = writable { + val generics = builderGenerics().joinToString(",") + rustTemplate( + """ + impl<$generics> ${builderName()}<$generics> { + #{Setters:W} + } + """, + "Setters" to builderSetters(), + ) + } + + private fun structDef(): Writable = writable { + val documentationLines = service.getTrait()?.value?.lines() + if (documentationLines != null) { + for (documentation in documentationLines) { + rust("/// $documentation") + } + } + rustTemplate( + """ + pub struct ${shapeToStructName(serviceId)} { + router: #{SmithyHttpServer}::routing::RoutingService<#{Router}, #{Protocol}>, + } + """, + "Router" to protocol.routerType(), + "Protocol" to protocol.markerStruct(), + *codegenScope, + ) + } + + private fun notSetGenerics(): Writable = writable { + for (index in 1..service.operations.size) { + rustTemplate("#{SmithyHttpServer}::operation::OperationNotSet,", *codegenScope) + } + } + + private fun notSetFields(): Writable = writable { + for (operation in service.operations) { + rustTemplate( + "${shapeToFieldName(operation)}: #{SmithyHttpServer}::operation::OperationNotSet,", + *codegenScope, + ) + } + } + + private fun structImpl(): Writable = writable { + rustTemplate( + """ + impl ${shapeToStructName(serviceId)}<()> { + /// Constructs a builder for [`${shapeToStructName(serviceId)}`]. + pub fn builder() -> ${builderName()}<#{NotSetGenerics:W}> { + ${builderName()} { + #{NotSetFields:W} + } + } + } + """, + "NotSetGenerics" to notSetGenerics(), "NotSetFields" to notSetFields(), + ) + } + + fun render(writer: RustWriter) { + writer.rustTemplate( + """ + #{Builder:W} + + #{BuilderImpl:W} + + #{Struct:W} + + #{StructImpl:W} + """, + "Builder" to builderDef(), + "BuilderImpl" to builderImpl(), + "Struct" to structDef(), + "StructImpl" to structImpl(), + ) + } +} From fc33fbc6b3aa64e0789eeb89d3658cd31615dca3 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 31 Aug 2022 23:44:32 +0000 Subject: [PATCH 06/73] Add temporary module rendering --- .../generators/ServerServiceGenerator.kt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt index 634be6c386..24650ead88 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt @@ -9,6 +9,7 @@ import software.amazon.smithy.model.knowledge.TopDownIndex import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.rustlang.RustModule import software.amazon.smithy.rust.codegen.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocol import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocolTestGenerator import software.amazon.smithy.rust.codegen.smithy.CoreCodegenContext import software.amazon.smithy.rust.codegen.smithy.RustCrate @@ -66,6 +67,28 @@ open class ServerServiceGenerator( ) { writer -> renderOperationRegistry(writer, operations) } + + // TODO: Remove, this is temporary. + rustCrate.withModule( + RustModule.public("operations", "TODO"), + ) { writer -> + for (operation in operations) { + ServerOperationGenerator(coreCodegenContext, operation).render(writer) + } + } + + // TODO: Remove, this is temporary. + rustCrate.withModule( + RustModule.public("services", "TODO"), + ) { writer -> + val serverProtocol = ServerProtocol.fromCoreProtocol(coreCodegenContext.runtimeConfig, protocol) + ServerServiceGeneratorV2( + coreCodegenContext.runtimeConfig, + coreCodegenContext.serviceShape, + serverProtocol, + ).render(writer) + } + renderExtras(operations) } From 40540fede286ff7c487daa131f36516922fbd61b Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Thu, 1 Sep 2022 08:31:23 +0000 Subject: [PATCH 07/73] Fix namespacing --- .../server/smithy/generators/ServerServiceGeneratorV2.kt | 2 +- .../server/smithy/generators/protocol/ServerProtocol.kt | 4 ++-- rust-runtime/aws-smithy-http-server/src/routing/mod.rs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index c813c93ee9..c9459e3934 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -160,7 +160,7 @@ class ServerServiceGeneratorV2( rustTemplate( """ pub struct ${shapeToStructName(serviceId)} { - router: #{SmithyHttpServer}::routing::RoutingService<#{Router}, #{Protocol}>, + router: #{SmithyHttpServer}::routing::routers::RoutingService<#{Router}, #{Protocol}>, } """, "Router" to protocol.routerType(), diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 933db8fc39..4caac28b20 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -54,7 +54,7 @@ class AwsJsonServerProtocol( } override fun routerType(): RuntimeType { - return RuntimeType("AwsJsonRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing") + return RuntimeType("AwsJsonRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::routers::aws_json") } } @@ -71,6 +71,6 @@ class RestJsonServerProtocol( } override fun routerType(): RuntimeType { - return RuntimeType("RestRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::rest") + return RuntimeType("RestRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::routers::rest") } } diff --git a/rust-runtime/aws-smithy-http-server/src/routing/mod.rs b/rust-runtime/aws-smithy-http-server/src/routing/mod.rs index d977d25d37..3e8a67c9c1 100644 --- a/rust-runtime/aws-smithy-http-server/src/routing/mod.rs +++ b/rust-runtime/aws-smithy-http-server/src/routing/mod.rs @@ -13,7 +13,7 @@ use std::{ }; use self::request_spec::RequestSpec; -use self::routers::{aws_json::AwsJsonRouter, rest::RestRouter}; +use self::routers::{aws_json::AwsJsonRouter, rest::RestRouter, RoutingService}; use crate::body::{boxed, Body, BoxBody, HttpBody}; use crate::error::BoxError; use crate::protocols::{AwsJson10, AwsJson11, AwsRestJson1, AwsRestXml}; @@ -31,12 +31,12 @@ mod lambda_handler; pub mod request_spec; mod route; -mod routers; +#[doc(hidden)] +pub mod routers; mod tiny_map; pub use self::lambda_handler::LambdaHandler; pub use self::{future::RouterFuture, into_make_service::IntoMakeService, route::Route}; -pub use routers::*; /// The router is a [`tower::Service`] that routes incoming requests to other `Service`s /// based on the request's URI and HTTP method or on some specific header setting the target operation. From 44c10683c56a6e5936c04af737bc462d59c614fd Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Thu, 1 Sep 2022 09:04:10 +0000 Subject: [PATCH 08/73] Add struct Service implementation --- .../generators/ServerServiceGeneratorV2.kt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index c9459e3934..54574dd036 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -8,6 +8,7 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.traits.DocumentationTrait +import software.amazon.smithy.rust.codegen.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.asType @@ -36,8 +37,10 @@ class ServerServiceGeneratorV2( ) { private val codegenScope = arrayOf( + "Http" to CargoDependency.Http.asType(), "SmithyHttpServer" to ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType(), + "Tower" to ServerCargoDependency.Tower.asType(), ) private val serviceId = service.id @@ -200,6 +203,30 @@ class ServerServiceGeneratorV2( ) } + private fun structServiceImpl(): Writable = writable { + rustTemplate( + """ + impl #{Tower}::Service<#{Http}::Request> for ${shapeToStructName(serviceId)} + where + S: #{Tower}::Service, Response = http::Response<#{SmithyHttpServer}::body::BoxBody>> + Clone, + { + type Response = #{Http}::Response<#{SmithyHttpServer}::body::BoxBody>; + type Error = S::Error; + type Future = #{SmithyHttpServer}::routing::routers::RoutingFuture; + + fn poll_ready(&mut self, cx: &mut std::task::Context) -> std::task::Poll> { + self.router.poll_ready(cx) + } + + fn call(&mut self, request: #{Http}::Request) -> Self::Future { + self.router.call(request) + } + } + """, + *codegenScope, + ) + } + fun render(writer: RustWriter) { writer.rustTemplate( """ @@ -210,11 +237,14 @@ class ServerServiceGeneratorV2( #{Struct:W} #{StructImpl:W} + + #{StructServiceImpl:W} """, "Builder" to builderDef(), "BuilderImpl" to builderImpl(), "Struct" to structDef(), "StructImpl" to structImpl(), + "StructServiceImpl" to structServiceImpl(), ) } } From 9397cc0d606f1be2fed8bd96827953f5d9b6f93a Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Thu, 1 Sep 2022 10:35:07 +0000 Subject: [PATCH 09/73] Fix lints --- .../server/smithy/generators/ServerServiceGenerator.kt | 4 ++-- .../server/smithy/generators/ServerServiceGeneratorV2.kt | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt index 24650ead88..876c81a411 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt @@ -68,7 +68,7 @@ open class ServerServiceGenerator( renderOperationRegistry(writer, operations) } - // TODO: Remove, this is temporary. + // TODO(Temporary): Remove, this is temporary. rustCrate.withModule( RustModule.public("operations", "TODO"), ) { writer -> @@ -77,7 +77,7 @@ open class ServerServiceGenerator( } } - // TODO: Remove, this is temporary. + // TODO(Temporary): Remove, this is temporary. rustCrate.withModule( RustModule.public("services", "TODO"), ) { writer -> diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 54574dd036..2483b78774 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -121,12 +121,8 @@ class ServerServiceGeneratorV2( /// /// This should be an [`Operation`](#{SmithyHttpServer}::operation::Operation) created from [`$structName`](crate::operations::$structName) /// using either [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationExt::from_handler) or - /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationExt::from_handler). - pub fn $fieldName(self, value: NewOp) -> ${builderName()}<${ - replacedGenerics.joinToString( - ",", - ) - }> { + /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationExt::from_service). + pub fn $fieldName(self, value: NewOp) -> ${builderName()}<${replacedGenerics.joinToString(",")}> { ${builderName()} { #{SwitchedFields:W} } From 8a67560926d0afd9bb599d0596a2c7a4a27ee29c Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Thu, 1 Sep 2022 23:32:18 +0000 Subject: [PATCH 10/73] Add Upgradable --- .../src/operation/mod.rs | 68 ++++++++++++++----- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/rust-runtime/aws-smithy-http-server/src/operation/mod.rs b/rust-runtime/aws-smithy-http-server/src/operation/mod.rs index 70199714c2..1e37e55743 100644 --- a/rust-runtime/aws-smithy-http-server/src/operation/mod.rs +++ b/rust-runtime/aws-smithy-http-server/src/operation/mod.rs @@ -183,7 +183,7 @@ mod upgrade; use tower::{ layer::util::{Identity, Stack}, - Layer, + Layer, Service, }; pub use handler::*; @@ -191,6 +191,12 @@ pub use operation_service::*; pub use shape::*; pub use upgrade::*; +use crate::{ + body::BoxBody, + request::{FromParts, FromRequest}, + response::IntoResponse, +}; + /// A Smithy operation, represented by a [`Service`](tower::Service) `S` and a [`Layer`] `L`. /// /// The `L` is held and applied lazily during [`Operation::upgrade`]. @@ -199,8 +205,6 @@ pub struct Operation { layer: L, } -type StackedUpgradeService = , L> as Layer>::Service; - impl Operation { /// Applies a [`Layer`] to the operation _after_ it has been upgraded via [`Operation::upgrade`]. pub fn layer(self, layer: NewL) -> Operation> { @@ -209,20 +213,6 @@ impl Operation { layer: Stack::new(self.layer, layer), } } - - /// Takes the [`Operation`], containing the inner [`Service`](tower::Service) `S`, the HTTP [`Layer`] `L` and - /// composes them together using [`UpgradeLayer`] for a specific protocol and [`OperationShape`]. - /// - /// The composition is made explicit in the method constraints and return type. - pub fn upgrade(self) -> StackedUpgradeService - where - UpgradeLayer: Layer, - L: Layer< as Layer>::Service>, - { - let Self { inner, layer } = self; - let layer = Stack::new(UpgradeLayer::new(), layer); - layer.layer(inner) - } } impl Operation> { @@ -264,3 +254,47 @@ pub enum OperationError { /// A [`Service::poll_ready`](tower::Service::poll_ready) failure occurred. PollReady(PollError), } + +/// Provides an interface to convert a representation of an operation to a HTTP [`Service`](tower::Service) with +/// canonical associated types. +pub trait Upgradable { + type Service: Service, Response = http::Response>; + + /// Performs an upgrade from a representation of an operation to a HTTP [`Service`](tower::Service). + fn upgrade(self) -> Self::Service; +} + +impl Upgradable for Operation +where + // `Op` is used to specify the operation shape + Op: OperationShape, + + // Smithy input must convert from a HTTP request + Op::Input: FromRequest, + // Smithy output must convert into a HTTP response + Op::Output: IntoResponse

, + // Smithy error must convert into a HTTP response + Op::Error: IntoResponse

, + + // Must be able to convert extensions + Exts: FromParts

, + + // The signature of the inner service is correct + S: Service<(Op::Input, Exts), Response = Op::Output, Error = OperationError> + Clone, + + // `L` can be applied to `Upgrade` + L: Layer>, + L::Service: Service, Response = http::Response>, +{ + type Service = L::Service; + + /// Takes the [`Operation`], containing the inner [`Service`](tower::Service) `S`, the HTTP [`Layer`] `L` and + /// composes them together using [`UpgradeLayer`] for a specific protocol and [`OperationShape`]. + /// + /// The composition is made explicit in the method constraints and return type. + fn upgrade(self) -> Self::Service { + let Self { inner, layer } = self; + let layer = Stack::new(UpgradeLayer::new(), layer); + layer.layer(inner) + } +} From cc7f6fe0a7b9bf6dabe152b5c966dc26a6424ac0 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Thu, 1 Sep 2022 23:33:07 +0000 Subject: [PATCH 11/73] Make Route::new public --- rust-runtime/aws-smithy-http-server/src/routing/route.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-http-server/src/routing/route.rs b/rust-runtime/aws-smithy-http-server/src/routing/route.rs index 29862c1a6c..8964c9629f 100644 --- a/rust-runtime/aws-smithy-http-server/src/routing/route.rs +++ b/rust-runtime/aws-smithy-http-server/src/routing/route.rs @@ -52,7 +52,7 @@ pub struct Route { } impl Route { - pub(super) fn new(svc: T) -> Self + pub fn new(svc: T) -> Self where T: Service, Response = Response, Error = Infallible> + Clone + Send + 'static, T::Future: Send + 'static, From b90d73ad4c3002ced34cead5e9829425b6fc406b Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Thu, 1 Sep 2022 23:35:16 +0000 Subject: [PATCH 12/73] Add code generated build method --- .../generators/ServerOperationGenerator.kt | 20 +-- .../generators/ServerServiceGenerator.kt | 4 +- .../generators/ServerServiceGeneratorV2.kt | 130 +++++++++++------- .../generators/protocol/ServerProtocol.kt | 98 ++++++++++++- 4 files changed, 182 insertions(+), 70 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt index 9f7d7fb710..a2cd307f2b 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt @@ -6,7 +6,6 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.Writable @@ -17,11 +16,6 @@ import software.amazon.smithy.rust.codegen.rustlang.writable import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency import software.amazon.smithy.rust.codegen.smithy.CoreCodegenContext import software.amazon.smithy.rust.codegen.util.getTrait -import software.amazon.smithy.rust.codegen.util.toPascalCase - -private fun shapeToStructName(shapeId: ShapeId): String { - return shapeId.name.toPascalCase() -} class ServerOperationGenerator( coreCodegenContext: CoreCodegenContext, @@ -33,7 +27,9 @@ class ServerOperationGenerator( "SmithyHttpServer" to ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType(), ) + private val symbolProvider = coreCodegenContext.symbolProvider + private val operationName = symbolProvider.toSymbol(operation).name private val operationId = operation.id private fun renderStructDef(): Writable = writable { @@ -44,27 +40,25 @@ class ServerOperationGenerator( } } - rust("pub struct ${shapeToStructName(operationId)};") + rust("pub struct $operationName;") } private fun operationError(): Writable = writable { if (operation.errors.isEmpty()) { rust("std::convert::Infallible") } else { - val operationStructName = shapeToStructName(operationId) - rust("crate::error::${operationStructName}Error") + rust("crate::error::${operationName}Error") } } private fun renderImpl(): Writable = writable { - val operationStructName = shapeToStructName(operationId) rustTemplate( """ - impl #{SmithyHttpServer}::operation::OperationShape for $operationStructName { + impl #{SmithyHttpServer}::operation::OperationShape for $operationName { const NAME: &'static str = "${operationId.toString().replace("#", "##")}"; - type Input = crate::input::${operationStructName}Input; - type Output = crate::output::${operationStructName}Output; + type Input = crate::input::${operationName}Input; + type Output = crate::output::${operationName}Output; type Error = #{Error:W}; } """, diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt index 876c81a411..6e9852a063 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt @@ -81,9 +81,9 @@ open class ServerServiceGenerator( rustCrate.withModule( RustModule.public("services", "TODO"), ) { writer -> - val serverProtocol = ServerProtocol.fromCoreProtocol(coreCodegenContext.runtimeConfig, protocol) + val serverProtocol = ServerProtocol.fromCoreProtocol(coreCodegenContext, protocol) ServerServiceGeneratorV2( - coreCodegenContext.runtimeConfig, + coreCodegenContext, coreCodegenContext.serviceShape, serverProtocol, ).render(writer) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 2483b78774..25f3dc8220 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -5,10 +5,11 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators +import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.shapes.ServiceShape -import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.rustlang.CargoDependency +import software.amazon.smithy.rust.codegen.rustlang.RustReservedWords import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.asType @@ -17,59 +18,48 @@ import software.amazon.smithy.rust.codegen.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.rustlang.writable import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocol -import software.amazon.smithy.rust.codegen.smithy.RuntimeConfig +import software.amazon.smithy.rust.codegen.smithy.CoreCodegenContext import software.amazon.smithy.rust.codegen.util.getTrait -import software.amazon.smithy.rust.codegen.util.toPascalCase +import software.amazon.smithy.rust.codegen.util.orNull import software.amazon.smithy.rust.codegen.util.toSnakeCase -private fun shapeToStructName(shapeId: ShapeId): String { - return shapeId.name.toPascalCase() -} - -private fun shapeToFieldName(shapeId: ShapeId): String { - return shapeId.name.toSnakeCase() -} - class ServerServiceGeneratorV2( - runtimeConfig: RuntimeConfig, + coreCodegenContext: CoreCodegenContext, private val service: ServiceShape, private val protocol: ServerProtocol, ) { + private val runtimeConfig = coreCodegenContext.runtimeConfig private val codegenScope = arrayOf( "Http" to CargoDependency.Http.asType(), "SmithyHttpServer" to ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType(), - "Tower" to ServerCargoDependency.Tower.asType(), + "Tower" to CargoDependency.Tower.asType(), ) + private val model = coreCodegenContext.model + private val symbolProvider = coreCodegenContext.symbolProvider - private val serviceId = service.id + private val serviceName = service.id.name + private val builderName = "${serviceName}Builder" - private fun builderName(): String { - return "${shapeToStructName(serviceId)}Builder" - } + private val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } - private fun builderGenerics(): Sequence { - return sequence { - for (index in 1..service.operations.size) { - yield("Op$index") - } + private fun builderGenerics(): Sequence = sequence { + for (index in 1..service.operations.size) { + yield("Op$index") } } - private fun builderFieldNames(): Sequence { - return sequence { - for (operation in service.operations) { - yield(shapeToFieldName(operation)) - } + private fun builderFieldNames(): Sequence = sequence { + for (operation in operationShapes) { + val field = RustReservedWords.escapeIfNeeded(symbolProvider.toSymbol(operation).name.toSnakeCase()) + yield(field) } } - private fun operationStructNames(): Sequence { - return sequence { - for (operation in service.operations) { - yield(shapeToStructName(operation)) - } + private fun operationStructNames(): Sequence = sequence { + for (operation in operationShapes) { + yield(symbolProvider.toSymbol(operation).name) } } @@ -83,10 +73,10 @@ class ServerServiceGeneratorV2( private fun builderDef(): Writable = writable { rustTemplate( """ - /// The service builder for [`${shapeToStructName(serviceId)}`]. + /// The service builder for [`$serviceName`]. /// - /// Constructed via [`${shapeToStructName(serviceId)}::builder`]. - pub struct ${builderName()}<${builderGenerics().joinToString(",")}> { + /// Constructed via [`$serviceName::builder`]. + pub struct $builderName<${builderGenerics().joinToString(",")}> { #{Fields:W} } """, @@ -117,13 +107,14 @@ class ServerServiceGeneratorV2( rustTemplate( """ - /// Sets the `$structName` operation. + /// Sets the [`$structName`](crate::operations::$structName) operation. /// - /// This should be an [`Operation`](#{SmithyHttpServer}::operation::Operation) created from [`$structName`](crate::operations::$structName) - /// using either [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationExt::from_handler) or + /// This should be an [`Operation`](#{SmithyHttpServer}::operation::Operation) created from + /// [`$structName`](crate::operations::$structName) using either + /// [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationExt::from_handler) or /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationExt::from_service). - pub fn $fieldName(self, value: NewOp) -> ${builderName()}<${replacedGenerics.joinToString(",")}> { - ${builderName()} { + pub fn $fieldName(self, value: NewOp) -> $builderName<${replacedGenerics.joinToString(",")}> { + $builderName { #{SwitchedFields:W} } } @@ -137,15 +128,56 @@ class ServerServiceGeneratorV2( } } + private fun extensionTypes(): Sequence = sequence { + for (index in 1..service.operations.size) { + yield("Exts$index") + } + } + + private fun buildConstraints(): Writable = writable { + for (tuple in operationShapes.asSequence().zip(builderGenerics()).zip(extensionTypes())) { + val (first, exts) = tuple + val (operation, type) = first + // TODO(Relax): The `Error = Infallible` is an excess requirement to stay at parity with existing builder. + rustTemplate( + """ + $type: #{SmithyHttpServer}::operation::Upgradable<#{Marker}, crate::operations::${symbolProvider.toSymbol(operation).name}, $exts, B>, + $type::Service: Clone + Send + 'static, + <$type::Service as #{Tower}::Service<#{Http}::Request>>::Future: Send + 'static, + + $type::Service: #{Tower}::Service<#{Http}::Request, Error = std::convert::Infallible>, + """, + "Marker" to protocol.markerStruct(), *codegenScope, + + ) + } + } + private fun builderImpl(): Writable = writable { val generics = builderGenerics().joinToString(",") + val router = protocol.routerConstruction(service, builderFieldNames().map { "self.$it.upgrade()" }.asIterable(), model) rustTemplate( """ - impl<$generics> ${builderName()}<$generics> { + impl<$generics> $builderName<$generics> { #{Setters:W} } + + impl<$generics> $builderName<$generics> { + pub fn build(self) -> $serviceName<#{SmithyHttpServer}::routing::Route> + where + #{BuildConstraints:W} + { + let router = #{Router:W}; + $serviceName { + router: #{SmithyHttpServer}::routing::routers::RoutingService::new(router), + } + } + } """, "Setters" to builderSetters(), + "BuildConstraints" to buildConstraints(), + "Router" to router, + *codegenScope, ) } @@ -158,7 +190,7 @@ class ServerServiceGeneratorV2( } rustTemplate( """ - pub struct ${shapeToStructName(serviceId)} { + pub struct $serviceName { router: #{SmithyHttpServer}::routing::routers::RoutingService<#{Router}, #{Protocol}>, } """, @@ -175,9 +207,9 @@ class ServerServiceGeneratorV2( } private fun notSetFields(): Writable = writable { - for (operation in service.operations) { + for (fieldName in builderFieldNames()) { rustTemplate( - "${shapeToFieldName(operation)}: #{SmithyHttpServer}::operation::OperationNotSet,", + "$fieldName: #{SmithyHttpServer}::operation::OperationNotSet,", *codegenScope, ) } @@ -186,10 +218,10 @@ class ServerServiceGeneratorV2( private fun structImpl(): Writable = writable { rustTemplate( """ - impl ${shapeToStructName(serviceId)}<()> { - /// Constructs a builder for [`${shapeToStructName(serviceId)}`]. - pub fn builder() -> ${builderName()}<#{NotSetGenerics:W}> { - ${builderName()} { + impl $serviceName<()> { + /// Constructs a builder for [`$serviceName`]. + pub fn builder() -> $builderName<#{NotSetGenerics:W}> { + $builderName { #{NotSetFields:W} } } @@ -202,7 +234,7 @@ class ServerServiceGeneratorV2( private fun structServiceImpl(): Writable = writable { rustTemplate( """ - impl #{Tower}::Service<#{Http}::Request> for ${shapeToStructName(serviceId)} + impl #{Tower}::Service<#{Http}::Request> for $serviceName where S: #{Tower}::Service, Response = http::Response<#{SmithyHttpServer}::body::BoxBody>> + Clone, { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 4caac28b20..7acfcb3817 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -5,13 +5,22 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators.protocol +import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.OperationShape +import software.amazon.smithy.model.shapes.ServiceShape +import software.amazon.smithy.rust.codegen.rustlang.Writable +import software.amazon.smithy.rust.codegen.rustlang.asType +import software.amazon.smithy.rust.codegen.rustlang.rustTemplate +import software.amazon.smithy.rust.codegen.rustlang.writable import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency -import software.amazon.smithy.rust.codegen.smithy.RuntimeConfig +import software.amazon.smithy.rust.codegen.smithy.CoreCodegenContext import software.amazon.smithy.rust.codegen.smithy.RuntimeType import software.amazon.smithy.rust.codegen.smithy.protocols.AwsJson import software.amazon.smithy.rust.codegen.smithy.protocols.AwsJsonVersion import software.amazon.smithy.rust.codegen.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.smithy.protocols.RestJson +import software.amazon.smithy.rust.codegen.util.dq +import software.amazon.smithy.rust.codegen.util.orNull interface ServerProtocol { fun coreProtocol(): Protocol @@ -20,11 +29,14 @@ interface ServerProtocol { fun routerType(): RuntimeType + // TODO(Decouple): Perhaps this should lean on a Rust interface. + fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable + companion object { - fun fromCoreProtocol(runtimeConfig: RuntimeConfig, protocol: Protocol): ServerProtocol { + fun fromCoreProtocol(coreCodegenContext: CoreCodegenContext, protocol: Protocol): ServerProtocol { val serverProtocol = when (protocol) { - is AwsJson -> AwsJsonServerProtocol(runtimeConfig, protocol) - is RestJson -> RestJsonServerProtocol(runtimeConfig, protocol) + is AwsJson -> AwsJsonServerProtocol(coreCodegenContext, protocol) + is RestJson -> RestJsonServerProtocol(coreCodegenContext, protocol) else -> throw IllegalStateException("unsupported protocol") } return serverProtocol @@ -33,9 +45,15 @@ interface ServerProtocol { } class AwsJsonServerProtocol( - private val runtimeConfig: RuntimeConfig, + coreCodegenContext: CoreCodegenContext, private val coreProtocol: AwsJson, ) : ServerProtocol { + private val runtimeConfig = coreCodegenContext.runtimeConfig + private val codegenScope = arrayOf( + "SmithyHttpServer" to ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType(), + ) + private val symbolProvider = coreCodegenContext.symbolProvider + override fun coreProtocol(): Protocol { return coreProtocol } @@ -56,12 +74,46 @@ class AwsJsonServerProtocol( override fun routerType(): RuntimeType { return RuntimeType("AwsJsonRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::routers::aws_json") } + + override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = writable { + val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } + // TODO(restore): This causes a panic: "symbol visitor should not be invoked in service shapes" + // val serviceName = symbolProvider.toSymbol(service).name + val serviceName = service.id.name + val pairs = writable { + for ((operation, operationValue) in operationShapes.zip(operationValues)) { + val operationName = symbolProvider.toSymbol(operation).name + val key = "String::from($serviceName.$operationName)".dq() + rustTemplate( + """ + ( + String::from($key), + #{SmithyHttpServer}::routing::Route::from_box_clone_service($operationValue) + ) + """, + *codegenScope, + ) + } + } + rustTemplate( + """ + #{Router}::from_iter(#{Pairs:W}) + """, + "Router" to routerType(), "Pairs" to pairs, + ) + } } class RestJsonServerProtocol( - private val runtimeConfig: RuntimeConfig, + coreCodegenContext: CoreCodegenContext, private val coreProtocol: RestJson, ) : ServerProtocol { + private val runtimeConfig = coreCodegenContext.runtimeConfig + private val codegenScope = arrayOf( + "SmithyHttpServer" to ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType(), + ) + private val symbolProvider = coreCodegenContext.symbolProvider + override fun coreProtocol(): Protocol { return coreProtocol } @@ -73,4 +125,38 @@ class RestJsonServerProtocol( override fun routerType(): RuntimeType { return RuntimeType("RestRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::routers::rest") } + + override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = writable { + val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } + // TODO(restore): This causes a panic: "symbol visitor should not be invoked in service shapes" + // val serviceName = symbolProvider.toSymbol(service).name + val serviceName = service.id.name + val pairs = writable { + for ((operationShape, operationValue) in operationShapes.zip(operationValues)) { + val operationName = symbolProvider.toSymbol(operationShape).name + val key = coreProtocol.serverRouterRequestSpec( + operationShape, + operationName, + serviceName, + ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType().member("routing::request_spec"), + ) + rustTemplate( + """ + ( + #{Key:W}, + #{SmithyHttpServer}::routing::Route::new($operationValue) + ), + """, + "Key" to key, + *codegenScope, + ) + } + } + rustTemplate( + """ + #{Router}::from_iter([#{Pairs:W}]) + """, + "Router" to routerType(), "Pairs" to pairs, + ) + } } From a3dc74aa4b53664a7ecaeb393c67b8a5d609b047 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Thu, 1 Sep 2022 23:58:12 +0000 Subject: [PATCH 13/73] Fix lints --- .../server/smithy/generators/ServerServiceGenerator.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt index 6e9852a063..7b23f010f7 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt @@ -70,7 +70,7 @@ open class ServerServiceGenerator( // TODO(Temporary): Remove, this is temporary. rustCrate.withModule( - RustModule.public("operations", "TODO"), + RustModule.public("operations", ""), ) { writer -> for (operation in operations) { ServerOperationGenerator(coreCodegenContext, operation).render(writer) @@ -79,7 +79,7 @@ open class ServerServiceGenerator( // TODO(Temporary): Remove, this is temporary. rustCrate.withModule( - RustModule.public("services", "TODO"), + RustModule.public("services", ""), ) { writer -> val serverProtocol = ServerProtocol.fromCoreProtocol(coreCodegenContext, protocol) ServerServiceGeneratorV2( From 12bb2f47447aeae21c83fdb336ab5b3b287c2846 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 2 Sep 2022 10:02:27 +0000 Subject: [PATCH 14/73] Add RestXmlServerProtocol --- .../generators/protocol/ServerProtocol.kt | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 7acfcb3817..9ad13049e9 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -19,6 +19,8 @@ import software.amazon.smithy.rust.codegen.smithy.protocols.AwsJson import software.amazon.smithy.rust.codegen.smithy.protocols.AwsJsonVersion import software.amazon.smithy.rust.codegen.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.smithy.protocols.RestJson +import software.amazon.smithy.rust.codegen.smithy.protocols.RestXml +import software.amazon.smithy.rust.codegen.util.PANIC import software.amazon.smithy.rust.codegen.util.dq import software.amazon.smithy.rust.codegen.util.orNull @@ -37,6 +39,7 @@ interface ServerProtocol { val serverProtocol = when (protocol) { is AwsJson -> AwsJsonServerProtocol(coreCodegenContext, protocol) is RestJson -> RestJsonServerProtocol(coreCodegenContext, protocol) + is RestXml -> RestXmlServerProtocol(coreCodegenContext, protocol) else -> throw IllegalStateException("unsupported protocol") } return serverProtocol @@ -88,8 +91,8 @@ class AwsJsonServerProtocol( """ ( String::from($key), - #{SmithyHttpServer}::routing::Route::from_box_clone_service($operationValue) - ) + #{SmithyHttpServer}::routing::Route::new($operationValue) + ), """, *codegenScope, ) @@ -97,18 +100,18 @@ class AwsJsonServerProtocol( } rustTemplate( """ - #{Router}::from_iter(#{Pairs:W}) + #{Router}::from_iter([#{Pairs:W}]) """, "Router" to routerType(), "Pairs" to pairs, ) } } -class RestJsonServerProtocol( +open class RestProtocol( coreCodegenContext: CoreCodegenContext, - private val coreProtocol: RestJson, + private val coreProtocol: Protocol, ) : ServerProtocol { - private val runtimeConfig = coreCodegenContext.runtimeConfig + val runtimeConfig = coreCodegenContext.runtimeConfig private val codegenScope = arrayOf( "SmithyHttpServer" to ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType(), ) @@ -119,7 +122,7 @@ class RestJsonServerProtocol( } override fun markerStruct(): RuntimeType { - return RuntimeType("AwsRestJson1", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") + PANIC("marker structure needs to specified") } override fun routerType(): RuntimeType { @@ -160,3 +163,21 @@ class RestJsonServerProtocol( ) } } + +class RestJsonServerProtocol( + coreCodegenContext: CoreCodegenContext, + coreProtocol: RestJson, +) : RestProtocol(coreCodegenContext, coreProtocol) { + override fun markerStruct(): RuntimeType { + return RuntimeType("AwsRestJson1", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") + } +} + +class RestXmlServerProtocol( + coreCodegenContext: CoreCodegenContext, + coreProtocol: RestXml, +) : RestProtocol(coreCodegenContext, coreProtocol) { + override fun markerStruct(): RuntimeType { + return RuntimeType("AwsRestXml", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") + } +} From 57afed9d2319fe3f60c6874e18b74c75f2b75405 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 2 Sep 2022 10:03:25 +0000 Subject: [PATCH 15/73] Fix documentation lints and name cases --- .../generators/ServerOperationGenerator.kt | 12 ++++++------ .../generators/ServerServiceGeneratorV2.kt | 19 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt index a2cd307f2b..f00ae9e9bc 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt @@ -10,12 +10,14 @@ import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.asType +import software.amazon.smithy.rust.codegen.rustlang.docs import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.rustlang.writable import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency import software.amazon.smithy.rust.codegen.smithy.CoreCodegenContext import software.amazon.smithy.rust.codegen.util.getTrait +import software.amazon.smithy.rust.codegen.util.toPascalCase class ServerOperationGenerator( coreCodegenContext: CoreCodegenContext, @@ -29,15 +31,13 @@ class ServerOperationGenerator( ) private val symbolProvider = coreCodegenContext.symbolProvider - private val operationName = symbolProvider.toSymbol(operation).name + private val operationName = symbolProvider.toSymbol(operation).name.toPascalCase() private val operationId = operation.id private fun renderStructDef(): Writable = writable { - val documentationLines = operation.getTrait()?.value?.lines() - if (documentationLines != null) { - for (documentation in documentationLines) { - rust("/// $documentation") - } + val documentation = operation.getTrait()?.value + if (documentation != null) { + docs(documentation.replace("#", "##")) } rust("pub struct $operationName;") diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 25f3dc8220..197298f042 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -13,6 +13,7 @@ import software.amazon.smithy.rust.codegen.rustlang.RustReservedWords import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.asType +import software.amazon.smithy.rust.codegen.rustlang.docs import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.rustlang.writable @@ -21,6 +22,7 @@ import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.Ser import software.amazon.smithy.rust.codegen.smithy.CoreCodegenContext import software.amazon.smithy.rust.codegen.util.getTrait import software.amazon.smithy.rust.codegen.util.orNull +import software.amazon.smithy.rust.codegen.util.toPascalCase import software.amazon.smithy.rust.codegen.util.toSnakeCase class ServerServiceGeneratorV2( @@ -59,7 +61,7 @@ class ServerServiceGeneratorV2( private fun operationStructNames(): Sequence = sequence { for (operation in operationShapes) { - yield(symbolProvider.toSymbol(operation).name) + yield(symbolProvider.toSymbol(operation).name.toPascalCase()) } } @@ -111,8 +113,8 @@ class ServerServiceGeneratorV2( /// /// This should be an [`Operation`](#{SmithyHttpServer}::operation::Operation) created from /// [`$structName`](crate::operations::$structName) using either - /// [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationExt::from_handler) or - /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationExt::from_service). + /// [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationShapeExt::from_handler) or + /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationShapeExt::from_service). pub fn $fieldName(self, value: NewOp) -> $builderName<${replacedGenerics.joinToString(",")}> { $builderName { #{SwitchedFields:W} @@ -141,7 +143,7 @@ class ServerServiceGeneratorV2( // TODO(Relax): The `Error = Infallible` is an excess requirement to stay at parity with existing builder. rustTemplate( """ - $type: #{SmithyHttpServer}::operation::Upgradable<#{Marker}, crate::operations::${symbolProvider.toSymbol(operation).name}, $exts, B>, + $type: #{SmithyHttpServer}::operation::Upgradable<#{Marker}, crate::operations::${symbolProvider.toSymbol(operation).name.toPascalCase()}, $exts, B>, $type::Service: Clone + Send + 'static, <$type::Service as #{Tower}::Service<#{Http}::Request>>::Future: Send + 'static, @@ -182,12 +184,11 @@ class ServerServiceGeneratorV2( } private fun structDef(): Writable = writable { - val documentationLines = service.getTrait()?.value?.lines() - if (documentationLines != null) { - for (documentation in documentationLines) { - rust("/// $documentation") - } + val documentation = service.getTrait()?.value + if (documentation != null) { + docs(documentation.replace("#", "##")) } + rustTemplate( """ pub struct $serviceName { From ba1125744dd5ad947af6db04b984f51d598ca562 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 2 Sep 2022 10:43:51 +0000 Subject: [PATCH 16/73] Fix ServerProtocol naming --- .../smithy/generators/protocol/ServerProtocol.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 9ad13049e9..2c73ee9066 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -37,9 +37,9 @@ interface ServerProtocol { companion object { fun fromCoreProtocol(coreCodegenContext: CoreCodegenContext, protocol: Protocol): ServerProtocol { val serverProtocol = when (protocol) { - is AwsJson -> AwsJsonServerProtocol(coreCodegenContext, protocol) - is RestJson -> RestJsonServerProtocol(coreCodegenContext, protocol) - is RestXml -> RestXmlServerProtocol(coreCodegenContext, protocol) + is AwsJson -> ServerAwsJsonProtocol(coreCodegenContext, protocol) + is RestJson -> ServerRestJsonProtocol(coreCodegenContext, protocol) + is RestXml -> ServerRestXmlProtocol(coreCodegenContext, protocol) else -> throw IllegalStateException("unsupported protocol") } return serverProtocol @@ -47,7 +47,7 @@ interface ServerProtocol { } } -class AwsJsonServerProtocol( +class ServerAwsJsonProtocol( coreCodegenContext: CoreCodegenContext, private val coreProtocol: AwsJson, ) : ServerProtocol { @@ -164,7 +164,7 @@ open class RestProtocol( } } -class RestJsonServerProtocol( +class ServerRestJsonProtocol( coreCodegenContext: CoreCodegenContext, coreProtocol: RestJson, ) : RestProtocol(coreCodegenContext, coreProtocol) { @@ -173,7 +173,7 @@ class RestJsonServerProtocol( } } -class RestXmlServerProtocol( +class ServerRestXmlProtocol( coreCodegenContext: CoreCodegenContext, coreProtocol: RestXml, ) : RestProtocol(coreCodegenContext, coreProtocol) { From 7814d18db2c0e20272ccc04d4f74af1341e87c89 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 2 Sep 2022 13:19:33 +0000 Subject: [PATCH 17/73] Include all service operations --- .../generators/ServerServiceGeneratorV2.kt | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 197298f042..2e7de1a1a6 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -6,6 +6,7 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.model.shapes.OperationShape +import software.amazon.smithy.model.shapes.ResourceShape import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.rustlang.CargoDependency @@ -44,23 +45,31 @@ class ServerServiceGeneratorV2( private val serviceName = service.id.name private val builderName = "${serviceName}Builder" + private val resourceOperationShapes = service + .resources + .mapNotNull { model.getShape(it).orNull() } + .mapNotNull { it as? ResourceShape } + .flatMap { it.allOperations } + .mapNotNull { model.getShape(it).orNull() } + .mapNotNull { it as? OperationShape } private val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } + private val allOperationShapes = resourceOperationShapes + operationShapes private fun builderGenerics(): Sequence = sequence { - for (index in 1..service.operations.size) { + for (index in 1..allOperationShapes.size) { yield("Op$index") } } private fun builderFieldNames(): Sequence = sequence { - for (operation in operationShapes) { + for (operation in allOperationShapes) { val field = RustReservedWords.escapeIfNeeded(symbolProvider.toSymbol(operation).name.toSnakeCase()) yield(field) } } private fun operationStructNames(): Sequence = sequence { - for (operation in operationShapes) { + for (operation in allOperationShapes) { yield(symbolProvider.toSymbol(operation).name.toPascalCase()) } } @@ -131,13 +140,13 @@ class ServerServiceGeneratorV2( } private fun extensionTypes(): Sequence = sequence { - for (index in 1..service.operations.size) { + for (index in 1..allOperationShapes.size) { yield("Exts$index") } } private fun buildConstraints(): Writable = writable { - for (tuple in operationShapes.asSequence().zip(builderGenerics()).zip(extensionTypes())) { + for (tuple in allOperationShapes.asSequence().zip(builderGenerics()).zip(extensionTypes())) { val (first, exts) = tuple val (operation, type) = first // TODO(Relax): The `Error = Infallible` is an excess requirement to stay at parity with existing builder. @@ -202,7 +211,7 @@ class ServerServiceGeneratorV2( } private fun notSetGenerics(): Writable = writable { - for (index in 1..service.operations.size) { + for (index in 1..allOperationShapes.size) { rustTemplate("#{SmithyHttpServer}::operation::OperationNotSet,", *codegenScope) } } From 6966d3370f1f03eb9b867de20228556ae0d7250a Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 2 Sep 2022 18:33:55 +0000 Subject: [PATCH 18/73] Add BuildModifier mechanism --- .../generators/ServerServiceGeneratorV2.kt | 35 +++++++-- .../generators/protocol/ServerProtocol.kt | 9 +-- .../src/build_modifier.rs | 19 +++++ .../aws-smithy-http-server/src/lib.rs | 2 + .../src/operation/mod.rs | 72 +++++-------------- .../src/operation/upgrade.rs | 55 +++++++++++++- 6 files changed, 125 insertions(+), 67 deletions(-) create mode 100644 rust-runtime/aws-smithy-http-server/src/build_modifier.rs diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 2e7de1a1a6..7f83d2c130 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -87,11 +87,13 @@ class ServerServiceGeneratorV2( /// The service builder for [`$serviceName`]. /// /// Constructed via [`$serviceName::builder`]. - pub struct $builderName<${builderGenerics().joinToString(",")}> { + pub struct $builderName<${builderGenerics().joinToString(",")}, Modifier = #{SmithyHttpServer}::build_modifier::Identity> { #{Fields:W} + modifier: Modifier } """, "Fields" to builderFields(), + *codegenScope, ) } @@ -127,6 +129,7 @@ class ServerServiceGeneratorV2( pub fn $fieldName(self, value: NewOp) -> $builderName<${replacedGenerics.joinToString(",")}> { $builderName { #{SwitchedFields:W} + modifier: self.modifier } } """, @@ -152,28 +155,43 @@ class ServerServiceGeneratorV2( // TODO(Relax): The `Error = Infallible` is an excess requirement to stay at parity with existing builder. rustTemplate( """ - $type: #{SmithyHttpServer}::operation::Upgradable<#{Marker}, crate::operations::${symbolProvider.toSymbol(operation).name.toPascalCase()}, $exts, B>, + $type: #{SmithyHttpServer}::operation::Upgradable< + #{Marker}, + crate::operations::${symbolProvider.toSymbol(operation).name.toPascalCase()}, + $exts, + B, + Modifier + >, $type::Service: Clone + Send + 'static, <$type::Service as #{Tower}::Service<#{Http}::Request>>::Future: Send + 'static, $type::Service: #{Tower}::Service<#{Http}::Request, Error = std::convert::Infallible>, """, - "Marker" to protocol.markerStruct(), *codegenScope, - + "Marker" to protocol.markerStruct(), + *codegenScope, ) } } private fun builderImpl(): Writable = writable { val generics = builderGenerics().joinToString(",") - val router = protocol.routerConstruction(service, builderFieldNames().map { "self.$it.upgrade()" }.asIterable(), model) + val router = protocol + .routerConstruction( + service, + builderFieldNames() + .map { + writable { rustTemplate("self.$it.upgrade(&self.modifier)") } + } + .asIterable(), + model, + ) rustTemplate( """ impl<$generics> $builderName<$generics> { #{Setters:W} } - impl<$generics> $builderName<$generics> { + impl<$generics, Modifier> $builderName<$generics, Modifier> { pub fn build(self) -> $serviceName<#{SmithyHttpServer}::routing::Route> where #{BuildConstraints:W} @@ -233,11 +251,14 @@ class ServerServiceGeneratorV2( pub fn builder() -> $builderName<#{NotSetGenerics:W}> { $builderName { #{NotSetFields:W} + modifier: #{SmithyHttpServer}::build_modifier::Identity } } } """, - "NotSetGenerics" to notSetGenerics(), "NotSetFields" to notSetFields(), + "NotSetGenerics" to notSetGenerics(), + "NotSetFields" to notSetFields(), + *codegenScope, ) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 2c73ee9066..5d9e87b0d0 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -32,7 +32,7 @@ interface ServerProtocol { fun routerType(): RuntimeType // TODO(Decouple): Perhaps this should lean on a Rust interface. - fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable + fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable companion object { fun fromCoreProtocol(coreCodegenContext: CoreCodegenContext, protocol: Protocol): ServerProtocol { @@ -78,7 +78,7 @@ class ServerAwsJsonProtocol( return RuntimeType("AwsJsonRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::routers::aws_json") } - override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = writable { + override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = writable { val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } // TODO(restore): This causes a panic: "symbol visitor should not be invoked in service shapes" // val serviceName = symbolProvider.toSymbol(service).name @@ -129,7 +129,7 @@ open class RestProtocol( return RuntimeType("RestRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::routers::rest") } - override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = writable { + override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = writable { val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } // TODO(restore): This causes a panic: "symbol visitor should not be invoked in service shapes" // val serviceName = symbolProvider.toSymbol(service).name @@ -147,10 +147,11 @@ open class RestProtocol( """ ( #{Key:W}, - #{SmithyHttpServer}::routing::Route::new($operationValue) + #{SmithyHttpServer}::routing::Route::new(#{OperationValue:W}) ), """, "Key" to key, + "OperationValue" to operationValue, *codegenScope, ) } diff --git a/rust-runtime/aws-smithy-http-server/src/build_modifier.rs b/rust-runtime/aws-smithy-http-server/src/build_modifier.rs new file mode 100644 index 0000000000..a6339335d2 --- /dev/null +++ b/rust-runtime/aws-smithy-http-server/src/build_modifier.rs @@ -0,0 +1,19 @@ +use crate::operation::Operation; + +pub trait BuildModifier { + type Service; + type Layer; + + fn modify(&self, operation: Operation) -> Operation; +} + +pub struct Identity; + +impl BuildModifier for Identity { + type Service = S; + type Layer = L; + + fn modify(&self, operation: Operation) -> Operation { + operation + } +} diff --git a/rust-runtime/aws-smithy-http-server/src/lib.rs b/rust-runtime/aws-smithy-http-server/src/lib.rs index b032060bbc..a9e84ad25e 100644 --- a/rust-runtime/aws-smithy-http-server/src/lib.rs +++ b/rust-runtime/aws-smithy-http-server/src/lib.rs @@ -11,6 +11,8 @@ pub(crate) mod macros; pub mod body; +#[doc(hidden)] +pub mod build_modifier; pub(crate) mod error; pub mod extension; #[doc(hidden)] diff --git a/rust-runtime/aws-smithy-http-server/src/operation/mod.rs b/rust-runtime/aws-smithy-http-server/src/operation/mod.rs index 1e37e55743..23a0d4c9d8 100644 --- a/rust-runtime/aws-smithy-http-server/src/operation/mod.rs +++ b/rust-runtime/aws-smithy-http-server/src/operation/mod.rs @@ -181,22 +181,13 @@ mod operation_service; mod shape; mod upgrade; -use tower::{ - layer::util::{Identity, Stack}, - Layer, Service, -}; +use tower::layer::util::{Identity, Stack}; pub use handler::*; pub use operation_service::*; pub use shape::*; pub use upgrade::*; -use crate::{ - body::BoxBody, - request::{FromParts, FromRequest}, - response::IntoResponse, -}; - /// A Smithy operation, represented by a [`Service`](tower::Service) `S` and a [`Layer`] `L`. /// /// The `L` is held and applied lazily during [`Operation::upgrade`]. @@ -213,6 +204,23 @@ impl Operation { layer: Stack::new(self.layer, layer), } } + + // /// Takes the [`Operation`], containing the inner [`Service`](tower::Service) `S`, the HTTP [`Layer`] `L` and + // /// composes them together using [`UpgradeLayer`] for a specific protocol and [`OperationShape`]. + // /// + // /// Prior to upgrade [`Operation`] is also + // /// + // /// The composition is made explicit in the method constraints and return type. + // pub fn upgrade( + // self, + // modify: Modify, + // ) -> >>::Service + // where + // Modify: ModifyBuild, + // Layer> + // { + + // } } impl Operation> { @@ -254,47 +262,3 @@ pub enum OperationError { /// A [`Service::poll_ready`](tower::Service::poll_ready) failure occurred. PollReady(PollError), } - -/// Provides an interface to convert a representation of an operation to a HTTP [`Service`](tower::Service) with -/// canonical associated types. -pub trait Upgradable { - type Service: Service, Response = http::Response>; - - /// Performs an upgrade from a representation of an operation to a HTTP [`Service`](tower::Service). - fn upgrade(self) -> Self::Service; -} - -impl Upgradable for Operation -where - // `Op` is used to specify the operation shape - Op: OperationShape, - - // Smithy input must convert from a HTTP request - Op::Input: FromRequest, - // Smithy output must convert into a HTTP response - Op::Output: IntoResponse

, - // Smithy error must convert into a HTTP response - Op::Error: IntoResponse

, - - // Must be able to convert extensions - Exts: FromParts

, - - // The signature of the inner service is correct - S: Service<(Op::Input, Exts), Response = Op::Output, Error = OperationError> + Clone, - - // `L` can be applied to `Upgrade` - L: Layer>, - L::Service: Service, Response = http::Response>, -{ - type Service = L::Service; - - /// Takes the [`Operation`], containing the inner [`Service`](tower::Service) `S`, the HTTP [`Layer`] `L` and - /// composes them together using [`UpgradeLayer`] for a specific protocol and [`OperationShape`]. - /// - /// The composition is made explicit in the method constraints and return type. - fn upgrade(self) -> Self::Service { - let Self { inner, layer } = self; - let layer = Stack::new(UpgradeLayer::new(), layer); - layer.layer(inner) - } -} diff --git a/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs b/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs index 17dd7b29ae..dace4974a8 100644 --- a/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs +++ b/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs @@ -12,14 +12,16 @@ use std::{ use futures_util::ready; use pin_project_lite::pin_project; -use tower::{Layer, Service}; +use tower::{layer::util::Stack, Layer, Service}; use crate::{ + body::BoxBody, + build_modifier::BuildModifier, request::{FromParts, FromRequest}, response::IntoResponse, }; -use super::{OperationError, OperationShape}; +use super::{Operation, OperationError, OperationShape}; /// A [`Layer`] responsible for taking an operation [`Service`], accepting and returning Smithy /// types and converting it into a [`Service`] taking and returning [`http`] types. @@ -211,3 +213,52 @@ where } } } + +/// Provides an interface to convert a representation of an operation to a HTTP [`Service`](tower::Service) with +/// canonical associated types. +pub trait Upgradable { + type Service: Service, Response = http::Response>; + + /// Performs an upgrade from a representation of an operation to a HTTP [`Service`](tower::Service). + fn upgrade(self, modify: &Modify) -> Self::Service; +} + +impl Upgradable for Operation +where + // `Op` is used to specify the operation shape + Op: OperationShape, + + // Smithy input must convert from a HTTP request + Op::Input: FromRequest, + // Smithy output must convert into a HTTP response + Op::Output: IntoResponse

, + // Smithy error must convert into a HTTP response + Op::Error: IntoResponse

, + + // Must be able to convert extensions + Exts: FromParts

, + + // The signature of the inner service is correct + S: Service<(Op::Input, Exts), Response = Op::Output, Error = OperationError> + Clone, + + // Modifier applies correctly to `Operation` + Modify: BuildModifier, + Modify::Layer: Layer>, + + // The signature of the output is correct + >>::Service: + Service, Response = http::Response>, +{ + type Service = >>::Service; + + /// Takes the [`Operation`](Operation), applies [`ModifyBuild::modify`] to it, applies [`UpgradeLayer`] to + /// the modified `S`, then finally applies the modified `L`. + /// + /// The composition is made explicit in the method constraints and return type. + fn upgrade(self, modify: &Modify) -> Self::Service { + let Operation { inner, layer } = modify.modify(self); + + let layer = Stack::new(UpgradeLayer::new(), layer); + layer.layer(inner) + } +} From c1ab8f672e3713e5987226d748884a08eb49c693 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 2 Sep 2022 19:06:35 +0000 Subject: [PATCH 19/73] Fix Rust documentation --- .../examples/pokemon-service/src/main.rs | 18 ++++++++++++++++-- .../src/build_modifier.rs | 5 +++++ .../src/operation/mod.rs | 11 ++++++----- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs b/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs index 6d03d4cf2c..7b511dbfdd 100644 --- a/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs +++ b/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs @@ -8,13 +8,15 @@ use std::{net::SocketAddr, sync::Arc}; use aws_smithy_http_server::{AddExtensionLayer, Router}; use clap::Parser; +use tower::ServiceBuilder; +use tower_http::trace::TraceLayer; + use pokemon_service::{ capture_pokemon, empty_operation, get_pokemon_species, get_server_statistics, get_storage, health_check_operation, setup_tracing, State, }; use pokemon_service_server_sdk::operation_registry::OperationRegistryBuilder; -use tower::ServiceBuilder; -use tower_http::trace::TraceLayer; +use pokemon_service_server_sdk::services::PokemonService; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] @@ -31,6 +33,8 @@ struct Args { pub async fn main() { let args = Args::parse(); setup_tracing(); + + // Old builder let app: Router = OperationRegistryBuilder::default() // Build a registry containing implementations to all the operations in the service. These // are async functions or async closures that take as input the operation's input and @@ -47,6 +51,16 @@ pub async fn main() { // implementation. .into(); + // New builder + let _app = PokemonService::builder() + .get_pokemon_species(get_pokemon_species) + .get_storage(get_storage) + .get_server_statistics(get_server_statistics) + .capture_pokemon_operation(capture_pokemon) + .empty_operation(empty_operation) + .health_check_operation(health_check_operation) + .build(); + // Setup shared state and middlewares. let shared_state = Arc::new(State::default()); let app = app.layer( diff --git a/rust-runtime/aws-smithy-http-server/src/build_modifier.rs b/rust-runtime/aws-smithy-http-server/src/build_modifier.rs index a6339335d2..a280f92b73 100644 --- a/rust-runtime/aws-smithy-http-server/src/build_modifier.rs +++ b/rust-runtime/aws-smithy-http-server/src/build_modifier.rs @@ -1,3 +1,8 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + use crate::operation::Operation; pub trait BuildModifier { diff --git a/rust-runtime/aws-smithy-http-server/src/operation/mod.rs b/rust-runtime/aws-smithy-http-server/src/operation/mod.rs index 23a0d4c9d8..6e79d3eced 100644 --- a/rust-runtime/aws-smithy-http-server/src/operation/mod.rs +++ b/rust-runtime/aws-smithy-http-server/src/operation/mod.rs @@ -168,11 +168,12 @@ //! - The intention of `PollError` is to signal that the underlying service is no longer able to take requests, so //! should be discarded. See [`Service::poll_ready`](tower::Service::poll_ready). //! -//! The [`UpgradeLayer`] and it's [`Layer::Service`] [`Upgrade`] are both parameterized by a protocol. This allows -//! for upgrading to `Service` to be protocol dependent. +//! The [`UpgradeLayer`] and it's [`Layer::Service`](tower::Layer::Service) [`Upgrade`] are both parameterized by a +//! protocol. This allows for upgrading to `Service` to be +//! protocol dependent. //! -//! The [`Operation::upgrade`] will apply [`UpgradeLayer`] to `S` then apply the [`Layer`] `L`. The service builder -//! provided to the user will perform this composition on `build`. +//! The [`Operation::upgrade`] will apply [`UpgradeLayer`] to `S` then apply the [`Layer`](tower::Layer) `L`. The +//! service builder provided to the user will perform this composition on `build`. //! //! [Smithy operation]: https://awslabs.github.io/smithy/2.0/spec/service-types.html#operation @@ -188,7 +189,7 @@ pub use operation_service::*; pub use shape::*; pub use upgrade::*; -/// A Smithy operation, represented by a [`Service`](tower::Service) `S` and a [`Layer`] `L`. +/// A Smithy operation, represented by a [`Service`](tower::Service) `S` and a [`Layer`](tower::Layer) `L`. /// /// The `L` is held and applied lazily during [`Operation::upgrade`]. pub struct Operation { From efa06353353623be07c6f4119eec2b8f2417ee81 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 2 Sep 2022 22:04:45 +0000 Subject: [PATCH 20/73] Fix missing :W --- .../server/smithy/generators/protocol/ServerProtocol.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 5d9e87b0d0..e2b2545f66 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -86,14 +86,15 @@ class ServerAwsJsonProtocol( val pairs = writable { for ((operation, operationValue) in operationShapes.zip(operationValues)) { val operationName = symbolProvider.toSymbol(operation).name - val key = "String::from($serviceName.$operationName)".dq() + val key = "$serviceName.$operationName".dq() rustTemplate( """ ( String::from($key), - #{SmithyHttpServer}::routing::Route::new($operationValue) + #{SmithyHttpServer}::routing::Route::new(#{OperationValue:W}) ), """, + "OperationValue" to operationValue, *codegenScope, ) } From 39b9c0cef908543ebe42a54d8c69106c20426664 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Sat, 3 Sep 2022 12:37:41 +0000 Subject: [PATCH 21/73] Add convenience setter --- .../generators/ServerServiceGeneratorV2.kt | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 7f83d2c130..e06a10f44c 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -100,6 +100,22 @@ class ServerServiceGeneratorV2( private fun builderSetters(): Writable = writable { for ((index, pair) in builderFieldNames().zip(operationStructNames()).withIndex()) { val (fieldName, structName) = pair + val replacedGenericsService = writable { + for ((innerIndex, item) in builderGenerics().withIndex()) { + if (innerIndex == index) { + rustTemplate( + """ + #{SmithyHttpServer}::operation::Operation<#{SmithyHttpServer}::operation::IntoService> + """, + *codegenScope, + ) + } else { + rust("$item") + } + rust(", ") + } + } + val replacedGenerics = builderGenerics().withIndex().map { (innerIndex, item) -> if (innerIndex == index) { "NewOp" @@ -126,7 +142,21 @@ class ServerServiceGeneratorV2( /// [`$structName`](crate::operations::$structName) using either /// [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationShapeExt::from_handler) or /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationShapeExt::from_service). - pub fn $fieldName(self, value: NewOp) -> $builderName<${replacedGenerics.joinToString(",")}> { + pub fn $fieldName(self, value: H) -> $builderName<#{ReplacedGenericsService:W}> + where + H: #{SmithyHttpServer}::operation::Handler + { + use #{SmithyHttpServer}::operation::OperationShapeExt; + self.${fieldName}_operation(crate::operations::$structName::from_handler(value)) + } + + /// Sets the [`$structName`](crate::operations::$structName) operation. + /// + /// This should be an [`Operation`](#{SmithyHttpServer}::operation::Operation) created from + /// [`$structName`](crate::operations::$structName) using either + /// [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationShapeExt::from_handler) or + /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationShapeExt::from_service). + pub fn ${fieldName}_operation(self, value: NewOp) -> $builderName<${replacedGenerics.joinToString(",")}> { $builderName { #{SwitchedFields:W} modifier: self.modifier @@ -134,6 +164,7 @@ class ServerServiceGeneratorV2( } """, "SwitchedFields" to switchedFields, + "ReplacedGenericsService" to replacedGenericsService, *codegenScope, ) From 7c8828c203b5013bb3986821d07a62dbb92ecf9f Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Sat, 3 Sep 2022 12:44:49 +0000 Subject: [PATCH 22/73] Add blanket conversion implementations --- .../aws-smithy-http-server/src/request.rs | 24 ++++++++++++++++++- .../aws-smithy-http-server/src/response.rs | 6 +++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-http-server/src/request.rs b/rust-runtime/aws-smithy-http-server/src/request.rs index 2775a68cf5..36b880e228 100644 --- a/rust-runtime/aws-smithy-http-server/src/request.rs +++ b/rust-runtime/aws-smithy-http-server/src/request.rs @@ -32,7 +32,10 @@ * DEALINGS IN THE SOFTWARE. */ -use std::future::{ready, Future, Ready}; +use std::{ + convert::Infallible, + future::{ready, Future, Ready}, +}; use futures_util::{ future::{try_join, MapErr, MapOk, TryJoin}, @@ -117,6 +120,25 @@ pub trait FromParts: Sized { fn from_parts(parts: &mut Parts) -> Result; } +impl

FromParts

for () { + type Rejection = Infallible; + + fn from_parts(_parts: &mut Parts) -> Result { + Ok(()) + } +} + +impl FromParts

for (T,) +where + T: FromParts

, +{ + type Rejection = T::Rejection; + + fn from_parts(parts: &mut Parts) -> Result { + Ok((T::from_parts(parts)?,)) + } +} + impl FromParts

for (T1, T2) where T1: FromParts

, diff --git a/rust-runtime/aws-smithy-http-server/src/response.rs b/rust-runtime/aws-smithy-http-server/src/response.rs index 4c7bab848d..f35c10ed3b 100644 --- a/rust-runtime/aws-smithy-http-server/src/response.rs +++ b/rust-runtime/aws-smithy-http-server/src/response.rs @@ -42,3 +42,9 @@ pub trait IntoResponse { /// Performs a conversion into a [`http::Response`]. fn into_response(self) -> http::Response; } + +impl

IntoResponse

for std::convert::Infallible { + fn into_response(self) -> http::Response { + match self {} + } +} From 04a1fa227f88a1128b70132cf53e2e34e1dfc9c5 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Sat, 3 Sep 2022 14:47:18 +0000 Subject: [PATCH 23/73] Add FromRequest impl for input structs --- .../ServerHttpBoundProtocolGenerator.kt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt index 7b403e6d01..99ce70e220 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt @@ -41,6 +41,7 @@ import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency import software.amazon.smithy.rust.codegen.server.smithy.ServerRuntimeType import software.amazon.smithy.rust.codegen.server.smithy.generators.http.ServerRequestBindingGenerator import software.amazon.smithy.rust.codegen.server.smithy.generators.http.ServerResponseBindingGenerator +import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocol import software.amazon.smithy.rust.codegen.smithy.RuntimeType import software.amazon.smithy.rust.codegen.smithy.ServerCodegenContext import software.amazon.smithy.rust.codegen.smithy.customize.OperationCustomization @@ -183,6 +184,7 @@ private class ServerHttpBoundProtocolTraitImplGenerator( } // Implement `from_request` trait for input types. + val serverProtocol = ServerProtocol.fromCoreProtocol(codegenContext, protocol) rustTemplate( """ ##[derive(Debug)] @@ -207,9 +209,31 @@ private class ServerHttpBoundProtocolTraitImplGenerator( ) } } + + impl #{SmithyHttpServer}::request::FromRequest<#{Marker}, B> for #{I} + where + B: #{SmithyHttpServer}::body::HttpBody + Send, + B: 'static, + ${streamingBodyTraitBounds(operationShape)} + B::Data: Send, + #{RequestRejection} : From<::Error> + { + type Rejection = #{RuntimeError}; + type Future = std::pin::Pin> + Send>>; + + fn from_request(request: #{http}::Request) -> Self::Future { + let fut = async move { + let mut request_parts = #{SmithyHttpServer}::request::RequestParts::new(request); + $inputName::from_request(&mut request_parts).await.map(|x| x.0) + }; + Box::pin(fut) + } + } + """.trimIndent(), *codegenScope, "I" to inputSymbol, + "Marker" to serverProtocol.markerStruct(), "parse_request" to serverParseRequest(operationShape), "verify_response_content_type" to verifyResponseContentType, ) From a243fbff64aab093738be884afe9b2b44cac7c68 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Sat, 3 Sep 2022 16:11:58 +0000 Subject: [PATCH 24/73] Add IntoResponse for Output and Error --- .../ServerHttpBoundProtocolGenerator.kt | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt index 99ce70e220..9c90f19dc9 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt @@ -120,6 +120,7 @@ private class ServerHttpBoundProtocolTraitImplGenerator( private val operationDeserModule = RustModule.private("operation_deser") private val operationSerModule = RustModule.private("operation_ser") private val typeConversionGenerator = TypeConversionGenerator(model, symbolProvider, runtimeConfig) + private val serverProtocol = ServerProtocol.fromCoreProtocol(codegenContext, protocol) private val codegenScope = arrayOf( "AsyncTrait" to ServerCargoDependency.AsyncTrait.asType(), @@ -184,7 +185,6 @@ private class ServerHttpBoundProtocolTraitImplGenerator( } // Implement `from_request` trait for input types. - val serverProtocol = ServerProtocol.fromCoreProtocol(codegenContext, protocol) rustTemplate( """ ##[derive(Debug)] @@ -289,10 +289,23 @@ private class ServerHttpBoundProtocolTraitImplGenerator( $intoResponseImpl } } + + impl #{SmithyHttpServer}::response::IntoResponse<#{Marker}> for #{O} { + fn into_response(self) -> #{SmithyHttpServer}::response::Response { + $outputName::Output(self).into_response() + } + } + + impl #{SmithyHttpServer}::response::IntoResponse<#{Marker}> for #{E} { + fn into_response(self) -> #{SmithyHttpServer}::response::Response { + $outputName::Error(self).into_response() + } + } """.trimIndent(), *codegenScope, "O" to outputSymbol, "E" to errorSymbol, + "Marker" to serverProtocol.markerStruct(), "serialize_response" to serverSerializeResponse(operationShape), "serialize_error" to serverSerializeError(operationShape), ) @@ -321,9 +334,16 @@ private class ServerHttpBoundProtocolTraitImplGenerator( $intoResponseImpl } } + + impl #{SmithyHttpServer}::response::IntoResponse<#{Marker}> for #{O} { + fn into_response(self) -> #{SmithyHttpServer}::response::Response { + $outputName(self).into_response() + } + } """.trimIndent(), *codegenScope, "O" to outputSymbol, + "Marker" to serverProtocol.markerStruct(), "serialize_response" to serverSerializeResponse(operationShape), ) } From fda3b0f933cf886fb3cd8e28d39974af766aa9d7 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Sat, 3 Sep 2022 16:18:16 +0000 Subject: [PATCH 25/73] Add IntoResponse for RuntimeError --- .../aws-smithy-http-server/src/runtime_error.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-http-server/src/runtime_error.rs b/rust-runtime/aws-smithy-http-server/src/runtime_error.rs index 78e94bc9fb..cd20c5a782 100644 --- a/rust-runtime/aws-smithy-http-server/src/runtime_error.rs +++ b/rust-runtime/aws-smithy-http-server/src/runtime_error.rs @@ -21,7 +21,10 @@ //! and converts into the corresponding `RuntimeError`, and then it uses the its //! [`RuntimeError::into_response`] method to render and send a response. -use crate::{protocols::Protocol, response::Response}; +use crate::{ + protocols::Protocol, + response::{IntoResponse, Response}, +}; #[derive(Debug)] pub enum RuntimeErrorKind { @@ -54,6 +57,12 @@ pub struct RuntimeError { pub kind: RuntimeErrorKind, } +impl

IntoResponse

for RuntimeError { + fn into_response(self) -> http::Response { + self.into_response() + } +} + impl RuntimeError { pub fn into_response(self) -> Response { let status_code = match self.kind { From d3c24843f21d946f0c06a95dc11c77d074bd71cd Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Sun, 4 Sep 2022 07:45:20 +0000 Subject: [PATCH 26/73] Move generics --- .../generators/ServerServiceGeneratorV2.kt | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index e06a10f44c..5458eba905 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -82,14 +82,16 @@ class ServerServiceGeneratorV2( } private fun builderDef(): Writable = writable { + val generics = (builderGenerics() + extensionTypes().map { "$it" }).joinToString(",") rustTemplate( """ /// The service builder for [`$serviceName`]. /// /// Constructed via [`$serviceName::builder`]. - pub struct $builderName<${builderGenerics().joinToString(",")}, Modifier = #{SmithyHttpServer}::build_modifier::Identity> { + pub struct $builderName<$generics, Modifier = #{SmithyHttpServer}::build_modifier::Identity> { #{Fields:W} - modifier: Modifier + modifier: Modifier, + _exts: std::marker::PhantomData<(${extensionTypes().joinToString(",")})> } """, "Fields" to builderFields(), @@ -142,7 +144,7 @@ class ServerServiceGeneratorV2( /// [`$structName`](crate::operations::$structName) using either /// [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationShapeExt::from_handler) or /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationShapeExt::from_service). - pub fn $fieldName(self, value: H) -> $builderName<#{ReplacedGenericsService:W}> + pub fn $fieldName(self, value: H) -> $builderName<#{ReplacedGenericsService:W} ${extensionTypes().joinToString(",")}> where H: #{SmithyHttpServer}::operation::Handler { @@ -156,10 +158,11 @@ class ServerServiceGeneratorV2( /// [`$structName`](crate::operations::$structName) using either /// [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationShapeExt::from_handler) or /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationShapeExt::from_service). - pub fn ${fieldName}_operation(self, value: NewOp) -> $builderName<${replacedGenerics.joinToString(",")}> { + pub fn ${fieldName}_operation(self, value: NewOp) -> $builderName<${(replacedGenerics + extensionTypes()).joinToString(",")}> { $builderName { #{SwitchedFields:W} - modifier: self.modifier + modifier: self.modifier, + _exts: std::marker::PhantomData } } """, @@ -205,7 +208,7 @@ class ServerServiceGeneratorV2( } private fun builderImpl(): Writable = writable { - val generics = builderGenerics().joinToString(",") + val generics = (builderGenerics() + extensionTypes()).joinToString(",") val router = protocol .routerConstruction( service, @@ -223,7 +226,7 @@ class ServerServiceGeneratorV2( } impl<$generics, Modifier> $builderName<$generics, Modifier> { - pub fn build(self) -> $serviceName<#{SmithyHttpServer}::routing::Route> + pub fn build(self) -> $serviceName<#{SmithyHttpServer}::routing::Route> where #{BuildConstraints:W} { @@ -279,10 +282,11 @@ class ServerServiceGeneratorV2( """ impl $serviceName<()> { /// Constructs a builder for [`$serviceName`]. - pub fn builder() -> $builderName<#{NotSetGenerics:W}> { + pub fn builder<${extensionTypes().joinToString(",")}>() -> $builderName<#{NotSetGenerics:W} ${extensionTypes().joinToString(",")}> { $builderName { #{NotSetFields:W} - modifier: #{SmithyHttpServer}::build_modifier::Identity + modifier: #{SmithyHttpServer}::build_modifier::Identity, + _exts: std::marker::PhantomData } } } From 0be9c197a25e331ea6ec73796d55406f684f05e7 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Sun, 4 Sep 2022 09:11:23 +0000 Subject: [PATCH 27/73] Add into_make_service method --- .../server/smithy/generators/ServerServiceGeneratorV2.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 5458eba905..9e59d0fdcb 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -252,6 +252,7 @@ class ServerServiceGeneratorV2( rustTemplate( """ + ##[derive(Clone)] pub struct $serviceName { router: #{SmithyHttpServer}::routing::routers::RoutingService<#{Router}, #{Protocol}>, } @@ -290,6 +291,13 @@ class ServerServiceGeneratorV2( } } } + + impl $serviceName { + /// Converts [`$serviceName`] into a [`MakeService`](tower::make::MakeService). + pub fn into_make_service(self) -> #{SmithyHttpServer}::routing::IntoMakeService { + #{SmithyHttpServer}::routing::IntoMakeService::new(self) + } + } """, "NotSetGenerics" to notSetGenerics(), "NotSetFields" to notSetFields(), From a33c6216e330854bf3ef3feda3fb5f89ee722ad7 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Sun, 4 Sep 2022 12:39:10 +0000 Subject: [PATCH 28/73] Make RoutingService more flexible --- .../src/routing/routers/mod.rs | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/rust-runtime/aws-smithy-http-server/src/routing/routers/mod.rs b/rust-runtime/aws-smithy-http-server/src/routing/routers/mod.rs index a6d0d2fc07..e70fe1abdf 100644 --- a/rust-runtime/aws-smithy-http-server/src/routing/routers/mod.rs +++ b/rust-runtime/aws-smithy-http-server/src/routing/routers/mod.rs @@ -12,12 +12,21 @@ use std::{ task::{Context, Poll}, }; -use futures_util::future::Either; +use bytes::Bytes; +use futures_util::{ + future::{Either, MapOk}, + TryFutureExt, +}; use http::Response; +use http_body::Body as HttpBody; use tower::{util::Oneshot, Service, ServiceExt}; use tracing::debug; -use crate::{body::BoxBody, response::IntoResponse}; +use crate::{ + body::{boxed, BoxBody}, + error::BoxError, + response::IntoResponse, +}; pub mod aws_json; pub mod rest; @@ -94,8 +103,8 @@ impl RoutingService { } type EitherOneshotReady = Either< - Oneshot>, - Ready>>::Response, >>::Error>>, + MapOk>, fn(>>::Response) -> http::Response>, + Ready, >>::Error>>, >; pin_project_lite::pin_project! { @@ -110,14 +119,19 @@ where S: Service>, { /// Creates a [`RoutingFuture`] from [`ServiceExt::oneshot`]. - pub(super) fn from_oneshot(future: Oneshot>) -> Self { + pub(super) fn from_oneshot(future: Oneshot>) -> Self + where + S: Service, Response = http::Response>, + RespB: HttpBody + Send + 'static, + RespB::Error: Into, + { Self { - inner: Either::Left(future), + inner: Either::Left(future.map_ok(|x| x.map(boxed))), } } /// Creates a [`RoutingFuture`] from [`Service::Response`]. - pub(super) fn from_response(response: S::Response) -> Self { + pub(super) fn from_response(response: http::Response) -> Self { Self { inner: Either::Right(ready(Ok(response))), } @@ -128,18 +142,20 @@ impl Future for RoutingFuture where S: Service>, { - type Output = ::Output; + type Output = Result, S::Error>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { self.project().inner.poll(cx) } } -impl Service> for RoutingService +impl Service> for RoutingService where R: Router, - R::Service: Service, Response = http::Response> + Clone, + R::Service: Service, Response = http::Response> + Clone, R::Error: IntoResponse

+ Error, + RespB: HttpBody + Send + 'static, + RespB::Error: Into, { type Response = Response; type Error = >>::Error; From ca78b046e1a1f63a10d56519a0e470c3b2ffbb17 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Sun, 4 Sep 2022 12:41:39 +0000 Subject: [PATCH 29/73] Add layer method to service --- .../generators/ServerServiceGeneratorV2.kt | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 9e59d0fdcb..53800f4c16 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -34,7 +34,9 @@ class ServerServiceGeneratorV2( private val runtimeConfig = coreCodegenContext.runtimeConfig private val codegenScope = arrayOf( + "Bytes" to CargoDependency.Bytes.asType(), "Http" to CargoDependency.Http.asType(), + "HttpBody" to CargoDependency.HttpBody.asType(), "SmithyHttpServer" to ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType(), "Tower" to CargoDependency.Tower.asType(), @@ -297,6 +299,16 @@ class ServerServiceGeneratorV2( pub fn into_make_service(self) -> #{SmithyHttpServer}::routing::IntoMakeService { #{SmithyHttpServer}::routing::IntoMakeService::new(self) } + + /// Applies a layer uniformly to all routes. + pub fn layer(self, layer: &L) -> $serviceName + where + L: #{Tower}::Layer + { + $serviceName { + router: self.router.map(|s| s.layer(layer)) + } + } } """, "NotSetGenerics" to notSetGenerics(), @@ -308,9 +320,11 @@ class ServerServiceGeneratorV2( private fun structServiceImpl(): Writable = writable { rustTemplate( """ - impl #{Tower}::Service<#{Http}::Request> for $serviceName + impl #{Tower}::Service<#{Http}::Request> for $serviceName where - S: #{Tower}::Service, Response = http::Response<#{SmithyHttpServer}::body::BoxBody>> + Clone, + S: #{Tower}::Service, Response = http::Response> + Clone, + RespB: #{HttpBody}::Body + Send + 'static, + RespB::Error: Into<#{Tower}::BoxError> { type Response = #{Http}::Response<#{SmithyHttpServer}::body::BoxBody>; type Error = S::Error; From 322c8f2112ffb3d152a76bf46630b96a65215a83 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Sun, 4 Sep 2022 12:46:02 +0000 Subject: [PATCH 30/73] Tweak example --- .../examples/pokemon-service/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs b/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs index 7b511dbfdd..3d0dd0b835 100644 --- a/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs +++ b/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs @@ -35,7 +35,7 @@ pub async fn main() { setup_tracing(); // Old builder - let app: Router = OperationRegistryBuilder::default() + let _app: Router = OperationRegistryBuilder::default() // Build a registry containing implementations to all the operations in the service. These // are async functions or async closures that take as input the operation's input and // return the operation's output. @@ -52,7 +52,7 @@ pub async fn main() { .into(); // New builder - let _app = PokemonService::builder() + let app = PokemonService::builder() .get_pokemon_species(get_pokemon_species) .get_storage(get_storage) .get_server_statistics(get_server_statistics) @@ -64,7 +64,7 @@ pub async fn main() { // Setup shared state and middlewares. let shared_state = Arc::new(State::default()); let app = app.layer( - ServiceBuilder::new() + &ServiceBuilder::new() .layer(TraceLayer::new_for_http()) .layer(AddExtensionLayer::new(shared_state)), ); From 7e4fbf41dce8223c0dcb6c5c6bba510687212caa Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Sun, 4 Sep 2022 14:15:36 +0000 Subject: [PATCH 31/73] Fix missing routes --- .../generators/protocol/ServerProtocol.kt | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index e2b2545f66..5b0924c7de 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -7,6 +7,7 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators.protocol import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.OperationShape +import software.amazon.smithy.model.shapes.ResourceShape import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.asType @@ -79,12 +80,21 @@ class ServerAwsJsonProtocol( } override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = writable { + val resourceOperationShapes = service + .resources + .mapNotNull { model.getShape(it).orNull() } + .mapNotNull { it as? ResourceShape } + .flatMap { it.allOperations } + .mapNotNull { model.getShape(it).orNull() } + .mapNotNull { it as? OperationShape } val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } + val allOperationShapes = resourceOperationShapes + operationShapes + // TODO(restore): This causes a panic: "symbol visitor should not be invoked in service shapes" // val serviceName = symbolProvider.toSymbol(service).name val serviceName = service.id.name val pairs = writable { - for ((operation, operationValue) in operationShapes.zip(operationValues)) { + for ((operation, operationValue) in allOperationShapes.zip(operationValues)) { val operationName = symbolProvider.toSymbol(operation).name val key = "$serviceName.$operationName".dq() rustTemplate( @@ -131,12 +141,21 @@ open class RestProtocol( } override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = writable { + val resourceOperationShapes = service + .resources + .mapNotNull { model.getShape(it).orNull() } + .mapNotNull { it as? ResourceShape } + .flatMap { it.allOperations } + .mapNotNull { model.getShape(it).orNull() } + .mapNotNull { it as? OperationShape } val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } + val allOperationShapes = resourceOperationShapes + operationShapes + // TODO(restore): This causes a panic: "symbol visitor should not be invoked in service shapes" // val serviceName = symbolProvider.toSymbol(service).name val serviceName = service.id.name val pairs = writable { - for ((operationShape, operationValue) in operationShapes.zip(operationValues)) { + for ((operationShape, operationValue) in allOperationShapes.zip(operationValues)) { val operationName = symbolProvider.toSymbol(operationShape).name val key = coreProtocol.serverRouterRequestSpec( operationShape, From 306fddcb69abfe09c2bcad1442da9383609c7f3a Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Sun, 4 Sep 2022 14:24:40 +0000 Subject: [PATCH 32/73] Allow unused parens --- .../codegen/server/smithy/generators/ServerServiceGeneratorV2.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 53800f4c16..c1c1a4cae0 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -93,6 +93,7 @@ class ServerServiceGeneratorV2( pub struct $builderName<$generics, Modifier = #{SmithyHttpServer}::build_modifier::Identity> { #{Fields:W} modifier: Modifier, + ##[allow(unused_parens)] _exts: std::marker::PhantomData<(${extensionTypes().joinToString(",")})> } """, From b4cee920cfdf1f52eeed62c643a23f16786e5f47 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Mon, 5 Sep 2022 09:35:19 +0000 Subject: [PATCH 33/73] Improve documentation --- .../generators/ServerOperationGenerator.kt | 27 ++-- .../generators/ServerServiceGeneratorV2.kt | 123 ++++++++---------- 2 files changed, 68 insertions(+), 82 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt index f00ae9e9bc..261079fba0 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt @@ -34,15 +34,7 @@ class ServerOperationGenerator( private val operationName = symbolProvider.toSymbol(operation).name.toPascalCase() private val operationId = operation.id - private fun renderStructDef(): Writable = writable { - val documentation = operation.getTrait()?.value - if (documentation != null) { - docs(documentation.replace("#", "##")) - } - - rust("pub struct $operationName;") - } - + // / Returns `std::convert::Infallible` if the model provides no errors. private fun operationError(): Writable = writable { if (operation.errors.isEmpty()) { rust("std::convert::Infallible") @@ -51,7 +43,15 @@ class ServerOperationGenerator( } } - private fun renderImpl(): Writable = writable { + // / Returns a `Writable` containing the operation struct definition and its `OperationShape` implementation. + private fun operation(): Writable = writable { + val documentation = operation.getTrait()?.value + if (documentation != null) { + docs(documentation.replace("#", "##")) + } + + rust("pub struct $operationName;") + rustTemplate( """ impl #{SmithyHttpServer}::operation::OperationShape for $operationName { @@ -70,12 +70,9 @@ class ServerOperationGenerator( fun render(writer: RustWriter) { writer.rustTemplate( """ - #{Struct:W} - - #{Impl:W} + #{Operation:W} """, - "Struct" to renderStructDef(), - "Impl" to renderImpl(), + "Operation" to operation(), ) // Adds newline to end of render writer.rust("") diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index c1c1a4cae0..9b6618548c 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -47,6 +47,7 @@ class ServerServiceGeneratorV2( private val serviceName = service.id.name private val builderName = "${serviceName}Builder" + // Calculate all `operationShape`s contained within the `ServiceShape`. private val resourceOperationShapes = service .resources .mapNotNull { model.getShape(it).orNull() } @@ -57,12 +58,21 @@ class ServerServiceGeneratorV2( private val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } private val allOperationShapes = resourceOperationShapes + operationShapes + // Returns the sequence of builder generics: `Op1`, ..., `OpN`. private fun builderGenerics(): Sequence = sequence { for (index in 1..allOperationShapes.size) { yield("Op$index") } } + // / Returns the sequence of extension types: `Ext1`, ..., `ExtN`. + private fun extensionTypes(): Sequence = sequence { + for (index in 1..allOperationShapes.size) { + yield("Exts$index") + } + } + + // / Returns the sequence of field names for the builder. private fun builderFieldNames(): Sequence = sequence { for (operation in allOperationShapes) { val field = RustReservedWords.escapeIfNeeded(symbolProvider.toSymbol(operation).name.toSnakeCase()) @@ -70,12 +80,14 @@ class ServerServiceGeneratorV2( } } + // / Returns the sequence of operation struct names. private fun operationStructNames(): Sequence = sequence { for (operation in allOperationShapes) { yield(symbolProvider.toSymbol(operation).name.toPascalCase()) } } + // / Returns a `Writable` block of "field: Type" for the builder. private fun builderFields(): Writable = writable { val zipped = builderFieldNames().zip(builderGenerics()) for ((name, type) in zipped) { @@ -83,28 +95,12 @@ class ServerServiceGeneratorV2( } } - private fun builderDef(): Writable = writable { - val generics = (builderGenerics() + extensionTypes().map { "$it" }).joinToString(",") - rustTemplate( - """ - /// The service builder for [`$serviceName`]. - /// - /// Constructed via [`$serviceName::builder`]. - pub struct $builderName<$generics, Modifier = #{SmithyHttpServer}::build_modifier::Identity> { - #{Fields:W} - modifier: Modifier, - ##[allow(unused_parens)] - _exts: std::marker::PhantomData<(${extensionTypes().joinToString(",")})> - } - """, - "Fields" to builderFields(), - *codegenScope, - ) - } - + // / Returns a `Writable` block containing all the `Handler` and `Operation` setters for the builder. private fun builderSetters(): Writable = writable { for ((index, pair) in builderFieldNames().zip(operationStructNames()).withIndex()) { val (fieldName, structName) = pair + + // The new generics for the handler setter, using `NewOp` where appropriate. val replacedGenericsService = writable { for ((innerIndex, item) in builderGenerics().withIndex()) { if (innerIndex == index) { @@ -121,6 +117,7 @@ class ServerServiceGeneratorV2( } } + // The new generics for the operation setter, using `NewOp` where appropriate. val replacedGenerics = builderGenerics().withIndex().map { (innerIndex, item) -> if (innerIndex == index) { "NewOp" @@ -129,6 +126,7 @@ class ServerServiceGeneratorV2( } } + // The assignment of fields, using value where appropriate. val switchedFields = writable { for ((innerIndex, innerFieldName) in builderFieldNames().withIndex()) { if (index == innerIndex) { @@ -179,12 +177,7 @@ class ServerServiceGeneratorV2( } } - private fun extensionTypes(): Sequence = sequence { - for (index in 1..allOperationShapes.size) { - yield("Exts$index") - } - } - + // / Retrurns the constraints required for the `build` method. private fun buildConstraints(): Writable = writable { for (tuple in allOperationShapes.asSequence().zip(builderGenerics()).zip(extensionTypes())) { val (first, exts) = tuple @@ -210,8 +203,11 @@ class ServerServiceGeneratorV2( } } - private fun builderImpl(): Writable = writable { + // / Returns a `Writable` containing the builder struct definition and its implementations. + private fun builder(): Writable = writable { val generics = (builderGenerics() + extensionTypes()).joinToString(",") + + // Generate router construction block. val router = protocol .routerConstruction( service, @@ -224,11 +220,22 @@ class ServerServiceGeneratorV2( ) rustTemplate( """ + /// The service builder for [`$serviceName`]. + /// + /// Constructed via [`$serviceName::builder`]. + pub struct $builderName<$generics, Modifier = #{SmithyHttpServer}::build_modifier::Identity> { + #{Fields:W} + modifier: Modifier, + ##[allow(unused_parens)] + _exts: std::marker::PhantomData<(${extensionTypes().joinToString(",")})> + } + impl<$generics> $builderName<$generics> { #{Setters:W} } impl<$generics, Modifier> $builderName<$generics, Modifier> { + /// Constructs a [`$serviceName`] from the arguments provided to the builder. pub fn build(self) -> $serviceName<#{SmithyHttpServer}::routing::Route> where #{BuildConstraints:W} @@ -240,6 +247,7 @@ class ServerServiceGeneratorV2( } } """, + "Fields" to builderFields(), "Setters" to builderSetters(), "BuildConstraints" to buildConstraints(), "Router" to router, @@ -247,31 +255,14 @@ class ServerServiceGeneratorV2( ) } - private fun structDef(): Writable = writable { - val documentation = service.getTrait()?.value - if (documentation != null) { - docs(documentation.replace("#", "##")) - } - - rustTemplate( - """ - ##[derive(Clone)] - pub struct $serviceName { - router: #{SmithyHttpServer}::routing::routers::RoutingService<#{Router}, #{Protocol}>, - } - """, - "Router" to protocol.routerType(), - "Protocol" to protocol.markerStruct(), - *codegenScope, - ) - } - + // / Returns a `Writable` comma delimited sequence of `OperationNotSet`. private fun notSetGenerics(): Writable = writable { for (index in 1..allOperationShapes.size) { rustTemplate("#{SmithyHttpServer}::operation::OperationNotSet,", *codegenScope) } } + // / Returns a `Writable` comma delimited sequence of `builder_field: OperationNotSet`. private fun notSetFields(): Writable = writable { for (fieldName in builderFieldNames()) { rustTemplate( @@ -281,9 +272,21 @@ class ServerServiceGeneratorV2( } } - private fun structImpl(): Writable = writable { + // / Returns a `Writable` containing the service struct definition and its implementations. + private fun struct(): Writable = writable { + // Generate struct documentation. + val documentation = service.getTrait()?.value + if (documentation != null) { + docs(documentation.replace("#", "##")) + } + rustTemplate( """ + ##[derive(Clone)] + pub struct $serviceName { + router: #{SmithyHttpServer}::routing::routers::RoutingService<#{Router}, #{Protocol}>, + } + impl $serviceName<()> { /// Constructs a builder for [`$serviceName`]. pub fn builder<${extensionTypes().joinToString(",")}>() -> $builderName<#{NotSetGenerics:W} ${extensionTypes().joinToString(",")}> { @@ -311,19 +314,10 @@ class ServerServiceGeneratorV2( } } } - """, - "NotSetGenerics" to notSetGenerics(), - "NotSetFields" to notSetFields(), - *codegenScope, - ) - } - private fun structServiceImpl(): Writable = writable { - rustTemplate( - """ impl #{Tower}::Service<#{Http}::Request> for $serviceName where - S: #{Tower}::Service, Response = http::Response> + Clone, + S: #{Tower}::Service<#{Http}::Request, Response = #{Http}::Response> + Clone, RespB: #{HttpBody}::Body + Send + 'static, RespB::Error: Into<#{Tower}::BoxError> { @@ -340,6 +334,10 @@ class ServerServiceGeneratorV2( } } """, + "NotSetGenerics" to notSetGenerics(), + "NotSetFields" to notSetFields(), + "Router" to protocol.routerType(), + "Protocol" to protocol.markerStruct(), *codegenScope, ) } @@ -349,19 +347,10 @@ class ServerServiceGeneratorV2( """ #{Builder:W} - #{BuilderImpl:W} - #{Struct:W} - - #{StructImpl:W} - - #{StructServiceImpl:W} """, - "Builder" to builderDef(), - "BuilderImpl" to builderImpl(), - "Struct" to structDef(), - "StructImpl" to structImpl(), - "StructServiceImpl" to structServiceImpl(), + "Builder" to builder(), + "Struct" to struct(), ) } } From d1d838304da907c7ff93e8ddb32eb42174f80631 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Mon, 5 Sep 2022 09:35:33 +0000 Subject: [PATCH 34/73] Extend example --- .../examples/pokemon-service/src/main.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs b/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs index 3d0dd0b835..0912f26c5f 100644 --- a/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs +++ b/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs @@ -6,7 +6,7 @@ // This program is exported as a binary named `pokemon-service`. use std::{net::SocketAddr, sync::Arc}; -use aws_smithy_http_server::{AddExtensionLayer, Router}; +use aws_smithy_http_server::{operation::OperationShapeExt, AddExtensionLayer, Router}; use clap::Parser; use tower::ServiceBuilder; use tower_http::trace::TraceLayer; @@ -16,6 +16,7 @@ use pokemon_service::{ setup_tracing, State, }; use pokemon_service_server_sdk::operation_registry::OperationRegistryBuilder; +use pokemon_service_server_sdk::operations::GetPokemonSpecies; use pokemon_service_server_sdk::services::PokemonService; #[derive(Parser, Debug)] @@ -52,8 +53,9 @@ pub async fn main() { .into(); // New builder + let get_pokemon_species = GetPokemonSpecies::from_handler(get_pokemon_species); let app = PokemonService::builder() - .get_pokemon_species(get_pokemon_species) + .get_pokemon_species_operation(get_pokemon_species) .get_storage(get_storage) .get_server_statistics(get_server_statistics) .capture_pokemon_operation(capture_pokemon) From 1690cd6b33d7bf5074011ee45f7b6c0a17b4dca6 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Mon, 5 Sep 2022 10:01:22 +0000 Subject: [PATCH 35/73] Fix // / kotlin documentation --- .../generators/ServerOperationGenerator.kt | 4 ++-- .../generators/ServerServiceGeneratorV2.kt | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt index 261079fba0..e238a65363 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt @@ -34,7 +34,7 @@ class ServerOperationGenerator( private val operationName = symbolProvider.toSymbol(operation).name.toPascalCase() private val operationId = operation.id - // / Returns `std::convert::Infallible` if the model provides no errors. + // Returns `std::convert::Infallible` if the model provides no errors. private fun operationError(): Writable = writable { if (operation.errors.isEmpty()) { rust("std::convert::Infallible") @@ -43,7 +43,7 @@ class ServerOperationGenerator( } } - // / Returns a `Writable` containing the operation struct definition and its `OperationShape` implementation. + // Returns a `Writable` containing the operation struct definition and its `OperationShape` implementation. private fun operation(): Writable = writable { val documentation = operation.getTrait()?.value if (documentation != null) { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 9b6618548c..3828e7446f 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -65,14 +65,14 @@ class ServerServiceGeneratorV2( } } - // / Returns the sequence of extension types: `Ext1`, ..., `ExtN`. + // Returns the sequence of extension types: `Ext1`, ..., `ExtN`. private fun extensionTypes(): Sequence = sequence { for (index in 1..allOperationShapes.size) { yield("Exts$index") } } - // / Returns the sequence of field names for the builder. + // Returns the sequence of field names for the builder. private fun builderFieldNames(): Sequence = sequence { for (operation in allOperationShapes) { val field = RustReservedWords.escapeIfNeeded(symbolProvider.toSymbol(operation).name.toSnakeCase()) @@ -80,14 +80,14 @@ class ServerServiceGeneratorV2( } } - // / Returns the sequence of operation struct names. + // Returns the sequence of operation struct names. private fun operationStructNames(): Sequence = sequence { for (operation in allOperationShapes) { yield(symbolProvider.toSymbol(operation).name.toPascalCase()) } } - // / Returns a `Writable` block of "field: Type" for the builder. + // Returns a `Writable` block of "field: Type" for the builder. private fun builderFields(): Writable = writable { val zipped = builderFieldNames().zip(builderGenerics()) for ((name, type) in zipped) { @@ -95,7 +95,7 @@ class ServerServiceGeneratorV2( } } - // / Returns a `Writable` block containing all the `Handler` and `Operation` setters for the builder. + // Returns a `Writable` block containing all the `Handler` and `Operation` setters for the builder. private fun builderSetters(): Writable = writable { for ((index, pair) in builderFieldNames().zip(operationStructNames()).withIndex()) { val (fieldName, structName) = pair @@ -177,7 +177,7 @@ class ServerServiceGeneratorV2( } } - // / Retrurns the constraints required for the `build` method. + // / Returns the constraints required for the `build` method. private fun buildConstraints(): Writable = writable { for (tuple in allOperationShapes.asSequence().zip(builderGenerics()).zip(extensionTypes())) { val (first, exts) = tuple @@ -203,7 +203,7 @@ class ServerServiceGeneratorV2( } } - // / Returns a `Writable` containing the builder struct definition and its implementations. + // Returns a `Writable` containing the builder struct definition and its implementations. private fun builder(): Writable = writable { val generics = (builderGenerics() + extensionTypes()).joinToString(",") @@ -255,14 +255,14 @@ class ServerServiceGeneratorV2( ) } - // / Returns a `Writable` comma delimited sequence of `OperationNotSet`. + // Returns a `Writable` comma delimited sequence of `OperationNotSet`. private fun notSetGenerics(): Writable = writable { for (index in 1..allOperationShapes.size) { rustTemplate("#{SmithyHttpServer}::operation::OperationNotSet,", *codegenScope) } } - // / Returns a `Writable` comma delimited sequence of `builder_field: OperationNotSet`. + // Returns a `Writable` comma delimited sequence of `builder_field: OperationNotSet`. private fun notSetFields(): Writable = writable { for (fieldName in builderFieldNames()) { rustTemplate( @@ -272,7 +272,7 @@ class ServerServiceGeneratorV2( } } - // / Returns a `Writable` containing the service struct definition and its implementations. + // Returns a `Writable` containing the service struct definition and its implementations. private fun struct(): Writable = writable { // Generate struct documentation. val documentation = service.getTrait()?.value From e7d889d7abcec4531f57f229868ef2079c004d90 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Mon, 5 Sep 2022 10:02:19 +0000 Subject: [PATCH 36/73] Remove excess rust call --- .../server/smithy/generators/ServerOperationGenerator.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt index e238a65363..520ad1345b 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt @@ -50,10 +50,10 @@ class ServerOperationGenerator( docs(documentation.replace("#", "##")) } - rust("pub struct $operationName;") - rustTemplate( """ + pub struct $operationName; + impl #{SmithyHttpServer}::operation::OperationShape for $operationName { const NAME: &'static str = "${operationId.toString().replace("#", "##")}"; From 98f661599e52a64771a17560eb211cb719b394cc Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Mon, 5 Sep 2022 10:03:47 +0000 Subject: [PATCH 37/73] Cleanup upgrade --- .../aws-smithy-http-server/src/operation/mod.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/rust-runtime/aws-smithy-http-server/src/operation/mod.rs b/rust-runtime/aws-smithy-http-server/src/operation/mod.rs index 6e79d3eced..e1a29f92f5 100644 --- a/rust-runtime/aws-smithy-http-server/src/operation/mod.rs +++ b/rust-runtime/aws-smithy-http-server/src/operation/mod.rs @@ -205,23 +205,6 @@ impl Operation { layer: Stack::new(self.layer, layer), } } - - // /// Takes the [`Operation`], containing the inner [`Service`](tower::Service) `S`, the HTTP [`Layer`] `L` and - // /// composes them together using [`UpgradeLayer`] for a specific protocol and [`OperationShape`]. - // /// - // /// Prior to upgrade [`Operation`] is also - // /// - // /// The composition is made explicit in the method constraints and return type. - // pub fn upgrade( - // self, - // modify: Modify, - // ) -> >>::Service - // where - // Modify: ModifyBuild, - // Layer> - // { - - // } } impl Operation> { From e0673aaf1d627c8d341e9a74bc575396874f086b Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Mon, 5 Sep 2022 12:35:16 +0000 Subject: [PATCH 38/73] Cleanup ServerProtocol --- .../generators/protocol/ServerProtocol.kt | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 5b0924c7de..bbd30e4b79 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -25,17 +25,35 @@ import software.amazon.smithy.rust.codegen.util.PANIC import software.amazon.smithy.rust.codegen.util.dq import software.amazon.smithy.rust.codegen.util.orNull +fun allOperationShapes(service: ServiceShape, model: Model): List { + val resourceOperationShapes = service + .resources + .mapNotNull { model.getShape(it).orNull() } + .mapNotNull { it as? ResourceShape } + .flatMap { it.allOperations } + .mapNotNull { model.getShape(it).orNull() } + .mapNotNull { it as? OperationShape } + val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } + return resourceOperationShapes + operationShapes +} + interface ServerProtocol { + // Returns the core `Protocol`. fun coreProtocol(): Protocol + // Returns the Rust marker struct enjoying `OperationShape`. fun markerStruct(): RuntimeType + // Returns the Rust router type. fun routerType(): RuntimeType + // Returns the construction of the `routerType` given a `ServiceShape`, a collection of operation values + // (`self.operation_name`, ...), and the `Model`. // TODO(Decouple): Perhaps this should lean on a Rust interface. fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable companion object { + // Upgrades the core protocol to a `ServerProtocol`. fun fromCoreProtocol(coreCodegenContext: CoreCodegenContext, protocol: Protocol): ServerProtocol { val serverProtocol = when (protocol) { is AwsJson -> ServerAwsJsonProtocol(coreCodegenContext, protocol) @@ -80,15 +98,7 @@ class ServerAwsJsonProtocol( } override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = writable { - val resourceOperationShapes = service - .resources - .mapNotNull { model.getShape(it).orNull() } - .mapNotNull { it as? ResourceShape } - .flatMap { it.allOperations } - .mapNotNull { model.getShape(it).orNull() } - .mapNotNull { it as? OperationShape } - val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } - val allOperationShapes = resourceOperationShapes + operationShapes + val allOperationShapes = allOperationShapes(service, model) // TODO(restore): This causes a panic: "symbol visitor should not be invoked in service shapes" // val serviceName = symbolProvider.toSymbol(service).name @@ -141,15 +151,7 @@ open class RestProtocol( } override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = writable { - val resourceOperationShapes = service - .resources - .mapNotNull { model.getShape(it).orNull() } - .mapNotNull { it as? ResourceShape } - .flatMap { it.allOperations } - .mapNotNull { model.getShape(it).orNull() } - .mapNotNull { it as? OperationShape } - val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } - val allOperationShapes = resourceOperationShapes + operationShapes + val allOperationShapes = allOperationShapes(service, model) // TODO(restore): This causes a panic: "symbol visitor should not be invoked in service shapes" // val serviceName = symbolProvider.toSymbol(service).name From 53404c09fed4990d79ad15c7584a126c3cc98172 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Mon, 5 Sep 2022 12:36:56 +0000 Subject: [PATCH 39/73] Fix another // / --- .../server/smithy/generators/ServerServiceGeneratorV2.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 3828e7446f..a1fab458bc 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -177,7 +177,7 @@ class ServerServiceGeneratorV2( } } - // / Returns the constraints required for the `build` method. + // Returns the constraints required for the `build` method. private fun buildConstraints(): Writable = writable { for (tuple in allOperationShapes.asSequence().zip(builderGenerics()).zip(extensionTypes())) { val (first, exts) = tuple From 9cef47eed4f5f82e8846d50945fe8bcd846d1d40 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Mon, 5 Sep 2022 14:09:48 +0000 Subject: [PATCH 40/73] Rework modules --- .../generators/ServerServiceGenerator.kt | 4 ++-- .../generators/ServerServiceGeneratorV2.kt | 16 ++++++++-------- .../smithy/rust/codegen/rustlang/RustModule.kt | 18 +++++++++++------- .../generators/NestedAccessorGenerator.kt | 2 +- .../smithy/generators/PaginatorGenerator.kt | 1 + .../examples/pokemon-service/src/main.rs | 4 ++-- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt index 7b23f010f7..9a60566cb1 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt @@ -70,7 +70,7 @@ open class ServerServiceGenerator( // TODO(Temporary): Remove, this is temporary. rustCrate.withModule( - RustModule.public("operations", ""), + RustModule.public("operation_shape", hidden = true), ) { writer -> for (operation in operations) { ServerOperationGenerator(coreCodegenContext, operation).render(writer) @@ -79,7 +79,7 @@ open class ServerServiceGenerator( // TODO(Temporary): Remove, this is temporary. rustCrate.withModule( - RustModule.public("services", ""), + RustModule.public("service", hidden = true), ) { writer -> val serverProtocol = ServerProtocol.fromCoreProtocol(coreCodegenContext, protocol) ServerServiceGeneratorV2( diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index a1fab458bc..e1c844ae41 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -106,7 +106,7 @@ class ServerServiceGeneratorV2( if (innerIndex == index) { rustTemplate( """ - #{SmithyHttpServer}::operation::Operation<#{SmithyHttpServer}::operation::IntoService> + #{SmithyHttpServer}::operation::Operation<#{SmithyHttpServer}::operation::IntoService> """, *codegenScope, ) @@ -139,24 +139,24 @@ class ServerServiceGeneratorV2( rustTemplate( """ - /// Sets the [`$structName`](crate::operations::$structName) operation. + /// Sets the [`$structName`](crate::operation_shape::$structName) operation. /// /// This should be an [`Operation`](#{SmithyHttpServer}::operation::Operation) created from - /// [`$structName`](crate::operations::$structName) using either + /// [`$structName`](crate::operation_shape::$structName) using either /// [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationShapeExt::from_handler) or /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationShapeExt::from_service). pub fn $fieldName(self, value: H) -> $builderName<#{ReplacedGenericsService:W} ${extensionTypes().joinToString(",")}> where - H: #{SmithyHttpServer}::operation::Handler + H: #{SmithyHttpServer}::operation::Handler { use #{SmithyHttpServer}::operation::OperationShapeExt; - self.${fieldName}_operation(crate::operations::$structName::from_handler(value)) + self.${fieldName}_operation(crate::operation_shape::$structName::from_handler(value)) } - /// Sets the [`$structName`](crate::operations::$structName) operation. + /// Sets the [`$structName`](crate::operation_shape::$structName) operation. /// /// This should be an [`Operation`](#{SmithyHttpServer}::operation::Operation) created from - /// [`$structName`](crate::operations::$structName) using either + /// [`$structName`](crate::operation_shape::$structName) using either /// [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationShapeExt::from_handler) or /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationShapeExt::from_service). pub fn ${fieldName}_operation(self, value: NewOp) -> $builderName<${(replacedGenerics + extensionTypes()).joinToString(",")}> { @@ -187,7 +187,7 @@ class ServerServiceGeneratorV2( """ $type: #{SmithyHttpServer}::operation::Upgradable< #{Marker}, - crate::operations::${symbolProvider.toSymbol(operation).name.toPascalCase()}, + crate::operation_shape::${symbolProvider.toSymbol(operation).name.toPascalCase()}, $exts, B, Modifier diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustModule.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustModule.kt index 624f104903..a01e5c37d9 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustModule.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustModule.kt @@ -5,23 +5,27 @@ package software.amazon.smithy.rust.codegen.rustlang -data class RustModule(val name: String, val rustMetadata: RustMetadata, val documentation: String?) { +data class RustModule(val name: String, val rustMetadata: RustMetadata, val documentation: String?, val hidden: Boolean?) { fun render(writer: RustWriter) { + if (hidden == true) { + writer.write("##[doc(hidden)]") + } documentation?.let { docs -> writer.docs(docs) } rustMetadata.render(writer) + writer.write("mod $name;") } companion object { - fun default(name: String, visibility: Visibility, documentation: String? = null): RustModule { - return RustModule(name, RustMetadata(visibility = visibility), documentation) + fun default(name: String, visibility: Visibility, documentation: String? = null, hidden: Boolean? = false): RustModule { + return RustModule(name, RustMetadata(visibility = visibility), documentation, hidden) } - fun public(name: String, documentation: String? = null): RustModule = - default(name, visibility = Visibility.PUBLIC, documentation = documentation) + fun public(name: String, documentation: String? = null, hidden: Boolean? = false): RustModule = + default(name, visibility = Visibility.PUBLIC, documentation, hidden) - fun private(name: String, documentation: String? = null): RustModule = - default(name, visibility = Visibility.PRIVATE, documentation = documentation) + fun private(name: String, documentation: String? = null, hidden: Boolean? = false): RustModule = + default(name, visibility = Visibility.PRIVATE, documentation, hidden) val Config = public("config", documentation = "Configuration for the service.") val Error = public("error", documentation = "Errors that can occur when calling the service.") diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/NestedAccessorGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/NestedAccessorGenerator.kt index 2651332671..3a3df9c900 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/NestedAccessorGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/NestedAccessorGenerator.kt @@ -24,7 +24,7 @@ import software.amazon.smithy.rust.codegen.smithy.protocols.lensName /** Generator for accessing nested fields through optional values **/ class NestedAccessorGenerator(private val symbolProvider: RustSymbolProvider) { - private val module = RustModule("lens", RustMetadata(visibility = Visibility.PUBLIC), "Generated accessors for nested fields") + private val module = RustModule("lens", RustMetadata(visibility = Visibility.PUBLIC), "Generated accessors for nested fields", false) /** * Generate an accessor on [root] that consumes [root] and returns an `Option` for the nested item diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/PaginatorGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/PaginatorGenerator.kt index 5b817edc93..e3fe51995e 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/PaginatorGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/PaginatorGenerator.kt @@ -79,6 +79,7 @@ class PaginatorGenerator private constructor( "paginator", RustMetadata(visibility = Visibility.PUBLIC), documentation = "Paginators for the service", + false, ) private val inputType = symbolProvider.toSymbol(operation.inputShape(model)) diff --git a/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs b/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs index 0912f26c5f..bba5198c54 100644 --- a/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs +++ b/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs @@ -16,8 +16,8 @@ use pokemon_service::{ setup_tracing, State, }; use pokemon_service_server_sdk::operation_registry::OperationRegistryBuilder; -use pokemon_service_server_sdk::operations::GetPokemonSpecies; -use pokemon_service_server_sdk::services::PokemonService; +use pokemon_service_server_sdk::operation_shape::GetPokemonSpecies; +use pokemon_service_server_sdk::service::PokemonService; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] From 6f8576ac50703151f999d028681efbafded6e249 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Mon, 5 Sep 2022 14:26:58 +0000 Subject: [PATCH 41/73] Update RFC --- design/src/rfcs/rfc0020_service_builder.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/design/src/rfcs/rfc0020_service_builder.md b/design/src/rfcs/rfc0020_service_builder.md index f2842569e7..e950010ba0 100644 --- a/design/src/rfcs/rfc0020_service_builder.md +++ b/design/src/rfcs/rfc0020_service_builder.md @@ -860,5 +860,6 @@ A toy implementation of the combined proposal is presented in [this PR](https:// - - [x] Add middleware primitives and error types to `rust-runtime/aws-smithy-http-server`. - -- [ ] Add code generation which outputs new service builder. +- [x] Add code generation which outputs new service builder. + - - [ ] Deprecate `OperationRegistryBuilder`, `OperationRegistry` and `Router`. From 1df5792821bfb6a39408828920f3011e301dbe79 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Mon, 5 Sep 2022 15:23:25 +0000 Subject: [PATCH 42/73] Change OperatioNotSet to MissingOperation --- .../server/smithy/generators/ServerServiceGeneratorV2.kt | 8 ++++---- rust-runtime/aws-smithy-http-server/src/operation/mod.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index e1c844ae41..28bf91bc6b 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -255,18 +255,18 @@ class ServerServiceGeneratorV2( ) } - // Returns a `Writable` comma delimited sequence of `OperationNotSet`. + // Returns a `Writable` comma delimited sequence of `MissingOperation`. private fun notSetGenerics(): Writable = writable { for (index in 1..allOperationShapes.size) { - rustTemplate("#{SmithyHttpServer}::operation::OperationNotSet,", *codegenScope) + rustTemplate("#{SmithyHttpServer}::operation::MissingOperation,", *codegenScope) } } - // Returns a `Writable` comma delimited sequence of `builder_field: OperationNotSet`. + // Returns a `Writable` comma delimited sequence of `builder_field: MissingOperation`. private fun notSetFields(): Writable = writable { for (fieldName in builderFieldNames()) { rustTemplate( - "$fieldName: #{SmithyHttpServer}::operation::OperationNotSet,", + "$fieldName: #{SmithyHttpServer}::operation::MissingOperation,", *codegenScope, ) } diff --git a/rust-runtime/aws-smithy-http-server/src/operation/mod.rs b/rust-runtime/aws-smithy-http-server/src/operation/mod.rs index e1a29f92f5..4fc4e50784 100644 --- a/rust-runtime/aws-smithy-http-server/src/operation/mod.rs +++ b/rust-runtime/aws-smithy-http-server/src/operation/mod.rs @@ -236,7 +236,7 @@ impl Operation> { } /// A marker struct indicating an [`Operation`] has not been set in a builder. -pub struct OperationNotSet; +pub struct MissingOperation; /// The operation [`Service`](tower::Service) has two classes of failure modes - those specified by the Smithy model /// and those associated with [`Service::poll_ready`](tower::Service::poll_ready). From d1b163952ef6411c18c9d3fde968f1092223817d Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Mon, 5 Sep 2022 20:44:11 +0000 Subject: [PATCH 43/73] Move Ext inference into setters --- .../generators/ServerServiceGeneratorV2.kt | 52 +++++++++++++------ .../src/operation/mod.rs | 3 -- .../src/operation/upgrade.rs | 3 ++ 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 28bf91bc6b..efc908e38f 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -100,8 +100,32 @@ class ServerServiceGeneratorV2( for ((index, pair) in builderFieldNames().zip(operationStructNames()).withIndex()) { val (fieldName, structName) = pair + // The new generics for the operation setter, using `NewOp` where appropriate. + val replacedOpGenerics = writable { + for ((innerIndex, item) in builderGenerics().withIndex()) { + if (innerIndex == index) { + rust("NewOp") + } else { + rust("$item") + } + rust(", ") + } + } + + // The new generics for the operation setter, using `NewOp` where appropriate. + val replacedExtGenerics = writable { + for ((innerIndex, item) in extensionTypes().withIndex()) { + if (innerIndex == index) { + rust("NewExts") + } else { + rust("$item") + } + rust(", ") + } + } + // The new generics for the handler setter, using `NewOp` where appropriate. - val replacedGenericsService = writable { + val replacedOpServiceGenerics = writable { for ((innerIndex, item) in builderGenerics().withIndex()) { if (innerIndex == index) { rustTemplate( @@ -117,15 +141,6 @@ class ServerServiceGeneratorV2( } } - // The new generics for the operation setter, using `NewOp` where appropriate. - val replacedGenerics = builderGenerics().withIndex().map { (innerIndex, item) -> - if (innerIndex == index) { - "NewOp" - } else { - item - } - } - // The assignment of fields, using value where appropriate. val switchedFields = writable { for ((innerIndex, innerFieldName) in builderFieldNames().withIndex()) { @@ -145,9 +160,9 @@ class ServerServiceGeneratorV2( /// [`$structName`](crate::operation_shape::$structName) using either /// [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationShapeExt::from_handler) or /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationShapeExt::from_service). - pub fn $fieldName(self, value: H) -> $builderName<#{ReplacedGenericsService:W} ${extensionTypes().joinToString(",")}> + pub fn $fieldName(self, value: H) -> $builderName<#{ReplacedOpServiceGenerics:W} #{ReplacedExtGenerics:W}> where - H: #{SmithyHttpServer}::operation::Handler + H: #{SmithyHttpServer}::operation::Handler { use #{SmithyHttpServer}::operation::OperationShapeExt; self.${fieldName}_operation(crate::operation_shape::$structName::from_handler(value)) @@ -159,7 +174,8 @@ class ServerServiceGeneratorV2( /// [`$structName`](crate::operation_shape::$structName) using either /// [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationShapeExt::from_handler) or /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationShapeExt::from_service). - pub fn ${fieldName}_operation(self, value: NewOp) -> $builderName<${(replacedGenerics + extensionTypes()).joinToString(",")}> { + pub fn ${fieldName}_operation(self, value: NewOp) -> $builderName<#{ReplacedOpGenerics:W} #{ReplacedExtGenerics:W}> + { $builderName { #{SwitchedFields:W} modifier: self.modifier, @@ -167,8 +183,11 @@ class ServerServiceGeneratorV2( } } """, + "Protocol" to protocol.markerStruct(), "SwitchedFields" to switchedFields, - "ReplacedGenericsService" to replacedGenericsService, + "ReplacedOpGenerics" to replacedOpGenerics, + "ReplacedOpServiceGenerics" to replacedOpServiceGenerics, + "ReplacedExtGenerics" to replacedExtGenerics, *codegenScope, ) @@ -205,6 +224,7 @@ class ServerServiceGeneratorV2( // Returns a `Writable` containing the builder struct definition and its implementations. private fun builder(): Writable = writable { + val structGenerics = (builderGenerics() + extensionTypes().map { "$it = ()" }).joinToString(",") val generics = (builderGenerics() + extensionTypes()).joinToString(",") // Generate router construction block. @@ -223,7 +243,7 @@ class ServerServiceGeneratorV2( /// The service builder for [`$serviceName`]. /// /// Constructed via [`$serviceName::builder`]. - pub struct $builderName<$generics, Modifier = #{SmithyHttpServer}::build_modifier::Identity> { + pub struct $builderName<$structGenerics, Modifier = #{SmithyHttpServer}::build_modifier::Identity> { #{Fields:W} modifier: Modifier, ##[allow(unused_parens)] @@ -289,7 +309,7 @@ class ServerServiceGeneratorV2( impl $serviceName<()> { /// Constructs a builder for [`$serviceName`]. - pub fn builder<${extensionTypes().joinToString(",")}>() -> $builderName<#{NotSetGenerics:W} ${extensionTypes().joinToString(",")}> { + pub fn builder() -> $builderName<#{NotSetGenerics:W}> { $builderName { #{NotSetFields:W} modifier: #{SmithyHttpServer}::build_modifier::Identity, diff --git a/rust-runtime/aws-smithy-http-server/src/operation/mod.rs b/rust-runtime/aws-smithy-http-server/src/operation/mod.rs index 4fc4e50784..5fec3a2f15 100644 --- a/rust-runtime/aws-smithy-http-server/src/operation/mod.rs +++ b/rust-runtime/aws-smithy-http-server/src/operation/mod.rs @@ -235,9 +235,6 @@ impl Operation> { } } -/// A marker struct indicating an [`Operation`] has not been set in a builder. -pub struct MissingOperation; - /// The operation [`Service`](tower::Service) has two classes of failure modes - those specified by the Smithy model /// and those associated with [`Service::poll_ready`](tower::Service::poll_ready). pub enum OperationError { diff --git a/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs b/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs index dace4974a8..5980901d0c 100644 --- a/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs +++ b/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs @@ -262,3 +262,6 @@ where layer.layer(inner) } } + +/// A marker struct indicating an [`Operation`] has not been set in a builder. +pub struct MissingOperation; From c75b97ffc3a78e01c8d3e6d305eb68f8e0364b94 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Tue, 6 Sep 2022 14:50:06 +0000 Subject: [PATCH 44/73] Use correct documentation idiom --- .../generators/ServerOperationGenerator.kt | 4 ++-- .../generators/ServerServiceGeneratorV2.kt | 22 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt index 520ad1345b..f981696e18 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt @@ -34,7 +34,7 @@ class ServerOperationGenerator( private val operationName = symbolProvider.toSymbol(operation).name.toPascalCase() private val operationId = operation.id - // Returns `std::convert::Infallible` if the model provides no errors. + /** Returns `std::convert::Infallible` if the model provides no errors. */ private fun operationError(): Writable = writable { if (operation.errors.isEmpty()) { rust("std::convert::Infallible") @@ -43,7 +43,7 @@ class ServerOperationGenerator( } } - // Returns a `Writable` containing the operation struct definition and its `OperationShape` implementation. + /** Returns a `Writable` containing the operation struct definition and its `OperationShape` implementation. */ private fun operation(): Writable = writable { val documentation = operation.getTrait()?.value if (documentation != null) { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index efc908e38f..a80fa8642f 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -58,21 +58,21 @@ class ServerServiceGeneratorV2( private val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } private val allOperationShapes = resourceOperationShapes + operationShapes - // Returns the sequence of builder generics: `Op1`, ..., `OpN`. + /** Returns the sequence of builder generics: `Op1`, ..., `OpN`. */ private fun builderGenerics(): Sequence = sequence { for (index in 1..allOperationShapes.size) { yield("Op$index") } } - // Returns the sequence of extension types: `Ext1`, ..., `ExtN`. + /** Returns the sequence of extension types: `Ext1`, ..., `ExtN`. */ private fun extensionTypes(): Sequence = sequence { for (index in 1..allOperationShapes.size) { yield("Exts$index") } } - // Returns the sequence of field names for the builder. + /** Returns the sequence of field names for the builder. */ private fun builderFieldNames(): Sequence = sequence { for (operation in allOperationShapes) { val field = RustReservedWords.escapeIfNeeded(symbolProvider.toSymbol(operation).name.toSnakeCase()) @@ -80,14 +80,14 @@ class ServerServiceGeneratorV2( } } - // Returns the sequence of operation struct names. + /** Returns the sequence of operation struct names. */ private fun operationStructNames(): Sequence = sequence { for (operation in allOperationShapes) { yield(symbolProvider.toSymbol(operation).name.toPascalCase()) } } - // Returns a `Writable` block of "field: Type" for the builder. + /** Returns a `Writable` block of "field: Type" for the builder. */ private fun builderFields(): Writable = writable { val zipped = builderFieldNames().zip(builderGenerics()) for ((name, type) in zipped) { @@ -95,7 +95,7 @@ class ServerServiceGeneratorV2( } } - // Returns a `Writable` block containing all the `Handler` and `Operation` setters for the builder. + /** Returns a `Writable` block containing all the `Handler` and `Operation` setters for the builder. */ private fun builderSetters(): Writable = writable { for ((index, pair) in builderFieldNames().zip(operationStructNames()).withIndex()) { val (fieldName, structName) = pair @@ -196,7 +196,7 @@ class ServerServiceGeneratorV2( } } - // Returns the constraints required for the `build` method. + /** Returns the constraints required for the `build` method. */ private fun buildConstraints(): Writable = writable { for (tuple in allOperationShapes.asSequence().zip(builderGenerics()).zip(extensionTypes())) { val (first, exts) = tuple @@ -222,7 +222,7 @@ class ServerServiceGeneratorV2( } } - // Returns a `Writable` containing the builder struct definition and its implementations. + /** Returns a `Writable` containing the builder struct definition and its implementations. */ private fun builder(): Writable = writable { val structGenerics = (builderGenerics() + extensionTypes().map { "$it = ()" }).joinToString(",") val generics = (builderGenerics() + extensionTypes()).joinToString(",") @@ -275,14 +275,14 @@ class ServerServiceGeneratorV2( ) } - // Returns a `Writable` comma delimited sequence of `MissingOperation`. + /** Returns a `Writable` comma delimited sequence of `MissingOperation`. */ private fun notSetGenerics(): Writable = writable { for (index in 1..allOperationShapes.size) { rustTemplate("#{SmithyHttpServer}::operation::MissingOperation,", *codegenScope) } } - // Returns a `Writable` comma delimited sequence of `builder_field: MissingOperation`. + /** Returns a `Writable` comma delimited sequence of `builder_field: MissingOperation`. */ private fun notSetFields(): Writable = writable { for (fieldName in builderFieldNames()) { rustTemplate( @@ -292,7 +292,7 @@ class ServerServiceGeneratorV2( } } - // Returns a `Writable` containing the service struct definition and its implementations. + /** Returns a `Writable` containing the service struct definition and its implementations. */ private fun struct(): Writable = writable { // Generate struct documentation. val documentation = service.getTrait()?.value From 38b8677a5ab6620373dd68cfc7b800d96dea81df Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Tue, 6 Sep 2022 15:00:39 +0000 Subject: [PATCH 45/73] Use documentShape --- .../smithy/generators/ServerOperationGenerator.kt | 10 +++------- .../smithy/generators/ServerServiceGeneratorV2.kt | 10 ++-------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt index f981696e18..b63a435b0d 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt @@ -6,17 +6,15 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.asType -import software.amazon.smithy.rust.codegen.rustlang.docs +import software.amazon.smithy.rust.codegen.rustlang.documentShape import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.rustlang.writable import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency import software.amazon.smithy.rust.codegen.smithy.CoreCodegenContext -import software.amazon.smithy.rust.codegen.util.getTrait import software.amazon.smithy.rust.codegen.util.toPascalCase class ServerOperationGenerator( @@ -30,6 +28,7 @@ class ServerOperationGenerator( ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType(), ) private val symbolProvider = coreCodegenContext.symbolProvider + private val model = coreCodegenContext.model private val operationName = symbolProvider.toSymbol(operation).name.toPascalCase() private val operationId = operation.id @@ -45,10 +44,7 @@ class ServerOperationGenerator( /** Returns a `Writable` containing the operation struct definition and its `OperationShape` implementation. */ private fun operation(): Writable = writable { - val documentation = operation.getTrait()?.value - if (documentation != null) { - docs(documentation.replace("#", "##")) - } + documentShape(operation, model) rustTemplate( """ diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index a80fa8642f..f1f3de9a8c 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -8,20 +8,18 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.shapes.ResourceShape import software.amazon.smithy.model.shapes.ServiceShape -import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.rustlang.RustReservedWords import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.asType -import software.amazon.smithy.rust.codegen.rustlang.docs +import software.amazon.smithy.rust.codegen.rustlang.documentShape import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.rustlang.writable import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocol import software.amazon.smithy.rust.codegen.smithy.CoreCodegenContext -import software.amazon.smithy.rust.codegen.util.getTrait import software.amazon.smithy.rust.codegen.util.orNull import software.amazon.smithy.rust.codegen.util.toPascalCase import software.amazon.smithy.rust.codegen.util.toSnakeCase @@ -294,11 +292,7 @@ class ServerServiceGeneratorV2( /** Returns a `Writable` containing the service struct definition and its implementations. */ private fun struct(): Writable = writable { - // Generate struct documentation. - val documentation = service.getTrait()?.value - if (documentation != null) { - docs(documentation.replace("#", "##")) - } + documentShape(service, model) rustTemplate( """ From 3ce36873c387e446f67d5056bdefcea77bbde201 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Tue, 6 Sep 2022 15:06:32 +0000 Subject: [PATCH 46/73] Remove excess argument in ServerServiceGeneratorV2 --- .../codegen/server/smithy/generators/ServerServiceGenerator.kt | 1 - .../server/smithy/generators/ServerServiceGeneratorV2.kt | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt index 9a60566cb1..c4504f3fd7 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt @@ -84,7 +84,6 @@ open class ServerServiceGenerator( val serverProtocol = ServerProtocol.fromCoreProtocol(coreCodegenContext, protocol) ServerServiceGeneratorV2( coreCodegenContext, - coreCodegenContext.serviceShape, serverProtocol, ).render(writer) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index f1f3de9a8c..ab4d94d037 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -7,7 +7,6 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.shapes.ResourceShape -import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.rust.codegen.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.rustlang.RustReservedWords import software.amazon.smithy.rust.codegen.rustlang.RustWriter @@ -26,7 +25,6 @@ import software.amazon.smithy.rust.codegen.util.toSnakeCase class ServerServiceGeneratorV2( coreCodegenContext: CoreCodegenContext, - private val service: ServiceShape, private val protocol: ServerProtocol, ) { private val runtimeConfig = coreCodegenContext.runtimeConfig @@ -42,6 +40,7 @@ class ServerServiceGeneratorV2( private val model = coreCodegenContext.model private val symbolProvider = coreCodegenContext.symbolProvider + private val service = coreCodegenContext.serviceShape private val serviceName = service.id.name private val builderName = "${serviceName}Builder" From 5e935452b9e2a6eabdd493019dcd8d71ce0a2160 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Tue, 6 Sep 2022 16:29:17 +0000 Subject: [PATCH 47/73] Fix documentation --- .../smithy/generators/ServerServiceGenerator.kt | 4 ++-- .../smithy/generators/ServerServiceGeneratorV2.kt | 8 +++----- .../smithy/generators/protocol/ServerProtocol.kt | 14 ++++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt index c4504f3fd7..001d716e28 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt @@ -68,7 +68,7 @@ open class ServerServiceGenerator( renderOperationRegistry(writer, operations) } - // TODO(Temporary): Remove, this is temporary. + // TODO(https://github.com/awslabs/smithy-rs/issues/1707): Remove, this is temporary. rustCrate.withModule( RustModule.public("operation_shape", hidden = true), ) { writer -> @@ -77,7 +77,7 @@ open class ServerServiceGenerator( } } - // TODO(Temporary): Remove, this is temporary. + // TODO(https://github.com/awslabs/smithy-rs/issues/1707): Remove, this is temporary. rustCrate.withModule( RustModule.public("service", hidden = true), ) { writer -> diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index ab4d94d037..d08c8bfe45 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -153,10 +153,8 @@ class ServerServiceGeneratorV2( """ /// Sets the [`$structName`](crate::operation_shape::$structName) operation. /// - /// This should be an [`Operation`](#{SmithyHttpServer}::operation::Operation) created from - /// [`$structName`](crate::operation_shape::$structName) using either - /// [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationShapeExt::from_handler) or - /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationShapeExt::from_service). + /// This should be a closure satisfying the [`Handler`](#{SmithyHttpServer}::operation::Handler) trait. + /// See the [operation module documentation](#{SmithyHttpServer}::operation) for more information. pub fn $fieldName(self, value: H) -> $builderName<#{ReplacedOpServiceGenerics:W} #{ReplacedExtGenerics:W}> where H: #{SmithyHttpServer}::operation::Handler @@ -188,7 +186,7 @@ class ServerServiceGeneratorV2( *codegenScope, ) - // Adds newline to between setters + // Adds newline between setters. rust("") } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index bbd30e4b79..4ea8544f76 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -38,22 +38,24 @@ fun allOperationShapes(service: ServiceShape, model: Model): List, model: Model): Writable companion object { - // Upgrades the core protocol to a `ServerProtocol`. + /** Upgrades the core protocol to a `ServerProtocol`. */ fun fromCoreProtocol(coreCodegenContext: CoreCodegenContext, protocol: Protocol): ServerProtocol { val serverProtocol = when (protocol) { is AwsJson -> ServerAwsJsonProtocol(coreCodegenContext, protocol) From 0da952a0fe7a5448421b2605c09aa1d02d8e7c2e Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Tue, 6 Sep 2022 17:14:49 +0000 Subject: [PATCH 48/73] Revert RustModule hidden argument --- .../generators/ServerServiceGenerator.kt | 16 ++++++++++++++-- .../smithy/rust/codegen/rustlang/RustModule.kt | 18 +++++++----------- .../generators/NestedAccessorGenerator.kt | 2 +- .../smithy/generators/PaginatorGenerator.kt | 1 - 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt index 001d716e28..3bc5c97a15 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt @@ -7,8 +7,11 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.model.knowledge.TopDownIndex import software.amazon.smithy.model.shapes.OperationShape +import software.amazon.smithy.rust.codegen.rustlang.Attribute +import software.amazon.smithy.rust.codegen.rustlang.RustMetadata import software.amazon.smithy.rust.codegen.rustlang.RustModule import software.amazon.smithy.rust.codegen.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.rustlang.Visibility import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocol import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocolTestGenerator import software.amazon.smithy.rust.codegen.smithy.CoreCodegenContext @@ -70,7 +73,16 @@ open class ServerServiceGenerator( // TODO(https://github.com/awslabs/smithy-rs/issues/1707): Remove, this is temporary. rustCrate.withModule( - RustModule.public("operation_shape", hidden = true), + RustModule( + "operation_shape", + RustMetadata( + visibility = Visibility.PUBLIC, + additionalAttributes = listOf( + Attribute.DocHidden, + ), + ), + null, + ), ) { writer -> for (operation in operations) { ServerOperationGenerator(coreCodegenContext, operation).render(writer) @@ -79,7 +91,7 @@ open class ServerServiceGenerator( // TODO(https://github.com/awslabs/smithy-rs/issues/1707): Remove, this is temporary. rustCrate.withModule( - RustModule.public("service", hidden = true), + RustModule("service", RustMetadata(visibility = Visibility.PUBLIC, additionalAttributes = listOf(Attribute.DocHidden)), null), ) { writer -> val serverProtocol = ServerProtocol.fromCoreProtocol(coreCodegenContext, protocol) ServerServiceGeneratorV2( diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustModule.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustModule.kt index a01e5c37d9..624f104903 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustModule.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/RustModule.kt @@ -5,27 +5,23 @@ package software.amazon.smithy.rust.codegen.rustlang -data class RustModule(val name: String, val rustMetadata: RustMetadata, val documentation: String?, val hidden: Boolean?) { +data class RustModule(val name: String, val rustMetadata: RustMetadata, val documentation: String?) { fun render(writer: RustWriter) { - if (hidden == true) { - writer.write("##[doc(hidden)]") - } documentation?.let { docs -> writer.docs(docs) } rustMetadata.render(writer) - writer.write("mod $name;") } companion object { - fun default(name: String, visibility: Visibility, documentation: String? = null, hidden: Boolean? = false): RustModule { - return RustModule(name, RustMetadata(visibility = visibility), documentation, hidden) + fun default(name: String, visibility: Visibility, documentation: String? = null): RustModule { + return RustModule(name, RustMetadata(visibility = visibility), documentation) } - fun public(name: String, documentation: String? = null, hidden: Boolean? = false): RustModule = - default(name, visibility = Visibility.PUBLIC, documentation, hidden) + fun public(name: String, documentation: String? = null): RustModule = + default(name, visibility = Visibility.PUBLIC, documentation = documentation) - fun private(name: String, documentation: String? = null, hidden: Boolean? = false): RustModule = - default(name, visibility = Visibility.PRIVATE, documentation, hidden) + fun private(name: String, documentation: String? = null): RustModule = + default(name, visibility = Visibility.PRIVATE, documentation = documentation) val Config = public("config", documentation = "Configuration for the service.") val Error = public("error", documentation = "Errors that can occur when calling the service.") diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/NestedAccessorGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/NestedAccessorGenerator.kt index 3a3df9c900..2651332671 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/NestedAccessorGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/NestedAccessorGenerator.kt @@ -24,7 +24,7 @@ import software.amazon.smithy.rust.codegen.smithy.protocols.lensName /** Generator for accessing nested fields through optional values **/ class NestedAccessorGenerator(private val symbolProvider: RustSymbolProvider) { - private val module = RustModule("lens", RustMetadata(visibility = Visibility.PUBLIC), "Generated accessors for nested fields", false) + private val module = RustModule("lens", RustMetadata(visibility = Visibility.PUBLIC), "Generated accessors for nested fields") /** * Generate an accessor on [root] that consumes [root] and returns an `Option` for the nested item diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/PaginatorGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/PaginatorGenerator.kt index e3fe51995e..5b817edc93 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/PaginatorGenerator.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/PaginatorGenerator.kt @@ -79,7 +79,6 @@ class PaginatorGenerator private constructor( "paginator", RustMetadata(visibility = Visibility.PUBLIC), documentation = "Paginators for the service", - false, ) private val inputType = symbolProvider.toSymbol(operation.inputShape(model)) From e0768f2161e95e0220a3d0bdaa35eb21236654be Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Tue, 6 Sep 2022 17:30:36 +0000 Subject: [PATCH 49/73] Revert changes to example --- .../examples/pokemon-service/src/main.rs | 26 ++++--------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs b/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs index bba5198c54..6d03d4cf2c 100644 --- a/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs +++ b/rust-runtime/aws-smithy-http-server/examples/pokemon-service/src/main.rs @@ -6,18 +6,15 @@ // This program is exported as a binary named `pokemon-service`. use std::{net::SocketAddr, sync::Arc}; -use aws_smithy_http_server::{operation::OperationShapeExt, AddExtensionLayer, Router}; +use aws_smithy_http_server::{AddExtensionLayer, Router}; use clap::Parser; -use tower::ServiceBuilder; -use tower_http::trace::TraceLayer; - use pokemon_service::{ capture_pokemon, empty_operation, get_pokemon_species, get_server_statistics, get_storage, health_check_operation, setup_tracing, State, }; use pokemon_service_server_sdk::operation_registry::OperationRegistryBuilder; -use pokemon_service_server_sdk::operation_shape::GetPokemonSpecies; -use pokemon_service_server_sdk::service::PokemonService; +use tower::ServiceBuilder; +use tower_http::trace::TraceLayer; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] @@ -34,9 +31,7 @@ struct Args { pub async fn main() { let args = Args::parse(); setup_tracing(); - - // Old builder - let _app: Router = OperationRegistryBuilder::default() + let app: Router = OperationRegistryBuilder::default() // Build a registry containing implementations to all the operations in the service. These // are async functions or async closures that take as input the operation's input and // return the operation's output. @@ -52,21 +47,10 @@ pub async fn main() { // implementation. .into(); - // New builder - let get_pokemon_species = GetPokemonSpecies::from_handler(get_pokemon_species); - let app = PokemonService::builder() - .get_pokemon_species_operation(get_pokemon_species) - .get_storage(get_storage) - .get_server_statistics(get_server_statistics) - .capture_pokemon_operation(capture_pokemon) - .empty_operation(empty_operation) - .health_check_operation(health_check_operation) - .build(); - // Setup shared state and middlewares. let shared_state = Arc::new(State::default()); let app = app.layer( - &ServiceBuilder::new() + ServiceBuilder::new() .layer(TraceLayer::new_for_http()) .layer(AddExtensionLayer::new(shared_state)), ); From fc26734dc5cd7776fd73288b1d2dcef649380fa8 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Tue, 6 Sep 2022 17:33:59 +0000 Subject: [PATCH 50/73] Improve formatting --- .../server/smithy/generators/protocol/ServerProtocol.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 4ea8544f76..47949b5b77 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -125,7 +125,8 @@ class ServerAwsJsonProtocol( """ #{Router}::from_iter([#{Pairs:W}]) """, - "Router" to routerType(), "Pairs" to pairs, + "Router" to routerType(), + "Pairs" to pairs, ) } } @@ -184,7 +185,8 @@ open class RestProtocol( """ #{Router}::from_iter([#{Pairs:W}]) """, - "Router" to routerType(), "Pairs" to pairs, + "Router" to routerType(), + "Pairs" to pairs, ) } } From dfad5f054fc376a6b9cb0ee475761b27411aa31c Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 7 Sep 2022 11:21:44 +0000 Subject: [PATCH 51/73] Inline ServerOperationGenerator::operation method --- .../smithy/generators/ServerOperationGenerator.kt | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt index b63a435b0d..5c2dafde00 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt @@ -42,8 +42,7 @@ class ServerOperationGenerator( } } - /** Returns a `Writable` containing the operation struct definition and its `OperationShape` implementation. */ - private fun operation(): Writable = writable { + fun render(writer: RustWriter) { documentShape(operation, model) rustTemplate( @@ -61,15 +60,6 @@ class ServerOperationGenerator( "Error" to operationError(), *codegenScope, ) - } - - fun render(writer: RustWriter) { - writer.rustTemplate( - """ - #{Operation:W} - """, - "Operation" to operation(), - ) // Adds newline to end of render writer.rust("") } From e5c0cd5d809cba7c5729cd09e9e51f06cf814c5f Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 7 Sep 2022 11:26:18 +0000 Subject: [PATCH 52/73] Remove "$x" --- .../server/smithy/generators/ServerServiceGeneratorV2.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index d08c8bfe45..8a9f68afb8 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -103,7 +103,7 @@ class ServerServiceGeneratorV2( if (innerIndex == index) { rust("NewOp") } else { - rust("$item") + rust(item) } rust(", ") } @@ -115,7 +115,7 @@ class ServerServiceGeneratorV2( if (innerIndex == index) { rust("NewExts") } else { - rust("$item") + rust(item) } rust(", ") } @@ -132,7 +132,7 @@ class ServerServiceGeneratorV2( *codegenScope, ) } else { - rust("$item") + rust(item) } rust(", ") } From 45a912682dfa69551dcb58d9680b3c58cfc49494 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 7 Sep 2022 11:28:54 +0000 Subject: [PATCH 53/73] Remove dependency on #{Tower}::Error --- .../server/smithy/generators/ServerServiceGeneratorV2.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 8a9f68afb8..f587a41f64 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -330,7 +330,7 @@ class ServerServiceGeneratorV2( where S: #{Tower}::Service<#{Http}::Request, Response = #{Http}::Response> + Clone, RespB: #{HttpBody}::Body + Send + 'static, - RespB::Error: Into<#{Tower}::BoxError> + RespB::Error: Into> { type Response = #{Http}::Response<#{SmithyHttpServer}::body::BoxBody>; type Error = S::Error; From f24de0c512f859f3ba833a9bd2cf87a3f6b55a3c Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 7 Sep 2022 11:29:41 +0000 Subject: [PATCH 54/73] Fix missing writer. --- .../server/smithy/generators/ServerOperationGenerator.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt index 5c2dafde00..8bdb4c35c1 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt @@ -43,9 +43,9 @@ class ServerOperationGenerator( } fun render(writer: RustWriter) { - documentShape(operation, model) + writer.documentShape(operation, model) - rustTemplate( + writer.rustTemplate( """ pub struct $operationName; From 0ce4d6ae840538eba57b90af0991ee11798289a3 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 7 Sep 2022 11:41:39 +0000 Subject: [PATCH 55/73] Remove unnecessary brackets --- .../generators/protocol/ServerProtocol.kt | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 47949b5b77..0ae472d465 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -78,9 +78,7 @@ class ServerAwsJsonProtocol( ) private val symbolProvider = coreCodegenContext.symbolProvider - override fun coreProtocol(): Protocol { - return coreProtocol - } + override fun coreProtocol() = coreProtocol override fun markerStruct(): RuntimeType { val name = when (coreProtocol.version) { @@ -95,9 +93,7 @@ class ServerAwsJsonProtocol( return RuntimeType(name, ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") } - override fun routerType(): RuntimeType { - return RuntimeType("AwsJsonRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::routers::aws_json") - } + override fun routerType() = RuntimeType("AwsJsonRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::routers::aws_json") override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = writable { val allOperationShapes = allOperationShapes(service, model) @@ -149,9 +145,7 @@ open class RestProtocol( PANIC("marker structure needs to specified") } - override fun routerType(): RuntimeType { - return RuntimeType("RestRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::routers::rest") - } + override fun routerType() = RuntimeType("RestRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::routers::rest") override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = writable { val allOperationShapes = allOperationShapes(service, model) @@ -195,16 +189,12 @@ class ServerRestJsonProtocol( coreCodegenContext: CoreCodegenContext, coreProtocol: RestJson, ) : RestProtocol(coreCodegenContext, coreProtocol) { - override fun markerStruct(): RuntimeType { - return RuntimeType("AwsRestJson1", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") - } + override fun markerStruct() = RuntimeType("AwsRestJson1", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") } class ServerRestXmlProtocol( coreCodegenContext: CoreCodegenContext, coreProtocol: RestXml, ) : RestProtocol(coreCodegenContext, coreProtocol) { - override fun markerStruct(): RuntimeType { - return RuntimeType("AwsRestXml", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") - } + override fun markerStruct() = RuntimeType("AwsRestXml", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") } From cb8958968d82cfb9b9247ed1d8af515e78e2b3c7 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 7 Sep 2022 13:20:15 +0000 Subject: [PATCH 56/73] Remove unnecessary brackets --- .../smithy/generators/protocol/ServerProtocol.kt | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 0ae472d465..8603a01557 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -56,14 +56,11 @@ interface ServerProtocol { companion object { /** Upgrades the core protocol to a `ServerProtocol`. */ - fun fromCoreProtocol(coreCodegenContext: CoreCodegenContext, protocol: Protocol): ServerProtocol { - val serverProtocol = when (protocol) { - is AwsJson -> ServerAwsJsonProtocol(coreCodegenContext, protocol) - is RestJson -> ServerRestJsonProtocol(coreCodegenContext, protocol) - is RestXml -> ServerRestXmlProtocol(coreCodegenContext, protocol) - else -> throw IllegalStateException("unsupported protocol") - } - return serverProtocol + fun fromCoreProtocol(coreCodegenContext: CoreCodegenContext, protocol: Protocol) = when (protocol) { + is AwsJson -> ServerAwsJsonProtocol(coreCodegenContext, protocol) + is RestJson -> ServerRestJsonProtocol(coreCodegenContext, protocol) + is RestXml -> ServerRestXmlProtocol(coreCodegenContext, protocol) + else -> throw IllegalStateException("unsupported protocol") } } } From 14e094d0831c8c575c0981177a01178ec1efbd9a Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 7 Sep 2022 13:21:27 +0000 Subject: [PATCH 57/73] Use double quotes inline --- .../server/smithy/generators/protocol/ServerProtocol.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 8603a01557..1958875e7a 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -22,7 +22,6 @@ import software.amazon.smithy.rust.codegen.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.smithy.protocols.RestJson import software.amazon.smithy.rust.codegen.smithy.protocols.RestXml import software.amazon.smithy.rust.codegen.util.PANIC -import software.amazon.smithy.rust.codegen.util.dq import software.amazon.smithy.rust.codegen.util.orNull fun allOperationShapes(service: ServiceShape, model: Model): List { @@ -101,11 +100,10 @@ class ServerAwsJsonProtocol( val pairs = writable { for ((operation, operationValue) in allOperationShapes.zip(operationValues)) { val operationName = symbolProvider.toSymbol(operation).name - val key = "$serviceName.$operationName".dq() rustTemplate( """ ( - String::from($key), + String::from(""$serviceName.$operationName""), #{SmithyHttpServer}::routing::Route::new(#{OperationValue:W}) ), """, From d1c5657d181fcbcc3bd7b5a1321f45f17aac14dc Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 7 Sep 2022 14:35:33 +0000 Subject: [PATCH 58/73] Use inheritance --- .../generators/ServerServiceGenerator.kt | 2 +- .../generators/protocol/ServerProtocol.kt | 150 ++++++++++-------- .../server/smithy/protocols/ServerAwsJson.kt | 2 +- .../ServerHttpBoundProtocolGenerator.kt | 2 +- .../rust/codegen/smithy/protocols/AwsJson.kt | 2 +- .../rust/codegen/smithy/protocols/RestJson.kt | 2 +- .../rust/codegen/smithy/protocols/RestXml.kt | 2 +- 7 files changed, 86 insertions(+), 76 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt index 3bc5c97a15..34fafbe77b 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt @@ -93,7 +93,7 @@ open class ServerServiceGenerator( rustCrate.withModule( RustModule("service", RustMetadata(visibility = Visibility.PUBLIC, additionalAttributes = listOf(Attribute.DocHidden)), null), ) { writer -> - val serverProtocol = ServerProtocol.fromCoreProtocol(coreCodegenContext, protocol) + val serverProtocol = ServerProtocol.fromCoreProtocol(protocol) ServerServiceGeneratorV2( coreCodegenContext, serverProtocol, diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 1958875e7a..07483192f1 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -15,13 +15,13 @@ import software.amazon.smithy.rust.codegen.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.rustlang.writable import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency import software.amazon.smithy.rust.codegen.smithy.CoreCodegenContext +import software.amazon.smithy.rust.codegen.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.smithy.RuntimeType import software.amazon.smithy.rust.codegen.smithy.protocols.AwsJson import software.amazon.smithy.rust.codegen.smithy.protocols.AwsJsonVersion import software.amazon.smithy.rust.codegen.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.smithy.protocols.RestJson import software.amazon.smithy.rust.codegen.smithy.protocols.RestXml -import software.amazon.smithy.rust.codegen.util.PANIC import software.amazon.smithy.rust.codegen.util.orNull fun allOperationShapes(service: ServiceShape, model: Model): List { @@ -36,10 +36,7 @@ fun allOperationShapes(service: ServiceShape, model: Model): List ServerAwsJsonProtocol(coreCodegenContext, protocol) - is RestJson -> ServerRestJsonProtocol(coreCodegenContext, protocol) - is RestXml -> ServerRestXmlProtocol(coreCodegenContext, protocol) + fun fromCoreProtocol(protocol: Protocol): ServerProtocol = when (protocol) { + is AwsJson -> ServerAwsJsonProtocol.fromCoreProtocol(protocol) + is RestJson -> ServerRestJsonProtocol.fromCoreProtocol(protocol) + is RestXml -> ServerRestXmlProtocol.fromCoreProtocol(protocol) else -> throw IllegalStateException("unsupported protocol") } } @@ -66,18 +63,22 @@ interface ServerProtocol { class ServerAwsJsonProtocol( coreCodegenContext: CoreCodegenContext, - private val coreProtocol: AwsJson, -) : ServerProtocol { + awsJsonVersion: AwsJsonVersion, +) : AwsJson(coreCodegenContext, awsJsonVersion), ServerProtocol { private val runtimeConfig = coreCodegenContext.runtimeConfig private val codegenScope = arrayOf( "SmithyHttpServer" to ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType(), ) private val symbolProvider = coreCodegenContext.symbolProvider - override fun coreProtocol() = coreProtocol + companion object { + fun fromCoreProtocol(awsJson: AwsJson): ServerAwsJsonProtocol { + return ServerAwsJsonProtocol(awsJson.coreCodegenContext, awsJson.version) + } + } override fun markerStruct(): RuntimeType { - val name = when (coreProtocol.version) { + val name = when (version) { is AwsJsonVersion.Json10 -> { "AwsJson10" } @@ -122,74 +123,83 @@ class ServerAwsJsonProtocol( } } -open class RestProtocol( - coreCodegenContext: CoreCodegenContext, - private val coreProtocol: Protocol, -) : ServerProtocol { - val runtimeConfig = coreCodegenContext.runtimeConfig - private val codegenScope = arrayOf( - "SmithyHttpServer" to ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType(), - ) - private val symbolProvider = coreCodegenContext.symbolProvider - - override fun coreProtocol(): Protocol { - return coreProtocol - } - - override fun markerStruct(): RuntimeType { - PANIC("marker structure needs to specified") - } - - override fun routerType() = RuntimeType("RestRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::routers::rest") - - override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = writable { - val allOperationShapes = allOperationShapes(service, model) +private fun restRouterType(runtimeConfig: RuntimeConfig) = RuntimeType("RestRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::routers::rest") - // TODO(restore): This causes a panic: "symbol visitor should not be invoked in service shapes" - // val serviceName = symbolProvider.toSymbol(service).name - val serviceName = service.id.name - val pairs = writable { - for ((operationShape, operationValue) in allOperationShapes.zip(operationValues)) { - val operationName = symbolProvider.toSymbol(operationShape).name - val key = coreProtocol.serverRouterRequestSpec( - operationShape, - operationName, - serviceName, - ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType().member("routing::request_spec"), - ) - rustTemplate( - """ - ( - #{Key:W}, - #{SmithyHttpServer}::routing::Route::new(#{OperationValue:W}) - ), - """, - "Key" to key, - "OperationValue" to operationValue, - *codegenScope, - ) - } +private fun restRouterConstruction( + protocol: ServerProtocol, + service: ServiceShape, + operationValues: Iterable, + model: Model, + coreCodegenContext: CoreCodegenContext, +): Writable = writable { + val allOperationShapes = allOperationShapes(service, model) + + // TODO(restore): This causes a panic: "symbol visitor should not be invoked in service shapes" + // val serviceName = symbolProvider.toSymbol(service).name + val serviceName = service.id.name + val pairs = writable { + for ((operationShape, operationValue) in allOperationShapes.zip(operationValues)) { + val operationName = coreCodegenContext.symbolProvider.toSymbol(operationShape).name + val key = protocol.serverRouterRequestSpec( + operationShape, + operationName, + serviceName, + ServerCargoDependency.SmithyHttpServer(coreCodegenContext.runtimeConfig).asType().member("routing::request_spec"), + ) + rustTemplate( + """ + ( + #{Key:W}, + #{SmithyHttpServer}::routing::Route::new(#{OperationValue:W}) + ), + """, + "Key" to key, + "OperationValue" to operationValue, + "SmithyHttpServer" to ServerCargoDependency.SmithyHttpServer(coreCodegenContext.runtimeConfig).asType(), + ) } - rustTemplate( - """ - #{Router}::from_iter([#{Pairs:W}]) - """, - "Router" to routerType(), - "Pairs" to pairs, - ) } + rustTemplate( + """ + #{Router}::from_iter([#{Pairs:W}]) + """, + "Router" to protocol.routerType(), + "Pairs" to pairs, + ) } class ServerRestJsonProtocol( coreCodegenContext: CoreCodegenContext, - coreProtocol: RestJson, -) : RestProtocol(coreCodegenContext, coreProtocol) { +) : RestJson(coreCodegenContext), ServerProtocol { + val runtimeConfig = coreCodegenContext.runtimeConfig + + companion object { + fun fromCoreProtocol(restJson: RestJson): ServerRestJsonProtocol { + return ServerRestJsonProtocol(restJson.coreCodegenContext) + } + } + override fun markerStruct() = RuntimeType("AwsRestJson1", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") + + override fun routerType() = restRouterType(runtimeConfig) + + override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = restRouterConstruction(this, service, operationValues, model, coreCodegenContext) } class ServerRestXmlProtocol( coreCodegenContext: CoreCodegenContext, - coreProtocol: RestXml, -) : RestProtocol(coreCodegenContext, coreProtocol) { +) : RestXml(coreCodegenContext), ServerProtocol { + val runtimeConfig = coreCodegenContext.runtimeConfig + + companion object { + fun fromCoreProtocol(restXml: RestXml): ServerRestXmlProtocol { + return ServerRestXmlProtocol(restXml.coreCodegenContext) + } + } + override fun markerStruct() = RuntimeType("AwsRestXml", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") + + override fun routerType() = restRouterType(runtimeConfig) + + override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = restRouterConstruction(this, service, operationValues, model, coreCodegenContext) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerAwsJson.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerAwsJson.kt index 6cd78583c1..db2e380387 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerAwsJson.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerAwsJson.kt @@ -95,7 +95,7 @@ class ServerAwsJsonSerializerGenerator( ) : StructuredDataSerializerGenerator by jsonSerializerGenerator class ServerAwsJson( - private val coreCodegenContext: CoreCodegenContext, + coreCodegenContext: CoreCodegenContext, private val awsJsonVersion: AwsJsonVersion, ) : AwsJson(coreCodegenContext, awsJsonVersion) { override fun structuredDataSerializer(operationShape: OperationShape): StructuredDataSerializerGenerator = diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt index 9c90f19dc9..c88857b93c 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt @@ -120,7 +120,7 @@ private class ServerHttpBoundProtocolTraitImplGenerator( private val operationDeserModule = RustModule.private("operation_deser") private val operationSerModule = RustModule.private("operation_ser") private val typeConversionGenerator = TypeConversionGenerator(model, symbolProvider, runtimeConfig) - private val serverProtocol = ServerProtocol.fromCoreProtocol(codegenContext, protocol) + private val serverProtocol = ServerProtocol.fromCoreProtocol(protocol) private val codegenScope = arrayOf( "AsyncTrait" to ServerCargoDependency.AsyncTrait.asType(), diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson.kt index 4f25b82f00..0b269fb587 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson.kt @@ -129,7 +129,7 @@ class AwsJsonSerializerGenerator( } open class AwsJson( - private val coreCodegenContext: CoreCodegenContext, + val coreCodegenContext: CoreCodegenContext, private val awsJsonVersion: AwsJsonVersion, ) : Protocol { private val runtimeConfig = coreCodegenContext.runtimeConfig diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/RestJson.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/RestJson.kt index 48e8a5bb7b..d44a7c37a9 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/RestJson.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/RestJson.kt @@ -87,7 +87,7 @@ class RestJsonHttpBindingResolver( } } -class RestJson(private val coreCodegenContext: CoreCodegenContext) : Protocol { +open class RestJson(val coreCodegenContext: CoreCodegenContext) : Protocol { private val runtimeConfig = coreCodegenContext.runtimeConfig private val errorScope = arrayOf( "Bytes" to RuntimeType.Bytes, diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/RestXml.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/RestXml.kt index 815c923520..81a092f9ab 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/RestXml.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/RestXml.kt @@ -53,7 +53,7 @@ class RestXmlFactory( } } -open class RestXml(private val coreCodegenContext: CoreCodegenContext) : Protocol { +open class RestXml(val coreCodegenContext: CoreCodegenContext) : Protocol { private val restXml = coreCodegenContext.serviceShape.expectTrait() private val runtimeConfig = coreCodegenContext.runtimeConfig private val errorScope = arrayOf( From 48f2680503f9dbd4972bff3415fcbb01efbc8b15 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 7 Sep 2022 14:55:51 +0000 Subject: [PATCH 59/73] Remove excess brackets --- .../server/smithy/generators/protocol/ServerProtocol.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 07483192f1..7534ca154b 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -72,9 +72,7 @@ class ServerAwsJsonProtocol( private val symbolProvider = coreCodegenContext.symbolProvider companion object { - fun fromCoreProtocol(awsJson: AwsJson): ServerAwsJsonProtocol { - return ServerAwsJsonProtocol(awsJson.coreCodegenContext, awsJson.version) - } + fun fromCoreProtocol(awsJson: AwsJson): ServerAwsJsonProtocol = ServerAwsJsonProtocol(awsJson.coreCodegenContext, awsJson.version) } override fun markerStruct(): RuntimeType { @@ -174,9 +172,7 @@ class ServerRestJsonProtocol( val runtimeConfig = coreCodegenContext.runtimeConfig companion object { - fun fromCoreProtocol(restJson: RestJson): ServerRestJsonProtocol { - return ServerRestJsonProtocol(restJson.coreCodegenContext) - } + fun fromCoreProtocol(restJson: RestJson): ServerRestJsonProtocol = ServerRestJsonProtocol(restJson.coreCodegenContext) } override fun markerStruct() = RuntimeType("AwsRestJson1", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") From 59c82d75d9e4e5cb697096150f45b9f6f9503453 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 7 Sep 2022 15:03:57 +0000 Subject: [PATCH 60/73] Fix double quotes --- .../codegen/server/smithy/generators/protocol/ServerProtocol.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 1958875e7a..4441deb80e 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -103,7 +103,7 @@ class ServerAwsJsonProtocol( rustTemplate( """ ( - String::from(""$serviceName.$operationName""), + String::from("$serviceName.$operationName"), #{SmithyHttpServer}::routing::Route::new(#{OperationValue:W}) ), """, From e35a7f1a404432605d9ced31c701917801e2714b Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 7 Sep 2022 15:47:10 +0000 Subject: [PATCH 61/73] Add general ServerRuntimeType.Protocol --- .../rust/codegen/server/smithy/ServerRuntimeType.kt | 6 ++++-- .../server/smithy/generators/protocol/ServerProtocol.kt | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRuntimeType.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRuntimeType.kt index e792fe4255..a2eaf3075d 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRuntimeType.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRuntimeType.kt @@ -39,6 +39,8 @@ object ServerRuntimeType { fun ResponseRejection(runtimeConfig: RuntimeConfig) = RuntimeType("ResponseRejection", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::rejection") - fun Protocol(runtimeConfig: RuntimeConfig) = - RuntimeType("Protocol", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") + fun Protocol(name: String, runtimeConfig: RuntimeConfig) = + RuntimeType(name, ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") + + fun Protocol(runtimeConfig: RuntimeConfig) = Protocol("Protocol", runtimeConfig) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 4441deb80e..2a69aa0547 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -14,6 +14,7 @@ import software.amazon.smithy.rust.codegen.rustlang.asType import software.amazon.smithy.rust.codegen.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.rustlang.writable import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency +import software.amazon.smithy.rust.codegen.server.smithy.ServerRuntimeType import software.amazon.smithy.rust.codegen.smithy.CoreCodegenContext import software.amazon.smithy.rust.codegen.smithy.RuntimeType import software.amazon.smithy.rust.codegen.smithy.protocols.AwsJson @@ -84,9 +85,8 @@ class ServerAwsJsonProtocol( is AwsJsonVersion.Json11 -> { "AwsJson11" } - else -> throw IllegalStateException() } - return RuntimeType(name, ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") + return ServerRuntimeType.Protocol(name, runtimeConfig) } override fun routerType() = RuntimeType("AwsJsonRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::routers::aws_json") @@ -184,12 +184,12 @@ class ServerRestJsonProtocol( coreCodegenContext: CoreCodegenContext, coreProtocol: RestJson, ) : RestProtocol(coreCodegenContext, coreProtocol) { - override fun markerStruct() = RuntimeType("AwsRestJson1", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") + override fun markerStruct() = ServerRuntimeType.Protocol("AwsRestJson1", runtimeConfig) } class ServerRestXmlProtocol( coreCodegenContext: CoreCodegenContext, coreProtocol: RestXml, ) : RestProtocol(coreCodegenContext, coreProtocol) { - override fun markerStruct() = RuntimeType("AwsRestXml", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::protocols") + override fun markerStruct() = ServerRuntimeType.Protocol("AwsRestXml", runtimeConfig) } From 5399ae3d0e432d8910d53f552a0eb1cd6a6801d7 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 7 Sep 2022 21:08:09 +0000 Subject: [PATCH 62/73] Improve TODOs --- .../server/smithy/generators/ServerServiceGeneratorV2.kt | 3 ++- .../server/smithy/generators/protocol/ServerProtocol.kt | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index f587a41f64..22947a236c 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -196,7 +196,8 @@ class ServerServiceGeneratorV2( for (tuple in allOperationShapes.asSequence().zip(builderGenerics()).zip(extensionTypes())) { val (first, exts) = tuple val (operation, type) = first - // TODO(Relax): The `Error = Infallible` is an excess requirement to stay at parity with existing builder. + // TODO(https://github.com/awslabs/smithy-rs/issues/1713#issue-1365169734): The `Error = Infallible` is an + // excess requirement to stay at parity with existing builder. rustTemplate( """ $type: #{SmithyHttpServer}::operation::Upgradable< diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 4e62f9c8b8..516edde201 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -44,7 +44,6 @@ interface ServerProtocol : Protocol { /** Returns the Rust router type. */ fun routerType(): RuntimeType - // TODO(Decouple): Perhaps this should lean on a Rust interface. /** * Returns the construction of the `routerType` given a `ServiceShape`, a collection of operation values * (`self.operation_name`, ...), and the `Model`. From a2ab7e78c93d213a0714cdfc9ffb20f5f4b630e3 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Wed, 7 Sep 2022 21:24:26 +0000 Subject: [PATCH 63/73] Remove BuildModifier --- .../generators/ServerServiceGeneratorV2.kt | 10 +++----- .../src/build_modifier.rs | 24 ------------------ .../aws-smithy-http-server/src/lib.rs | 2 -- .../src/operation/upgrade.rs | 25 ++++++++----------- 4 files changed, 13 insertions(+), 48 deletions(-) delete mode 100644 rust-runtime/aws-smithy-http-server/src/build_modifier.rs diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 22947a236c..330f14c5f0 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -173,7 +173,6 @@ class ServerServiceGeneratorV2( { $builderName { #{SwitchedFields:W} - modifier: self.modifier, _exts: std::marker::PhantomData } } @@ -205,7 +204,6 @@ class ServerServiceGeneratorV2( crate::operation_shape::${symbolProvider.toSymbol(operation).name.toPascalCase()}, $exts, B, - Modifier >, $type::Service: Clone + Send + 'static, <$type::Service as #{Tower}::Service<#{Http}::Request>>::Future: Send + 'static, @@ -229,7 +227,7 @@ class ServerServiceGeneratorV2( service, builderFieldNames() .map { - writable { rustTemplate("self.$it.upgrade(&self.modifier)") } + writable { rustTemplate("self.$it.upgrade()") } } .asIterable(), model, @@ -239,9 +237,8 @@ class ServerServiceGeneratorV2( /// The service builder for [`$serviceName`]. /// /// Constructed via [`$serviceName::builder`]. - pub struct $builderName<$structGenerics, Modifier = #{SmithyHttpServer}::build_modifier::Identity> { + pub struct $builderName<$structGenerics> { #{Fields:W} - modifier: Modifier, ##[allow(unused_parens)] _exts: std::marker::PhantomData<(${extensionTypes().joinToString(",")})> } @@ -250,7 +247,7 @@ class ServerServiceGeneratorV2( #{Setters:W} } - impl<$generics, Modifier> $builderName<$generics, Modifier> { + impl<$generics> $builderName<$generics> { /// Constructs a [`$serviceName`] from the arguments provided to the builder. pub fn build(self) -> $serviceName<#{SmithyHttpServer}::routing::Route> where @@ -304,7 +301,6 @@ class ServerServiceGeneratorV2( pub fn builder() -> $builderName<#{NotSetGenerics:W}> { $builderName { #{NotSetFields:W} - modifier: #{SmithyHttpServer}::build_modifier::Identity, _exts: std::marker::PhantomData } } diff --git a/rust-runtime/aws-smithy-http-server/src/build_modifier.rs b/rust-runtime/aws-smithy-http-server/src/build_modifier.rs deleted file mode 100644 index a280f92b73..0000000000 --- a/rust-runtime/aws-smithy-http-server/src/build_modifier.rs +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use crate::operation::Operation; - -pub trait BuildModifier { - type Service; - type Layer; - - fn modify(&self, operation: Operation) -> Operation; -} - -pub struct Identity; - -impl BuildModifier for Identity { - type Service = S; - type Layer = L; - - fn modify(&self, operation: Operation) -> Operation { - operation - } -} diff --git a/rust-runtime/aws-smithy-http-server/src/lib.rs b/rust-runtime/aws-smithy-http-server/src/lib.rs index a9e84ad25e..b032060bbc 100644 --- a/rust-runtime/aws-smithy-http-server/src/lib.rs +++ b/rust-runtime/aws-smithy-http-server/src/lib.rs @@ -11,8 +11,6 @@ pub(crate) mod macros; pub mod body; -#[doc(hidden)] -pub mod build_modifier; pub(crate) mod error; pub mod extension; #[doc(hidden)] diff --git a/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs b/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs index 5980901d0c..c5e5ca668e 100644 --- a/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs +++ b/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs @@ -16,7 +16,6 @@ use tower::{layer::util::Stack, Layer, Service}; use crate::{ body::BoxBody, - build_modifier::BuildModifier, request::{FromParts, FromRequest}, response::IntoResponse, }; @@ -216,14 +215,14 @@ where /// Provides an interface to convert a representation of an operation to a HTTP [`Service`](tower::Service) with /// canonical associated types. -pub trait Upgradable { +pub trait Upgradable { type Service: Service, Response = http::Response>; /// Performs an upgrade from a representation of an operation to a HTTP [`Service`](tower::Service). - fn upgrade(self, modify: &Modify) -> Self::Service; + fn upgrade(self) -> Self::Service; } -impl Upgradable for Operation +impl Upgradable for Operation where // `Op` is used to specify the operation shape Op: OperationShape, @@ -241,25 +240,21 @@ where // The signature of the inner service is correct S: Service<(Op::Input, Exts), Response = Op::Output, Error = OperationError> + Clone, - // Modifier applies correctly to `Operation` - Modify: BuildModifier, - Modify::Layer: Layer>, + // Layer applies correctly to `Upgrade` + L: Layer>, // The signature of the output is correct - >>::Service: - Service, Response = http::Response>, + L::Service: Service, Response = http::Response>, { - type Service = >>::Service; + type Service = L::Service; /// Takes the [`Operation`](Operation), applies [`ModifyBuild::modify`] to it, applies [`UpgradeLayer`] to /// the modified `S`, then finally applies the modified `L`. /// /// The composition is made explicit in the method constraints and return type. - fn upgrade(self, modify: &Modify) -> Self::Service { - let Operation { inner, layer } = modify.modify(self); - - let layer = Stack::new(UpgradeLayer::new(), layer); - layer.layer(inner) + fn upgrade(self) -> Self::Service { + let layer = Stack::new(UpgradeLayer::new(), self.layer); + layer.layer(self.inner) } } From a048715f778e642ba1de286737d08611aa6ec1b8 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Thu, 8 Sep 2022 21:22:03 +0000 Subject: [PATCH 64/73] Use TopDownIndex to collect all operations --- .../generators/ServerServiceGeneratorV2.kt | 29 +++++--------- .../generators/protocol/ServerProtocol.kt | 39 +++++++------------ 2 files changed, 23 insertions(+), 45 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 330f14c5f0..e64b830f99 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -5,8 +5,7 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators -import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.ResourceShape +import software.amazon.smithy.model.knowledge.TopDownIndex import software.amazon.smithy.rust.codegen.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.rustlang.RustReservedWords import software.amazon.smithy.rust.codegen.rustlang.RustWriter @@ -19,7 +18,6 @@ import software.amazon.smithy.rust.codegen.rustlang.writable import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocol import software.amazon.smithy.rust.codegen.smithy.CoreCodegenContext -import software.amazon.smithy.rust.codegen.util.orNull import software.amazon.smithy.rust.codegen.util.toPascalCase import software.amazon.smithy.rust.codegen.util.toSnakeCase @@ -45,33 +43,26 @@ class ServerServiceGeneratorV2( private val builderName = "${serviceName}Builder" // Calculate all `operationShape`s contained within the `ServiceShape`. - private val resourceOperationShapes = service - .resources - .mapNotNull { model.getShape(it).orNull() } - .mapNotNull { it as? ResourceShape } - .flatMap { it.allOperations } - .mapNotNull { model.getShape(it).orNull() } - .mapNotNull { it as? OperationShape } - private val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } - private val allOperationShapes = resourceOperationShapes + operationShapes + private val index = TopDownIndex.of(coreCodegenContext.model) + private val operations = index.getContainedOperations(coreCodegenContext.serviceShape).sortedBy { it.id } /** Returns the sequence of builder generics: `Op1`, ..., `OpN`. */ private fun builderGenerics(): Sequence = sequence { - for (index in 1..allOperationShapes.size) { + for (index in 1..operations.size) { yield("Op$index") } } /** Returns the sequence of extension types: `Ext1`, ..., `ExtN`. */ private fun extensionTypes(): Sequence = sequence { - for (index in 1..allOperationShapes.size) { + for (index in 1..operations.size) { yield("Exts$index") } } /** Returns the sequence of field names for the builder. */ private fun builderFieldNames(): Sequence = sequence { - for (operation in allOperationShapes) { + for (operation in operations) { val field = RustReservedWords.escapeIfNeeded(symbolProvider.toSymbol(operation).name.toSnakeCase()) yield(field) } @@ -79,7 +70,7 @@ class ServerServiceGeneratorV2( /** Returns the sequence of operation struct names. */ private fun operationStructNames(): Sequence = sequence { - for (operation in allOperationShapes) { + for (operation in operations) { yield(symbolProvider.toSymbol(operation).name.toPascalCase()) } } @@ -192,7 +183,7 @@ class ServerServiceGeneratorV2( /** Returns the constraints required for the `build` method. */ private fun buildConstraints(): Writable = writable { - for (tuple in allOperationShapes.asSequence().zip(builderGenerics()).zip(extensionTypes())) { + for (tuple in operations.asSequence().zip(builderGenerics()).zip(extensionTypes())) { val (first, exts) = tuple val (operation, type) = first // TODO(https://github.com/awslabs/smithy-rs/issues/1713#issue-1365169734): The `Error = Infallible` is an @@ -224,13 +215,11 @@ class ServerServiceGeneratorV2( // Generate router construction block. val router = protocol .routerConstruction( - service, builderFieldNames() .map { writable { rustTemplate("self.$it.upgrade()") } } .asIterable(), - model, ) rustTemplate( """ @@ -270,7 +259,7 @@ class ServerServiceGeneratorV2( /** Returns a `Writable` comma delimited sequence of `MissingOperation`. */ private fun notSetGenerics(): Writable = writable { - for (index in 1..allOperationShapes.size) { + for (index in 1..operations.size) { rustTemplate("#{SmithyHttpServer}::operation::MissingOperation,", *codegenScope) } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 516edde201..6549497ce3 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -5,10 +5,8 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators.protocol -import software.amazon.smithy.model.Model +import software.amazon.smithy.model.knowledge.TopDownIndex import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.model.shapes.ResourceShape -import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.asType import software.amazon.smithy.rust.codegen.rustlang.rustTemplate @@ -23,18 +21,10 @@ import software.amazon.smithy.rust.codegen.smithy.protocols.AwsJsonVersion import software.amazon.smithy.rust.codegen.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.smithy.protocols.RestJson import software.amazon.smithy.rust.codegen.smithy.protocols.RestXml -import software.amazon.smithy.rust.codegen.util.orNull - -fun allOperationShapes(service: ServiceShape, model: Model): List { - val resourceOperationShapes = service - .resources - .mapNotNull { model.getShape(it).orNull() } - .mapNotNull { it as? ResourceShape } - .flatMap { it.allOperations } - .mapNotNull { model.getShape(it).orNull() } - .mapNotNull { it as? OperationShape } - val operationShapes = service.operations.mapNotNull { model.getShape(it).orNull() }.mapNotNull { it as? OperationShape } - return resourceOperationShapes + operationShapes + +private fun allOperations(coreCodegenContext: CoreCodegenContext): List { + val index = TopDownIndex.of(coreCodegenContext.model) + return index.getContainedOperations(coreCodegenContext.serviceShape).sortedBy { it.id } } interface ServerProtocol : Protocol { @@ -48,7 +38,7 @@ interface ServerProtocol : Protocol { * Returns the construction of the `routerType` given a `ServiceShape`, a collection of operation values * (`self.operation_name`, ...), and the `Model`. */ - fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable + fun routerConstruction(operationValues: Iterable): Writable companion object { /** Upgrades the core protocol to a `ServerProtocol`. */ @@ -70,6 +60,7 @@ class ServerAwsJsonProtocol( "SmithyHttpServer" to ServerCargoDependency.SmithyHttpServer(runtimeConfig).asType(), ) private val symbolProvider = coreCodegenContext.symbolProvider + private val service = coreCodegenContext.serviceShape companion object { fun fromCoreProtocol(awsJson: AwsJson): ServerAwsJsonProtocol = ServerAwsJsonProtocol(awsJson.coreCodegenContext, awsJson.version) @@ -89,8 +80,8 @@ class ServerAwsJsonProtocol( override fun routerType() = RuntimeType("AwsJsonRouter", ServerCargoDependency.SmithyHttpServer(runtimeConfig), "${runtimeConfig.crateSrcPrefix}_http_server::routing::routers::aws_json") - override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = writable { - val allOperationShapes = allOperationShapes(service, model) + override fun routerConstruction(operationValues: Iterable): Writable = writable { + val allOperationShapes = allOperations(coreCodegenContext) // TODO(restore): This causes a panic: "symbol visitor should not be invoked in service shapes" // val serviceName = symbolProvider.toSymbol(service).name @@ -124,18 +115,16 @@ private fun restRouterType(runtimeConfig: RuntimeConfig) = RuntimeType("RestRout private fun restRouterConstruction( protocol: ServerProtocol, - service: ServiceShape, operationValues: Iterable, - model: Model, coreCodegenContext: CoreCodegenContext, ): Writable = writable { - val allOperationShapes = allOperationShapes(service, model) + val operations = allOperations(coreCodegenContext) // TODO(restore): This causes a panic: "symbol visitor should not be invoked in service shapes" // val serviceName = symbolProvider.toSymbol(service).name - val serviceName = service.id.name + val serviceName = coreCodegenContext.serviceShape.id.name val pairs = writable { - for ((operationShape, operationValue) in allOperationShapes.zip(operationValues)) { + for ((operationShape, operationValue) in operations.zip(operationValues)) { val operationName = coreCodegenContext.symbolProvider.toSymbol(operationShape).name val key = protocol.serverRouterRequestSpec( operationShape, @@ -178,7 +167,7 @@ class ServerRestJsonProtocol( override fun routerType() = restRouterType(runtimeConfig) - override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = restRouterConstruction(this, service, operationValues, model, coreCodegenContext) + override fun routerConstruction(operationValues: Iterable): Writable = restRouterConstruction(this, operationValues, coreCodegenContext) } class ServerRestXmlProtocol( @@ -196,5 +185,5 @@ class ServerRestXmlProtocol( override fun routerType() = restRouterType(runtimeConfig) - override fun routerConstruction(service: ServiceShape, operationValues: Iterable, model: Model): Writable = restRouterConstruction(this, service, operationValues, model, coreCodegenContext) + override fun routerConstruction(operationValues: Iterable): Writable = restRouterConstruction(this, operationValues, coreCodegenContext) } From da62ae67e0ca89c250e312ef8ad129d3236508df Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 9 Sep 2022 09:24:31 +0000 Subject: [PATCH 65/73] Link server specific SymbolProvider issue in TODO --- .../server/smithy/generators/protocol/ServerProtocol.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index 6549497ce3..0b908eec9f 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -83,7 +83,8 @@ class ServerAwsJsonProtocol( override fun routerConstruction(operationValues: Iterable): Writable = writable { val allOperationShapes = allOperations(coreCodegenContext) - // TODO(restore): This causes a panic: "symbol visitor should not be invoked in service shapes" + // TODO(https://github.com/awslabs/smithy-rs/issues/1724#issue-1367509999): This causes a panic: "symbol + // visitor should not be invoked in service shapes" // val serviceName = symbolProvider.toSymbol(service).name val serviceName = service.id.name val pairs = writable { @@ -120,7 +121,8 @@ private fun restRouterConstruction( ): Writable = writable { val operations = allOperations(coreCodegenContext) - // TODO(restore): This causes a panic: "symbol visitor should not be invoked in service shapes" + // TODO(https://github.com/awslabs/smithy-rs/issues/1724#issue-1367509999): This causes a panic: "symbol visitor + // should not be invoked in service shapes" // val serviceName = symbolProvider.toSymbol(service).name val serviceName = coreCodegenContext.serviceShape.id.name val pairs = writable { From ba9ea60da13fa9faf10dbdeb324cc450662e6317 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 9 Sep 2022 11:58:30 +0000 Subject: [PATCH 66/73] Add InternalFailure operation --- .../generators/ServerServiceGeneratorV2.kt | 30 +++++++++++ .../src/operation/upgrade.rs | 52 ++++++++++++++++++- .../src/runtime_error.rs | 35 ++++++++++++- 3 files changed, 115 insertions(+), 2 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index e64b830f99..d6d7687acd 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -274,6 +274,23 @@ class ServerServiceGeneratorV2( } } + // Returns a `Writable` comma delimited sequence of `DummyOperation`. + private fun internalFailureGenerics(): Writable = writable { + for (index in 1..operations.size) { + rustTemplate("#{SmithyHttpServer}::operation::InternalFailureOperation,", *codegenScope) + } + } + + // Returns a `Writable` comma delimited sequence of `builder_field: DummyOperation`. + private fun internalFailureFields(): Writable = writable { + for (fieldName in builderFieldNames()) { + rustTemplate( + "$fieldName: #{SmithyHttpServer}::operation::InternalFailureOperation,", + *codegenScope, + ) + } + } + /** Returns a `Writable` containing the service struct definition and its implementations. */ private fun struct(): Writable = writable { documentShape(service, model) @@ -293,6 +310,17 @@ class ServerServiceGeneratorV2( _exts: std::marker::PhantomData } } + + /// Constructs an unchecked builder for [`$serviceName`]. + /// + /// This will not enforce that all operations are set, however if an unset operation is used at runtime + /// it will return status code 500 and log an error. + pub fn unchecked_builder() -> $builderName<#{InternalFailureGenerics:W}> { + $builderName { + #{InternalFailureFields:W} + _exts: std::marker::PhantomData + } + } } impl $serviceName { @@ -331,6 +359,8 @@ class ServerServiceGeneratorV2( } } """, + "InternalFailureGenerics" to internalFailureGenerics(), + "InternalFailureFields" to internalFailureFields(), "NotSetGenerics" to notSetGenerics(), "NotSetFields" to notSetFields(), "Router" to protocol.routerType(), diff --git a/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs b/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs index c5e5ca668e..036cfa7a14 100644 --- a/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs +++ b/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs @@ -4,7 +4,8 @@ */ use std::{ - future::Future, + convert::Infallible, + future::{Future, Ready}, marker::PhantomData, pin::Pin, task::{Context, Poll}, @@ -13,11 +14,13 @@ use std::{ use futures_util::ready; use pin_project_lite::pin_project; use tower::{layer::util::Stack, Layer, Service}; +use tracing::error; use crate::{ body::BoxBody, request::{FromParts, FromRequest}, response::IntoResponse, + runtime_error::InternalFailureException, }; use super::{Operation, OperationError, OperationShape}; @@ -259,4 +262,51 @@ where } /// A marker struct indicating an [`Operation`] has not been set in a builder. +/// +/// This does _not_ implement [`Upgradable`] purposely. pub struct MissingOperation; + +/// A marker struct indicating an [`Operation`] has not been set in a builder. +/// +/// This _does_ implement [`Upgradable`] but produces a [`Service`] which always returns an internal failure message. +pub struct InternalFailureOperation; + +impl Upgradable for InternalFailureOperation +where + InternalFailureException: IntoResponse

, +{ + type Service = InternalFailureService

; + + fn upgrade(self) -> Self::Service { + InternalFailureService { _protocol: PhantomData } + } +} + +/// A [`Service`] which always returns an internal failure message. +pub struct InternalFailureService

{ + _protocol: PhantomData

, +} + +impl

Clone for InternalFailureService

{ + fn clone(&self) -> Self { + InternalFailureService { _protocol: PhantomData } + } +} + +impl Service for InternalFailureService

+where + InternalFailureException: IntoResponse

, +{ + type Response = http::Response; + type Error = Infallible; + type Future = Ready>; + + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, _request: R) -> Self::Future { + error!("internal failure occurred"); + std::future::ready(Ok(InternalFailureException.into_response())) + } +} diff --git a/rust-runtime/aws-smithy-http-server/src/runtime_error.rs b/rust-runtime/aws-smithy-http-server/src/runtime_error.rs index cd20c5a782..3151a25b36 100644 --- a/rust-runtime/aws-smithy-http-server/src/runtime_error.rs +++ b/rust-runtime/aws-smithy-http-server/src/runtime_error.rs @@ -22,7 +22,7 @@ //! [`RuntimeError::into_response`] method to render and send a response. use crate::{ - protocols::Protocol, + protocols::{AwsJson10, AwsJson11, AwsRestJson1, AwsRestXml, Protocol}, response::{IntoResponse, Response}, }; @@ -51,6 +51,32 @@ impl RuntimeErrorKind { } } +pub struct InternalFailureException; + +impl IntoResponse for InternalFailureException { + fn into_response(self) -> http::Response { + RuntimeError::internal_failure_from_protocol(Protocol::AwsJson10).into_response() + } +} + +impl IntoResponse for InternalFailureException { + fn into_response(self) -> http::Response { + RuntimeError::internal_failure_from_protocol(Protocol::AwsJson11).into_response() + } +} + +impl IntoResponse for InternalFailureException { + fn into_response(self) -> http::Response { + RuntimeError::internal_failure_from_protocol(Protocol::RestJson1).into_response() + } +} + +impl IntoResponse for InternalFailureException { + fn into_response(self) -> http::Response { + RuntimeError::internal_failure_from_protocol(Protocol::RestXml).into_response() + } +} + #[derive(Debug)] pub struct RuntimeError { pub protocol: Protocol, @@ -64,6 +90,13 @@ impl

IntoResponse

for RuntimeError { } impl RuntimeError { + pub fn internal_failure_from_protocol(protocol: Protocol) -> Self { + RuntimeError { + protocol, + kind: RuntimeErrorKind::InternalFailure(crate::Error::new(String::new())), + } + } + pub fn into_response(self) -> Response { let status_code = match self.kind { RuntimeErrorKind::Serialization(_) => http::StatusCode::BAD_REQUEST, From f2ba048155a7574d169835db9a925e0513215ed2 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 9 Sep 2022 14:37:47 +0000 Subject: [PATCH 67/73] Mem replace the service for safety --- rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs b/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs index 036cfa7a14..135960534a 100644 --- a/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs +++ b/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs @@ -207,8 +207,10 @@ where } fn call(&mut self, req: http::Request) -> Self::Future { + let clone = self.inner.clone(); + let service = std::mem::replace(&mut self.inner, clone); UpgradeFuture { - service: self.inner.clone(), + service, inner: Inner::FromRequest { inner: <(Op::Input, Exts) as FromRequest>::from_request(req), }, From 925ed1f4fd9bba2f02021fd9d65f7f0e18ebdc8a Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 9 Sep 2022 14:48:49 +0000 Subject: [PATCH 68/73] Fix documentation --- .../generators/ServerServiceGeneratorV2.kt | 4 ++-- .../src/operation/upgrade.rs | 22 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index d6d7687acd..24492b7326 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -277,7 +277,7 @@ class ServerServiceGeneratorV2( // Returns a `Writable` comma delimited sequence of `DummyOperation`. private fun internalFailureGenerics(): Writable = writable { for (index in 1..operations.size) { - rustTemplate("#{SmithyHttpServer}::operation::InternalFailureOperation,", *codegenScope) + rustTemplate("#{SmithyHttpServer}::operation::FailOnMissingOperation,", *codegenScope) } } @@ -285,7 +285,7 @@ class ServerServiceGeneratorV2( private fun internalFailureFields(): Writable = writable { for (fieldName in builderFieldNames()) { rustTemplate( - "$fieldName: #{SmithyHttpServer}::operation::InternalFailureOperation,", + "$fieldName: #{SmithyHttpServer}::operation::FailOnMissingOperation,", *codegenScope, ) } diff --git a/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs b/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs index 135960534a..3d4a617ccf 100644 --- a/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs +++ b/rust-runtime/aws-smithy-http-server/src/operation/upgrade.rs @@ -253,7 +253,7 @@ where { type Service = L::Service; - /// Takes the [`Operation`](Operation), applies [`ModifyBuild::modify`] to it, applies [`UpgradeLayer`] to + /// Takes the [`Operation`](Operation), applies [`UpgradeLayer`] to /// the modified `S`, then finally applies the modified `L`. /// /// The composition is made explicit in the method constraints and return type. @@ -271,31 +271,31 @@ pub struct MissingOperation; /// A marker struct indicating an [`Operation`] has not been set in a builder. /// /// This _does_ implement [`Upgradable`] but produces a [`Service`] which always returns an internal failure message. -pub struct InternalFailureOperation; +pub struct FailOnMissingOperation; -impl Upgradable for InternalFailureOperation +impl Upgradable for FailOnMissingOperation where InternalFailureException: IntoResponse

, { - type Service = InternalFailureService

; + type Service = MissingFailure

; fn upgrade(self) -> Self::Service { - InternalFailureService { _protocol: PhantomData } + MissingFailure { _protocol: PhantomData } } } -/// A [`Service`] which always returns an internal failure message. -pub struct InternalFailureService

{ +/// A [`Service`] which always returns an internal failure message and logs an error. +pub struct MissingFailure

{ _protocol: PhantomData

, } -impl

Clone for InternalFailureService

{ +impl

Clone for MissingFailure

{ fn clone(&self) -> Self { - InternalFailureService { _protocol: PhantomData } + MissingFailure { _protocol: PhantomData } } } -impl Service for InternalFailureService

+impl Service for MissingFailure

where InternalFailureException: IntoResponse

, { @@ -308,7 +308,7 @@ where } fn call(&mut self, _request: R) -> Self::Future { - error!("internal failure occurred"); + error!("the operation has not been set"); std::future::ready(Ok(InternalFailureException.into_response())) } } From 0717fc14df7a9be36b317cd2207fea2ed31f949d Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 9 Sep 2022 16:58:36 +0000 Subject: [PATCH 69/73] Better use of iterators --- .../smithy/rust/codegen/rustlang/Writable.kt | 7 + .../generators/ServerServiceGeneratorV2.kt | 196 +++++++----------- 2 files changed, 84 insertions(+), 119 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/Writable.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/Writable.kt index 7c51295e96..fbda23b4f7 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/Writable.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/rustlang/Writable.kt @@ -26,6 +26,13 @@ fun Writable.isEmpty(): Boolean { return writer.toString() == RustWriter.root().toString() } +operator fun Writable.plus(other: Writable): Writable { + val first = this + return writable { + rustTemplate("#{First:W}#{Second:W}", "First" to first, "Second" to other) + } +} + /** * Helper allowing a `Iterable` to be joined together using a `String` separator. */ diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 24492b7326..1025ee09f4 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -7,11 +7,12 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.model.knowledge.TopDownIndex import software.amazon.smithy.rust.codegen.rustlang.CargoDependency -import software.amazon.smithy.rust.codegen.rustlang.RustReservedWords import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.asType import software.amazon.smithy.rust.codegen.rustlang.documentShape +import software.amazon.smithy.rust.codegen.rustlang.join +import software.amazon.smithy.rust.codegen.rustlang.plus import software.amazon.smithy.rust.codegen.rustlang.rust import software.amazon.smithy.rust.codegen.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.rustlang.writable @@ -42,101 +43,68 @@ class ServerServiceGeneratorV2( private val serviceName = service.id.name private val builderName = "${serviceName}Builder" - // Calculate all `operationShape`s contained within the `ServiceShape`. + /** Calculate all `operationShape`s contained within the `ServiceShape`. */ private val index = TopDownIndex.of(coreCodegenContext.model) private val operations = index.getContainedOperations(coreCodegenContext.serviceShape).sortedBy { it.id } - /** Returns the sequence of builder generics: `Op1`, ..., `OpN`. */ - private fun builderGenerics(): Sequence = sequence { - for (index in 1..operations.size) { - yield("Op$index") - } - } + /** The sequence of builder generics: `Op1`, ..., `OpN`. */ + private val builderOps = (1..operations.size).map { "Op$it" } - /** Returns the sequence of extension types: `Ext1`, ..., `ExtN`. */ - private fun extensionTypes(): Sequence = sequence { - for (index in 1..operations.size) { - yield("Exts$index") - } - } + /** The sequence of extension types: `Ext1`, ..., `ExtN`. */ + private val extensionTypes = (1..operations.size).map { "Exts$it" } - /** Returns the sequence of field names for the builder. */ - private fun builderFieldNames(): Sequence = sequence { - for (operation in operations) { - val field = RustReservedWords.escapeIfNeeded(symbolProvider.toSymbol(operation).name.toSnakeCase()) - yield(field) - } - } + /** The sequence of field names for the builder. */ + private val builderFieldNames = operations.map { symbolProvider.toSymbol(it).name.toSnakeCase() } - /** Returns the sequence of operation struct names. */ - private fun operationStructNames(): Sequence = sequence { - for (operation in operations) { - yield(symbolProvider.toSymbol(operation).name.toPascalCase()) - } - } + /** The sequence of operation struct names. */ + private val operationStructNames = operations.map { symbolProvider.toSymbol(it).name.toPascalCase() } - /** Returns a `Writable` block of "field: Type" for the builder. */ - private fun builderFields(): Writable = writable { - val zipped = builderFieldNames().zip(builderGenerics()) - for ((name, type) in zipped) { - rust("$name: $type,") - } - } + /** A `Writable` block of "field: Type" for the builder. */ + private val builderFields = builderFieldNames.zip(builderOps).map { (name, type) -> "$name: $type" } - /** Returns a `Writable` block containing all the `Handler` and `Operation` setters for the builder. */ + /** A `Writable` block containing all the `Handler` and `Operation` setters for the builder. */ private fun builderSetters(): Writable = writable { - for ((index, pair) in builderFieldNames().zip(operationStructNames()).withIndex()) { + for ((index, pair) in builderFieldNames.zip(operationStructNames).withIndex()) { val (fieldName, structName) = pair // The new generics for the operation setter, using `NewOp` where appropriate. - val replacedOpGenerics = writable { - for ((innerIndex, item) in builderGenerics().withIndex()) { - if (innerIndex == index) { - rust("NewOp") - } else { - rust(item) - } - rust(", ") + val replacedOpGenerics = builderOps.withIndex().map { (innerIndex, item) -> + if (innerIndex == index) { + "NewOp" + } else { + item } } // The new generics for the operation setter, using `NewOp` where appropriate. - val replacedExtGenerics = writable { - for ((innerIndex, item) in extensionTypes().withIndex()) { - if (innerIndex == index) { - rust("NewExts") - } else { - rust(item) - } - rust(", ") + val replacedExtGenerics = extensionTypes.withIndex().map { (innerIndex, item) -> + if (innerIndex == index) { + "NewExts" + } else { + item } } // The new generics for the handler setter, using `NewOp` where appropriate. - val replacedOpServiceGenerics = writable { - for ((innerIndex, item) in builderGenerics().withIndex()) { - if (innerIndex == index) { - rustTemplate( - """ - #{SmithyHttpServer}::operation::Operation<#{SmithyHttpServer}::operation::IntoService> - """, - *codegenScope, - ) - } else { - rust(item) - } - rust(", ") + val replacedOpServiceGenerics = builderOps.withIndex().map { (innerIndex, item) -> + if (innerIndex == index) writable { + rustTemplate( + """ + #{SmithyHttpServer}::operation::Operation<#{SmithyHttpServer}::operation::IntoService> + """, + *codegenScope, + ) + } else { + writable(item) } } // The assignment of fields, using value where appropriate. - val switchedFields = writable { - for ((innerIndex, innerFieldName) in builderFieldNames().withIndex()) { - if (index == innerIndex) { - rust("$innerFieldName: value,") - } else { - rust("$innerFieldName: self.$innerFieldName,") - } + val switchedFields = builderFieldNames.withIndex().map { (innerIndex, item) -> + if (index == innerIndex) { + "$item: value" + } else { + "$item: self.$item" } } @@ -146,7 +114,7 @@ class ServerServiceGeneratorV2( /// /// This should be a closure satisfying the [`Handler`](#{SmithyHttpServer}::operation::Handler) trait. /// See the [operation module documentation](#{SmithyHttpServer}::operation) for more information. - pub fn $fieldName(self, value: H) -> $builderName<#{ReplacedOpServiceGenerics:W} #{ReplacedExtGenerics:W}> + pub fn $fieldName(self, value: H) -> $builderName<#{HandlerSetterGenerics:W}> where H: #{SmithyHttpServer}::operation::Handler { @@ -160,19 +128,16 @@ class ServerServiceGeneratorV2( /// [`$structName`](crate::operation_shape::$structName) using either /// [`OperationShape::from_handler`](#{SmithyHttpServer}::operation::OperationShapeExt::from_handler) or /// [`OperationShape::from_service`](#{SmithyHttpServer}::operation::OperationShapeExt::from_service). - pub fn ${fieldName}_operation(self, value: NewOp) -> $builderName<#{ReplacedOpGenerics:W} #{ReplacedExtGenerics:W}> + pub fn ${fieldName}_operation(self, value: NewOp) -> $builderName<${(replacedOpGenerics + replacedExtGenerics).joinToString(", ")}> { $builderName { - #{SwitchedFields:W} + ${switchedFields.joinToString(", ")}, _exts: std::marker::PhantomData } } """, "Protocol" to protocol.markerStruct(), - "SwitchedFields" to switchedFields, - "ReplacedOpGenerics" to replacedOpGenerics, - "ReplacedOpServiceGenerics" to replacedOpServiceGenerics, - "ReplacedExtGenerics" to replacedExtGenerics, + "HandlerSetterGenerics" to (replacedOpServiceGenerics + (replacedExtGenerics.map { writable(it) })).join(", "), *codegenScope, ) @@ -182,12 +147,11 @@ class ServerServiceGeneratorV2( } /** Returns the constraints required for the `build` method. */ - private fun buildConstraints(): Writable = writable { - for (tuple in operations.asSequence().zip(builderGenerics()).zip(extensionTypes())) { - val (first, exts) = tuple - val (operation, type) = first - // TODO(https://github.com/awslabs/smithy-rs/issues/1713#issue-1365169734): The `Error = Infallible` is an - // excess requirement to stay at parity with existing builder. + private val buildConstraints = operations.zip(builderOps).zip(extensionTypes).map { (first, exts) -> + val (operation, type) = first + // TODO(https://github.com/awslabs/smithy-rs/issues/1713#issue-1365169734): The `Error = Infallible` is an + // excess requirement to stay at parity with existing builder. + writable { rustTemplate( """ $type: #{SmithyHttpServer}::operation::Upgradable< @@ -199,7 +163,7 @@ class ServerServiceGeneratorV2( $type::Service: Clone + Send + 'static, <$type::Service as #{Tower}::Service<#{Http}::Request>>::Future: Send + 'static, - $type::Service: #{Tower}::Service<#{Http}::Request, Error = std::convert::Infallible>, + $type::Service: #{Tower}::Service<#{Http}::Request, Error = std::convert::Infallible> """, "Marker" to protocol.markerStruct(), *codegenScope, @@ -209,13 +173,14 @@ class ServerServiceGeneratorV2( /** Returns a `Writable` containing the builder struct definition and its implementations. */ private fun builder(): Writable = writable { - val structGenerics = (builderGenerics() + extensionTypes().map { "$it = ()" }).joinToString(",") - val generics = (builderGenerics() + extensionTypes()).joinToString(",") + val extensionTypesDefault = extensionTypes.map { "$it = ()" } + val structGenerics = (builderOps + extensionTypesDefault).joinToString(", ") + val builderGenerics = (builderOps + extensionTypes).joinToString(", ") // Generate router construction block. val router = protocol .routerConstruction( - builderFieldNames() + builderFieldNames .map { writable { rustTemplate("self.$it.upgrade()") } } @@ -227,16 +192,16 @@ class ServerServiceGeneratorV2( /// /// Constructed via [`$serviceName::builder`]. pub struct $builderName<$structGenerics> { - #{Fields:W} + ${builderFields.joinToString(", ")}, ##[allow(unused_parens)] - _exts: std::marker::PhantomData<(${extensionTypes().joinToString(",")})> + _exts: std::marker::PhantomData<(${extensionTypes.joinToString(", ")})> } - impl<$generics> $builderName<$generics> { + impl<$builderGenerics> $builderName<$builderGenerics> { #{Setters:W} } - impl<$generics> $builderName<$generics> { + impl<$builderGenerics> $builderName<$builderGenerics> { /// Constructs a [`$serviceName`] from the arguments provided to the builder. pub fn build(self) -> $serviceName<#{SmithyHttpServer}::routing::Route> where @@ -249,43 +214,36 @@ class ServerServiceGeneratorV2( } } """, - "Fields" to builderFields(), "Setters" to builderSetters(), - "BuildConstraints" to buildConstraints(), + "BuildConstraints" to buildConstraints.join(", "), "Router" to router, *codegenScope, ) } - /** Returns a `Writable` comma delimited sequence of `MissingOperation`. */ - private fun notSetGenerics(): Writable = writable { - for (index in 1..operations.size) { - rustTemplate("#{SmithyHttpServer}::operation::MissingOperation,", *codegenScope) - } + /** A `Writable` comma delimited sequence of `MissingOperation`. */ + private val notSetGenerics = (1..operations.size).map { + writable { rustTemplate("#{SmithyHttpServer}::operation::MissingOperation", *codegenScope) } } /** Returns a `Writable` comma delimited sequence of `builder_field: MissingOperation`. */ - private fun notSetFields(): Writable = writable { - for (fieldName in builderFieldNames()) { + private val notSetFields = builderFieldNames.map { + writable { rustTemplate( - "$fieldName: #{SmithyHttpServer}::operation::MissingOperation,", + "$it: #{SmithyHttpServer}::operation::MissingOperation", *codegenScope, ) } } - // Returns a `Writable` comma delimited sequence of `DummyOperation`. - private fun internalFailureGenerics(): Writable = writable { - for (index in 1..operations.size) { - rustTemplate("#{SmithyHttpServer}::operation::FailOnMissingOperation,", *codegenScope) - } - } + /** A `Writable` comma delimited sequence of `DummyOperation`. */ + private val internalFailureGenerics = (1..operations.size).map { writable { rustTemplate("#{SmithyHttpServer}::operation::FailOnMissingOperation", *codegenScope) } } - // Returns a `Writable` comma delimited sequence of `builder_field: DummyOperation`. - private fun internalFailureFields(): Writable = writable { - for (fieldName in builderFieldNames()) { + /** A `Writable` comma delimited sequence of `builder_field: DummyOperation`. */ + private val internalFailureFields = builderFieldNames.map { + writable { rustTemplate( - "$fieldName: #{SmithyHttpServer}::operation::FailOnMissingOperation,", + "$it: #{SmithyHttpServer}::operation::FailOnMissingOperation", *codegenScope, ) } @@ -306,7 +264,7 @@ class ServerServiceGeneratorV2( /// Constructs a builder for [`$serviceName`]. pub fn builder() -> $builderName<#{NotSetGenerics:W}> { $builderName { - #{NotSetFields:W} + #{NotSetFields:W}, _exts: std::marker::PhantomData } } @@ -317,7 +275,7 @@ class ServerServiceGeneratorV2( /// it will return status code 500 and log an error. pub fn unchecked_builder() -> $builderName<#{InternalFailureGenerics:W}> { $builderName { - #{InternalFailureFields:W} + #{InternalFailureFields:W}, _exts: std::marker::PhantomData } } @@ -359,10 +317,10 @@ class ServerServiceGeneratorV2( } } """, - "InternalFailureGenerics" to internalFailureGenerics(), - "InternalFailureFields" to internalFailureFields(), - "NotSetGenerics" to notSetGenerics(), - "NotSetFields" to notSetFields(), + "InternalFailureGenerics" to internalFailureGenerics.join(", "), + "InternalFailureFields" to internalFailureFields.join(", "), + "NotSetGenerics" to notSetGenerics.join(", "), + "NotSetFields" to notSetFields.join(", "), "Router" to protocol.routerType(), "Protocol" to protocol.markerStruct(), *codegenScope, From d9c3628f848f42ecefebb6ff9016003a147fe8e3 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 9 Sep 2022 17:05:07 +0000 Subject: [PATCH 70/73] Restore escapeIfNeeded --- .../server/smithy/generators/ServerServiceGeneratorV2.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 1025ee09f4..54e6751fe0 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -7,6 +7,7 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.model.knowledge.TopDownIndex import software.amazon.smithy.rust.codegen.rustlang.CargoDependency +import software.amazon.smithy.rust.codegen.rustlang.RustReservedWords import software.amazon.smithy.rust.codegen.rustlang.RustWriter import software.amazon.smithy.rust.codegen.rustlang.Writable import software.amazon.smithy.rust.codegen.rustlang.asType @@ -54,7 +55,7 @@ class ServerServiceGeneratorV2( private val extensionTypes = (1..operations.size).map { "Exts$it" } /** The sequence of field names for the builder. */ - private val builderFieldNames = operations.map { symbolProvider.toSymbol(it).name.toSnakeCase() } + private val builderFieldNames = operations.map { RustReservedWords.escapeIfNeeded(symbolProvider.toSymbol(it).name.toSnakeCase()) } /** The sequence of operation struct names. */ private val operationStructNames = operations.map { symbolProvider.toSymbol(it).name.toPascalCase() } From 32dc9b7f3c39cef2866e268a6172ada5f8181cc7 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 9 Sep 2022 23:14:26 +0000 Subject: [PATCH 71/73] Ensure service name is PascalCase --- .../server/smithy/generators/ServerServiceGeneratorV2.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt index 35c6933784..7e93e79caa 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGeneratorV2.kt @@ -40,7 +40,7 @@ class ServerServiceGeneratorV2( private val symbolProvider = coreCodegenContext.symbolProvider private val service = coreCodegenContext.serviceShape - private val serviceName = service.id.name + private val serviceName = service.id.name.toPascalCase() private val builderName = "${serviceName}Builder" /** Calculate all `operationShape`s contained within the `ServiceShape`. */ From ba8d7720a2d0ce41603b7c8106d6388417c2f852 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Fri, 9 Sep 2022 23:15:12 +0000 Subject: [PATCH 72/73] Integrate new service builder into protocol tests --- .../protocol/ServerProtocolTestGenerator.kt | 77 ++++++++++++++----- 1 file changed, 58 insertions(+), 19 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt index ebf52a91e0..221a4735c4 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt @@ -52,6 +52,7 @@ import software.amazon.smithy.rust.codegen.client.util.inputShape import software.amazon.smithy.rust.codegen.client.util.isStreaming import software.amazon.smithy.rust.codegen.client.util.orNull import software.amazon.smithy.rust.codegen.client.util.outputShape +import software.amazon.smithy.rust.codegen.client.util.toPascalCase import software.amazon.smithy.rust.codegen.client.util.toSnakeCase import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency import software.amazon.smithy.rust.codegen.server.smithy.ServerRuntimeType @@ -75,6 +76,7 @@ class ServerProtocolTestGenerator( private val symbolProvider = coreCodegenContext.symbolProvider private val operationIndex = OperationIndex.of(coreCodegenContext.model) + private val serviceName = coreCodegenContext.serviceShape.id.name.toPascalCase() private val operations = TopDownIndex.of(coreCodegenContext.model).getContainedOperations(coreCodegenContext.serviceShape).sortedBy { it.id } private val operationInputOutputTypes = operations.associateWith { @@ -357,6 +359,8 @@ class ServerProtocolTestGenerator( rust("/* test case disabled for this protocol (not yet supported) */") return } + + // Test against original `OperationRegistryBuilder`. with(httpRequestTestCase) { renderHttpRequest(uri, method, headers, body.orNull(), queryParams, host.orNull()) } @@ -364,6 +368,14 @@ class ServerProtocolTestGenerator( checkRequest(operationShape, operationSymbol, httpRequestTestCase, this) } + // Test against new service builder. + with(httpRequestTestCase) { + renderHttpRequest(uri, method, headers, body.orNull(), queryParams, host.orNull()) + } + if (protocolSupport.requestBodyDeserialization) { + checkRequest2(operationShape, operationSymbol, httpRequestTestCase, this) + } + // Explicitly warn if the test case defined parameters that we aren't doing anything with with(httpRequestTestCase) { if (authScheme.isPresent) { @@ -495,11 +507,34 @@ class ServerProtocolTestGenerator( } } - private fun checkRequest(operationShape: OperationShape, operationSymbol: Symbol, httpRequestTestCase: HttpRequestTestCase, rustWriter: RustWriter) { + /** Returns the body of the request test. */ + private fun checkRequestHandler(operationShape: OperationShape, httpRequestTestCase: HttpRequestTestCase) = writable { val inputShape = operationShape.inputShape(coreCodegenContext.model) val outputShape = operationShape.outputShape(coreCodegenContext.model) + // Construct expected request. + withBlock("let expected = ", ";") { + instantiator.render(this, inputShape, httpRequestTestCase.params) + } + + checkRequestParams(inputShape, this) + + // Construct a dummy response. + withBlock("let response = ", ";") { + instantiator.render(this, outputShape, Node.objectNode(), Instantiator.defaultContext().copy(defaultsForRequiredFields = true)) + } + + if (operationShape.errors.isEmpty()) { + write("response") + } else { + write("Ok(response)") + } + } + + /** Checks the request using the `OperationRegistryBuilder`. */ + private fun checkRequest(operationShape: OperationShape, operationSymbol: Symbol, httpRequestTestCase: HttpRequestTestCase, rustWriter: RustWriter) { val (inputT, outputT) = operationInputOutputTypes[operationShape]!! + rustWriter.withBlock( """ super::$PROTOCOL_TEST_HELPER_MODULE_NAME::build_router_and_make_request( @@ -509,29 +544,33 @@ class ServerProtocolTestGenerator( builder.${operationShape.toName()}((|input| Box::pin(async move { """, - "})) as super::$PROTOCOL_TEST_HELPER_MODULE_NAME::Fun<$inputT, $outputT>)}).await", + "})) as super::$PROTOCOL_TEST_HELPER_MODULE_NAME::Fun<$inputT, $outputT>)}).await;", ) { - // Construct expected request. - rustWriter.withBlock("let expected = ", ";") { - instantiator.render(this, inputShape, httpRequestTestCase.params) - } - - checkRequestParams(inputShape, rustWriter) - - // Construct a dummy response. - rustWriter.withBlock("let response = ", ";") { - instantiator.render(this, outputShape, Node.objectNode(), Instantiator.defaultContext().copy(defaultsForRequiredFields = true)) - } - - if (operationShape.errors.isEmpty()) { - rustWriter.write("response") - } else { - rustWriter.write("Ok(response)") - } + checkRequestHandler(operationShape, httpRequestTestCase)() } } + /** Checks the request using the new service builder. */ + private fun checkRequest2(operationShape: OperationShape, operationSymbol: Symbol, httpRequestTestCase: HttpRequestTestCase, rustWriter: RustWriter) { + val (inputT, outputT) = operationInputOutputTypes[operationShape]!! + val operationName = RustReservedWords.escapeIfNeeded(operationSymbol.name.toSnakeCase()) + rustWriter.rustTemplate( + """ + let service = crate::service::$serviceName::unchecked_builder() + .$operationName(|input: $inputT| async move { + #{Body:W} + }) + .build::<#{Hyper}::body::Body>(); + let http_response = #{Tower}::ServiceExt::oneshot(service, http_request) + .await + .expect("unable to make an HTTP request"); + """, + "Body" to checkRequestHandler(operationShape, httpRequestTestCase), + *codegenScope, + ) + } + private fun checkRequestParams(inputShape: StructureShape, rustWriter: RustWriter) { if (inputShape.hasStreamingMember(model)) { // A streaming shape does not implement `PartialEq`, so we have to iterate over the input shape's members From a19fdf6e9e2f236c543e269d6c82645bcd188147 Mon Sep 17 00:00:00 2001 From: Harry Barber Date: Sat, 10 Sep 2022 08:01:07 +0000 Subject: [PATCH 73/73] Add service builder test assertion --- .../protocol/ServerProtocolTestGenerator.kt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt index 221a4735c4..7bb0e3d89c 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt @@ -106,6 +106,7 @@ class ServerProtocolTestGenerator( "SmithyHttp" to CargoDependency.SmithyHttp(coreCodegenContext.runtimeConfig).asType(), "Http" to CargoDependency.Http.asType(), "Hyper" to CargoDependency.Hyper.asType(), + "Tokio" to ServerCargoDependency.TokioDev.asType(), "Tower" to CargoDependency.Tower.asType(), "SmithyHttpServer" to ServerCargoDependency.SmithyHttpServer(coreCodegenContext.runtimeConfig).asType(), "AssertEq" to CargoDependency.PrettyAssertions.asType().member("assert_eq!"), @@ -553,18 +554,25 @@ class ServerProtocolTestGenerator( /** Checks the request using the new service builder. */ private fun checkRequest2(operationShape: OperationShape, operationSymbol: Symbol, httpRequestTestCase: HttpRequestTestCase, rustWriter: RustWriter) { - val (inputT, outputT) = operationInputOutputTypes[operationShape]!! + val (inputT, _) = operationInputOutputTypes[operationShape]!! val operationName = RustReservedWords.escapeIfNeeded(operationSymbol.name.toSnakeCase()) rustWriter.rustTemplate( """ + let (sender, mut receiver) = #{Tokio}::sync::mpsc::channel(1); let service = crate::service::$serviceName::unchecked_builder() - .$operationName(|input: $inputT| async move { - #{Body:W} + .$operationName(move |input: $inputT| { + let sender = sender.clone(); + async move { + let result = { #{Body:W} }; + sender.send(()).await.expect("receiver dropped early"); + result + } }) .build::<#{Hyper}::body::Body>(); let http_response = #{Tower}::ServiceExt::oneshot(service, http_request) .await .expect("unable to make an HTTP request"); + assert!(receiver.recv().await.is_some()) """, "Body" to checkRequestHandler(operationShape, httpRequestTestCase), *codegenScope,