Skip to content

Commit f986609

Browse files
authored
Merge pull request #2795 from Mingun/has-flatten-rework
`has_flatten` rework
2 parents 85c73ef + 77a6a9d commit f986609

File tree

5 files changed

+54
-114
lines changed

5 files changed

+54
-114
lines changed

serde_derive/src/de.rs

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -281,21 +281,11 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
281281
} else if let attr::Identifier::No = cont.attrs.identifier() {
282282
match &cont.data {
283283
Data::Enum(variants) => deserialize_enum(params, variants, &cont.attrs),
284-
Data::Struct(Style::Struct, fields) => deserialize_struct(
285-
params,
286-
fields,
287-
&cont.attrs,
288-
cont.attrs.has_flatten(),
289-
StructForm::Struct,
290-
),
284+
Data::Struct(Style::Struct, fields) => {
285+
deserialize_struct(params, fields, &cont.attrs, StructForm::Struct)
286+
}
291287
Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => {
292-
deserialize_tuple(
293-
params,
294-
fields,
295-
&cont.attrs,
296-
cont.attrs.has_flatten(),
297-
TupleForm::Tuple,
298-
)
288+
deserialize_tuple(params, fields, &cont.attrs, TupleForm::Tuple)
299289
}
300290
Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs),
301291
}
@@ -469,11 +459,10 @@ fn deserialize_tuple(
469459
params: &Parameters,
470460
fields: &[Field],
471461
cattrs: &attr::Container,
472-
has_flatten: bool,
473462
form: TupleForm,
474463
) -> Fragment {
475464
assert!(
476-
!has_flatten,
465+
!has_flatten(fields),
477466
"tuples and tuple variants cannot have flatten fields"
478467
);
479468

@@ -594,7 +583,7 @@ fn deserialize_tuple_in_place(
594583
cattrs: &attr::Container,
595584
) -> Fragment {
596585
assert!(
597-
!cattrs.has_flatten(),
586+
!has_flatten(fields),
598587
"tuples and tuple variants cannot have flatten fields"
599588
);
600589

@@ -927,7 +916,6 @@ fn deserialize_struct(
927916
params: &Parameters,
928917
fields: &[Field],
929918
cattrs: &attr::Container,
930-
has_flatten: bool,
931919
form: StructForm,
932920
) -> Fragment {
933921
let this_type = &params.this_type;
@@ -976,6 +964,8 @@ fn deserialize_struct(
976964
)
977965
})
978966
.collect();
967+
968+
let has_flatten = has_flatten(fields);
979969
let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs, has_flatten);
980970

981971
// untagged struct variants do not get a visit_seq method. The same applies to
@@ -1115,7 +1105,7 @@ fn deserialize_struct_in_place(
11151105
) -> Option<Fragment> {
11161106
// for now we do not support in_place deserialization for structs that
11171107
// are represented as map.
1118-
if cattrs.has_flatten() {
1108+
if has_flatten(fields) {
11191109
return None;
11201110
}
11211111

@@ -1831,14 +1821,12 @@ fn deserialize_externally_tagged_variant(
18311821
params,
18321822
&variant.fields,
18331823
cattrs,
1834-
variant.attrs.has_flatten(),
18351824
TupleForm::ExternallyTagged(variant_ident),
18361825
),
18371826
Style::Struct => deserialize_struct(
18381827
params,
18391828
&variant.fields,
18401829
cattrs,
1841-
variant.attrs.has_flatten(),
18421830
StructForm::ExternallyTagged(variant_ident),
18431831
),
18441832
}
@@ -1882,7 +1870,6 @@ fn deserialize_internally_tagged_variant(
18821870
params,
18831871
&variant.fields,
18841872
cattrs,
1885-
variant.attrs.has_flatten(),
18861873
StructForm::InternallyTagged(variant_ident, deserializer),
18871874
),
18881875
Style::Tuple => unreachable!("checked in serde_derive_internals"),
@@ -1933,14 +1920,12 @@ fn deserialize_untagged_variant(
19331920
params,
19341921
&variant.fields,
19351922
cattrs,
1936-
variant.attrs.has_flatten(),
19371923
TupleForm::Untagged(variant_ident, deserializer),
19381924
),
19391925
Style::Struct => deserialize_struct(
19401926
params,
19411927
&variant.fields,
19421928
cattrs,
1943-
variant.attrs.has_flatten(),
19441929
StructForm::Untagged(variant_ident, deserializer),
19451930
),
19461931
}
@@ -2707,7 +2692,7 @@ fn deserialize_map_in_place(
27072692
cattrs: &attr::Container,
27082693
) -> Fragment {
27092694
assert!(
2710-
!cattrs.has_flatten(),
2695+
!has_flatten(fields),
27112696
"inplace deserialization of maps does not support flatten fields"
27122697
);
27132698

@@ -3042,6 +3027,13 @@ fn effective_style(variant: &Variant) -> Style {
30423027
}
30433028
}
30443029

3030+
/// True if there are fields that is not skipped and has a `#[serde(flatten)]` attribute.
3031+
fn has_flatten(fields: &[Field]) -> bool {
3032+
fields
3033+
.iter()
3034+
.any(|field| field.attrs.flatten() && !field.attrs.skip_deserializing())
3035+
}
3036+
30453037
struct DeImplGenerics<'a>(&'a Parameters);
30463038
#[cfg(feature = "deserialize_in_place")]
30473039
struct InPlaceImplGenerics<'a>(&'a Parameters);

serde_derive/src/internals/ast.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ impl<'a> Container<'a> {
6363
item: &'a syn::DeriveInput,
6464
derive: Derive,
6565
) -> Option<Container<'a>> {
66-
let mut attrs = attr::Container::from_ast(cx, item);
66+
let attrs = attr::Container::from_ast(cx, item);
6767

6868
let mut data = match &item.data {
6969
syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())),
@@ -77,16 +77,11 @@ impl<'a> Container<'a> {
7777
}
7878
};
7979

80-
let mut has_flatten = false;
8180
match &mut data {
8281
Data::Enum(variants) => {
8382
for variant in variants {
8483
variant.attrs.rename_by_rules(attrs.rename_all_rules());
8584
for field in &mut variant.fields {
86-
if field.attrs.flatten() {
87-
has_flatten = true;
88-
variant.attrs.mark_has_flatten();
89-
}
9085
field.attrs.rename_by_rules(
9186
variant
9287
.attrs
@@ -98,18 +93,11 @@ impl<'a> Container<'a> {
9893
}
9994
Data::Struct(_, fields) => {
10095
for field in fields {
101-
if field.attrs.flatten() {
102-
has_flatten = true;
103-
}
10496
field.attrs.rename_by_rules(attrs.rename_all_rules());
10597
}
10698
}
10799
}
108100

109-
if has_flatten {
110-
attrs.mark_has_flatten();
111-
}
112-
113101
let mut item = Container {
114102
ident: item.ident.clone(),
115103
attrs,

serde_derive/src/internals/attr.rs

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -216,23 +216,6 @@ pub struct Container {
216216
type_into: Option<syn::Type>,
217217
remote: Option<syn::Path>,
218218
identifier: Identifier,
219-
/// True if container is a struct and has a field with `#[serde(flatten)]`,
220-
/// or is an enum with a struct variant which has a field with
221-
/// `#[serde(flatten)]`.
222-
///
223-
/// ```ignore
224-
/// struct Container {
225-
/// #[serde(flatten)]
226-
/// some_field: (),
227-
/// }
228-
/// enum Container {
229-
/// Variant {
230-
/// #[serde(flatten)]
231-
/// some_field: (),
232-
/// },
233-
/// }
234-
/// ```
235-
has_flatten: bool,
236219
serde_path: Option<syn::Path>,
237220
is_packed: bool,
238221
/// Error message generated when type can't be deserialized
@@ -603,7 +586,6 @@ impl Container {
603586
type_into: type_into.get(),
604587
remote: remote.get(),
605588
identifier: decide_identifier(cx, item, field_identifier, variant_identifier),
606-
has_flatten: false,
607589
serde_path: serde_path.get(),
608590
is_packed,
609591
expecting: expecting.get(),
@@ -671,14 +653,6 @@ impl Container {
671653
self.identifier
672654
}
673655

674-
pub fn has_flatten(&self) -> bool {
675-
self.has_flatten
676-
}
677-
678-
pub fn mark_has_flatten(&mut self) {
679-
self.has_flatten = true;
680-
}
681-
682656
pub fn custom_serde_path(&self) -> Option<&syn::Path> {
683657
self.serde_path.as_ref()
684658
}
@@ -810,18 +784,6 @@ pub struct Variant {
810784
rename_all_rules: RenameAllRules,
811785
ser_bound: Option<Vec<syn::WherePredicate>>,
812786
de_bound: Option<Vec<syn::WherePredicate>>,
813-
/// True if variant is a struct variant which contains a field with
814-
/// `#[serde(flatten)]`.
815-
///
816-
/// ```ignore
817-
/// enum Enum {
818-
/// Variant {
819-
/// #[serde(flatten)]
820-
/// some_field: (),
821-
/// },
822-
/// }
823-
/// ```
824-
has_flatten: bool,
825787
skip_deserializing: bool,
826788
skip_serializing: bool,
827789
other: bool,
@@ -991,7 +953,6 @@ impl Variant {
991953
},
992954
ser_bound: ser_bound.get(),
993955
de_bound: de_bound.get(),
994-
has_flatten: false,
995956
skip_deserializing: skip_deserializing.get(),
996957
skip_serializing: skip_serializing.get(),
997958
other: other.get(),
@@ -1034,14 +995,6 @@ impl Variant {
1034995
self.de_bound.as_ref().map(|vec| &vec[..])
1035996
}
1036997

1037-
pub fn has_flatten(&self) -> bool {
1038-
self.has_flatten
1039-
}
1040-
1041-
pub fn mark_has_flatten(&mut self) {
1042-
self.has_flatten = true;
1043-
}
1044-
1045998
pub fn skip_deserializing(&self) -> bool {
1046999
self.skip_deserializing
10471000
}

serde_derive/src/ser.rs

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -289,9 +289,18 @@ fn serialize_tuple_struct(
289289
}
290290

291291
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
292-
assert!(fields.len() as u64 <= u64::from(u32::MAX));
292+
assert!(
293+
fields.len() as u64 <= u64::from(u32::MAX),
294+
"too many fields in {}: {}, maximum supported count is {}",
295+
cattrs.name().serialize_name(),
296+
fields.len(),
297+
u32::MAX
298+
);
293299

294-
if cattrs.has_flatten() {
300+
let has_non_skipped_flatten = fields
301+
.iter()
302+
.any(|field| field.attrs.flatten() && !field.attrs.skip_serializing());
303+
if has_non_skipped_flatten {
295304
serialize_struct_as_map(params, fields, cattrs)
296305
} else {
297306
serialize_struct_as_struct(params, fields, cattrs)
@@ -370,26 +379,8 @@ fn serialize_struct_as_map(
370379

371380
let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists);
372381

373-
let len = if cattrs.has_flatten() {
374-
quote!(_serde::__private::None)
375-
} else {
376-
let len = serialized_fields
377-
.map(|field| match field.attrs.skip_serializing_if() {
378-
None => quote!(1),
379-
Some(path) => {
380-
let field_expr = get_member(params, field, &field.member);
381-
quote!(if #path(#field_expr) { 0 } else { 1 })
382-
}
383-
})
384-
.fold(
385-
quote!(#tag_field_exists as usize),
386-
|sum, expr| quote!(#sum + #expr),
387-
);
388-
quote!(_serde::__private::Some(#len))
389-
};
390-
391382
quote_block! {
392-
let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, #len)?;
383+
let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, _serde::__private::None)?;
393384
#tag_field
394385
#(#serialize_fields)*
395386
_serde::ser::SerializeMap::end(__serde_state)

test_suite/tests/test_gen.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -547,13 +547,32 @@ fn test_gen() {
547547
}
548548
assert::<FlattenWith>();
549549

550+
#[derive(Serialize, Deserialize)]
551+
pub struct Flatten<T> {
552+
#[serde(flatten)]
553+
t: T,
554+
}
555+
550556
#[derive(Serialize, Deserialize)]
551557
#[serde(deny_unknown_fields)]
552558
pub struct FlattenDenyUnknown<T> {
553559
#[serde(flatten)]
554560
t: T,
555561
}
556562

563+
#[derive(Serialize, Deserialize)]
564+
pub struct SkipDeserializing<T> {
565+
#[serde(skip_deserializing)]
566+
flat: T,
567+
}
568+
569+
#[derive(Serialize, Deserialize)]
570+
#[serde(deny_unknown_fields)]
571+
pub struct SkipDeserializingDenyUnknown<T> {
572+
#[serde(skip_deserializing)]
573+
flat: T,
574+
}
575+
557576
#[derive(Serialize, Deserialize)]
558577
pub struct StaticStrStruct<'a> {
559578
a: &'a str,
@@ -720,14 +739,11 @@ fn test_gen() {
720739
flat: StdOption<T>,
721740
}
722741

723-
#[allow(clippy::collection_is_never_read)] // FIXME
724-
const _: () = {
725-
#[derive(Serialize, Deserialize)]
726-
pub struct FlattenSkipDeserializing<T> {
727-
#[serde(flatten, skip_deserializing)]
728-
flat: T,
729-
}
730-
};
742+
#[derive(Serialize, Deserialize)]
743+
pub struct FlattenSkipDeserializing<T> {
744+
#[serde(flatten, skip_deserializing)]
745+
flat: T,
746+
}
731747

732748
#[derive(Serialize, Deserialize)]
733749
#[serde(untagged)]

0 commit comments

Comments
 (0)