mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-20 03:21:03 +00:00
Move body generator for enums to its own module
Cut-paste
This commit is contained in:
+2
-85
@@ -12,6 +12,7 @@ use syn::punctuated::Punctuated;
|
|||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::{parse_quote, Ident, Index, Member};
|
use syn::{parse_quote, Ident, Index, Member};
|
||||||
|
|
||||||
|
mod enum_;
|
||||||
mod enum_adjacently;
|
mod enum_adjacently;
|
||||||
mod enum_externally;
|
mod enum_externally;
|
||||||
mod enum_internally;
|
mod enum_internally;
|
||||||
@@ -307,7 +308,7 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
|
|||||||
deserialize_try_from(type_try_from)
|
deserialize_try_from(type_try_from)
|
||||||
} else if let attr::Identifier::No = cont.attrs.identifier() {
|
} else if let attr::Identifier::No = cont.attrs.identifier() {
|
||||||
match &cont.data {
|
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) => {
|
Data::Struct(Style::Struct, fields) => {
|
||||||
deserialize_struct(params, fields, &cont.attrs, StructForm::Struct)
|
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> {
|
struct FieldWithAliases<'a> {
|
||||||
ident: Ident,
|
ident: Ident,
|
||||||
aliases: &'a BTreeSet<Name>,
|
aliases: &'a BTreeSet<Name>,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -5,8 +5,9 @@
|
|||||||
//! enum Enum {}
|
//! enum Enum {}
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
use crate::de::enum_;
|
||||||
use crate::de::enum_untagged;
|
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::fragment::{Fragment, Match};
|
||||||
use crate::internals::ast::{Style, Variant};
|
use crate::internals::ast::{Style, Variant};
|
||||||
use crate::internals::attr;
|
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 (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics();
|
||||||
let delife = params.borrowed.de_lifetime();
|
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
|
let variant_arms: &Vec<_> = &variants
|
||||||
.iter()
|
.iter()
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
//! enum Enum {}
|
//! enum Enum {}
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
use crate::de::enum_;
|
||||||
use crate::de::{
|
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,
|
unwrap_to_variant_closure, wrap_deserialize_field_with, wrap_deserialize_with, Parameters,
|
||||||
StructForm, TupleForm,
|
StructForm, TupleForm,
|
||||||
};
|
};
|
||||||
@@ -31,7 +32,7 @@ pub fn deserialize_externally_tagged_enum(
|
|||||||
let expecting = format!("enum {}", params.type_name());
|
let expecting = format!("enum {}", params.type_name());
|
||||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
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
|
// Match arms to extract a variant from a string
|
||||||
let variant_arms = variants
|
let variant_arms = variants
|
||||||
|
|||||||
@@ -5,9 +5,10 @@
|
|||||||
//! enum Enum {}
|
//! enum Enum {}
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
use crate::de::enum_;
|
||||||
use crate::de::enum_untagged;
|
use crate::de::enum_untagged;
|
||||||
use crate::de::{
|
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,
|
unwrap_to_variant_closure, Parameters, StructForm,
|
||||||
};
|
};
|
||||||
use crate::fragment::{Expr, Fragment, Match};
|
use crate::fragment::{Expr, Fragment, Match};
|
||||||
@@ -23,7 +24,7 @@ pub fn deserialize_internally_tagged_enum(
|
|||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
tag: &str,
|
tag: &str,
|
||||||
) -> Fragment {
|
) -> 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
|
// Match arms to extract a variant from a string
|
||||||
let variant_arms = variants
|
let variant_arms = variants
|
||||||
|
|||||||
Reference in New Issue
Block a user