From 15be2a600a3e8692cd755f3cf48ab95baf7bcae7 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sun, 11 Aug 2024 02:06:52 +0500 Subject: [PATCH 01/22] Remove confusing call to deserialize_untagged_variant in deserialize_internally_tagged_variant deserialize_untagged_variant in that place is called when deserialzie_with attribute is set. In that case it performs special actions that is better to use explicitly in deserialize_untagged_variant for readability --- serde_derive/src/de.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 26c57c9d..747e4519 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1868,8 +1868,11 @@ fn deserialize_internally_tagged_variant( cattrs: &attr::Container, deserializer: TokenStream, ) -> Fragment { - if variant.attrs.deserialize_with().is_some() { - return deserialize_untagged_variant(params, variant, cattrs, deserializer); + if let Some(path) = variant.attrs.deserialize_with() { + let unwrap_fn = unwrap_to_variant_closure(params, variant, false); + return quote_block! { + _serde::#private::Result::map(#path(#deserializer), #unwrap_fn) + }; } let variant_ident = &variant.ident; From 6dffc0b1c84a7c12646cabd12e5ee6e3360a0aa8 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 14 Jun 2025 16:43:24 +0500 Subject: [PATCH 02/22] Remove one-line intermediate function --- serde_derive/src/de.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 747e4519..29b0c02d 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1228,7 +1228,7 @@ fn deserialize_enum( Some(variant_idx) => { let (tagged, untagged) = variants.split_at(variant_idx); let tagged_frag = Expr(deserialize_homogeneous_enum(params, tagged, cattrs)); - deserialize_untagged_enum_after(params, untagged, cattrs, Some(tagged_frag)) + deserialize_untagged_enum(params, untagged, cattrs, Some(tagged_frag)) } None => deserialize_homogeneous_enum(params, variants, cattrs), } @@ -1247,7 +1247,7 @@ fn deserialize_homogeneous_enum( attr::TagType::Adjacent { tag, content } => { deserialize_adjacently_tagged_enum(params, variants, cattrs, tag, content) } - attr::TagType::None => deserialize_untagged_enum(params, variants, cattrs), + attr::TagType::None => deserialize_untagged_enum(params, variants, cattrs, None), } } @@ -1753,15 +1753,6 @@ fn deserialize_untagged_enum( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, -) -> Fragment { - let first_attempt = None; - deserialize_untagged_enum_after(params, variants, cattrs, first_attempt) -} - -fn deserialize_untagged_enum_after( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, first_attempt: Option, ) -> Fragment { let attempts = variants From 4855fb467f41b96985962ba913486032f56490b2 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 14 Jun 2025 17:32:31 +0500 Subject: [PATCH 03/22] Move code for injecting tagged variants to untagged generator to the place where the decision was made --- serde_derive/src/de.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 29b0c02d..3175525e 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1228,6 +1228,14 @@ fn deserialize_enum( Some(variant_idx) => { let (tagged, untagged) = variants.split_at(variant_idx); let tagged_frag = Expr(deserialize_homogeneous_enum(params, tagged, cattrs)); + // Ignore any error associated with non-untagged deserialization so that we + // can fall through to the untagged variants. This may be infallible so we + // need to provide the error type. + let tagged_frag = quote! { + if let _serde::#private::Result::<_, __D::Error>::Ok(__ok) = (|| #tagged_frag)() { + return _serde::#private::Ok(__ok); + } + }; deserialize_untagged_enum(params, untagged, cattrs, Some(tagged_frag)) } None => deserialize_homogeneous_enum(params, variants, cattrs), @@ -1753,7 +1761,7 @@ fn deserialize_untagged_enum( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, - first_attempt: Option, + first_attempt: Option, ) -> Fragment { let attempts = variants .iter() @@ -1778,17 +1786,6 @@ fn deserialize_untagged_enum( ); let fallthrough_msg = cattrs.expecting().unwrap_or(&fallthrough_msg); - // Ignore any error associated with non-untagged deserialization so that we - // can fall through to the untagged variants. This may be infallible so we - // need to provide the error type. - let first_attempt = first_attempt.map(|expr| { - quote! { - if let _serde::#private::Result::<_, __D::Error>::Ok(__ok) = (|| #expr)() { - return _serde::#private::Ok(__ok); - } - } - }); - let private2 = private; quote_block! { let __content = _serde::de::DeserializeSeed::deserialize(_serde::#private::de::ContentVisitor::new(), __deserializer)?; From ddb7c4b30f552c8bfb2fcdda99570632aae4c834 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 14 Jun 2025 19:59:09 +0500 Subject: [PATCH 04/22] Convert `split_with_de_lifetime` to method of `Parameters` --- serde_derive/src/de.rs | 62 +++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 3175525e..29dc7403 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -25,7 +25,7 @@ pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result String { self.this_type.segments.last().unwrap().ident.to_string() } + + /// Split a deserialized type's generics into the pieces required for impl'ing + /// a `Deserialize` trait for that type. Additionally appends the `'de` lifetime + /// to list of impl generics. + fn generics( + &self, + ) -> ( + DeImplGenerics, + DeTypeGenerics, + syn::TypeGenerics, + Option<&syn::WhereClause>, + ) { + let de_impl_generics = DeImplGenerics(self); + let de_ty_generics = DeTypeGenerics(self); + let (_, ty_generics, where_clause) = self.generics.split_for_impl(); + (de_impl_generics, de_ty_generics, ty_generics, where_clause) + } } // All the generics in the input, plus a bound `T: Deserialize` for each generic @@ -418,8 +435,7 @@ fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fra let this_type = ¶ms.this_type; let this_value = ¶ms.this_value; let type_name = cattrs.name().deserialize_name(); - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); let delife = params.borrowed.de_lifetime(); let expecting = format!("unit struct {}", params.type_name()); @@ -488,8 +504,7 @@ fn deserialize_tuple( let this_type = ¶ms.this_type; let this_value = ¶ms.this_value; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); + 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 @@ -610,8 +625,7 @@ fn deserialize_tuple_in_place( .count(); let this_type = ¶ms.this_type; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); let delife = params.borrowed.de_lifetime(); let expecting = format!("tuple struct {}", params.type_name()); @@ -952,8 +966,7 @@ fn deserialize_struct( ) -> Fragment { let this_type = ¶ms.this_type; let this_value = ¶ms.this_value; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); + 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 @@ -1140,8 +1153,7 @@ fn deserialize_struct_in_place( } let this_type = ¶ms.this_type; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); + 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()); @@ -1308,8 +1320,7 @@ fn deserialize_externally_tagged_enum( cattrs: &attr::Container, ) -> Fragment { let this_type = ¶ms.this_type; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); let delife = params.borrowed.de_lifetime(); let type_name = cattrs.name().deserialize_name(); @@ -1454,8 +1465,7 @@ fn deserialize_adjacently_tagged_enum( ) -> Fragment { let this_type = ¶ms.this_type; let this_value = ¶ms.this_value; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); let delife = params.borrowed.de_lifetime(); let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants); @@ -2182,8 +2192,7 @@ fn deserialize_custom_identifier( Some(fields) }; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); let delife = params.borrowed.de_lifetime(); let visitor_impl = Stmts(deserialize_identifier( &this_value, @@ -2861,7 +2870,7 @@ fn deserialize_map_in_place( }); let this_type = ¶ms.this_type; - let (_, _, ty_generics, _) = split_with_de_lifetime(params); + let (_, _, ty_generics, _) = params.generics(); let let_default = match cattrs.default() { attr::Default::Default => Some(quote!( @@ -2906,8 +2915,7 @@ fn wrap_deserialize_with( deserialize_with: &syn::ExprPath, ) -> (TokenStream, TokenStream) { let this_type = ¶ms.this_type; - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = - split_with_de_lifetime(params); + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); let delife = params.borrowed.de_lifetime(); let deserializer_var = quote!(__deserializer); @@ -3227,17 +3235,3 @@ fn place_lifetime() -> syn::LifetimeParam { bounds: Punctuated::new(), } } - -fn split_with_de_lifetime( - params: &Parameters, -) -> ( - DeImplGenerics, - DeTypeGenerics, - syn::TypeGenerics, - Option<&syn::WhereClause>, -) { - let de_impl_generics = DeImplGenerics(params); - let de_ty_generics = DeTypeGenerics(params); - let (_, ty_generics, where_clause) = params.generics.split_for_impl(); - (de_impl_generics, de_ty_generics, ty_generics, where_clause) -} From ca79f61d0fc9e0379259238892f7453f08a1f015 Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 19 Sep 2025 20:26:14 +0500 Subject: [PATCH 05/22] `deserialize_internally_tagged_variant` always called with the same `deserializer`, so remove that parameter --- serde_derive/src/de.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 29dc7403..e0fcfd31 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1425,10 +1425,7 @@ fn deserialize_internally_tagged_enum( let variant_name = field_i(i); let block = Match(deserialize_internally_tagged_variant( - params, - variant, - cattrs, - quote!(__deserializer), + params, variant, cattrs, )); quote! { @@ -1864,12 +1861,11 @@ fn deserialize_internally_tagged_variant( params: &Parameters, variant: &Variant, cattrs: &attr::Container, - deserializer: TokenStream, ) -> Fragment { if let Some(path) = variant.attrs.deserialize_with() { let unwrap_fn = unwrap_to_variant_closure(params, variant, false); return quote_block! { - _serde::#private::Result::map(#path(#deserializer), #unwrap_fn) + _serde::#private::Result::map(#path(__deserializer), #unwrap_fn) }; } @@ -1885,7 +1881,7 @@ fn deserialize_internally_tagged_variant( quote!((#default)) }); quote_block! { - _serde::Deserializer::deserialize_any(#deserializer, _serde::#private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))?; + _serde::Deserializer::deserialize_any(__deserializer, _serde::#private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))?; _serde::#private::Ok(#this_value::#variant_ident #default) } } @@ -1893,13 +1889,13 @@ fn deserialize_internally_tagged_variant( variant_ident, params, &variant.fields[0], - &deserializer, + "e!(__deserializer), ), Style::Struct => deserialize_struct( params, &variant.fields, cattrs, - StructForm::InternallyTagged(variant_ident, deserializer), + StructForm::InternallyTagged(variant_ident, quote!(__deserializer)), ), Style::Tuple => unreachable!("checked in serde_derive_internals"), } From 3a682c951b6b02b238cd4cd1381b24b2b041bfde Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 19 Sep 2025 20:31:13 +0500 Subject: [PATCH 06/22] `deserialize_untagged_variant` always called with the same `deserializer`, so remove that parameter --- serde_derive/src/de.rs | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index e0fcfd31..51b4593f 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1474,12 +1474,7 @@ fn deserialize_adjacently_tagged_enum( .map(|(i, variant)| { let variant_index = field_i(i); - let block = Match(deserialize_untagged_variant( - params, - variant, - cattrs, - quote!(__deserializer), - )); + let block = Match(deserialize_untagged_variant(params, variant, cattrs)); quote! { __Field::#variant_index => #block @@ -1773,14 +1768,7 @@ fn deserialize_untagged_enum( let attempts = variants .iter() .filter(|variant| !variant.attrs.skip_deserializing()) - .map(|variant| { - Expr(deserialize_untagged_variant( - params, - variant, - cattrs, - quote!(__deserializer), - )) - }); + .map(|variant| Expr(deserialize_untagged_variant(params, variant, cattrs))); // TODO this message could be better by saving the errors from the failed // attempts. The heuristic used by TOML was to count the number of fields // processed before an error, and use the error that happened after the @@ -1905,12 +1893,11 @@ fn deserialize_untagged_variant( params: &Parameters, variant: &Variant, cattrs: &attr::Container, - deserializer: TokenStream, ) -> Fragment { if let Some(path) = variant.attrs.deserialize_with() { let unwrap_fn = unwrap_to_variant_closure(params, variant, false); return quote_block! { - _serde::#private::Result::map(#path(#deserializer), #unwrap_fn) + _serde::#private::Result::map(#path(__deserializer), #unwrap_fn) }; } @@ -1927,7 +1914,7 @@ fn deserialize_untagged_variant( }); quote_expr! { match _serde::Deserializer::deserialize_any( - #deserializer, + __deserializer, _serde::#private::de::UntaggedUnitVisitor::new(#type_name, #variant_name) ) { _serde::#private::Ok(()) => _serde::#private::Ok(#this_value::#variant_ident #default), @@ -1939,19 +1926,19 @@ fn deserialize_untagged_variant( variant_ident, params, &variant.fields[0], - &deserializer, + "e!(__deserializer), ), Style::Tuple => deserialize_tuple( params, &variant.fields, cattrs, - TupleForm::Untagged(variant_ident, deserializer), + TupleForm::Untagged(variant_ident, quote!(__deserializer)), ), Style::Struct => deserialize_struct( params, &variant.fields, cattrs, - StructForm::Untagged(variant_ident, deserializer), + StructForm::Untagged(variant_ident, quote!(__deserializer)), ), } } From 915686d0ecb415f5fe3118456bcbfeb90834dd39 Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 19 Sep 2025 20:34:26 +0500 Subject: [PATCH 07/22] `deserialize_untagged_newtype_variant` always called with the same `deserializer`, so remove that parameter --- serde_derive/src/de.rs | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 51b4593f..70982b3e 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -1873,12 +1873,9 @@ fn deserialize_internally_tagged_variant( _serde::#private::Ok(#this_value::#variant_ident #default) } } - Style::Newtype => deserialize_untagged_newtype_variant( - variant_ident, - params, - &variant.fields[0], - "e!(__deserializer), - ), + Style::Newtype => { + deserialize_untagged_newtype_variant(variant_ident, params, &variant.fields[0]) + } Style::Struct => deserialize_struct( params, &variant.fields, @@ -1922,12 +1919,9 @@ fn deserialize_untagged_variant( } } } - Style::Newtype => deserialize_untagged_newtype_variant( - variant_ident, - params, - &variant.fields[0], - "e!(__deserializer), - ), + Style::Newtype => { + deserialize_untagged_newtype_variant(variant_ident, params, &variant.fields[0]) + } Style::Tuple => deserialize_tuple( params, &variant.fields, @@ -1985,7 +1979,6 @@ fn deserialize_untagged_newtype_variant( variant_ident: &syn::Ident, params: &Parameters, field: &Field, - deserializer: &TokenStream, ) -> Fragment { let this_value = ¶ms.this_value; let field_ty = field.ty; @@ -1994,12 +1987,12 @@ fn deserialize_untagged_newtype_variant( let span = field.original.span(); let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); quote_expr! { - _serde::#private::Result::map(#func(#deserializer), #this_value::#variant_ident) + _serde::#private::Result::map(#func(__deserializer), #this_value::#variant_ident) } } Some(path) => { quote_block! { - let __value: _serde::#private::Result<#field_ty, _> = #path(#deserializer); + let __value: _serde::#private::Result<#field_ty, _> = #path(__deserializer); _serde::#private::Result::map(__value, #this_value::#variant_ident) } } From 896d91f0bb4c27cdc5deac7288347ed1b3e1f2ae Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 19 Sep 2025 20:37:03 +0500 Subject: [PATCH 08/22] TupleForm::Untagged always instantiated with the same deserializer, so remove that parameter --- serde_derive/src/de.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 70982b3e..1fb1bb56 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -480,9 +480,8 @@ enum TupleForm<'a> { Tuple, /// Contains a variant name ExternallyTagged(&'a syn::Ident), - /// Contains a variant name and an intermediate deserializer from which actual - /// deserialization will be performed - Untagged(&'a syn::Ident, TokenStream), + /// Contains a variant name + Untagged(&'a syn::Ident), } /// Generates `Deserialize::deserialize` body for a `struct Tuple(...);` including `struct Newtype(T);` @@ -519,13 +518,13 @@ fn deserialize_tuple( let type_path = match form { TupleForm::Tuple => construct, - TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident, _) => { + TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident) => { quote!(#construct::#variant_ident) } }; let expecting = match form { TupleForm::Tuple => format!("tuple struct {}", params.type_name()), - TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident, _) => { + TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident) => { format!("tuple variant {}::{}", params.type_name(), variant_ident) } }; @@ -566,8 +565,8 @@ fn deserialize_tuple( TupleForm::ExternallyTagged(_) => quote! { _serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr) }, - TupleForm::Untagged(_, deserializer) => quote! { - _serde::Deserializer::deserialize_tuple(#deserializer, #field_count, #visitor_expr) + TupleForm::Untagged(_) => quote! { + _serde::Deserializer::deserialize_tuple(__deserializer, #field_count, #visitor_expr) }, }; @@ -1926,7 +1925,7 @@ fn deserialize_untagged_variant( params, &variant.fields, cattrs, - TupleForm::Untagged(variant_ident, quote!(__deserializer)), + TupleForm::Untagged(variant_ident), ), Style::Struct => deserialize_struct( params, From c8184be23822f3db85e40c87320cf56c22692ae5 Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 19 Sep 2025 20:38:46 +0500 Subject: [PATCH 09/22] StructForm::Untagged always instantiated with the same deserializer, so remove that parameter --- serde_derive/src/de.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 1fb1bb56..a07a0d5f 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -951,9 +951,8 @@ enum StructForm<'a> { /// Contains a variant name and an intermediate deserializer from which actual /// deserialization will be performed InternallyTagged(&'a syn::Ident, TokenStream), - /// Contains a variant name and an intermediate deserializer from which actual - /// deserialization will be performed - Untagged(&'a syn::Ident, TokenStream), + /// Contains a variant name + Untagged(&'a syn::Ident), } /// Generates `Deserialize::deserialize` body for a `struct Struct {...}` @@ -982,13 +981,13 @@ fn deserialize_struct( StructForm::Struct => construct, StructForm::ExternallyTagged(variant_ident) | StructForm::InternallyTagged(variant_ident, _) - | StructForm::Untagged(variant_ident, _) => quote!(#construct::#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, _) => { + | StructForm::Untagged(variant_ident) => { format!("struct variant {}::{}", params.type_name(), variant_ident) } }; @@ -1012,7 +1011,7 @@ fn deserialize_struct( // 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, + StructForm::Untagged(_) => None, _ if has_flatten => None, _ => { let mut_seq = if deserialized_fields.is_empty() { @@ -1097,8 +1096,8 @@ fn deserialize_struct( StructForm::InternallyTagged(_, deserializer) => quote! { _serde::Deserializer::deserialize_any(#deserializer, #visitor_expr) }, - StructForm::Untagged(_, deserializer) => quote! { - _serde::Deserializer::deserialize_any(#deserializer, #visitor_expr) + StructForm::Untagged(_) => quote! { + _serde::Deserializer::deserialize_any(__deserializer, #visitor_expr) }, }; @@ -1931,7 +1930,7 @@ fn deserialize_untagged_variant( params, &variant.fields, cattrs, - StructForm::Untagged(variant_ident, quote!(__deserializer)), + StructForm::Untagged(variant_ident), ), } } From e04f0ba2de17ffb544d57dd93636f96298c01135 Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 19 Sep 2025 20:28:22 +0500 Subject: [PATCH 10/22] StructForm::InternallyTagged always instantiated with the same deserializer, so remove that parameter --- serde_derive/src/de.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index a07a0d5f..596b74ee 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -948,9 +948,8 @@ enum StructForm<'a> { Struct, /// Contains a variant name ExternallyTagged(&'a syn::Ident), - /// Contains a variant name and an intermediate deserializer from which actual - /// deserialization will be performed - InternallyTagged(&'a syn::Ident, TokenStream), + /// Contains a variant name + InternallyTagged(&'a syn::Ident), /// Contains a variant name Untagged(&'a syn::Ident), } @@ -980,13 +979,13 @@ fn deserialize_struct( let type_path = match form { StructForm::Struct => construct, StructForm::ExternallyTagged(variant_ident) - | StructForm::InternallyTagged(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::InternallyTagged(variant_ident) | StructForm::Untagged(variant_ident) => { format!("struct variant {}::{}", params.type_name(), variant_ident) } @@ -1093,8 +1092,8 @@ fn deserialize_struct( StructForm::ExternallyTagged(_) => quote! { _serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr) }, - StructForm::InternallyTagged(_, deserializer) => quote! { - _serde::Deserializer::deserialize_any(#deserializer, #visitor_expr) + StructForm::InternallyTagged(_) => quote! { + _serde::Deserializer::deserialize_any(__deserializer, #visitor_expr) }, StructForm::Untagged(_) => quote! { _serde::Deserializer::deserialize_any(__deserializer, #visitor_expr) @@ -1878,7 +1877,7 @@ fn deserialize_internally_tagged_variant( params, &variant.fields, cattrs, - StructForm::InternallyTagged(variant_ident, quote!(__deserializer)), + StructForm::InternallyTagged(variant_ident), ), Style::Tuple => unreachable!("checked in serde_derive_internals"), } From e60f62a289ecb6ae06992b8df92a7b997b6e8ab2 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 14 Jun 2025 16:15:57 +0500 Subject: [PATCH 11/22] Move body generator for adjacently tagged enums to its own module Cut-paste --- serde_derive/src/de.rs | 310 +----------------------- serde_derive/src/de/enum_adjacently.rs | 320 +++++++++++++++++++++++++ 2 files changed, 323 insertions(+), 307 deletions(-) create mode 100644 serde_derive/src/de/enum_adjacently.rs diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 596b74ee..0965e0b1 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -12,6 +12,8 @@ use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{parse_quote, Ident, Index, Member}; +mod enum_adjacently; + pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result { replace_receiver(input); @@ -1262,7 +1264,7 @@ fn deserialize_homogeneous_enum( deserialize_internally_tagged_enum(params, variants, cattrs, tag) } attr::TagType::Adjacent { tag, content } => { - deserialize_adjacently_tagged_enum(params, variants, cattrs, tag, content) + enum_adjacently::deserialize_adjacently_tagged_enum(params, variants, cattrs, tag, content) } attr::TagType::None => deserialize_untagged_enum(params, variants, cattrs, None), } @@ -1449,312 +1451,6 @@ fn deserialize_internally_tagged_enum( } } -/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag, content)]` attributes -fn deserialize_adjacently_tagged_enum( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, - tag: &str, - content: &str, -) -> 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(); - - let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants); - - let variant_arms: &Vec<_> = &variants - .iter() - .enumerate() - .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) - .map(|(i, variant)| { - let variant_index = field_i(i); - - let block = Match(deserialize_untagged_variant(params, variant, cattrs)); - - quote! { - __Field::#variant_index => #block - } - }) - .collect(); - - let rust_name = params.type_name(); - let expecting = format!("adjacently tagged enum {}", rust_name); - let expecting = cattrs.expecting().unwrap_or(&expecting); - let type_name = cattrs.name().deserialize_name(); - let deny_unknown_fields = cattrs.deny_unknown_fields(); - - // If unknown fields are allowed, we pick the visitor that can step over - // those. Otherwise we pick the visitor that fails on unknown keys. - let field_visitor_ty = if deny_unknown_fields { - quote! { _serde::#private::de::TagOrContentFieldVisitor } - } else { - quote! { _serde::#private::de::TagContentOtherFieldVisitor } - }; - - let mut missing_content = quote! { - _serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#content)) - }; - let mut missing_content_fallthrough = quote!(); - let missing_content_arms = variants - .iter() - .enumerate() - .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) - .filter_map(|(i, variant)| { - let variant_index = field_i(i); - let variant_ident = &variant.ident; - - let arm = match variant.style { - Style::Unit => quote! { - _serde::#private::Ok(#this_value::#variant_ident) - }, - Style::Newtype if variant.attrs.deserialize_with().is_none() => { - let span = variant.original.span(); - let func = quote_spanned!(span=> _serde::#private::de::missing_field); - quote! { - #func(#content).map(#this_value::#variant_ident) - } - } - _ => { - missing_content_fallthrough = quote!(_ => #missing_content); - return None; - } - }; - Some(quote! { - __Field::#variant_index => #arm, - }) - }) - .collect::>(); - if !missing_content_arms.is_empty() { - missing_content = quote! { - match __field { - #(#missing_content_arms)* - #missing_content_fallthrough - } - }; - } - - // Advance the map by one key, returning early in case of error. - let next_key = quote! { - _serde::de::MapAccess::next_key_seed(&mut __map, #field_visitor_ty { - tag: #tag, - content: #content, - })? - }; - - let variant_from_map = quote! { - _serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::AdjacentlyTaggedEnumVariantSeed::<__Field> { - enum_name: #rust_name, - variants: VARIANTS, - fields_enum: _serde::#private::PhantomData - })? - }; - - // When allowing unknown fields, we want to transparently step through keys - // we don't care about until we find `tag`, `content`, or run out of keys. - let next_relevant_key = if deny_unknown_fields { - next_key - } else { - quote!({ - let mut __rk : _serde::#private::Option<_serde::#private::de::TagOrContentField> = _serde::#private::None; - while let _serde::#private::Some(__k) = #next_key { - match __k { - _serde::#private::de::TagContentOtherField::Other => { - let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; - continue; - }, - _serde::#private::de::TagContentOtherField::Tag => { - __rk = _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag); - break; - } - _serde::#private::de::TagContentOtherField::Content => { - __rk = _serde::#private::Some(_serde::#private::de::TagOrContentField::Content); - break; - } - } - } - - __rk - }) - }; - - // Step through remaining keys, looking for duplicates of previously-seen - // keys. When unknown fields are denied, any key that isn't a duplicate will - // at this point immediately produce an error. - let visit_remaining_keys = quote! { - match #next_relevant_key { - _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => { - _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag)) - } - _serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => { - _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content)) - } - _serde::#private::None => _serde::#private::Ok(__ret), - } - }; - - let finish_content_then_tag = if variant_arms.is_empty() { - quote! { - match #variant_from_map {} - } - } else { - quote! { - let __seed = __Seed { - variant: #variant_from_map, - marker: _serde::#private::PhantomData, - lifetime: _serde::#private::PhantomData, - }; - let __deserializer = _serde::#private::de::ContentDeserializer::<__A::Error>::new(__content); - let __ret = _serde::de::DeserializeSeed::deserialize(__seed, __deserializer)?; - // Visit remaining keys, looking for duplicates. - #visit_remaining_keys - } - }; - - quote_block! { - #variant_visitor - - #variants_stmt - - #[doc(hidden)] - struct __Seed #de_impl_generics #where_clause { - variant: __Field, - marker: _serde::#private::PhantomData<#this_type #ty_generics>, - lifetime: _serde::#private::PhantomData<&#delife ()>, - } - - #[automatically_derived] - impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Seed #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>, - { - match self.variant { - #(#variant_arms)* - } - } - } - - #[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) - } - - fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result - where - __A: _serde::de::MapAccess<#delife>, - { - // Visit the first relevant key. - match #next_relevant_key { - // First key is the tag. - _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => { - // Parse the tag. - let __field = #variant_from_map; - // Visit the second key. - match #next_relevant_key { - // Second key is a duplicate of the tag. - _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => { - _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag)) - } - // Second key is the content. - _serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => { - let __ret = _serde::de::MapAccess::next_value_seed(&mut __map, - __Seed { - variant: __field, - marker: _serde::#private::PhantomData, - lifetime: _serde::#private::PhantomData, - })?; - // Visit remaining keys, looking for duplicates. - #visit_remaining_keys - } - // There is no second key; might be okay if the we have a unit variant. - _serde::#private::None => #missing_content - } - } - // First key is the content. - _serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => { - // Buffer up the content. - let __content = _serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::ContentVisitor::new())?; - // Visit the second key. - match #next_relevant_key { - // Second key is the tag. - _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => { - #finish_content_then_tag - } - // Second key is a duplicate of the content. - _serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => { - _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content)) - } - // There is no second key. - _serde::#private::None => { - _serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#tag)) - } - } - } - // There is no first key. - _serde::#private::None => { - _serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#tag)) - } - } - } - - fn visit_seq<__A>(self, mut __seq: __A) -> _serde::#private::Result - where - __A: _serde::de::SeqAccess<#delife>, - { - // Visit the first element - the tag. - match _serde::de::SeqAccess::next_element(&mut __seq)? { - _serde::#private::Some(__variant) => { - // Visit the second element - the content. - match _serde::de::SeqAccess::next_element_seed( - &mut __seq, - __Seed { - variant: __variant, - marker: _serde::#private::PhantomData, - lifetime: _serde::#private::PhantomData, - }, - )? { - _serde::#private::Some(__ret) => _serde::#private::Ok(__ret), - // There is no second element. - _serde::#private::None => { - _serde::#private::Err(_serde::de::Error::invalid_length(1, &self)) - } - } - } - // There is no first element. - _serde::#private::None => { - _serde::#private::Err(_serde::de::Error::invalid_length(0, &self)) - } - } - } - } - - #[doc(hidden)] - const FIELDS: &'static [&'static str] = &[#tag, #content]; - _serde::Deserializer::deserialize_struct( - __deserializer, - #type_name, - FIELDS, - __Visitor { - marker: _serde::#private::PhantomData::<#this_type #ty_generics>, - lifetime: _serde::#private::PhantomData, - }, - ) - } -} - /// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(untagged)]` attribute fn deserialize_untagged_enum( params: &Parameters, diff --git a/serde_derive/src/de/enum_adjacently.rs b/serde_derive/src/de/enum_adjacently.rs new file mode 100644 index 00000000..c5e64a23 --- /dev/null +++ b/serde_derive/src/de/enum_adjacently.rs @@ -0,0 +1,320 @@ +//! Generator of the deserialization code for the adjacently tagged enums: +//! +//! ```ignore +//! #[serde(tag = "...", content = "...")] +//! enum Enum {} +//! ``` + +use crate::de::{deserialize_untagged_variant, field_i, prepare_enum_variant_enum, Parameters}; +use crate::fragment::{Fragment, Match}; +use crate::internals::ast::{Style, Variant}; +use crate::internals::attr; +use crate::private; +use quote::{quote, quote_spanned}; +use syn::spanned::Spanned; + +/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag, content)]` attributes +pub fn deserialize_adjacently_tagged_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, + tag: &str, + content: &str, +) -> 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(); + + let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants); + + let variant_arms: &Vec<_> = &variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .map(|(i, variant)| { + let variant_index = field_i(i); + + let block = Match(deserialize_untagged_variant(params, variant, cattrs)); + + quote! { + __Field::#variant_index => #block + } + }) + .collect(); + + let rust_name = params.type_name(); + let expecting = format!("adjacently tagged enum {}", rust_name); + let expecting = cattrs.expecting().unwrap_or(&expecting); + let type_name = cattrs.name().deserialize_name(); + let deny_unknown_fields = cattrs.deny_unknown_fields(); + + // If unknown fields are allowed, we pick the visitor that can step over + // those. Otherwise we pick the visitor that fails on unknown keys. + let field_visitor_ty = if deny_unknown_fields { + quote! { _serde::#private::de::TagOrContentFieldVisitor } + } else { + quote! { _serde::#private::de::TagContentOtherFieldVisitor } + }; + + let mut missing_content = quote! { + _serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#content)) + }; + let mut missing_content_fallthrough = quote!(); + let missing_content_arms = variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .filter_map(|(i, variant)| { + let variant_index = field_i(i); + let variant_ident = &variant.ident; + + let arm = match variant.style { + Style::Unit => quote! { + _serde::#private::Ok(#this_value::#variant_ident) + }, + Style::Newtype if variant.attrs.deserialize_with().is_none() => { + let span = variant.original.span(); + let func = quote_spanned!(span=> _serde::#private::de::missing_field); + quote! { + #func(#content).map(#this_value::#variant_ident) + } + } + _ => { + missing_content_fallthrough = quote!(_ => #missing_content); + return None; + } + }; + Some(quote! { + __Field::#variant_index => #arm, + }) + }) + .collect::>(); + if !missing_content_arms.is_empty() { + missing_content = quote! { + match __field { + #(#missing_content_arms)* + #missing_content_fallthrough + } + }; + } + + // Advance the map by one key, returning early in case of error. + let next_key = quote! { + _serde::de::MapAccess::next_key_seed(&mut __map, #field_visitor_ty { + tag: #tag, + content: #content, + })? + }; + + let variant_from_map = quote! { + _serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::AdjacentlyTaggedEnumVariantSeed::<__Field> { + enum_name: #rust_name, + variants: VARIANTS, + fields_enum: _serde::#private::PhantomData + })? + }; + + // When allowing unknown fields, we want to transparently step through keys + // we don't care about until we find `tag`, `content`, or run out of keys. + let next_relevant_key = if deny_unknown_fields { + next_key + } else { + quote!({ + let mut __rk : _serde::#private::Option<_serde::#private::de::TagOrContentField> = _serde::#private::None; + while let _serde::#private::Some(__k) = #next_key { + match __k { + _serde::#private::de::TagContentOtherField::Other => { + let _ = _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?; + continue; + }, + _serde::#private::de::TagContentOtherField::Tag => { + __rk = _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag); + break; + } + _serde::#private::de::TagContentOtherField::Content => { + __rk = _serde::#private::Some(_serde::#private::de::TagOrContentField::Content); + break; + } + } + } + + __rk + }) + }; + + // Step through remaining keys, looking for duplicates of previously-seen + // keys. When unknown fields are denied, any key that isn't a duplicate will + // at this point immediately produce an error. + let visit_remaining_keys = quote! { + match #next_relevant_key { + _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => { + _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag)) + } + _serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => { + _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content)) + } + _serde::#private::None => _serde::#private::Ok(__ret), + } + }; + + let finish_content_then_tag = if variant_arms.is_empty() { + quote! { + match #variant_from_map {} + } + } else { + quote! { + let __seed = __Seed { + variant: #variant_from_map, + marker: _serde::#private::PhantomData, + lifetime: _serde::#private::PhantomData, + }; + let __deserializer = _serde::#private::de::ContentDeserializer::<__A::Error>::new(__content); + let __ret = _serde::de::DeserializeSeed::deserialize(__seed, __deserializer)?; + // Visit remaining keys, looking for duplicates. + #visit_remaining_keys + } + }; + + quote_block! { + #variant_visitor + + #variants_stmt + + #[doc(hidden)] + struct __Seed #de_impl_generics #where_clause { + variant: __Field, + marker: _serde::#private::PhantomData<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData<&#delife ()>, + } + + #[automatically_derived] + impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Seed #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>, + { + match self.variant { + #(#variant_arms)* + } + } + } + + #[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) + } + + fn visit_map<__A>(self, mut __map: __A) -> _serde::#private::Result + where + __A: _serde::de::MapAccess<#delife>, + { + // Visit the first relevant key. + match #next_relevant_key { + // First key is the tag. + _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => { + // Parse the tag. + let __field = #variant_from_map; + // Visit the second key. + match #next_relevant_key { + // Second key is a duplicate of the tag. + _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => { + _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#tag)) + } + // Second key is the content. + _serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => { + let __ret = _serde::de::MapAccess::next_value_seed(&mut __map, + __Seed { + variant: __field, + marker: _serde::#private::PhantomData, + lifetime: _serde::#private::PhantomData, + })?; + // Visit remaining keys, looking for duplicates. + #visit_remaining_keys + } + // There is no second key; might be okay if the we have a unit variant. + _serde::#private::None => #missing_content + } + } + // First key is the content. + _serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => { + // Buffer up the content. + let __content = _serde::de::MapAccess::next_value_seed(&mut __map, _serde::#private::de::ContentVisitor::new())?; + // Visit the second key. + match #next_relevant_key { + // Second key is the tag. + _serde::#private::Some(_serde::#private::de::TagOrContentField::Tag) => { + #finish_content_then_tag + } + // Second key is a duplicate of the content. + _serde::#private::Some(_serde::#private::de::TagOrContentField::Content) => { + _serde::#private::Err(<__A::Error as _serde::de::Error>::duplicate_field(#content)) + } + // There is no second key. + _serde::#private::None => { + _serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#tag)) + } + } + } + // There is no first key. + _serde::#private::None => { + _serde::#private::Err(<__A::Error as _serde::de::Error>::missing_field(#tag)) + } + } + } + + fn visit_seq<__A>(self, mut __seq: __A) -> _serde::#private::Result + where + __A: _serde::de::SeqAccess<#delife>, + { + // Visit the first element - the tag. + match _serde::de::SeqAccess::next_element(&mut __seq)? { + _serde::#private::Some(__variant) => { + // Visit the second element - the content. + match _serde::de::SeqAccess::next_element_seed( + &mut __seq, + __Seed { + variant: __variant, + marker: _serde::#private::PhantomData, + lifetime: _serde::#private::PhantomData, + }, + )? { + _serde::#private::Some(__ret) => _serde::#private::Ok(__ret), + // There is no second element. + _serde::#private::None => { + _serde::#private::Err(_serde::de::Error::invalid_length(1, &self)) + } + } + } + // There is no first element. + _serde::#private::None => { + _serde::#private::Err(_serde::de::Error::invalid_length(0, &self)) + } + } + } + } + + #[doc(hidden)] + const FIELDS: &'static [&'static str] = &[#tag, #content]; + _serde::Deserializer::deserialize_struct( + __deserializer, + #type_name, + FIELDS, + __Visitor { + marker: _serde::#private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData, + }, + ) + } +} From 85d0b9ccd84ce03e69df45d25f47d4a88c86a264 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 14 Jun 2025 16:20:49 +0500 Subject: [PATCH 12/22] Move body generator for externally tagged enums to its own module Cut-paste --- serde_derive/src/de.rs | 194 +---------------------- serde_derive/src/de/enum_externally.rs | 209 +++++++++++++++++++++++++ 2 files changed, 211 insertions(+), 192 deletions(-) create mode 100644 serde_derive/src/de/enum_externally.rs diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 0965e0b1..b5c66a47 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -13,6 +13,7 @@ use syn::spanned::Spanned; use syn::{parse_quote, Ident, Index, Member}; mod enum_adjacently; +mod enum_externally; pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result { replace_receiver(input); @@ -1259,7 +1260,7 @@ fn deserialize_homogeneous_enum( cattrs: &attr::Container, ) -> Fragment { match cattrs.tag() { - attr::TagType::External => deserialize_externally_tagged_enum(params, variants, cattrs), + attr::TagType::External => enum_externally::deserialize_externally_tagged_enum(params, variants, cattrs), attr::TagType::Internal { tag } => { deserialize_internally_tagged_enum(params, variants, cattrs, tag) } @@ -1312,100 +1313,6 @@ fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) { (variants_stmt, variant_visitor) } -/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` without additional attributes -fn deserialize_externally_tagged_enum( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, -) -> Fragment { - 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 type_name = cattrs.name().deserialize_name(); - let expecting = format!("enum {}", params.type_name()); - let expecting = cattrs.expecting().unwrap_or(&expecting); - - let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants); - - // Match arms to extract a variant from a string - let variant_arms = variants - .iter() - .enumerate() - .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) - .map(|(i, variant)| { - let variant_name = field_i(i); - - let block = Match(deserialize_externally_tagged_variant( - params, variant, cattrs, - )); - - quote! { - (__Field::#variant_name, __variant) => #block - } - }); - - let all_skipped = variants - .iter() - .all(|variant| variant.attrs.skip_deserializing()); - let match_variant = if all_skipped { - // This is an empty enum like `enum Impossible {}` or an enum in which - // all variants have `#[serde(skip_deserializing)]`. - quote! { - // FIXME: Once feature(exhaustive_patterns) is stable: - // let _serde::#private::Err(__err) = _serde::de::EnumAccess::variant::<__Field>(__data); - // _serde::#private::Err(__err) - _serde::#private::Result::map( - _serde::de::EnumAccess::variant::<__Field>(__data), - |(__impossible, _)| match __impossible {}) - } - } else { - quote! { - match _serde::de::EnumAccess::variant(__data)? { - #(#variant_arms)* - } - } - }; - - quote_block! { - #variant_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) - } - - fn visit_enum<__A>(self, __data: __A) -> _serde::#private::Result - where - __A: _serde::de::EnumAccess<#delife>, - { - #match_variant - } - } - - #variants_stmt - - _serde::Deserializer::deserialize_enum( - __deserializer, - #type_name, - VARIANTS, - __Visitor { - marker: _serde::#private::PhantomData::<#this_type #ty_generics>, - lifetime: _serde::#private::PhantomData, - }, - ) - } -} - /// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag)]` attribute fn deserialize_internally_tagged_enum( params: &Parameters, @@ -1491,51 +1398,6 @@ fn deserialize_untagged_enum( } } -fn deserialize_externally_tagged_variant( - params: &Parameters, - variant: &Variant, - cattrs: &attr::Container, -) -> Fragment { - if let Some(path) = variant.attrs.deserialize_with() { - let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path); - return quote_block! { - #wrapper - _serde::#private::Result::map( - _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn) - }; - } - - let variant_ident = &variant.ident; - - match variant.style { - Style::Unit => { - let this_value = ¶ms.this_value; - quote_block! { - _serde::de::VariantAccess::unit_variant(__variant)?; - _serde::#private::Ok(#this_value::#variant_ident) - } - } - Style::Newtype => deserialize_externally_tagged_newtype_variant( - variant_ident, - params, - &variant.fields[0], - cattrs, - ), - Style::Tuple => deserialize_tuple( - params, - &variant.fields, - cattrs, - TupleForm::ExternallyTagged(variant_ident), - ), - Style::Struct => deserialize_struct( - params, - &variant.fields, - cattrs, - StructForm::ExternallyTagged(variant_ident), - ), - } -} - // Generates significant part of the visit_seq and visit_map bodies of visitors // for the variants of internally tagged enum. fn deserialize_internally_tagged_variant( @@ -1630,44 +1492,6 @@ fn deserialize_untagged_variant( } } -fn deserialize_externally_tagged_newtype_variant( - variant_ident: &syn::Ident, - params: &Parameters, - field: &Field, - cattrs: &attr::Container, -) -> Fragment { - let this_value = ¶ms.this_value; - - if field.attrs.skip_deserializing() { - let default = Expr(expr_is_missing(field, cattrs)); - return quote_block! { - _serde::de::VariantAccess::unit_variant(__variant)?; - _serde::#private::Ok(#this_value::#variant_ident(#default)) - }; - } - - match field.attrs.deserialize_with() { - None => { - let field_ty = field.ty; - let span = field.original.span(); - let func = - quote_spanned!(span=> _serde::de::VariantAccess::newtype_variant::<#field_ty>); - quote_expr! { - _serde::#private::Result::map(#func(__variant), #this_value::#variant_ident) - } - } - Some(path) => { - let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); - quote_block! { - #wrapper - _serde::#private::Result::map( - _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), - |__wrapper| #this_value::#variant_ident(__wrapper.value)) - } - } - } -} - fn deserialize_untagged_newtype_variant( variant_ident: &syn::Ident, params: &Parameters, @@ -2631,20 +2455,6 @@ fn wrap_deserialize_field_with( wrap_deserialize_with(params, "e!(#field_ty), deserialize_with) } -fn wrap_deserialize_variant_with( - params: &Parameters, - variant: &Variant, - deserialize_with: &syn::ExprPath, -) -> (TokenStream, TokenStream, TokenStream) { - let field_tys = variant.fields.iter().map(|field| field.ty); - let (wrapper, wrapper_ty) = - wrap_deserialize_with(params, "e!((#(#field_tys),*)), deserialize_with); - - let unwrap_fn = unwrap_to_variant_closure(params, variant, true); - - (wrapper, wrapper_ty, unwrap_fn) -} - // Generates closure that converts single input parameter to the final value. fn unwrap_to_variant_closure( params: &Parameters, diff --git a/serde_derive/src/de/enum_externally.rs b/serde_derive/src/de/enum_externally.rs new file mode 100644 index 00000000..ea548f0e --- /dev/null +++ b/serde_derive/src/de/enum_externally.rs @@ -0,0 +1,209 @@ +//! Generator of the deserialization code for the externally tagged enums: +//! +//! ```ignore +//! enum Enum {} +//! ``` + +use crate::de::{ + deserialize_struct, deserialize_tuple, expr_is_missing, field_i, prepare_enum_variant_enum, + unwrap_to_variant_closure, wrap_deserialize_field_with, wrap_deserialize_with, Parameters, + StructForm, TupleForm, +}; +use crate::fragment::{Expr, Fragment, Match}; +use crate::internals::ast::{Field, Style, Variant}; +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 an `enum Enum {...}` without additional attributes +pub fn deserialize_externally_tagged_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + 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 type_name = cattrs.name().deserialize_name(); + let expecting = format!("enum {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants); + + // Match arms to extract a variant from a string + let variant_arms = variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .map(|(i, variant)| { + let variant_name = field_i(i); + + let block = Match(deserialize_externally_tagged_variant( + params, variant, cattrs, + )); + + quote! { + (__Field::#variant_name, __variant) => #block + } + }); + + let all_skipped = variants + .iter() + .all(|variant| variant.attrs.skip_deserializing()); + let match_variant = if all_skipped { + // This is an empty enum like `enum Impossible {}` or an enum in which + // all variants have `#[serde(skip_deserializing)]`. + quote! { + // FIXME: Once feature(exhaustive_patterns) is stable: + // let _serde::#private::Err(__err) = _serde::de::EnumAccess::variant::<__Field>(__data); + // _serde::#private::Err(__err) + _serde::#private::Result::map( + _serde::de::EnumAccess::variant::<__Field>(__data), + |(__impossible, _)| match __impossible {}) + } + } else { + quote! { + match _serde::de::EnumAccess::variant(__data)? { + #(#variant_arms)* + } + } + }; + + quote_block! { + #variant_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) + } + + fn visit_enum<__A>(self, __data: __A) -> _serde::#private::Result + where + __A: _serde::de::EnumAccess<#delife>, + { + #match_variant + } + } + + #variants_stmt + + _serde::Deserializer::deserialize_enum( + __deserializer, + #type_name, + VARIANTS, + __Visitor { + marker: _serde::#private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData, + }, + ) + } +} + +fn deserialize_externally_tagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, +) -> Fragment { + if let Some(path) = variant.attrs.deserialize_with() { + let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path); + return quote_block! { + #wrapper + _serde::#private::Result::map( + _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn) + }; + } + + let variant_ident = &variant.ident; + + match variant.style { + Style::Unit => { + let this_value = ¶ms.this_value; + quote_block! { + _serde::de::VariantAccess::unit_variant(__variant)?; + _serde::#private::Ok(#this_value::#variant_ident) + } + } + Style::Newtype => deserialize_externally_tagged_newtype_variant( + variant_ident, + params, + &variant.fields[0], + cattrs, + ), + Style::Tuple => deserialize_tuple( + params, + &variant.fields, + cattrs, + TupleForm::ExternallyTagged(variant_ident), + ), + Style::Struct => deserialize_struct( + params, + &variant.fields, + cattrs, + StructForm::ExternallyTagged(variant_ident), + ), + } +} + +fn deserialize_externally_tagged_newtype_variant( + variant_ident: &syn::Ident, + params: &Parameters, + field: &Field, + cattrs: &attr::Container, +) -> Fragment { + let this_value = ¶ms.this_value; + + if field.attrs.skip_deserializing() { + let default = Expr(expr_is_missing(field, cattrs)); + return quote_block! { + _serde::de::VariantAccess::unit_variant(__variant)?; + _serde::#private::Ok(#this_value::#variant_ident(#default)) + }; + } + + match field.attrs.deserialize_with() { + None => { + let field_ty = field.ty; + let span = field.original.span(); + let func = + quote_spanned!(span=> _serde::de::VariantAccess::newtype_variant::<#field_ty>); + quote_expr! { + _serde::#private::Result::map(#func(__variant), #this_value::#variant_ident) + } + } + Some(path) => { + let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); + quote_block! { + #wrapper + _serde::#private::Result::map( + _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), + |__wrapper| #this_value::#variant_ident(__wrapper.value)) + } + } + } +} + +fn wrap_deserialize_variant_with( + params: &Parameters, + variant: &Variant, + deserialize_with: &syn::ExprPath, +) -> (TokenStream, TokenStream, TokenStream) { + let field_tys = variant.fields.iter().map(|field| field.ty); + let (wrapper, wrapper_ty) = + wrap_deserialize_with(params, "e!((#(#field_tys),*)), deserialize_with); + + let unwrap_fn = unwrap_to_variant_closure(params, variant, true); + + (wrapper, wrapper_ty, unwrap_fn) +} From ae00c4acb735c8cddf6781ba2bfba2d709fc178c Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 14 Jun 2025 16:30:43 +0500 Subject: [PATCH 13/22] Move body generator for internally tagged enums to its own module Cut-paste --- serde_derive/src/de.rs | 91 +--------------------- serde_derive/src/de/enum_internally.rs | 104 +++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 89 deletions(-) create mode 100644 serde_derive/src/de/enum_internally.rs diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index b5c66a47..4632c5ed 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -14,6 +14,7 @@ use syn::{parse_quote, Ident, Index, Member}; mod enum_adjacently; mod enum_externally; +mod enum_internally; pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result { replace_receiver(input); @@ -1262,7 +1263,7 @@ fn deserialize_homogeneous_enum( match cattrs.tag() { attr::TagType::External => enum_externally::deserialize_externally_tagged_enum(params, variants, cattrs), attr::TagType::Internal { tag } => { - deserialize_internally_tagged_enum(params, variants, cattrs, tag) + enum_internally::deserialize_internally_tagged_enum(params, variants, cattrs, tag) } attr::TagType::Adjacent { tag, content } => { enum_adjacently::deserialize_adjacently_tagged_enum(params, variants, cattrs, tag, content) @@ -1313,51 +1314,6 @@ fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) { (variants_stmt, variant_visitor) } -/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag)]` attribute -fn deserialize_internally_tagged_enum( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, - tag: &str, -) -> Fragment { - let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants); - - // Match arms to extract a variant from a string - let variant_arms = variants - .iter() - .enumerate() - .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) - .map(|(i, variant)| { - let variant_name = field_i(i); - - let block = Match(deserialize_internally_tagged_variant( - params, variant, cattrs, - )); - - quote! { - __Field::#variant_name => #block - } - }); - - let expecting = format!("internally tagged enum {}", params.type_name()); - let expecting = cattrs.expecting().unwrap_or(&expecting); - - quote_block! { - #variant_visitor - - #variants_stmt - - let (__tag, __content) = _serde::Deserializer::deserialize_any( - __deserializer, - _serde::#private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting))?; - let __deserializer = _serde::#private::de::ContentDeserializer::<__D::Error>::new(__content); - - match __tag { - #(#variant_arms)* - } - } -} - /// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(untagged)]` attribute fn deserialize_untagged_enum( params: &Parameters, @@ -1398,49 +1354,6 @@ fn deserialize_untagged_enum( } } -// Generates significant part of the visit_seq and visit_map bodies of visitors -// for the variants of internally tagged enum. -fn deserialize_internally_tagged_variant( - params: &Parameters, - variant: &Variant, - cattrs: &attr::Container, -) -> Fragment { - if let Some(path) = variant.attrs.deserialize_with() { - let unwrap_fn = unwrap_to_variant_closure(params, variant, false); - return quote_block! { - _serde::#private::Result::map(#path(__deserializer), #unwrap_fn) - }; - } - - let variant_ident = &variant.ident; - - match effective_style(variant) { - Style::Unit => { - let this_value = ¶ms.this_value; - let type_name = params.type_name(); - let variant_name = variant.ident.to_string(); - let default = variant.fields.first().map(|field| { - let default = Expr(expr_is_missing(field, cattrs)); - quote!((#default)) - }); - quote_block! { - _serde::Deserializer::deserialize_any(__deserializer, _serde::#private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))?; - _serde::#private::Ok(#this_value::#variant_ident #default) - } - } - Style::Newtype => { - deserialize_untagged_newtype_variant(variant_ident, params, &variant.fields[0]) - } - Style::Struct => deserialize_struct( - params, - &variant.fields, - cattrs, - StructForm::InternallyTagged(variant_ident), - ), - Style::Tuple => unreachable!("checked in serde_derive_internals"), - } -} - fn deserialize_untagged_variant( params: &Parameters, variant: &Variant, diff --git a/serde_derive/src/de/enum_internally.rs b/serde_derive/src/de/enum_internally.rs new file mode 100644 index 00000000..8c848e22 --- /dev/null +++ b/serde_derive/src/de/enum_internally.rs @@ -0,0 +1,104 @@ +//! Generator of the deserialization code for the internally tagged enums: +//! +//! ```ignore +//! #[serde(tag = "...")] +//! enum Enum {} +//! ``` + +use crate::de::{ + deserialize_struct, deserialize_untagged_newtype_variant, effective_style, expr_is_missing, + field_i, prepare_enum_variant_enum, unwrap_to_variant_closure, Parameters, StructForm, +}; +use crate::fragment::{Expr, Fragment, Match}; +use crate::internals::ast::{Style, Variant}; +use crate::internals::attr; +use crate::private; +use quote::quote; + +/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag)]` attribute +pub fn deserialize_internally_tagged_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, + tag: &str, +) -> Fragment { + let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants); + + // Match arms to extract a variant from a string + let variant_arms = variants + .iter() + .enumerate() + .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) + .map(|(i, variant)| { + let variant_name = field_i(i); + + let block = Match(deserialize_internally_tagged_variant( + params, variant, cattrs, + )); + + quote! { + __Field::#variant_name => #block + } + }); + + let expecting = format!("internally tagged enum {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + quote_block! { + #variant_visitor + + #variants_stmt + + let (__tag, __content) = _serde::Deserializer::deserialize_any( + __deserializer, + _serde::#private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting))?; + let __deserializer = _serde::#private::de::ContentDeserializer::<__D::Error>::new(__content); + + match __tag { + #(#variant_arms)* + } + } +} + +// Generates significant part of the visit_seq and visit_map bodies of visitors +// for the variants of internally tagged enum. +fn deserialize_internally_tagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, +) -> Fragment { + if let Some(path) = variant.attrs.deserialize_with() { + let unwrap_fn = unwrap_to_variant_closure(params, variant, false); + return quote_block! { + _serde::#private::Result::map(#path(__deserializer), #unwrap_fn) + }; + } + + let variant_ident = &variant.ident; + + match effective_style(variant) { + Style::Unit => { + let this_value = ¶ms.this_value; + let type_name = params.type_name(); + let variant_name = variant.ident.to_string(); + let default = variant.fields.first().map(|field| { + let default = Expr(expr_is_missing(field, cattrs)); + quote!((#default)) + }); + quote_block! { + _serde::Deserializer::deserialize_any(__deserializer, _serde::#private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))?; + _serde::#private::Ok(#this_value::#variant_ident #default) + } + } + Style::Newtype => { + deserialize_untagged_newtype_variant(variant_ident, params, &variant.fields[0]) + } + Style::Struct => deserialize_struct( + params, + &variant.fields, + cattrs, + StructForm::InternallyTagged(variant_ident), + ), + Style::Tuple => unreachable!("checked in serde_derive_internals"), + } +} From ec13eb4ed60f0d39a4aea9113c3a4f43d258f028 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 14 Jun 2025 16:57:34 +0500 Subject: [PATCH 14/22] Move body generator for untagged enums to its own module Cut-paste --- serde_derive/src/de.rs | 120 +--------------------- serde_derive/src/de/enum_adjacently.rs | 5 +- serde_derive/src/de/enum_internally.rs | 7 +- serde_derive/src/de/enum_untagged.rs | 133 +++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 122 deletions(-) create mode 100644 serde_derive/src/de/enum_untagged.rs diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 4632c5ed..b8f665ca 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -15,6 +15,7 @@ use syn::{parse_quote, Ident, Index, Member}; mod enum_adjacently; mod enum_externally; mod enum_internally; +mod enum_untagged; pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result { replace_receiver(input); @@ -1249,7 +1250,7 @@ fn deserialize_enum( return _serde::#private::Ok(__ok); } }; - deserialize_untagged_enum(params, untagged, cattrs, Some(tagged_frag)) + enum_untagged::deserialize_untagged_enum(params, untagged, cattrs, Some(tagged_frag)) } None => deserialize_homogeneous_enum(params, variants, cattrs), } @@ -1268,7 +1269,7 @@ fn deserialize_homogeneous_enum( attr::TagType::Adjacent { tag, content } => { enum_adjacently::deserialize_adjacently_tagged_enum(params, variants, cattrs, tag, content) } - attr::TagType::None => deserialize_untagged_enum(params, variants, cattrs, None), + attr::TagType::None => enum_untagged::deserialize_untagged_enum(params, variants, cattrs, None), } } @@ -1314,121 +1315,6 @@ fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) { (variants_stmt, variant_visitor) } -/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(untagged)]` attribute -fn deserialize_untagged_enum( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, - first_attempt: Option, -) -> Fragment { - let attempts = variants - .iter() - .filter(|variant| !variant.attrs.skip_deserializing()) - .map(|variant| Expr(deserialize_untagged_variant(params, variant, cattrs))); - // TODO this message could be better by saving the errors from the failed - // attempts. The heuristic used by TOML was to count the number of fields - // processed before an error, and use the error that happened after the - // largest number of fields. I'm not sure I like that. Maybe it would be - // better to save all the errors and combine them into one message that - // explains why none of the variants matched. - let fallthrough_msg = format!( - "data did not match any variant of untagged enum {}", - params.type_name() - ); - let fallthrough_msg = cattrs.expecting().unwrap_or(&fallthrough_msg); - - let private2 = private; - quote_block! { - let __content = _serde::de::DeserializeSeed::deserialize(_serde::#private::de::ContentVisitor::new(), __deserializer)?; - let __deserializer = _serde::#private::de::ContentRefDeserializer::<__D::Error>::new(&__content); - - #first_attempt - - #( - if let _serde::#private2::Ok(__ok) = #attempts { - return _serde::#private2::Ok(__ok); - } - )* - - _serde::#private::Err(_serde::de::Error::custom(#fallthrough_msg)) - } -} - -fn deserialize_untagged_variant( - params: &Parameters, - variant: &Variant, - cattrs: &attr::Container, -) -> Fragment { - if let Some(path) = variant.attrs.deserialize_with() { - let unwrap_fn = unwrap_to_variant_closure(params, variant, false); - return quote_block! { - _serde::#private::Result::map(#path(__deserializer), #unwrap_fn) - }; - } - - let variant_ident = &variant.ident; - - match effective_style(variant) { - Style::Unit => { - let this_value = ¶ms.this_value; - let type_name = params.type_name(); - let variant_name = variant.ident.to_string(); - let default = variant.fields.first().map(|field| { - let default = Expr(expr_is_missing(field, cattrs)); - quote!((#default)) - }); - quote_expr! { - match _serde::Deserializer::deserialize_any( - __deserializer, - _serde::#private::de::UntaggedUnitVisitor::new(#type_name, #variant_name) - ) { - _serde::#private::Ok(()) => _serde::#private::Ok(#this_value::#variant_ident #default), - _serde::#private::Err(__err) => _serde::#private::Err(__err), - } - } - } - Style::Newtype => { - deserialize_untagged_newtype_variant(variant_ident, params, &variant.fields[0]) - } - Style::Tuple => deserialize_tuple( - params, - &variant.fields, - cattrs, - TupleForm::Untagged(variant_ident), - ), - Style::Struct => deserialize_struct( - params, - &variant.fields, - cattrs, - StructForm::Untagged(variant_ident), - ), - } -} - -fn deserialize_untagged_newtype_variant( - variant_ident: &syn::Ident, - params: &Parameters, - field: &Field, -) -> Fragment { - let this_value = ¶ms.this_value; - let field_ty = field.ty; - match field.attrs.deserialize_with() { - None => { - let span = field.original.span(); - let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); - quote_expr! { - _serde::#private::Result::map(#func(__deserializer), #this_value::#variant_ident) - } - } - Some(path) => { - quote_block! { - let __value: _serde::#private::Result<#field_ty, _> = #path(__deserializer); - _serde::#private::Result::map(__value, #this_value::#variant_ident) - } - } - } -} - struct FieldWithAliases<'a> { ident: Ident, aliases: &'a BTreeSet, diff --git a/serde_derive/src/de/enum_adjacently.rs b/serde_derive/src/de/enum_adjacently.rs index c5e64a23..ac013e37 100644 --- a/serde_derive/src/de/enum_adjacently.rs +++ b/serde_derive/src/de/enum_adjacently.rs @@ -5,7 +5,8 @@ //! enum Enum {} //! ``` -use crate::de::{deserialize_untagged_variant, field_i, prepare_enum_variant_enum, Parameters}; +use crate::de::enum_untagged; +use crate::de::{field_i, prepare_enum_variant_enum, Parameters}; use crate::fragment::{Fragment, Match}; use crate::internals::ast::{Style, Variant}; use crate::internals::attr; @@ -35,7 +36,7 @@ pub fn deserialize_adjacently_tagged_enum( .map(|(i, variant)| { let variant_index = field_i(i); - let block = Match(deserialize_untagged_variant(params, variant, cattrs)); + let block = Match(enum_untagged::deserialize_untagged_variant(params, variant, cattrs)); quote! { __Field::#variant_index => #block diff --git a/serde_derive/src/de/enum_internally.rs b/serde_derive/src/de/enum_internally.rs index 8c848e22..4dbb6cfa 100644 --- a/serde_derive/src/de/enum_internally.rs +++ b/serde_derive/src/de/enum_internally.rs @@ -5,9 +5,10 @@ //! enum Enum {} //! ``` +use crate::de::enum_untagged; use crate::de::{ - deserialize_struct, deserialize_untagged_newtype_variant, effective_style, expr_is_missing, - field_i, prepare_enum_variant_enum, unwrap_to_variant_closure, Parameters, StructForm, + deserialize_struct, effective_style, expr_is_missing, field_i, prepare_enum_variant_enum, + unwrap_to_variant_closure, Parameters, StructForm, }; use crate::fragment::{Expr, Fragment, Match}; use crate::internals::ast::{Style, Variant}; @@ -91,7 +92,7 @@ fn deserialize_internally_tagged_variant( } } Style::Newtype => { - deserialize_untagged_newtype_variant(variant_ident, params, &variant.fields[0]) + enum_untagged::deserialize_untagged_newtype_variant(variant_ident, params, &variant.fields[0]) } Style::Struct => deserialize_struct( params, diff --git a/serde_derive/src/de/enum_untagged.rs b/serde_derive/src/de/enum_untagged.rs new file mode 100644 index 00000000..78546870 --- /dev/null +++ b/serde_derive/src/de/enum_untagged.rs @@ -0,0 +1,133 @@ +//! Generator of the deserialization code for the untagged enums: +//! +//! ```ignore +//! #[serde(untagged)] +//! enum Enum {} +//! ``` + +use crate::de::{ + deserialize_struct, deserialize_tuple, effective_style, expr_is_missing, + unwrap_to_variant_closure, Parameters, StructForm, TupleForm, +}; +use crate::fragment::{Expr, Fragment}; +use crate::internals::ast::{Field, Style, Variant}; +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 an `enum Enum {...}` with `#[serde(untagged)]` attribute +pub fn deserialize_untagged_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, + first_attempt: Option, +) -> Fragment { + let attempts = variants + .iter() + .filter(|variant| !variant.attrs.skip_deserializing()) + .map(|variant| Expr(deserialize_untagged_variant(params, variant, cattrs))); + // TODO this message could be better by saving the errors from the failed + // attempts. The heuristic used by TOML was to count the number of fields + // processed before an error, and use the error that happened after the + // largest number of fields. I'm not sure I like that. Maybe it would be + // better to save all the errors and combine them into one message that + // explains why none of the variants matched. + let fallthrough_msg = format!( + "data did not match any variant of untagged enum {}", + params.type_name() + ); + let fallthrough_msg = cattrs.expecting().unwrap_or(&fallthrough_msg); + + let private2 = private; + quote_block! { + let __content = _serde::de::DeserializeSeed::deserialize(_serde::#private::de::ContentVisitor::new(), __deserializer)?; + let __deserializer = _serde::#private::de::ContentRefDeserializer::<__D::Error>::new(&__content); + + #first_attempt + + #( + if let _serde::#private2::Ok(__ok) = #attempts { + return _serde::#private2::Ok(__ok); + } + )* + + _serde::#private::Err(_serde::de::Error::custom(#fallthrough_msg)) + } +} + +pub fn deserialize_untagged_variant( + params: &Parameters, + variant: &Variant, + cattrs: &attr::Container, +) -> Fragment { + if let Some(path) = variant.attrs.deserialize_with() { + let unwrap_fn = unwrap_to_variant_closure(params, variant, false); + return quote_block! { + _serde::#private::Result::map(#path(__deserializer), #unwrap_fn) + }; + } + + let variant_ident = &variant.ident; + + match effective_style(variant) { + Style::Unit => { + let this_value = ¶ms.this_value; + let type_name = params.type_name(); + let variant_name = variant.ident.to_string(); + let default = variant.fields.first().map(|field| { + let default = Expr(expr_is_missing(field, cattrs)); + quote!((#default)) + }); + quote_expr! { + match _serde::Deserializer::deserialize_any( + __deserializer, + _serde::#private::de::UntaggedUnitVisitor::new(#type_name, #variant_name) + ) { + _serde::#private::Ok(()) => _serde::#private::Ok(#this_value::#variant_ident #default), + _serde::#private::Err(__err) => _serde::#private::Err(__err), + } + } + } + Style::Newtype => { + deserialize_untagged_newtype_variant(variant_ident, params, &variant.fields[0]) + } + Style::Tuple => deserialize_tuple( + params, + &variant.fields, + cattrs, + TupleForm::Untagged(variant_ident), + ), + Style::Struct => deserialize_struct( + params, + &variant.fields, + cattrs, + StructForm::Untagged(variant_ident), + ), + } +} + +pub fn deserialize_untagged_newtype_variant( + variant_ident: &syn::Ident, + params: &Parameters, + field: &Field, +) -> Fragment { + let this_value = ¶ms.this_value; + let field_ty = field.ty; + match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); + quote_expr! { + _serde::#private::Result::map(#func(__deserializer), #this_value::#variant_ident) + } + } + Some(path) => { + quote_block! { + let __value: _serde::#private::Result<#field_ty, _> = #path(__deserializer); + _serde::#private::Result::map(__value, #this_value::#variant_ident) + } + } + } +} From 19956e6b8e57188c9d94a5aad0dbe0279ed5513e Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 20 Sep 2025 00:15:59 +0500 Subject: [PATCH 15/22] Move body generator for enums to its own module Cut-paste --- serde_derive/src/de.rs | 87 +---------------------- serde_derive/src/de/enum_.rs | 95 ++++++++++++++++++++++++++ serde_derive/src/de/enum_adjacently.rs | 5 +- serde_derive/src/de/enum_externally.rs | 5 +- serde_derive/src/de/enum_internally.rs | 5 +- 5 files changed, 106 insertions(+), 91 deletions(-) create mode 100644 serde_derive/src/de/enum_.rs diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index b8f665ca..7c98a998 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -12,6 +12,7 @@ use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{parse_quote, Ident, Index, Member}; +mod enum_; mod enum_adjacently; mod enum_externally; mod enum_internally; @@ -307,7 +308,7 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { deserialize_try_from(type_try_from) } else if let attr::Identifier::No = cont.attrs.identifier() { match &cont.data { - Data::Enum(variants) => deserialize_enum(params, variants, &cont.attrs), + Data::Enum(variants) => enum_::deserialize_enum(params, variants, &cont.attrs), Data::Struct(Style::Struct, fields) => { deserialize_struct(params, fields, &cont.attrs, StructForm::Struct) } @@ -1231,90 +1232,6 @@ fn deserialize_struct_in_place( }) } -/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` -fn deserialize_enum( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, -) -> Fragment { - // The variants have already been checked (in ast.rs) that all untagged variants appear at the end - match variants.iter().position(|var| var.attrs.untagged()) { - Some(variant_idx) => { - let (tagged, untagged) = variants.split_at(variant_idx); - let tagged_frag = Expr(deserialize_homogeneous_enum(params, tagged, cattrs)); - // Ignore any error associated with non-untagged deserialization so that we - // can fall through to the untagged variants. This may be infallible so we - // need to provide the error type. - let tagged_frag = quote! { - if let _serde::#private::Result::<_, __D::Error>::Ok(__ok) = (|| #tagged_frag)() { - return _serde::#private::Ok(__ok); - } - }; - enum_untagged::deserialize_untagged_enum(params, untagged, cattrs, Some(tagged_frag)) - } - None => deserialize_homogeneous_enum(params, variants, cattrs), - } -} - -fn deserialize_homogeneous_enum( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, -) -> Fragment { - match cattrs.tag() { - attr::TagType::External => enum_externally::deserialize_externally_tagged_enum(params, variants, cattrs), - attr::TagType::Internal { tag } => { - enum_internally::deserialize_internally_tagged_enum(params, variants, cattrs, tag) - } - attr::TagType::Adjacent { tag, content } => { - enum_adjacently::deserialize_adjacently_tagged_enum(params, variants, cattrs, tag, content) - } - attr::TagType::None => enum_untagged::deserialize_untagged_enum(params, variants, cattrs, None), - } -} - -fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) { - let deserialized_variants = variants - .iter() - .enumerate() - .filter(|&(_i, variant)| !variant.attrs.skip_deserializing()); - - let fallthrough = deserialized_variants - .clone() - .find(|(_i, variant)| variant.attrs.other()) - .map(|(i, _variant)| { - let ignore_variant = field_i(i); - quote!(_serde::#private::Ok(__Field::#ignore_variant)) - }); - - let variants_stmt = { - let variant_names = deserialized_variants - .clone() - .flat_map(|(_i, variant)| variant.attrs.aliases()); - quote! { - #[doc(hidden)] - const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ]; - } - }; - - let deserialized_variants: Vec<_> = deserialized_variants - .map(|(i, variant)| FieldWithAliases { - ident: field_i(i), - aliases: variant.attrs.aliases(), - }) - .collect(); - - let variant_visitor = Stmts(deserialize_generated_identifier( - &deserialized_variants, - false, // variant identifiers do not depend on the presence of flatten fields - true, - None, - fallthrough, - )); - - (variants_stmt, variant_visitor) -} - struct FieldWithAliases<'a> { ident: Ident, aliases: &'a BTreeSet, diff --git a/serde_derive/src/de/enum_.rs b/serde_derive/src/de/enum_.rs new file mode 100644 index 00000000..12e7d75c --- /dev/null +++ b/serde_derive/src/de/enum_.rs @@ -0,0 +1,95 @@ +use crate::de::enum_adjacently; +use crate::de::enum_externally; +use crate::de::enum_internally; +use crate::de::enum_untagged; +use crate::de::{deserialize_generated_identifier, field_i, FieldWithAliases, Parameters}; +use crate::fragment::{Expr, Fragment, Stmts}; +use crate::internals::ast::Variant; +use crate::internals::attr; +use crate::private; +use proc_macro2::TokenStream; +use quote::quote; + +/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` +pub fn deserialize_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + // The variants have already been checked (in ast.rs) that all untagged variants appear at the end + match variants.iter().position(|var| var.attrs.untagged()) { + Some(variant_idx) => { + let (tagged, untagged) = variants.split_at(variant_idx); + let tagged_frag = Expr(deserialize_homogeneous_enum(params, tagged, cattrs)); + // Ignore any error associated with non-untagged deserialization so that we + // can fall through to the untagged variants. This may be infallible so we + // need to provide the error type. + let tagged_frag = quote! { + if let _serde::#private::Result::<_, __D::Error>::Ok(__ok) = (|| #tagged_frag)() { + return _serde::#private::Ok(__ok); + } + }; + enum_untagged::deserialize_untagged_enum(params, untagged, cattrs, Some(tagged_frag)) + } + None => deserialize_homogeneous_enum(params, variants, cattrs), + } +} + +fn deserialize_homogeneous_enum( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + match cattrs.tag() { + attr::TagType::External => enum_externally::deserialize_externally_tagged_enum(params, variants, cattrs), + attr::TagType::Internal { tag } => { + enum_internally::deserialize_internally_tagged_enum(params, variants, cattrs, tag) + } + attr::TagType::Adjacent { tag, content } => { + enum_adjacently::deserialize_adjacently_tagged_enum(params, variants, cattrs, tag, content) + } + attr::TagType::None => enum_untagged::deserialize_untagged_enum(params, variants, cattrs, None), + } +} + +pub fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) { + let deserialized_variants = variants + .iter() + .enumerate() + .filter(|&(_i, variant)| !variant.attrs.skip_deserializing()); + + let fallthrough = deserialized_variants + .clone() + .find(|(_i, variant)| variant.attrs.other()) + .map(|(i, _variant)| { + let ignore_variant = field_i(i); + quote!(_serde::#private::Ok(__Field::#ignore_variant)) + }); + + let variants_stmt = { + let variant_names = deserialized_variants + .clone() + .flat_map(|(_i, variant)| variant.attrs.aliases()); + quote! { + #[doc(hidden)] + const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ]; + } + }; + + let deserialized_variants: Vec<_> = deserialized_variants + .map(|(i, variant)| FieldWithAliases { + ident: field_i(i), + aliases: variant.attrs.aliases(), + }) + .collect(); + + let variant_visitor = Stmts(deserialize_generated_identifier( + &deserialized_variants, + false, // variant identifiers do not depend on the presence of flatten fields + true, + None, + fallthrough, + )); + + (variants_stmt, variant_visitor) +} diff --git a/serde_derive/src/de/enum_adjacently.rs b/serde_derive/src/de/enum_adjacently.rs index ac013e37..88b55718 100644 --- a/serde_derive/src/de/enum_adjacently.rs +++ b/serde_derive/src/de/enum_adjacently.rs @@ -5,8 +5,9 @@ //! enum Enum {} //! ``` +use crate::de::enum_; use crate::de::enum_untagged; -use crate::de::{field_i, prepare_enum_variant_enum, Parameters}; +use crate::de::{field_i, Parameters}; use crate::fragment::{Fragment, Match}; use crate::internals::ast::{Style, Variant}; use crate::internals::attr; @@ -27,7 +28,7 @@ pub fn deserialize_adjacently_tagged_enum( let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); let delife = params.borrowed.de_lifetime(); - let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants); + let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants); let variant_arms: &Vec<_> = &variants .iter() diff --git a/serde_derive/src/de/enum_externally.rs b/serde_derive/src/de/enum_externally.rs index ea548f0e..ad321065 100644 --- a/serde_derive/src/de/enum_externally.rs +++ b/serde_derive/src/de/enum_externally.rs @@ -4,8 +4,9 @@ //! enum Enum {} //! ``` +use crate::de::enum_; use crate::de::{ - deserialize_struct, deserialize_tuple, expr_is_missing, field_i, prepare_enum_variant_enum, + deserialize_struct, deserialize_tuple, expr_is_missing, field_i, unwrap_to_variant_closure, wrap_deserialize_field_with, wrap_deserialize_with, Parameters, StructForm, TupleForm, }; @@ -31,7 +32,7 @@ pub fn deserialize_externally_tagged_enum( let expecting = format!("enum {}", params.type_name()); let expecting = cattrs.expecting().unwrap_or(&expecting); - let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants); + let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants); // Match arms to extract a variant from a string let variant_arms = variants diff --git a/serde_derive/src/de/enum_internally.rs b/serde_derive/src/de/enum_internally.rs index 4dbb6cfa..0f21c1ea 100644 --- a/serde_derive/src/de/enum_internally.rs +++ b/serde_derive/src/de/enum_internally.rs @@ -5,9 +5,10 @@ //! enum Enum {} //! ``` +use crate::de::enum_; use crate::de::enum_untagged; use crate::de::{ - deserialize_struct, effective_style, expr_is_missing, field_i, prepare_enum_variant_enum, + deserialize_struct, effective_style, expr_is_missing, field_i, unwrap_to_variant_closure, Parameters, StructForm, }; use crate::fragment::{Expr, Fragment, Match}; @@ -23,7 +24,7 @@ pub fn deserialize_internally_tagged_enum( cattrs: &attr::Container, tag: &str, ) -> Fragment { - let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants); + let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants); // Match arms to extract a variant from a string let variant_arms = variants From 2d607de146df7c9ef550755a1a7073bb7240227f Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 14 Jun 2025 19:03:18 +0500 Subject: [PATCH 16/22] 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(()) + } +} From c4986f10b9e5393ccbd3659d8b23ad239608470c Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 19 Sep 2025 23:12:48 +0500 Subject: [PATCH 17/22] Move body generator for tuple structs to its own module Cut-paste --- serde_derive/src/de.rs | 276 +----------------------- serde_derive/src/de/enum_externally.rs | 5 +- serde_derive/src/de/enum_untagged.rs | 5 +- serde_derive/src/de/tuple.rs | 281 +++++++++++++++++++++++++ 4 files changed, 290 insertions(+), 277 deletions(-) create mode 100644 serde_derive/src/de/tuple.rs diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 1b8ac19d..48d2b57c 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -18,6 +18,7 @@ mod enum_externally; mod enum_internally; mod enum_untagged; mod struct_; +mod tuple; pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result { replace_receiver(input); @@ -314,7 +315,7 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { 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) + tuple::deserialize_tuple(params, fields, &cont.attrs, TupleForm::Tuple) } Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs), } @@ -349,7 +350,7 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option { - deserialize_tuple_in_place(params, fields, &cont.attrs) + tuple::deserialize_tuple_in_place(params, fields, &cont.attrs) } Data::Enum(_) | Data::Struct(Style::Unit, _) => { return None; @@ -491,228 +492,6 @@ enum TupleForm<'a> { Untagged(&'a syn::Ident), } -/// Generates `Deserialize::deserialize` body for a `struct Tuple(...);` including `struct Newtype(T);` -fn deserialize_tuple( - params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, - form: TupleForm, -) -> Fragment { - assert!( - !has_flatten(fields), - "tuples and tuple variants cannot have flatten fields" - ); - - let field_count = fields - .iter() - .filter(|field| !field.attrs.skip_deserializing()) - .count(); - - 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 { - TupleForm::Tuple => construct, - TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident) => { - quote!(#construct::#variant_ident) - } - }; - let expecting = match form { - TupleForm::Tuple => format!("tuple struct {}", params.type_name()), - TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident) => { - format!("tuple variant {}::{}", params.type_name(), variant_ident) - } - }; - let expecting = cattrs.expecting().unwrap_or(&expecting); - - let nfields = fields.len(); - - let visit_newtype_struct = match form { - TupleForm::Tuple if nfields == 1 => { - Some(deserialize_newtype_struct(&type_path, params, &fields[0])) - } - _ => None, - }; - - let visit_seq = Stmts(deserialize_seq( - &type_path, params, fields, false, cattrs, expecting, - )); - - let visitor_expr = quote! { - __Visitor { - marker: _serde::#private::PhantomData::<#this_type #ty_generics>, - lifetime: _serde::#private::PhantomData, - } - }; - let dispatch = match form { - TupleForm::Tuple if nfields == 1 => { - let type_name = cattrs.name().deserialize_name(); - quote! { - _serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr) - } - } - TupleForm::Tuple => { - let type_name = cattrs.name().deserialize_name(); - quote! { - _serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr) - } - } - TupleForm::ExternallyTagged(_) => quote! { - _serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr) - }, - TupleForm::Untagged(_) => quote! { - _serde::Deserializer::deserialize_tuple(__deserializer, #field_count, #visitor_expr) - }, - }; - - let visitor_var = if field_count == 0 { - quote!(_) - } else { - quote!(mut __seq) - }; - - quote_block! { - #[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_newtype_struct - - #[inline] - fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::#private::Result - where - __A: _serde::de::SeqAccess<#delife>, - { - #visit_seq - } - } - - #dispatch - } -} - -/// Generates `Deserialize::deserialize_in_place` body for a `struct Tuple(...);` including `struct Newtype(T);` -#[cfg(feature = "deserialize_in_place")] -fn deserialize_tuple_in_place( - params: &Parameters, - fields: &[Field], - cattrs: &attr::Container, -) -> Fragment { - assert!( - !has_flatten(fields), - "tuples and tuple variants cannot have flatten fields" - ); - - let field_count = fields - .iter() - .filter(|field| !field.attrs.skip_deserializing()) - .count(); - - 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!("tuple struct {}", params.type_name()); - let expecting = cattrs.expecting().unwrap_or(&expecting); - - let nfields = fields.len(); - - let visit_newtype_struct = if nfields == 1 { - // We do not generate deserialize_in_place if every field has a - // deserialize_with. - assert!(fields[0].attrs.deserialize_with().is_none()); - - Some(quote! { - #[inline] - fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::#private::Result - where - __E: _serde::Deserializer<#delife>, - { - _serde::Deserialize::deserialize_in_place(__e, &mut self.place.0) - } - }) - } else { - None - }; - - let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting)); - - let visitor_expr = quote! { - __Visitor { - place: __place, - lifetime: _serde::#private::PhantomData, - } - }; - - let type_name = cattrs.name().deserialize_name(); - let dispatch = if nfields == 1 { - quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)) - } else { - quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr)) - }; - - let visitor_var = if field_count == 0 { - quote!(_) - } else { - quote!(mut __seq) - }; - - 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(); - - quote_block! { - #[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) - } - - #visit_newtype_struct - - #[inline] - fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::#private::Result - where - __A: _serde::de::SeqAccess<#delife>, - { - #visit_seq - } - } - - #dispatch - } -} - fn deserialize_seq( type_path: &TokenStream, params: &Parameters, @@ -902,55 +681,6 @@ fn deserialize_seq_in_place( } } -fn deserialize_newtype_struct( - type_path: &TokenStream, - params: &Parameters, - field: &Field, -) -> TokenStream { - let delife = params.borrowed.de_lifetime(); - let field_ty = field.ty; - let deserializer_var = quote!(__e); - - let value = match field.attrs.deserialize_with() { - None => { - let span = field.original.span(); - let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); - quote! { - #func(#deserializer_var)? - } - } - Some(path) => { - // 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(with = "...")] - // ^^^^^ - quote_spanned! {path.span()=> - #path(#deserializer_var)? - } - } - }; - - let mut result = quote!(#type_path(__field0)); - 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! { - #[inline] - fn visit_newtype_struct<__E>(self, #deserializer_var: __E) -> _serde::#private::Result - where - __E: _serde::Deserializer<#delife>, - { - let __field0: #field_ty = #value; - _serde::#private::Ok(#result) - } - } -} - enum StructForm<'a> { Struct, /// Contains a variant name diff --git a/serde_derive/src/de/enum_externally.rs b/serde_derive/src/de/enum_externally.rs index c9a9f236..42fc840b 100644 --- a/serde_derive/src/de/enum_externally.rs +++ b/serde_derive/src/de/enum_externally.rs @@ -6,8 +6,9 @@ use crate::de::enum_; use crate::de::struct_; +use crate::de::tuple; use crate::de::{ - deserialize_tuple, expr_is_missing, field_i, + expr_is_missing, field_i, unwrap_to_variant_closure, wrap_deserialize_field_with, wrap_deserialize_with, Parameters, StructForm, TupleForm, }; @@ -143,7 +144,7 @@ fn deserialize_externally_tagged_variant( &variant.fields[0], cattrs, ), - Style::Tuple => deserialize_tuple( + Style::Tuple => tuple::deserialize_tuple( params, &variant.fields, cattrs, diff --git a/serde_derive/src/de/enum_untagged.rs b/serde_derive/src/de/enum_untagged.rs index 05a41498..d954efe2 100644 --- a/serde_derive/src/de/enum_untagged.rs +++ b/serde_derive/src/de/enum_untagged.rs @@ -6,8 +6,9 @@ //! ``` use crate::de::struct_; +use crate::de::tuple; use crate::de::{ - deserialize_tuple, effective_style, expr_is_missing, + effective_style, expr_is_missing, unwrap_to_variant_closure, Parameters, StructForm, TupleForm, }; use crate::fragment::{Expr, Fragment}; @@ -94,7 +95,7 @@ pub fn deserialize_untagged_variant( Style::Newtype => { deserialize_untagged_newtype_variant(variant_ident, params, &variant.fields[0]) } - Style::Tuple => deserialize_tuple( + Style::Tuple => tuple::deserialize_tuple( params, &variant.fields, cattrs, diff --git a/serde_derive/src/de/tuple.rs b/serde_derive/src/de/tuple.rs new file mode 100644 index 00000000..a7a998a8 --- /dev/null +++ b/serde_derive/src/de/tuple.rs @@ -0,0 +1,281 @@ +use crate::de::{deserialize_seq, has_flatten, Parameters, TupleForm}; +#[cfg(feature = "deserialize_in_place")] +use crate::de::{deserialize_seq_in_place, place_lifetime}; +use crate::fragment::{Fragment, 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 Tuple(...);` including `struct Newtype(T);` +pub fn deserialize_tuple( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, + form: TupleForm, +) -> Fragment { + assert!( + !has_flatten(fields), + "tuples and tuple variants cannot have flatten fields" + ); + + let field_count = fields + .iter() + .filter(|field| !field.attrs.skip_deserializing()) + .count(); + + 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 { + TupleForm::Tuple => construct, + TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident) => { + quote!(#construct::#variant_ident) + } + }; + let expecting = match form { + TupleForm::Tuple => format!("tuple struct {}", params.type_name()), + TupleForm::ExternallyTagged(variant_ident) | TupleForm::Untagged(variant_ident) => { + format!("tuple variant {}::{}", params.type_name(), variant_ident) + } + }; + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let nfields = fields.len(); + + let visit_newtype_struct = match form { + TupleForm::Tuple if nfields == 1 => { + Some(deserialize_newtype_struct(&type_path, params, &fields[0])) + } + _ => None, + }; + + let visit_seq = Stmts(deserialize_seq( + &type_path, params, fields, false, cattrs, expecting, + )); + + let visitor_expr = quote! { + __Visitor { + marker: _serde::#private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData, + } + }; + let dispatch = match form { + TupleForm::Tuple if nfields == 1 => { + let type_name = cattrs.name().deserialize_name(); + quote! { + _serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr) + } + } + TupleForm::Tuple => { + let type_name = cattrs.name().deserialize_name(); + quote! { + _serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr) + } + } + TupleForm::ExternallyTagged(_) => quote! { + _serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr) + }, + TupleForm::Untagged(_) => quote! { + _serde::Deserializer::deserialize_tuple(__deserializer, #field_count, #visitor_expr) + }, + }; + + let visitor_var = if field_count == 0 { + quote!(_) + } else { + quote!(mut __seq) + }; + + quote_block! { + #[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_newtype_struct + + #[inline] + fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::#private::Result + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + } + + #dispatch + } +} + +/// Generates `Deserialize::deserialize_in_place` body for a `struct Tuple(...);` including `struct Newtype(T);` +#[cfg(feature = "deserialize_in_place")] +pub fn deserialize_tuple_in_place( + params: &Parameters, + fields: &[Field], + cattrs: &attr::Container, +) -> Fragment { + assert!( + !has_flatten(fields), + "tuples and tuple variants cannot have flatten fields" + ); + + let field_count = fields + .iter() + .filter(|field| !field.attrs.skip_deserializing()) + .count(); + + 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!("tuple struct {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + let nfields = fields.len(); + + let visit_newtype_struct = if nfields == 1 { + // We do not generate deserialize_in_place if every field has a + // deserialize_with. + assert!(fields[0].attrs.deserialize_with().is_none()); + + Some(quote! { + #[inline] + fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::#private::Result + where + __E: _serde::Deserializer<#delife>, + { + _serde::Deserialize::deserialize_in_place(__e, &mut self.place.0) + } + }) + } else { + None + }; + + let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting)); + + let visitor_expr = quote! { + __Visitor { + place: __place, + lifetime: _serde::#private::PhantomData, + } + }; + + let type_name = cattrs.name().deserialize_name(); + let dispatch = if nfields == 1 { + quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr)) + } else { + quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr)) + }; + + let visitor_var = if field_count == 0 { + quote!(_) + } else { + quote!(mut __seq) + }; + + 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(); + + quote_block! { + #[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) + } + + #visit_newtype_struct + + #[inline] + fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::#private::Result + where + __A: _serde::de::SeqAccess<#delife>, + { + #visit_seq + } + } + + #dispatch + } +} + +fn deserialize_newtype_struct( + type_path: &TokenStream, + params: &Parameters, + field: &Field, +) -> TokenStream { + let delife = params.borrowed.de_lifetime(); + let field_ty = field.ty; + let deserializer_var = quote!(__e); + + let value = match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); + quote! { + #func(#deserializer_var)? + } + } + Some(path) => { + // 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(with = "...")] + // ^^^^^ + quote_spanned! {path.span()=> + #path(#deserializer_var)? + } + } + }; + + let mut result = quote!(#type_path(__field0)); + 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! { + #[inline] + fn visit_newtype_struct<__E>(self, #deserializer_var: __E) -> _serde::#private::Result + where + __E: _serde::Deserializer<#delife>, + { + let __field0: #field_ty = #value; + _serde::#private::Ok(#result) + } + } +} From c4a07ed4e80c5db43293526798f5d1ba580351f5 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 20 Sep 2025 00:10:10 +0500 Subject: [PATCH 18/22] Move body generator for unit structs to its own module Cut-paste --- serde_derive/src/de.rs | 49 ++--------------------------------- serde_derive/src/de/unit.rs | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 47 deletions(-) create mode 100644 serde_derive/src/de/unit.rs diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 48d2b57c..b20c840e 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -19,6 +19,7 @@ mod enum_internally; mod enum_untagged; mod struct_; mod tuple; +mod unit; pub fn expand_derive_deserialize(input: &mut syn::DeriveInput) -> syn::Result { replace_receiver(input); @@ -317,7 +318,7 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => { tuple::deserialize_tuple(params, fields, &cont.attrs, TupleForm::Tuple) } - Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs), + Data::Struct(Style::Unit, _) => unit::deserialize_unit_struct(params, &cont.attrs), } } else { match &cont.data { @@ -438,52 +439,6 @@ fn deserialize_try_from(type_try_from: &syn::Type) -> Fragment { } } -/// Generates `Deserialize::deserialize` body for a `struct Unit;` -fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fragment { - let this_type = ¶ms.this_type; - let this_value = ¶ms.this_value; - let type_name = cattrs.name().deserialize_name(); - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); - let delife = params.borrowed.de_lifetime(); - - let expecting = format!("unit struct {}", params.type_name()); - let expecting = cattrs.expecting().unwrap_or(&expecting); - - quote_block! { - #[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) - } - - #[inline] - fn visit_unit<__E>(self) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(#this_value) - } - } - - _serde::Deserializer::deserialize_unit_struct( - __deserializer, - #type_name, - __Visitor { - marker: _serde::#private::PhantomData::<#this_type #ty_generics>, - lifetime: _serde::#private::PhantomData, - }, - ) - } -} - enum TupleForm<'a> { Tuple, /// Contains a variant name diff --git a/serde_derive/src/de/unit.rs b/serde_derive/src/de/unit.rs new file mode 100644 index 00000000..3bce02c3 --- /dev/null +++ b/serde_derive/src/de/unit.rs @@ -0,0 +1,51 @@ +use crate::de::Parameters; +use crate::fragment::Fragment; +use crate::internals::attr; +use crate::private; +use quote::quote; + +/// Generates `Deserialize::deserialize` body for a `struct Unit;` +pub fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fragment { + let this_type = ¶ms.this_type; + let this_value = ¶ms.this_value; + let type_name = cattrs.name().deserialize_name(); + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); + let delife = params.borrowed.de_lifetime(); + + let expecting = format!("unit struct {}", params.type_name()); + let expecting = cattrs.expecting().unwrap_or(&expecting); + + quote_block! { + #[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) + } + + #[inline] + fn visit_unit<__E>(self) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(#this_value) + } + } + + _serde::Deserializer::deserialize_unit_struct( + __deserializer, + #type_name, + __Visitor { + marker: _serde::#private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData, + }, + ) + } +} From fa298c9df490ba9a905dfbae1ed6075261ac09dc Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 19 Sep 2025 23:50:32 +0500 Subject: [PATCH 19/22] Move generator for identifiers to its own module Cut-paste --- serde_derive/src/de.rs | 471 +---------------------------- serde_derive/src/de/enum_.rs | 5 +- serde_derive/src/de/identifier.rs | 475 ++++++++++++++++++++++++++++++ serde_derive/src/de/struct_.rs | 5 +- 4 files changed, 484 insertions(+), 472 deletions(-) create mode 100644 serde_derive/src/de/identifier.rs diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index b20c840e..835a13c9 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -4,7 +4,7 @@ use crate::internals::ast::{Container, Data, Field, Style, Variant}; use crate::internals::name::Name; use crate::internals::{attr, replace_receiver, ungroup, Ctxt, Derive}; use crate::{bound, dummy, pretend, private, this}; -use proc_macro2::{Literal, Span, TokenStream}; +use proc_macro2::{Span, TokenStream}; use quote::{quote, quote_spanned, ToTokens}; use std::collections::BTreeSet; use std::ptr; @@ -17,6 +17,7 @@ mod enum_adjacently; mod enum_externally; mod enum_internally; mod enum_untagged; +mod identifier; mod struct_; mod tuple; mod unit; @@ -322,7 +323,7 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { } } else { match &cont.data { - Data::Enum(variants) => deserialize_custom_identifier(params, variants, &cont.attrs), + Data::Enum(variants) => identifier::deserialize_custom_identifier(params, variants, &cont.attrs), Data::Struct(_, _) => unreachable!("checked in serde_derive_internals"), } } @@ -651,472 +652,6 @@ struct FieldWithAliases<'a> { aliases: &'a BTreeSet, } -fn deserialize_generated_identifier( - deserialized_fields: &[FieldWithAliases], - has_flatten: bool, - is_variant: bool, - ignore_variant: Option, - fallthrough: Option, -) -> Fragment { - let this_value = quote!(__Field); - let field_idents: &Vec<_> = &deserialized_fields - .iter() - .map(|field| &field.ident) - .collect(); - - let visitor_impl = Stmts(deserialize_identifier( - &this_value, - deserialized_fields, - is_variant, - fallthrough, - None, - !is_variant && has_flatten, - None, - )); - - let lifetime = if !is_variant && has_flatten { - Some(quote!(<'de>)) - } else { - None - }; - - quote_block! { - #[allow(non_camel_case_types)] - #[doc(hidden)] - enum __Field #lifetime { - #(#field_idents,)* - #ignore_variant - } - - #[doc(hidden)] - struct __FieldVisitor; - - #[automatically_derived] - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field #lifetime; - - #visitor_impl - } - - #[automatically_derived] - impl<'de> _serde::Deserialize<'de> for __Field #lifetime { - #[inline] - fn deserialize<__D>(__deserializer: __D) -> _serde::#private::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) - } - } - } -} - -// Generates `Deserialize::deserialize` body for an enum with -// `serde(field_identifier)` or `serde(variant_identifier)` attribute. -fn deserialize_custom_identifier( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, -) -> Fragment { - let is_variant = match cattrs.identifier() { - attr::Identifier::Variant => true, - attr::Identifier::Field => false, - attr::Identifier::No => unreachable!(), - }; - - let this_type = params.this_type.to_token_stream(); - let this_value = params.this_value.to_token_stream(); - - let (ordinary, fallthrough, fallthrough_borrowed) = if let Some(last) = variants.last() { - let last_ident = &last.ident; - if last.attrs.other() { - // Process `serde(other)` attribute. It would always be found on the - // last variant (checked in `check_identifier`), so all preceding - // are ordinary variants. - let ordinary = &variants[..variants.len() - 1]; - let fallthrough = quote!(_serde::#private::Ok(#this_value::#last_ident)); - (ordinary, Some(fallthrough), None) - } else if let Style::Newtype = last.style { - let ordinary = &variants[..variants.len() - 1]; - let fallthrough = |value| { - quote! { - _serde::#private::Result::map( - _serde::Deserialize::deserialize( - _serde::#private::de::IdentifierDeserializer::from(#value) - ), - #this_value::#last_ident) - } - }; - ( - ordinary, - Some(fallthrough(quote!(__value))), - Some(fallthrough(quote!(_serde::#private::de::Borrowed( - __value - )))), - ) - } else { - (variants, None, None) - } - } else { - (variants, None, None) - }; - - let idents_aliases: Vec<_> = ordinary - .iter() - .map(|variant| FieldWithAliases { - ident: variant.ident.clone(), - aliases: variant.attrs.aliases(), - }) - .collect(); - - let names = idents_aliases.iter().flat_map(|variant| variant.aliases); - - let names_const = if fallthrough.is_some() { - None - } else if is_variant { - let variants = quote! { - #[doc(hidden)] - const VARIANTS: &'static [&'static str] = &[ #(#names),* ]; - }; - Some(variants) - } else { - let fields = quote! { - #[doc(hidden)] - const FIELDS: &'static [&'static str] = &[ #(#names),* ]; - }; - Some(fields) - }; - - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); - let delife = params.borrowed.de_lifetime(); - let visitor_impl = Stmts(deserialize_identifier( - &this_value, - &idents_aliases, - is_variant, - fallthrough, - fallthrough_borrowed, - false, - cattrs.expecting(), - )); - - quote_block! { - #names_const - - #[doc(hidden)] - struct __FieldVisitor #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 __FieldVisitor #de_ty_generics #where_clause { - type Value = #this_type #ty_generics; - - #visitor_impl - } - - let __visitor = __FieldVisitor { - marker: _serde::#private::PhantomData::<#this_type #ty_generics>, - lifetime: _serde::#private::PhantomData, - }; - _serde::Deserializer::deserialize_identifier(__deserializer, __visitor) - } -} - -fn deserialize_identifier( - this_value: &TokenStream, - deserialized_fields: &[FieldWithAliases], - is_variant: bool, - fallthrough: Option, - fallthrough_borrowed: Option, - collect_other_fields: bool, - expecting: Option<&str>, -) -> Fragment { - let str_mapping = deserialized_fields.iter().map(|field| { - let ident = &field.ident; - let aliases = field.aliases; - let private2 = private; - // `aliases` also contains a main name - quote! { - #( - #aliases => _serde::#private2::Ok(#this_value::#ident), - )* - } - }); - let bytes_mapping = deserialized_fields.iter().map(|field| { - let ident = &field.ident; - // `aliases` also contains a main name - let aliases = field - .aliases - .iter() - .map(|alias| Literal::byte_string(alias.value.as_bytes())); - let private2 = private; - quote! { - #( - #aliases => _serde::#private2::Ok(#this_value::#ident), - )* - } - }); - - let expecting = expecting.unwrap_or(if is_variant { - "variant identifier" - } else { - "field identifier" - }); - - let bytes_to_str = if fallthrough.is_some() || collect_other_fields { - None - } else { - Some(quote! { - let __value = &_serde::#private::from_utf8_lossy(__value); - }) - }; - - let ( - value_as_str_content, - value_as_borrowed_str_content, - value_as_bytes_content, - value_as_borrowed_bytes_content, - ) = if collect_other_fields { - ( - Some(quote! { - let __value = _serde::#private::de::Content::String(_serde::#private::ToString::to_string(__value)); - }), - Some(quote! { - let __value = _serde::#private::de::Content::Str(__value); - }), - Some(quote! { - let __value = _serde::#private::de::Content::ByteBuf(__value.to_vec()); - }), - Some(quote! { - let __value = _serde::#private::de::Content::Bytes(__value); - }), - ) - } else { - (None, None, None, None) - }; - - let fallthrough_arm_tokens; - let fallthrough_arm = if let Some(fallthrough) = &fallthrough { - fallthrough - } else if is_variant { - fallthrough_arm_tokens = quote! { - _serde::#private::Err(_serde::de::Error::unknown_variant(__value, VARIANTS)) - }; - &fallthrough_arm_tokens - } else { - fallthrough_arm_tokens = quote! { - _serde::#private::Err(_serde::de::Error::unknown_field(__value, FIELDS)) - }; - &fallthrough_arm_tokens - }; - - let visit_other = if collect_other_fields { - quote! { - fn visit_bool<__E>(self, __value: bool) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Bool(__value))) - } - - fn visit_i8<__E>(self, __value: i8) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I8(__value))) - } - - fn visit_i16<__E>(self, __value: i16) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I16(__value))) - } - - fn visit_i32<__E>(self, __value: i32) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I32(__value))) - } - - fn visit_i64<__E>(self, __value: i64) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I64(__value))) - } - - fn visit_u8<__E>(self, __value: u8) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U8(__value))) - } - - fn visit_u16<__E>(self, __value: u16) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U16(__value))) - } - - fn visit_u32<__E>(self, __value: u32) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U32(__value))) - } - - fn visit_u64<__E>(self, __value: u64) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U64(__value))) - } - - fn visit_f32<__E>(self, __value: f32) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::F32(__value))) - } - - fn visit_f64<__E>(self, __value: f64) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::F64(__value))) - } - - fn visit_char<__E>(self, __value: char) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Char(__value))) - } - - fn visit_unit<__E>(self) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Unit)) - } - } - } else { - let u64_mapping = deserialized_fields.iter().enumerate().map(|(i, field)| { - let i = i as u64; - let ident = &field.ident; - quote!(#i => _serde::#private::Ok(#this_value::#ident)) - }); - - let u64_fallthrough_arm_tokens; - let u64_fallthrough_arm = if let Some(fallthrough) = &fallthrough { - fallthrough - } else { - let index_expecting = if is_variant { "variant" } else { "field" }; - let fallthrough_msg = format!( - "{} index 0 <= i < {}", - index_expecting, - deserialized_fields.len(), - ); - u64_fallthrough_arm_tokens = quote! { - _serde::#private::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &#fallthrough_msg, - )) - }; - &u64_fallthrough_arm_tokens - }; - - quote! { - fn visit_u64<__E>(self, __value: u64) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - match __value { - #(#u64_mapping,)* - _ => #u64_fallthrough_arm, - } - } - } - }; - - let visit_borrowed = if fallthrough_borrowed.is_some() || collect_other_fields { - let str_mapping = str_mapping.clone(); - let bytes_mapping = bytes_mapping.clone(); - let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(fallthrough_arm); - Some(quote! { - fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - match __value { - #(#str_mapping)* - _ => { - #value_as_borrowed_str_content - #fallthrough_borrowed_arm - } - } - } - - fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - match __value { - #(#bytes_mapping)* - _ => { - #bytes_to_str - #value_as_borrowed_bytes_content - #fallthrough_borrowed_arm - } - } - } - }) - } else { - None - }; - - quote_block! { - fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { - _serde::#private::Formatter::write_str(__formatter, #expecting) - } - - #visit_other - - fn visit_str<__E>(self, __value: &str) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - match __value { - #(#str_mapping)* - _ => { - #value_as_str_content - #fallthrough_arm - } - } - } - - fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - match __value { - #(#bytes_mapping)* - _ => { - #bytes_to_str - #value_as_bytes_content - #fallthrough_arm - } - } - } - - #visit_borrowed - } -} - fn field_i(i: usize) -> Ident { Ident::new(&format!("__field{}", i), Span::call_site()) } diff --git a/serde_derive/src/de/enum_.rs b/serde_derive/src/de/enum_.rs index 12e7d75c..f13ad188 100644 --- a/serde_derive/src/de/enum_.rs +++ b/serde_derive/src/de/enum_.rs @@ -2,7 +2,8 @@ use crate::de::enum_adjacently; use crate::de::enum_externally; use crate::de::enum_internally; use crate::de::enum_untagged; -use crate::de::{deserialize_generated_identifier, field_i, FieldWithAliases, Parameters}; +use crate::de::identifier; +use crate::de::{field_i, FieldWithAliases, Parameters}; use crate::fragment::{Expr, Fragment, Stmts}; use crate::internals::ast::Variant; use crate::internals::attr; @@ -83,7 +84,7 @@ pub fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) { }) .collect(); - let variant_visitor = Stmts(deserialize_generated_identifier( + let variant_visitor = Stmts(identifier::deserialize_generated_identifier( &deserialized_variants, false, // variant identifiers do not depend on the presence of flatten fields true, diff --git a/serde_derive/src/de/identifier.rs b/serde_derive/src/de/identifier.rs new file mode 100644 index 00000000..2fe04129 --- /dev/null +++ b/serde_derive/src/de/identifier.rs @@ -0,0 +1,475 @@ +//! Contains generators of enums that represents identifiers of fields in structs or variants in enums. + +use crate::de::{FieldWithAliases, Parameters}; +use crate::fragment::{Fragment, Stmts}; +use crate::internals::ast::{Style, Variant}; +use crate::internals::attr; +use crate::private; +use proc_macro2::{Literal, TokenStream}; +use quote::{quote, ToTokens}; + +pub fn deserialize_generated_identifier( + deserialized_fields: &[FieldWithAliases], + has_flatten: bool, + is_variant: bool, + ignore_variant: Option, + fallthrough: Option, +) -> Fragment { + let this_value = quote!(__Field); + let field_idents: &Vec<_> = &deserialized_fields + .iter() + .map(|field| &field.ident) + .collect(); + + let visitor_impl = Stmts(deserialize_identifier( + &this_value, + deserialized_fields, + is_variant, + fallthrough, + None, + !is_variant && has_flatten, + None, + )); + + let lifetime = if !is_variant && has_flatten { + Some(quote!(<'de>)) + } else { + None + }; + + quote_block! { + #[allow(non_camel_case_types)] + #[doc(hidden)] + enum __Field #lifetime { + #(#field_idents,)* + #ignore_variant + } + + #[doc(hidden)] + struct __FieldVisitor; + + #[automatically_derived] + impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { + type Value = __Field #lifetime; + + #visitor_impl + } + + #[automatically_derived] + impl<'de> _serde::Deserialize<'de> for __Field #lifetime { + #[inline] + fn deserialize<__D>(__deserializer: __D) -> _serde::#private::Result + where + __D: _serde::Deserializer<'de>, + { + _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) + } + } + } +} + +// Generates `Deserialize::deserialize` body for an enum with +// `serde(field_identifier)` or `serde(variant_identifier)` attribute. +pub fn deserialize_custom_identifier( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + let is_variant = match cattrs.identifier() { + attr::Identifier::Variant => true, + attr::Identifier::Field => false, + attr::Identifier::No => unreachable!(), + }; + + let this_type = params.this_type.to_token_stream(); + let this_value = params.this_value.to_token_stream(); + + let (ordinary, fallthrough, fallthrough_borrowed) = if let Some(last) = variants.last() { + let last_ident = &last.ident; + if last.attrs.other() { + // Process `serde(other)` attribute. It would always be found on the + // last variant (checked in `check_identifier`), so all preceding + // are ordinary variants. + let ordinary = &variants[..variants.len() - 1]; + let fallthrough = quote!(_serde::#private::Ok(#this_value::#last_ident)); + (ordinary, Some(fallthrough), None) + } else if let Style::Newtype = last.style { + let ordinary = &variants[..variants.len() - 1]; + let fallthrough = |value| { + quote! { + _serde::#private::Result::map( + _serde::Deserialize::deserialize( + _serde::#private::de::IdentifierDeserializer::from(#value) + ), + #this_value::#last_ident) + } + }; + ( + ordinary, + Some(fallthrough(quote!(__value))), + Some(fallthrough(quote!(_serde::#private::de::Borrowed( + __value + )))), + ) + } else { + (variants, None, None) + } + } else { + (variants, None, None) + }; + + let idents_aliases: Vec<_> = ordinary + .iter() + .map(|variant| FieldWithAliases { + ident: variant.ident.clone(), + aliases: variant.attrs.aliases(), + }) + .collect(); + + let names = idents_aliases.iter().flat_map(|variant| variant.aliases); + + let names_const = if fallthrough.is_some() { + None + } else if is_variant { + let variants = quote! { + #[doc(hidden)] + const VARIANTS: &'static [&'static str] = &[ #(#names),* ]; + }; + Some(variants) + } else { + let fields = quote! { + #[doc(hidden)] + const FIELDS: &'static [&'static str] = &[ #(#names),* ]; + }; + Some(fields) + }; + + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); + let delife = params.borrowed.de_lifetime(); + let visitor_impl = Stmts(deserialize_identifier( + &this_value, + &idents_aliases, + is_variant, + fallthrough, + fallthrough_borrowed, + false, + cattrs.expecting(), + )); + + quote_block! { + #names_const + + #[doc(hidden)] + struct __FieldVisitor #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 __FieldVisitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + #visitor_impl + } + + let __visitor = __FieldVisitor { + marker: _serde::#private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData, + }; + _serde::Deserializer::deserialize_identifier(__deserializer, __visitor) + } +} + +fn deserialize_identifier( + this_value: &TokenStream, + deserialized_fields: &[FieldWithAliases], + is_variant: bool, + fallthrough: Option, + fallthrough_borrowed: Option, + collect_other_fields: bool, + expecting: Option<&str>, +) -> Fragment { + let str_mapping = deserialized_fields.iter().map(|field| { + let ident = &field.ident; + let aliases = field.aliases; + let private2 = private; + // `aliases` also contains a main name + quote! { + #( + #aliases => _serde::#private2::Ok(#this_value::#ident), + )* + } + }); + let bytes_mapping = deserialized_fields.iter().map(|field| { + let ident = &field.ident; + // `aliases` also contains a main name + let aliases = field + .aliases + .iter() + .map(|alias| Literal::byte_string(alias.value.as_bytes())); + let private2 = private; + quote! { + #( + #aliases => _serde::#private2::Ok(#this_value::#ident), + )* + } + }); + + let expecting = expecting.unwrap_or(if is_variant { + "variant identifier" + } else { + "field identifier" + }); + + let bytes_to_str = if fallthrough.is_some() || collect_other_fields { + None + } else { + Some(quote! { + let __value = &_serde::#private::from_utf8_lossy(__value); + }) + }; + + let ( + value_as_str_content, + value_as_borrowed_str_content, + value_as_bytes_content, + value_as_borrowed_bytes_content, + ) = if collect_other_fields { + ( + Some(quote! { + let __value = _serde::#private::de::Content::String(_serde::#private::ToString::to_string(__value)); + }), + Some(quote! { + let __value = _serde::#private::de::Content::Str(__value); + }), + Some(quote! { + let __value = _serde::#private::de::Content::ByteBuf(__value.to_vec()); + }), + Some(quote! { + let __value = _serde::#private::de::Content::Bytes(__value); + }), + ) + } else { + (None, None, None, None) + }; + + let fallthrough_arm_tokens; + let fallthrough_arm = if let Some(fallthrough) = &fallthrough { + fallthrough + } else if is_variant { + fallthrough_arm_tokens = quote! { + _serde::#private::Err(_serde::de::Error::unknown_variant(__value, VARIANTS)) + }; + &fallthrough_arm_tokens + } else { + fallthrough_arm_tokens = quote! { + _serde::#private::Err(_serde::de::Error::unknown_field(__value, FIELDS)) + }; + &fallthrough_arm_tokens + }; + + let visit_other = if collect_other_fields { + quote! { + fn visit_bool<__E>(self, __value: bool) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Bool(__value))) + } + + fn visit_i8<__E>(self, __value: i8) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I8(__value))) + } + + fn visit_i16<__E>(self, __value: i16) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I16(__value))) + } + + fn visit_i32<__E>(self, __value: i32) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I32(__value))) + } + + fn visit_i64<__E>(self, __value: i64) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I64(__value))) + } + + fn visit_u8<__E>(self, __value: u8) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U8(__value))) + } + + fn visit_u16<__E>(self, __value: u16) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U16(__value))) + } + + fn visit_u32<__E>(self, __value: u32) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U32(__value))) + } + + fn visit_u64<__E>(self, __value: u64) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U64(__value))) + } + + fn visit_f32<__E>(self, __value: f32) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::F32(__value))) + } + + fn visit_f64<__E>(self, __value: f64) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::F64(__value))) + } + + fn visit_char<__E>(self, __value: char) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Char(__value))) + } + + fn visit_unit<__E>(self) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Unit)) + } + } + } else { + let u64_mapping = deserialized_fields.iter().enumerate().map(|(i, field)| { + let i = i as u64; + let ident = &field.ident; + quote!(#i => _serde::#private::Ok(#this_value::#ident)) + }); + + let u64_fallthrough_arm_tokens; + let u64_fallthrough_arm = if let Some(fallthrough) = &fallthrough { + fallthrough + } else { + let index_expecting = if is_variant { "variant" } else { "field" }; + let fallthrough_msg = format!( + "{} index 0 <= i < {}", + index_expecting, + deserialized_fields.len(), + ); + u64_fallthrough_arm_tokens = quote! { + _serde::#private::Err(_serde::de::Error::invalid_value( + _serde::de::Unexpected::Unsigned(__value), + &#fallthrough_msg, + )) + }; + &u64_fallthrough_arm_tokens + }; + + quote! { + fn visit_u64<__E>(self, __value: u64) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#u64_mapping,)* + _ => #u64_fallthrough_arm, + } + } + } + }; + + let visit_borrowed = if fallthrough_borrowed.is_some() || collect_other_fields { + let str_mapping = str_mapping.clone(); + let bytes_mapping = bytes_mapping.clone(); + let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(fallthrough_arm); + Some(quote! { + fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#str_mapping)* + _ => { + #value_as_borrowed_str_content + #fallthrough_borrowed_arm + } + } + } + + fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#bytes_mapping)* + _ => { + #bytes_to_str + #value_as_borrowed_bytes_content + #fallthrough_borrowed_arm + } + } + } + }) + } else { + None + }; + + quote_block! { + fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { + _serde::#private::Formatter::write_str(__formatter, #expecting) + } + + #visit_other + + fn visit_str<__E>(self, __value: &str) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#str_mapping)* + _ => { + #value_as_str_content + #fallthrough_arm + } + } + } + + fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#bytes_mapping)* + _ => { + #bytes_to_str + #value_as_bytes_content + #fallthrough_arm + } + } + } + + #visit_borrowed + } +} diff --git a/serde_derive/src/de/struct_.rs b/serde_derive/src/de/struct_.rs index 721a4839..83dff143 100644 --- a/serde_derive/src/de/struct_.rs +++ b/serde_derive/src/de/struct_.rs @@ -1,5 +1,6 @@ +use crate::de::identifier; use crate::de::{ - deserialize_generated_identifier, deserialize_seq, expr_is_missing, field_i, has_flatten, + deserialize_seq, expr_is_missing, field_i, has_flatten, wrap_deserialize_field_with, FieldWithAliases, Parameters, StructForm, }; #[cfg(feature = "deserialize_in_place")] @@ -303,7 +304,7 @@ fn deserialize_field_identifier( (Some(ignore_variant), Some(fallthrough)) }; - Stmts(deserialize_generated_identifier( + Stmts(identifier::deserialize_generated_identifier( deserialized_fields, has_flatten, false, From 88b6a9abf422ceebaef2e31f3e86adfebedf4f3d Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 19 Sep 2025 21:27:30 +0500 Subject: [PATCH 20/22] Rename functions and run `cargo fmt` --- serde_derive/src/de.rs | 14 +++++++------- serde_derive/src/de/enum_.rs | 14 +++++++------- serde_derive/src/de/enum_adjacently.rs | 4 ++-- serde_derive/src/de/enum_externally.rs | 11 +++++------ serde_derive/src/de/enum_internally.rs | 9 ++++----- serde_derive/src/de/enum_untagged.rs | 22 +++++++++++----------- serde_derive/src/de/identifier.rs | 4 ++-- serde_derive/src/de/struct_.rs | 10 +++++----- serde_derive/src/de/tuple.rs | 4 ++-- serde_derive/src/de/unit.rs | 2 +- 10 files changed, 46 insertions(+), 48 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 835a13c9..9e4e6804 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -312,18 +312,18 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { deserialize_try_from(type_try_from) } else if let attr::Identifier::No = cont.attrs.identifier() { match &cont.data { - Data::Enum(variants) => enum_::deserialize_enum(params, variants, &cont.attrs), + Data::Enum(variants) => enum_::generate_body(params, variants, &cont.attrs), Data::Struct(Style::Struct, fields) => { - struct_::deserialize_struct(params, fields, &cont.attrs, StructForm::Struct) + struct_::generate_body(params, fields, &cont.attrs, StructForm::Struct) } Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => { - tuple::deserialize_tuple(params, fields, &cont.attrs, TupleForm::Tuple) + tuple::generate_body(params, fields, &cont.attrs, TupleForm::Tuple) } - Data::Struct(Style::Unit, _) => unit::deserialize_unit_struct(params, &cont.attrs), + Data::Struct(Style::Unit, _) => unit::generate_body(params, &cont.attrs), } } else { match &cont.data { - Data::Enum(variants) => identifier::deserialize_custom_identifier(params, variants, &cont.attrs), + Data::Enum(variants) => identifier::generate_body(params, variants, &cont.attrs), Data::Struct(_, _) => unreachable!("checked in serde_derive_internals"), } } @@ -349,10 +349,10 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option { - struct_::deserialize_struct_in_place(params, fields, &cont.attrs)? + struct_::generate_body_in_place(params, fields, &cont.attrs)? } Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => { - tuple::deserialize_tuple_in_place(params, fields, &cont.attrs) + tuple::generate_body_in_place(params, fields, &cont.attrs) } Data::Enum(_) | Data::Struct(Style::Unit, _) => { return None; diff --git a/serde_derive/src/de/enum_.rs b/serde_derive/src/de/enum_.rs index f13ad188..c5040b89 100644 --- a/serde_derive/src/de/enum_.rs +++ b/serde_derive/src/de/enum_.rs @@ -12,7 +12,7 @@ use proc_macro2::TokenStream; use quote::quote; /// Generates `Deserialize::deserialize` body for an `enum Enum {...}` -pub fn deserialize_enum( +pub fn generate_body( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, @@ -30,7 +30,7 @@ pub fn deserialize_enum( return _serde::#private::Ok(__ok); } }; - enum_untagged::deserialize_untagged_enum(params, untagged, cattrs, Some(tagged_frag)) + enum_untagged::generate_body(params, untagged, cattrs, Some(tagged_frag)) } None => deserialize_homogeneous_enum(params, variants, cattrs), } @@ -42,14 +42,14 @@ fn deserialize_homogeneous_enum( cattrs: &attr::Container, ) -> Fragment { match cattrs.tag() { - attr::TagType::External => enum_externally::deserialize_externally_tagged_enum(params, variants, cattrs), + attr::TagType::External => enum_externally::generate_body(params, variants, cattrs), attr::TagType::Internal { tag } => { - enum_internally::deserialize_internally_tagged_enum(params, variants, cattrs, tag) + enum_internally::generate_body(params, variants, cattrs, tag) } attr::TagType::Adjacent { tag, content } => { - enum_adjacently::deserialize_adjacently_tagged_enum(params, variants, cattrs, tag, content) + enum_adjacently::generate_body(params, variants, cattrs, tag, content) } - attr::TagType::None => enum_untagged::deserialize_untagged_enum(params, variants, cattrs, None), + attr::TagType::None => enum_untagged::generate_body(params, variants, cattrs, None), } } @@ -84,7 +84,7 @@ pub fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) { }) .collect(); - let variant_visitor = Stmts(identifier::deserialize_generated_identifier( + let variant_visitor = Stmts(identifier::generate_identifier( &deserialized_variants, false, // variant identifiers do not depend on the presence of flatten fields true, diff --git a/serde_derive/src/de/enum_adjacently.rs b/serde_derive/src/de/enum_adjacently.rs index 88b55718..34561bdb 100644 --- a/serde_derive/src/de/enum_adjacently.rs +++ b/serde_derive/src/de/enum_adjacently.rs @@ -16,7 +16,7 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; /// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag, content)]` attributes -pub fn deserialize_adjacently_tagged_enum( +pub fn generate_body( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, @@ -37,7 +37,7 @@ pub fn deserialize_adjacently_tagged_enum( .map(|(i, variant)| { let variant_index = field_i(i); - let block = Match(enum_untagged::deserialize_untagged_variant(params, variant, cattrs)); + let block = Match(enum_untagged::generate_variant(params, variant, cattrs)); quote! { __Field::#variant_index => #block diff --git a/serde_derive/src/de/enum_externally.rs b/serde_derive/src/de/enum_externally.rs index 42fc840b..b777571c 100644 --- a/serde_derive/src/de/enum_externally.rs +++ b/serde_derive/src/de/enum_externally.rs @@ -8,9 +8,8 @@ use crate::de::enum_; use crate::de::struct_; use crate::de::tuple; use crate::de::{ - expr_is_missing, field_i, - unwrap_to_variant_closure, wrap_deserialize_field_with, wrap_deserialize_with, Parameters, - StructForm, TupleForm, + expr_is_missing, field_i, unwrap_to_variant_closure, wrap_deserialize_field_with, + wrap_deserialize_with, Parameters, StructForm, TupleForm, }; use crate::fragment::{Expr, Fragment, Match}; use crate::internals::ast::{Field, Style, Variant}; @@ -21,7 +20,7 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; /// Generates `Deserialize::deserialize` body for an `enum Enum {...}` without additional attributes -pub fn deserialize_externally_tagged_enum( +pub fn generate_body( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, @@ -144,13 +143,13 @@ fn deserialize_externally_tagged_variant( &variant.fields[0], cattrs, ), - Style::Tuple => tuple::deserialize_tuple( + Style::Tuple => tuple::generate_body( params, &variant.fields, cattrs, TupleForm::ExternallyTagged(variant_ident), ), - Style::Struct => struct_::deserialize_struct( + Style::Struct => struct_::generate_body( params, &variant.fields, cattrs, diff --git a/serde_derive/src/de/enum_internally.rs b/serde_derive/src/de/enum_internally.rs index 7d9a9ff1..2b176284 100644 --- a/serde_derive/src/de/enum_internally.rs +++ b/serde_derive/src/de/enum_internally.rs @@ -9,8 +9,7 @@ use crate::de::enum_; use crate::de::enum_untagged; use crate::de::struct_; use crate::de::{ - effective_style, expr_is_missing, field_i, - unwrap_to_variant_closure, Parameters, StructForm, + effective_style, expr_is_missing, field_i, unwrap_to_variant_closure, Parameters, StructForm, }; use crate::fragment::{Expr, Fragment, Match}; use crate::internals::ast::{Style, Variant}; @@ -19,7 +18,7 @@ use crate::private; use quote::quote; /// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag)]` attribute -pub fn deserialize_internally_tagged_enum( +pub fn generate_body( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, @@ -94,9 +93,9 @@ fn deserialize_internally_tagged_variant( } } Style::Newtype => { - enum_untagged::deserialize_untagged_newtype_variant(variant_ident, params, &variant.fields[0]) + enum_untagged::generate_newtype_variant(variant_ident, params, &variant.fields[0]) } - Style::Struct => struct_::deserialize_struct( + Style::Struct => struct_::generate_body( params, &variant.fields, cattrs, diff --git a/serde_derive/src/de/enum_untagged.rs b/serde_derive/src/de/enum_untagged.rs index d954efe2..08c4bb6a 100644 --- a/serde_derive/src/de/enum_untagged.rs +++ b/serde_derive/src/de/enum_untagged.rs @@ -8,8 +8,7 @@ use crate::de::struct_; use crate::de::tuple; use crate::de::{ - effective_style, expr_is_missing, - unwrap_to_variant_closure, Parameters, StructForm, TupleForm, + effective_style, expr_is_missing, unwrap_to_variant_closure, Parameters, StructForm, TupleForm, }; use crate::fragment::{Expr, Fragment}; use crate::internals::ast::{Field, Style, Variant}; @@ -20,7 +19,7 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; /// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(untagged)]` attribute -pub fn deserialize_untagged_enum( +pub fn generate_body( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, @@ -29,7 +28,7 @@ pub fn deserialize_untagged_enum( let attempts = variants .iter() .filter(|variant| !variant.attrs.skip_deserializing()) - .map(|variant| Expr(deserialize_untagged_variant(params, variant, cattrs))); + .map(|variant| Expr(generate_variant(params, variant, cattrs))); // TODO this message could be better by saving the errors from the failed // attempts. The heuristic used by TOML was to count the number of fields // processed before an error, and use the error that happened after the @@ -59,7 +58,8 @@ pub fn deserialize_untagged_enum( } } -pub fn deserialize_untagged_variant( +// Also used by adjacently tagged enums +pub fn generate_variant( params: &Parameters, variant: &Variant, cattrs: &attr::Container, @@ -92,16 +92,14 @@ pub fn deserialize_untagged_variant( } } } - Style::Newtype => { - deserialize_untagged_newtype_variant(variant_ident, params, &variant.fields[0]) - } - Style::Tuple => tuple::deserialize_tuple( + Style::Newtype => generate_newtype_variant(variant_ident, params, &variant.fields[0]), + Style::Tuple => tuple::generate_body( params, &variant.fields, cattrs, TupleForm::Untagged(variant_ident), ), - Style::Struct => struct_::deserialize_struct( + Style::Struct => struct_::generate_body( params, &variant.fields, cattrs, @@ -110,7 +108,9 @@ pub fn deserialize_untagged_variant( } } -pub fn deserialize_untagged_newtype_variant( +// Also used by internally tagged enums +// Implicitly (via `generate_variant`) used by adjacently tagged enums +pub fn generate_newtype_variant( variant_ident: &syn::Ident, params: &Parameters, field: &Field, diff --git a/serde_derive/src/de/identifier.rs b/serde_derive/src/de/identifier.rs index 2fe04129..19c52e13 100644 --- a/serde_derive/src/de/identifier.rs +++ b/serde_derive/src/de/identifier.rs @@ -8,7 +8,7 @@ use crate::private; use proc_macro2::{Literal, TokenStream}; use quote::{quote, ToTokens}; -pub fn deserialize_generated_identifier( +pub fn generate_identifier( deserialized_fields: &[FieldWithAliases], has_flatten: bool, is_variant: bool, @@ -70,7 +70,7 @@ pub fn deserialize_generated_identifier( // Generates `Deserialize::deserialize` body for an enum with // `serde(field_identifier)` or `serde(variant_identifier)` attribute. -pub fn deserialize_custom_identifier( +pub fn generate_body( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, diff --git a/serde_derive/src/de/struct_.rs b/serde_derive/src/de/struct_.rs index 83dff143..bef1c500 100644 --- a/serde_derive/src/de/struct_.rs +++ b/serde_derive/src/de/struct_.rs @@ -1,7 +1,7 @@ use crate::de::identifier; use crate::de::{ - deserialize_seq, expr_is_missing, field_i, has_flatten, - wrap_deserialize_field_with, FieldWithAliases, Parameters, StructForm, + 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}; @@ -14,7 +14,7 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; /// Generates `Deserialize::deserialize` body for a `struct Struct {...}` -pub fn deserialize_struct( +pub fn generate_body( params: &Parameters, fields: &[Field], cattrs: &attr::Container, @@ -197,7 +197,7 @@ pub fn deserialize_struct( /// Generates `Deserialize::deserialize_in_place` body for a `struct Struct {...}` #[cfg(feature = "deserialize_in_place")] -pub fn deserialize_struct_in_place( +pub fn generate_body_in_place( params: &Parameters, fields: &[Field], cattrs: &attr::Container, @@ -304,7 +304,7 @@ fn deserialize_field_identifier( (Some(ignore_variant), Some(fallthrough)) }; - Stmts(identifier::deserialize_generated_identifier( + Stmts(identifier::generate_identifier( deserialized_fields, has_flatten, false, diff --git a/serde_derive/src/de/tuple.rs b/serde_derive/src/de/tuple.rs index a7a998a8..da3b286c 100644 --- a/serde_derive/src/de/tuple.rs +++ b/serde_derive/src/de/tuple.rs @@ -10,7 +10,7 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; /// Generates `Deserialize::deserialize` body for a `struct Tuple(...);` including `struct Newtype(T);` -pub fn deserialize_tuple( +pub fn generate_body( params: &Parameters, fields: &[Field], cattrs: &attr::Container, @@ -133,7 +133,7 @@ pub fn deserialize_tuple( /// Generates `Deserialize::deserialize_in_place` body for a `struct Tuple(...);` including `struct Newtype(T);` #[cfg(feature = "deserialize_in_place")] -pub fn deserialize_tuple_in_place( +pub fn generate_body_in_place( params: &Parameters, fields: &[Field], cattrs: &attr::Container, diff --git a/serde_derive/src/de/unit.rs b/serde_derive/src/de/unit.rs index 3bce02c3..3bad35e1 100644 --- a/serde_derive/src/de/unit.rs +++ b/serde_derive/src/de/unit.rs @@ -5,7 +5,7 @@ use crate::private; use quote::quote; /// Generates `Deserialize::deserialize` body for a `struct Unit;` -pub fn deserialize_unit_struct(params: &Parameters, cattrs: &attr::Container) -> Fragment { +pub fn generate_body(params: &Parameters, cattrs: &attr::Container) -> Fragment { let this_type = ¶ms.this_type; let this_value = ¶ms.this_value; let type_name = cattrs.name().deserialize_name(); From 8c3445efe4b81d31fd87ea0d4069de266795314e Mon Sep 17 00:00:00 2001 From: Mingun Date: Fri, 19 Sep 2025 21:39:47 +0500 Subject: [PATCH 21/22] Group some functions that used together --- serde_derive/src/de/enum_externally.rs | 28 +-- serde_derive/src/de/identifier.rs | 120 ++++++------- serde_derive/src/de/struct_.rs | 236 ++++++++++++------------- serde_derive/src/de/tuple.rs | 98 +++++----- 4 files changed, 241 insertions(+), 241 deletions(-) diff --git a/serde_derive/src/de/enum_externally.rs b/serde_derive/src/de/enum_externally.rs index b777571c..41c3aeaf 100644 --- a/serde_derive/src/de/enum_externally.rs +++ b/serde_derive/src/de/enum_externally.rs @@ -158,6 +158,20 @@ fn deserialize_externally_tagged_variant( } } +fn wrap_deserialize_variant_with( + params: &Parameters, + variant: &Variant, + deserialize_with: &syn::ExprPath, +) -> (TokenStream, TokenStream, TokenStream) { + let field_tys = variant.fields.iter().map(|field| field.ty); + let (wrapper, wrapper_ty) = + wrap_deserialize_with(params, "e!((#(#field_tys),*)), deserialize_with); + + let unwrap_fn = unwrap_to_variant_closure(params, variant, true); + + (wrapper, wrapper_ty, unwrap_fn) +} + fn deserialize_externally_tagged_newtype_variant( variant_ident: &syn::Ident, params: &Parameters, @@ -195,17 +209,3 @@ fn deserialize_externally_tagged_newtype_variant( } } } - -fn wrap_deserialize_variant_with( - params: &Parameters, - variant: &Variant, - deserialize_with: &syn::ExprPath, -) -> (TokenStream, TokenStream, TokenStream) { - let field_tys = variant.fields.iter().map(|field| field.ty); - let (wrapper, wrapper_ty) = - wrap_deserialize_with(params, "e!((#(#field_tys),*)), deserialize_with); - - let unwrap_fn = unwrap_to_variant_closure(params, variant, true); - - (wrapper, wrapper_ty, unwrap_fn) -} diff --git a/serde_derive/src/de/identifier.rs b/serde_derive/src/de/identifier.rs index 19c52e13..1b347b35 100644 --- a/serde_derive/src/de/identifier.rs +++ b/serde_derive/src/de/identifier.rs @@ -8,66 +8,6 @@ use crate::private; use proc_macro2::{Literal, TokenStream}; use quote::{quote, ToTokens}; -pub fn generate_identifier( - deserialized_fields: &[FieldWithAliases], - has_flatten: bool, - is_variant: bool, - ignore_variant: Option, - fallthrough: Option, -) -> Fragment { - let this_value = quote!(__Field); - let field_idents: &Vec<_> = &deserialized_fields - .iter() - .map(|field| &field.ident) - .collect(); - - let visitor_impl = Stmts(deserialize_identifier( - &this_value, - deserialized_fields, - is_variant, - fallthrough, - None, - !is_variant && has_flatten, - None, - )); - - let lifetime = if !is_variant && has_flatten { - Some(quote!(<'de>)) - } else { - None - }; - - quote_block! { - #[allow(non_camel_case_types)] - #[doc(hidden)] - enum __Field #lifetime { - #(#field_idents,)* - #ignore_variant - } - - #[doc(hidden)] - struct __FieldVisitor; - - #[automatically_derived] - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field #lifetime; - - #visitor_impl - } - - #[automatically_derived] - impl<'de> _serde::Deserialize<'de> for __Field #lifetime { - #[inline] - fn deserialize<__D>(__deserializer: __D) -> _serde::#private::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) - } - } - } -} - // Generates `Deserialize::deserialize` body for an enum with // `serde(field_identifier)` or `serde(variant_identifier)` attribute. pub fn generate_body( @@ -180,6 +120,66 @@ pub fn generate_body( } } +pub fn generate_identifier( + deserialized_fields: &[FieldWithAliases], + has_flatten: bool, + is_variant: bool, + ignore_variant: Option, + fallthrough: Option, +) -> Fragment { + let this_value = quote!(__Field); + let field_idents: &Vec<_> = &deserialized_fields + .iter() + .map(|field| &field.ident) + .collect(); + + let visitor_impl = Stmts(deserialize_identifier( + &this_value, + deserialized_fields, + is_variant, + fallthrough, + None, + !is_variant && has_flatten, + None, + )); + + let lifetime = if !is_variant && has_flatten { + Some(quote!(<'de>)) + } else { + None + }; + + quote_block! { + #[allow(non_camel_case_types)] + #[doc(hidden)] + enum __Field #lifetime { + #(#field_idents,)* + #ignore_variant + } + + #[doc(hidden)] + struct __FieldVisitor; + + #[automatically_derived] + impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { + type Value = __Field #lifetime; + + #visitor_impl + } + + #[automatically_derived] + impl<'de> _serde::Deserialize<'de> for __Field #lifetime { + #[inline] + fn deserialize<__D>(__deserializer: __D) -> _serde::#private::Result + where + __D: _serde::Deserializer<'de>, + { + _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) + } + } + } +} + fn deserialize_identifier( this_value: &TokenStream, deserialized_fields: &[FieldWithAliases], diff --git a/serde_derive/src/de/struct_.rs b/serde_derive/src/de/struct_.rs index bef1c500..4d80e08f 100644 --- a/serde_derive/src/de/struct_.rs +++ b/serde_derive/src/de/struct_.rs @@ -195,124 +195,6 @@ pub fn generate_body( } } -/// Generates `Deserialize::deserialize_in_place` body for a `struct Struct {...}` -#[cfg(feature = "deserialize_in_place")] -pub fn generate_body_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(identifier::generate_identifier( - deserialized_fields, - has_flatten, - false, - ignore_variant, - fallthrough, - )) -} - fn deserialize_map( struct_path: &TokenStream, params: &Parameters, @@ -535,6 +417,96 @@ fn deserialize_map( } } +/// Generates `Deserialize::deserialize_in_place` body for a `struct Struct {...}` +#[cfg(feature = "deserialize_in_place")] +pub fn generate_body_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, + }) + }) +} + #[cfg(feature = "deserialize_in_place")] fn deserialize_map_in_place( params: &Parameters, @@ -693,3 +665,31 @@ fn deserialize_map_in_place( _serde::#private::Ok(()) } } + +/// 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(identifier::generate_identifier( + deserialized_fields, + has_flatten, + false, + ignore_variant, + fallthrough, + )) +} diff --git a/serde_derive/src/de/tuple.rs b/serde_derive/src/de/tuple.rs index da3b286c..2a2d9f97 100644 --- a/serde_derive/src/de/tuple.rs +++ b/serde_derive/src/de/tuple.rs @@ -131,6 +131,55 @@ pub fn generate_body( } } +fn deserialize_newtype_struct( + type_path: &TokenStream, + params: &Parameters, + field: &Field, +) -> TokenStream { + let delife = params.borrowed.de_lifetime(); + let field_ty = field.ty; + let deserializer_var = quote!(__e); + + let value = match field.attrs.deserialize_with() { + None => { + let span = field.original.span(); + let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); + quote! { + #func(#deserializer_var)? + } + } + Some(path) => { + // 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(with = "...")] + // ^^^^^ + quote_spanned! {path.span()=> + #path(#deserializer_var)? + } + } + }; + + let mut result = quote!(#type_path(__field0)); + 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! { + #[inline] + fn visit_newtype_struct<__E>(self, #deserializer_var: __E) -> _serde::#private::Result + where + __E: _serde::Deserializer<#delife>, + { + let __field0: #field_ty = #value; + _serde::#private::Ok(#result) + } + } +} + /// Generates `Deserialize::deserialize_in_place` body for a `struct Tuple(...);` including `struct Newtype(T);` #[cfg(feature = "deserialize_in_place")] pub fn generate_body_in_place( @@ -230,52 +279,3 @@ pub fn generate_body_in_place( #dispatch } } - -fn deserialize_newtype_struct( - type_path: &TokenStream, - params: &Parameters, - field: &Field, -) -> TokenStream { - let delife = params.borrowed.de_lifetime(); - let field_ty = field.ty; - let deserializer_var = quote!(__e); - - let value = match field.attrs.deserialize_with() { - None => { - let span = field.original.span(); - let func = quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize); - quote! { - #func(#deserializer_var)? - } - } - Some(path) => { - // 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(with = "...")] - // ^^^^^ - quote_spanned! {path.span()=> - #path(#deserializer_var)? - } - } - }; - - let mut result = quote!(#type_path(__field0)); - 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! { - #[inline] - fn visit_newtype_struct<__E>(self, #deserializer_var: __E) -> _serde::#private::Result - where - __E: _serde::Deserializer<#delife>, - { - let __field0: #field_ty = #value; - _serde::#private::Ok(#result) - } - } -} From 027112eccb750e6dc9ca53a23ae4ee07626d1de2 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sun, 21 Sep 2025 20:58:53 +0500 Subject: [PATCH 22/22] Visibility fix for Rust 1.61 --- serde_derive/src/de/enum_.rs | 2 +- serde_derive/src/de/enum_adjacently.rs | 2 +- serde_derive/src/de/enum_externally.rs | 2 +- serde_derive/src/de/enum_internally.rs | 2 +- serde_derive/src/de/enum_untagged.rs | 6 +++--- serde_derive/src/de/identifier.rs | 4 ++-- serde_derive/src/de/struct_.rs | 4 ++-- serde_derive/src/de/tuple.rs | 4 ++-- serde_derive/src/de/unit.rs | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/serde_derive/src/de/enum_.rs b/serde_derive/src/de/enum_.rs index c5040b89..15a1e541 100644 --- a/serde_derive/src/de/enum_.rs +++ b/serde_derive/src/de/enum_.rs @@ -12,7 +12,7 @@ use proc_macro2::TokenStream; use quote::quote; /// Generates `Deserialize::deserialize` body for an `enum Enum {...}` -pub fn generate_body( +pub(super) fn generate_body( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, diff --git a/serde_derive/src/de/enum_adjacently.rs b/serde_derive/src/de/enum_adjacently.rs index 34561bdb..59239351 100644 --- a/serde_derive/src/de/enum_adjacently.rs +++ b/serde_derive/src/de/enum_adjacently.rs @@ -16,7 +16,7 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; /// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag, content)]` attributes -pub fn generate_body( +pub(super) fn generate_body( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, diff --git a/serde_derive/src/de/enum_externally.rs b/serde_derive/src/de/enum_externally.rs index 41c3aeaf..75f329ec 100644 --- a/serde_derive/src/de/enum_externally.rs +++ b/serde_derive/src/de/enum_externally.rs @@ -20,7 +20,7 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; /// Generates `Deserialize::deserialize` body for an `enum Enum {...}` without additional attributes -pub fn generate_body( +pub(super) fn generate_body( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, diff --git a/serde_derive/src/de/enum_internally.rs b/serde_derive/src/de/enum_internally.rs index 2b176284..e3e85f52 100644 --- a/serde_derive/src/de/enum_internally.rs +++ b/serde_derive/src/de/enum_internally.rs @@ -18,7 +18,7 @@ use crate::private; use quote::quote; /// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag)]` attribute -pub fn generate_body( +pub(super) fn generate_body( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, diff --git a/serde_derive/src/de/enum_untagged.rs b/serde_derive/src/de/enum_untagged.rs index 08c4bb6a..d431e537 100644 --- a/serde_derive/src/de/enum_untagged.rs +++ b/serde_derive/src/de/enum_untagged.rs @@ -19,7 +19,7 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; /// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(untagged)]` attribute -pub fn generate_body( +pub(super) fn generate_body( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, @@ -59,7 +59,7 @@ pub fn generate_body( } // Also used by adjacently tagged enums -pub fn generate_variant( +pub(super) fn generate_variant( params: &Parameters, variant: &Variant, cattrs: &attr::Container, @@ -110,7 +110,7 @@ pub fn generate_variant( // Also used by internally tagged enums // Implicitly (via `generate_variant`) used by adjacently tagged enums -pub fn generate_newtype_variant( +pub(super) fn generate_newtype_variant( variant_ident: &syn::Ident, params: &Parameters, field: &Field, diff --git a/serde_derive/src/de/identifier.rs b/serde_derive/src/de/identifier.rs index 1b347b35..d90903bf 100644 --- a/serde_derive/src/de/identifier.rs +++ b/serde_derive/src/de/identifier.rs @@ -10,7 +10,7 @@ use quote::{quote, ToTokens}; // Generates `Deserialize::deserialize` body for an enum with // `serde(field_identifier)` or `serde(variant_identifier)` attribute. -pub fn generate_body( +pub(super) fn generate_body( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, @@ -120,7 +120,7 @@ pub fn generate_body( } } -pub fn generate_identifier( +pub(super) fn generate_identifier( deserialized_fields: &[FieldWithAliases], has_flatten: bool, is_variant: bool, diff --git a/serde_derive/src/de/struct_.rs b/serde_derive/src/de/struct_.rs index 4d80e08f..09e13d80 100644 --- a/serde_derive/src/de/struct_.rs +++ b/serde_derive/src/de/struct_.rs @@ -14,7 +14,7 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; /// Generates `Deserialize::deserialize` body for a `struct Struct {...}` -pub fn generate_body( +pub(super) fn generate_body( params: &Parameters, fields: &[Field], cattrs: &attr::Container, @@ -419,7 +419,7 @@ fn deserialize_map( /// Generates `Deserialize::deserialize_in_place` body for a `struct Struct {...}` #[cfg(feature = "deserialize_in_place")] -pub fn generate_body_in_place( +pub(super) fn generate_body_in_place( params: &Parameters, fields: &[Field], cattrs: &attr::Container, diff --git a/serde_derive/src/de/tuple.rs b/serde_derive/src/de/tuple.rs index 2a2d9f97..7b96ae02 100644 --- a/serde_derive/src/de/tuple.rs +++ b/serde_derive/src/de/tuple.rs @@ -10,7 +10,7 @@ use quote::{quote, quote_spanned}; use syn::spanned::Spanned; /// Generates `Deserialize::deserialize` body for a `struct Tuple(...);` including `struct Newtype(T);` -pub fn generate_body( +pub(super) fn generate_body( params: &Parameters, fields: &[Field], cattrs: &attr::Container, @@ -182,7 +182,7 @@ fn deserialize_newtype_struct( /// Generates `Deserialize::deserialize_in_place` body for a `struct Tuple(...);` including `struct Newtype(T);` #[cfg(feature = "deserialize_in_place")] -pub fn generate_body_in_place( +pub(super) fn generate_body_in_place( params: &Parameters, fields: &[Field], cattrs: &attr::Container, diff --git a/serde_derive/src/de/unit.rs b/serde_derive/src/de/unit.rs index 3bad35e1..34f90808 100644 --- a/serde_derive/src/de/unit.rs +++ b/serde_derive/src/de/unit.rs @@ -5,7 +5,7 @@ use crate::private; use quote::quote; /// Generates `Deserialize::deserialize` body for a `struct Unit;` -pub fn generate_body(params: &Parameters, cattrs: &attr::Container) -> Fragment { +pub(super) fn generate_body(params: &Parameters, cattrs: &attr::Container) -> Fragment { let this_type = ¶ms.this_type; let this_value = ¶ms.this_value; let type_name = cattrs.name().deserialize_name();