From 51df47576b392ad43a72c086ab0201e1659b0a62 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Thu, 9 Mar 2023 11:10:03 -0800 Subject: [PATCH] Make module docs customizable and update mod docs for crate reorg (#2418) --- .../smithy/rustsdk/InlineAwsDependency.kt | 6 +- .../rustsdk/endpoints/AwsEndpointDecorator.kt | 4 +- .../client/smithy/ClientCodegenContext.kt | 4 +- .../client/smithy/ClientCodegenVisitor.kt | 24 +++++- .../codegen/client/smithy/ClientRustModule.kt | 80 ++++++++++++++----- .../endpoint/EndpointConfigCustomization.kt | 31 +++---- .../smithy/endpoint/EndpointsDecorator.kt | 6 +- .../codegen/client/smithy/endpoint/Util.kt | 4 +- .../generators/EndpointParamsGenerator.kt | 30 ++----- .../generators/EndpointResolverGenerator.kt | 5 +- .../generators/NestedAccessorGenerator.kt | 2 +- .../client/FluentClientGenerator.kt | 2 +- .../protocol/ProtocolTestGenerator.kt | 5 +- .../codegen/client/testutil/TestHelpers.kt | 2 + .../rust/codegen/core/rustlang/RustModule.kt | 41 ++++------ .../rust/codegen/core/rustlang/RustWriter.kt | 5 +- .../codegen/core/smithy/CodegenContext.kt | 10 +++ .../codegen/core/smithy/CodegenDelegator.kt | 41 ++++++++-- .../smithy/customize/CoreCodegenDecorator.kt | 16 ++++ .../smithy/rust/codegen/core/testutil/Rust.kt | 25 ++++-- .../rust/codegen/core/testutil/TestHelpers.kt | 11 +-- .../core/rustlang/InlineDependencyTest.kt | 8 +- .../codegen/core/rustlang/RustWriterTest.kt | 6 +- .../smithy/PythonServerCodegenVisitor.kt | 19 ++++- .../python/smithy/PythonServerRustModule.kt | 25 ++++++ .../generators/PythonServerModuleGenerator.kt | 6 +- .../PythonServerServiceGenerator.kt | 4 +- .../smithy/ConstrainedShapeSymbolProvider.kt | 1 + .../ConstraintViolationSymbolProvider.kt | 4 +- .../rust/codegen/server/smithy/Constraints.kt | 3 +- .../RustCrateInlineModuleComposingWriter.kt | 11 +-- .../server/smithy/ServerCodegenContext.kt | 4 +- .../server/smithy/ServerCodegenVisitor.kt | 15 +++- .../codegen/server/smithy/ServerRustModule.kt | 40 ++++++++-- .../generators/ConstrainedStringGenerator.kt | 2 +- .../smithy/generators/ServerBuilderSymbol.kt | 8 +- .../smithy/generators/ServerEnumGenerator.kt | 4 +- .../generators/ServerServiceGenerator.kt | 26 ++---- .../http/ServerResponseBindingGenerator.kt | 5 -- .../generators/protocol/ServerProtocol.kt | 4 - .../protocol/ServerProtocolTestGenerator.kt | 2 +- .../smithy/testutil/ServerTestHelpers.kt | 2 + .../smithy/ConstraintsMemberShapeTest.kt | 1 + ...ustCrateInlineModuleComposingWriterTest.kt | 11 ++- .../generators/ServerInstantiatorTest.kt | 2 +- 45 files changed, 382 insertions(+), 185 deletions(-) create mode 100644 codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerRustModule.kt diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/InlineAwsDependency.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/InlineAwsDependency.kt index b127795fc3..4f34f3a750 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/InlineAwsDependency.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/InlineAwsDependency.kt @@ -15,5 +15,9 @@ object InlineAwsDependency { forRustFileAs(file, file, visibility, *additionalDependency) fun forRustFileAs(file: String, moduleName: String, visibility: Visibility = Visibility.PRIVATE, vararg additionalDependency: RustDependency): InlineDependency = - InlineDependency.Companion.forRustFile(RustModule.new(moduleName, visibility), "/aws-inlineable/src/$file.rs", *additionalDependency) + InlineDependency.Companion.forRustFile( + RustModule.new(moduleName, visibility, documentationOverride = ""), + "/aws-inlineable/src/$file.rs", + *additionalDependency, + ) } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/AwsEndpointDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/AwsEndpointDecorator.kt index 7885db72d6..94013f1b8f 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/AwsEndpointDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/AwsEndpointDecorator.kt @@ -15,9 +15,9 @@ import software.amazon.smithy.rulesengine.language.syntax.parameters.Builtins import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameters import software.amazon.smithy.rulesengine.traits.EndpointRuleSetTrait import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext +import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointTypesGenerator -import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.EndpointsModule import software.amazon.smithy.rust.codegen.client.smithy.featureGatedConfigModule import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig @@ -109,7 +109,7 @@ class AwsEndpointDecorator : ClientCodegenDecorator { println("not generating a resolver for ${codegenContext.serviceShape}") return } - rustCrate.withModule(EndpointsModule) { + rustCrate.withModule(ClientRustModule.Endpoint) { // TODO(https://github.com/awslabs/smithy-rs/issues/1784) cleanup task rustTemplate( """ diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenContext.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenContext.kt index 38567aa0cd..e0ec0afb6e 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenContext.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenContext.kt @@ -11,6 +11,7 @@ import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.ModuleDocProvider import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider /** @@ -22,6 +23,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider data class ClientCodegenContext( override val model: Model, override val symbolProvider: RustSymbolProvider, + override val moduleDocProvider: ModuleDocProvider?, override val serviceShape: ServiceShape, override val protocol: ShapeId, override val settings: ClientRustSettings, @@ -29,5 +31,5 @@ data class ClientCodegenContext( // decorator val rootDecorator: ClientCodegenDecorator, ) : CodegenContext( - model, symbolProvider, serviceShape, protocol, settings, CodegenTarget.CLIENT, + model, symbolProvider, moduleDocProvider, serviceShape, protocol, settings, CodegenTarget.CLIENT, ) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenVisitor.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenVisitor.kt index 3c64d5fade..c165c35681 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenVisitor.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenVisitor.kt @@ -18,6 +18,7 @@ import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.model.traits.ErrorTrait +import software.amazon.smithy.model.traits.TitleTrait import software.amazon.smithy.model.transform.ModelTransformer import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator import software.amazon.smithy.rust.codegen.client.smithy.generators.ClientEnumGenerator @@ -69,7 +70,7 @@ class ClientCodegenVisitor( private val rustCrate: RustCrate private val fileManifest = context.fileManifest private val model: Model - private val codegenContext: ClientCodegenContext + private var codegenContext: ClientCodegenContext private val protocolGeneratorFactory: ProtocolGeneratorFactory private val protocolGenerator: ClientProtocolGenerator @@ -100,12 +101,31 @@ class ClientCodegenVisitor( val service = settings.getService(model) symbolProvider = RustClientCodegenPlugin.baseSymbolProvider(settings, model, service, rustSymbolProviderConfig, codegenDecorator) - codegenContext = ClientCodegenContext(model, symbolProvider, service, protocol, settings, codegenDecorator) + codegenContext = ClientCodegenContext( + model, + symbolProvider, + null, + service, + protocol, + settings, + codegenDecorator, + ) + + codegenContext = codegenContext.copy( + moduleDocProvider = codegenDecorator.moduleDocumentationCustomization( + codegenContext, + ClientModuleDocProvider( + settings.codegenConfig, + service.getTrait()?.value ?: "the service", + ), + ), + ) rustCrate = RustCrate( context.fileManifest, symbolProvider, codegenContext.settings.codegenConfig, + codegenContext.expectModuleDocProvider(), ) protocolGenerator = protocolGeneratorFactory.buildProtocolGenerator(codegenContext) } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustModule.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustModule.kt index 895b2c1ff4..a2bc4b6006 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustModule.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustModule.kt @@ -15,6 +15,7 @@ import software.amazon.smithy.model.traits.ErrorTrait import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWords import software.amazon.smithy.rust.codegen.core.rustlang.Visibility +import software.amazon.smithy.rust.codegen.core.smithy.ModuleDocProvider import software.amazon.smithy.rust.codegen.core.smithy.ModuleProvider import software.amazon.smithy.rust.codegen.core.smithy.ModuleProviderContext import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider @@ -22,6 +23,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.contextName import software.amazon.smithy.rust.codegen.core.smithy.module import software.amazon.smithy.rust.codegen.core.smithy.traits.SyntheticInputTrait import software.amazon.smithy.rust.codegen.core.smithy.traits.SyntheticOutputTrait +import software.amazon.smithy.rust.codegen.core.util.PANIC import software.amazon.smithy.rust.codegen.core.util.UNREACHABLE import software.amazon.smithy.rust.codegen.core.util.getTrait import software.amazon.smithy.rust.codegen.core.util.hasTrait @@ -38,32 +40,74 @@ object ClientRustModule { val client = Client.self object Client { /** crate::client */ - val self = RustModule.public("client", "Client and fluent builders for calling the service.") + val self = RustModule.public("client") /** crate::client::customize */ - val customize = RustModule.public("customize", parent = self, documentation = "Operation customization and supporting types") + val customize = RustModule.public("customize", parent = self) } - val Config = RustModule.public("config", documentation = "Configuration for the service.") - val Error = RustModule.public("error", documentation = "All error types that operations can return. Documentation on these types is copied from the model.") - val Operation = RustModule.public("operation", documentation = "All operations that this crate can perform.") - val Meta = RustModule.public("meta", documentation = "Information about this crate.") - val Input = RustModule.public("input", documentation = "Input structures for operations. Documentation on these types is copied from the model.") - val Output = RustModule.public("output", documentation = "Output structures for operations. Documentation on these types is copied from the model.") - val Primitives = RustModule.public("primitives", documentation = "Data primitives referenced by other data types.") + val Config = RustModule.public("config") + val Error = RustModule.public("error") + val Endpoint = RustModule.public("endpoint") + val Operation = RustModule.public("operation") + val Meta = RustModule.public("meta") + val Input = RustModule.public("input") + val Output = RustModule.public("output") + val Primitives = RustModule.public("primitives") /** crate::types */ val types = Types.self object Types { /** crate::types */ - val self = RustModule.public("types", documentation = "Data primitives referenced by other data types.") + val self = RustModule.public("types") /** crate::types::error */ - val Error = RustModule.public("error", parent = self, documentation = "All error types that operations can return. Documentation on these types is copied from the model.") + val Error = RustModule.public("error", parent = self) } // TODO(CrateReorganization): Remove this module when cleaning up `enableNewCrateOrganizationScheme` - val Model = RustModule.public("model", documentation = "Data structures used by operation inputs/outputs. Documentation on these types is copied from the model.") + val Model = RustModule.public("model") +} + +class ClientModuleDocProvider( + private val config: ClientCodegenConfig, + private val serviceName: String, +) : ModuleDocProvider { + override fun docs(module: RustModule.LeafModule): String? = + when (config.enableNewCrateOrganizationScheme) { + true -> when (module) { + ClientRustModule.client -> "Client for calling $serviceName." + ClientRustModule.Client.customize -> "Operation customization and supporting types." + ClientRustModule.Config -> "Configuration for $serviceName." + ClientRustModule.Error -> "Common errors and error handling utilities." + ClientRustModule.Endpoint -> "Endpoint resolution functionality." + ClientRustModule.Operation -> "All operations that this crate can perform." + ClientRustModule.Meta -> "Information about this crate." + ClientRustModule.Input -> PANIC("this module shouldn't exist in the new scheme") + ClientRustModule.Output -> PANIC("this module shouldn't exist in the new scheme") + ClientRustModule.Primitives -> "Primitives such as `Blob` or `DateTime` used by other types." + ClientRustModule.types -> "Data primitives referenced by other data types." + ClientRustModule.Types.Error -> "Error types that $serviceName can respond with." + ClientRustModule.Model -> PANIC("this module shouldn't exist in the new scheme") + else -> TODO("Document this module: $module") + } + else -> when (module) { + ClientRustModule.client -> "Client and fluent builders for calling $serviceName." + ClientRustModule.Client.customize -> "Operation customization and supporting types." + ClientRustModule.Config -> "Configuration for $serviceName." + ClientRustModule.Error -> "All error types that operations can return. Documentation on these types is copied from the model." + ClientRustModule.Endpoint -> "Endpoint resolution functionality." + ClientRustModule.Operation -> "All operations that this crate can perform." + ClientRustModule.Meta -> PANIC("this module shouldn't exist in the old scheme") + ClientRustModule.Input -> "Input structures for operations. Documentation on these types is copied from the model." + ClientRustModule.Output -> "Output structures for operations. Documentation on these types is copied from the model." + ClientRustModule.Primitives -> PANIC("this module shouldn't exist in the old scheme") + ClientRustModule.types -> "Data primitives referenced by other data types." + ClientRustModule.Types.Error -> PANIC("this module shouldn't exist in the old scheme") + ClientRustModule.Model -> "Data structures used by operation inputs/outputs." + else -> TODO("Document this module: $module") + } + } } object ClientModuleProvider : ModuleProvider { @@ -90,7 +134,7 @@ object ClientModuleProvider : ModuleProvider { ): RustModule.LeafModule = ClientRustModule.Error override fun moduleForBuilder(context: ModuleProviderContext, shape: Shape, symbol: Symbol): RustModule.LeafModule = - RustModule.public("builders", parent = symbol.module(), documentation = "Builders") + RustModule.public("builders", parent = symbol.module(), documentationOverride = "Builders") private fun Shape.findOperation(model: Model): OperationShape { val inputTrait = getTrait() @@ -111,7 +155,7 @@ object ClientModuleProvider : ModuleProvider { return RustModule.public( operationModuleName, parent = ClientRustModule.Operation, - documentation = "Types for the `$contextName` operation.", + documentationOverride = "Types for the `$contextName` operation.", ) } } @@ -147,7 +191,7 @@ object OldModuleSchemeClientModuleProvider : ModuleProvider { visibility = Visibility.PUBLIC, parent = symbol.module(), inline = true, - documentation = "See [`${symbol.name}`](${symbol.module().fullyQualifiedPath()}::${symbol.name}).", + documentationOverride = "See [`${symbol.name}`](${symbol.module().fullyQualifiedPath()}::${symbol.name}).", ) } } @@ -163,8 +207,8 @@ fun ClientCodegenContext.featureGatedCustomizeModule() = when (settings.codegenC true -> ClientRustModule.Client.customize else -> RustModule.public( "customize", - "Operation customization and supporting types", parent = ClientRustModule.Operation, + documentationOverride = "Operation customization and supporting types", ) } @@ -180,9 +224,9 @@ fun ClientCodegenContext.featureGatedPaginatorModule(symbolProvider: RustSymbolP true -> RustModule.public( "paginator", parent = symbolProvider.moduleForShape(operation), - documentation = "Paginator for this operation", + documentationOverride = "Paginator for this operation", ) - else -> RustModule.public("paginator", "Paginators for the service") + else -> RustModule.public("paginator", documentationOverride = "Paginators for the service") } // TODO(CrateReorganization): Remove when cleaning up `enableNewCrateOrganizationScheme` diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointConfigCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointConfigCustomization.kt index 1b31dec174..d6bb2cccc7 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointConfigCustomization.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointConfigCustomization.kt @@ -6,7 +6,7 @@ package software.amazon.smithy.rust.codegen.client.smithy.endpoint import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext -import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.EndpointsModule +import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig import software.amazon.smithy.rust.codegen.core.rustlang.Writable @@ -128,21 +128,22 @@ internal class EndpointConfigCustomization( "DefaultResolver" to defaultResolver, ) } else { - val alwaysFailsResolver = RuntimeType.forInlineFun("MissingResolver", EndpointsModule) { - rustTemplate( - """ - pub(crate) struct MissingResolver; - impl #{ResolveEndpoint} for MissingResolver { - fn resolve_endpoint(&self, _params: &T) -> #{Result} { - Err(#{ResolveEndpointError}::message("an endpoint resolver must be provided.")) + val alwaysFailsResolver = + RuntimeType.forInlineFun("MissingResolver", ClientRustModule.Endpoint) { + rustTemplate( + """ + pub(crate) struct MissingResolver; + impl #{ResolveEndpoint} for MissingResolver { + fn resolve_endpoint(&self, _params: &T) -> #{Result} { + Err(#{ResolveEndpointError}::message("an endpoint resolver must be provided.")) + } } - } - """, - "ResolveEndpoint" to types.resolveEndpoint, - "ResolveEndpointError" to types.resolveEndpointError, - "Result" to types.smithyHttpEndpointModule.resolve("Result"), - ) - } + """, + "ResolveEndpoint" to types.resolveEndpoint, + "ResolveEndpointError" to types.resolveEndpointError, + "Result" to types.smithyHttpEndpointModule.resolve("Result"), + ) + } // To keep this diff under control, rather than `.expect` here, insert a resolver that will // always fail. In the future, this will be changed to an `expect()` rustTemplate( diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt index 3b8edb69ad..4cfaafd2b9 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt @@ -14,11 +14,11 @@ import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameter import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameters import software.amazon.smithy.rulesengine.traits.ContextIndex import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext +import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.CustomRuntimeFunction import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.EndpointParamsGenerator import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.EndpointTests -import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.EndpointsModule import software.amazon.smithy.rust.codegen.client.smithy.endpoint.rulesgen.SmithyEndpointsStdLib import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization import software.amazon.smithy.rust.codegen.core.rustlang.Writable @@ -133,8 +133,8 @@ class EndpointsDecorator : ClientCodegenDecorator { override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { val generator = EndpointTypesGenerator.fromContext(codegenContext) - rustCrate.withModule(EndpointsModule) { - withInlineModule(EndpointTests) { + rustCrate.withModule(ClientRustModule.Endpoint) { + withInlineModule(EndpointTests, rustCrate.moduleDocProvider) { generator.testGenerator()(this) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt index 5e5b3d7b2f..ed283bc6de 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt @@ -10,7 +10,7 @@ import software.amazon.smithy.rulesengine.language.syntax.Identifier import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameter import software.amazon.smithy.rulesengine.language.syntax.parameters.ParameterType import software.amazon.smithy.rulesengine.traits.ContextParamTrait -import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.EndpointsStdLib +import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.EndpointStdLib import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.FunctionRegistry import software.amazon.smithy.rust.codegen.core.rustlang.InlineDependency import software.amazon.smithy.rust.codegen.core.rustlang.RustDependency @@ -38,7 +38,7 @@ fun Identifier.rustName(): String { internal fun endpointsLib(name: String, vararg additionalDependency: RustDependency) = InlineDependency.forRustFile( RustModule.pubCrate( name, - parent = EndpointsStdLib, + parent = EndpointStdLib, ), "/inlineable/src/endpoint_lib/$name.rs", *additionalDependency, diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsGenerator.kt index b2a7bde292..286f34443d 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsGenerator.kt @@ -8,6 +8,7 @@ package software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators import software.amazon.smithy.rulesengine.language.eval.Value import software.amazon.smithy.rulesengine.language.syntax.Identifier import software.amazon.smithy.rulesengine.language.syntax.parameters.Parameters +import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule import software.amazon.smithy.rust.codegen.client.smithy.endpoint.memberName import software.amazon.smithy.rust.codegen.client.smithy.endpoint.rustName import software.amazon.smithy.rust.codegen.client.smithy.endpoint.symbol @@ -34,34 +35,19 @@ import software.amazon.smithy.rust.codegen.core.smithy.rustType import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.orNull -/** - * The module containing all endpoint resolution machinery. Module layout: - * ``` - * crate::endpoints:: - * struct Params // Endpoint parameter struct - * struct ParamsBuilder // Builder for Params - * enum InvalidParams - * DefaultResolver // struct implementing the endpoint resolver based on the provided rules for the service - * internal // private module containing the endpoints library functions, the private version of the default resolver - * endpoints_lib::{endpoints_fn*, ...} - * fn default_resolver(params: &Params, partition_metadata: &PartitionMetadata, error_collector: &mut ErrorCollector) - * ``` - */ -val EndpointsModule = RustModule.public("endpoint", "Endpoint resolution functionality") - // internals contains the actual resolver function -val EndpointsImpl = RustModule.private("internals", "Endpoints internals", parent = EndpointsModule) +val EndpointImpl = RustModule.private("internals", parent = ClientRustModule.Endpoint) val EndpointTests = RustModule.new( "test", visibility = Visibility.PRIVATE, - documentation = "Generated endpoint tests", - parent = EndpointsModule, + parent = ClientRustModule.Endpoint, inline = true, + documentationOverride = "", ).cfgTest() // stdlib is isolated because it contains code generated names of stdlib functions–we want to ensure we avoid clashing -val EndpointsStdLib = RustModule.private("endpoint_lib", "Endpoints standard library functions") +val EndpointStdLib = RustModule.private("endpoint_lib") /** Endpoint Parameters generator. * @@ -128,15 +114,15 @@ internal class EndpointParamsGenerator(private val parameters: Parameters) { fun setterName(parameterName: String) = "set_${memberName(parameterName)}" } - fun paramsStruct(): RuntimeType = RuntimeType.forInlineFun("Params", EndpointsModule) { + fun paramsStruct(): RuntimeType = RuntimeType.forInlineFun("Params", ClientRustModule.Endpoint) { generateEndpointsStruct(this) } - private fun endpointsBuilder(): RuntimeType = RuntimeType.forInlineFun("ParamsBuilder", EndpointsModule) { + private fun endpointsBuilder(): RuntimeType = RuntimeType.forInlineFun("ParamsBuilder", ClientRustModule.Endpoint) { generateEndpointParamsBuilder(this) } - private fun paramsError(): RuntimeType = RuntimeType.forInlineFun("InvalidParams", EndpointsModule) { + private fun paramsError(): RuntimeType = RuntimeType.forInlineFun("InvalidParams", ClientRustModule.Endpoint) { rust( """ /// An error that occurred during endpoint resolution diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointResolverGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointResolverGenerator.kt index d4f3fe32f0..5fade8768d 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointResolverGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointResolverGenerator.kt @@ -15,6 +15,7 @@ import software.amazon.smithy.rulesengine.language.syntax.fn.IsSet import software.amazon.smithy.rulesengine.language.syntax.rule.Condition import software.amazon.smithy.rulesengine.language.syntax.rule.Rule import software.amazon.smithy.rulesengine.language.visit.RuleValueVisitor +import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule import software.amazon.smithy.rust.codegen.client.smithy.endpoint.Context import software.amazon.smithy.rust.codegen.client.smithy.endpoint.Types import software.amazon.smithy.rust.codegen.client.smithy.endpoint.endpointsLib @@ -164,7 +165,7 @@ internal class EndpointResolverGenerator(stdlib: List, ru // Now that we rendered the rules once (and then threw it away) we can see what functions we actually used! val fnsUsed = registry.fnsUsed() - return RuntimeType.forInlineFun("DefaultResolver", EndpointsModule) { + return RuntimeType.forInlineFun("DefaultResolver", ClientRustModule.Endpoint) { rustTemplate( """ /// The default endpoint resolver @@ -202,7 +203,7 @@ internal class EndpointResolverGenerator(stdlib: List, ru endpointRuleSet: EndpointRuleSet, fnsUsed: List, ): RuntimeType { - return RuntimeType.forInlineFun("resolve_endpoint", EndpointsImpl) { + return RuntimeType.forInlineFun("resolve_endpoint", EndpointImpl) { Attribute(allow(allowLintsForResolver)).render(this) rustTemplate( """ diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/NestedAccessorGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/NestedAccessorGenerator.kt index 2976a57b16..2c752814be 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/NestedAccessorGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/NestedAccessorGenerator.kt @@ -23,7 +23,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.protocols.nestedAccessorN /** Generator for accessing nested fields through optional values **/ class NestedAccessorGenerator(private val codegenContext: CodegenContext) { private val symbolProvider = codegenContext.symbolProvider - private val module = RustModule.private("lens", "Generated accessors for nested fields") + private val module = RustModule.private("lens") /** * Generate an accessor on [root] that consumes [root] and returns an `Option` for the nested item diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 5a70ab92a5..ac2b15dc70 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -426,7 +426,7 @@ private fun OperationShape.fluentBuilderModule( else -> RustModule.public( "fluent_builders", parent = ClientRustModule.client, - documentation = """ + documentationOverride = """ Utilities to ergonomically construct a request to the service. Fluent builders are created through the [`Client`](crate::client::Client) by calling diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt index 5e9fc23cb0..5a1c4993b0 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt @@ -92,7 +92,10 @@ class ProtocolTestGenerator( val additionalAttributes = listOf( Attribute(allow("unreachable_code", "unused_variables")), ) - writer.withInlineModule(RustModule.inlineTests(testModuleName, additionalAttributes = additionalAttributes)) { + writer.withInlineModule( + RustModule.inlineTests(testModuleName, additionalAttributes = additionalAttributes), + null, + ) { renderAllTestCases(allTests) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/testutil/TestHelpers.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/testutil/TestHelpers.kt index ae2d67205f..8cc56a8350 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/testutil/TestHelpers.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/testutil/TestHelpers.kt @@ -20,6 +20,7 @@ import software.amazon.smithy.rust.codegen.client.smithy.customize.CombinedClien import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProviderConfig +import software.amazon.smithy.rust.codegen.core.testutil.TestModuleDocProvider import software.amazon.smithy.rust.codegen.core.testutil.TestRuntimeConfig import software.amazon.smithy.rust.codegen.core.testutil.TestWriterDelegator @@ -79,6 +80,7 @@ fun testClientCodegenContext( ): ClientCodegenContext = ClientCodegenContext( model, symbolProvider ?: testSymbolProvider(model), + TestModuleDocProvider, serviceShape ?: model.serviceShapes.firstOrNull() ?: ServiceShape.builder().version("test").id("test#Service").build(), diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustModule.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustModule.kt index b0fa7354f8..b8c3237e41 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustModule.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustModule.kt @@ -5,6 +5,7 @@ package software.amazon.smithy.rust.codegen.core.rustlang +import software.amazon.smithy.rust.codegen.core.smithy.ModuleDocProvider import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.util.PANIC @@ -30,11 +31,11 @@ sealed class RustModule { data class LeafModule( val name: String, val rustMetadata: RustMetadata, - val documentation: String? = null, val parent: RustModule = LibRs, val inline: Boolean = false, /* module is a cfg(test) module */ val tests: Boolean = false, + val documentationOverride: String? = null, ) : RustModule() { init { @@ -63,37 +64,40 @@ sealed class RustModule { fun new( name: String, visibility: Visibility, - documentation: String? = null, inline: Boolean = false, parent: RustModule = LibRs, additionalAttributes: List = listOf(), + documentationOverride: String? = null, ): LeafModule { return LeafModule( RustReservedWords.escapeIfNeeded(name), RustMetadata(visibility = visibility, additionalAttributes = additionalAttributes), - documentation, inline = inline, parent = parent, + documentationOverride = documentationOverride, ) } /** Creates a new public module */ - fun public(name: String, documentation: String? = null, parent: RustModule = LibRs): LeafModule = - new(name, visibility = Visibility.PUBLIC, documentation = documentation, inline = false, parent = parent) + fun public(name: String, parent: RustModule = LibRs, documentationOverride: String? = null): LeafModule = + new( + name, + visibility = Visibility.PUBLIC, + inline = false, + parent = parent, + documentationOverride = documentationOverride, + ) /** Creates a new private module */ - fun private(name: String, documentation: String? = null, parent: RustModule = LibRs): LeafModule = - new(name, visibility = Visibility.PRIVATE, documentation = documentation, inline = false, parent = parent) + fun private(name: String, parent: RustModule = LibRs): LeafModule = + new(name, visibility = Visibility.PRIVATE, inline = false, parent = parent) fun pubCrate( name: String, - documentation: String? = null, parent: RustModule = LibRs, additionalAttributes: List = emptyList(), ): LeafModule = new( - name, - visibility = Visibility.PUBCRATE, - documentation = documentation, + name, visibility = Visibility.PUBCRATE, inline = false, parent = parent, additionalAttributes = additionalAttributes, @@ -110,17 +114,6 @@ sealed class RustModule { additionalAttributes = additionalAttributes, parent = parent, ).cfgTest() - - /** - * Helper method to generate the `operation` Rust module. - * Its visibility depends on the generation context (client or server). - */ - fun operation(visibility: Visibility): RustModule = - new( - "operation", - visibility = visibility, - documentation = "All operations that this crate can perform.", - ) } fun isInline(): Boolean = when (this) { @@ -154,13 +147,13 @@ sealed class RustModule { * pub mod my_module_name * ``` */ - fun renderModStatement(writer: RustWriter) { + fun renderModStatement(writer: RustWriter, moduleDocProvider: ModuleDocProvider) { when (this) { is LeafModule -> { if (name.startsWith("r#")) { PANIC("Something went wrong with module name escaping (module named '$name'). This is a bug.") } - documentation?.let { docs -> writer.docs(docs) } + ModuleDocProvider.writeDocs(moduleDocProvider, this, writer) rustMetadata.render(writer) writer.write("mod $name;") } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt index 1628fe9cca..82691791af 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt @@ -24,6 +24,7 @@ import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.traits.DeprecatedTrait import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.deprecated +import software.amazon.smithy.rust.codegen.core.smithy.ModuleDocProvider import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.isOptional import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.ValueExpression @@ -533,11 +534,13 @@ class RustWriter private constructor( */ fun withInlineModule( module: RustModule.LeafModule, + moduleDocProvider: ModuleDocProvider?, moduleWriter: Writable, ): RustWriter { check(module.isInline()) { "Only inline modules may be used with `withInlineModule`: $module" } + // In Rust, modules must specify their own imports—they don't have access to the parent scope. // To easily handle this, create a new inner writer to collect imports, then dump it // into an inline module. @@ -548,7 +551,7 @@ class RustWriter private constructor( devDependenciesOnly = devDependenciesOnly || module.tests, ) moduleWriter(innerWriter) - module.documentation?.let { docs -> docs(docs) } + ModuleDocProvider.writeDocs(moduleDocProvider, module, this) module.rustMetadata.render(this) rustBlock("mod ${module.name}") { writeWithNoFormatting(innerWriter.toString()) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenContext.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenContext.kt index 17a21c887c..3fa6f688e3 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenContext.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenContext.kt @@ -31,6 +31,11 @@ open class CodegenContext( */ open val symbolProvider: RustSymbolProvider, + /** + * Provider of documentation for generated Rust modules. + */ + open val moduleDocProvider: ModuleDocProvider?, + /** * Entrypoint service shape for code generation. */ @@ -79,4 +84,9 @@ open class CodegenContext( * it must be in snake-case. Call this method to get this crate's name in snake-case. */ fun moduleUseName() = moduleName.replace("-", "_") + + /** Return a ModuleDocProvider or panic if one wasn't configured */ + fun expectModuleDocProvider(): ModuleDocProvider = checkNotNull(moduleDocProvider) { + "A ModuleDocProvider must be set on the CodegenContext" + } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt index cbfb2cc39a..0db54ecd63 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt @@ -18,13 +18,43 @@ import software.amazon.smithy.rust.codegen.core.rustlang.InlineDependency import software.amazon.smithy.rust.codegen.core.rustlang.RustDependency import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.core.rustlang.Visibility import software.amazon.smithy.rust.codegen.core.rustlang.Writable +import software.amazon.smithy.rust.codegen.core.rustlang.docs import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.smithy.generators.CargoTomlGenerator import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsGenerator import software.amazon.smithy.rust.codegen.core.smithy.generators.ManifestCustomizations +/** Provider of documentation for generated Rust modules */ +interface ModuleDocProvider { + companion object { + fun writeDocs(provider: ModuleDocProvider?, module: RustModule.LeafModule, writer: RustWriter) { + check( + provider != null || + module.documentationOverride != null || + module.rustMetadata.visibility != Visibility.PUBLIC, + ) { + "Documentation must be provided for public modules, either via ModuleDocumentationProvider, or " + + "by the module documentationOverride. Module: $module" + } + try { + val docs = module.documentationOverride ?: provider?.docs(module) + docs?.also(writer::docs) + } catch (e: NotImplementedError) { + // Catch `TODO()` and rethrow only if its a public module + if (module.rustMetadata.visibility == Visibility.PUBLIC) { + throw e + } + } + } + } + + /** Returns documentation for the given module */ + fun docs(module: RustModule.LeafModule): String? +} + /** * RustCrate abstraction. * @@ -46,6 +76,7 @@ open class RustCrate( fileManifest: FileManifest, private val symbolProvider: SymbolProvider, coreCodegenConfig: CoreCodegenConfig, + val moduleDocProvider: ModuleDocProvider, ) { private val inner = WriterDelegator(fileManifest, symbolProvider, RustWriter.factory(coreCodegenConfig.debugMode)) private val features: MutableSet = mutableSetOf() @@ -152,13 +183,13 @@ open class RustCrate( if (module.isInline()) { withModule(module.parent) { - withInlineModule(module, moduleWriter) + withInlineModule(module, moduleDocProvider, moduleWriter) } } else { // Create a dependency which adds the mod statement for this module. This will be added to the writer // so that _usage_ of this module will generate _exactly one_ `mod ` with the correct modifiers. val modStatement = RuntimeType.forInlineFun("mod_" + module.fullyQualifiedPath(), module.parent) { - module.renderModStatement(this) + module.renderModStatement(this, moduleDocProvider) } val path = module.fullyQualifiedPath().split("::").drop(1).joinToString("/") inner.useFileWriter("src/$path.rs", module.fullyQualifiedPath()) { writer -> @@ -204,10 +235,8 @@ open class RustCrate( } // TODO(https://github.com/awslabs/smithy-rs/issues/2341): Remove unconstrained/constrained from codegen-core -val UnconstrainedModule = - RustModule.private("unconstrained", "Unconstrained types for constrained shapes.") -val ConstrainedModule = - RustModule.private("constrained", "Constrained types for constrained shapes.") +val UnconstrainedModule = RustModule.private("unconstrained") +val ConstrainedModule = RustModule.private("constrained") /** * Finalize all the writers by: diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customize/CoreCodegenDecorator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customize/CoreCodegenDecorator.kt index 924c9628d4..1df3fb7dd3 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customize/CoreCodegenDecorator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customize/CoreCodegenDecorator.kt @@ -8,6 +8,7 @@ package software.amazon.smithy.rust.codegen.core.smithy.customize import software.amazon.smithy.build.PluginContext import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.ServiceShape +import software.amazon.smithy.rust.codegen.core.smithy.ModuleDocProvider import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderCustomization @@ -49,6 +50,14 @@ interface CoreCodegenDecorator { */ fun extras(codegenContext: CodegenContext, rustCrate: RustCrate) {} + /** + * Customize the documentation provider for module documentation. + */ + fun moduleDocumentationCustomization( + codegenContext: CodegenContext, + baseModuleDocProvider: ModuleDocProvider, + ): ModuleDocProvider = baseModuleDocProvider + /** * Hook to customize the generated `Cargo.toml` file. * @@ -124,6 +133,13 @@ abstract class CombinedCoreCodegenDecorator + decorator.moduleDocumentationCustomization(codegenContext, base) + } + final override fun libRsCustomizations( codegenContext: CodegenContext, baseCustomizations: List, diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 613a12252d..e3e8f13206 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -26,6 +26,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.raw import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock import software.amazon.smithy.rust.codegen.core.smithy.CoreCodegenConfig +import software.amazon.smithy.rust.codegen.core.smithy.ModuleDocProvider import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider @@ -39,6 +40,12 @@ import java.nio.file.Files.createTempDirectory import java.nio.file.Path import kotlin.io.path.absolutePathString +val TestModuleDocProvider = object : ModuleDocProvider { + override fun docs(module: RustModule.LeafModule): String? { + return "Some test documentation\n\nSome more details..." + } +} + /** * Waiting for Kotlin to stabilize their temp directory functionality */ @@ -269,12 +276,8 @@ class TestWriterDelegator( private val fileManifest: FileManifest, symbolProvider: RustSymbolProvider, val codegenConfig: CoreCodegenConfig, -) : - RustCrate( - fileManifest, - symbolProvider, - codegenConfig, - ) { + moduleDocProvider: ModuleDocProvider = TestModuleDocProvider, +) : RustCrate(fileManifest, symbolProvider, codegenConfig, moduleDocProvider) { val baseDir: Path = fileManifest.baseDir fun printGeneratedFiles() { @@ -289,7 +292,13 @@ class TestWriterDelegator( * * This should only be used in test code—the generated module name will be something like `tests_123` */ -fun RustCrate.testModule(block: Writable) = lib { withInlineModule(RustModule.inlineTests(safeName("tests")), block) } +fun RustCrate.testModule(block: Writable) = lib { + withInlineModule( + RustModule.inlineTests(safeName("tests")), + TestModuleDocProvider, + block, + ) +} fun FileManifest.printGeneratedFiles() { this.files.forEach { path -> @@ -468,7 +477,7 @@ fun RustCrate.integrationTest(name: String, writable: Writable) = this.withFile( fun TestWriterDelegator.unitTest(test: Writable): TestWriterDelegator { lib { val name = safeName("test") - withInlineModule(RustModule.inlineTests(name)) { + withInlineModule(RustModule.inlineTests(name), TestModuleDocProvider) { unitTest(name) { test(this) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt index 574e9daa04..8524fc38b4 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt @@ -57,11 +57,11 @@ val TestRuntimeConfig = private object CodegenCoreTestModules { // Use module paths that don't align with either server or client to make sure // the codegen is resilient to differences in module path. - val ModelsTestModule = RustModule.public("test_model", documentation = "Test models module") - val ErrorsTestModule = RustModule.public("test_error", documentation = "Test error module") - val InputsTestModule = RustModule.public("test_input", documentation = "Test input module") - val OutputsTestModule = RustModule.public("test_output", documentation = "Test output module") - val OperationsTestModule = RustModule.public("test_operation", documentation = "Test operation module") + val ModelsTestModule = RustModule.public("test_model") + val ErrorsTestModule = RustModule.public("test_error") + val InputsTestModule = RustModule.public("test_input") + val OutputsTestModule = RustModule.public("test_output") + val OperationsTestModule = RustModule.public("test_operation") object TestModuleProvider : ModuleProvider { override fun moduleForShape(context: ModuleProviderContext, shape: Shape): RustModule.LeafModule = @@ -155,6 +155,7 @@ internal fun testCodegenContext( ): CodegenContext = CodegenContext( model, testSymbolProvider(model), + TestModuleDocProvider, serviceShape ?: model.serviceShapes.firstOrNull() ?: ServiceShape.builder().version("test").id("test#Service").build(), diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/InlineDependencyTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/InlineDependencyTest.kt index 9664ce1dac..9d613f558f 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/InlineDependencyTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/InlineDependencyTest.kt @@ -80,8 +80,8 @@ internal class InlineDependencyTest { fun `prevent the creation of duplicate modules`() { val root = RustModule.private("parent") // create a child module with no docs - val child1 = RustModule.private("child", parent = root) - val child2 = RustModule.public("child", parent = root) + val child1 = RustModule.public("child", parent = root) + val child2 = RustModule.private("child", parent = root) val crate = TestWorkspace.testProject() crate.withModule(child1) { } shouldThrow { @@ -90,11 +90,11 @@ internal class InlineDependencyTest { shouldThrow { // can't make one with docs when the old one had no docs - crate.withModule(RustModule.private("child", documentation = "docs", parent = root)) {} + crate.withModule(child1.copy(documentationOverride = "docs")) {} } // but making an identical module is fine - val identicalChild = RustModule.private("child", parent = root) + val identicalChild = RustModule.public("child", parent = root) crate.withModule(identicalChild) {} identicalChild.fullyQualifiedPath() shouldBe "crate::parent::child" } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt index 0d8f93617c..eb78c76962 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt @@ -18,6 +18,7 @@ import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.deprecated import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.core.testutil.TestModuleDocProvider import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.compileAndRun import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest @@ -30,7 +31,10 @@ class RustWriterTest { fun `inner modules correctly handle dependencies`() { val sut = RustWriter.forModule("parent") val requestBuilder = RuntimeType.HttpRequestBuilder - sut.withInlineModule(RustModule.new("inner", visibility = Visibility.PUBLIC, inline = true)) { + sut.withInlineModule( + RustModule.new("inner", visibility = Visibility.PUBLIC, inline = true), + TestModuleDocProvider, + ) { rustBlock("fn build(builder: #T)", requestBuilder) { } } diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt index ad1cbf275f..e58f21a832 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt @@ -17,7 +17,6 @@ import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.model.shapes.UnionShape import software.amazon.smithy.model.traits.EnumTrait import software.amazon.smithy.model.traits.ErrorTrait -import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProviderConfig @@ -29,6 +28,7 @@ import software.amazon.smithy.rust.codegen.server.python.smithy.generators.Pytho import software.amazon.smithy.rust.codegen.server.python.smithy.generators.PythonServerStructureGenerator import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenVisitor +import software.amazon.smithy.rust.codegen.server.smithy.ServerModuleDocProvider import software.amazon.smithy.rust.codegen.server.smithy.ServerModuleProvider import software.amazon.smithy.rust.codegen.server.smithy.ServerRustSettings import software.amazon.smithy.rust.codegen.server.smithy.ServerSymbolProviders @@ -99,6 +99,7 @@ class PythonServerCodegenVisitor( ServerCodegenContext( model, serverSymbolProviders.symbolProvider, + null, service, protocol, settings, @@ -108,8 +109,20 @@ class PythonServerCodegenVisitor( serverSymbolProviders.pubCrateConstrainedShapeSymbolProvider, ) + codegenContext = codegenContext.copy( + moduleDocProvider = codegenDecorator.moduleDocumentationCustomization( + codegenContext, + PythonServerModuleDocProvider(ServerModuleDocProvider()), + ), + ) + // Override `rustCrate` which carries the symbolProvider. - rustCrate = RustCrate(context.fileManifest, codegenContext.symbolProvider, settings.codegenConfig) + rustCrate = RustCrate( + context.fileManifest, + codegenContext.symbolProvider, + settings.codegenConfig, + codegenContext.expectModuleDocProvider(), + ) // Override `protocolGenerator` which carries the symbolProvider. protocolGenerator = protocolGeneratorFactory.buildProtocolGenerator(codegenContext) } @@ -191,7 +204,7 @@ class PythonServerCodegenVisitor( override fun operationShape(shape: OperationShape) { super.operationShape(shape) - rustCrate.withModule(RustModule.public("python_operation_adaptor")) { + rustCrate.withModule(PythonServerRustModule.PythonOperationAdapter) { PythonServerOperationHandlerGenerator(codegenContext, shape).render(this) } } diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerRustModule.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerRustModule.kt new file mode 100644 index 0000000000..063e7ea1b0 --- /dev/null +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerRustModule.kt @@ -0,0 +1,25 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.server.python.smithy + +import software.amazon.smithy.rust.codegen.core.rustlang.RustModule +import software.amazon.smithy.rust.codegen.core.smithy.ModuleDocProvider + +object PythonServerRustModule { + val PythonModuleExport = RustModule.public("python_module_export") + val PythonOperationAdapter = RustModule.public("python_operation_adaptor") + val PythonServerApplication = RustModule.public("python_server_application") +} + +class PythonServerModuleDocProvider(private val base: ModuleDocProvider) : ModuleDocProvider { + override fun docs(module: RustModule.LeafModule): String? = when (module) { + PythonServerRustModule.PythonModuleExport -> "Export PyO3 symbols in the shared library" + PythonServerRustModule.PythonServerApplication -> "Python server and application implementation." + // TODO(ServerTeam): Document this module (I don't have context) + PythonServerRustModule.PythonOperationAdapter -> "" + else -> base.docs(module) + } +} diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerModuleGenerator.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerModuleGenerator.kt index df7e246880..689865e9d2 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerModuleGenerator.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerModuleGenerator.kt @@ -10,13 +10,13 @@ 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.shapes.Shape -import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.rustBlockTemplate import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.util.toSnakeCase import software.amazon.smithy.rust.codegen.server.python.smithy.PythonServerCargoDependency +import software.amazon.smithy.rust.codegen.server.python.smithy.PythonServerRustModule import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext class PythonServerModuleGenerator( @@ -32,9 +32,7 @@ class PythonServerModuleGenerator( private val libName = codegenContext.settings.moduleName.toSnakeCase() fun render() { - rustCrate.withModule( - RustModule.public("python_module_export", "Export PyO3 symbols in the shared library"), - ) { + rustCrate.withModule(PythonServerRustModule.PythonModuleExport) { rustBlockTemplate( """ ##[#{pyo3}::pymodule] diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerServiceGenerator.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerServiceGenerator.kt index 58e87bc388..d205a84bb3 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerServiceGenerator.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerServiceGenerator.kt @@ -6,10 +6,10 @@ package software.amazon.smithy.rust.codegen.server.python.smithy.generators import software.amazon.smithy.model.shapes.OperationShape -import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.generators.protocol.ProtocolSupport +import software.amazon.smithy.rust.codegen.server.python.smithy.PythonServerRustModule import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.generators.ServerServiceGenerator import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocol @@ -34,7 +34,7 @@ class PythonServerServiceGenerator( } override fun renderExtras(operations: List) { - rustCrate.withModule(RustModule.public("python_server_application", "Python server and application implementation.")) { + rustCrate.withModule(PythonServerRustModule.PythonServerApplication) { PythonApplicationGenerator(context, protocol, operations) .render(this) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstrainedShapeSymbolProvider.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstrainedShapeSymbolProvider.kt index 25b1000977..15e5a61dd0 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstrainedShapeSymbolProvider.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstrainedShapeSymbolProvider.kt @@ -182,6 +182,7 @@ class ConstrainedShapeSymbolProvider( visibility = Visibility.publicIf(!pubCrateServerBuilder, Visibility.PUBCRATE), parent = defaultModule, inline = true, + documentationOverride = "", ) val renameTo = syntheticMemberTrait.member.memberName ?: syntheticMemberTrait.member.id.name Pair(renameTo.toPascalCase(), innerModule) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintViolationSymbolProvider.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintViolationSymbolProvider.kt index 969b95a6f8..c42ed10198 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintViolationSymbolProvider.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintViolationSymbolProvider.kt @@ -82,7 +82,7 @@ class ConstraintViolationSymbolProvider( val symbol = base.toSymbol(this) "See [`${this.contextName(serviceShape)}`]($symbol)." } else { - null + "" } val syntheticTrait = getTrait() @@ -103,7 +103,7 @@ class ConstraintViolationSymbolProvider( visibility = visibility, parent = module, inline = true, - documentation = documentation, + documentationOverride = documentation, ) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt index 4bac39c2df..8152272a1c 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt @@ -31,6 +31,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWords import software.amazon.smithy.rust.codegen.core.rustlang.Visibility import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext import software.amazon.smithy.rust.codegen.core.smithy.DirectedWalker +import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.isOptional import software.amazon.smithy.rust.codegen.core.smithy.module import software.amazon.smithy.rust.codegen.core.util.UNREACHABLE @@ -182,7 +183,7 @@ fun Shape.overriddenConstrainedMemberInfo(): Pair? { /** * Returns the parent and the inline module that this particular shape should go in. */ -fun Shape.getParentAndInlineModuleForConstrainedMember(symbolProvider: SymbolProvider, publicConstrainedTypes: Boolean): Pair? { +fun Shape.getParentAndInlineModuleForConstrainedMember(symbolProvider: RustSymbolProvider, publicConstrainedTypes: Boolean): Pair? { val overriddenTrait = getTrait() ?: return null return if (overriddenTrait.container is StructureShape) { val structureModule = symbolProvider.toSymbol(overriddenTrait.container).module() diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriter.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriter.kt index f4f352260e..32abe41d69 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriter.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriter.kt @@ -10,6 +10,7 @@ import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Writable +import software.amazon.smithy.rust.codegen.core.smithy.ModuleDocProvider import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.module import java.util.concurrent.ConcurrentHashMap @@ -22,13 +23,13 @@ typealias InlineModuleCreator = (Symbol, Writable) -> Unit */ fun RustCrate.initializeInlineModuleWriter(debugMode: Boolean): InnerModule = crateToInlineModule - .getOrPut(this) { InnerModule(debugMode) } + .getOrPut(this) { InnerModule(moduleDocProvider, debugMode) } /** * Returns the InnerModule for the given RustCrate */ fun RustCrate.getInlineModuleWriter(): InnerModule { - return crateToInlineModule.getOrPut(this) { InnerModule(false) } + return crateToInlineModule.getOrPut(this) { InnerModule(moduleDocProvider, false) } } /** @@ -126,7 +127,7 @@ fun RustCrate.withInMemoryInlineModule( fun RustWriter.createTestInlineModuleCreator(): InlineModuleCreator { return { symbol: Symbol, writable: Writable -> - this.withInlineModule(symbol.module()) { + this.withInlineModule(symbol.module(), null) { writable() } } @@ -143,7 +144,7 @@ private data class InlineModuleWithWriter(val inlineModule: RustModule.LeafModul private val crateToInlineModule: ConcurrentHashMap = ConcurrentHashMap() -class InnerModule(debugMode: Boolean) { +class InnerModule(private val moduleDocProvider: ModuleDocProvider, debugMode: Boolean) { // Holds the root modules to start rendering the descendents from. private val topLevelModuleWriters: ConcurrentHashMap = ConcurrentHashMap() private val inlineModuleWriters: ConcurrentHashMap> = ConcurrentHashMap() @@ -272,7 +273,7 @@ class InnerModule(debugMode: Boolean) { inlineModuleWriters[inMemoryWriter]!!.forEach { writeDocs(it.inlineModule) - topLevelWriter.withInlineModule(it.inlineModule) { + topLevelWriter.withInlineModule(it.inlineModule, moduleDocProvider) { writeInlineCode(this, it.writer.toString()) renderDescendents(this, it.writer) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenContext.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenContext.kt index e71ae7ded1..d5c2a7084a 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenContext.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenContext.kt @@ -10,6 +10,7 @@ import software.amazon.smithy.model.shapes.ServiceShape import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.ModuleDocProvider import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider /** @@ -24,6 +25,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider data class ServerCodegenContext( override val model: Model, override val symbolProvider: RustSymbolProvider, + override val moduleDocProvider: ModuleDocProvider?, override val serviceShape: ServiceShape, override val protocol: ShapeId, override val settings: ServerRustSettings, @@ -32,5 +34,5 @@ data class ServerCodegenContext( val constraintViolationSymbolProvider: ConstraintViolationSymbolProvider, val pubCrateConstrainedShapeSymbolProvider: PubCrateConstrainedShapeSymbolProvider, ) : CodegenContext( - model, symbolProvider, serviceShape, protocol, settings, CodegenTarget.SERVER, + model, symbolProvider, moduleDocProvider, serviceShape, protocol, settings, CodegenTarget.SERVER, ) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt index 50b6a2007e..0a238af19d 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt @@ -139,6 +139,7 @@ open class ServerCodegenVisitor( codegenContext = ServerCodegenContext( model, serverSymbolProviders.symbolProvider, + null, service, protocol, settings, @@ -151,7 +152,19 @@ open class ServerCodegenVisitor( // We can use a not-null assertion because [CombinedServerCodegenDecorator] returns a not null value. validationExceptionConversionGenerator = codegenDecorator.validationExceptionConversion(codegenContext)!! - rustCrate = RustCrate(context.fileManifest, codegenContext.symbolProvider, settings.codegenConfig) + codegenContext = codegenContext.copy( + moduleDocProvider = codegenDecorator.moduleDocumentationCustomization( + codegenContext, + ServerModuleDocProvider(), + ), + ) + + rustCrate = RustCrate( + context.fileManifest, + codegenContext.symbolProvider, + settings.codegenConfig, + codegenContext.expectModuleDocProvider(), + ) protocolGenerator = protocolGeneratorFactory.buildProtocolGenerator(codegenContext) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRustModule.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRustModule.kt index bd784a6ece..3d397b2425 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRustModule.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRustModule.kt @@ -14,6 +14,7 @@ import software.amazon.smithy.model.traits.ErrorTrait import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWords import software.amazon.smithy.rust.codegen.core.rustlang.Visibility +import software.amazon.smithy.rust.codegen.core.smithy.ModuleDocProvider import software.amazon.smithy.rust.codegen.core.smithy.ModuleProvider import software.amazon.smithy.rust.codegen.core.smithy.ModuleProviderContext import software.amazon.smithy.rust.codegen.core.smithy.module @@ -25,12 +26,14 @@ import software.amazon.smithy.rust.codegen.core.util.toSnakeCase object ServerRustModule { val root = RustModule.LibRs - val Error = RustModule.public("error", documentation = "All error types that operations can return. Documentation on these types is copied from the model.") - val Operation = RustModule.public("operation", documentation = "All operations that this crate can perform.") - val Model = RustModule.public("model", documentation = "Data structures used by operation inputs/outputs. Documentation on these types is copied from the model.") - val Input = RustModule.public("input", documentation = "Input structures for operations. Documentation on these types is copied from the model.") - val Output = RustModule.public("output", documentation = "Output structures for operations. Documentation on these types is copied from the model.") - val Types = RustModule.public("types", documentation = "Data primitives referenced by other data types.") + val Error = RustModule.public("error") + val Operation = RustModule.public("operation") + val OperationShape = RustModule.public("operation_shape") + val Model = RustModule.public("model") + val Input = RustModule.public("input") + val Output = RustModule.public("output") + val Types = RustModule.public("types") + val Server = RustModule.public("server") val UnconstrainedModule = software.amazon.smithy.rust.codegen.core.smithy.UnconstrainedModule @@ -38,6 +41,23 @@ object ServerRustModule { software.amazon.smithy.rust.codegen.core.smithy.ConstrainedModule } +class ServerModuleDocProvider : ModuleDocProvider { + override fun docs(module: RustModule.LeafModule): String? = when (module) { + ServerRustModule.Error -> "All error types that operations can return. Documentation on these types is copied from the model." + ServerRustModule.Operation -> "All operations that this crate can perform." + // TODO(ServerTeam): Document this module (I don't have context) + ServerRustModule.OperationShape -> "" + ServerRustModule.Model -> "Data structures used by operation inputs/outputs. Documentation on these types is copied from the model." + ServerRustModule.Input -> "Input structures for operations. Documentation on these types is copied from the model." + ServerRustModule.Output -> "Output structures for operations. Documentation on these types is copied from the model." + ServerRustModule.Types -> "Data primitives referenced by other data types." + ServerRustModule.Server -> "Contains the types that are re-exported from the `aws-smithy-http-server` crate." + ServerRustModule.UnconstrainedModule -> "Unconstrained types for constrained shapes." + ServerRustModule.ConstrainedModule -> "Constrained types for constrained shapes." + else -> TODO("Document this module: $module") + } +} + object ServerModuleProvider : ModuleProvider { override fun moduleForShape(context: ModuleProviderContext, shape: Shape): RustModule.LeafModule = when (shape) { is OperationShape -> ServerRustModule.Operation @@ -72,6 +92,12 @@ object ServerModuleProvider : ModuleProvider { true -> Visibility.PUBCRATE false -> Visibility.PUBLIC } - return RustModule.new(builderNamespace, visibility, parent = symbol.module(), inline = true) + return RustModule.new( + builderNamespace, + visibility, + parent = symbol.module(), + inline = true, + documentationOverride = "", + ) } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGenerator.kt index 7d3fe75110..d7b1486607 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGenerator.kt @@ -175,7 +175,7 @@ class ConstrainedStringGenerator( if (testCases.isNotEmpty()) { val testModule = constrainedShapeSymbolProvider.testModuleForShape(shape) - writer.withInlineModule(testModule) { + writer.withInlineModule(testModule, null) { rustTemplate( """ #{TestCases:W} diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderSymbol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderSymbol.kt index 948aea0d89..64d35e0a8f 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderSymbol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderSymbol.kt @@ -36,7 +36,13 @@ fun StructureShape.serverBuilderModule(symbolProvider: SymbolProvider, pubCrate: true -> Visibility.PUBCRATE false -> Visibility.PUBLIC } - return RustModule.new(builderNamespace, visibility, parent = structureSymbol.module(), inline = true) + return RustModule.new( + builderNamespace, + visibility, + parent = structureSymbol.module(), + inline = true, + documentationOverride = "", + ) } // TODO(https://github.com/awslabs/smithy-rs/issues/2396): Replace this with `RustSymbolProvider.symbolForBuilder` diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt index 88ca5e4fef..cc811b80f2 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt @@ -21,7 +21,7 @@ import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.traits.isReachableFromOperationInput open class ConstrainedEnum( - codegenContext: ServerCodegenContext, + private val codegenContext: ServerCodegenContext, private val shape: StringShape, private val validationExceptionConversionGenerator: ValidationExceptionConversionGenerator, ) : EnumType() { @@ -41,7 +41,7 @@ open class ConstrainedEnum( ) override fun implFromForStr(context: EnumGeneratorContext): Writable = writable { - withInlineModule(constraintViolationSymbol.module()) { + withInlineModule(constraintViolationSymbol.module(), codegenContext.moduleDocProvider) { rustTemplate( """ ##[derive(Debug, PartialEq)] 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 4d2a275fce..d8f30f27cc 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 @@ -10,7 +10,6 @@ import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWords import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter -import software.amazon.smithy.rust.codegen.core.rustlang.Visibility import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.join import software.amazon.smithy.rust.codegen.core.rustlang.rust @@ -21,6 +20,7 @@ import software.amazon.smithy.rust.codegen.core.util.toPascalCase import software.amazon.smithy.rust.codegen.core.util.toSnakeCase import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext +import software.amazon.smithy.rust.codegen.server.smithy.ServerRustModule import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocol import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocolGenerator import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocolTestGenerator @@ -245,7 +245,7 @@ open class ServerServiceGenerator( rust("pub use crate::service::{$serviceName, ${serviceName}Builder, MissingOperationsError};") } - rustCrate.withModule(RustModule.operation(Visibility.PRIVATE)) { + rustCrate.withModule(ServerRustModule.Operation) { ServerProtocolTestGenerator(codegenContext, protocolSupport, protocolGenerator).render(this) } @@ -257,31 +257,17 @@ open class ServerServiceGenerator( } } - rustCrate.withModule( - RustModule.public("operation_shape"), - ) { + rustCrate.withModule(ServerRustModule.OperationShape) { ServerOperationShapeGenerator(operations, codegenContext).render(this) } - rustCrate.withModule( - RustModule.private("service"), - ) { - ServerServiceGeneratorV2( - codegenContext, - protocol, - ).render(this) + rustCrate.withModule(RustModule.private("service")) { + ServerServiceGeneratorV2(codegenContext, protocol).render(this) } renderExtras(operations) - rustCrate.withModule( - RustModule.public( - "server", - """ - Contains the types that are re-exported from the `aws-smithy-http-server` create. - """, - ), - ) { + rustCrate.withModule(ServerRustModule.Server) { renderServerReExports(this) } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/ServerResponseBindingGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/ServerResponseBindingGenerator.kt index 33f062b6b9..cc47830054 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/ServerResponseBindingGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/ServerResponseBindingGenerator.kt @@ -5,7 +5,6 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators.http -import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.shapes.ByteShape import software.amazon.smithy.model.shapes.CollectionShape import software.amazon.smithy.model.shapes.IntegerShape @@ -13,7 +12,6 @@ import software.amazon.smithy.model.shapes.LongShape import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.model.shapes.ShortShape -import software.amazon.smithy.model.shapes.StructureShape import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.writable @@ -25,7 +23,6 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.http.HttpMessa import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.ValueExpression import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext -import software.amazon.smithy.rust.codegen.server.smithy.generators.serverBuilderSymbol import software.amazon.smithy.rust.codegen.server.smithy.workingWithPublicConstrainedWrapperTupleType class ServerResponseBindingGenerator( @@ -33,8 +30,6 @@ class ServerResponseBindingGenerator( private val codegenContext: ServerCodegenContext, operationShape: OperationShape, ) { - private fun builderSymbol(shape: StructureShape): Symbol = shape.serverBuilderSymbol(codegenContext) - private val httpBindingGenerator = HttpBindingGenerator( protocol, 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 7df2a98c7f..ece9b26b42 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,7 +5,6 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators.protocol -import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.knowledge.TopDownIndex import software.amazon.smithy.model.shapes.OperationShape import software.amazon.smithy.model.shapes.Shape @@ -34,7 +33,6 @@ import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.ServerRuntimeType import software.amazon.smithy.rust.codegen.server.smithy.canReachConstrainedShape -import software.amazon.smithy.rust.codegen.server.smithy.generators.serverBuilderSymbol import software.amazon.smithy.rust.codegen.server.smithy.protocols.ServerAwsJsonSerializerGenerator import software.amazon.smithy.rust.codegen.server.smithy.protocols.ServerRestJsonSerializerGenerator import software.amazon.smithy.rust.codegen.server.smithy.targetCanReachConstrainedShape @@ -153,8 +151,6 @@ class ServerRestJsonProtocol( val runtimeConfig = codegenContext.runtimeConfig override fun structuredDataParser(operationShape: OperationShape): StructuredDataParserGenerator { - fun builderSymbol(shape: StructureShape): Symbol = - shape.serverBuilderSymbol(serverCodegenContext) fun returnSymbolToParse(shape: Shape): ReturnSymbolToParse = if (shape.canReachConstrainedShape(codegenContext.model, codegenContext.symbolProvider)) { ReturnSymbolToParse(serverCodegenContext.unconstrainedShapeSymbolProvider.toSymbol(shape), true) 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 d1ff2b37d4..06d5333562 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 @@ -175,7 +175,7 @@ class ServerProtocolTestGenerator( ), inline = true, ) - writer.withInlineModule(module) { + writer.withInlineModule(module, null) { renderAllTestCases(operationShape, allTests) } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerTestHelpers.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerTestHelpers.kt index 4d53599abe..d7c3c7fb5c 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerTestHelpers.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerTestHelpers.kt @@ -18,6 +18,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProviderConfig import software.amazon.smithy.rust.codegen.core.smithy.generators.StructureGenerator +import software.amazon.smithy.rust.codegen.core.testutil.TestModuleDocProvider import software.amazon.smithy.rust.codegen.core.testutil.TestRuntimeConfig import software.amazon.smithy.rust.codegen.server.smithy.RustServerCodegenPlugin import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenConfig @@ -117,6 +118,7 @@ fun serverTestCodegenContext( return ServerCodegenContext( model, serverSymbolProviders.symbolProvider, + TestModuleDocProvider, service, protocol, settings, diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintsMemberShapeTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintsMemberShapeTest.kt index 952140d726..f5b619ea74 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintsMemberShapeTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintsMemberShapeTest.kt @@ -309,6 +309,7 @@ class ConstraintsMemberShapeTest { context.fileManifest, codegenContext.symbolProvider, settings.codegenConfig, + codegenContext.expectModuleDocProvider(), ) // We cannot write to the lib anymore as the RustWriter overwrites it, so writing code directly to check.rs diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriterTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriterTest.kt index 3637548d9a..d4358aa4c0 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriterTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriterTest.kt @@ -68,14 +68,18 @@ class RustCrateInlineModuleComposingWriterTest { runtimeConfig = runtimeConfig, ) val settings = ServerRustSettings.from(context.model, context.settings) - rustCrate = RustCrate(context.fileManifest, codegenContext.symbolProvider, settings.codegenConfig) + rustCrate = RustCrate( + context.fileManifest, + codegenContext.symbolProvider, + settings.codegenConfig, + codegenContext.expectModuleDocProvider(), + ) } - private fun createTestInlineModule(parentModule: RustModule, moduleName: String, documentation: String? = null): RustModule.LeafModule = + private fun createTestInlineModule(parentModule: RustModule, moduleName: String): RustModule.LeafModule = RustModule.new( moduleName, visibility = Visibility.PUBLIC, - documentation = documentation ?: moduleName, parent = parentModule, inline = true, ) @@ -84,7 +88,6 @@ class RustCrateInlineModuleComposingWriterTest { RustModule.new( moduleName, visibility = Visibility.PUBLIC, - documentation = moduleName, parent = RustModule.LibRs, inline = true, ) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiatorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiatorTest.kt index eef80be1c4..bc7ee94c56 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiatorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiatorTest.kt @@ -146,7 +146,7 @@ class ServerInstantiatorTest { nestedStruct.serverRenderWithModelBuilder(project, model, symbolProvider, this) UnionGenerator(model, symbolProvider, this, union).render() - withInlineModule(RustModule.inlineTests()) { + withInlineModule(RustModule.inlineTests(), null) { unitTest("server_instantiator_test") { withBlock("let result = ", ";") { sut.render(this, structure, data)