serde_derive/de/
enum_untagged.rs

1//! Deserialization for untagged enums:
2//!
3//! ```ignore
4//! #[serde(untagged)]
5//! enum Enum {}
6//! ```
7
8use crate::de::struct_;
9use crate::de::tuple;
10use crate::de::{
11    effective_style, expr_is_missing, unwrap_to_variant_closure, Parameters, StructForm, TupleForm,
12};
13use crate::fragment::{Expr, Fragment};
14use crate::internals::ast::{Field, Style, Variant};
15use crate::internals::attr;
16use crate::private;
17use proc_macro2::TokenStream;
18use quote::{quote, quote_spanned};
19use syn::spanned::Spanned;
20
21/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` with `#[serde(untagged)]` attribute
22pub(super) fn deserialize(
23    params: &Parameters,
24    variants: &[Variant],
25    cattrs: &attr::Container,
26    first_attempt: Option<TokenStream>,
27) -> Fragment {
28    let attempts = variants
29        .iter()
30        .filter(|variant| !variant.attrs.skip_deserializing())
31        .map(|variant| Expr(deserialize_variant(params, variant, cattrs)));
32    // TODO this message could be better by saving the errors from the failed
33    // attempts. The heuristic used by TOML was to count the number of fields
34    // processed before an error, and use the error that happened after the
35    // largest number of fields. I'm not sure I like that. Maybe it would be
36    // better to save all the errors and combine them into one message that
37    // explains why none of the variants matched.
38    let fallthrough_msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("data did not match any variant of untagged enum {0}",
                params.type_name()))
    })format!(
39        "data did not match any variant of untagged enum {}",
40        params.type_name()
41    );
42    let fallthrough_msg = cattrs.expecting().unwrap_or(&fallthrough_msg);
43
44    let private2 = private;
45    crate::fragment::Fragment::Block({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_ident(&mut _s, "let");
        ::quote::__private::push_ident(&mut _s, "__content");
        ::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, "de");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "DeserializeSeed");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "deserialize");
        ::quote::__private::push_group(&mut _s,
            ::quote::__private::Delimiter::Parenthesis,
            {
                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, "de");
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s, "ContentVisitor");
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s, "new");
                ::quote::__private::push_group(&mut _s,
                    ::quote::__private::Delimiter::Parenthesis,
                    ::quote::__private::TokenStream::new());
                ::quote::__private::push_comma(&mut _s);
                ::quote::__private::push_ident(&mut _s, "__deserializer");
                _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, "ContentRefDeserializer");
        ::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_and(&mut _s);
                ::quote::__private::push_ident(&mut _s, "__content");
                _s
            });
        ::quote::__private::push_semi(&mut _s);
        ::quote::ToTokens::to_tokens(&first_attempt, &mut _s);
        {
            use ::quote::__private::ext::*;
            let has_iter = ::quote::__private::HasIterator::<false>;
            #[allow(unused_mut)]
            let (mut private2, i) = private2.quote_into_iter();
            let has_iter = has_iter | i;
            #[allow(unused_mut)]
            let (mut attempts, i) = attempts.quote_into_iter();
            let has_iter = has_iter | i;
            #[allow(unused_mut)]
            let (mut private2, i) = private2.quote_into_iter();
            let has_iter = has_iter | i;
            <_ as
                    ::quote::__private::CheckHasIterator<true>>::check(has_iter);
            while true {
                let private2 =
                    match private2.next() {
                        Some(_x) => ::quote::__private::RepInterp(_x),
                        None => break,
                    };
                let attempts =
                    match attempts.next() {
                        Some(_x) => ::quote::__private::RepInterp(_x),
                        None => break,
                    };
                let private2 =
                    match private2.next() {
                        Some(_x) => ::quote::__private::RepInterp(_x),
                        None => break,
                    };
                ::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(&private2, &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::ToTokens::to_tokens(&attempts, &mut _s);
                ::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(&private2, &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
                    });
            }
        }
        ::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, "Err");
        ::quote::__private::push_group(&mut _s,
            ::quote::__private::Delimiter::Parenthesis,
            {
                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, "de");
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s, "Error");
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s, "custom");
                ::quote::__private::push_group(&mut _s,
                    ::quote::__private::Delimiter::Parenthesis,
                    {
                        let mut _s = ::quote::__private::TokenStream::new();
                        ::quote::ToTokens::to_tokens(&fallthrough_msg, &mut _s);
                        _s
                    });
                _s
            });
        _s
    });quote_block! {
46        let __content = _serde::de::DeserializeSeed::deserialize(_serde::#private::de::ContentVisitor::new(), __deserializer)?;
47        let __deserializer = _serde::#private::de::ContentRefDeserializer::<__D::Error>::new(&__content);
48
49        #first_attempt
50
51        #(
52            if let _serde::#private2::Ok(__ok) = #attempts {
53                return _serde::#private2::Ok(__ok);
54            }
55        )*
56
57        _serde::#private::Err(_serde::de::Error::custom(#fallthrough_msg))
58    }
59}
60
61// Also used by adjacently tagged enums
62pub(super) fn deserialize_variant(
63    params: &Parameters,
64    variant: &Variant,
65    cattrs: &attr::Container,
66) -> Fragment {
67    if let Some(path) = variant.attrs.deserialize_with() {
68        let unwrap_fn = unwrap_to_variant_closure(params, variant, false);
69        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! {
70            _serde::#private::Result::map(#path(__deserializer), #unwrap_fn)
71        };
72    }
73
74    let variant_ident = &variant.ident;
75
76    match effective_style(variant) {
77        Style::Unit => {
78            let this_value = &params.this_value;
79            let type_name = params.type_name();
80            let variant_name = variant.ident.to_string();
81            let default = variant.fields.first().map(|field| {
82                let default = Expr(expr_is_missing(field, cattrs));
83                {
    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))
84            });
85            crate::fragment::Fragment::Expr({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_ident(&mut _s, "match");
        ::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,
                    "UntaggedUnitVisitor");
                ::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_group(&mut _s,
            ::quote::__private::Delimiter::Brace,
            {
                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_group(&mut _s,
                            ::quote::__private::Delimiter::Parenthesis,
                            ::quote::__private::TokenStream::new());
                        _s
                    });
                ::quote::__private::push_fat_arrow(&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
                    });
                ::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, "Err");
                ::quote::__private::push_group(&mut _s,
                    ::quote::__private::Delimiter::Parenthesis,
                    {
                        let mut _s = ::quote::__private::TokenStream::new();
                        ::quote::__private::push_ident(&mut _s, "__err");
                        _s
                    });
                ::quote::__private::push_fat_arrow(&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, "Err");
                ::quote::__private::push_group(&mut _s,
                    ::quote::__private::Delimiter::Parenthesis,
                    {
                        let mut _s = ::quote::__private::TokenStream::new();
                        ::quote::__private::push_ident(&mut _s, "__err");
                        _s
                    });
                ::quote::__private::push_comma(&mut _s);
                _s
            });
        _s
    });quote_expr! {
86                match _serde::Deserializer::deserialize_any(
87                    __deserializer,
88                    _serde::#private::de::UntaggedUnitVisitor::new(#type_name, #variant_name)
89                ) {
90                    _serde::#private::Ok(()) => _serde::#private::Ok(#this_value::#variant_ident #default),
91                    _serde::#private::Err(__err) => _serde::#private::Err(__err),
92                }
93            }
94        }
95        Style::Newtype => deserialize_newtype_variant(variant_ident, params, &variant.fields[0]),
96        Style::Tuple => tuple::deserialize(
97            params,
98            &variant.fields,
99            cattrs,
100            TupleForm::Untagged(variant_ident),
101        ),
102        Style::Struct => struct_::deserialize(
103            params,
104            &variant.fields,
105            cattrs,
106            StructForm::Untagged(variant_ident),
107        ),
108    }
109}
110
111// Also used by internally tagged enums
112// Implicitly (via `generate_variant`) used by adjacently tagged enums
113pub(super) fn deserialize_newtype_variant(
114    variant_ident: &syn::Ident,
115    params: &Parameters,
116    field: &Field,
117) -> Fragment {
118    let this_value = &params.this_value;
119    let field_ty = field.ty;
120    match field.attrs.deserialize_with() {
121        None => {
122            let span = field.original.span();
123            let func = {
    let mut _s = ::quote::__private::TokenStream::new();
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    ::quote::__private::push_lt_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "as");
    ::quote::__private::push_ident_spanned(&mut _s, _span, "_serde");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "Deserialize");
    ::quote::__private::push_gt_spanned(&mut _s, _span);
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "deserialize");
    _s
}quote_spanned!(span=> <#field_ty as _serde::Deserialize>::deserialize);
124            crate::fragment::Fragment::Expr({
        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(&func, &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(&this_value, &mut _s);
                ::quote::__private::push_colon2(&mut _s);
                ::quote::ToTokens::to_tokens(&variant_ident, &mut _s);
                _s
            });
        _s
    });quote_expr! {
125                _serde::#private::Result::map(#func(__deserializer), #this_value::#variant_ident)
126            }
127        }
128        Some(path) => {
129            crate::fragment::Fragment::Block({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_ident(&mut _s, "let");
        ::quote::__private::push_ident(&mut _s, "__value");
        ::quote::__private::push_colon(&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, "Result");
        ::quote::__private::push_lt(&mut _s);
        ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
        ::quote::__private::push_comma(&mut _s);
        ::quote::__private::push_underscore(&mut _s);
        ::quote::__private::push_gt(&mut _s);
        ::quote::__private::push_eq(&mut _s);
        ::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_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, "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::__private::push_ident(&mut _s, "__value");
                ::quote::__private::push_comma(&mut _s);
                ::quote::ToTokens::to_tokens(&this_value, &mut _s);
                ::quote::__private::push_colon2(&mut _s);
                ::quote::ToTokens::to_tokens(&variant_ident, &mut _s);
                _s
            });
        _s
    });quote_block! {
130                let __value: _serde::#private::Result<#field_ty, _> = #path(__deserializer);
131                _serde::#private::Result::map(__value, #this_value::#variant_ident)
132            }
133        }
134    }
135}