Summary
When a struct is a variant of a discriminated oneOf (or anyOf), the discriminator field is correctly filtered out of the generated struct (src/generator.rs:932-947) so it doesn't double-encode against #[serde(tag = "...")]. However, the single-variant enum that was cached during analysis for that field is still emitted at the top level as orphan code — never referenced by any struct field.
Repro
This already happens today for enum: ["X"] discriminator fields. The snapshot src/snapshots/openapi_to_rust__test_helpers__discriminator_no_mapping.snap captures the pattern:
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(tag = "species")]
pub enum Animal {
#[serde(rename = "cat")]
Cat(Cat),
#[serde(rename = "dog")]
Dog(Dog),
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Dog {
pub bark: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Default)]
pub enum DogSpecies { // ← orphan: nothing references this
#[default]
#[serde(rename = "dog")]
Dog,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Cat {
pub meow: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Default)]
pub enum CatSpecies { // ← orphan
#[default]
#[serde(rename = "cat")]
Cat,
}
After #10 is fixed (treating const-only as a single-value enum), this same orphan pattern shows up for { "type": "string", "const": "X" } discriminator fields too — visible in oneof_in_property.snap and array_union_items.snap after that PR.
Why it matters
- Cosmetic clutter in generated modules.
- Names like
DogSpecies / URLImageSourceType pollute the public surface of the generated crate, which is awkward for downstream consumers using pub use generated::*.
- Misleading API surface — these types look usable but have no role in (de)serialization.
Suggested fix
Add a dead-type pruning pass after analysis, before codegen: walk the type graph from root operations / non-filtered struct fields, and drop anything in resolved_cache that isn't reachable. Alternatively, when the generator filters a discriminator field out of a struct, mark its referenced inline-cached enum as a candidate for removal if it has no other dependents.
The first option is more general (also catches any other unreferenced types that might leak in) and probably worth doing once.
Discovered while
Working on #10 — const-only string property generation. The fix for #10 makes this orphan pattern more visible because more discriminator fields now produce single-variant enums, but it does not introduce the underlying bug.
Summary
When a struct is a variant of a discriminated
oneOf(oranyOf), the discriminator field is correctly filtered out of the generated struct (src/generator.rs:932-947) so it doesn't double-encode against#[serde(tag = "...")]. However, the single-variant enum that was cached during analysis for that field is still emitted at the top level as orphan code — never referenced by any struct field.Repro
This already happens today for
enum: ["X"]discriminator fields. The snapshotsrc/snapshots/openapi_to_rust__test_helpers__discriminator_no_mapping.snapcaptures the pattern:After #10 is fixed (treating
const-only as a single-value enum), this same orphan pattern shows up for{ "type": "string", "const": "X" }discriminator fields too — visible inoneof_in_property.snapandarray_union_items.snapafter that PR.Why it matters
DogSpecies/URLImageSourceTypepollute the public surface of the generated crate, which is awkward for downstream consumers usingpub use generated::*.Suggested fix
Add a dead-type pruning pass after analysis, before codegen: walk the type graph from root operations / non-filtered struct fields, and drop anything in
resolved_cachethat isn't reachable. Alternatively, when the generator filters a discriminator field out of a struct, mark its referenced inline-cached enum as a candidate for removal if it has no other dependents.The first option is more general (also catches any other unreferenced types that might leak in) and probably worth doing once.
Discovered while
Working on #10 —
const-only string property generation. The fix for #10 makes this orphan pattern more visible because more discriminator fields now produce single-variant enums, but it does not introduce the underlying bug.