Skip to content

Commit 7393169

Browse files
authored
Merge pull request #2553 from Mingun/default-on-tuples
Allow `#[serde(default)]` on tuple structs
2 parents 4d93e9f + 5c33931 commit 7393169

File tree

13 files changed

+230
-60
lines changed

13 files changed

+230
-60
lines changed

serde_derive/src/de.rs

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -723,19 +723,11 @@ fn deserialize_seq(
723723
})
724724
}
725725
};
726-
let value_if_none = match field.attrs.default() {
727-
attr::Default::Default => quote!(_serde::__private::Default::default()),
728-
attr::Default::Path(path) => quote!(#path()),
729-
attr::Default::None => quote!(
730-
return _serde::__private::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting));
731-
),
732-
};
726+
let value_if_none = expr_is_missing_seq(None, index_in_seq, field, cattrs, expecting);
733727
let assign = quote! {
734728
let #var = match #visit {
735729
_serde::__private::Some(__value) => __value,
736-
_serde::__private::None => {
737-
#value_if_none
738-
}
730+
_serde::__private::None => #value_if_none,
739731
};
740732
};
741733
index_in_seq += 1;
@@ -811,24 +803,14 @@ fn deserialize_seq_in_place(
811803
self.place.#member = #default;
812804
}
813805
} else {
814-
let value_if_none = match field.attrs.default() {
815-
attr::Default::Default => quote!(
816-
self.place.#member = _serde::__private::Default::default();
817-
),
818-
attr::Default::Path(path) => quote!(
819-
self.place.#member = #path();
820-
),
821-
attr::Default::None => quote!(
822-
return _serde::__private::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting));
823-
),
824-
};
806+
let value_if_none = expr_is_missing_seq(Some(quote!(self.place.#member = )), index_in_seq, field, cattrs, expecting);
825807
let write = match field.attrs.deserialize_with() {
826808
None => {
827809
quote! {
828810
if let _serde::__private::None = _serde::de::SeqAccess::next_element_seed(&mut __seq,
829811
_serde::__private::de::InPlaceSeed(&mut self.place.#member))?
830812
{
831-
#value_if_none
813+
#value_if_none;
832814
}
833815
}
834816
}
@@ -841,7 +823,7 @@ fn deserialize_seq_in_place(
841823
self.place.#member = __wrap.value;
842824
}
843825
_serde::__private::None => {
844-
#value_if_none
826+
#value_if_none;
845827
}
846828
}
847829
})
@@ -2980,6 +2962,35 @@ fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
29802962
}
29812963
}
29822964

2965+
fn expr_is_missing_seq(
2966+
assign_to: Option<TokenStream>,
2967+
index: usize,
2968+
field: &Field,
2969+
cattrs: &attr::Container,
2970+
expecting: &str,
2971+
) -> TokenStream {
2972+
match field.attrs.default() {
2973+
attr::Default::Default => {
2974+
let span = field.original.span();
2975+
return quote_spanned!(span=> #assign_to _serde::__private::Default::default());
2976+
}
2977+
attr::Default::Path(path) => {
2978+
return quote_spanned!(path.span()=> #assign_to #path());
2979+
}
2980+
attr::Default::None => { /* below */ }
2981+
}
2982+
2983+
match *cattrs.default() {
2984+
attr::Default::Default | attr::Default::Path(_) => {
2985+
let member = &field.member;
2986+
return quote!(#assign_to __default.#member);
2987+
}
2988+
attr::Default::None => quote!(
2989+
return _serde::__private::Err(_serde::de::Error::invalid_length(#index, &#expecting))
2990+
),
2991+
}
2992+
}
2993+
29832994
fn effective_style(variant: &Variant) -> Style {
29842995
match variant.style {
29852996
Style::Newtype if variant.fields[0].attrs.skip_deserializing() => Style::Unit,

serde_derive/src/internals/attr.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -396,20 +396,20 @@ impl Container {
396396
if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? {
397397
match &item.data {
398398
syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields {
399-
syn::Fields::Named(_) => {
399+
syn::Fields::Named(_) | syn::Fields::Unnamed(_) => {
400400
default.set(&meta.path, Default::Path(path));
401401
}
402-
syn::Fields::Unnamed(_) | syn::Fields::Unit => {
403-
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
402+
syn::Fields::Unit => {
403+
let msg = "#[serde(default = \"...\")] can only be used on structs with fields";
404404
cx.syn_error(meta.error(msg));
405405
}
406406
},
407407
syn::Data::Enum(_) => {
408-
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
408+
let msg = "#[serde(default = \"...\")] can only be used on structs with fields";
409409
cx.syn_error(meta.error(msg));
410410
}
411411
syn::Data::Union(_) => {
412-
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
412+
let msg = "#[serde(default = \"...\")] can only be used on structs with fields";
413413
cx.syn_error(meta.error(msg));
414414
}
415415
}
@@ -418,20 +418,20 @@ impl Container {
418418
// #[serde(default)]
419419
match &item.data {
420420
syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields {
421-
syn::Fields::Named(_) => {
421+
syn::Fields::Named(_) | syn::Fields::Unnamed(_) => {
422422
default.set(meta.path, Default::Default);
423423
}
424-
syn::Fields::Unnamed(_) | syn::Fields::Unit => {
425-
let msg = "#[serde(default)] can only be used on structs with named fields";
424+
syn::Fields::Unit => {
425+
let msg = "#[serde(default)] can only be used on structs with fields";
426426
cx.error_spanned_by(fields, msg);
427427
}
428428
},
429429
syn::Data::Enum(_) => {
430-
let msg = "#[serde(default)] can only be used on structs with named fields";
430+
let msg = "#[serde(default)] can only be used on structs with fields";
431431
cx.syn_error(meta.error(msg));
432432
}
433433
syn::Data::Union(_) => {
434-
let msg = "#[serde(default)] can only be used on structs with named fields";
434+
let msg = "#[serde(default)] can only be used on structs with fields";
435435
cx.syn_error(meta.error(msg));
436436
}
437437
}

serde_derive/src/internals/check.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use crate::internals::ast::{Container, Data, Field, Style};
2-
use crate::internals::attr::{Identifier, TagType};
2+
use crate::internals::attr::{Default, Identifier, TagType};
33
use crate::internals::{ungroup, Ctxt, Derive};
44
use syn::{Member, Type};
55

66
// Cross-cutting checks that require looking at more than a single attrs object.
77
// Simpler checks should happen when parsing and building the attrs.
88
pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
9+
check_default_on_tuple(cx, cont);
910
check_remote_generic(cx, cont);
1011
check_getter(cx, cont);
1112
check_flatten(cx, cont);
@@ -17,6 +18,41 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
1718
check_from_and_try_from(cx, cont);
1819
}
1920

21+
/// If some field of tuple is marked as `#[serde(default)]` then all subsequent
22+
/// fields also should be marked with that attribute or the struct itself should
23+
/// have this attribute. This is because using default value for a field is
24+
/// possible only if the sequence is exhausted that means that all subsequent
25+
/// fields will fail to deserialize and should provide a default value if we want
26+
/// the successful deserialization.
27+
fn check_default_on_tuple(cx: &Ctxt, cont: &Container) {
28+
if let Default::None = cont.attrs.default() {
29+
if let Data::Struct(Style::Tuple, fields) = &cont.data {
30+
let mut first_default_index = None;
31+
for (i, field) in fields.iter().enumerate() {
32+
// Skipped fields automatically get the #[serde(default)] attribute
33+
// We interested only on non-skipped fields here
34+
if field.attrs.skip_deserializing() {
35+
continue;
36+
}
37+
if let Default::None = field.attrs.default() {
38+
if let Some(first) = first_default_index {
39+
cx.error_spanned_by(
40+
field.ty,
41+
format!("struct or field must have #[serde(default)] because previous field {} have #[serde(default)]", first),
42+
);
43+
}
44+
continue;
45+
}
46+
if let None = first_default_index {
47+
first_default_index = Some(i);
48+
}
49+
}
50+
}
51+
}
52+
// TODO: Warn if container has default and all fields also marked with default
53+
// when warnings in proc-macro become available
54+
}
55+
2056
// Remote derive definition type must have either all of the generics of the
2157
// remote type:
2258
//

test_suite/tests/ui/default-attribute/enum.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: #[serde(default)] can only be used on structs with named fields
1+
error: #[serde(default)] can only be used on structs with fields
22
--> tests/ui/default-attribute/enum.rs:4:9
33
|
44
4 | #[serde(default)]

test_suite/tests/ui/default-attribute/enum_path.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: #[serde(default = "...")] can only be used on structs with named fields
1+
error: #[serde(default = "...")] can only be used on structs with fields
22
--> tests/ui/default-attribute/enum_path.rs:4:9
33
|
44
4 | #[serde(default = "default_e")]

test_suite/tests/ui/default-attribute/nameless_struct_fields.rs

Lines changed: 0 additions & 7 deletions
This file was deleted.

test_suite/tests/ui/default-attribute/nameless_struct_fields.stderr

Lines changed: 0 additions & 5 deletions
This file was deleted.

test_suite/tests/ui/default-attribute/nameless_struct_fields_path.rs

Lines changed: 0 additions & 7 deletions
This file was deleted.

test_suite/tests/ui/default-attribute/nameless_struct_fields_path.stderr

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
use serde_derive::Deserialize;
2+
3+
/// No errors expected
4+
#[derive(Deserialize)]
5+
struct T0(u8, u8);
6+
7+
/// No errors expected:
8+
/// - if both fields are provided, both gets value from data
9+
/// - if only one field is provided, the second gets default value
10+
#[derive(Deserialize)]
11+
struct T1(u8, #[serde(default)] u8);
12+
13+
/// Errors expected -- the first field can get default value only if sequence is
14+
/// empty, but that mean that all other fields cannot be deserialized without
15+
/// errors, so the `#[serde(default)]` attribute is superfluous
16+
#[derive(Deserialize)]
17+
struct T2(#[serde(default)] u8, u8, u8);
18+
19+
/// No errors expected:
20+
/// - if both fields are provided, both gets value from data
21+
/// - if only one field is provided, the second gets default value
22+
/// - if none fields are provided, both gets default value
23+
#[derive(Deserialize)]
24+
struct T3(#[serde(default)] u8, #[serde(default)] u8);
25+
26+
////////////////////////////////////////////////////////////////////////////////
27+
28+
/// No errors expected -- missing fields gets default values
29+
#[derive(Deserialize, Default)]
30+
#[serde(default)]
31+
struct T4(u8, u8);
32+
33+
/// No errors expected -- missing fields gets default values
34+
#[derive(Deserialize, Default)]
35+
#[serde(default)]
36+
struct T5(#[serde(default)] u8, u8);
37+
38+
/// No errors expected -- missing fields gets default values
39+
#[derive(Deserialize, Default)]
40+
#[serde(default)]
41+
struct T6(u8, #[serde(default)] u8);
42+
43+
/// No errors expected -- missing fields gets default values
44+
#[derive(Deserialize, Default)]
45+
#[serde(default)]
46+
struct T7(#[serde(default)] u8, #[serde(default)] u8);
47+
48+
fn main() {}

0 commit comments

Comments
 (0)