diff --git a/serde/src/private/de.rs b/serde/src/private/de.rs index a3a55d8e..74eda4da 100644 --- a/serde/src/private/de.rs +++ b/serde/src/private/de.rs @@ -8,7 +8,7 @@ use lib::*; -use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor}; +use de::{Deserialize, DeserializeSeed, Deserializer, Error, IntoDeserializer, Visitor, MapAccess}; #[cfg(any(feature = "std", feature = "alloc"))] use de::Unexpected; @@ -2062,3 +2062,117 @@ where T::deserialize_in_place(deserializer, self.0) } } + +#[cfg(any(feature = "std", feature = "alloc"))] +pub struct FlatMapDeserializer<'a, 'de: 'a, E>( + pub &'a mut Vec)>>, + pub PhantomData +); + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E> + where E: Error +{ + type Error = E; + + fn deserialize_any(self, _visitor: V) -> Result + where + V: Visitor<'de>, + { + Err(Error::custom("can only deserialize structs and maps in flatten mode")) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_map(FlatMapAccess::new(self.0.iter_mut(), None)) + } + + fn deserialize_struct( + self, + _: &'static str, + fields: &'static [&'static str], + visitor: V + ) -> Result + where + V: Visitor<'de>, + { + visitor.visit_map(FlatMapAccess::new(self.0.iter_mut(), Some(fields))) + } + + 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 newtype_struct seq tuple + tuple_struct enum identifier ignored_any + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +pub struct FlatMapAccess<'a, 'de: 'a, E> { + iter: slice::IterMut<'a, Option<(String, Content<'de>)>>, + pending_content: Option>, + fields: Option<&'static [&'static str]>, + _marker: PhantomData, +} + +impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> { + fn new( + iter: slice::IterMut<'a, Option<(String, Content<'de>)>>, + fields: Option<&'static [&'static str]> + ) -> FlatMapAccess<'a, 'de, E> { + FlatMapAccess { + iter: iter, + pending_content: None, + fields: fields, + _marker: PhantomData, + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E> + where E: Error +{ + type Error = E; + + fn next_key_seed(&mut self, seed: T) -> Result, Self::Error> + where + T: DeserializeSeed<'de>, + { + loop { + let item = match self.iter.next() { + Some(item) => { + if item.is_some() { + item + } else { + continue; + } + } + None => return Ok(None) + }; + + if match self.fields { + None => false, + Some(fields) if fields.contains(&item.as_ref().unwrap().0.as_str()) => false, + _ => true + } { + continue; + } + + let (key, content) = item.take().unwrap(); + self.pending_content = Some(content); + return seed.deserialize(ContentDeserializer::new(Content::String(key))).map(Some); + } + } + + fn next_value_seed(&mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + match self.pending_content.take() { + Some(value) => seed.deserialize(ContentDeserializer::new(value)), + None => Err(Error::custom("value is missing")), + } + } +} diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 01ea6bfe..c9c6989f 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -2026,7 +2026,7 @@ fn deserialize_map( // Collect contents for flatten fields into a buffer let let_collect = if cattrs.has_flatten() { Some(quote! { - let mut __collect = Vec::<(String, _serde::private::de::Content)>::new(); + let mut __collect = Vec::>::new(); }) } else { None @@ -2070,7 +2070,7 @@ fn deserialize_map( let ignored_arm = if cattrs.has_flatten() { Some(quote! { __Field::__other(__name) => { - __collect.push((__name, try!(_serde::de::MapAccess::next_value(&mut __map)))); + __collect.push(Some((__name, try!(_serde::de::MapAccess::next_value(&mut __map))))); } }) } else if cattrs.deny_unknown_fields() { @@ -2130,7 +2130,7 @@ fn deserialize_map( let collected_deny_unknown_fields = if cattrs.has_flatten() && cattrs.deny_unknown_fields() { Some(quote! { - if let Some((__key, _)) = __collect.into_iter().next() { + if let Some(Some((__key, _))) = __collect.into_iter().filter(|x| x.is_some()).next() { return _serde::export::Err( _serde::de::Error::unknown_field_in_flattened_structure(&__key)); }