[rust] fix: oneOf discriminator with an enum-typed tag
When the variants of a oneOf declare the discriminator property as an enum (inline or $ref), the union gets #[serde(tag = "...")] while each variant struct still has the field. Serializing writes the tag twice, and deserializing a valid payload fails with missing field, since serde consumes the tag before the variant sees it.
For those unions the template now implements Serialize/Deserialize instead of using serde(tag):
- serialize: write the variant as is, adding the tag only if the variant left it unset
- deserialize: match on the tag and pass the whole object, tag included, to the variant
This is the same approach rust-axum takes. Variant structs don't change, and plain-string tags and allOf unions keep their current output.
This is an alternative to #22489, which stalled.
Still unsupported, same as on master: discriminators without mapping, and several mapping values pointing to the same schema.
Tests: RustClientCodegenTest#testOneOfEnumDiscriminatorKeepsTagInContent (3.0 and 3.1 specs), and tests/enum_discriminator_test.rs in the reqwest composed-oneof sample.
cc @frol @farcaller @richardwhiuk @paladinzh @jacob-pro @dsteeley
PR checklist
- Read the contribution guidelines.
- Run the following to build the project and update samples:
Commit all changed files../mvnw clean package || exit ./bin/generate-samples.sh ./bin/configs/*.yaml || exit ./bin/utils/export_docs_generators.sh || exit - If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.
Summary by cubic
Fixes oneOf discriminated unions whose discriminator tag is an enum (inline or $ref) so the tag is written once and valid payloads deserialize instead of failing with a missing-field error.
- For these unions, generates custom
Serialize/Deserializeimplementations instead of serde'stagattribute. - Serialization writes the variant payload as-is, then always overrides the tag to the mapped value; deserialization matches the tag and passes the whole payload, tag included, to the variant.
- Plain string tags and
allOfunions keep the existingserde(tag)output. - Still unsupported: discriminators without
mapping, and several mapping values pointing to the same schema.