diff --git a/serde/src/de/mod.rs b/serde/src/de/mod.rs index b2cc64c86..6df788948 100644 --- a/serde/src/de/mod.rs +++ b/serde/src/de/mod.rs @@ -2010,6 +2010,18 @@ pub trait EnumAccess<'de>: Sized { } } +/// Variant Hint for VariantAccess +pub enum VariantHint { + /// variant with no values + Unit, + /// variant with a single value + Newtype, + /// vuple-like variant with the length of the tuple + Tuple(usize), + /// struct-like variant. with names of the fields of the struct variant + Struct(&'static [&'static str]), +} + /// `VariantAccess` is a visitor that is created by the `Deserializer` and /// passed to the `Deserialize` to deserialize the content of a particular enum /// variant. @@ -2127,6 +2139,49 @@ pub trait VariantAccess<'de>: Sized { self.newtype_variant_seed(PhantomData) } + /// Variant type hint + /// ```edition2021 + /// # use serde::de::{self, value, DeserializeSeed, Visitor, VariantAccess, VariantHint, Unexpected}; + /// # + /// # enum X { + /// # Unit, + /// # Newtype, + /// # } + /// # + /// # impl<'de> VariantAccess<'de> for X { + /// # type Error = value::Error; + /// # + /// # fn unit_variant(self) -> Result<(), Self::Error> { + /// # unimplemented!() + /// # } + /// # + /// fn hint(&self) -> Option { + /// Some(match self { + /// Self::Unit => VariantHint::Unit, + /// Self::Newtype => VariantHint::Newtype, + /// }) + /// } + /// # + /// # fn newtype_variant_seed(self, _seed: T) -> Result + /// # where + /// # T: DeserializeSeed<'de>, + /// # { unimplemented!() } + /// # + /// # fn tuple_variant(self, _: usize, _: V) -> Result + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # + /// # fn struct_variant(self, _: &[&str], _: V) -> Result + /// # where + /// # V: Visitor<'de>, + /// # { unimplemented!() } + /// # } + /// ``` + fn hint(&self) -> Option { + None + } + /// Called when deserializing a tuple-like variant. /// /// The `len` is the number of fields expected in the tuple variant. diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index af5878bbb..817948e26 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -212,7 +212,7 @@ mod content { use crate::de::value::{MapDeserializer, SeqDeserializer}; use crate::de::{ self, size_hint, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Expected, - IgnoredAny, MapAccess, SeqAccess, Unexpected, Visitor, + IgnoredAny, MapAccess, SeqAccess, Unexpected, VariantAccess, Visitor, }; /// Used from generated code to buffer the contents of the Deserializer when @@ -525,13 +525,21 @@ mod content { Ok(Content::Map(vec)) } - fn visit_enum(self, _visitor: V) -> Result + fn visit_enum(self, visitor: V) -> Result where V: EnumAccess<'de>, { - Err(de::Error::custom( + let (key, data) = tri!(visitor.variant::()); + let variant_hint = tri!(data.hint().ok_or(de::Error::custom( "untagged and internally tagged enums do not support enum input", - )) + ))); + let data = match variant_hint { + de::VariantHint::Unit => Content::Unit, + de::VariantHint::Newtype => tri!(data.newtype_variant()), + de::VariantHint::Tuple(len) => tri!(data.tuple_variant(len, self)), + de::VariantHint::Struct(fields) => tri!(data.struct_variant(fields, self)), + }; + Ok(Content::Map([(key, data)].into())) } }