serde_derive/de/
enum_externally.rs

1//! Deserialization for externally tagged enums:
2//!
3//! ```ignore
4//! enum Enum {}
5//! ```
6
7use crate::de::enum_;
8use crate::de::struct_;
9use crate::de::tuple;
10use crate::de::{
11    expr_is_missing, field_i, unwrap_to_variant_closure, wrap_deserialize_field_with,
12    wrap_deserialize_with, Parameters, StructForm, TupleForm,
13};
14use crate::fragment::{Expr, Fragment, Match};
15use crate::internals::ast::{Field, Style, Variant};
16use crate::internals::attr;
17use crate::private;
18use proc_macro2::TokenStream;
19use quote::{quote, quote_spanned};
20use syn::spanned::Spanned;
21
22/// Generates `Deserialize::deserialize` body for an `enum Enum {...}` without additional attributes
23pub(super) fn deserialize(
24    params: &Parameters,
25    variants: &[Variant],
26    cattrs: &attr::Container,
27) -> Fragment {
28    let this_type = &params.this_type;
29    let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
30        params.generics_with_de_lifetime();
31    let delife = params.borrowed.de_lifetime();
32
33    let type_name = cattrs.name().deserialize_name();
34    let expecting = format!("enum {}", params.type_name());
35    let expecting = cattrs.expecting().unwrap_or(&expecting);
36
37    let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants);
38
39    // Match arms to extract a variant from a string
40    let variant_arms = variants
41        .iter()
42        .enumerate()
43        .filter(|&(_, variant)| !variant.attrs.skip_deserializing())
44        .map(|(i, variant)| {
45            let variant_name = field_i(i);
46
47            let block = Match(deserialize_externally_tagged_variant(
48                params, variant, cattrs,
49            ));
50
51            quote! {
52                (__Field::#variant_name, __variant) => #block
53            }
54        });
55
56    let all_skipped = variants
57        .iter()
58        .all(|variant| variant.attrs.skip_deserializing());
59    let match_variant = if all_skipped {
60        // This is an empty enum like `enum Impossible {}` or an enum in which
61        // all variants have `#[serde(skip_deserializing)]`.
62        quote! {
63            // FIXME: Once feature(exhaustive_patterns) is stable:
64            // let _serde::#private::Err(__err) = _serde::de::EnumAccess::variant::<__Field>(__data);
65            // _serde::#private::Err(__err)
66            _serde::#private::Result::map(
67                _serde::de::EnumAccess::variant::<__Field>(__data),
68                |(__impossible, _)| match __impossible {})
69        }
70    } else {
71        quote! {
72            match _serde::de::EnumAccess::variant(__data)? {
73                #(#variant_arms)*
74            }
75        }
76    };
77
78    quote_block! {
79        #variant_visitor
80
81        #[doc(hidden)]
82        struct __Visitor #de_impl_generics #where_clause {
83            marker: _serde::#private::PhantomData<#this_type #ty_generics>,
84            lifetime: _serde::#private::PhantomData<&#delife ()>,
85        }
86
87        #[automatically_derived]
88        impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause {
89            type Value = #this_type #ty_generics;
90
91            fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result {
92                _serde::#private::Formatter::write_str(__formatter, #expecting)
93            }
94
95            fn visit_enum<__A>(self, __data: __A) -> _serde::#private::Result<Self::Value, __A::Error>
96            where
97                __A: _serde::de::EnumAccess<#delife>,
98            {
99                #match_variant
100            }
101        }
102
103        #variants_stmt
104
105        _serde::Deserializer::deserialize_enum(
106            __deserializer,
107            #type_name,
108            VARIANTS,
109            __Visitor {
110                marker: _serde::#private::PhantomData::<#this_type #ty_generics>,
111                lifetime: _serde::#private::PhantomData,
112            },
113        )
114    }
115}
116
117fn deserialize_externally_tagged_variant(
118    params: &Parameters,
119    variant: &Variant,
120    cattrs: &attr::Container,
121) -> Fragment {
122    if let Some(path) = variant.attrs.deserialize_with() {
123        let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path);
124        return quote_block! {
125            #wrapper
126            _serde::#private::Result::map(
127                _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn)
128        };
129    }
130
131    let variant_ident = &variant.ident;
132
133    match variant.style {
134        Style::Unit => {
135            let this_value = &params.this_value;
136            quote_block! {
137                _serde::de::VariantAccess::unit_variant(__variant)?;
138                _serde::#private::Ok(#this_value::#variant_ident)
139            }
140        }
141        Style::Newtype => deserialize_externally_tagged_newtype_variant(
142            variant_ident,
143            params,
144            &variant.fields[0],
145            cattrs,
146        ),
147        Style::Tuple => tuple::deserialize(
148            params,
149            &variant.fields,
150            cattrs,
151            TupleForm::ExternallyTagged(variant_ident),
152        ),
153        Style::Struct => struct_::deserialize(
154            params,
155            &variant.fields,
156            cattrs,
157            StructForm::ExternallyTagged(variant_ident),
158        ),
159    }
160}
161
162fn wrap_deserialize_variant_with(
163    params: &Parameters,
164    variant: &Variant,
165    deserialize_with: &syn::ExprPath,
166) -> (TokenStream, TokenStream, TokenStream) {
167    let field_tys = variant.fields.iter().map(|field| field.ty);
168    let (wrapper, wrapper_ty) =
169        wrap_deserialize_with(params, &quote!((#(#field_tys),*)), deserialize_with);
170
171    let unwrap_fn = unwrap_to_variant_closure(params, variant, true);
172
173    (wrapper, wrapper_ty, unwrap_fn)
174}
175
176fn deserialize_externally_tagged_newtype_variant(
177    variant_ident: &syn::Ident,
178    params: &Parameters,
179    field: &Field,
180    cattrs: &attr::Container,
181) -> Fragment {
182    let this_value = &params.this_value;
183
184    if field.attrs.skip_deserializing() {
185        let default = Expr(expr_is_missing(field, cattrs));
186        return quote_block! {
187            _serde::de::VariantAccess::unit_variant(__variant)?;
188            _serde::#private::Ok(#this_value::#variant_ident(#default))
189        };
190    }
191
192    match field.attrs.deserialize_with() {
193        None => {
194            let field_ty = field.ty;
195            let span = field.original.span();
196            let func =
197                quote_spanned!(span=> _serde::de::VariantAccess::newtype_variant::<#field_ty>);
198            quote_expr! {
199                _serde::#private::Result::map(#func(__variant), #this_value::#variant_ident)
200            }
201        }
202        Some(path) => {
203            let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path);
204            quote_block! {
205                #wrapper
206                _serde::#private::Result::map(
207                    _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant),
208                    |__wrapper| #this_value::#variant_ident(__wrapper.value))
209            }
210        }
211    }
212}