[rust-axum] fix: box recursive model fields

TE
20h ago
+3077-5

Fixes #25295

rust-axum generates model fields that hold another model without any indirection. When a model leads back to itself, the generated type has infinite size and the crate fails to compile with E0072. Examples: parent: Node; a nullable self reference via anyOf/oneOf with null or nullable + allOf; a cycle such as Employee -> Department -> Employee; or a cycle through a oneOf enum such as Circle.inner -> Shape -> Circle.

Changes

  • New option boxRecursiveModels (default false). Without it the generated code is exactly what master produces today; with it, the boxing below is applied.
  • RustAxumServerCodegen.postProcessAllModels: checks every struct field that holds a model directly (not inside a container). If that model can lead back to the current one, the field gets x-is-boxed. The check follows direct model fields and the oneOf/anyOf variants of enum models.
  • models.mustache: for x-is-boxed fields, wraps the type in Box<...> in the struct field and in new(), and boxes the parsed value in the FromStr implementation.
  • Non-recursive fields are not changed. All existing rust-axum samples are byte-identical after regeneration.
  • New spec 3_1/rust-axum/rust-axum-recursive-models.yaml and sample config rust-axum-recursive-models (with boxRecursiveModels: true).

Not covered

  • rust-server (#5950) and rust-salvo, which have the same issue.

Testing

  • New RustAxumServerCodegenTest#testRecursiveModelFieldsAreBoxed. It checks direct, nullable (anyOf/oneOf null), indirect and oneOf-variant recursion. It also checks that Vec and non-recursive references are not boxed. The test fails without the fix.
  • New RustAxumServerCodegenTest#testRecursiveModelFieldsAreNotBoxedByDefault: without the option, nothing is boxed.
  • mvn integration-test -f samples/server/petstore/rust-axum/pom.xml passes.
  • New sample samples/server/petstore/rust-axum/output/rust-axum-recursive-models. These pass on it: cargo build --all-targets --all-features, cargo build --all-targets --no-default-features, cargo test, cargo clippy --all-targets --all-features. Before the fix, the same spec fails cargo check with E0072.

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    Regenerated all rust-axum samples with RUST_POST_PROCESS_FILE=$PWD/samples/server/petstore/rust-axum/rustfmt-2021.sh ./bin/generate-samples.sh bin/configs/manual/rust-axum* (17 configs, including the new rust-axum-recursive-models). The only change is the new sample. docs/generators/rust-axum.md was regenerated with export_docs_generators.sh for the new option.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

cc @frol @farcaller @richardwhiuk @paladinzh @jacob-pro @dsteeley


Summary by cubic

Fixes recursive model fields in the rust-axum generator so models that reference themselves, directly or through other models, compile without E0072. Fields that would create an infinitely sized type are now wrapped in Box<...> behind the new boxRecursiveModels option (default false), so existing generated code stays byte-identical.

  • Detects cycles in postProcessAllModels and marks the offending fields with x-is-boxed.
  • Updates models.mustache to emit Box<...> for those fields in the struct, new(), and FromStr.
  • Only direct model references are boxed; containers like Vec and non-recursive references are unchanged.
  • Adds a new sample (rust-axum-recursive-models) and unit tests covering direct, nullable, indirect, and oneOf recursion.