Skip to content

Commit

Permalink
Split the types and builders modules into per-shape private modul…
Browse files Browse the repository at this point in the history
  • Loading branch information
jdisanti committed Feb 24, 2023
1 parent 4c76847 commit 5183ccb
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 28 deletions.
Expand Up @@ -6,6 +6,7 @@
package software.amazon.smithy.rust.codegen.client.smithy

import software.amazon.smithy.build.PluginContext
import software.amazon.smithy.codegen.core.Symbol
import software.amazon.smithy.model.Model
import software.amazon.smithy.model.knowledge.NullableIndex
import software.amazon.smithy.model.shapes.OperationShape
Expand All @@ -27,14 +28,20 @@ import software.amazon.smithy.rust.codegen.client.smithy.generators.protocol.Cli
import software.amazon.smithy.rust.codegen.client.smithy.protocols.ClientProtocolLoader
import software.amazon.smithy.rust.codegen.client.smithy.transformers.AddErrorMessage
import software.amazon.smithy.rust.codegen.client.smithy.transformers.RemoveEventStreamOperations
import software.amazon.smithy.rust.codegen.core.rustlang.EscapeFor
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.Writable
import software.amazon.smithy.rust.codegen.core.rustlang.implBlock
import software.amazon.smithy.rust.codegen.core.smithy.DirectedWalker
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.contextName
import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderGenerator
import software.amazon.smithy.rust.codegen.core.smithy.generators.StructureGenerator
import software.amazon.smithy.rust.codegen.core.smithy.generators.UnionGenerator
import software.amazon.smithy.rust.codegen.core.smithy.module
import software.amazon.smithy.rust.codegen.core.smithy.protocols.ProtocolGeneratorFactory
import software.amazon.smithy.rust.codegen.core.smithy.transformers.EventStreamNormalizer
import software.amazon.smithy.rust.codegen.core.smithy.transformers.OperationNormalizer
Expand All @@ -45,6 +52,7 @@ import software.amazon.smithy.rust.codegen.core.util.hasTrait
import software.amazon.smithy.rust.codegen.core.util.isEventStream
import software.amazon.smithy.rust.codegen.core.util.letIf
import software.amazon.smithy.rust.codegen.core.util.runCommand
import software.amazon.smithy.rust.codegen.core.util.toSnakeCase
import java.util.logging.Logger

/**
Expand Down Expand Up @@ -182,6 +190,29 @@ class ClientCodegenVisitor(
override fun getDefault(shape: Shape?) {
}

// TODO(CrateReorganization): Remove this function when cleaning up `enableNewCrateOrganizationScheme`
private fun RustCrate.maybeInPrivateModuleWithReexport(
privateModule: RustModule.LeafModule,
symbol: Symbol,
writer: Writable,
) {
if (codegenContext.settings.codegenConfig.enableNewCrateOrganizationScheme) {
inPrivateModuleWithReexport(privateModule, symbol, writer)
} else {
withModule(symbol.module(), writer)
}
}

private fun privateModule(shape: Shape): RustModule.LeafModule =
RustModule.private(privateModuleName(shape), parent = symbolProvider.moduleForShape(shape))

private fun privateModuleName(shape: Shape): String =
shape.contextName(codegenContext.serviceShape).let(this::privateModuleName)

private fun privateModuleName(name: String): String =
// Add the underscore to avoid colliding with public module names
"_" + RustReservedWords.escapeIfNeeded(name.toSnakeCase(), EscapeFor.ModuleName)

/**
* Structure Shape Visitor
*
Expand All @@ -192,9 +223,9 @@ class ClientCodegenVisitor(
* This function _does not_ generate any serializers
*/
override fun structureShape(shape: StructureShape) {
when (val errorTrait = shape.getTrait<ErrorTrait>()) {
val (renderStruct, renderBuilder) = when (val errorTrait = shape.getTrait<ErrorTrait>()) {
null -> {
rustCrate.useShapeWriter(shape) {
val struct: Writable = {
StructureGenerator(
model,
symbolProvider,
Expand All @@ -207,27 +238,35 @@ class ClientCodegenVisitor(
BuilderGenerator.renderConvenienceMethod(this, symbolProvider, shape)
}
}

rustCrate.withModule(symbolProvider.moduleForBuilder(shape)) {
val builder: Writable = {
BuilderGenerator(
codegenContext.model,
codegenContext.symbolProvider,
shape,
codegenDecorator.builderCustomizations(codegenContext, emptyList()),
).render(this)
}
struct to builder
}
else -> {
ErrorGenerator(
rustCrate,
val errorGenerator = ErrorGenerator(
model,
symbolProvider,
shape,
errorTrait,
codegenDecorator.errorImplCustomizations(codegenContext, emptyList()),
).render()
)
errorGenerator::renderStruct to errorGenerator::renderBuilder
}
}

val privateModule = privateModule(shape)
rustCrate.maybeInPrivateModuleWithReexport(privateModule, symbolProvider.toSymbol(shape)) {
renderStruct(this)
}
rustCrate.maybeInPrivateModuleWithReexport(privateModule, symbolProvider.symbolForBuilder(shape)) {
renderBuilder(this)
}
}

/**
Expand All @@ -237,7 +276,8 @@ class ClientCodegenVisitor(
*/
override fun stringShape(shape: StringShape) {
if (shape.hasTrait<EnumTrait>()) {
rustCrate.useShapeWriter(shape) {
val privateModule = privateModule(shape)
rustCrate.maybeInPrivateModuleWithReexport(privateModule, symbolProvider.toSymbol(shape)) {
ClientEnumGenerator(codegenContext, shape).render(this)
}
}
Expand All @@ -251,7 +291,7 @@ class ClientCodegenVisitor(
* Note: this does not generate serializers
*/
override fun unionShape(shape: UnionShape) {
rustCrate.useShapeWriter(shape) {
rustCrate.maybeInPrivateModuleWithReexport(privateModule(shape), symbolProvider.toSymbol(shape)) {
UnionGenerator(model, symbolProvider, this, shape, renderUnknownVariant = true).render()
}
if (shape.isEventStream()) {
Expand Down
Expand Up @@ -8,6 +8,7 @@ package software.amazon.smithy.rust.codegen.client.smithy.generators.error
import software.amazon.smithy.model.Model
import software.amazon.smithy.model.shapes.StructureShape
import software.amazon.smithy.model.traits.ErrorTrait
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.rustlang.implBlock
import software.amazon.smithy.rust.codegen.core.rustlang.rust
Expand All @@ -17,7 +18,6 @@ import software.amazon.smithy.rust.codegen.core.rustlang.writable
import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.errorMetadata
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
import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderGenerator
Expand All @@ -29,19 +29,17 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.error.ErrorImp
import software.amazon.smithy.rust.codegen.core.smithy.generators.error.ErrorImplGenerator

class ErrorGenerator(
private val rustCrate: RustCrate,
private val model: Model,
private val symbolProvider: RustSymbolProvider,
private val shape: StructureShape,
private val error: ErrorTrait,
private val implCustomizations: List<ErrorImplCustomization>,
) {
private val runtimeConfig = symbolProvider.config.runtimeConfig
private val symbol = symbolProvider.toSymbol(shape)

fun render() {
val symbol = symbolProvider.toSymbol(shape)

rustCrate.useShapeWriter(shape) {
fun renderStruct(writer: RustWriter) {
writer.apply {
StructureGenerator(
model, symbolProvider, this, shape,
listOf(
Expand All @@ -55,14 +53,22 @@ class ErrorGenerator(
is StructureSection.AdditionalDebugFields -> {
rust("""${section.formatterName}.field("meta", &self.meta);""")
}

else -> {}
}
}
},
),
).render()

ErrorImplGenerator(model, symbolProvider, this, shape, error, implCustomizations).render(CodegenTarget.CLIENT)
ErrorImplGenerator(
model,
symbolProvider,
this,
shape,
error,
implCustomizations,
).render(CodegenTarget.CLIENT)

rustBlock("impl #T for ${symbol.name}", RuntimeType.provideErrorMetadataTrait(runtimeConfig)) {
rust("fn meta(&self) -> &#T { &self.meta }", errorMetadata(runtimeConfig))
Expand All @@ -72,8 +78,10 @@ class ErrorGenerator(
BuilderGenerator.renderConvenienceMethod(this, symbolProvider, shape)
}
}
}

rustCrate.withModule(symbolProvider.moduleForBuilder(shape)) {
fun renderBuilder(writer: RustWriter) {
writer.apply {
BuilderGenerator(
model, symbolProvider, shape,
listOf(
Expand Down
Expand Up @@ -81,13 +81,18 @@ abstract class ClientEventStreamBaseRequirements : EventStreamTestRequirements<C
shape: StructureShape,
) {
val errorTrait = shape.expectTrait<ErrorTrait>()
ErrorGenerator(
rustCrate,
val errorGenerator = ErrorGenerator(
codegenContext.model,
codegenContext.symbolProvider,
shape,
errorTrait,
emptyList(),
).render()
)
rustCrate.useShapeWriter(shape) {
errorGenerator.renderStruct(this)
}
rustCrate.withModule(codegenContext.symbolProvider.moduleForBuilder(shape)) {
errorGenerator.renderBuilder(this)
}
}
}
Expand Up @@ -101,6 +101,11 @@ class RustReservedWordSymbolProvider(private val base: RustSymbolProvider) : Wra
}
}

enum class EscapeFor {
TypeName,
ModuleName,
}

object RustReservedWords : ReservedWords {
private val RustKeywords = setOf(
"as",
Expand Down Expand Up @@ -169,15 +174,22 @@ object RustReservedWords : ReservedWords {
"SelfValue" to "SelfValue_",
)

override fun escape(word: String): String = when (val mapped = keywordEscapingMap[word]) {
null -> "r##$word"
else -> mapped
}
override fun escape(word: String): String = doEscape(word, EscapeFor.TypeName)

fun escapeIfNeeded(word: String): String = when (isReserved(word)) {
true -> escape(word)
else -> word
}
private fun doEscape(word: String, escapeFor: EscapeFor = EscapeFor.TypeName): String =
when (val mapped = keywordEscapingMap[word]) {
null -> when (escapeFor) {
EscapeFor.TypeName -> "r##$word"
EscapeFor.ModuleName -> "${word}_"
}
else -> mapped
}

fun escapeIfNeeded(word: String, escapeFor: EscapeFor = EscapeFor.TypeName): String =
when (isReserved(word)) {
true -> doEscape(word, escapeFor)
else -> word
}

override fun isReserved(word: String): Boolean = RustKeywords.contains(word) || keywordEscapingMap.contains(word)
}
Expand Up @@ -6,6 +6,7 @@
package software.amazon.smithy.rust.codegen.core.smithy

import software.amazon.smithy.build.FileManifest
import software.amazon.smithy.codegen.core.Symbol
import software.amazon.smithy.codegen.core.SymbolProvider
import software.amazon.smithy.codegen.core.WriterDelegator
import software.amazon.smithy.model.Model
Expand All @@ -18,6 +19,7 @@ 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.Writable
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
Expand Down Expand Up @@ -183,6 +185,22 @@ open class RustCrate(
fileWriter(it)
}
}

/**
* Render something in a private module and re-export it into the given symbol.
*
* @param privateModule: Private module to render into
* @param symbol: The symbol of the thing being rendered, which will be re-exported. This symbol
* should be the public-facing symbol rather than the private symbol.
*/
fun inPrivateModuleWithReexport(privateModule: RustModule.LeafModule, symbol: Symbol, writer: Writable) {
withModule(privateModule, writer)
privateModule.toType().resolve(symbol.name).toSymbol().also { privateSymbol ->
withModule(symbol.module()) {
rust("pub use #T;", privateSymbol)
}
}
}
}

// TODO(https://github.com/awslabs/smithy-rs/issues/2341): Remove unconstrained/constrained from codegen-core
Expand Down

0 comments on commit 5183ccb

Please sign in to comment.