Compare commits

..

38 Commits

Author SHA1 Message Date
David Tolnay 151b45ae36 Release 1.0.184 2023-08-20 19:49:55 -07:00
Oli Scherer 4617c957b9 Merge pull request #2587 from wucke13/master
fix shebang in build.sh
2023-08-21 00:22:31 +02:00
wucke13 2547ed83ca fix shebang in build.sh
This fixes #2583.
2023-08-20 23:51:47 +02:00
David Tolnay bfcd44704f Discard the possibility of upx compressing binary
This adds too much decompression overhead per invocation.

It could work if the subprocess were reused across multiple macro
expansions (https://github.com/serde-rs/serde/pull/2523).
2023-08-17 19:07:42 -07:00
David Tolnay 7b548db91e Merge pull request #2572 from serde-rs/cargorm
Adopt `cargo rm` after Cargo bugfix
2023-08-14 04:21:23 -07:00
David Tolnay d39dea85ad Adopt 'cargo rm' after Cargo bugfix 2023-08-14 04:12:55 -07:00
David Tolnay 5e56c9fba8 Merge pull request #2570 from dtolnay/remotenonexhaustive
Treat unmatched non-exhaustive remote variant as serde(skip)
2023-08-13 21:20:42 -07:00
David Tolnay 8d3a03288b Treat unmatched non-exhaustive remote variant as serde(skip) 2023-08-13 21:14:33 -07:00
David Tolnay cb490ec16d Add test of remote enum with non_exhaustive 2023-08-13 21:14:12 -07:00
David Tolnay 45271c3676 Resolve ignored_unit_patterns pedantic clippy lint
warning: matching over `()` is more explicit
       --> serde_derive/src/internals/attr.rs:710:33
        |
    710 |         (Some((untagged_tokens, _)), Some((tag_tokens, _)), None) => {
        |                                 ^ help: use `()` instead of `_`: `()`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ignored_unit_patterns
        = note: `-W clippy::ignored-unit-patterns` implied by `-W clippy::pedantic`

    warning: matching over `()` is more explicit
       --> serde_derive/src/internals/attr.rs:721:33
        |
    721 |         (Some((untagged_tokens, _)), None, Some((content_tokens, _))) => {
        |                                 ^ help: use `()` instead of `_`: `()`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ignored_unit_patterns

    warning: matching over `()` is more explicit
       --> serde_derive/src/internals/attr.rs:728:33
        |
    728 |         (Some((untagged_tokens, _)), Some((tag_tokens, _)), Some((content_tokens, _))) => {
        |                                 ^ help: use `()` instead of `_`: `()`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ignored_unit_patterns

    warning: matching over `()` is more explicit
       --> serde_derive/src/internals/attr.rs:750:44
        |
    750 |         (_, Some((field_identifier_tokens, _)), Some((variant_identifier_tokens, _))) => {
        |                                            ^ help: use `()` instead of `_`: `()`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ignored_unit_patterns

    warning: matching over `()` is more explicit
       --> serde_derive/src/internals/attr.rs:750:82
        |
    750 |         (_, Some((field_identifier_tokens, _)), Some((variant_identifier_tokens, _))) => {
        |                                                                                  ^ help: use `()` instead of `_`: `()`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ignored_unit_patterns
2023-08-11 20:27:21 -07:00
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
30 changed files with 560 additions and 261 deletions
+3 -5
View File
@@ -122,13 +122,11 @@ jobs:
- run: precompiled/build.sh
- name: replace serde_derive dependency with precompiled
run: |
# FIXME: consider using `cargo rm serde_derive` but it's currently broken
# https://github.com/rust-lang/cargo/issues/12419
sed -i '/serde_derive =/d' serde/Cargo.toml
sed -i '/derive = \["serde_derive"\]/d' serde/Cargo.toml
cargo rm serde_derive --package serde
cargo rm serde_derive --package serde --dev
sed -i '/"serde_derive"/d' Cargo.toml
sed -i '/\[workspace\]/d' precompiled/serde_derive/Cargo.toml
cargo add --dev serde_derive --path precompiled/serde_derive --manifest-path test_suite/Cargo.toml
cargo add --dev serde_derive --path precompiled/serde_derive --package serde_test_suite
git diff
- run: cd test_suite && cargo test --features unstable -- --skip ui --exact
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.181"
version = "1.0.184"
authors = ["David Tolnay <dtolnay@gmail.com>"]
publish = false
+1 -3
View File
@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null
set -e -x
@@ -17,5 +17,3 @@ cargo +nightly build \
rm -f serde_derive/serde_derive-x86_64-unknown-linux-gnu
mv serde_derive/serde_derive{,-x86_64-unknown-linux-gnu}
#upx --best --lzma serde_derive/serde_derive-x86_64-unknown-linux-gnu
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.181"
version = "1.0.184"
authors = ["David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std", "no-std::no-alloc"]
description = "Implementation of #[derive(Serialize, Deserialize)]"
+1 -1
View File
@@ -13,7 +13,7 @@
//!
//! [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.184")]
#[cfg(not(all(target_arch = "x86_64", target_os = "linux", target_env = "gnu")))]
include!("lib_from_source.rs");
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "serde"
version = "1.0.181" # remember to update html_root_url and serde_derive dependency
version = "1.0.184" # remember to update html_root_url and serde_derive dependency
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs"
categories = ["encoding", "no-std", "no-std::no-alloc"]
@@ -15,7 +15,7 @@ repository = "https://github.com/serde-rs/serde"
rust-version = "1.31"
[dependencies]
serde_derive = { version = "=1.0.181", optional = true, path = "../serde_derive" }
serde_derive = { version = "=1.0.184", optional = true, path = "../serde_derive" }
[dev-dependencies]
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"))]
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"))]
impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T>
where
+1 -1
View File
@@ -93,7 +93,7 @@
////////////////////////////////////////////////////////////////////////////////
// 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.184")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and
+13
View File
@@ -1370,3 +1370,16 @@ impl Serialize for AdjacentlyTaggedEnumVariant {
serializer.serialize_unit_variant(self.enum_name, self.variant_index, self.variant_name)
}
}
// Error when Serialize for a non_exhaustive remote enum encounters a variant
// that is not recognized.
pub struct CannotSerializeVariant<T>(pub T);
impl<T> Display for CannotSerializeVariant<T>
where
T: Debug,
{
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "enum variant cannot be serialized: {:?}", self.0)
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "serde_derive"
version = "1.0.181" # remember to update html_root_url
version = "1.0.184" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std", "no-std::no-alloc"]
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() {
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 value_if_none = expr_is_missing_seq(None, index_in_seq, field, cattrs, expecting);
let assign = quote! {
let #var = match #visit {
_serde::__private::Some(__value) => __value,
_serde::__private::None => {
#value_if_none
}
_serde::__private::None => #value_if_none,
};
};
index_in_seq += 1;
@@ -811,24 +803,14 @@ fn deserialize_seq_in_place(
self.place.#member = #default;
}
} else {
let value_if_none = match field.attrs.default() {
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 value_if_none = expr_is_missing_seq(Some(quote!(self.place.#member = )), index_in_seq, field, cattrs, expecting);
let write = match field.attrs.deserialize_with() {
None => {
quote! {
if let _serde::__private::None = _serde::de::SeqAccess::next_element_seed(&mut __seq,
_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;
}
_serde::__private::None => {
#value_if_none
#value_if_none;
}
}
})
@@ -983,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.
@@ -1040,7 +1017,7 @@ fn deserialize_struct(
} else {
let field_names = field_names_idents
.iter()
.flat_map(|(_, _, aliases)| aliases);
.flat_map(|&(_, _, aliases)| aliases);
Some(quote! {
#[doc(hidden)]
@@ -1146,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!(_)
@@ -1162,7 +1134,7 @@ fn deserialize_struct_in_place(
let visit_map = Stmts(deserialize_map_in_place(params, fields, cattrs));
let field_names = field_names_idents
.iter()
.flat_map(|(_, _, aliases)| aliases);
.flat_map(|&(_, _, aliases)| aliases);
let type_name = cattrs.name().deserialize_name();
let in_place_impl_generics = de_impl_generics.in_place();
@@ -1265,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);
@@ -1279,7 +1256,8 @@ fn prepare_enum_variant_enum(
&variant_names_idents,
cattrs,
true,
other_idx,
None,
fallthrough,
));
(variants_stmt, variant_visitor)
@@ -2001,30 +1979,15 @@ fn deserialize_untagged_newtype_variant(
}
fn deserialize_generated_identifier(
fields: &[(String, Ident, Vec<String>)],
fields: &[(&str, Ident, &BTreeSet<String>)],
cattrs: &attr::Container,
is_variant: bool,
other_idx: Option<usize>,
ignore_variant: Option<TokenStream>,
fallthrough: Option<TokenStream>,
) -> 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,
@@ -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
// `serde(field_identifier)` or `serde(variant_identifier)` attribute.
fn deserialize_custom_identifier(
@@ -2131,7 +2121,7 @@ fn deserialize_custom_identifier(
})
.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() {
None
@@ -2187,32 +2177,24 @@ fn deserialize_custom_identifier(
fn deserialize_identifier(
this_value: &TokenStream,
fields: &[(String, Ident, Vec<String>)],
fields: &[(&str, Ident, &BTreeSet<String>)],
is_variant: bool,
fallthrough: Option<TokenStream>,
fallthrough_borrowed: Option<TokenStream>,
collect_other_fields: bool,
expecting: Option<&str>,
) -> Fragment {
let mut flat_fields = Vec::new();
for (_, ident, aliases) in fields {
flat_fields.extend(aliases.iter().map(|alias| (alias, ident)));
}
let field_strs: &Vec<_> = &flat_fields.iter().map(|(name, _)| name).collect();
let field_bytes: &Vec<_> = &flat_fields
.iter()
.map(|(name, _)| Literal::byte_string(name.as_bytes()))
.collect();
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 str_mapping = fields.iter().map(|(_, ident, aliases)| {
// `aliases` also contains a main name
quote!(#(#aliases)|* => _serde::__private::Ok(#this_value::#ident))
});
let bytes_mapping = fields.iter().map(|(_, ident, aliases)| {
// `aliases` also contains a main name
let aliases = aliases
.iter()
.map(|alias| Literal::byte_string(alias.as_bytes()));
quote!(#(#aliases)|* => _serde::__private::Ok(#this_value::#ident))
});
let expecting = expecting.unwrap_or(if is_variant {
"variant identifier"
@@ -2220,8 +2202,6 @@ fn deserialize_identifier(
"field identifier"
});
let index_expecting = if is_variant { "variant" } else { "field" };
let bytes_to_str = if fallthrough.is_some() || collect_other_fields {
None
} else {
@@ -2269,21 +2249,6 @@ fn deserialize_identifier(
&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 {
quote! {
fn visit_bool<__E>(self, __value: bool) -> _serde::__private::Result<Self::Value, __E>
@@ -2378,15 +2343,33 @@ fn deserialize_identifier(
}
}
} 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! {
fn visit_u64<__E>(self, __value: u64) -> _serde::__private::Result<Self::Value, __E>
where
__E: _serde::de::Error,
{
match __value {
#(
#variant_indices => _serde::__private::Ok(#main_constructors),
)*
#(#u64_mapping,)*
_ => #u64_fallthrough_arm,
}
}
@@ -2394,6 +2377,8 @@ fn deserialize_identifier(
};
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);
Some(quote! {
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,
{
match __value {
#(
#field_strs => _serde::__private::Ok(#constructors),
)*
#(#str_mapping,)*
_ => {
#value_as_borrowed_str_content
#fallthrough_borrowed_arm
@@ -2416,9 +2399,7 @@ fn deserialize_identifier(
__E: _serde::de::Error,
{
match __value {
#(
#field_bytes => _serde::__private::Ok(#constructors),
)*
#(#bytes_mapping,)*
_ => {
#bytes_to_str
#value_as_borrowed_bytes_content
@@ -2443,9 +2424,7 @@ fn deserialize_identifier(
__E: _serde::de::Error,
{
match __value {
#(
#field_strs => _serde::__private::Ok(#constructors),
)*
#(#str_mapping,)*
_ => {
#value_as_str_content
#fallthrough_arm
@@ -2458,9 +2437,7 @@ fn deserialize_identifier(
__E: _serde::de::Error,
{
match __value {
#(
#field_bytes => _serde::__private::Ok(#constructors),
)*
#(#bytes_mapping,)*
_ => {
#bytes_to_str
#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 {
match variant.style {
Style::Newtype if variant.fields[0].attrs.skip_deserializing() => Style::Unit,
+44 -38
View File
@@ -134,7 +134,7 @@ pub struct Name {
serialize_renamed: bool,
deserialize: String,
deserialize_renamed: bool,
deserialize_aliases: Vec<String>,
deserialize_aliases: BTreeSet<String>,
}
fn unraw(ident: &Ident) -> String {
@@ -148,16 +148,12 @@ impl Name {
de_name: Attr<String>,
de_aliases: Option<VecAttr<String>>,
) -> Name {
let deserialize_aliases = match de_aliases {
Some(de_aliases) => {
let mut alias_list = BTreeSet::new();
for alias_name in de_aliases.get() {
alias_list.insert(alias_name);
}
alias_list.into_iter().collect()
let mut alias_set = BTreeSet::new();
if let Some(de_aliases) = de_aliases {
for alias_name in de_aliases.get() {
alias_set.insert(alias_name);
}
None => Vec::new(),
};
}
let ser_name = ser_name.get();
let ser_renamed = ser_name.is_some();
@@ -168,27 +164,22 @@ impl Name {
serialize_renamed: ser_renamed,
deserialize: de_name.unwrap_or(source_name),
deserialize_renamed: de_renamed,
deserialize_aliases,
deserialize_aliases: alias_set,
}
}
/// Return the container name for the container when serializing.
pub fn serialize_name(&self) -> String {
self.serialize.clone()
pub fn serialize_name(&self) -> &str {
&self.serialize
}
/// Return the container name for the container when deserializing.
pub fn deserialize_name(&self) -> String {
self.deserialize.clone()
pub fn deserialize_name(&self) -> &str {
&self.deserialize
}
fn deserialize_aliases(&self) -> Vec<String> {
let mut aliases = self.deserialize_aliases.clone();
let main_name = self.deserialize_name();
if !aliases.contains(&main_name) {
aliases.push(main_name);
}
aliases
fn deserialize_aliases(&self) -> &BTreeSet<String> {
&self.deserialize_aliases
}
}
@@ -230,6 +221,7 @@ pub struct Container {
is_packed: bool,
/// Error message generated when type can't be deserialized
expecting: Option<String>,
non_exhaustive: bool,
}
/// Styles of representing an enum.
@@ -315,9 +307,12 @@ impl Container {
let mut variant_identifier = BoolAttr::none(cx, VARIANT_IDENTIFIER);
let mut serde_path = Attr::none(cx, CRATE);
let mut expecting = Attr::none(cx, EXPECTING);
let mut non_exhaustive = false;
for attr in &item.attrs {
if attr.path() != SERDE {
non_exhaustive |=
matches!(&attr.meta, syn::Meta::Path(path) if path == NON_EXHAUSTIVE);
continue;
}
@@ -405,20 +400,20 @@ impl Container {
if let Some(path) = parse_lit_into_expr_path(cx, DEFAULT, &meta)? {
match &item.data {
syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields {
syn::Fields::Named(_) => {
syn::Fields::Named(_) | syn::Fields::Unnamed(_) => {
default.set(&meta.path, Default::Path(path));
}
syn::Fields::Unnamed(_) | syn::Fields::Unit => {
let msg = "#[serde(default = \"...\")] can only be used on structs with named fields";
syn::Fields::Unit => {
let msg = "#[serde(default = \"...\")] can only be used on structs that have fields";
cx.syn_error(meta.error(msg));
}
},
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));
}
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));
}
}
@@ -427,20 +422,20 @@ impl Container {
// #[serde(default)]
match &item.data {
syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields {
syn::Fields::Named(_) => {
syn::Fields::Named(_) | syn::Fields::Unnamed(_) => {
default.set(meta.path, Default::Default);
}
syn::Fields::Unnamed(_) | syn::Fields::Unit => {
let msg = "#[serde(default)] can only be used on structs with named fields";
syn::Fields::Unit => {
let msg = "#[serde(default)] can only be used on structs that have fields";
cx.error_spanned_by(fields, msg);
}
},
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));
}
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));
}
}
@@ -596,6 +591,7 @@ impl Container {
serde_path: serde_path.get(),
is_packed,
expecting: expecting.get(),
non_exhaustive,
}
}
@@ -681,6 +677,10 @@ impl Container {
pub fn expecting(&self) -> Option<&str> {
self.expecting.as_ref().map(String::as_ref)
}
pub fn non_exhaustive(&self) -> bool {
self.non_exhaustive
}
}
fn decide_tag(
@@ -716,7 +716,7 @@ fn decide_tag(
}
TagType::Internal { tag }
}
(Some((untagged_tokens, _)), Some((tag_tokens, _)), None) => {
(Some((untagged_tokens, ())), Some((tag_tokens, _)), None) => {
let msg = "enum cannot be both untagged and internally tagged";
cx.error_spanned_by(untagged_tokens, msg);
cx.error_spanned_by(tag_tokens, msg);
@@ -727,14 +727,14 @@ fn decide_tag(
cx.error_spanned_by(content_tokens, msg);
TagType::External
}
(Some((untagged_tokens, _)), None, Some((content_tokens, _))) => {
(Some((untagged_tokens, ())), None, Some((content_tokens, _))) => {
let msg = "untagged enum cannot have #[serde(content = \"...\")]";
cx.error_spanned_by(untagged_tokens, msg);
cx.error_spanned_by(content_tokens, msg);
TagType::External
}
(None, Some((_, tag)), Some((_, content))) => TagType::Adjacent { tag, content },
(Some((untagged_tokens, _)), Some((tag_tokens, _)), Some((content_tokens, _))) => {
(Some((untagged_tokens, ())), Some((tag_tokens, _)), Some((content_tokens, _))) => {
let msg = "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]";
cx.error_spanned_by(untagged_tokens, msg);
cx.error_spanned_by(tag_tokens, msg);
@@ -756,7 +756,7 @@ fn decide_identifier(
variant_identifier.0.get_with_tokens(),
) {
(_, None, None) => Identifier::No,
(_, Some((field_identifier_tokens, _)), Some((variant_identifier_tokens, _))) => {
(_, Some((field_identifier_tokens, ())), Some((variant_identifier_tokens, ()))) => {
let msg =
"#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set";
cx.error_spanned_by(field_identifier_tokens, msg);
@@ -977,7 +977,7 @@ impl Variant {
&self.name
}
pub fn aliases(&self) -> Vec<String> {
pub fn aliases(&self) -> &BTreeSet<String> {
self.name.deserialize_aliases()
}
@@ -988,6 +988,9 @@ impl Variant {
if !self.name.deserialize_renamed {
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 {
@@ -1316,7 +1319,7 @@ impl Field {
&self.name
}
pub fn aliases(&self) -> Vec<String> {
pub fn aliases(&self) -> &BTreeSet<String> {
self.name.deserialize_aliases()
}
@@ -1327,6 +1330,9 @@ impl Field {
if !self.name.deserialize_renamed {
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 {
+35 -1
View File
@@ -1,11 +1,12 @@
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 syn::{Member, Type};
// Cross-cutting checks that require looking at more than a single attrs object.
// Simpler checks should happen when parsing and building the attrs.
pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) {
check_default_on_tuple(cx, cont);
check_remote_generic(cx, cont);
check_getter(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);
}
// 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 type:
//
+1
View File
@@ -19,6 +19,7 @@ pub const FLATTEN: Symbol = Symbol("flatten");
pub const FROM: Symbol = Symbol("from");
pub const GETTER: Symbol = Symbol("getter");
pub const INTO: Symbol = Symbol("into");
pub const NON_EXHAUSTIVE: Symbol = Symbol("non_exhaustive");
pub const OTHER: Symbol = Symbol("other");
pub const REMOTE: Symbol = Symbol("remote");
pub const RENAME: Symbol = Symbol("rename");
+1 -1
View File
@@ -13,7 +13,7 @@
//!
//! [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.184")]
// Ignored clippy lints
#![allow(
// clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054
+16 -10
View File
@@ -401,7 +401,7 @@ fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Cont
let self_var = &params.self_var;
let arms: Vec<_> = variants
let mut arms: Vec<_> = variants
.iter()
.enumerate()
.map(|(variant_index, variant)| {
@@ -409,6 +409,12 @@ fn serialize_enum(params: &Parameters, variants: &[Variant], cattrs: &attr::Cont
})
.collect();
if cattrs.non_exhaustive() {
arms.push(quote! {
unrecognized => _serde::__private::Err(_serde::ser::Error::custom(_serde::__private::ser::CannotSerializeVariant(unrecognized))),
});
}
quote_expr! {
match *#self_var {
#(#arms)*
@@ -566,7 +572,7 @@ fn serialize_externally_tagged_variant(
},
params,
&variant.fields,
&type_name,
type_name,
),
}
}
@@ -631,7 +637,7 @@ fn serialize_internally_tagged_variant(
StructVariant::InternallyTagged { tag, variant_name },
params,
&variant.fields,
&type_name,
type_name,
),
Style::Tuple => unreachable!("checked in serde_derive_internals"),
}
@@ -698,7 +704,7 @@ fn serialize_adjacently_tagged_variant(
StructVariant::Untagged,
params,
&variant.fields,
&variant_name,
variant_name,
),
}
});
@@ -794,16 +800,16 @@ fn serialize_untagged_variant(
Style::Tuple => serialize_tuple_variant(TupleVariant::Untagged, params, &variant.fields),
Style::Struct => {
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 {
type_name: String,
type_name: &'a str,
variant_index: u32,
variant_name: String,
variant_name: &'a str,
},
Untagged,
}
@@ -870,11 +876,11 @@ fn serialize_tuple_variant(
enum StructVariant<'a> {
ExternallyTagged {
variant_index: u32,
variant_name: String,
variant_name: &'a str,
},
InternallyTagged {
tag: &'a str,
variant_name: String,
variant_name: &'a str,
},
Untagged,
}
+1
View File
@@ -1,3 +1,4 @@
#![allow(internal_features)]
#![feature(lang_items, start)]
#![no_std]
+2 -2
View File
@@ -605,7 +605,7 @@ fn test_unknown_field_rename_struct() {
Token::Str("a4"),
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::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)]
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)]
#[serde(variant_identifier)]
enum V {
Aaa,
#[serde(alias = "Ccc", alias = "Ddd")]
Bbb,
}
assert_de_tokens(&V::Aaa, &[Token::U8(0)]);
assert_de_tokens(&V::Aaa, &[Token::U16(0)]);
assert_de_tokens(&V::Aaa, &[Token::U32(0)]);
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 variant1() {
assert_de_tokens(&V::Aaa, &[Token::U8(0)]);
assert_de_tokens(&V::Aaa, &[Token::U16(0)]);
assert_de_tokens(&V::Aaa, &[Token::U32(0)]);
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]
fn test_field_identifier() {
mod field_identifier {
use super::*;
#[derive(Deserialize, Debug, PartialEq)]
#[serde(field_identifier, rename_all = "snake_case")]
enum F {
Aaa,
#[serde(alias = "ccc", alias = "ddd")]
Bbb,
}
assert_de_tokens(&F::Aaa, &[Token::U8(0)]);
assert_de_tokens(&F::Aaa, &[Token::U16(0)]);
assert_de_tokens(&F::Aaa, &[Token::U32(0)]);
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,
#[test]
fn field1() {
assert_de_tokens(&F::Aaa, &[Token::U8(0)]);
assert_de_tokens(&F::Aaa, &[Token::U16(0)]);
assert_de_tokens(&F::Aaa, &[Token::U32(0)]);
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")]);
}
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 aliases() {
assert_de_tokens(&F::Bbb, &[Token::U8(1)]);
assert_de_tokens(&F::Bbb, &[Token::U16(1)]);
assert_de_tokens(&F::Bbb, &[Token::U32(1)]);
assert_de_tokens(&F::Bbb, &[Token::U64(1)]);
#[test]
fn test_newtype_fallthrough() {
#[derive(Deserialize, Debug, PartialEq)]
#[serde(field_identifier, rename_all = "snake_case")]
enum F {
Aaa,
Bbb,
Other(String),
assert_de_tokens(&F::Bbb, &[Token::Str("bbb")]);
assert_de_tokens(&F::Bbb, &[Token::Bytes(b"bbb")]);
assert_de_tokens(&F::Bbb, &[Token::Str("ccc")]);
assert_de_tokens(&F::Bbb, &[Token::Bytes(b"ccc")]);
assert_de_tokens(&F::Bbb, &[Token::Str("ddd")]);
assert_de_tokens(&F::Bbb, &[Token::Bytes(b"ddd")]);
}
assert_de_tokens(&F::Other("x".to_owned()), &[Token::Str("x")]);
}
#[test]
fn test_newtype_fallthrough_generic() {
#[derive(Deserialize, Debug, PartialEq)]
#[serde(field_identifier, rename_all = "snake_case")]
enum F<T> {
Aaa,
Bbb,
Other(T),
#[test]
fn unknown() {
assert_de_tokens_error::<F>(
&[Token::U8(42)],
"invalid value: integer `42`, expected field index 0 <= i < 2",
);
assert_de_tokens_error::<F>(
&[Token::U16(42)],
"invalid value: integer `42`, expected field index 0 <= i < 2",
);
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)]);
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")]);
#[test]
fn 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)]);
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")]);
}
}
+12
View File
@@ -125,6 +125,9 @@ struct Test {
#[serde(with = "EnumConcrete")]
enum_concrete: remote::EnumGeneric<u8>,
#[serde(with = "ErrorKindDef")]
io_error_kind: std::io::ErrorKind,
}
#[derive(Serialize, Deserialize)]
@@ -197,6 +200,15 @@ enum EnumConcrete {
Variant(u8),
}
#[derive(Serialize, Deserialize)]
#[serde(remote = "std::io::ErrorKind")]
#[non_exhaustive]
enum ErrorKindDef {
NotFound,
PermissionDenied,
// ...
}
impl From<PrimitivePrivDef> for remote::PrimitivePriv {
fn from(def: PrimitivePrivDef) -> Self {
remote::PrimitivePriv::new(def.0)
@@ -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
|
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
|
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);
| ^^