Move body generator for enums to its own module

Cut-paste
This commit is contained in:
Mingun 2025-09-20 00:15:59 +05:00
parent ec13eb4ed6
commit 19956e6b8e
5 changed files with 106 additions and 91 deletions

View File

@ -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<Name>,

View File

@ -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)
}

View File

@ -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()

View File

@ -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

View File

@ -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