serde_derive/de/
enum_.rs

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
14/// Generates `Deserialize::deserialize` body for an `enum Enum {...}`
15pub(super) fn deserialize(
16    params: &Parameters,
17    variants: &[Variant],
18    cattrs: &attr::Container,
19) -> Fragment {
20    // The variants have already been checked (in ast.rs) that all untagged variants appear at the end
21    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            // Ignore any error associated with non-untagged deserialization so that we
26            // can fall through to the untagged variants. This may be infallible so we
27            // need to provide the error type.
28            let first_attempt = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "if");
    ::quote::__private::push_ident(&mut _s, "let");
    ::quote::__private::push_ident(&mut _s, "_serde");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&private, &mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Result");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_underscore(&mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__D");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Error");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Ok");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "__ok");
            _s
        });
    ::quote::__private::push_eq(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_or_or(&mut _s);
            ::quote::ToTokens::to_tokens(&tagged_frag, &mut _s);
            _s
        });
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "return");
            ::quote::__private::push_ident(&mut _s, "_serde");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::ToTokens::to_tokens(&private, &mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Ok");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "__ok");
                    _s
                });
            ::quote::__private::push_semi(&mut _s);
            _s
        });
    _s
}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            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "_serde");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&private, &mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Ok");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "__Field");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::ToTokens::to_tokens(&ignore_variant, &mut _s);
            _s
        });
    _s
}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        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "doc");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "hidden");
                    _s
                });
            _s
        });
    ::quote::__private::push_ident(&mut _s, "const");
    ::quote::__private::push_ident(&mut _s, "VARIANTS");
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_lifetime(&mut _s, "\'static");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_and(&mut _s);
            ::quote::__private::push_lifetime(&mut _s, "\'static");
            ::quote::__private::push_ident(&mut _s, "str");
            _s
        });
    ::quote::__private::push_eq(&mut _s);
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            {
                use ::quote::__private::ext::*;
                let mut _i = 0usize;
                let has_iter = ::quote::__private::HasIterator::<false>;
                #[allow(unused_mut)]
                let (mut variant_names, i) = variant_names.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let variant_names =
                        match variant_names.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    if _i > 0 { ::quote::__private::push_comma(&mut _s); }
                    _i += 1;
                    ::quote::ToTokens::to_tokens(&variant_names, &mut _s);
                }
            }
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    _s
}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, // variant identifiers do not depend on the presence of flatten fields
90        true,
91        None,
92        fallthrough,
93    ));
94
95    (variants_stmt, variant_visitor)
96}