Switch to using Content keys internally for flattening to later support arbitrary keys
This commit is contained in:
parent
58d52e784b
commit
ad40f976db
@ -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>
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user