serde-rs / serde

Serialization framework for Rust
https://serde.rs/
Apache License 2.0
8.82k stars 748 forks source link

RFC: Support deserializing enum values in internally/untagged enums #2692

Open Stebalien opened 5 months ago

Stebalien commented 5 months ago

This patch adds support for deserializing enum values in internally/untagged enums. E.g.:

#[derive(Debug, Deserialize, PartialEq)]
pub enum Inner {
    A, B, C
}
#[derive(Debug, Deserialize, PartialEq)]
#[serde(tag = "type")]
pub enum Internally {
    Variant { inner: Inner },
}

At the moment, if the Deserializer knows that Inner is an enum and calls visit_enum (e.g., a self-describing format that understands enums), this error will be triggered:

https://github.com/serde-rs/serde/blob/ede9762a583c3cc3b87c10a53551828fad339525/serde/src/private/de.rs#L517-L519

I'm working around this issue by serializing the variant as a Content and visiting the value with EnumAccess::newtype_variant::<Content>.

There is no perfect solution here as the enum value could be a map, tuple, unit, etc. However, given that we're trying to deserialize arbitrary values, deserializing as a "newtype" actually makes a lot of sense:

  1. Deserializers can opt-in to this fairly easily by implementing EnumAccess::newtype_variant_seed.
  2. Types (implementing Deserialize) should "just work" as expected because maps, tuples, etc. are preserved.

If you're interested in this change, I can add some tests. Unfortunately, the token test logic never calls visit_enum from deserialize_any, so testing will either require implementing a custom Deserializer and/or modifying the token deserializer.