---

name: "codegen"
description: Change generated code in this repository. Use when editing anything that looks like a generated file, when the Smithy models or the data under data/ change, when a codegen run leaves a diff, or when adding a generated module.
license: "Apache-2.0"
---

# Codegen

Most of the API surface of `s3s` and `s3s-aws` is generated from the Smithy models in `data/`. A generated file is an output: the change belongs in the generator, and the output is committed together with it.

## The loop

- `just crawl` refreshes the models and the error-code table under `data/` (`cargo run -p xtask -- crawl update`).
- `just codegen` regenerates the workspace from that data, then runs `cargo fmt --all` and `cargo check`.
- `just ci-rust` ends with `just assert_unchanged`, which requires an empty `git status`, so a codegen run that leaves a diff fails CI. Run `just codegen` before pushing anything that touches the models, the data or an emitter.

## The boundary

- Generated files carry a `//! Auto generated by ...` marker. They live under `crates/s3s/src/{dto,xml,access,error,header}/generated.rs`, `crates/s3s/src/ops/generated/`, `crates/s3s-aws/src/{conv,proxy}/generated.rs` and `crates/s3s/tests/generated/`.
- Hand-written code sits beside them (`dto/mod.rs`, `xml/mod.rs`, `ops/mod.rs`, ...). Edit that file, or the emitter, never the generated one.
- An emitter change and the output it produces belong to the same commit: every commit has to leave a consistent tree, and `assert_unchanged` enforces exactly that.

## Where the generators live

`codegen/src/v1/` holds one module per family (`dto.rs`, `xml.rs`, `ops.rs`, `s3_trait.rs`, `access.rs`, `error.rs`, `headers.rs`, `aws_conv.rs`, `aws_proxy.rs`, `gen_tests/`), driven from `mod.rs`: `run()` reads the model data and calls each module, `write_file` and `write_dir_file` write into the checkout, and `postprocess()` finishes the job. Output has to be deterministic and stable under `cargo fmt`, so iterate maps in a fixed order.

## The MinIO variant

Every mergeable module is generated twice — into `generated.rs` and `generated_minio.rs` — and `postprocess()` merges the pair back into the first file: the differences become inline `#[cfg(feature = "minio")]` / `#[cfg(not(feature = "minio"))]` blocks, and the temporary `*_minio.rs` is deleted. Two consequences:

- Verify both builds. `cargo test --all-features` and a plain `cargo test` execute different halves of a merged file, and the same holds for `cargo check` with and without the feature.
- A type or a value subtree that differs between the two models is generated once per branch, so a test that covers it needs the same gates.

## Generated tests

`codegen/src/v1/gen_tests/` writes the coverage test suite into `crates/s3s/tests/generated/`. The same rule applies there: extend the emitter instead of editing the generated tests by hand.
