From 2d607de146df7c9ef550755a1a7073bb7240227f Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 14 Jun 2025 19:03:18 +0500 Subject: [PATCH] Move body generator for structs to its own module Cut-paste --- serde_derive/src/de.rs | 688 +----------------------- serde_derive/src/de/enum_externally.rs | 5 +- serde_derive/src/de/enum_internally.rs | 5 +- serde_derive/src/de/enum_untagged.rs | 5 +- serde_derive/src/de/struct_.rs | 694 +++++++++++++++++++++++++ 5 files changed, 707 insertions(+), 690 deletions(-) create mode 100644 serde_derive/src/de/struct_.rs diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 7c98a998..1b8ac19d 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1,5 +1,5 @@ use crate::deprecated::allow_deprecated; -use crate::fragment::{Expr, Fragment, Match, Stmts}; +use crate::fragment::{Expr, Fragment, Stmts}; use crate::internals::ast::{Container, Data, Field, Style, Variant}; use crate::internals::name::Name; use crate::internals::{attr, replace_receiver, ungroup, Ctxt, Derive}; @@ -17,6 +17,7 @@ mod enum_adjacently; mod enum_externally; mod enum_internally; mod enum_untagged; +mod struct_; pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result { replace_receiver(input); @@ -310,7 +311,7 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { match &cont.data { Data::Enum(variants) => enum_::deserialize_enum(params, variants, &cont.attrs), Data::Struct(Style::Struct, fields) => { - deserialize_struct(params, fields, &cont.attrs, StructForm::Struct) + struct_::deserialize_struct(params, fields, &cont.attrs, StructForm::Struct) } Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => { deserialize_tuple(params, fields, &cont.attrs, TupleForm::Tuple) @@ -345,7 +346,7 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option { - deserialize_struct_in_place(params, fields, &cont.attrs)? + struct_::deserialize_struct_in_place(params, fields, &cont.attrs)? } Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => { deserialize_tuple_in_place(params, fields, &cont.attrs) @@ -960,278 +961,6 @@ enum StructForm<'a> { Untagged(&'a syn::Ident), } -/// Generates `Deserialize::deserialize` body for a `struct Struct {...}` -fn deserialize_struct( - params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, - form: StructForm, -) -> Fragment { - let this_type = ¶ms.this_type; - let this_value = ¶ms.this_value; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); - let delife = params.borrowed.de_lifetime(); - - // If there are getters (implying private fields), construct the local type - // and use an `Into` conversion to get the remote type. If there are no - // getters then construct the target type directly. - let construct = if params.has_getter { - let local = ¶ms.local; - quote!(#local) - } else { - quote!(#this_value) - }; - - let type_path = match form { - StructForm::Struct => construct, - StructForm::ExternallyTagged(variant_ident) - | StructForm::InternallyTagged(variant_ident) - | StructForm::Untagged(variant_ident) => quote!(#construct::#variant_ident), - }; - let expecting = match form { - StructForm::Struct => format!("struct {}", params.type_name()), - StructForm::ExternallyTagged(variant_ident) - | StructForm::InternallyTagged(variant_ident) - | StructForm::Untagged(variant_ident) => { - format!("struct variant {}::{}", params.type_name(), variant_ident) - } - }; - let expecting = cattrs.expecting().unwrap_or(&expecting); - - let deserialized_fields: Vec<_> = fields - .iter() - .enumerate() - // Skip fields that shouldn't be deserialized or that were flattened, - // so they don't appear in the storage in their literal form - .filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) - .map(|(i, field)| FieldWithAliases { - ident: field_i(i), - aliases: field.attrs.aliases(), - }) - .collect(); - - let has_flatten = has_flatten(fields); - let field_visitor = deserialize_field_identifier(&deserialized_fields, cattrs, has_flatten); - - // untagged struct variants do not get a visit_seq method. The same applies to - // structs that only have a map representation. - let visit_seq = match form { - StructForm::Untagged(_) => None, - _ if has_flatten => None, - _ => { - let mut_seq = if deserialized_fields.is_empty() { - quote!(_) - } else { - quote!(mut __seq) - }; - - let visit_seq = Stmts(deserialize_seq( - &type_path, params, fields, true, cattrs, expecting, - )); - - Some(quote! { - #[inline] - fn visit_seq<__A>(self, #mut_seq: __A) -> _serde::#private::Result - where - __A: _serde::de::SeqAccess<#delife>, - { - #visit_seq - } - }) - } - }; - let visit_map = Stmts(deserialize_map( - &type_path, - params, - fields, - cattrs, - has_flatten, - )); - - let visitor_seed = match form { - StructForm::ExternallyTagged(..) if has_flatten => Some(quote! { - #[automatically_derived] - impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause { - type Value = #this_type #ty_generics; - - fn deserialize<__D>(self, __deserializer: __D) -> _serde::#private::Result - where - __D: _serde::Deserializer<#delife>, - { - _serde::Deserializer::deserialize_map(__deserializer, self) - } - } - }), - _ => None, - }; - - let fields_stmt = if has_flatten { - None - } else { - let field_names = deserialized_fields.iter().flat_map(|field| field.aliases); - - Some(quote! { - #[doc(hidden)] - const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; - }) - }; - - let visitor_expr = quote! { - __Visitor { - marker: _serde::#private::PhantomData::<#this_type #ty_generics>, - lifetime: _serde::#private::PhantomData, - } - }; - let dispatch = match form { - StructForm::Struct if has_flatten => quote! { - _serde::Deserializer::deserialize_map(__deserializer, #visitor_expr) - }, - StructForm::Struct => { - let type_name = cattrs.name().deserialize_name(); - quote! { - _serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr) - } - } - StructForm::ExternallyTagged(_) if has_flatten => quote! { - _serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr) - }, - StructForm::ExternallyTagged(_) => quote! { - _serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr) - }, - StructForm::InternallyTagged(_) => quote! { - _serde::Deserializer::deserialize_any(__deserializer, #visitor_expr) - }, - StructForm::Untagged(_) => quote! { - _serde::Deserializer::deserialize_any(__deserializer, #visitor_expr) - }, - }; - - quote_block! { - #field_visitor - - #[doc(hidden)] - struct __Visitor #de_impl_generics #where_clause { - marker: _serde::#private::PhantomData<#this_type #ty_generics>, - lifetime: _serde::#private::PhantomData<&#delife ()>, - } - - #[automatically_derived] - impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { - type Value = #this_type #ty_generics; - - fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { - _serde::#private::Formatter::write_str(__formatter, #expecting) - } - - #visit_seq - - #[inline] - fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result - where - __A: _serde::de::MapAccess<#delife>, - { - #visit_map - } - } - - #visitor_seed - - #fields_stmt - - #dispatch - } -} - -/// Generates `Deserialize::deserialize_in_place` body for a `struct Struct {...}` -#[cfg(feature = "deserialize_in_place")] -fn deserialize_struct_in_place( - params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, -) -> Option { - // for now we do not support in_place deserialization for structs that - // are represented as map. - if has_flatten(fields) { - return None; - } - - let this_type = ¶ms.this_type; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); - let delife = params.borrowed.de_lifetime(); - - let expecting = format!("struct {}", params.type_name()); - let expecting = cattrs.expecting().unwrap_or(&expecting); - - let deserialized_fields: Vec<_> = fields - .iter() - .enumerate() - .filter(|&(_, field)| !field.attrs.skip_deserializing()) - .map(|(i, field)| FieldWithAliases { - ident: field_i(i), - aliases: field.attrs.aliases(), - }) - .collect(); - - let field_visitor = deserialize_field_identifier(&deserialized_fields, cattrs, false); - - let mut_seq = if deserialized_fields.is_empty() { - quote!(_) - } else { - quote!(mut __seq) - }; - let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting)); - let visit_map = Stmts(deserialize_map_in_place(params, fields, cattrs)); - let field_names = deserialized_fields.iter().flat_map(|field| field.aliases); - let type_name = cattrs.name().deserialize_name(); - - let in_place_impl_generics = de_impl_generics.in_place(); - let in_place_ty_generics = de_ty_generics.in_place(); - let place_life = place_lifetime(); - - Some(quote_block! { - #field_visitor - - #[doc(hidden)] - struct __Visitor #in_place_impl_generics #where_clause { - place: &#place_life mut #this_type #ty_generics, - lifetime: _serde::#private::PhantomData<&#delife ()>, - } - - #[automatically_derived] - impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause { - type Value = (); - - fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { - _serde::#private::Formatter::write_str(__formatter, #expecting) - } - - #[inline] - fn visit_seq<__A>(self, #mut_seq: __A) -> _serde::#private::Result - where - __A: _serde::de::SeqAccess<#delife>, - { - #visit_seq - } - - #[inline] - fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result - where - __A: _serde::de::MapAccess<#delife>, - { - #visit_map - } - } - - #[doc(hidden)] - const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; - - _serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, __Visitor { - place: __place, - lifetime: _serde::#private::PhantomData, - }) - }) -} - struct FieldWithAliases<'a> { ident: Ident, aliases: &'a BTreeSet, @@ -1297,34 +1026,6 @@ fn deserialize_generated_identifier( } } -/// Generates enum and its `Deserialize` implementation that represents each -/// non-skipped field of the struct -fn deserialize_field_identifier( - deserialized_fields: &[FieldWithAliases], - cattrs: &attr::Container, - has_flatten: bool, -) -> Stmts { - let (ignore_variant, fallthrough) = if has_flatten { - let ignore_variant = quote!(__other(_serde::#private::de::Content<'de>),); - let fallthrough = quote!(_serde::#private::Ok(__Field::__other(__value))); - (Some(ignore_variant), Some(fallthrough)) - } else if cattrs.deny_unknown_fields() { - (None, None) - } else { - let ignore_variant = quote!(__ignore,); - let fallthrough = quote!(_serde::#private::Ok(__Field::__ignore)); - (Some(ignore_variant), Some(fallthrough)) - }; - - Stmts(deserialize_generated_identifier( - deserialized_fields, - has_flatten, - false, - ignore_variant, - fallthrough, - )) -} - // Generates `Deserialize::deserialize` body for an enum with // `serde(field_identifier)` or `serde(variant_identifier)` attribute. fn deserialize_custom_identifier( @@ -1731,387 +1432,6 @@ fn deserialize_identifier( } } -fn deserialize_map( - struct_path: &TokenStream, - params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, - has_flatten: bool, -) -> Fragment { - // Create the field names for the fields. - let fields_names: Vec<_> = fields - .iter() - .enumerate() - .map(|(i, field)| (field, field_i(i))) - .collect(); - - // Declare each field that will be deserialized. - let let_values = fields_names - .iter() - .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) - .map(|(field, name)| { - let field_ty = field.ty; - quote! { - let mut #name: _serde::#private::Option<#field_ty> = _serde::#private::None; - } - }); - - // Collect contents for flatten fields into a buffer - let let_collect = if has_flatten { - Some(quote! { - let mut __collect = _serde::#private::Vec::<_serde::#private::Option<( - _serde::#private::de::Content, - _serde::#private::de::Content - )>>::new(); - }) - } else { - None - }; - - // Match arms to extract a value for a field. - let value_arms = fields_names - .iter() - .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) - .map(|(field, name)| { - let deser_name = field.attrs.name().deserialize_name(); - - let visit = match field.attrs.deserialize_with() { - None => { - let field_ty = field.ty; - let span = field.original.span(); - let func = - quote_spanned!(span=> _serde::de::MapAccess::next_value::<#field_ty>); - quote! { - #func(&mut __map)? - } - } - Some(path) => { - let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); - quote!({ - #wrapper - match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) { - _serde::#private::Ok(__wrapper) => __wrapper.value, - _serde::#private::Err(__err) => { - return _serde::#private::Err(__err); - } - } - }) - } - }; - quote! { - __Field::#name => { - if _serde::#private::Option::is_some(&#name) { - return _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name)); - } - #name = _serde::#private::Some(#visit); - } - } - }); - - // Visit ignored values to consume them - let ignored_arm = if has_flatten { - Some(quote! { - __Field::__other(__name) => { - __collect.push(_serde::#private::Some(( - __name, - _serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::ContentVisitor::new())?))); - } - }) - } else if cattrs.deny_unknown_fields() { - None - } else { - Some(quote! { - _ => { let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; } - }) - }; - - let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); - let match_keys = if cattrs.deny_unknown_fields() && all_skipped { - quote! { - // FIXME: Once feature(exhaustive_patterns) is stable: - // let _serde::#private::None::<__Field> = _serde::de::MapAccess::next_key(&mut __map)?; - _serde::#private::Option::map( - _serde::de::MapAccess::next_key::<__Field>(&mut __map)?, - |__impossible| match __impossible {}); - } - } else { - quote! { - while let _serde::#private::Some(__key) = _serde::de::MapAccess::next_key::<__Field>(&mut __map)? { - match __key { - #(#value_arms)* - #ignored_arm - } - } - } - }; - - let extract_values = fields_names - .iter() - .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) - .map(|(field, name)| { - let missing_expr = Match(expr_is_missing(field, cattrs)); - - quote! { - let #name = match #name { - _serde::#private::Some(#name) => #name, - _serde::#private::None => #missing_expr - }; - } - }); - - let extract_collected = fields_names - .iter() - .filter(|&&(field, _)| field.attrs.flatten() && !field.attrs.skip_deserializing()) - .map(|(field, name)| { - let field_ty = field.ty; - let func = match field.attrs.deserialize_with() { - None => { - let span = field.original.span(); - quote_spanned!(span=> _serde::de::Deserialize::deserialize) - } - Some(path) => quote!(#path), - }; - quote! { - let #name: #field_ty = #func( - _serde::#private::de::FlatMapDeserializer( - &mut __collect, - _serde::#private::PhantomData))?; - } - }); - - let collected_deny_unknown_fields = if has_flatten && cattrs.deny_unknown_fields() { - Some(quote! { - if let _serde::#private::Some(_serde::#private::Some((__key, _))) = - __collect.into_iter().filter(_serde::#private::Option::is_some).next() - { - if let _serde::#private::Some(__key) = _serde::#private::de::content_as_str(&__key) { - return _serde::#private::Err( - _serde::de::Error::custom(format_args!("unknown field `{}`", &__key))); - } else { - return _serde::#private::Err( - _serde::de::Error::custom(format_args!("unexpected map key"))); - } - } - }) - } else { - None - }; - - let result = fields_names.iter().map(|(field, name)| { - let member = &field.member; - if field.attrs.skip_deserializing() { - let value = Expr(expr_is_missing(field, cattrs)); - quote!(#member: #value) - } else { - quote!(#member: #name) - } - }); - - let let_default = match cattrs.default() { - attr::Default::Default => Some(quote!( - let __default: Self::Value = _serde::#private::Default::default(); - )), - // If #path returns wrong type, error will be reported here (^^^^^). - // We attach span of the path to the function so it will be reported - // on the #[serde(default = "...")] - // ^^^^^ - attr::Default::Path(path) => Some(quote_spanned!(path.span()=> - let __default: Self::Value = #path(); - )), - attr::Default::None => { - // We don't need the default value, to prevent an unused variable warning - // we'll leave the line empty. - None - } - }; - - let mut result = quote!(#struct_path { #(#result),* }); - if params.has_getter { - let this_type = ¶ms.this_type; - let (_, ty_generics, _) = params.generics.split_for_impl(); - result = quote! { - _serde::#private::Into::<#this_type #ty_generics>::into(#result) - }; - } - - quote_block! { - #(#let_values)* - - #let_collect - - #match_keys - - #let_default - - #(#extract_values)* - - #(#extract_collected)* - - #collected_deny_unknown_fields - - _serde::#private::Ok(#result) - } -} - -#[cfg(feature = "deserialize_in_place")] -fn deserialize_map_in_place( - params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, -) -> Fragment { - assert!( - !has_flatten(fields), - "inplace deserialization of maps does not support flatten fields" - ); - - // Create the field names for the fields. - let fields_names: Vec<_> = fields - .iter() - .enumerate() - .map(|(i, field)| (field, field_i(i))) - .collect(); - - // For deserialize_in_place, declare booleans for each field that will be - // deserialized. - let let_flags = fields_names - .iter() - .filter(|&&(field, _)| !field.attrs.skip_deserializing()) - .map(|(_, name)| { - quote! { - let mut #name: bool = false; - } - }); - - // Match arms to extract a value for a field. - let value_arms_from = fields_names - .iter() - .filter(|&&(field, _)| !field.attrs.skip_deserializing()) - .map(|(field, name)| { - let deser_name = field.attrs.name().deserialize_name(); - let member = &field.member; - - let visit = match field.attrs.deserialize_with() { - None => { - quote! { - _serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::InPlaceSeed(&mut self.place.#member))? - } - } - Some(path) => { - let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); - quote!({ - #wrapper - self.place.#member = match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) { - _serde::#private::Ok(__wrapper) => __wrapper.value, - _serde::#private::Err(__err) => { - return _serde::#private::Err(__err); - } - }; - }) - } - }; - quote! { - __Field::#name => { - if #name { - return _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name)); - } - #visit; - #name = true; - } - } - }); - - // Visit ignored values to consume them - let ignored_arm = if cattrs.deny_unknown_fields() { - None - } else { - Some(quote! { - _ => { let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; } - }) - }; - - let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); - - let match_keys = if cattrs.deny_unknown_fields() && all_skipped { - quote! { - // FIXME: Once feature(exhaustive_patterns) is stable: - // let _serde::#private::None::<__Field> = _serde::de::MapAccess::next_key(&mut __map)?; - _serde::#private::Option::map( - _serde::de::MapAccess::next_key::<__Field>(&mut __map)?, - |__impossible| match __impossible {}); - } - } else { - quote! { - while let _serde::#private::Some(__key) = _serde::de::MapAccess::next_key::<__Field>(&mut __map)? { - match __key { - #(#value_arms_from)* - #ignored_arm - } - } - } - }; - - let check_flags = fields_names - .iter() - .filter(|&&(field, _)| !field.attrs.skip_deserializing()) - .map(|(field, name)| { - let missing_expr = expr_is_missing(field, cattrs); - // If missing_expr unconditionally returns an error, don't try - // to assign its value to self.place. - if field.attrs.default().is_none() - && cattrs.default().is_none() - && field.attrs.deserialize_with().is_some() - { - let missing_expr = Stmts(missing_expr); - quote! { - if !#name { - #missing_expr; - } - } - } else { - let member = &field.member; - let missing_expr = Expr(missing_expr); - quote! { - if !#name { - self.place.#member = #missing_expr; - }; - } - } - }); - - let this_type = ¶ms.this_type; - let (_, _, ty_generics, _) = params.generics(); - - let let_default = match cattrs.default() { - attr::Default::Default => Some(quote!( - let __default: #this_type #ty_generics = _serde::#private::Default::default(); - )), - // If #path returns wrong type, error will be reported here (^^^^^). - // We attach span of the path to the function so it will be reported - // on the #[serde(default = "...")] - // ^^^^^ - attr::Default::Path(path) => Some(quote_spanned!(path.span()=> - let __default: #this_type #ty_generics = #path(); - )), - attr::Default::None => { - // We don't need the default value, to prevent an unused variable warning - // we'll leave the line empty. - None - } - }; - - quote_block! { - #(#let_flags)* - - #match_keys - - #let_default - - #(#check_flags)* - - _serde::#private::Ok(()) - } -} - fn field_i(i: usize) -> Ident { Ident::new(&format!("__field{}", i), Span::call_site()) } diff --git a/serde_derive/src/de/enum_externally.rs b/serde_derive/src/de/enum_externally.rs index ad321065..c9a9f236 100644 --- a/serde_derive/src/de/enum_externally.rs +++ b/serde_derive/src/de/enum_externally.rs @@ -5,8 +5,9 @@ //! ``` use crate::de::enum_; +use crate::de::struct_; use crate::de::{ - deserialize_struct, deserialize_tuple, expr_is_missing, field_i, + deserialize_tuple, expr_is_missing, field_i, unwrap_to_variant_closure, wrap_deserialize_field_with, wrap_deserialize_with, Parameters, StructForm, TupleForm, }; @@ -148,7 +149,7 @@ fn deserialize_externally_tagged_variant( cattrs, TupleForm::ExternallyTagged(variant_ident), ), - Style::Struct => deserialize_struct( + Style::Struct => struct_::deserialize_struct( params, &variant.fields, cattrs, diff --git a/serde_derive/src/de/enum_internally.rs b/serde_derive/src/de/enum_internally.rs index 0f21c1ea..7d9a9ff1 100644 --- a/serde_derive/src/de/enum_internally.rs +++ b/serde_derive/src/de/enum_internally.rs @@ -7,8 +7,9 @@ use crate::de::enum_; use crate::de::enum_untagged; +use crate::de::struct_; use crate::de::{ - deserialize_struct, effective_style, expr_is_missing, field_i, + effective_style, expr_is_missing, field_i, unwrap_to_variant_closure, Parameters, StructForm, }; use crate::fragment::{Expr, Fragment, Match}; @@ -95,7 +96,7 @@ fn deserialize_internally_tagged_variant( Style::Newtype => { enum_untagged::deserialize_untagged_newtype_variant(variant_ident, params, &variant.fields[0]) } - Style::Struct => deserialize_struct( + Style::Struct => struct_::deserialize_struct( params, &variant.fields, cattrs, diff --git a/serde_derive/src/de/enum_untagged.rs b/serde_derive/src/de/enum_untagged.rs index 78546870..05a41498 100644 --- a/serde_derive/src/de/enum_untagged.rs +++ b/serde_derive/src/de/enum_untagged.rs @@ -5,8 +5,9 @@ //! enum Enum {} //! ``` +use crate::de::struct_; use crate::de::{ - deserialize_struct, deserialize_tuple, effective_style, expr_is_missing, + deserialize_tuple, effective_style, expr_is_missing, unwrap_to_variant_closure, Parameters, StructForm, TupleForm, }; use crate::fragment::{Expr, Fragment}; @@ -99,7 +100,7 @@ pub fn deserialize_untagged_variant( cattrs, TupleForm::Untagged(variant_ident), ), - Style::Struct => deserialize_struct( + Style::Struct => struct_::deserialize_struct( params, &variant.fields, cattrs, diff --git a/serde_derive/src/de/struct_.rs b/serde_derive/src/de/struct_.rs new file mode 100644 index 00000000..721a4839 --- /dev/null +++ b/serde_derive/src/de/struct_.rs @@ -0,0 +1,694 @@ +use crate::de::{ + deserialize_generated_identifier, deserialize_seq, expr_is_missing, field_i, has_flatten, + wrap_deserialize_field_with, FieldWithAliases, Parameters, StructForm, +}; +#[cfg(feature = "deserialize_in_place")] +use crate::de::{deserialize_seq_in_place, place_lifetime}; +use crate::fragment::{Expr, Fragment, Match, Stmts}; +use crate::internals::ast::Field; +use crate::internals::attr; +use crate::private; +use proc_macro2::TokenStream; +use quote::{quote, quote_spanned}; +use syn::spanned::Spanned; + +/// Generates `Deserialize::deserialize` body for a `struct Struct {...}` +pub fn deserialize_struct( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + form: StructForm, +) -> Fragment { + let this_type = ¶ms.this_type; + let this_value = ¶ms.this_value; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); + let delife = params.borrowed.de_lifetime(); + + // If there are getters (implying private fields), construct the local type + // and use an `Into` conversion to get the remote type. If there are no + // getters then construct the target type directly. + let construct = if params.has_getter { + let local = ¶ms.local; + quote!(#local) + } else { + quote!(#this_value) + }; + + let type_path = match form { + StructForm::Struct => construct, + StructForm::ExternallyTagged(variant_ident) + | StructForm::InternallyTagged(variant_ident) + | StructForm::Untagged(variant_ident) => quote!(#construct::#variant_ident), + }; + let expecting = match form { + StructForm::Struct => format!("struct {}", params.type_name()), + StructForm::ExternallyTagged(variant_ident) + | StructForm::InternallyTagged(variant_ident) + | StructForm::Untagged(variant_ident) => { + format!("struct variant {}::{}", params.type_name(), variant_ident) + } + }; + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let deserialized_fields: Vec<_> = fields + .iter() + .enumerate() + // Skip fields that shouldn't be deserialized or that were flattened, + // so they don't appear in the storage in their literal form + .filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|(i, field)| FieldWithAliases { + ident: field_i(i), + aliases: field.attrs.aliases(), + }) + .collect(); + + let has_flatten = has_flatten(fields); + let field_visitor = deserialize_field_identifier(&deserialized_fields, cattrs, has_flatten); + + // untagged struct variants do not get a visit_seq method. The same applies to + // structs that only have a map representation. + let visit_seq = match form { + StructForm::Untagged(_) => None, + _ if has_flatten => None, + _ => { + let mut_seq = if deserialized_fields.is_empty() { + quote!(_) + } else { + quote!(mut __seq) + }; + + let visit_seq = Stmts(deserialize_seq( + &type_path, params, fields, true, cattrs, expecting, + )); + + Some(quote! { + #[inline] + fn visit_seq<__A>(self, #mut_seq: __A) -> _serde::#private::Result + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + }) + } + }; + let visit_map = Stmts(deserialize_map( + &type_path, + params, + fields, + cattrs, + has_flatten, + )); + + let visitor_seed = match form { + StructForm::ExternallyTagged(..) if has_flatten => Some(quote! { + #[automatically_derived] + impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn deserialize<__D>(self, __deserializer: __D) -> _serde::#private::Result + where + __D: _serde::Deserializer<#delife>, + { + _serde::Deserializer::deserialize_map(__deserializer, self) + } + } + }), + _ => None, + }; + + let fields_stmt = if has_flatten { + None + } else { + let field_names = deserialized_fields.iter().flat_map(|field| field.aliases); + + Some(quote! { + #[doc(hidden)] + const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; + }) + }; + + let visitor_expr = quote! { + __Visitor { + marker: _serde::#private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData, + } + }; + let dispatch = match form { + StructForm::Struct if has_flatten => quote! { + _serde::Deserializer::deserialize_map(__deserializer, #visitor_expr) + }, + StructForm::Struct => { + let type_name = cattrs.name().deserialize_name(); + quote! { + _serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr) + } + } + StructForm::ExternallyTagged(_) if has_flatten => quote! { + _serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr) + }, + StructForm::ExternallyTagged(_) => quote! { + _serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr) + }, + StructForm::InternallyTagged(_) => quote! { + _serde::Deserializer::deserialize_any(__deserializer, #visitor_expr) + }, + StructForm::Untagged(_) => quote! { + _serde::Deserializer::deserialize_any(__deserializer, #visitor_expr) + }, + }; + + quote_block! { + #field_visitor + + #[doc(hidden)] + struct __Visitor #de_impl_generics #where_clause { + marker: _serde::#private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData<&#delife ()>, + } + + #[automatically_derived] + impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { + _serde::#private::Formatter::write_str(__formatter, #expecting) + } + + #visit_seq + + #[inline] + fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result + where + __A: _serde::de::MapAccess<#delife>, + { + #visit_map + } + } + + #visitor_seed + + #fields_stmt + + #dispatch + } +} + +/// Generates `Deserialize::deserialize_in_place` body for a `struct Struct {...}` +#[cfg(feature = "deserialize_in_place")] +pub fn deserialize_struct_in_place( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Option { + // for now we do not support in_place deserialization for structs that + // are represented as map. + if has_flatten(fields) { + return None; + } + + let this_type = ¶ms.this_type; + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); + let delife = params.borrowed.de_lifetime(); + + let expecting = format!("struct {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let deserialized_fields: Vec<_> = fields + .iter() + .enumerate() + .filter(|&(_, field)| !field.attrs.skip_deserializing()) + .map(|(i, field)| FieldWithAliases { + ident: field_i(i), + aliases: field.attrs.aliases(), + }) + .collect(); + + let field_visitor = deserialize_field_identifier(&deserialized_fields, cattrs, false); + + let mut_seq = if deserialized_fields.is_empty() { + quote!(_) + } else { + quote!(mut __seq) + }; + let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting)); + let visit_map = Stmts(deserialize_map_in_place(params, fields, cattrs)); + let field_names = deserialized_fields.iter().flat_map(|field| field.aliases); + let type_name = cattrs.name().deserialize_name(); + + let in_place_impl_generics = de_impl_generics.in_place(); + let in_place_ty_generics = de_ty_generics.in_place(); + let place_life = place_lifetime(); + + Some(quote_block! { + #field_visitor + + #[doc(hidden)] + struct __Visitor #in_place_impl_generics #where_clause { + place: &#place_life mut #this_type #ty_generics, + lifetime: _serde::#private::PhantomData<&#delife ()>, + } + + #[automatically_derived] + impl #in_place_impl_generics _serde::de::Visitor<#delife> for __Visitor #in_place_ty_generics #where_clause { + type Value = (); + + fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { + _serde::#private::Formatter::write_str(__formatter, #expecting) + } + + #[inline] + fn visit_seq<__A>(self, #mut_seq: __A) -> _serde::#private::Result + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + + #[inline] + fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result + where + __A: _serde::de::MapAccess<#delife>, + { + #visit_map + } + } + + #[doc(hidden)] + const FIELDS: &'static [&'static str] = &[ #(#field_names),* ]; + + _serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, __Visitor { + place: __place, + lifetime: _serde::#private::PhantomData, + }) + }) +} + +/// Generates enum and its `Deserialize` implementation that represents each +/// non-skipped field of the struct +fn deserialize_field_identifier( + deserialized_fields: &[FieldWithAliases], + cattrs: &attr::Container, + has_flatten: bool, +) -> Stmts { + let (ignore_variant, fallthrough) = if has_flatten { + let ignore_variant = quote!(__other(_serde::#private::de::Content<'de>),); + let fallthrough = quote!(_serde::#private::Ok(__Field::__other(__value))); + (Some(ignore_variant), Some(fallthrough)) + } else if cattrs.deny_unknown_fields() { + (None, None) + } else { + let ignore_variant = quote!(__ignore,); + let fallthrough = quote!(_serde::#private::Ok(__Field::__ignore)); + (Some(ignore_variant), Some(fallthrough)) + }; + + Stmts(deserialize_generated_identifier( + deserialized_fields, + has_flatten, + false, + ignore_variant, + fallthrough, + )) +} + +fn deserialize_map( + struct_path: &TokenStream, + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + has_flatten: bool, +) -> Fragment { + // Create the field names for the fields. + let fields_names: Vec<_> = fields + .iter() + .enumerate() + .map(|(i, field)| (field, field_i(i))) + .collect(); + + // Declare each field that will be deserialized. + let let_values = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|(field, name)| { + let field_ty = field.ty; + quote! { + let mut #name: _serde::#private::Option<#field_ty> = _serde::#private::None; + } + }); + + // Collect contents for flatten fields into a buffer + let let_collect = if has_flatten { + Some(quote! { + let mut __collect = _serde::#private::Vec::<_serde::#private::Option<( + _serde::#private::de::Content, + _serde::#private::de::Content + )>>::new(); + }) + } else { + None + }; + + // Match arms to extract a value for a field. + let value_arms = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|(field, name)| { + let deser_name = field.attrs.name().deserialize_name(); + + let visit = match field.attrs.deserialize_with() { + None => { + let field_ty = field.ty; + let span = field.original.span(); + let func = + quote_spanned!(span=> _serde::de::MapAccess::next_value::<#field_ty>); + quote! { + #func(&mut __map)? + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote!({ + #wrapper + match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) { + _serde::#private::Ok(__wrapper) => __wrapper.value, + _serde::#private::Err(__err) => { + return _serde::#private::Err(__err); + } + } + }) + } + }; + quote! { + __Field::#name => { + if _serde::#private::Option::is_some(&#name) { + return _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name)); + } + #name = _serde::#private::Some(#visit); + } + } + }); + + // Visit ignored values to consume them + let ignored_arm = if has_flatten { + Some(quote! { + __Field::__other(__name) => { + __collect.push(_serde::#private::Some(( + __name, + _serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::ContentVisitor::new())?))); + } + }) + } else if cattrs.deny_unknown_fields() { + None + } else { + Some(quote! { + _ => { let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; } + }) + }; + + let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); + let match_keys = if cattrs.deny_unknown_fields() && all_skipped { + quote! { + // FIXME: Once feature(exhaustive_patterns) is stable: + // let _serde::#private::None::<__Field> = _serde::de::MapAccess::next_key(&mut __map)?; + _serde::#private::Option::map( + _serde::de::MapAccess::next_key::<__Field>(&mut __map)?, + |__impossible| match __impossible {}); + } + } else { + quote! { + while let _serde::#private::Some(__key) = _serde::de::MapAccess::next_key::<__Field>(&mut __map)? { + match __key { + #(#value_arms)* + #ignored_arm + } + } + } + }; + + let extract_values = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing() && !field.attrs.flatten()) + .map(|(field, name)| { + let missing_expr = Match(expr_is_missing(field, cattrs)); + + quote! { + let #name = match #name { + _serde::#private::Some(#name) => #name, + _serde::#private::None => #missing_expr + }; + } + }); + + let extract_collected = fields_names + .iter() + .filter(|&&(field, _)| field.attrs.flatten() && !field.attrs.skip_deserializing()) + .map(|(field, name)| { + let field_ty = field.ty; + let func = match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + quote_spanned!(span=> _serde::de::Deserialize::deserialize) + } + Some(path) => quote!(#path), + }; + quote! { + let #name: #field_ty = #func( + _serde::#private::de::FlatMapDeserializer( + &mut __collect, + _serde::#private::PhantomData))?; + } + }); + + let collected_deny_unknown_fields = if has_flatten && cattrs.deny_unknown_fields() { + Some(quote! { + if let _serde::#private::Some(_serde::#private::Some((__key, _))) = + __collect.into_iter().filter(_serde::#private::Option::is_some).next() + { + if let _serde::#private::Some(__key) = _serde::#private::de::content_as_str(&__key) { + return _serde::#private::Err( + _serde::de::Error::custom(format_args!("unknown field `{}`", &__key))); + } else { + return _serde::#private::Err( + _serde::de::Error::custom(format_args!("unexpected map key"))); + } + } + }) + } else { + None + }; + + let result = fields_names.iter().map(|(field, name)| { + let member = &field.member; + if field.attrs.skip_deserializing() { + let value = Expr(expr_is_missing(field, cattrs)); + quote!(#member: #value) + } else { + quote!(#member: #name) + } + }); + + let let_default = match cattrs.default() { + attr::Default::Default => Some(quote!( + let __default: Self::Value = _serde::#private::Default::default(); + )), + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + attr::Default::Path(path) => Some(quote_spanned!(path.span()=> + let __default: Self::Value = #path(); + )), + attr::Default::None => { + // We don't need the default value, to prevent an unused variable warning + // we'll leave the line empty. + None + } + }; + + let mut result = quote!(#struct_path { #(#result),* }); + if params.has_getter { + let this_type = ¶ms.this_type; + let (_, ty_generics, _) = params.generics.split_for_impl(); + result = quote! { + _serde::#private::Into::<#this_type #ty_generics>::into(#result) + }; + } + + quote_block! { + #(#let_values)* + + #let_collect + + #match_keys + + #let_default + + #(#extract_values)* + + #(#extract_collected)* + + #collected_deny_unknown_fields + + _serde::#private::Ok(#result) + } +} + +#[cfg(feature = "deserialize_in_place")] +fn deserialize_map_in_place( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + assert!( + !has_flatten(fields), + "inplace deserialization of maps does not support flatten fields" + ); + + // Create the field names for the fields. + let fields_names: Vec<_> = fields + .iter() + .enumerate() + .map(|(i, field)| (field, field_i(i))) + .collect(); + + // For deserialize_in_place, declare booleans for each field that will be + // deserialized. + let let_flags = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing()) + .map(|(_, name)| { + quote! { + let mut #name: bool = false; + } + }); + + // Match arms to extract a value for a field. + let value_arms_from = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing()) + .map(|(field, name)| { + let deser_name = field.attrs.name().deserialize_name(); + let member = &field.member; + + let visit = match field.attrs.deserialize_with() { + None => { + quote! { + _serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::InPlaceSeed(&mut self.place.#member))? + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote!({ + #wrapper + self.place.#member = match _serde::de::MapAccess::next_value::<#wrapper_ty>(&mut __map) { + _serde::#private::Ok(__wrapper) => __wrapper.value, + _serde::#private::Err(__err) => { + return _serde::#private::Err(__err); + } + }; + }) + } + }; + quote! { + __Field::#name => { + if #name { + return _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#deser_name)); + } + #visit; + #name = true; + } + } + }); + + // Visit ignored values to consume them + let ignored_arm = if cattrs.deny_unknown_fields() { + None + } else { + Some(quote! { + _ => { let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; } + }) + }; + + let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing()); + + let match_keys = if cattrs.deny_unknown_fields() && all_skipped { + quote! { + // FIXME: Once feature(exhaustive_patterns) is stable: + // let _serde::#private::None::<__Field> = _serde::de::MapAccess::next_key(&mut __map)?; + _serde::#private::Option::map( + _serde::de::MapAccess::next_key::<__Field>(&mut __map)?, + |__impossible| match __impossible {}); + } + } else { + quote! { + while let _serde::#private::Some(__key) = _serde::de::MapAccess::next_key::<__Field>(&mut __map)? { + match __key { + #(#value_arms_from)* + #ignored_arm + } + } + } + }; + + let check_flags = fields_names + .iter() + .filter(|&&(field, _)| !field.attrs.skip_deserializing()) + .map(|(field, name)| { + let missing_expr = expr_is_missing(field, cattrs); + // If missing_expr unconditionally returns an error, don't try + // to assign its value to self.place. + if field.attrs.default().is_none() + && cattrs.default().is_none() + && field.attrs.deserialize_with().is_some() + { + let missing_expr = Stmts(missing_expr); + quote! { + if !#name { + #missing_expr; + } + } + } else { + let member = &field.member; + let missing_expr = Expr(missing_expr); + quote! { + if !#name { + self.place.#member = #missing_expr; + }; + } + } + }); + + let this_type = ¶ms.this_type; + let (_, _, ty_generics, _) = params.generics(); + + let let_default = match cattrs.default() { + attr::Default::Default => Some(quote!( + let __default: #this_type #ty_generics = _serde::#private::Default::default(); + )), + // If #path returns wrong type, error will be reported here (^^^^^). + // We attach span of the path to the function so it will be reported + // on the #[serde(default = "...")] + // ^^^^^ + attr::Default::Path(path) => Some(quote_spanned!(path.span()=> + let __default: #this_type #ty_generics = #path(); + )), + attr::Default::None => { + // We don't need the default value, to prevent an unused variable warning + // we'll leave the line empty. + None + } + }; + + quote_block! { + #(#let_flags)* + + #match_keys + + #let_default + + #(#check_flags)* + + _serde::#private::Ok(()) + } +}