diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index d93cac6ec..aa3a7017d 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -965,12 +965,7 @@ fn deserialize_struct( ) }) .collect(); - let field_visitor = Stmts(deserialize_generated_identifier( - &field_names_idents, - cattrs, - false, - None, - )); + let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs); // untagged struct variants do not get a visit_seq method. The same applies to // structs that only have a map representation. @@ -1128,12 +1123,7 @@ fn deserialize_struct_in_place( }) .collect(); - let field_visitor = Stmts(deserialize_generated_identifier( - &field_names_idents, - cattrs, - false, - None, - )); + let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs); let mut_seq = if field_names_idents.is_empty() { quote!(_) @@ -1247,7 +1237,12 @@ fn prepare_enum_variant_enum( }) .collect(); - let other_idx = deserialized_variants.position(|(_, variant)| variant.attrs.other()); + let fallthrough = deserialized_variants + .position(|(_, variant)| variant.attrs.other()) + .map(|other_idx| { + let ignore_variant = variant_names_idents[other_idx].1.clone(); + quote!(_serde::__private::Ok(__Field::#ignore_variant)) + }); let variants_stmt = { let variant_names = variant_names_idents.iter().map(|(name, _, _)| name); @@ -1261,7 +1256,8 @@ fn prepare_enum_variant_enum( &variant_names_idents, cattrs, true, - other_idx, + None, + fallthrough, )); (variants_stmt, variant_visitor) @@ -1986,27 +1982,12 @@ fn deserialize_generated_identifier( fields: &[(&str, Ident, &BTreeSet)], cattrs: &attr::Container, is_variant: bool, - other_idx: Option, + ignore_variant: Option, + fallthrough: Option, ) -> Fragment { let this_value = quote!(__Field); let field_idents: &Vec<_> = &fields.iter().map(|(_, ident, _)| ident).collect(); - let (ignore_variant, fallthrough) = if !is_variant && cattrs.has_flatten() { - let ignore_variant = quote!(__other(_serde::__private::de::Content<'de>),); - let fallthrough = quote!(_serde::__private::Ok(__Field::__other(__value))); - (Some(ignore_variant), Some(fallthrough)) - } else if let Some(other_idx) = other_idx { - let ignore_variant = fields[other_idx].1.clone(); - let fallthrough = quote!(_serde::__private::Ok(__Field::#ignore_variant)); - (None, Some(fallthrough)) - } else if is_variant || cattrs.deny_unknown_fields() { - (None, None) - } else { - let ignore_variant = quote!(__ignore,); - let fallthrough = quote!(_serde::__private::Ok(__Field::__ignore)); - (Some(ignore_variant), Some(fallthrough)) - }; - let visitor_impl = Stmts(deserialize_identifier( &this_value, fields, @@ -2052,6 +2033,33 @@ fn deserialize_generated_identifier( } } +/// Generates enum and its `Deserialize` implementation that represents each +/// non-skipped field of the struct +fn deserialize_field_identifier( + fields: &[(&str, Ident, &BTreeSet)], + cattrs: &attr::Container, +) -> Stmts { + let (ignore_variant, fallthrough) = if cattrs.has_flatten() { + let ignore_variant = quote!(__other(_serde::__private::de::Content<'de>),); + let fallthrough = quote!(_serde::__private::Ok(__Field::__other(__value))); + (Some(ignore_variant), Some(fallthrough)) + } else if cattrs.deny_unknown_fields() { + (None, None) + } else { + let ignore_variant = quote!(__ignore,); + let fallthrough = quote!(_serde::__private::Ok(__Field::__ignore)); + (Some(ignore_variant), Some(fallthrough)) + }; + + Stmts(deserialize_generated_identifier( + fields, + cattrs, + false, + ignore_variant, + fallthrough, + )) +} + // Generates `Deserialize::deserialize` body for an enum with // `serde(field_identifier)` or `serde(variant_identifier)` attribute. fn deserialize_custom_identifier(