serde_derive/de/
enum_internally.rs

1//! Deserialization for internally tagged enums:
2//!
3//! ```ignore
4//! #[serde(tag = "...")]
5//! enum Enum {}
6//! ```
7
8use crate::de::enum_;
9use crate::de::enum_untagged;
10use crate::de::struct_;
11use crate::de::{
12    effective_style, expr_is_missing, field_i, unwrap_to_variant_closure, Parameters, StructForm,
13};
14use crate::fragment::{Expr, Fragment, Match};
15use crate::internals::ast::{Style, Variant};
16use crate::internals::attr;
17use crate::private;
18use quote::quote;
19
20/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(tag)]` attribute
21pub(super) fn deserialize(
22    params: &Parameters,
23    variants: &[Variant],
24    cattrs: &attr::Container,
25    tag: &str,
26) -> Fragment {
27    let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants);
28
29    // Match arms to extract a variant from a string
30    let variant_arms = variants
31        .iter()
32        .enumerate()
33        .filter(|&(_, variant)| !variant.attrs.skip_deserializing())
34        .map(|(i, variant)| {
35            let variant_name = field_i(i);
36
37            let block = Match(deserialize_internally_tagged_variant(
38                params, variant, cattrs,
39            ));
40
41            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "__Field");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::ToTokens::to_tokens(&variant_name, &mut _s);
    ::quote::__private::push_fat_arrow(&mut _s);
    ::quote::ToTokens::to_tokens(&block, &mut _s);
    _s
}quote! {
42                __Field::#variant_name => #block
43            }
44        });
45
46    let expecting = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("internally tagged enum {0}",
                params.type_name()))
    })format!("internally tagged enum {}", params.type_name());
47    let expecting = cattrs.expecting().unwrap_or(&expecting);
48
49    crate::fragment::Fragment::Block({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::ToTokens::to_tokens(&variant_visitor, &mut _s);
        ::quote::ToTokens::to_tokens(&variants_stmt, &mut _s);
        ::quote::__private::push_ident(&mut _s, "let");
        ::quote::__private::push_group(&mut _s,
            ::quote::__private::Delimiter::Parenthesis,
            {
                let mut _s = ::quote::__private::TokenStream::new();
                ::quote::__private::push_ident(&mut _s, "__tag");
                ::quote::__private::push_comma(&mut _s);
                ::quote::__private::push_ident(&mut _s, "__content");
                _s
            });
        ::quote::__private::push_eq(&mut _s);
        ::quote::__private::push_ident(&mut _s, "_serde");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Deserializer");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "deserialize_any");
        ::quote::__private::push_group(&mut _s,
            ::quote::__private::Delimiter::Parenthesis,
            {
                let mut _s = ::quote::__private::TokenStream::new();
                ::quote::__private::push_ident(&mut _s, "__deserializer");
                ::quote::__private::push_comma(&mut _s);
                ::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, "de");
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s,
                    "TaggedContentVisitor");
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_lt(&mut _s);
                ::quote::__private::push_ident(&mut _s, "__Field");
                ::quote::__private::push_gt(&mut _s);
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s, "new");
                ::quote::__private::push_group(&mut _s,
                    ::quote::__private::Delimiter::Parenthesis,
                    {
                        let mut _s = ::quote::__private::TokenStream::new();
                        ::quote::ToTokens::to_tokens(&tag, &mut _s);
                        ::quote::__private::push_comma(&mut _s);
                        ::quote::ToTokens::to_tokens(&expecting, &mut _s);
                        _s
                    });
                _s
            });
        ::quote::__private::push_question(&mut _s);
        ::quote::__private::push_semi(&mut _s);
        ::quote::__private::push_ident(&mut _s, "let");
        ::quote::__private::push_ident(&mut _s, "__deserializer");
        ::quote::__private::push_eq(&mut _s);
        ::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, "de");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "ContentDeserializer");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_lt(&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, "new");
        ::quote::__private::push_group(&mut _s,
            ::quote::__private::Delimiter::Parenthesis,
            {
                let mut _s = ::quote::__private::TokenStream::new();
                ::quote::__private::push_ident(&mut _s, "__content");
                _s
            });
        ::quote::__private::push_semi(&mut _s);
        ::quote::__private::push_ident(&mut _s, "match");
        ::quote::__private::push_ident(&mut _s, "__tag");
        ::quote::__private::push_group(&mut _s,
            ::quote::__private::Delimiter::Brace,
            {
                let mut _s = ::quote::__private::TokenStream::new();
                {
                    use ::quote::__private::ext::*;
                    let has_iter = ::quote::__private::HasIterator::<false>;
                    #[allow(unused_mut)]
                    let (mut variant_arms, i) = variant_arms.quote_into_iter();
                    let has_iter = has_iter | i;
                    <_ as
                            ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                    while true {
                        let variant_arms =
                            match variant_arms.next() {
                                Some(_x) => ::quote::__private::RepInterp(_x),
                                None => break,
                            };
                        ::quote::ToTokens::to_tokens(&variant_arms, &mut _s);
                    }
                }
                _s
            });
        _s
    });quote_block! {
50        #variant_visitor
51
52        #variants_stmt
53
54        let (__tag, __content) = _serde::Deserializer::deserialize_any(
55            __deserializer,
56            _serde::#private::de::TaggedContentVisitor::<__Field>::new(#tag, #expecting))?;
57        let __deserializer = _serde::#private::de::ContentDeserializer::<__D::Error>::new(__content);
58
59        match __tag {
60            #(#variant_arms)*
61        }
62    }
63}
64
65// Generates significant part of the visit_seq and visit_map bodies of visitors
66// for the variants of internally tagged enum.
67fn deserialize_internally_tagged_variant(
68    params: &Parameters,
69    variant: &Variant,
70    cattrs: &attr::Container,
71) -> Fragment {
72    if let Some(path) = variant.attrs.deserialize_with() {
73        let unwrap_fn = unwrap_to_variant_closure(params, variant, false);
74        return crate::fragment::Fragment::Block({
        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, "Result");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "map");
        ::quote::__private::push_group(&mut _s,
            ::quote::__private::Delimiter::Parenthesis,
            {
                let mut _s = ::quote::__private::TokenStream::new();
                ::quote::ToTokens::to_tokens(&path, &mut _s);
                ::quote::__private::push_group(&mut _s,
                    ::quote::__private::Delimiter::Parenthesis,
                    {
                        let mut _s = ::quote::__private::TokenStream::new();
                        ::quote::__private::push_ident(&mut _s, "__deserializer");
                        _s
                    });
                ::quote::__private::push_comma(&mut _s);
                ::quote::ToTokens::to_tokens(&unwrap_fn, &mut _s);
                _s
            });
        _s
    })quote_block! {
75            _serde::#private::Result::map(#path(__deserializer), #unwrap_fn)
76        };
77    }
78
79    let variant_ident = &variant.ident;
80
81    match effective_style(variant) {
82        Style::Unit => {
83            let this_value = &params.this_value;
84            let type_name = params.type_name();
85            let variant_name = variant.ident.to_string();
86            let default = variant.fields.first().map(|field| {
87                let default = Expr(expr_is_missing(field, cattrs));
88                {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&default, &mut _s);
            _s
        });
    _s
}quote!((#default))
89            });
90            crate::fragment::Fragment::Block({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_ident(&mut _s, "_serde");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Deserializer");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "deserialize_any");
        ::quote::__private::push_group(&mut _s,
            ::quote::__private::Delimiter::Parenthesis,
            {
                let mut _s = ::quote::__private::TokenStream::new();
                ::quote::__private::push_ident(&mut _s, "__deserializer");
                ::quote::__private::push_comma(&mut _s);
                ::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, "de");
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s,
                    "InternallyTaggedUnitVisitor");
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s, "new");
                ::quote::__private::push_group(&mut _s,
                    ::quote::__private::Delimiter::Parenthesis,
                    {
                        let mut _s = ::quote::__private::TokenStream::new();
                        ::quote::ToTokens::to_tokens(&type_name, &mut _s);
                        ::quote::__private::push_comma(&mut _s);
                        ::quote::ToTokens::to_tokens(&variant_name, &mut _s);
                        _s
                    });
                _s
            });
        ::quote::__private::push_question(&mut _s);
        ::quote::__private::push_semi(&mut _s);
        ::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::ToTokens::to_tokens(&this_value, &mut _s);
                ::quote::__private::push_colon2(&mut _s);
                ::quote::ToTokens::to_tokens(&variant_ident, &mut _s);
                ::quote::ToTokens::to_tokens(&default, &mut _s);
                _s
            });
        _s
    });quote_block! {
91                _serde::Deserializer::deserialize_any(__deserializer, _serde::#private::de::InternallyTaggedUnitVisitor::new(#type_name, #variant_name))?;
92                _serde::#private::Ok(#this_value::#variant_ident #default)
93            }
94        }
95        Style::Newtype => {
96            enum_untagged::deserialize_newtype_variant(variant_ident, params, &variant.fields[0])
97        }
98        Style::Struct => struct_::deserialize(
99            params,
100            &variant.fields,
101            cattrs,
102            StructForm::InternallyTagged(variant_ident),
103        ),
104        Style::Tuple => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("checked in serde_derive_internals")));
}unreachable!("checked in serde_derive_internals"),
105    }
106}