-
Notifications
You must be signed in to change notification settings - Fork 607
Open
Description
Serde Untagged Enum Limitation: Cannot Deserialize Strings into Unit Variants
Problem
When using untagged enums with serde, it's impossible to deserialize string values into unit variants without custom deserializers. This is a common issue when parsing CSS-like values or other structured data where you want to minimize data size.
Example
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum OpticalSizing {
#[serde(rename = "auto")]
Auto,
#[serde(rename = "none")]
None,
Fixed(f32),
}
Expected behavior:
"auto"
→OpticalSizing::Auto
"none"
→OpticalSizing::None
14.0
→OpticalSizing::Fixed(14.0)
Actual behavior:
Error("data did not match any variant of untagged enum OpticalSizing")
Why This Happens
With untagged enums, serde tries to deserialize the JSON value against each variant in order:
- Tries to deserialize
"auto"
asAuto
(unit variant) - fails because unit variants don't accept strings - Tries to deserialize
"auto"
asNone
(unit variant) - fails - Tries to deserialize
"auto"
asf32
- fails because"auto"
is not a valid f32
Use Case
This is common when parsing CSS values or similar structured data where you want to minimize data size. For example:
{
"fontOpticalSizing": "auto", // String variant
"fontSize": 14.0, // Numeric variant
"lineHeight": "normal" // String variant
}
Workarounds Tested
❌ Newtype Wrapper (Doesn't Work)
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum OpticalSizing {
Auto(#[serde(rename = "auto")] ()),
None(#[serde(rename = "none")] ()),
Fixed(f32),
}
❌ Reorder Variants (Breaks Round-trip)
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum OpticalSizing {
Fixed(f32), // Put numeric first
Auto, // Then unit variants
None,
}
✅ Custom Deserializer (Only Working Solution)
#[derive(Debug, Clone, Copy, PartialEq, Serialize)]
pub enum OpticalSizing {
Auto,
None,
Fixed(f32),
}
impl<'de> Deserialize<'de> for OpticalSizing {
// Custom implementation required
}
Request
Consider enhancing serde to support string deserialization into unit variants for untagged enums, especially when rename
attributes are present. This would eliminate the need for custom deserializers in common cases like CSS value parsing.
Related
- This affects any use case where you want to parse mixed string/numeric values into an enum
- Common in web standards, CSS parsing, configuration files
- Forces developers to write custom deserializers for what should be a simple case
Metadata
Metadata
Assignees
Labels
No labels