Support deserializing flattened untagged enum

This commit is contained in:
David Tolnay 2018-05-10 08:33:47 -07:00
parent f9c6f0ab62
commit 368961e961
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
4 changed files with 91 additions and 33 deletions

View File

@ -1132,18 +1132,6 @@ pub trait Deserializer<'de>: Sized {
fn is_human_readable(&self) -> bool {
true
}
// Not public API.
#[doc(hidden)]
fn private_deserialize_internally_tagged_enum<V>(
self,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_any(visitor)
}
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -2640,6 +2640,32 @@ pub struct FlatMapDeserializer<'a, 'de: 'a, E>(
pub PhantomData<E>,
);
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> FlatMapDeserializer<'a, 'de, E>
where
E: Error,
{
fn deserialize_other<V>(self, _: V) -> Result<V::Value, E>
where
V: Visitor<'de>,
{
Err(Error::custom("can only flatten structs and maps"))
}
}
macro_rules! forward_to_deserialize_other {
($($func:ident ( $($arg:ty),* ))*) => {
$(
fn $func<V>(self, $(_: $arg,)* visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_other(visitor)
}
)*
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
where
@ -2647,11 +2673,15 @@ where
{
type Error = E;
fn deserialize_any<V>(self, _: V) -> Result<V::Value, Self::Error>
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
Err(Error::custom("can only flatten structs and maps"))
visitor.visit_map(FlatInternallyTaggedAccess {
iter: self.0.iter_mut(),
pending: None,
_marker: PhantomData,
})
}
fn deserialize_enum<V>(
@ -2710,24 +2740,31 @@ where
visitor.visit_newtype_struct(self)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
byte_buf option unit unit_struct seq tuple tuple_struct identifier
ignored_any
}
fn private_deserialize_internally_tagged_enum<V>(
self,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_map(FlatInternallyTaggedAccess {
iter: self.0.iter_mut(),
pending: None,
_marker: PhantomData,
})
forward_to_deserialize_other! {
deserialize_bool()
deserialize_i8()
deserialize_i16()
deserialize_i32()
deserialize_i64()
deserialize_u8()
deserialize_u16()
deserialize_u32()
deserialize_u64()
deserialize_f32()
deserialize_f64()
deserialize_char()
deserialize_str()
deserialize_string()
deserialize_bytes()
deserialize_byte_buf()
deserialize_option()
deserialize_unit()
deserialize_unit_struct(&'static str)
deserialize_seq()
deserialize_tuple(usize)
deserialize_tuple_struct(&'static str, usize)
deserialize_identifier()
deserialize_ignored_any()
}
}

View File

@ -1263,7 +1263,7 @@ fn deserialize_internally_tagged_enum(
#variants_stmt
let __tagged = try!(_serde::Deserializer::private_deserialize_internally_tagged_enum(
let __tagged = try!(_serde::Deserializer::deserialize_any(
__deserializer,
_serde::private::de::TaggedContentVisitor::<__Field>::new(#tag)));

View File

@ -2062,3 +2062,36 @@ fn test_untagged_enum_containing_flatten() {
],
);
}
#[test]
fn test_flatten_untagged_enum() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Outer {
#[serde(flatten)]
inner: Inner,
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(untagged)]
enum Inner {
Variant {
a: i32,
},
}
let data = Outer {
inner: Inner::Variant {
a: 0,
}
};
assert_tokens(
&data,
&[
Token::Map { len: None },
Token::Str("a"),
Token::I32(0),
Token::MapEnd,
],
);
}