//! Deserialization for externally tagged enums: //! //! ```ignore //! enum Enum {} //! ``` use crate::de::enum_; use crate::de::struct_; use crate::de::tuple; use crate::de::{ expr_is_missing, field_i, unwrap_to_variant_closure, wrap_deserialize_field_with, wrap_deserialize_with, Parameters, StructForm, TupleForm, }; use crate::fragment::{Expr, Fragment, Match}; use crate::internals::ast::{Field, Style, Variant}; use crate::internals::attr; use crate::private; use proc_macro2::TokenStream; use quote::{quote, quote_spanned}; use syn::spanned::Spanned; /// Generates `Deserialize::deserialize` body for an `enum Enum {...}` without additional attributes pub(super) fn deserialize( params: &Parameters, variants: &[Variant], cattrs: &attr::Container, ) -> Fragment { let this_type = ¶ms.this_type; let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics_with_de_lifetime(); let delife = params.borrowed.de_lifetime(); let type_name = cattrs.name().deserialize_name(); let expecting = format!("enum {}", params.type_name()); let expecting = cattrs.expecting().unwrap_or(&expecting); let (variants_stmt, variant_visitor) = enum_::prepare_enum_variant_enum(variants); // Match arms to extract a variant from a string let variant_arms = variants .iter() .enumerate() .filter(|&(_, variant)| !variant.attrs.skip_deserializing()) .map(|(i, variant)| { let variant_name = field_i(i); let block = Match(deserialize_externally_tagged_variant( params, variant, cattrs, )); quote! { (__Field::#variant_name, __variant) => #block } }); let all_skipped = variants .iter() .all(|variant| variant.attrs.skip_deserializing()); let match_variant = if all_skipped { // This is an empty enum like `enum Impossible {}` or an enum in which // all variants have `#[serde(skip_deserializing)]`. quote! { // FIXME: Once feature(exhaustive_patterns) is stable: // let _serde::#private::Err(__err) = _serde::de::EnumAccess::variant::<__Field>(__data); // _serde::#private::Err(__err) _serde::#private::Result::map( _serde::de::EnumAccess::variant::<__Field>(__data), |(__impossible, _)| match __impossible {}) } } else { quote! { match _serde::de::EnumAccess::variant(__data)? { #(#variant_arms)* } } }; quote_block! { #variant_visitor #[doc(hidden)] struct __Visitor #de_impl_generics #where_clause { marker: _serde::#private::PhantomData<#this_type #ty_generics>, lifetime: _serde::#private::PhantomData<&#delife ()>, } #[automatically_derived] impl #de_impl_generics _serde::de::Visitor<#delife> for __Visitor #de_ty_generics #where_clause { type Value = #this_type #ty_generics; fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { _serde::#private::Formatter::write_str(__formatter, #expecting) } fn visit_enum<__A>(self, __data: __A) -> _serde::#private::Result where __A: _serde::de::EnumAccess<#delife>, { #match_variant } } #variants_stmt _serde::Deserializer::deserialize_enum( __deserializer, #type_name, VARIANTS, __Visitor { marker: _serde::#private::PhantomData::<#this_type #ty_generics>, lifetime: _serde::#private::PhantomData, }, ) } } fn deserialize_externally_tagged_variant( params: &Parameters, variant: &Variant, cattrs: &attr::Container, ) -> Fragment { if let Some(path) = variant.attrs.deserialize_with() { let (wrapper, wrapper_ty, unwrap_fn) = wrap_deserialize_variant_with(params, variant, path); return quote_block! { #wrapper _serde::#private::Result::map( _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), #unwrap_fn) }; } let variant_ident = &variant.ident; match variant.style { Style::Unit => { let this_value = ¶ms.this_value; quote_block! { _serde::de::VariantAccess::unit_variant(__variant)?; _serde::#private::Ok(#this_value::#variant_ident) } } Style::Newtype => deserialize_externally_tagged_newtype_variant( variant_ident, params, &variant.fields[0], cattrs, ), Style::Tuple => tuple::deserialize( params, &variant.fields, cattrs, TupleForm::ExternallyTagged(variant_ident), ), Style::Struct => struct_::deserialize( params, &variant.fields, cattrs, StructForm::ExternallyTagged(variant_ident), ), } } fn wrap_deserialize_variant_with( params: &Parameters, variant: &Variant, deserialize_with: &syn::ExprPath, ) -> (TokenStream, TokenStream, TokenStream) { let field_tys = variant.fields.iter().map(|field| field.ty); let (wrapper, wrapper_ty) = wrap_deserialize_with(params, "e!((#(#field_tys),*)), deserialize_with); let unwrap_fn = unwrap_to_variant_closure(params, variant, true); (wrapper, wrapper_ty, unwrap_fn) } fn deserialize_externally_tagged_newtype_variant( variant_ident: &syn::Ident, params: &Parameters, field: &Field, cattrs: &attr::Container, ) -> Fragment { let this_value = ¶ms.this_value; if field.attrs.skip_deserializing() { let default = Expr(expr_is_missing(field, cattrs)); return quote_block! { _serde::de::VariantAccess::unit_variant(__variant)?; _serde::#private::Ok(#this_value::#variant_ident(#default)) }; } match field.attrs.deserialize_with() { None => { let field_ty = field.ty; let span = field.original.span(); let func = quote_spanned!(span=> _serde::de::VariantAccess::newtype_variant::<#field_ty>); quote_expr! { _serde::#private::Result::map(#func(__variant), #this_value::#variant_ident) } } Some(path) => { let (wrapper, wrapper_ty) = wrap_deserialize_field_with(params, field.ty, path); quote_block! { #wrapper _serde::#private::Result::map( _serde::de::VariantAccess::newtype_variant::<#wrapper_ty>(__variant), |__wrapper| #this_value::#variant_ident(__wrapper.value)) } } } }