From 368961e9615513b53b8a41b8f7ca72c68b051d04 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 10 May 2018 08:33:47 -0700 Subject: [PATCH] Support deserializing flattened untagged enum --- serde/src/de/mod.rs | 12 ----- serde/src/private/de.rs | 77 ++++++++++++++++++++-------- serde_derive/src/de.rs | 2 +- test_suite/tests/test_annotations.rs | 33 ++++++++++++ 4 files changed, 91 insertions(+), 33 deletions(-) diff --git a/serde/src/de/mod.rs b/serde/src/de/mod.rs index 0a5c487d..826662df 100644 --- a/serde/src/de/mod.rs +++ b/serde/src/de/mod.rs @@ -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( - self, - visitor: V, - ) -> Result - where - V: Visitor<'de>, - { - self.deserialize_any(visitor) - } } //////////////////////////////////////////////////////////////////////////////// diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index feb45df5..dce863fd 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -2640,6 +2640,32 @@ pub struct FlatMapDeserializer<'a, 'de: 'a, E>( pub PhantomData, ); +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de, E> FlatMapDeserializer<'a, 'de, E> +where + E: Error, +{ + fn deserialize_other(self, _: V) -> Result + 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(self, $(_: $arg,)* visitor: V) -> Result + 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(self, _: V) -> Result + fn deserialize_any(self, visitor: V) -> Result 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( @@ -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( - self, - visitor: V, - ) -> Result - 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() } } diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 6566fd94..af10a2b8 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -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))); diff --git a/test_suite/tests/test_annotations.rs b/test_suite/tests/test_annotations.rs index 5461254f..248e4211 100644 --- a/test_suite/tests/test_annotations.rs +++ b/test_suite/tests/test_annotations.rs @@ -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, + ], + ); +}