1use crate::de::enum_adjacently;
2use crate::de::enum_externally;
3use crate::de::enum_internally;
4use crate::de::enum_untagged;
5use crate::de::identifier;
6use crate::de::{field_i, FieldWithAliases, Parameters};
7use crate::fragment::{Expr, Fragment, Stmts};
8use crate::internals::ast::Variant;
9use crate::internals::attr;
10use crate::private;
11use proc_macro2::TokenStream;
12use quote::quote;
13
14pub(super) fn deserialize(
16 params: &Parameters,
17 variants: &[Variant],
18 cattrs: &attr::Container,
19) -> Fragment {
20 match variants.iter().position(|var| var.attrs.untagged()) {
22 Some(variant_idx) => {
23 let (tagged, untagged) = variants.split_at(variant_idx);
24 let tagged_frag = Expr(deserialize_homogeneous_enum(params, tagged, cattrs));
25 let first_attempt = quote! {
29 if let _serde::#private::Result::<_, __D::Error>::Ok(__ok) = (|| #tagged_frag)() {
30 return _serde::#private::Ok(__ok);
31 }
32 };
33 enum_untagged::deserialize(params, untagged, cattrs, Some(first_attempt))
34 }
35 None => deserialize_homogeneous_enum(params, variants, cattrs),
36 }
37}
38
39fn deserialize_homogeneous_enum(
40 params: &Parameters,
41 variants: &[Variant],
42 cattrs: &attr::Container,
43) -> Fragment {
44 match cattrs.tag() {
45 attr::TagType::External => enum_externally::deserialize(params, variants, cattrs),
46 attr::TagType::Internal { tag } => {
47 enum_internally::deserialize(params, variants, cattrs, tag)
48 }
49 attr::TagType::Adjacent { tag, content } => {
50 enum_adjacently::deserialize(params, variants, cattrs, tag, content)
51 }
52 attr::TagType::None => enum_untagged::deserialize(params, variants, cattrs, None),
53 }
54}
55
56pub fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) {
57 let deserialized_variants = variants
58 .iter()
59 .enumerate()
60 .filter(|&(_i, variant)| !variant.attrs.skip_deserializing());
61
62 let fallthrough = deserialized_variants
63 .clone()
64 .find(|(_i, variant)| variant.attrs.other())
65 .map(|(i, _variant)| {
66 let ignore_variant = field_i(i);
67 quote!(_serde::#private::Ok(__Field::#ignore_variant))
68 });
69
70 let variants_stmt = {
71 let variant_names = deserialized_variants
72 .clone()
73 .flat_map(|(_i, variant)| variant.attrs.aliases());
74 quote! {
75 #[doc(hidden)]
76 const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
77 }
78 };
79
80 let deserialized_variants: Vec<_> = deserialized_variants
81 .map(|(i, variant)| FieldWithAliases {
82 ident: field_i(i),
83 aliases: variant.attrs.aliases(),
84 })
85 .collect();
86
87 let variant_visitor = Stmts(identifier::deserialize_generated(
88 &deserialized_variants,
89 false, true,
91 None,
92 fallthrough,
93 ));
94
95 (variants_stmt, variant_visitor)
96}