mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-22 05:37:58 +00:00
97 lines
3.4 KiB
Rust
97 lines
3.4 KiB
Rust
use crate::de::enum_adjacently;
|
|
use crate::de::enum_externally;
|
|
use crate::de::enum_internally;
|
|
use crate::de::enum_untagged;
|
|
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;
|
|
use crate::private;
|
|
use proc_macro2::TokenStream;
|
|
use quote::quote;
|
|
|
|
/// Generates `Deserialize::deserialize` body for an `enum Enum {...}`
|
|
pub(super) fn deserialize(
|
|
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 first_attempt = quote! {
|
|
if let _serde::#private::Result::<_, __D::Error>::Ok(__ok) = (|| #tagged_frag)() {
|
|
return _serde::#private::Ok(__ok);
|
|
}
|
|
};
|
|
enum_untagged::deserialize(params, untagged, cattrs, Some(first_attempt))
|
|
}
|
|
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(params, variants, cattrs),
|
|
attr::TagType::Internal { tag } => {
|
|
enum_internally::deserialize(params, variants, cattrs, tag)
|
|
}
|
|
attr::TagType::Adjacent { tag, content } => {
|
|
enum_adjacently::deserialize(params, variants, cattrs, tag, content)
|
|
}
|
|
attr::TagType::None => enum_untagged::deserialize(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(identifier::deserialize_generated(
|
|
&deserialized_variants,
|
|
false, // variant identifiers do not depend on the presence of flatten fields
|
|
true,
|
|
None,
|
|
fallthrough,
|
|
));
|
|
|
|
(variants_stmt, variant_visitor)
|
|
}
|