[rust] fix: discriminated-union variants drop every child-specific field
A schema with a discriminator and mapped children generates an internally tagged enum whose variants are inline structs built from the parent's vars, so every child-specific field is dropped (ObjectExists { message } loses identifier). The test-duplicates sample even mixed vars across models.
Fix
Newtype variants wrapping the mapped models, boxed like the oneOf variants, with the derived #[serde(tag)] kept:
ObjectExists(Box<models::ObjectExists>),
The variant is named by the uniquified modelName and wraps the model's real classname.
serde consumes the tag before the child deserializes, so a mapped child's discriminator field is marked and defaulted, and skipped while unset: Option::is_none if nullable, String::is_empty if a string. Standalone use of the child is unchanged.
Two kinds of union keep master's inline variants, children untouched:
- a mapping that names the base itself would wrap itself (E0275);
- an enum-typed discriminator (inline or
$ref) would be written twice, the child's copy holding the enum's default ("petType":"Dog","petType":"Cat").
Verification
RustClientCodegenTest#testDiscriminatedUnionKeepsChildFields: string, nullable, inline-enum, enum-ref and self-mapped discriminators.cargo checkof the fixture;cargo runwire → union → wire keeps child fields and writes one tag. Enum-discriminated output is byte-identical to master.- Samples:
oneOfandtest-duplicates(hyper + reqwest) unions become newtypes;oneOfchildren gain the@typeattribute. All build.
Known gaps
- A child built with
new()and wrapped in the union writes the tag twice ({"type":"ObjectExists","type":"ObjectExists",...}). - Self-mapped and enum-discriminated unions still drop their children's fields, as on master.
PR checklist
- Read the contribution guidelines.
- Built the project and updated samples (
./bin/generate-samples.sh ./bin/configs/rust-*). - Technical committee (Rust): @frol @farcaller @richardwhiuk @paladinzh @jacob-pro @dsteeley
Summary by cubic
Fixes Rust client generation for schemas with a discriminator and mapped children so enum variants keep their child-specific fields. Variants were inline structs built from the parent's vars, silently dropping every field the child added; they now wrap the mapped model in a boxed newtype variant.
Behavior
- Duplicate mapping entries sharing one schema still get distinct variants, each wrapping the real model.
- The child's discriminator property stays declared but is marked as a discriminator: the consumed serde tag key defaults instead of erroring and is skipped back out while unset (
Option::is_nonefor nullable,String::is_emptyfor non-nullable strings), keeping the tag the only occurrence on the wire. - Self-mapped and enum-typed discriminators keep the inline variants, so those unions still drop their children's fields; a child built with
new()still writes the tag twice through the union.
Testing
- Adds the
discriminated-union.yamlfixture and a regression test pinning the derived#[serde(tag)].
Generated with Claude Code