From fd5b5e9aa561e29d9312ecef2019ec670b4bc334 Mon Sep 17 00:00:00 2001 From: Mingun Date: Sun, 11 Aug 2024 18:46:31 +0500 Subject: [PATCH] Correctly calculate `has_flatten` attribute in all cases for deserialization Consequence: `FlattenSkipDeserializing[DenyUnknown]` - does not collect data in Field, because do not read them anyway - gets `deserialize_in_place` method - gets ability to deserialize from sequence (visit_seq method) - uses `deserialize_struct` instead of `deserialize_map` --- serde_derive/src/de.rs | 30 +++++++++++++----------------- serde_derive/src/internals/ast.rs | 1 - serde_derive/src/internals/attr.rs | 21 --------------------- 3 files changed, 13 insertions(+), 39 deletions(-) diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 1ccecb26c..be1666e7b 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -285,13 +285,7 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment { deserialize_struct(params, fields, &cont.attrs, StructForm::Struct) } Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => { - deserialize_tuple( - params, - fields, - &cont.attrs, - cont.attrs.has_flatten(), - TupleForm::Tuple, - ) + deserialize_tuple(params, fields, &cont.attrs, TupleForm::Tuple) } Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs), } @@ -465,11 +459,10 @@ fn deserialize_tuple( params: &Parameters, fields: &[Field], cattrs: &attr::Container, - has_flatten: bool, form: TupleForm, ) -> Fragment { assert!( - !has_flatten, + !has_flatten(fields), "tuples and tuple variants cannot have flatten fields" ); @@ -590,7 +583,7 @@ fn deserialize_tuple_in_place( cattrs: &attr::Container, ) -> Fragment { assert!( - !cattrs.has_flatten(), + !has_flatten(fields), "tuples and tuple variants cannot have flatten fields" ); @@ -972,9 +965,7 @@ fn deserialize_struct( }) .collect(); - let has_flatten = fields - .iter() - .any(|field| field.attrs.flatten() && !field.attrs.skip_deserializing()); + let has_flatten = has_flatten(fields); let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs, has_flatten); // untagged struct variants do not get a visit_seq method. The same applies to @@ -1114,7 +1105,7 @@ fn deserialize_struct_in_place( ) -> Option { // for now we do not support in_place deserialization for structs that // are represented as map. - if cattrs.has_flatten() { + if has_flatten(fields) { return None; } @@ -1830,7 +1821,6 @@ fn deserialize_externally_tagged_variant( params, &variant.fields, cattrs, - variant.attrs.has_flatten(), TupleForm::ExternallyTagged(variant_ident), ), Style::Struct => deserialize_struct( @@ -1930,7 +1920,6 @@ fn deserialize_untagged_variant( params, &variant.fields, cattrs, - variant.attrs.has_flatten(), TupleForm::Untagged(variant_ident, deserializer), ), Style::Struct => deserialize_struct( @@ -2703,7 +2692,7 @@ fn deserialize_map_in_place( cattrs: &attr::Container, ) -> Fragment { assert!( - !cattrs.has_flatten(), + !has_flatten(fields), "inplace deserialization of maps does not support flatten fields" ); @@ -3038,6 +3027,13 @@ fn effective_style(variant: &Variant) -> Style { } } +/// True if there are fields that is not skipped and has a `#[serde(flatten)]` attribute. +fn has_flatten(fields: &[Field]) -> bool { + fields + .iter() + .any(|field| field.attrs.flatten() && !field.attrs.skip_deserializing()) +} + struct DeImplGenerics<'a>(&'a Parameters); #[cfg(feature = "deserialize_in_place")] struct InPlaceImplGenerics<'a>(&'a Parameters); diff --git a/serde_derive/src/internals/ast.rs b/serde_derive/src/internals/ast.rs index 4ec709952..a28d3ae7e 100644 --- a/serde_derive/src/internals/ast.rs +++ b/serde_derive/src/internals/ast.rs @@ -85,7 +85,6 @@ impl<'a> Container<'a> { for field in &mut variant.fields { if field.attrs.flatten() { has_flatten = true; - variant.attrs.mark_has_flatten(); } field.attrs.rename_by_rules( variant diff --git a/serde_derive/src/internals/attr.rs b/serde_derive/src/internals/attr.rs index ba3a2d8d8..28ed54267 100644 --- a/serde_derive/src/internals/attr.rs +++ b/serde_derive/src/internals/attr.rs @@ -810,18 +810,6 @@ pub struct Variant { rename_all_rules: RenameAllRules, ser_bound: Option>, de_bound: Option>, - /// True if variant is a struct variant which contains a field with - /// `#[serde(flatten)]`. - /// - /// ```ignore - /// enum Enum { - /// Variant { - /// #[serde(flatten)] - /// some_field: (), - /// }, - /// } - /// ``` - has_flatten: bool, skip_deserializing: bool, skip_serializing: bool, other: bool, @@ -991,7 +979,6 @@ impl Variant { }, ser_bound: ser_bound.get(), de_bound: de_bound.get(), - has_flatten: false, skip_deserializing: skip_deserializing.get(), skip_serializing: skip_serializing.get(), other: other.get(), @@ -1034,14 +1021,6 @@ impl Variant { self.de_bound.as_ref().map(|vec| &vec[..]) } - pub fn has_flatten(&self) -> bool { - self.has_flatten - } - - pub fn mark_has_flatten(&mut self) { - self.has_flatten = true; - } - pub fn skip_deserializing(&self) -> bool { self.skip_deserializing }