From 6627540dd63f21800b7a0bc752d32b38f41c4c11 Mon Sep 17 00:00:00 2001 From: Jan Michael Auer Date: Thu, 15 Mar 2018 15:49:40 +0100 Subject: [PATCH] Added support basic deserialization in derive --- serde/src/de/mod.rs | 7 +++++ serde/src/export.rs | 1 - serde_derive/src/de.rs | 58 ++++++++++++++++++++++++++++------------- serde_derive/src/ser.rs | 2 +- 4 files changed, 48 insertions(+), 20 deletions(-) diff --git a/serde/src/de/mod.rs b/serde/src/de/mod.rs index cc2c6502..162d4ad4 100644 --- a/serde/src/de/mod.rs +++ b/serde/src/de/mod.rs @@ -255,6 +255,13 @@ macro_rules! declare_error_trait { } } + /// Raised when a `Deserialize` struct type recieved a field with an + /// unrecognized name but the names are not actually known because of + /// flattening. + fn unknow_field_in_flattened_structure(field: &str) -> Self { + Error::custom(format_args!("unknown field `{}`", field)) + } + /// Raised when a `Deserialize` struct type expected to receive a required /// field with a particular name but that field was not present in the /// input. diff --git a/serde/src/export.rs b/serde/src/export.rs index e92b647d..772f3103 100644 --- a/serde/src/export.rs +++ b/serde/src/export.rs @@ -13,7 +13,6 @@ pub use lib::fmt::{self, Formatter}; pub use lib::marker::PhantomData; pub use lib::option::Option::{self, None, Some}; pub use lib::result::Result::{self, Err, Ok}; -pub use lib::iter::once; pub use self::string::from_utf8_lossy; diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 606b0f4e..7ced726a 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1711,7 +1711,7 @@ fn deserialize_generated_identifier( let (ignore_variant, fallthrough, want_value) = if is_variant || cattrs.deny_unknown_fields() { (None, None, false) - } else if cattrs.unknown_fields_into().is_some() { + } else if cattrs.has_flatten() { let ignore_variant = quote!(__other(String),); let fallthrough = quote!(_serde::export::Ok(__Field::__other(__value.to_string()))); (Some(ignore_variant), Some(fallthrough), true) @@ -2023,18 +2023,14 @@ fn deserialize_map( } }); - // If we have a collect into, we also need a container that can - // hold the data we accumulate. - let mut let_collect = None; - for &(field, _) in fields_names.iter() { - if field.attrs.collection_field() { - let field_ty = &field.ty; - let_collect = Some(quote! { - let mut __collect: #field_ty = Default::default(); - }); - break; - } - } + // Collect contents for flatten fields into a buffer + let let_collect = if cattrs.has_flatten() { + Some(quote! { + let mut __collect = Vec::<_serde::private::de::Content>::new(); + }) + } else { + None + }; // Match arms to extract a value for a field. let value_arms = fields_names @@ -2073,10 +2069,10 @@ fn deserialize_map( // Visit ignored values to consume them let ignored_arm = if cattrs.deny_unknown_fields() { None - } else if cattrs.unknown_fields_into().is_some() { + } else if cattrs.has_flatten() { Some(quote! { __Field::__other(__name) => { - __collect.extend(_serde::export::once((__name, try!(_serde::de::MapAccess::next_value(&mut __map))))); + __collect.push((__name, try!(_serde::de::MapAccess::next_value(&mut __map)))); } }) } else { @@ -2119,11 +2115,33 @@ fn deserialize_map( } }); + let extract_collected = fields_names + .iter() + .filter(|&&(field, _)| field.attrs.flatten()) + .map(|&(field, ref name)| { + let field_ty = field.ty; + quote! { + let #name: #field_ty = try!(_serde::de::Deserialize::deserialize( + _serde::private::de::FlatMapDeserializer::new( + &mut __collect, + _serde::export::PhantomData))); + } + }); + + let collected_deny_unknown_fields = if cattrs.deny_unknown_fields() { + Some(quote! { + if let Some((__key, _)) = __collect.into_iter().next() { + return _serde::export::Err( + _serde::de::Error::unknown_field_in_flattened_structure(__key)); + } + }) + } else { + None + }; + let result = fields_names.iter().map(|&(field, ref name)| { let ident = field.ident.expect("struct contains unnamed fields"); - if field.attrs.collection_field() { - quote_spanned!(Span::def_site()=> #ident: __collect) - } else if field.attrs.skip_deserializing() { + if field.attrs.skip_deserializing() && !field.attrs.flatten() { let value = Expr(expr_is_missing(field, cattrs)); quote_spanned!(Span::call_site()=> #ident: #value) } else { @@ -2164,6 +2182,10 @@ fn deserialize_map( #(#extract_values)* + #(#extract_collected)* + + #collected_deny_unknown_fields + _serde::export::Ok(#result) } } diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index eb938816..20d22ff6 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -925,7 +925,7 @@ fn serialize_struct_visitor( let span = Span::def_site().located_at(field.original.span()); let ser = if field.attrs.flatten() { quote! { - try!((#field_expr).serialize(_serde::private::ser::FlatSerializer(&mut __serde_state))); + try!((#field_expr).serialize(_serde::private::ser::FlatSerializer::new(&mut __serde_state))); } } else { let func = struct_trait.serialize_field(span);