From 19956e6b8e57188c9d94a5aad0dbe0279ed5513e Mon Sep 17 00:00:00 2001 From: Mingun Date: Sat, 20 Sep 2025 00:15:59 +0500 Subject: [PATCH] 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