Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more docs to codegen #776

Merged
merged 1 commit into from
Oct 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,36 @@ import software.amazon.smithy.model.shapes.ShapeId
* Configuration needed to generate the client for a given Service<->Protocol pair
*/
data class CodegenContext(
/**
* The smithy model.
*
* Note: This model may or not be pruned to the given service closure, so ensure that `serviceShape` is used as
* an entry point.
*/
val model: Model,
val symbolProvider: RustSymbolProvider,
/**
* Configuration of the runtime package:
* - Where are the runtime crates (smithy-*) located on the file system? Or are they versioned?
* - What are they called?
*/
val runtimeConfig: RuntimeConfig,
/**
* Entrypoint service shape for code generation
*/
val serviceShape: ServiceShape,
/**
* Smithy Protocol to generate, eg. RestJson1
*/
val protocol: ShapeId,
/**
* The name of the cargo crate to generate eg. `aws-sdk-s3`
* This is loaded from the smithy-build.json during codegen.
*/
val moduleName: String,
/**
* Settings loaded from smithy-build.json
*/
val settings: RustSettings,
) {
constructor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,46 @@ import software.amazon.smithy.rust.codegen.smithy.generators.LibRsCustomization
import software.amazon.smithy.rust.codegen.smithy.generators.LibRsGenerator
import software.amazon.smithy.rust.codegen.smithy.generators.ManifestCustomizations

/**
* RustCrate abstraction.
*
* **Note**: This is the only implementation, `open` only for test purposes.
*
* All code-generation at some point goes through this class. `RustCrate` maintains a `CodegenWriterDelegator` internally
* which tracks a set of file-writer pairs and allows them to be loaded and cached (see: [useShapeWriter])
*
* On top of this, it adds Rust specific features:
* - Generation of a `lib.rs` which adds `mod` statements automatically for every module that was used
* - Tracking dependencies and crate features used during code generation, enabling generation of `Cargo.toml`
*
* Users will generally want to use two main entry points:
* 1. [useShapeWriter]: Find or create a writer that will contain a given shape. See [locatedIn] for context about how
* shape locations are determined.
* 2. [finalize]: Write the crate out to the file system, generating a lib.rs and Cargo.toml
*/
open class RustCrate(
fileManifest: FileManifest,
symbolProvider: SymbolProvider,
/**
* For core modules like `input`, `output`, and `error`, we need to specify whether these modules should be public or
* private as well as any other metadata. [baseModules] enables configuring this. See [DefaultPublicModules].
*/
baseModules: Map<String, RustModule>
) {
private val inner = CodegenWriterDelegator(fileManifest, symbolProvider, RustWriter.Factory)
private val modules: MutableMap<String, RustModule> = baseModules.toMutableMap()
private val features: MutableSet<Feature> = mutableSetOf()

/**
* Write into the module that this shape is [locatedIn]
*/
fun useShapeWriter(shape: Shape, f: (RustWriter) -> Unit) {
inner.useShapeWriter(shape, f)
}

/**
* Write directly into lib.rs
*/
fun lib(moduleWriter: (RustWriter) -> Unit) {
inner.useFileWriter("src/lib.rs", "crate", moduleWriter)
}
Expand All @@ -51,6 +79,11 @@ open class RustCrate(
}
}

/**
* Finalize Cargo.toml and lib.rs and flush the writers to the file system.
*
* This is also where inline dependencies are actually reified and written, potentially recursively.
*/
fun finalize(
settings: RustSettings,
model: Model,
Expand Down Expand Up @@ -82,6 +115,9 @@ open class RustCrate(
}
}

/**
* Create a new module directly. The resulting module will be placed in `src/<modulename>.rs`
*/
fun withModule(
module: RustModule,
moduleWriter: (RustWriter) -> Unit
Expand All @@ -92,6 +128,9 @@ open class RustCrate(
return this
}

/**
* Create a new file directly
*/
fun withFile(filename: String, fileWriter: (RustWriter) -> Unit) {
inner.useFileWriter(filename) {
fileWriter(it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,20 @@ import software.amazon.smithy.rust.codegen.rustlang.RustWriter
import software.amazon.smithy.rust.codegen.rustlang.asType
import java.util.Optional

/**
* Location of the runtime crates (smithy-http, smithy-types etc.)
*
* This can be configured via the `runtimeConfig.version` field in smithy-build.json
*/
sealed class RuntimeCrateLocation {
/**
* Relative path to find the runtime crates, eg. `../`
*/
data class Path(val path: String) : RuntimeCrateLocation()

/**
* Version for the runtime crates, eg. `v0.0.1-alpha`
*/
data class Versioned(val version: String) : RuntimeCrateLocation()
}

Expand All @@ -30,12 +42,18 @@ fun RuntimeCrateLocation.crateLocation(): DependencyLocation = when (this) {
is RuntimeCrateLocation.Versioned -> CratesIo(this.version)
}

/**
* Prefix & crate location for the runtime crates.
*/
data class RuntimeConfig(
val cratePrefix: String = "smithy",
val runtimeCrateLocation: RuntimeCrateLocation = RuntimeCrateLocation.Path("../")
) {
companion object {

/**
* Load a `RuntimeConfig` from an [ObjectNode] (JSON)
*/
fun fromNode(node: Optional<ObjectNode>): RuntimeConfig {
return if (node.isPresent) {
val runtimeCrateLocation = if (node.get().containsMember("version")) {
Expand All @@ -57,7 +75,31 @@ data class RuntimeConfig(
CargoDependency("$cratePrefix-$runtimeCrateName", runtimeCrateLocation.crateLocation(), optional = optional)
}

/**
* `RuntimeType` captures all necessary information to render a type into a Rust file:
* - [name]: What type is this?
* - [dependency]: What other crates, if any, are required to use this type?
* - [namespace]: Where can we find this type.
*
* For example:
*
* `http::header::HeaderName`
* ------------ ----------
* | |
* [namespace] [name]
*
* This type would have a [CargoDependency] pointing to the `http` crate.
*
* By grouping all of this information, when we render a type into a [RustWriter], we can not only render a fully qualified
* name, but also ensure that we automatically add any dependencies **as they are used**.
*/
data class RuntimeType(val name: String?, val dependency: RustDependency?, val namespace: String) {
/**
* Convert this [RuntimeType] into a [Symbol].
*
* This is not commonly required, but is occasionally useful when you want to force an import without referencing a type
* (eg. when bringing a trait into scope). See [CodegenWriter.addUseImports].
*/
fun toSymbol(): Symbol {
val builder = Symbol.builder().name(name).namespace(namespace, "::")
.rustType(RustType.Opaque(name ?: "", namespace = namespace))
Expand All @@ -66,17 +108,31 @@ data class RuntimeType(val name: String?, val dependency: RustDependency?, val n
return builder.build()
}

/**
* Create a new [RuntimeType] with a nested name.
*
* # Example
* ```kotlin
* val http = CargoDependency.http.member("Request")
* ```
*/
fun member(member: String): RuntimeType {
val newName = name?.let { "$name::$member" } ?: member
return copy(name = newName)
}

/**
* Returns the fully qualified name for this type
*/
fun fullyQualifiedName(): String {
val postFix = name?.let { "::$name" } ?: ""
return "$namespace$postFix"
}

// TODO: refactor to be RuntimeTypeProvider a la Symbol provider that packages the `RuntimeConfig` state.
/**
* The companion object contains commonly used RuntimeTypes
*/
companion object {
fun errorKind(runtimeConfig: RuntimeConfig) = RuntimeType(
"ErrorKind",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class RetryConfigProviderConfig(codegenContext: CodegenContext) : ConfigCustomiz
self.set_retry_config(Some(retry_config));
self
}

/// Set the retry_config for the builder
///
/// ## Examples
Expand Down
39 changes: 0 additions & 39 deletions gradle/jvm.gradle

This file was deleted.