diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index b20c840e..835a13c9 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -4,7 +4,7 @@ use crate::internals::ast::{Container, Data, Field, Style, Variant}; use crate::internals::name::Name; use crate::internals::{attr, replace_receiver, ungroup, Ctxt, Derive}; use crate::{bound, dummy, pretend, private, this}; -use proc_macro2::{Literal, Span, TokenStream}; +use proc_macro2::{Span, TokenStream}; use quote::{quote, quote_spanned, ToTokens}; use std::collections::BTreeSet; use std::ptr; @@ -17,6 +17,7 @@ mod enum_adjacently; mod enum_externally; mod enum_internally; mod enum_untagged; +mod identifier; mod struct_; mod tuple; mod unit; @@ -322,7 +323,7 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { } } else { match &cont.data { - Data::Enum(variants) => deserialize_custom_identifier(params, variants, &cont.attrs), + Data::Enum(variants) => identifier::deserialize_custom_identifier(params, variants, &cont.attrs), Data::Struct(_, _) => unreachable!("checked in serde_derive_internals"), } } @@ -651,472 +652,6 @@ struct FieldWithAliases<'a> { aliases: &'a BTreeSet, } -fn deserialize_generated_identifier( - deserialized_fields: &[FieldWithAliases], - has_flatten: bool, - is_variant: bool, - ignore_variant: Option, - fallthrough: Option, -) -> Fragment { - let this_value = quote!(__Field); - let field_idents: &Vec<_> = &deserialized_fields - .iter() - .map(|field| &field.ident) - .collect(); - - let visitor_impl = Stmts(deserialize_identifier( - &this_value, - deserialized_fields, - is_variant, - fallthrough, - None, - !is_variant && has_flatten, - None, - )); - - let lifetime = if !is_variant && has_flatten { - Some(quote!(<'de>)) - } else { - None - }; - - quote_block! { - #[allow(non_camel_case_types)] - #[doc(hidden)] - enum __Field #lifetime { - #(#field_idents,)* - #ignore_variant - } - - #[doc(hidden)] - struct __FieldVisitor; - - #[automatically_derived] - impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { - type Value = __Field #lifetime; - - #visitor_impl - } - - #[automatically_derived] - impl<'de> _serde::Deserialize<'de> for __Field #lifetime { - #[inline] - fn deserialize<__D>(__deserializer: __D) -> _serde::#private::Result - where - __D: _serde::Deserializer<'de>, - { - _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) - } - } - } -} - -// Generates `Deserialize::deserialize` body for an enum with -// `serde(field_identifier)` or `serde(variant_identifier)` attribute. -fn deserialize_custom_identifier( - params: &Parameters, - variants: &[Variant], - cattrs: &attr::Container, -) -> Fragment { - let is_variant = match cattrs.identifier() { - attr::Identifier::Variant => true, - attr::Identifier::Field => false, - attr::Identifier::No => unreachable!(), - }; - - let this_type = params.this_type.to_token_stream(); - let this_value = params.this_value.to_token_stream(); - - let (ordinary, fallthrough, fallthrough_borrowed) = if let Some(last) = variants.last() { - let last_ident = &last.ident; - if last.attrs.other() { - // Process `serde(other)` attribute. It would always be found on the - // last variant (checked in `check_identifier`), so all preceding - // are ordinary variants. - let ordinary = &variants[..variants.len() - 1]; - let fallthrough = quote!(_serde::#private::Ok(#this_value::#last_ident)); - (ordinary, Some(fallthrough), None) - } else if let Style::Newtype = last.style { - let ordinary = &variants[..variants.len() - 1]; - let fallthrough = |value| { - quote! { - _serde::#private::Result::map( - _serde::Deserialize::deserialize( - _serde::#private::de::IdentifierDeserializer::from(#value) - ), - #this_value::#last_ident) - } - }; - ( - ordinary, - Some(fallthrough(quote!(__value))), - Some(fallthrough(quote!(_serde::#private::de::Borrowed( - __value - )))), - ) - } else { - (variants, None, None) - } - } else { - (variants, None, None) - }; - - let idents_aliases: Vec<_> = ordinary - .iter() - .map(|variant| FieldWithAliases { - ident: variant.ident.clone(), - aliases: variant.attrs.aliases(), - }) - .collect(); - - let names = idents_aliases.iter().flat_map(|variant| variant.aliases); - - let names_const = if fallthrough.is_some() { - None - } else if is_variant { - let variants = quote! { - #[doc(hidden)] - const VARIANTS: &'static [&'static str] = &[ #(#names),* ]; - }; - Some(variants) - } else { - let fields = quote! { - #[doc(hidden)] - const FIELDS: &'static [&'static str] = &[ #(#names),* ]; - }; - Some(fields) - }; - - let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); - let delife = params.borrowed.de_lifetime(); - let visitor_impl = Stmts(deserialize_identifier( - &this_value, - &idents_aliases, - is_variant, - fallthrough, - fallthrough_borrowed, - false, - cattrs.expecting(), - )); - - quote_block! { - #names_const - - #[doc(hidden)] - struct __FieldVisitor #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 __FieldVisitor #de_ty_generics #where_clause { - type Value = #this_type #ty_generics; - - #visitor_impl - } - - let __visitor = __FieldVisitor { - marker: _serde::#private::PhantomData::<#this_type #ty_generics>, - lifetime: _serde::#private::PhantomData, - }; - _serde::Deserializer::deserialize_identifier(__deserializer, __visitor) - } -} - -fn deserialize_identifier( - this_value: &TokenStream, - deserialized_fields: &[FieldWithAliases], - is_variant: bool, - fallthrough: Option, - fallthrough_borrowed: Option, - collect_other_fields: bool, - expecting: Option<&str>, -) -> Fragment { - let str_mapping = deserialized_fields.iter().map(|field| { - let ident = &field.ident; - let aliases = field.aliases; - let private2 = private; - // `aliases` also contains a main name - quote! { - #( - #aliases => _serde::#private2::Ok(#this_value::#ident), - )* - } - }); - let bytes_mapping = deserialized_fields.iter().map(|field| { - let ident = &field.ident; - // `aliases` also contains a main name - let aliases = field - .aliases - .iter() - .map(|alias| Literal::byte_string(alias.value.as_bytes())); - let private2 = private; - quote! { - #( - #aliases => _serde::#private2::Ok(#this_value::#ident), - )* - } - }); - - let expecting = expecting.unwrap_or(if is_variant { - "variant identifier" - } else { - "field identifier" - }); - - let bytes_to_str = if fallthrough.is_some() || collect_other_fields { - None - } else { - Some(quote! { - let __value = &_serde::#private::from_utf8_lossy(__value); - }) - }; - - let ( - value_as_str_content, - value_as_borrowed_str_content, - value_as_bytes_content, - value_as_borrowed_bytes_content, - ) = if collect_other_fields { - ( - Some(quote! { - let __value = _serde::#private::de::Content::String(_serde::#private::ToString::to_string(__value)); - }), - Some(quote! { - let __value = _serde::#private::de::Content::Str(__value); - }), - Some(quote! { - let __value = _serde::#private::de::Content::ByteBuf(__value.to_vec()); - }), - Some(quote! { - let __value = _serde::#private::de::Content::Bytes(__value); - }), - ) - } else { - (None, None, None, None) - }; - - let fallthrough_arm_tokens; - let fallthrough_arm = if let Some(fallthrough) = &fallthrough { - fallthrough - } else if is_variant { - fallthrough_arm_tokens = quote! { - _serde::#private::Err(_serde::de::Error::unknown_variant(__value, VARIANTS)) - }; - &fallthrough_arm_tokens - } else { - fallthrough_arm_tokens = quote! { - _serde::#private::Err(_serde::de::Error::unknown_field(__value, FIELDS)) - }; - &fallthrough_arm_tokens - }; - - let visit_other = if collect_other_fields { - quote! { - fn visit_bool<__E>(self, __value: bool) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Bool(__value))) - } - - fn visit_i8<__E>(self, __value: i8) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I8(__value))) - } - - fn visit_i16<__E>(self, __value: i16) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I16(__value))) - } - - fn visit_i32<__E>(self, __value: i32) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I32(__value))) - } - - fn visit_i64<__E>(self, __value: i64) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I64(__value))) - } - - fn visit_u8<__E>(self, __value: u8) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U8(__value))) - } - - fn visit_u16<__E>(self, __value: u16) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U16(__value))) - } - - fn visit_u32<__E>(self, __value: u32) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U32(__value))) - } - - fn visit_u64<__E>(self, __value: u64) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U64(__value))) - } - - fn visit_f32<__E>(self, __value: f32) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::F32(__value))) - } - - fn visit_f64<__E>(self, __value: f64) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::F64(__value))) - } - - fn visit_char<__E>(self, __value: char) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Char(__value))) - } - - fn visit_unit<__E>(self) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Unit)) - } - } - } else { - let u64_mapping = deserialized_fields.iter().enumerate().map(|(i, field)| { - let i = i as u64; - let ident = &field.ident; - quote!(#i => _serde::#private::Ok(#this_value::#ident)) - }); - - let u64_fallthrough_arm_tokens; - let u64_fallthrough_arm = if let Some(fallthrough) = &fallthrough { - fallthrough - } else { - let index_expecting = if is_variant { "variant" } else { "field" }; - let fallthrough_msg = format!( - "{} index 0 <= i < {}", - index_expecting, - deserialized_fields.len(), - ); - u64_fallthrough_arm_tokens = quote! { - _serde::#private::Err(_serde::de::Error::invalid_value( - _serde::de::Unexpected::Unsigned(__value), - &#fallthrough_msg, - )) - }; - &u64_fallthrough_arm_tokens - }; - - quote! { - fn visit_u64<__E>(self, __value: u64) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - match __value { - #(#u64_mapping,)* - _ => #u64_fallthrough_arm, - } - } - } - }; - - let visit_borrowed = if fallthrough_borrowed.is_some() || collect_other_fields { - let str_mapping = str_mapping.clone(); - let bytes_mapping = bytes_mapping.clone(); - let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(fallthrough_arm); - Some(quote! { - fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - match __value { - #(#str_mapping)* - _ => { - #value_as_borrowed_str_content - #fallthrough_borrowed_arm - } - } - } - - fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - match __value { - #(#bytes_mapping)* - _ => { - #bytes_to_str - #value_as_borrowed_bytes_content - #fallthrough_borrowed_arm - } - } - } - }) - } else { - None - }; - - quote_block! { - fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { - _serde::#private::Formatter::write_str(__formatter, #expecting) - } - - #visit_other - - fn visit_str<__E>(self, __value: &str) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - match __value { - #(#str_mapping)* - _ => { - #value_as_str_content - #fallthrough_arm - } - } - } - - fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::#private::Result - where - __E: _serde::de::Error, - { - match __value { - #(#bytes_mapping)* - _ => { - #bytes_to_str - #value_as_bytes_content - #fallthrough_arm - } - } - } - - #visit_borrowed - } -} - fn field_i(i: usize) -> Ident { Ident::new(&format!("__field{}", i), Span::call_site()) } diff --git a/serde_derive/src/de/enum_.rs b/serde_derive/src/de/enum_.rs index 12e7d75c..f13ad188 100644 --- a/serde_derive/src/de/enum_.rs +++ b/serde_derive/src/de/enum_.rs @@ -2,7 +2,8 @@ use crate::de::enum_adjacently; use crate::de::enum_externally; use crate::de::enum_internally; use crate::de::enum_untagged; -use crate::de::{deserialize_generated_identifier, field_i, FieldWithAliases, Parameters}; +use crate::de::identifier; +use crate::de::{field_i, FieldWithAliases, Parameters}; use crate::fragment::{Expr, Fragment, Stmts}; use crate::internals::ast::Variant; use crate::internals::attr; @@ -83,7 +84,7 @@ pub fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) { }) .collect(); - let variant_visitor = Stmts(deserialize_generated_identifier( + let variant_visitor = Stmts(identifier::deserialize_generated_identifier( &deserialized_variants, false, // variant identifiers do not depend on the presence of flatten fields true, diff --git a/serde_derive/src/de/identifier.rs b/serde_derive/src/de/identifier.rs new file mode 100644 index 00000000..2fe04129 --- /dev/null +++ b/serde_derive/src/de/identifier.rs @@ -0,0 +1,475 @@ +//! Contains generators of enums that represents identifiers of fields in structs or variants in enums. + +use crate::de::{FieldWithAliases, Parameters}; +use crate::fragment::{Fragment, Stmts}; +use crate::internals::ast::{Style, Variant}; +use crate::internals::attr; +use crate::private; +use proc_macro2::{Literal, TokenStream}; +use quote::{quote, ToTokens}; + +pub fn deserialize_generated_identifier( + deserialized_fields: &[FieldWithAliases], + has_flatten: bool, + is_variant: bool, + ignore_variant: Option, + fallthrough: Option, +) -> Fragment { + let this_value = quote!(__Field); + let field_idents: &Vec<_> = &deserialized_fields + .iter() + .map(|field| &field.ident) + .collect(); + + let visitor_impl = Stmts(deserialize_identifier( + &this_value, + deserialized_fields, + is_variant, + fallthrough, + None, + !is_variant && has_flatten, + None, + )); + + let lifetime = if !is_variant && has_flatten { + Some(quote!(<'de>)) + } else { + None + }; + + quote_block! { + #[allow(non_camel_case_types)] + #[doc(hidden)] + enum __Field #lifetime { + #(#field_idents,)* + #ignore_variant + } + + #[doc(hidden)] + struct __FieldVisitor; + + #[automatically_derived] + impl<'de> _serde::de::Visitor<'de> for __FieldVisitor { + type Value = __Field #lifetime; + + #visitor_impl + } + + #[automatically_derived] + impl<'de> _serde::Deserialize<'de> for __Field #lifetime { + #[inline] + fn deserialize<__D>(__deserializer: __D) -> _serde::#private::Result + where + __D: _serde::Deserializer<'de>, + { + _serde::Deserializer::deserialize_identifier(__deserializer, __FieldVisitor) + } + } + } +} + +// Generates `Deserialize::deserialize` body for an enum with +// `serde(field_identifier)` or `serde(variant_identifier)` attribute. +pub fn deserialize_custom_identifier( + params: &Parameters, + variants: &[Variant], + cattrs: &attr::Container, +) -> Fragment { + let is_variant = match cattrs.identifier() { + attr::Identifier::Variant => true, + attr::Identifier::Field => false, + attr::Identifier::No => unreachable!(), + }; + + let this_type = params.this_type.to_token_stream(); + let this_value = params.this_value.to_token_stream(); + + let (ordinary, fallthrough, fallthrough_borrowed) = if let Some(last) = variants.last() { + let last_ident = &last.ident; + if last.attrs.other() { + // Process `serde(other)` attribute. It would always be found on the + // last variant (checked in `check_identifier`), so all preceding + // are ordinary variants. + let ordinary = &variants[..variants.len() - 1]; + let fallthrough = quote!(_serde::#private::Ok(#this_value::#last_ident)); + (ordinary, Some(fallthrough), None) + } else if let Style::Newtype = last.style { + let ordinary = &variants[..variants.len() - 1]; + let fallthrough = |value| { + quote! { + _serde::#private::Result::map( + _serde::Deserialize::deserialize( + _serde::#private::de::IdentifierDeserializer::from(#value) + ), + #this_value::#last_ident) + } + }; + ( + ordinary, + Some(fallthrough(quote!(__value))), + Some(fallthrough(quote!(_serde::#private::de::Borrowed( + __value + )))), + ) + } else { + (variants, None, None) + } + } else { + (variants, None, None) + }; + + let idents_aliases: Vec<_> = ordinary + .iter() + .map(|variant| FieldWithAliases { + ident: variant.ident.clone(), + aliases: variant.attrs.aliases(), + }) + .collect(); + + let names = idents_aliases.iter().flat_map(|variant| variant.aliases); + + let names_const = if fallthrough.is_some() { + None + } else if is_variant { + let variants = quote! { + #[doc(hidden)] + const VARIANTS: &'static [&'static str] = &[ #(#names),* ]; + }; + Some(variants) + } else { + let fields = quote! { + #[doc(hidden)] + const FIELDS: &'static [&'static str] = &[ #(#names),* ]; + }; + Some(fields) + }; + + let (de_impl_generics, de_ty_generics, ty_generics, where_clause) = params.generics(); + let delife = params.borrowed.de_lifetime(); + let visitor_impl = Stmts(deserialize_identifier( + &this_value, + &idents_aliases, + is_variant, + fallthrough, + fallthrough_borrowed, + false, + cattrs.expecting(), + )); + + quote_block! { + #names_const + + #[doc(hidden)] + struct __FieldVisitor #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 __FieldVisitor #de_ty_generics #where_clause { + type Value = #this_type #ty_generics; + + #visitor_impl + } + + let __visitor = __FieldVisitor { + marker: _serde::#private::PhantomData::<#this_type #ty_generics>, + lifetime: _serde::#private::PhantomData, + }; + _serde::Deserializer::deserialize_identifier(__deserializer, __visitor) + } +} + +fn deserialize_identifier( + this_value: &TokenStream, + deserialized_fields: &[FieldWithAliases], + is_variant: bool, + fallthrough: Option, + fallthrough_borrowed: Option, + collect_other_fields: bool, + expecting: Option<&str>, +) -> Fragment { + let str_mapping = deserialized_fields.iter().map(|field| { + let ident = &field.ident; + let aliases = field.aliases; + let private2 = private; + // `aliases` also contains a main name + quote! { + #( + #aliases => _serde::#private2::Ok(#this_value::#ident), + )* + } + }); + let bytes_mapping = deserialized_fields.iter().map(|field| { + let ident = &field.ident; + // `aliases` also contains a main name + let aliases = field + .aliases + .iter() + .map(|alias| Literal::byte_string(alias.value.as_bytes())); + let private2 = private; + quote! { + #( + #aliases => _serde::#private2::Ok(#this_value::#ident), + )* + } + }); + + let expecting = expecting.unwrap_or(if is_variant { + "variant identifier" + } else { + "field identifier" + }); + + let bytes_to_str = if fallthrough.is_some() || collect_other_fields { + None + } else { + Some(quote! { + let __value = &_serde::#private::from_utf8_lossy(__value); + }) + }; + + let ( + value_as_str_content, + value_as_borrowed_str_content, + value_as_bytes_content, + value_as_borrowed_bytes_content, + ) = if collect_other_fields { + ( + Some(quote! { + let __value = _serde::#private::de::Content::String(_serde::#private::ToString::to_string(__value)); + }), + Some(quote! { + let __value = _serde::#private::de::Content::Str(__value); + }), + Some(quote! { + let __value = _serde::#private::de::Content::ByteBuf(__value.to_vec()); + }), + Some(quote! { + let __value = _serde::#private::de::Content::Bytes(__value); + }), + ) + } else { + (None, None, None, None) + }; + + let fallthrough_arm_tokens; + let fallthrough_arm = if let Some(fallthrough) = &fallthrough { + fallthrough + } else if is_variant { + fallthrough_arm_tokens = quote! { + _serde::#private::Err(_serde::de::Error::unknown_variant(__value, VARIANTS)) + }; + &fallthrough_arm_tokens + } else { + fallthrough_arm_tokens = quote! { + _serde::#private::Err(_serde::de::Error::unknown_field(__value, FIELDS)) + }; + &fallthrough_arm_tokens + }; + + let visit_other = if collect_other_fields { + quote! { + fn visit_bool<__E>(self, __value: bool) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Bool(__value))) + } + + fn visit_i8<__E>(self, __value: i8) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I8(__value))) + } + + fn visit_i16<__E>(self, __value: i16) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I16(__value))) + } + + fn visit_i32<__E>(self, __value: i32) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I32(__value))) + } + + fn visit_i64<__E>(self, __value: i64) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::I64(__value))) + } + + fn visit_u8<__E>(self, __value: u8) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U8(__value))) + } + + fn visit_u16<__E>(self, __value: u16) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U16(__value))) + } + + fn visit_u32<__E>(self, __value: u32) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U32(__value))) + } + + fn visit_u64<__E>(self, __value: u64) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::U64(__value))) + } + + fn visit_f32<__E>(self, __value: f32) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::F32(__value))) + } + + fn visit_f64<__E>(self, __value: f64) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::F64(__value))) + } + + fn visit_char<__E>(self, __value: char) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Char(__value))) + } + + fn visit_unit<__E>(self) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + _serde::#private::Ok(__Field::__other(_serde::#private::de::Content::Unit)) + } + } + } else { + let u64_mapping = deserialized_fields.iter().enumerate().map(|(i, field)| { + let i = i as u64; + let ident = &field.ident; + quote!(#i => _serde::#private::Ok(#this_value::#ident)) + }); + + let u64_fallthrough_arm_tokens; + let u64_fallthrough_arm = if let Some(fallthrough) = &fallthrough { + fallthrough + } else { + let index_expecting = if is_variant { "variant" } else { "field" }; + let fallthrough_msg = format!( + "{} index 0 <= i < {}", + index_expecting, + deserialized_fields.len(), + ); + u64_fallthrough_arm_tokens = quote! { + _serde::#private::Err(_serde::de::Error::invalid_value( + _serde::de::Unexpected::Unsigned(__value), + &#fallthrough_msg, + )) + }; + &u64_fallthrough_arm_tokens + }; + + quote! { + fn visit_u64<__E>(self, __value: u64) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#u64_mapping,)* + _ => #u64_fallthrough_arm, + } + } + } + }; + + let visit_borrowed = if fallthrough_borrowed.is_some() || collect_other_fields { + let str_mapping = str_mapping.clone(); + let bytes_mapping = bytes_mapping.clone(); + let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(fallthrough_arm); + Some(quote! { + fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#str_mapping)* + _ => { + #value_as_borrowed_str_content + #fallthrough_borrowed_arm + } + } + } + + fn visit_borrowed_bytes<__E>(self, __value: &'de [u8]) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#bytes_mapping)* + _ => { + #bytes_to_str + #value_as_borrowed_bytes_content + #fallthrough_borrowed_arm + } + } + } + }) + } else { + None + }; + + quote_block! { + fn expecting(&self, __formatter: &mut _serde::#private::Formatter) -> _serde::#private::fmt::Result { + _serde::#private::Formatter::write_str(__formatter, #expecting) + } + + #visit_other + + fn visit_str<__E>(self, __value: &str) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#str_mapping)* + _ => { + #value_as_str_content + #fallthrough_arm + } + } + } + + fn visit_bytes<__E>(self, __value: &[u8]) -> _serde::#private::Result + where + __E: _serde::de::Error, + { + match __value { + #(#bytes_mapping)* + _ => { + #bytes_to_str + #value_as_bytes_content + #fallthrough_arm + } + } + } + + #visit_borrowed + } +} diff --git a/serde_derive/src/de/struct_.rs b/serde_derive/src/de/struct_.rs index 721a4839..83dff143 100644 --- a/serde_derive/src/de/struct_.rs +++ b/serde_derive/src/de/struct_.rs @@ -1,5 +1,6 @@ +use crate::de::identifier; use crate::de::{ - deserialize_generated_identifier, deserialize_seq, expr_is_missing, field_i, has_flatten, + deserialize_seq, expr_is_missing, field_i, has_flatten, wrap_deserialize_field_with, FieldWithAliases, Parameters, StructForm, }; #[cfg(feature = "deserialize_in_place")] @@ -303,7 +304,7 @@ fn deserialize_field_identifier( (Some(ignore_variant), Some(fallthrough)) }; - Stmts(deserialize_generated_identifier( + Stmts(identifier::deserialize_generated_identifier( deserialized_fields, has_flatten, false,