Switch to using Content keys internally for flattening to later support arbitrary keys

This commit is contained in:
Armin Ronacher 2018-03-18 21:07:08 +01:00
parent 58d52e784b
commit ad40f976db
2 changed files with 78 additions and 65 deletions

View File

@ -269,6 +269,14 @@ mod content {
} }
impl<'de> Content<'de> { impl<'de> Content<'de> {
pub fn as_str(&self) -> Option<&str> {
match *self {
Content::Str(x) => Some(x),
Content::String(ref x) => Some(x.as_str()),
_ => None,
}
}
fn unexpected(&self) -> Unexpected { fn unexpected(&self) -> Unexpected {
match *self { match *self {
Content::Bool(b) => Unexpected::Bool(b), Content::Bool(b) => Unexpected::Bool(b),
@ -2073,7 +2081,7 @@ where
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapDeserializer<'a, 'de: 'a, E>( pub struct FlatMapDeserializer<'a, 'de: 'a, E>(
pub &'a mut Vec<Option<(String, Content<'de>)>>, pub &'a mut Vec<Option<(Content<'de>, Content<'de>)>>,
pub PhantomData<E> pub PhantomData<E>
); );
@ -2100,28 +2108,23 @@ impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
V: Visitor<'de>, V: Visitor<'de>,
{ {
let mut iter = self.0.iter_mut(); let mut iter = self.0.iter_mut();
loop { while let Some(item) = iter.next() {
let item = match iter.next() { if item.is_none() || !item.as_ref().unwrap().0.as_str()
Some(item) => { .map(|x| variants.contains(&x)).unwrap_or(false) {
if item.is_some() {
item
} else {
continue;
}
}
None => return Err(Error::custom(format_args!(
"no variant of enum {} not found in flattened data",
name
)))
};
if !variants.contains(&item.as_ref().unwrap().0.as_str()) {
continue; continue;
} }
let (key, value) = item.take().unwrap(); let (key, value) = item.take().unwrap();
return visitor.visit_enum(EnumDeserializer::new(Content::String(key), Some(value))); return visitor.visit_enum(EnumDeserializer::new(
key,
Some(value)
));
} }
Err(Error::custom(format_args!(
"no variant of enum {} not found in flattened data",
name
)))
} }
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
@ -2163,7 +2166,7 @@ impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapAccess<'a, 'de: 'a, E> { pub struct FlatMapAccess<'a, 'de: 'a, E> {
iter: slice::IterMut<'a, Option<(String, Content<'de>)>>, iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
pending_content: Option<Content<'de>>, pending_content: Option<Content<'de>>,
fields: Option<&'static [&'static str]>, fields: Option<&'static [&'static str]>,
_marker: PhantomData<E>, _marker: PhantomData<E>,
@ -2172,7 +2175,7 @@ pub struct FlatMapAccess<'a, 'de: 'a, E> {
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> { impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> {
fn new( fn new(
iter: slice::IterMut<'a, Option<(String, Content<'de>)>>, iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
fields: Option<&'static [&'static str]> fields: Option<&'static [&'static str]>
) -> FlatMapAccess<'a, 'de, E> { ) -> FlatMapAccess<'a, 'de, E> {
FlatMapAccess { FlatMapAccess {
@ -2194,30 +2197,27 @@ impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
where where
T: DeserializeSeed<'de>, T: DeserializeSeed<'de>,
{ {
loop { while let Some(item) = self.iter.next() {
let item = match self.iter.next() { if item.is_none() {
Some(item) => { continue;
if item.is_some() {
item
} else {
continue;
}
}
None => return Ok(None)
}; };
if match self.fields { if !item.as_ref().unwrap().0.as_str()
None => false, .map(|key| {
Some(fields) if fields.contains(&item.as_ref().unwrap().0.as_str()) => false, match self.fields {
_ => true None => true,
} { Some(fields) if fields.contains(&key) => true,
_ => false
}
}).unwrap_or(true) {
continue; continue;
} }
let (key, content) = item.take().unwrap(); let (key, content) = item.take().unwrap();
self.pending_content = Some(content); self.pending_content = Some(content);
return seed.deserialize(ContentDeserializer::new(Content::String(key))).map(Some); return seed.deserialize(ContentDeserializer::new(key)).map(Some);
} }
Ok(None)
} }
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error> fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>

View File

@ -1042,7 +1042,6 @@ fn deserialize_externally_tagged_enum(
&variant_names_idents, &variant_names_idents,
cattrs, cattrs,
true, true,
false,
)); ));
// Match arms to extract a variant from a string // Match arms to extract a variant from a string
@ -1142,7 +1141,6 @@ fn deserialize_internally_tagged_enum(
&variant_names_idents, &variant_names_idents,
cattrs, cattrs,
true, true,
false,
)); ));
// Match arms to extract a variant from a string // Match arms to extract a variant from a string
@ -1212,7 +1210,6 @@ fn deserialize_adjacently_tagged_enum(
&variant_names_idents, &variant_names_idents,
cattrs, cattrs,
true, true,
false,
)); ));
let variant_arms: &Vec<_> = &variants let variant_arms: &Vec<_> = &variants
@ -1712,22 +1709,22 @@ fn deserialize_untagged_newtype_variant(
fn deserialize_generated_identifier( fn deserialize_generated_identifier(
fields: &[(String, Ident)], fields: &[(String, Ident)],
cattrs: &attr::Container, cattrs: &attr::Container,
is_variant: bool, is_variant: bool
struct_as_map_mode: bool,
) -> Fragment { ) -> Fragment {
let this = quote!(__Field); let this = quote!(__Field);
let field_idents: &Vec<_> = &fields.iter().map(|&(_, ref ident)| ident).collect(); let field_idents: &Vec<_> = &fields.iter().map(|&(_, ref ident)| ident).collect();
let (ignore_variant, fallthrough, want_value) = if cattrs.has_flatten() { let (ignore_variant, fallthrough) = if cattrs.has_flatten() {
let ignore_variant = quote!(__other(String),); let ignore_variant = quote!(__other(_serde::private::de::Content<'de>),);
let fallthrough = quote!(_serde::export::Ok(__Field::__other(__value.to_string()))); let fallthrough = quote!(_serde::export::Ok(__Field::__other(
(Some(ignore_variant), Some(fallthrough), true) _serde::private::de::Content::String(__value.to_string()))));
(Some(ignore_variant), Some(fallthrough))
} else if is_variant || cattrs.deny_unknown_fields() { } else if is_variant || cattrs.deny_unknown_fields() {
(None, None, false) (None, None)
} else { } else {
let ignore_variant = quote!(__ignore,); let ignore_variant = quote!(__ignore,);
let fallthrough = quote!(_serde::export::Ok(__Field::__ignore)); let fallthrough = quote!(_serde::export::Ok(__Field::__ignore));
(Some(ignore_variant), Some(fallthrough), false) (Some(ignore_variant), Some(fallthrough))
}; };
let visitor_impl = Stmts(deserialize_identifier( let visitor_impl = Stmts(deserialize_identifier(
@ -1735,13 +1732,18 @@ fn deserialize_generated_identifier(
fields, fields,
is_variant, is_variant,
fallthrough, fallthrough,
struct_as_map_mode, cattrs.has_flatten(),
want_value,
)); ));
let lifetime = if cattrs.has_flatten() {
Some(quote!(<'de>))
} else {
None
};
quote_block! { quote_block! {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
enum __Field { enum __Field #lifetime {
#(#field_idents,)* #(#field_idents,)*
#ignore_variant #ignore_variant
} }
@ -1749,12 +1751,12 @@ fn deserialize_generated_identifier(
struct __FieldVisitor; struct __FieldVisitor;
impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
type Value = __Field; type Value = __Field #lifetime;
#visitor_impl #visitor_impl
} }
impl<'de> _serde::Deserialize<'de> for __Field { impl<'de> _serde::Deserialize<'de> for __Field #lifetime {
#[inline] #[inline]
fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error> fn deserialize<__D>(__deserializer: __D) -> _serde::export::Result<Self, __D::Error>
where __D: _serde::Deserializer<'de> where __D: _serde::Deserializer<'de>
@ -1836,7 +1838,6 @@ fn deserialize_custom_identifier(
is_variant, is_variant,
fallthrough, fallthrough,
false, false,
false,
)); ));
quote_block! { quote_block! {
@ -1866,8 +1867,7 @@ fn deserialize_identifier(
fields: &[(String, Ident)], fields: &[(String, Ident)],
is_variant: bool, is_variant: bool,
fallthrough: Option<Tokens>, fallthrough: Option<Tokens>,
struct_as_map_mode: bool, collect_other_fields: bool
want_value: bool
) -> Fragment { ) -> Fragment {
let field_strs = fields.iter().map(|&(ref name, _)| name); let field_strs = fields.iter().map(|&(ref name, _)| name);
let field_bytes = fields.iter().map(|&(ref name, _)| Literal::byte_string(name.as_bytes())); let field_bytes = fields.iter().map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));
@ -1887,7 +1887,7 @@ fn deserialize_identifier(
let variant_indices = 0u64..; let variant_indices = 0u64..;
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len()); let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, fields.len());
let visit_index = if struct_as_map_mode { let visit_index = if collect_other_fields {
None None
} else { } else {
Some(quote! { Some(quote! {
@ -1906,7 +1906,7 @@ fn deserialize_identifier(
}) })
}; };
let bytes_to_str = if fallthrough.is_some() && !want_value { let bytes_to_str = if fallthrough.is_some() && !collect_other_fields {
None None
} else { } else {
let conversion = quote! { let conversion = quote! {
@ -1981,7 +1981,7 @@ fn deserialize_struct_as_struct_visitor(
} }
}; };
let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, false); let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false);
let visit_map = deserialize_map(struct_path, params, fields, cattrs); let visit_map = deserialize_map(struct_path, params, fields, cattrs);
@ -2001,7 +2001,7 @@ fn deserialize_struct_as_map_visitor(
.map(|(i, field)| (field.attrs.name().deserialize_name(), field_i(i))) .map(|(i, field)| (field.attrs.name().deserialize_name(), field_i(i)))
.collect(); .collect();
let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, true); let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false);
let visit_map = deserialize_map(struct_path, params, fields, cattrs); let visit_map = deserialize_map(struct_path, params, fields, cattrs);
@ -2035,7 +2035,10 @@ fn deserialize_map(
// Collect contents for flatten fields into a buffer // Collect contents for flatten fields into a buffer
let let_collect = if cattrs.has_flatten() { let let_collect = if cattrs.has_flatten() {
Some(quote! { Some(quote! {
let mut __collect = Vec::<Option<(String, _serde::private::de::Content)>>::new(); let mut __collect = Vec::<Option<(
_serde::private::de::Content,
_serde::private::de::Content
)>>::new();
}) })
} else { } else {
None None
@ -2079,7 +2082,9 @@ fn deserialize_map(
let ignored_arm = if cattrs.has_flatten() { let ignored_arm = if cattrs.has_flatten() {
Some(quote! { Some(quote! {
__Field::__other(__name) => { __Field::__other(__name) => {
__collect.push(Some((__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() { } else if cattrs.deny_unknown_fields() {
@ -2140,8 +2145,13 @@ fn deserialize_map(
let collected_deny_unknown_fields = if cattrs.has_flatten() && cattrs.deny_unknown_fields() { let collected_deny_unknown_fields = if cattrs.has_flatten() && cattrs.deny_unknown_fields() {
Some(quote! { Some(quote! {
if let Some(Some((__key, _))) = __collect.into_iter().filter(|x| x.is_some()).next() { if let Some(Some((__key, _))) = __collect.into_iter().filter(|x| x.is_some()).next() {
return _serde::export::Err( if let Some(__key) = __key.as_str() {
_serde::de::Error::custom(format_args!("unknown field `{}`", &__key))); return _serde::export::Err(
_serde::de::Error::custom(format_args!("unknown field `{}`", &__key)));
} else {
return _serde::export::Err(
_serde::de::Error::custom(format_args!("unexpected map key")));
}
} }
}) })
} else { } else {
@ -2219,7 +2229,7 @@ fn deserialize_struct_as_struct_in_place_visitor(
} }
}; };
let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, false); let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false);
let visit_map = deserialize_map_in_place(params, fields, cattrs); let visit_map = deserialize_map_in_place(params, fields, cattrs);
@ -2252,7 +2262,10 @@ fn deserialize_map_in_place(
// Collect contents for flatten fields into a buffer // Collect contents for flatten fields into a buffer
let let_collect = if cattrs.has_flatten() { let let_collect = if cattrs.has_flatten() {
Some(quote! { Some(quote! {
let mut __collect = Vec::<Option<(String, _serde::private::de::Content)>>::new(); let mut __collect = Vec::<Option<(
_serde::private::de::Content,
_serde::private::de::Content
)>>::new();
}) })
} else { } else {
None None