Compare commits

...

28 Commits

Author SHA1 Message Date
David Tolnay 05a5b7e3c6 Release 1.0.183 2023-08-06 21:00:14 -07:00
David Tolnay 3bff326fb3 Merge pull request #2555 from Mingun/field
Refactor code that generates `__Field` enums
2023-08-06 18:23:52 -07:00
David Tolnay aaadd93878 Merge pull request #2556 from DBLouis/master
Add forward impl for OsStr
2023-08-06 18:02:21 -07:00
Louis Dupré Bertoni 9c864f0b02 Add forward impl for OsStr 2023-08-06 19:41:19 +03:00
Mingun 070cce0d9c Get rid of temporary variable 2023-08-06 19:55:48 +05:00
Mingun b58e8bac12 Replace if let Some(...) = ... to Option::map 2023-08-06 19:53:39 +05:00
Mingun ada50b077e ignore_variant variable is always None, let's take this into account 2023-08-06 19:36:48 +05:00
Mingun 5e313a7330 Move generiс code out-of-function, create more specialized and simple code 2023-08-06 19:35:27 +05:00
Mingun 2a36d11238 Introduce a dedicated function for generating Field enum
(the enum that represents all fields of a struct)
2023-08-06 19:32:53 +05:00
David Tolnay b6685cf9dd Release 1.0.182 2023-08-05 22:16:46 -07:00
David Tolnay fc273c6763 Resolve needless_return clippy lint in PR 2553
warning: unneeded `return` statement
        --> serde_derive/src/de.rs:2986:13
         |
    2986 |             return quote!(#assign_to __default.#member);
         |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
         = note: `-W clippy::needless-return` implied by `-W clippy::all`
    help: remove `return`
         |
    2986 -             return quote!(#assign_to __default.#member);
    2986 +             quote!(#assign_to __default.#member)
         |
2023-08-05 22:16:19 -07:00
David Tolnay bd7b0e257e Touch up PR 2553 2023-08-05 22:13:09 -07:00
David Tolnay 73931692b2 Merge pull request #2553 from Mingun/default-on-tuples
Allow `#[serde(default)]` on tuple structs
2023-08-05 22:12:10 -07:00
David Tolnay 4d93e9f44c Keep deserialize aliases as a sorted set 2023-08-05 17:06:11 -07:00
David Tolnay da55ed7e8d Remove some clones of names of things 2023-08-05 17:01:34 -07:00
David Tolnay e3617e1f28 Update explanation of correct_aliases 2023-08-05 16:39:38 -07:00
David Tolnay 431636af0d Merge pull request #2458 from Mingun/identifier
Keep aliases always sorted and include aliases in expecting message for field/variant_identifier
2023-08-05 16:39:14 -07:00
David Tolnay 891ced598a Update test suite to nightly-2023-08-05
error: the feature `lang_items` is internal to the compiler or standard library
     --> src/main.rs:1:12
      |
    1 | #![feature(lang_items, start)]
      |            ^^^^^^^^^^
      |
      = note: using it is strongly discouraged
      = note: `#[deny(internal_features)]` on by default
2023-08-04 19:09:00 -07:00
Mingun 5c33931422 Allow #[serde(default)] on tuple structs 2023-08-03 22:32:34 +05:00
Mingun f709fc05b0 Do not run the code when results are not used 2023-07-23 15:23:39 +05:00
Mingun 089aae1292 Eliminate even more allocations 2023-07-23 15:23:39 +05:00
Mingun 855acaf112 Eliminate additional allocations for flattening aliases 2023-07-23 15:23:38 +05:00
Mingun 7ca7720262 Slightly reduced number of allocations 2023-07-23 15:23:37 +05:00
Mingun 78fea3aa4a Show possible aliases in the expected message
Fixes tests
2023-07-23 15:23:37 +05:00
Mingun 1efb8b6a53 Add tests for aliases
failures (2):
    field_identifier::unknown
    variant_identifier::unknown
2023-07-23 15:23:36 +05:00
Mingun bc1960b106 Add tests for unknown field / variant 2023-07-23 15:23:33 +05:00
Mingun 967023b755 Group field_identifier and variant_identifier tests in sub-modules
(review this commit with "ignore whitespace changes" option on)
2023-07-23 15:21:22 +05:00
Mingun bb51e68f16 Keep aliases sorted 2023-07-23 15:21:21 +05:00
25 changed files with 510 additions and 248 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive" name = "serde_derive"
version = "1.0.181" version = "1.0.183"
authors = ["David Tolnay <dtolnay@gmail.com>"] authors = ["David Tolnay <dtolnay@gmail.com>"]
publish = false publish = false
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive" name = "serde_derive"
version = "1.0.181" version = "1.0.183"
authors = ["David Tolnay <dtolnay@gmail.com>"] authors = ["David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std", "no-std::no-alloc"] categories = ["no-std", "no-std::no-alloc"]
description = "Implementation of #[derive(Serialize, Deserialize)]" description = "Implementation of #[derive(Serialize, Deserialize)]"
+1 -1
View File
@@ -13,7 +13,7 @@
//! //!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html //! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.181")] #![doc(html_root_url = "https://docs.rs/serde_derive/1.0.183")]
#[cfg(not(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu")))] #[cfg(not(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu")))]
include!("lib_from_source.rs"); include!("lib_from_source.rs");
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde" name = "serde"
version = "1.0.181" # remember to update html_root_url and serde_derive dependency version = "1.0.183" # remember to update html_root_url and serde_derive dependency
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs" build = "build.rs"
categories = ["encoding", "no-std", "no-std::no-alloc"] categories = ["encoding", "no-std", "no-std::no-alloc"]
@@ -15,7 +15,7 @@ repository = "https://github.com/serde-rs/serde"
rust-version = "1.31" rust-version = "1.31"
[dependencies] [dependencies]
serde_derive = { version = "=1.0.181", optional = true, path = "../serde_derive" } serde_derive = { version = "=1.0.183", optional = true, path = "../serde_derive" }
[dev-dependencies] [dev-dependencies]
serde_derive = { version = "1", path = "../serde_derive" } serde_derive = { version = "1", path = "../serde_derive" }
+3
View File
@@ -1789,6 +1789,9 @@ forwarded_impl!((T), Box<[T]>, Vec::into_boxed_slice);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
forwarded_impl!((), Box<str>, String::into_boxed_str); forwarded_impl!((), Box<str>, String::into_boxed_str);
#[cfg(all(feature = "std", any(unix, windows)))]
forwarded_impl!((), Box<OsStr>, OsString::into_boxed_os_str);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T> impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T>
where where
+1 -1
View File
@@ -93,7 +93,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here. // Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.181")] #![doc(html_root_url = "https://docs.rs/serde/1.0.183")]
// Support using Serde without the standard library! // Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and // Unstable functionality only if the user asks for it. For tracking and
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive" name = "serde_derive"
version = "1.0.181" # remember to update html_root_url version = "1.0.183" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std", "no-std::no-alloc"] categories = ["no-std", "no-std::no-alloc"]
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
+116 -110
View File
@@ -723,19 +723,11 @@ fn deserialize_seq(
}) })
} }
}; };
let value_if_none = match field.attrs.default() { let value_if_none = expr_is_missing_seq(None, index_in_seq, field, cattrs, expecting);
attr::Default::Default => quote!(_serde::__private::Default::default()),
attr::Default::Path(path) => quote!(#path()),
attr::Default::None => quote!(
return _serde::__private::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting));
),
};
let assign = quote! { let assign = quote! {
let #var = match #visit { let #var = match #visit {
_serde::__private::Some(__value) => __value, _serde::__private::Some(__value) => __value,
_serde::__private::None => { _serde::__private::None => #value_if_none,
#value_if_none
}
}; };
}; };
index_in_seq += 1; index_in_seq += 1;
@@ -811,24 +803,14 @@ fn deserialize_seq_in_place(
self.place.#member = #default; self.place.#member = #default;
} }
} else { } else {
let value_if_none = match field.attrs.default() { let value_if_none = expr_is_missing_seq(Some(quote!(self.place.#member = )), index_in_seq, field, cattrs, expecting);
attr::Default::Default => quote!(
self.place.#member = _serde::__private::Default::default();
),
attr::Default::Path(path) => quote!(
self.place.#member = #path();
),
attr::Default::None => quote!(
return _serde::__private::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting));
),
};
let write = match field.attrs.deserialize_with() { let write = match field.attrs.deserialize_with() {
None => { None => {
quote! { quote! {
if let _serde::__private::None = _serde::de::SeqAccess::next_element_seed(&mut __seq, if let _serde::__private::None = _serde::de::SeqAccess::next_element_seed(&mut __seq,
_serde::__private::de::InPlaceSeed(&mut self.place.#member))? _serde::__private::de::InPlaceSeed(&mut self.place.#member))?
{ {
#value_if_none #value_if_none;
} }
} }
} }
@@ -841,7 +823,7 @@ fn deserialize_seq_in_place(
self.place.#member = __wrap.value; self.place.#member = __wrap.value;
} }
_serde::__private::None => { _serde::__private::None => {
#value_if_none #value_if_none;
} }
} }
}) })
@@ -983,12 +965,7 @@ fn deserialize_struct(
) )
}) })
.collect(); .collect();
let field_visitor = Stmts(deserialize_generated_identifier( let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs);
&field_names_idents,
cattrs,
false,
None,
));
// untagged struct variants do not get a visit_seq method. The same applies to // untagged struct variants do not get a visit_seq method. The same applies to
// structs that only have a map representation. // structs that only have a map representation.
@@ -1040,7 +1017,7 @@ fn deserialize_struct(
} else { } else {
let field_names = field_names_idents let field_names = field_names_idents
.iter() .iter()
.flat_map(|(_, _, aliases)| aliases); .flat_map(|&(_, _, aliases)| aliases);
Some(quote! { Some(quote! {
#[doc(hidden)] #[doc(hidden)]
@@ -1146,12 +1123,7 @@ fn deserialize_struct_in_place(
}) })
.collect(); .collect();
let field_visitor = Stmts(deserialize_generated_identifier( let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs);
&field_names_idents,
cattrs,
false,
None,
));
let mut_seq = if field_names_idents.is_empty() { let mut_seq = if field_names_idents.is_empty() {
quote!(_) quote!(_)
@@ -1162,7 +1134,7 @@ fn deserialize_struct_in_place(
let visit_map = Stmts(deserialize_map_in_place(params, fields, cattrs)); let visit_map = Stmts(deserialize_map_in_place(params, fields, cattrs));
let field_names = field_names_idents let field_names = field_names_idents
.iter() .iter()
.flat_map(|(_, _, aliases)| aliases); .flat_map(|&(_, _, aliases)| aliases);
let type_name = cattrs.name().deserialize_name(); let type_name = cattrs.name().deserialize_name();
let in_place_impl_generics = de_impl_generics.in_place(); let in_place_impl_generics = de_impl_generics.in_place();
@@ -1265,7 +1237,12 @@ fn prepare_enum_variant_enum(
}) })
.collect(); .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 variants_stmt = {
let variant_names = variant_names_idents.iter().map(|(name, _, _)| name); let variant_names = variant_names_idents.iter().map(|(name, _, _)| name);
@@ -1279,7 +1256,8 @@ fn prepare_enum_variant_enum(
&variant_names_idents, &variant_names_idents,
cattrs, cattrs,
true, true,
other_idx, None,
fallthrough,
)); ));
(variants_stmt, variant_visitor) (variants_stmt, variant_visitor)
@@ -2001,30 +1979,15 @@ fn deserialize_untagged_newtype_variant(
} }
fn deserialize_generated_identifier( fn deserialize_generated_identifier(
fields: &[(String, Ident, Vec<String>)], fields: &[(&str, Ident, &BTreeSet<String>)],
cattrs: &attr::Container, cattrs: &attr::Container,
is_variant: bool, is_variant: bool,
other_idx: Option<usize>, ignore_variant: Option<TokenStream>,
fallthrough: Option<TokenStream>,
) -> Fragment { ) -> Fragment {
let this_value = quote!(__Field); let this_value = quote!(__Field);
let field_idents: &Vec<_> = &fields.iter().map(|(_, ident, _)| ident).collect(); 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( let visitor_impl = Stmts(deserialize_identifier(
&this_value, &this_value,
fields, fields,
@@ -2070,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<String>)],
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 // Generates `Deserialize::deserialize` body for an enum with
// `serde(field_identifier)` or `serde(variant_identifier)` attribute. // `serde(field_identifier)` or `serde(variant_identifier)` attribute.
fn deserialize_custom_identifier( fn deserialize_custom_identifier(
@@ -2131,7 +2121,7 @@ fn deserialize_custom_identifier(
}) })
.collect(); .collect();
let names = names_idents.iter().map(|(name, _, _)| name); let names = names_idents.iter().flat_map(|&(_, _, aliases)| aliases);
let names_const = if fallthrough.is_some() { let names_const = if fallthrough.is_some() {
None None
@@ -2187,32 +2177,24 @@ fn deserialize_custom_identifier(
fn deserialize_identifier( fn deserialize_identifier(
this_value: &TokenStream, this_value: &TokenStream,
fields: &[(String, Ident, Vec<String>)], fields: &[(&str, Ident, &BTreeSet<String>)],
is_variant: bool, is_variant: bool,
fallthrough: Option<TokenStream>, fallthrough: Option<TokenStream>,
fallthrough_borrowed: Option<TokenStream>, fallthrough_borrowed: Option<TokenStream>,
collect_other_fields: bool, collect_other_fields: bool,
expecting: Option<&str>, expecting: Option<&str>,
) -> Fragment { ) -> Fragment {
let mut flat_fields = Vec::new(); let str_mapping = fields.iter().map(|(_, ident, aliases)| {
for (_, ident, aliases) in fields { // `aliases` also contains a main name
flat_fields.extend(aliases.iter().map(|alias| (alias, ident))); quote!(#(#aliases)|* => _serde::__private::Ok(#this_value::#ident))
} });
let bytes_mapping = fields.iter().map(|(_, ident, aliases)| {
let field_strs: &Vec<_> = &flat_fields.iter().map(|(name, _)| name).collect(); // `aliases` also contains a main name
let field_bytes: &Vec<_> = &flat_fields let aliases = aliases
.iter() .iter()
.map(|(name, _)| Literal::byte_string(name.as_bytes())) .map(|alias| Literal::byte_string(alias.as_bytes()));
.collect(); quote!(#(#aliases)|* => _serde::__private::Ok(#this_value::#ident))
});
let constructors: &Vec<_> = &flat_fields
.iter()
.map(|(_, ident)| quote!(#this_value::#ident))
.collect();
let main_constructors: &Vec<_> = &fields
.iter()
.map(|(_, ident, _)| quote!(#this_value::#ident))
.collect();
let expecting = expecting.unwrap_or(if is_variant { let expecting = expecting.unwrap_or(if is_variant {
"variant identifier" "variant identifier"
@@ -2220,8 +2202,6 @@ fn deserialize_identifier(
"field identifier" "field identifier"
}); });
let index_expecting = if is_variant { "variant" } else { "field" };
let bytes_to_str = if fallthrough.is_some() || collect_other_fields { let bytes_to_str = if fallthrough.is_some() || collect_other_fields {
None None
} else { } else {
@@ -2269,21 +2249,6 @@ fn deserialize_identifier(
&fallthrough_arm_tokens &fallthrough_arm_tokens
}; };
let u64_fallthrough_arm_tokens;
let u64_fallthrough_arm = if let Some(fallthrough) = &fallthrough {
fallthrough
} else {
let fallthrough_msg = format!("{} index 0 <= i < {}", index_expecting, 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
};
let variant_indices = 0_u64..;
let visit_other = if collect_other_fields { let visit_other = if collect_other_fields {
quote! { quote! {
fn visit_bool<__E>(self, __value: bool) -> _serde::__private::Result<Self::Value, __E> fn visit_bool<__E>(self, __value: bool) -> _serde::__private::Result<Self::Value, __E>
@@ -2378,15 +2343,33 @@ fn deserialize_identifier(
} }
} }
} else { } else {
let u64_mapping = fields.iter().enumerate().map(|(i, (_, ident, _))| {
let i = i as u64;
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, 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! { quote! {
fn visit_u64<__E>(self, __value: u64) -> _serde::__private::Result<Self::Value, __E> fn visit_u64<__E>(self, __value: u64) -> _serde::__private::Result<Self::Value, __E>
where where
__E: _serde::de::Error, __E: _serde::de::Error,
{ {
match __value { match __value {
#( #(#u64_mapping,)*
#variant_indices => _serde::__private::Ok(#main_constructors),
)*
_ => #u64_fallthrough_arm, _ => #u64_fallthrough_arm,
} }
} }
@@ -2394,6 +2377,8 @@ fn deserialize_identifier(
}; };
let visit_borrowed = if fallthrough_borrowed.is_some() || collect_other_fields { 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); let fallthrough_borrowed_arm = fallthrough_borrowed.as_ref().unwrap_or(fallthrough_arm);
Some(quote! { Some(quote! {
fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::__private::Result<Self::Value, __E> fn visit_borrowed_str<__E>(self, __value: &'de str) -> _serde::__private::Result<Self::Value, __E>
@@ -2401,9 +2386,7 @@ fn deserialize_identifier(
__E: _serde::de::Error, __E: _serde::de::Error,
{ {
match __value { match __value {
#( #(#str_mapping,)*
#field_strs => _serde::__private::Ok(#constructors),
)*
_ => { _ => {
#value_as_borrowed_str_content #value_as_borrowed_str_content
#fallthrough_borrowed_arm #fallthrough_borrowed_arm
@@ -2416,9 +2399,7 @@ fn deserialize_identifier(
__E: _serde::de::Error, __E: _serde::de::Error,
{ {
match __value { match __value {
#( #(#bytes_mapping,)*
#field_bytes => _serde::__private::Ok(#constructors),
)*
_ => { _ => {
#bytes_to_str #bytes_to_str
#value_as_borrowed_bytes_content #value_as_borrowed_bytes_content
@@ -2443,9 +2424,7 @@ fn deserialize_identifier(
__E: _serde::de::Error, __E: _serde::de::Error,
{ {
match __value { match __value {
#( #(#str_mapping,)*
#field_strs => _serde::__private::Ok(#constructors),
)*
_ => { _ => {
#value_as_str_content #value_as_str_content
#fallthrough_arm #fallthrough_arm
@@ -2458,9 +2437,7 @@ fn deserialize_identifier(
__E: _serde::de::Error, __E: _serde::de::Error,
{ {
match __value { match __value {
#( #(#bytes_mapping,)*
#field_bytes => _serde::__private::Ok(#constructors),
)*
_ => { _ => {
#bytes_to_str #bytes_to_str
#value_as_bytes_content #value_as_bytes_content
@@ -2993,6 +2970,35 @@ fn expr_is_missing(field: &Field, cattrs: &attr::Container) -> Fragment {
} }
} }
fn expr_is_missing_seq(
assign_to: Option<TokenStream>,
index: usize,
field: &Field,
cattrs: &attr::Container,
expecting: &str,
) -> TokenStream {
match field.attrs.default() {
attr::Default::Default => {
let span = field.original.span();
return quote_spanned!(span=> #assign_to _serde::__private::Default::default());
}
attr::Default::Path(path) => {
return quote_spanned!(path.span()=> #assign_to #path());
}
attr::Default::None => { /* below */ }
}
match *cattrs.default() {
attr::Default::Default | attr::Default::Path(_) => {
let member = &field.member;
quote!(#assign_to __default.#member)
}
attr::Default::None => quote!(
return _serde::__private::Err(_serde::de::Error::invalid_length(#index, &#expecting))
),
}
}
fn effective_style(variant: &Variant) -> Style { fn effective_style(variant: &Variant) -> Style {
match variant.style { match variant.style {
Style::Newtype if variant.fields[0].attrs.skip_deserializing() => Style::Unit, Style::Newtype if variant.fields[0].attrs.skip_deserializing() => Style::Unit,
+31 -34
View File
@@ -134,7 +134,7 @@ pub struct Name {
serialize_renamed: bool, serialize_renamed: bool,
deserialize: String, deserialize: String,
deserialize_renamed: bool, deserialize_renamed: bool,
deserialize_aliases: Vec<String>, deserialize_aliases: BTreeSet<String>,
} }
fn unraw(ident: &Ident) -> String { fn unraw(ident: &Ident) -> String {
@@ -148,16 +148,12 @@ impl Name {
de_name: Attr<String>, de_name: Attr<String>,
de_aliases: Option<VecAttr<String>>, de_aliases: Option<VecAttr<String>>,
) -> Name { ) -> Name {
let deserialize_aliases = match de_aliases { let mut alias_set = BTreeSet::new();
Some(de_aliases) => { if let Some(de_aliases) = de_aliases {
let mut alias_list = BTreeSet::new(); for alias_name in de_aliases.get() {
for alias_name in de_aliases.get() { alias_set.insert(alias_name);
alias_list.insert(alias_name);
}
alias_list.into_iter().collect()
} }
None => Vec::new(), }
};
let ser_name = ser_name.get(); let ser_name = ser_name.get();
let ser_renamed = ser_name.is_some(); let ser_renamed = ser_name.is_some();
@@ -168,27 +164,22 @@ impl Name {
serialize_renamed: ser_renamed, serialize_renamed: ser_renamed,
deserialize: de_name.unwrap_or(source_name), deserialize: de_name.unwrap_or(source_name),
deserialize_renamed: de_renamed, deserialize_renamed: de_renamed,
deserialize_aliases, deserialize_aliases: alias_set,
} }
} }
/// Return the container name for the container when serializing. /// Return the container name for the container when serializing.
pub fn serialize_name(&self) -> String { pub fn serialize_name(&self) -> &str {
self.serialize.clone() &self.serialize
} }
/// Return the container name for the container when deserializing. /// Return the container name for the container when deserializing.
pub fn deserialize_name(&self) -> String { pub fn deserialize_name(&self) -> &str {
self.deserialize.clone() &self.deserialize
} }
fn deserialize_aliases(&self) -> Vec<String> { fn deserialize_aliases(&self) -> &BTreeSet<String> {
let mut aliases = self.deserialize_aliases.clone(); &self.deserialize_aliases
let main_name = self.deserialize_name();
if !aliases.contains(&main_name) {
aliases.push(main_name);
}
aliases
} }
} }
@@ -405,20 +396,20 @@ impl Container {
if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? { if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? {
match &item.data { match &item.data {
syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields {
syn::Fields::Named(_) => { syn::Fields::Named(_) | syn::Fields::Unnamed(_) => {
default.set(&meta.path, Default::Path(path)); default.set(&meta.path, Default::Path(path));
} }
syn::Fields::Unnamed(_) | syn::Fields::Unit => { syn::Fields::Unit => {
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields"; let msg = "#[serde(default = \"...\")] can only be used on structs that have fields";
cx.syn_error(meta.error(msg)); cx.syn_error(meta.error(msg));
} }
}, },
syn::Data::Enum(_) => { syn::Data::Enum(_) => {
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields"; let msg = "#[serde(default = \"...\")] can only be used on structs";
cx.syn_error(meta.error(msg)); cx.syn_error(meta.error(msg));
} }
syn::Data::Union(_) => { syn::Data::Union(_) => {
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields"; let msg = "#[serde(default = \"...\")] can only be used on structs";
cx.syn_error(meta.error(msg)); cx.syn_error(meta.error(msg));
} }
} }
@@ -427,20 +418,20 @@ impl Container {
// #[serde(default)] // #[serde(default)]
match &item.data { match &item.data {
syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields {
syn::Fields::Named(_) => { syn::Fields::Named(_) | syn::Fields::Unnamed(_) => {
default.set(meta.path, Default::Default); default.set(meta.path, Default::Default);
} }
syn::Fields::Unnamed(_) | syn::Fields::Unit => { syn::Fields::Unit => {
let msg = "#[serde(default)] can only be used on structs with named fields"; let msg = "#[serde(default)] can only be used on structs that have fields";
cx.error_spanned_by(fields, msg); cx.error_spanned_by(fields, msg);
} }
}, },
syn::Data::Enum(_) => { syn::Data::Enum(_) => {
let msg = "#[serde(default)] can only be used on structs with named fields"; let msg = "#[serde(default)] can only be used on structs";
cx.syn_error(meta.error(msg)); cx.syn_error(meta.error(msg));
} }
syn::Data::Union(_) => { syn::Data::Union(_) => {
let msg = "#[serde(default)] can only be used on structs with named fields"; let msg = "#[serde(default)] can only be used on structs";
cx.syn_error(meta.error(msg)); cx.syn_error(meta.error(msg));
} }
} }
@@ -977,7 +968,7 @@ impl Variant {
&self.name &self.name
} }
pub fn aliases(&self) -> Vec<String> { pub fn aliases(&self) -> &BTreeSet<String> {
self.name.deserialize_aliases() self.name.deserialize_aliases()
} }
@@ -988,6 +979,9 @@ impl Variant {
if !self.name.deserialize_renamed { if !self.name.deserialize_renamed {
self.name.deserialize = rules.deserialize.apply_to_variant(&self.name.deserialize); self.name.deserialize = rules.deserialize.apply_to_variant(&self.name.deserialize);
} }
self.name
.deserialize_aliases
.insert(self.name.deserialize.clone());
} }
pub fn rename_all_rules(&self) -> RenameAllRules { pub fn rename_all_rules(&self) -> RenameAllRules {
@@ -1316,7 +1310,7 @@ impl Field {
&self.name &self.name
} }
pub fn aliases(&self) -> Vec<String> { pub fn aliases(&self) -> &BTreeSet<String> {
self.name.deserialize_aliases() self.name.deserialize_aliases()
} }
@@ -1327,6 +1321,9 @@ impl Field {
if !self.name.deserialize_renamed { if !self.name.deserialize_renamed {
self.name.deserialize = rules.deserialize.apply_to_field(&self.name.deserialize); self.name.deserialize = rules.deserialize.apply_to_field(&self.name.deserialize);
} }
self.name
.deserialize_aliases
.insert(self.name.deserialize.clone());
} }
pub fn skip_serializing(&self) -> bool { pub fn skip_serializing(&self) -> bool {
+35 -1
View File
@@ -1,11 +1,12 @@
use crate::internals::ast::{Container, Data, Field, Style}; use crate::internals::ast::{Container, Data, Field, Style};
use crate::internals::attr::{Identifier, TagType}; use crate::internals::attr::{Default, Identifier, TagType};
use crate::internals::{ungroup, Ctxt, Derive}; use crate::internals::{ungroup, Ctxt, Derive};
use syn::{Member, Type}; use syn::{Member, Type};
// Cross-cutting checks that require looking at more than a single attrs object. // Cross-cutting checks that require looking at more than a single attrs object.
// Simpler checks should happen when parsing and building the attrs. // Simpler checks should happen when parsing and building the attrs.
pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
check_default_on_tuple(cx, cont);
check_remote_generic(cx, cont); check_remote_generic(cx, cont);
check_getter(cx, cont); check_getter(cx, cont);
check_flatten(cx, cont); check_flatten(cx, cont);
@@ -17,6 +18,39 @@ pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
check_from_and_try_from(cx, cont); check_from_and_try_from(cx, cont);
} }
// If some field of a tuple struct is marked #[serde(default)] then all fields
// after it must also be marked with that attribute, or the struct must have a
// container-level serde(default) attribute. A field's default value is only
// used for tuple fields if the sequence is exhausted at that point; that means
// all subsequent fields will fail to deserialize if they don't have their own
// default.
fn check_default_on_tuple(cx: &Ctxt, cont: &Container) {
if let Default::None = cont.attrs.default() {
if let Data::Struct(Style::Tuple, fields) = &cont.data {
let mut first_default_index = None;
for (i, field) in fields.iter().enumerate() {
// Skipped fields automatically get the #[serde(default)]
// attribute. We are interested only on non-skipped fields here.
if field.attrs.skip_deserializing() {
continue;
}
if let Default::None = field.attrs.default() {
if let Some(first) = first_default_index {
cx.error_spanned_by(
field.ty,
format!("field must have #[serde(default)] because previous field {} has #[serde(default)]", first),
);
}
continue;
}
if first_default_index.is_none() {
first_default_index = Some(i);
}
}
}
}
}
// Remote derive definition type must have either all of the generics of the // Remote derive definition type must have either all of the generics of the
// remote type: // remote type:
// //
+1 -1
View File
@@ -13,7 +13,7 @@
//! //!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html //! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.181")] #![doc(html_root_url = "https://docs.rs/serde_derive/1.0.183")]
// Ignored clippy lints // Ignored clippy lints
#![allow( #![allow(
// clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054 // clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054
+9 -9
View File
@@ -566,7 +566,7 @@ fn serialize_externally_tagged_variant(
}, },
params, params,
&variant.fields, &variant.fields,
&type_name, type_name,
), ),
} }
} }
@@ -631,7 +631,7 @@ fn serialize_internally_tagged_variant(
StructVariant::InternallyTagged { tag, variant_name }, StructVariant::InternallyTagged { tag, variant_name },
params, params,
&variant.fields, &variant.fields,
&type_name, type_name,
), ),
Style::Tuple => unreachable!("checked in serde_derive_internals"), Style::Tuple => unreachable!("checked in serde_derive_internals"),
} }
@@ -698,7 +698,7 @@ fn serialize_adjacently_tagged_variant(
StructVariant::Untagged, StructVariant::Untagged,
params, params,
&variant.fields, &variant.fields,
&variant_name, variant_name,
), ),
} }
}); });
@@ -794,16 +794,16 @@ fn serialize_untagged_variant(
Style::Tuple => serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields), Style::Tuple => serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields),
Style::Struct => { Style::Struct => {
let type_name = cattrs.name().serialize_name(); let type_name = cattrs.name().serialize_name();
serialize_struct_variant(StructVariant::Untagged, params, &variant.fields, &type_name) serialize_struct_variant(StructVariant::Untagged, params, &variant.fields, type_name)
} }
} }
} }
enum TupleVariant { enum TupleVariant<'a> {
ExternallyTagged { ExternallyTagged {
type_name: String, type_name: &'a str,
variant_index: u32, variant_index: u32,
variant_name: String, variant_name: &'a str,
}, },
Untagged, Untagged,
} }
@@ -870,11 +870,11 @@ fn serialize_tuple_variant(
enum StructVariant<'a> { enum StructVariant<'a> {
ExternallyTagged { ExternallyTagged {
variant_index: u32, variant_index: u32,
variant_name: String, variant_name: &'a str,
}, },
InternallyTagged { InternallyTagged {
tag: &'a str, tag: &'a str,
variant_name: String, variant_name: &'a str,
}, },
Untagged, Untagged,
} }
+1
View File
@@ -1,3 +1,4 @@
#![allow(internal_features)]
#![feature(lang_items, start)] #![feature(lang_items, start)]
#![no_std] #![no_std]
+2 -2
View File
@@ -605,7 +605,7 @@ fn test_unknown_field_rename_struct() {
Token::Str("a4"), Token::Str("a4"),
Token::I32(3), Token::I32(3),
], ],
"unknown field `a4`, expected one of `a1`, `a3`, `a2`, `a5`, `a6`", "unknown field `a4`, expected one of `a1`, `a2`, `a3`, `a5`, `a6`",
); );
} }
@@ -799,7 +799,7 @@ fn test_unknown_field_rename_enum() {
Token::Str("d"), Token::Str("d"),
Token::I8(2), Token::I8(2),
], ],
"unknown field `d`, expected one of `a`, `c`, `b`, `e`, `f`", "unknown field `d`, expected one of `a`, `b`, `c`, `e`, `f`",
); );
} }
+158 -58
View File
@@ -3,86 +3,186 @@
#![allow(clippy::derive_partial_eq_without_eq)] #![allow(clippy::derive_partial_eq_without_eq)]
use serde_derive::Deserialize; use serde_derive::Deserialize;
use serde_test::{assert_de_tokens, Token}; use serde_test::{assert_de_tokens, assert_de_tokens_error, Token};
mod variant_identifier {
use super::*;
#[test]
fn test_variant_identifier() {
#[derive(Deserialize, Debug, PartialEq)] #[derive(Deserialize, Debug, PartialEq)]
#[serde(variant_identifier)] #[serde(variant_identifier)]
enum V { enum V {
Aaa, Aaa,
#[serde(alias = "Ccc", alias = "Ddd")]
Bbb, Bbb,
} }
assert_de_tokens(&V::Aaa, &[Token::U8(0)]); #[test]
assert_de_tokens(&V::Aaa, &[Token::U16(0)]); fn variant1() {
assert_de_tokens(&V::Aaa, &[Token::U32(0)]); assert_de_tokens(&V::Aaa, &[Token::U8(0)]);
assert_de_tokens(&V::Aaa, &[Token::U64(0)]); assert_de_tokens(&V::Aaa, &[Token::U16(0)]);
assert_de_tokens(&V::Aaa, &[Token::Str("Aaa")]); assert_de_tokens(&V::Aaa, &[Token::U32(0)]);
assert_de_tokens(&V::Aaa, &[Token::Bytes(b"Aaa")]); assert_de_tokens(&V::Aaa, &[Token::U64(0)]);
assert_de_tokens(&V::Aaa, &[Token::Str("Aaa")]);
assert_de_tokens(&V::Aaa, &[Token::Bytes(b"Aaa")]);
}
#[test]
fn aliases() {
assert_de_tokens(&V::Bbb, &[Token::U8(1)]);
assert_de_tokens(&V::Bbb, &[Token::U16(1)]);
assert_de_tokens(&V::Bbb, &[Token::U32(1)]);
assert_de_tokens(&V::Bbb, &[Token::U64(1)]);
assert_de_tokens(&V::Bbb, &[Token::Str("Bbb")]);
assert_de_tokens(&V::Bbb, &[Token::Bytes(b"Bbb")]);
assert_de_tokens(&V::Bbb, &[Token::Str("Ccc")]);
assert_de_tokens(&V::Bbb, &[Token::Bytes(b"Ccc")]);
assert_de_tokens(&V::Bbb, &[Token::Str("Ddd")]);
assert_de_tokens(&V::Bbb, &[Token::Bytes(b"Ddd")]);
}
#[test]
fn unknown() {
assert_de_tokens_error::<V>(
&[Token::U8(42)],
"invalid value: integer `42`, expected variant index 0 <= i < 2",
);
assert_de_tokens_error::<V>(
&[Token::U16(42)],
"invalid value: integer `42`, expected variant index 0 <= i < 2",
);
assert_de_tokens_error::<V>(
&[Token::U32(42)],
"invalid value: integer `42`, expected variant index 0 <= i < 2",
);
assert_de_tokens_error::<V>(
&[Token::U64(42)],
"invalid value: integer `42`, expected variant index 0 <= i < 2",
);
assert_de_tokens_error::<V>(
&[Token::Str("Unknown")],
"unknown variant `Unknown`, expected one of `Aaa`, `Bbb`, `Ccc`, `Ddd`",
);
assert_de_tokens_error::<V>(
&[Token::Bytes(b"Unknown")],
"unknown variant `Unknown`, expected one of `Aaa`, `Bbb`, `Ccc`, `Ddd`",
);
}
} }
#[test] mod field_identifier {
fn test_field_identifier() { use super::*;
#[derive(Deserialize, Debug, PartialEq)] #[derive(Deserialize, Debug, PartialEq)]
#[serde(field_identifier, rename_all = "snake_case")] #[serde(field_identifier, rename_all = "snake_case")]
enum F { enum F {
Aaa, Aaa,
#[serde(alias = "ccc", alias = "ddd")]
Bbb, Bbb,
} }
assert_de_tokens(&F::Aaa, &[Token::U8(0)]); #[test]
assert_de_tokens(&F::Aaa, &[Token::U16(0)]); fn field1() {
assert_de_tokens(&F::Aaa, &[Token::U32(0)]); assert_de_tokens(&F::Aaa, &[Token::U8(0)]);
assert_de_tokens(&F::Aaa, &[Token::U64(0)]); assert_de_tokens(&F::Aaa, &[Token::U16(0)]);
assert_de_tokens(&F::Aaa, &[Token::Str("aaa")]); assert_de_tokens(&F::Aaa, &[Token::U32(0)]);
assert_de_tokens(&F::Aaa, &[Token::Bytes(b"aaa")]); assert_de_tokens(&F::Aaa, &[Token::U64(0)]);
} assert_de_tokens(&F::Aaa, &[Token::Str("aaa")]);
assert_de_tokens(&F::Aaa, &[Token::Bytes(b"aaa")]);
#[test]
fn test_unit_fallthrough() {
#[derive(Deserialize, Debug, PartialEq)]
#[serde(field_identifier, rename_all = "snake_case")]
enum F {
Aaa,
Bbb,
#[serde(other)]
Other,
} }
assert_de_tokens(&F::Other, &[Token::U8(42)]); #[test]
assert_de_tokens(&F::Other, &[Token::U16(42)]); fn aliases() {
assert_de_tokens(&F::Other, &[Token::U32(42)]); assert_de_tokens(&F::Bbb, &[Token::U8(1)]);
assert_de_tokens(&F::Other, &[Token::U64(42)]); assert_de_tokens(&F::Bbb, &[Token::U16(1)]);
assert_de_tokens(&F::Other, &[Token::Str("x")]); assert_de_tokens(&F::Bbb, &[Token::U32(1)]);
} assert_de_tokens(&F::Bbb, &[Token::U64(1)]);
#[test] assert_de_tokens(&F::Bbb, &[Token::Str("bbb")]);
fn test_newtype_fallthrough() { assert_de_tokens(&F::Bbb, &[Token::Bytes(b"bbb")]);
#[derive(Deserialize, Debug, PartialEq)]
#[serde(field_identifier, rename_all = "snake_case")] assert_de_tokens(&F::Bbb, &[Token::Str("ccc")]);
enum F { assert_de_tokens(&F::Bbb, &[Token::Bytes(b"ccc")]);
Aaa,
Bbb, assert_de_tokens(&F::Bbb, &[Token::Str("ddd")]);
Other(String), assert_de_tokens(&F::Bbb, &[Token::Bytes(b"ddd")]);
} }
assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]); #[test]
} fn unknown() {
assert_de_tokens_error::<F>(
#[test] &[Token::U8(42)],
fn test_newtype_fallthrough_generic() { "invalid value: integer `42`, expected field index 0 <= i < 2",
#[derive(Deserialize, Debug, PartialEq)] );
#[serde(field_identifier, rename_all = "snake_case")] assert_de_tokens_error::<F>(
enum F<T> { &[Token::U16(42)],
Aaa, "invalid value: integer `42`, expected field index 0 <= i < 2",
Bbb, );
Other(T), assert_de_tokens_error::<F>(
&[Token::U32(42)],
"invalid value: integer `42`, expected field index 0 <= i < 2",
);
assert_de_tokens_error::<F>(
&[Token::U64(42)],
"invalid value: integer `42`, expected field index 0 <= i < 2",
);
assert_de_tokens_error::<F>(
&[Token::Str("unknown")],
"unknown field `unknown`, expected one of `aaa`, `bbb`, `ccc`, `ddd`",
);
assert_de_tokens_error::<F>(
&[Token::Bytes(b"unknown")],
"unknown field `unknown`, expected one of `aaa`, `bbb`, `ccc`, `ddd`",
);
} }
assert_de_tokens(&F::Other(42u8), &[Token::U8(42)]); #[test]
assert_de_tokens(&F::Other(42u16), &[Token::U16(42)]); fn unit_fallthrough() {
assert_de_tokens(&F::Other(42u32), &[Token::U32(42)]); #[derive(Deserialize, Debug, PartialEq)]
assert_de_tokens(&F::Other(42u64), &[Token::U64(42)]); #[serde(field_identifier, rename_all = "snake_case")]
assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]); enum F {
Aaa,
Bbb,
#[serde(other)]
Other,
}
assert_de_tokens(&F::Other, &[Token::U8(42)]);
assert_de_tokens(&F::Other, &[Token::U16(42)]);
assert_de_tokens(&F::Other, &[Token::U32(42)]);
assert_de_tokens(&F::Other, &[Token::U64(42)]);
assert_de_tokens(&F::Other, &[Token::Str("x")]);
}
#[test]
fn newtype_fallthrough() {
#[derive(Deserialize, Debug, PartialEq)]
#[serde(field_identifier, rename_all = "snake_case")]
enum F {
Aaa,
Bbb,
Other(String),
}
assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]);
}
#[test]
fn newtype_fallthrough_generic() {
#[derive(Deserialize, Debug, PartialEq)]
#[serde(field_identifier, rename_all = "snake_case")]
enum F<T> {
Aaa,
Bbb,
Other(T),
}
assert_de_tokens(&F::Other(42u8), &[Token::U8(42)]);
assert_de_tokens(&F::Other(42u16), &[Token::U16(42)]);
assert_de_tokens(&F::Other(42u32), &[Token::U32(42)]);
assert_de_tokens(&F::Other(42u64), &[Token::U64(42)]);
assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]);
}
} }
@@ -1,4 +1,4 @@
error: #[serde(default)] can only be used on structs with named fields error: #[serde(default)] can only be used on structs
--> tests/ui/default-attribute/enum.rs:4:9 --> tests/ui/default-attribute/enum.rs:4:9
| |
4 | #[serde(default)] 4 | #[serde(default)]
@@ -1,4 +1,4 @@
error: #[serde(default = "...")] can only be used on structs with named fields error: #[serde(default = "...")] can only be used on structs
--> tests/ui/default-attribute/enum_path.rs:4:9 --> tests/ui/default-attribute/enum_path.rs:4:9
| |
4 | #[serde(default = "default_e")] 4 | #[serde(default = "default_e")]
@@ -1,7 +0,0 @@
use serde_derive::Deserialize;
#[derive(Deserialize)]
#[serde(default)]
struct T(u8, u8);
fn main() {}
@@ -1,5 +0,0 @@
error: #[serde(default)] can only be used on structs with named fields
--> tests/ui/default-attribute/nameless_struct_fields.rs:5:9
|
5 | struct T(u8, u8);
| ^^^^^^^^
@@ -1,7 +0,0 @@
use serde_derive::Deserialize;
#[derive(Deserialize)]
#[serde(default = "default_t")]
struct T(u8, u8);
fn main() {}
@@ -1,5 +0,0 @@
error: #[serde(default = "...")] can only be used on structs with named fields
--> tests/ui/default-attribute/nameless_struct_fields_path.rs:4:9
|
4 | #[serde(default = "default_t")]
| ^^^^^^^^^^^^^^^^^^^^^
@@ -0,0 +1,47 @@
use serde_derive::Deserialize;
// No errors expected.
#[derive(Deserialize)]
struct T0(u8, u8);
// No errors expected:
// - If both fields are provided, both get value from data.
// - If only one field is provided, the second gets default value.
#[derive(Deserialize)]
struct T1(u8, #[serde(default)] u8);
// ERROR: The first field can get default value only if sequence is empty, but
// that mean that all other fields cannot be deserialized without errors.
#[derive(Deserialize)]
struct T2(#[serde(default)] u8, u8, u8);
// No errors expected:
// - If both fields are provided, both get value from data.
// - If only one field is provided, the second gets default value.
// - If no fields are provided, both get default value.
#[derive(Deserialize)]
struct T3(#[serde(default)] u8, #[serde(default)] u8);
////////////////////////////////////////////////////////////////////////////////
// No errors expected -- missing fields get default values.
#[derive(Deserialize, Default)]
#[serde(default)]
struct T4(u8, u8);
// No errors expected -- missing fields get default values.
#[derive(Deserialize, Default)]
#[serde(default)]
struct T5(#[serde(default)] u8, u8);
// No errors expected -- missing fields get default values.
#[derive(Deserialize, Default)]
#[serde(default)]
struct T6(u8, #[serde(default)] u8);
// No errors expected -- missing fields get default values.
#[derive(Deserialize, Default)]
#[serde(default)]
struct T7(#[serde(default)] u8, #[serde(default)] u8);
fn main() {}
@@ -0,0 +1,11 @@
error: field must have #[serde(default)] because previous field 0 has #[serde(default)]
--> tests/ui/default-attribute/tuple_struct.rs:16:33
|
16 | struct T2(#[serde(default)] u8, u8, u8);
| ^^
error: field must have #[serde(default)] because previous field 0 has #[serde(default)]
--> tests/ui/default-attribute/tuple_struct.rs:16:37
|
16 | struct T2(#[serde(default)] u8, u8, u8);
| ^^
@@ -0,0 +1,76 @@
use serde_derive::Deserialize;
fn d<T>() -> T {
unimplemented!()
}
// No errors expected:
// - If both fields are provided, both get value from data.
// - If only one field is provided, the second gets default value.
#[derive(Deserialize)]
struct T1(u8, #[serde(default = "d")] u8);
// ERROR: The first field can get default value only if sequence is empty, but
// that mean that all other fields cannot be deserialized without errors.
#[derive(Deserialize)]
struct T2(#[serde(default = "d")] u8, u8, u8);
// No errors expected:
// - If both fields are provided, both get value from data.
// - If only one field is provided, the second gets default value.
// - If no fields are provided, both get default value.
#[derive(Deserialize)]
struct T3(#[serde(default = "d")] u8, #[serde(default = "d")] u8);
////////////////////////////////////////////////////////////////////////////////
// No errors expected -- missing fields get default values.
#[derive(Deserialize, Default)]
#[serde(default)]
struct T1D(#[serde(default = "d")] u8, u8);
// No errors expected -- missing fields get default values.
#[derive(Deserialize, Default)]
#[serde(default)]
struct T2D(u8, #[serde(default = "d")] u8);
// No errors expected -- missing fields get default values.
#[derive(Deserialize, Default)]
#[serde(default)]
struct T3D(#[serde(default = "d")] u8, #[serde(default = "d")] u8);
////////////////////////////////////////////////////////////////////////////////
// No errors expected -- missing fields get default values.
#[derive(Deserialize)]
#[serde(default = "d")]
struct T1Path(#[serde(default)] u8, u8);
// No errors expected -- missing fields get default values.
#[derive(Deserialize)]
#[serde(default = "d")]
struct T2Path(u8, #[serde(default)] u8);
// No errors expected -- missing fields get default values.
#[derive(Deserialize)]
#[serde(default = "d")]
struct T3Path(#[serde(default)] u8, #[serde(default)] u8);
////////////////////////////////////////////////////////////////////////////////
// No errors expected -- missing fields get default values.
#[derive(Deserialize)]
#[serde(default = "d")]
struct T1PathD(#[serde(default = "d")] u8, u8);
// No errors expected -- missing fields get default values.
#[derive(Deserialize)]
#[serde(default = "d")]
struct T2PathD(u8, #[serde(default = "d")] u8);
// No errors expected -- missing fields get default values.
#[derive(Deserialize)]
#[serde(default = "d")]
struct T3PathD(#[serde(default = "d")] u8, #[serde(default = "d")] u8);
fn main() {}
@@ -0,0 +1,11 @@
error: field must have #[serde(default)] because previous field 0 has #[serde(default)]
--> tests/ui/default-attribute/tuple_struct_path.rs:16:39
|
16 | struct T2(#[serde(default = "d")] u8, u8, u8);
| ^^
error: field must have #[serde(default)] because previous field 0 has #[serde(default)]
--> tests/ui/default-attribute/tuple_struct_path.rs:16:43
|
16 | struct T2(#[serde(default = "d")] u8, u8, u8);
| ^^