|
| 1 | +# Smithy-rs AI Agent Guide |
| 2 | + |
| 3 | +## Package Layout |
| 4 | + |
| 5 | +- **`codegen-core/`** - Shared codegen |
| 6 | +- **`codegen-server/`** - Server codegen |
| 7 | +- **`codegen-client/`** - Client codegen |
| 8 | +- **`rust-runtime/`** - Runtime libraries |
| 9 | +- **`codegen-server-test/`** - Server integration tests |
| 10 | + |
| 11 | +Protocol files: `codegen-{core,server}/.../protocols/` |
| 12 | + |
| 13 | +## preludeScope: Rust Prelude Types |
| 14 | + |
| 15 | +**Always use `preludeScope` for Rust prelude types:** |
| 16 | + |
| 17 | +```kotlin |
| 18 | +rustTemplate( |
| 19 | + "let result: #{Result}<#{String}, #{Error}> = #{Ok}(value);", |
| 20 | + *preludeScope, // Provides Result, String, Ok |
| 21 | + "Error" to myErrorType |
| 22 | +) |
| 23 | +``` |
| 24 | + |
| 25 | +❌ Wrong: `"let result: Result<String, Error> = Ok(value);"` |
| 26 | +✅ Correct: Use `*preludeScope` in templates |
| 27 | + |
| 28 | +## RuntimeType and Dependencies |
| 29 | + |
| 30 | +`RuntimeType` objects contain: |
| 31 | +- **`path`**: Rust path (e.g., `"::mime::Mime"`) |
| 32 | +- **`dependency`**: `CargoDependency` or `InlineDependency` |
| 33 | + |
| 34 | +Using a `RuntimeType` automatically adds its dependency to `Cargo.toml`. |
| 35 | + |
| 36 | +### Creating RuntimeTypes |
| 37 | + |
| 38 | +```kotlin |
| 39 | +// Pre-defined dependencies |
| 40 | +val Mime = CargoDependency.Mime.toType() |
| 41 | +val Bytes = CargoDependency.Bytes.toType().resolve("Bytes") |
| 42 | + |
| 43 | +// Runtime crates |
| 44 | +val smithyTypes = RuntimeType.smithyTypes(runtimeConfig) |
| 45 | +``` |
| 46 | + |
| 47 | +### Always Use Symbols |
| 48 | + |
| 49 | +❌ Wrong: `rust("const MIME: ::mime::Mime = ::mime::APPLICATION_JSON;")` |
| 50 | +✅ Correct: `rustTemplate("const MIME: #{Mime}::Mime = #{Mime}::APPLICATION_JSON;", "Mime" to RuntimeType.Mime)` |
| 51 | + |
| 52 | +## RuntimeType.forInlineFun: Lazy Generation |
| 53 | + |
| 54 | +Code is only generated if used. `forInlineFun` enables lazy generation: |
| 55 | + |
| 56 | +```kotlin |
| 57 | +val mimeType = RuntimeType.forInlineFun("APPLICATION_JSON", module) { |
| 58 | + rustTemplate( |
| 59 | + "pub const APPLICATION_JSON: #{Mime}::Mime = #{Mime}::APPLICATION_JSON;", |
| 60 | + "Mime" to RuntimeType.Mime |
| 61 | + ) |
| 62 | +} |
| 63 | +``` |
| 64 | + |
| 65 | +⚠️ **Footgun**: Name collisions mean only one implementation gets generated. |
| 66 | + |
| 67 | +## Testing |
| 68 | + |
| 69 | +### Integration Tests |
| 70 | +Test actual generated code, not just codegen logic: |
| 71 | + |
| 72 | +```kotlin |
| 73 | +serverIntegrationTest(model) { codegenContext, rustCrate -> |
| 74 | + rustCrate.testModule { |
| 75 | + tokioTest("test_accept_header") { |
| 76 | + rustTemplate(""" |
| 77 | + let request = ::http::Request::builder() |
| 78 | + .header("Accept", "application/cbor") |
| 79 | + .body(Body::empty()).unwrap(); |
| 80 | + let result = MyInput::from_request(request).await; |
| 81 | + result.expect("should accept valid header"); |
| 82 | + """) |
| 83 | + } |
| 84 | + } |
| 85 | +} |
| 86 | +``` |
| 87 | + |
| 88 | +### Running Tests |
| 89 | + |
| 90 | +**Codegen tests:** |
| 91 | +```bash |
| 92 | +./gradlew test --tests "*MyTest*" |
| 93 | +./gradlew codegen-server-test:assemble --quiet |
| 94 | +``` |
| 95 | + |
| 96 | +**Debug failing tests:** |
| 97 | +```bash |
| 98 | +# Remove --quiet to see failure details |
| 99 | +./gradlew :codegen-core:test --tests "*InlineDependencyTest*" |
| 100 | +# Extract just the error from HTML report (avoid HTML markup pollution) |
| 101 | +grep -A 5 "AssertionError\|Exception" codegen-core/build/reports/tests/test/classes/software.amazon.smithy.rust.codegen.core.rustlang.InlineDependencyTest.html |
| 102 | +``` |
| 103 | + |
| 104 | +**Runtime tests:** |
| 105 | +```bash |
| 106 | +cd rust-runtime && cargo test --quiet -p aws-smithy-types |
| 107 | +``` |
| 108 | + |
| 109 | +**Protocol tests:** |
| 110 | +```bash |
| 111 | +./gradlew codegen-client-test:assemble --quiet |
| 112 | +cd codegen-client-test/build/smithyprojections/codegen-client-test/rest_xml_extras/rust-client-codegen |
| 113 | +cargo test --quiet |
| 114 | +``` |
| 115 | + |
| 116 | +## Viewing Generated Code |
| 117 | + |
| 118 | +Generated code appears in: |
| 119 | +``` |
| 120 | +codegen-server-test/build/smithyprojections/codegen-server-test/SERVICE_NAME/rust-server-codegen/ |
| 121 | +``` |
| 122 | + |
| 123 | +Enable debug comments: |
| 124 | +```kotlin |
| 125 | +serverIntegrationTest(model, IntegrationTestParams( |
| 126 | + additionalSettings = ServerAdditionalSettings.builder() |
| 127 | + .generateCodegenComments() // Adds Kotlin source line comments |
| 128 | + .toObjectNode() |
| 129 | +)) { /* test code */ } |
| 130 | +``` |
0 commit comments