mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-04-23 15:18:01 +00:00
Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 05a5b7e3c6 | |||
| 3bff326fb3 | |||
| aaadd93878 | |||
| 9c864f0b02 | |||
| 070cce0d9c | |||
| b58e8bac12 | |||
| ada50b077e | |||
| 5e313a7330 | |||
| 2a36d11238 | |||
| b6685cf9dd | |||
| fc273c6763 | |||
| bd7b0e257e | |||
| 73931692b2 | |||
| 4d93e9f44c | |||
| da55ed7e8d | |||
| e3617e1f28 | |||
| 431636af0d | |||
| 891ced598a | |||
| 57dc0ee769 | |||
| 5e102c4da1 | |||
| 5c33931422 | |||
| 4aa54222f4 | |||
| ef4f860384 | |||
| 9bd52ec5c1 | |||
| 5cdd82d41e | |||
| 110bf10481 | |||
| 43035f6f37 | |||
| 83b1a3d5dc | |||
| 878110a4bc | |||
| 59ec8b7db2 | |||
| cae1b43829 | |||
| 99fde4ee3e | |||
| afe3872810 | |||
| 3a3e6bf103 | |||
| 935f0bd70f | |||
| 5c18bfeda6 | |||
| 957ef206d1 | |||
| 0c367838cc | |||
| 2023cf345f | |||
| f709fc05b0 | |||
| 089aae1292 | |||
| 855acaf112 | |||
| 7ca7720262 | |||
| 78fea3aa4a | |||
| 1efb8b6a53 | |||
| bc1960b106 | |||
| 967023b755 | |||
| bb51e68f16 |
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_derive"
|
||||
version = "1.0.180"
|
||||
version = "1.0.183"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
publish = false
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_derive"
|
||||
version = "1.0.180"
|
||||
version = "1.0.183"
|
||||
authors = ["David Tolnay <dtolnay@gmail.com>"]
|
||||
categories = ["no-std", "no-std::no-alloc"]
|
||||
description = "Implementation of #[derive(Serialize, Deserialize)]"
|
||||
|
||||
@@ -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.180")]
|
||||
#![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")))]
|
||||
include!("lib_from_source.rs");
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde"
|
||||
version = "1.0.180" # 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>"]
|
||||
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.180", optional = true, path = "../serde_derive" }
|
||||
serde_derive = { version = "=1.0.183", optional = true, path = "../serde_derive" }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_derive = { version = "1", path = "../serde_derive" }
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::de::{
|
||||
use crate::seed::InPlaceSeed;
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
use crate::__private::size_hint;
|
||||
use crate::de::size_hint;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -122,6 +122,7 @@ pub mod value;
|
||||
mod format;
|
||||
mod ignored_any;
|
||||
mod impls;
|
||||
pub(crate) mod size_hint;
|
||||
mod utf8;
|
||||
|
||||
pub use self::ignored_any::IgnoredAny;
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
use crate::lib::*;
|
||||
|
||||
use self::private::{First, Second};
|
||||
use crate::__private::size_hint;
|
||||
use crate::de::{self, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor};
|
||||
use crate::de::{self, size_hint, Deserializer, Expected, IntoDeserializer, SeqAccess, Visitor};
|
||||
use crate::ser;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
+43
-47
@@ -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.180")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.183")]
|
||||
// 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
|
||||
@@ -102,55 +102,51 @@
|
||||
// https://github.com/serde-rs/serde/issues/812
|
||||
#![cfg_attr(feature = "unstable", feature(error_in_core, never_type))]
|
||||
#![allow(unknown_lints, bare_trait_objects, deprecated)]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
|
||||
// Ignored clippy and clippy_pedantic lints
|
||||
#![cfg_attr(
|
||||
feature = "cargo-clippy",
|
||||
allow(
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
||||
unnested_or_patterns,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/7768
|
||||
semicolon_if_nothing_returned,
|
||||
// not available in our oldest supported compiler
|
||||
empty_enum,
|
||||
type_repetition_in_bounds, // https://github.com/rust-lang/rust-clippy/issues/8772
|
||||
// integer and float ser/de requires these sorts of casts
|
||||
cast_possible_truncation,
|
||||
cast_possible_wrap,
|
||||
cast_sign_loss,
|
||||
// things are often more readable this way
|
||||
cast_lossless,
|
||||
module_name_repetitions,
|
||||
option_if_let_else,
|
||||
single_match_else,
|
||||
type_complexity,
|
||||
use_self,
|
||||
zero_prefixed_literal,
|
||||
// correctly used
|
||||
derive_partial_eq_without_eq,
|
||||
enum_glob_use,
|
||||
explicit_auto_deref,
|
||||
let_underscore_untyped,
|
||||
map_err_ignore,
|
||||
new_without_default,
|
||||
result_unit_err,
|
||||
wildcard_imports,
|
||||
// not practical
|
||||
needless_pass_by_value,
|
||||
similar_names,
|
||||
too_many_lines,
|
||||
// preference
|
||||
doc_markdown,
|
||||
unseparated_literal_suffix,
|
||||
// false positive
|
||||
needless_doctest_main,
|
||||
// noisy
|
||||
missing_errors_doc,
|
||||
must_use_candidate,
|
||||
)
|
||||
#![allow(
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
|
||||
clippy::unnested_or_patterns,
|
||||
// clippy bug: https://github.com/rust-lang/rust-clippy/issues/7768
|
||||
clippy::semicolon_if_nothing_returned,
|
||||
// not available in our oldest supported compiler
|
||||
clippy::empty_enum,
|
||||
clippy::type_repetition_in_bounds, // https://github.com/rust-lang/rust-clippy/issues/8772
|
||||
// integer and float ser/de requires these sorts of casts
|
||||
clippy::cast_possible_truncation,
|
||||
clippy::cast_possible_wrap,
|
||||
clippy::cast_sign_loss,
|
||||
// things are often more readable this way
|
||||
clippy::cast_lossless,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::option_if_let_else,
|
||||
clippy::single_match_else,
|
||||
clippy::type_complexity,
|
||||
clippy::use_self,
|
||||
clippy::zero_prefixed_literal,
|
||||
// correctly used
|
||||
clippy::derive_partial_eq_without_eq,
|
||||
clippy::enum_glob_use,
|
||||
clippy::explicit_auto_deref,
|
||||
clippy::let_underscore_untyped,
|
||||
clippy::map_err_ignore,
|
||||
clippy::new_without_default,
|
||||
clippy::result_unit_err,
|
||||
clippy::wildcard_imports,
|
||||
// not practical
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::similar_names,
|
||||
clippy::too_many_lines,
|
||||
// preference
|
||||
clippy::doc_markdown,
|
||||
clippy::unseparated_literal_suffix,
|
||||
// false positive
|
||||
clippy::needless_doctest_main,
|
||||
// noisy
|
||||
clippy::missing_errors_doc,
|
||||
clippy::must_use_candidate,
|
||||
)]
|
||||
// Restrictions
|
||||
#![cfg_attr(feature = "cargo-clippy", deny(question_mark_used))]
|
||||
#![deny(clippy::question_mark_used)]
|
||||
// Rustc lints.
|
||||
#![deny(missing_docs, unused_imports)]
|
||||
|
||||
|
||||
+59
-5
@@ -1,10 +1,13 @@
|
||||
use crate::lib::*;
|
||||
|
||||
use crate::de::value::{BorrowedBytesDeserializer, BytesDeserializer};
|
||||
use crate::de::{Deserialize, Deserializer, Error, IntoDeserializer, Visitor};
|
||||
use crate::de::{
|
||||
Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error, IntoDeserializer, VariantAccess,
|
||||
Visitor,
|
||||
};
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
use crate::de::{DeserializeSeed, MapAccess, Unexpected};
|
||||
use crate::de::{MapAccess, Unexpected};
|
||||
|
||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||
pub use self::content::{
|
||||
@@ -205,12 +208,11 @@ mod content {
|
||||
|
||||
use crate::lib::*;
|
||||
|
||||
use crate::__private::size_hint;
|
||||
use crate::actually_private;
|
||||
use crate::de::value::{MapDeserializer, SeqDeserializer};
|
||||
use crate::de::{
|
||||
self, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Expected, IgnoredAny,
|
||||
MapAccess, SeqAccess, Unexpected, Visitor,
|
||||
self, size_hint, Deserialize, DeserializeSeed, Deserializer, EnumAccess, Expected,
|
||||
IgnoredAny, MapAccess, SeqAccess, Unexpected, Visitor,
|
||||
};
|
||||
|
||||
/// Used from generated code to buffer the contents of the Deserializer when
|
||||
@@ -2836,3 +2838,55 @@ fn flat_map_take_entry<'de>(
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AdjacentlyTaggedEnumVariantSeed<F> {
|
||||
pub enum_name: &'static str,
|
||||
pub variants: &'static [&'static str],
|
||||
pub fields_enum: PhantomData<F>,
|
||||
}
|
||||
|
||||
pub struct AdjacentlyTaggedEnumVariantVisitor<F> {
|
||||
enum_name: &'static str,
|
||||
fields_enum: PhantomData<F>,
|
||||
}
|
||||
|
||||
impl<'de, F> Visitor<'de> for AdjacentlyTaggedEnumVariantVisitor<F>
|
||||
where
|
||||
F: Deserialize<'de>,
|
||||
{
|
||||
type Value = F;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "variant of enum {}", self.enum_name)
|
||||
}
|
||||
|
||||
fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: EnumAccess<'de>,
|
||||
{
|
||||
let (variant, variant_access) = tri!(data.variant());
|
||||
tri!(variant_access.unit_variant());
|
||||
Ok(variant)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, F> DeserializeSeed<'de> for AdjacentlyTaggedEnumVariantSeed<F>
|
||||
where
|
||||
F: Deserialize<'de>,
|
||||
{
|
||||
type Value = F;
|
||||
|
||||
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_enum(
|
||||
self.enum_name,
|
||||
self.variants,
|
||||
AdjacentlyTaggedEnumVariantVisitor {
|
||||
enum_name: self.enum_name,
|
||||
fields_enum: PhantomData,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ pub mod de;
|
||||
#[cfg(not(no_serde_derive))]
|
||||
pub mod ser;
|
||||
|
||||
pub mod size_hint;
|
||||
|
||||
// FIXME: #[cfg(doctest)] once https://github.com/rust-lang/rust/issues/67295 is fixed.
|
||||
pub mod doc;
|
||||
|
||||
|
||||
@@ -1355,3 +1355,18 @@ where
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AdjacentlyTaggedEnumVariant {
|
||||
pub enum_name: &'static str,
|
||||
pub variant_index: u32,
|
||||
pub variant_name: &'static str,
|
||||
}
|
||||
|
||||
impl Serialize for AdjacentlyTaggedEnumVariant {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_unit_variant(self.enum_name, self.variant_index, self.variant_name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "serde_derive"
|
||||
version = "1.0.180" # 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>"]
|
||||
categories = ["no-std", "no-std::no-alloc"]
|
||||
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
|
||||
|
||||
+184
-231
@@ -324,10 +324,10 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option<St
|
||||
|
||||
let code = match &cont.data {
|
||||
Data::Struct(Style::Struct, fields) => {
|
||||
deserialize_struct_in_place(None, params, fields, &cont.attrs, None)?
|
||||
deserialize_struct_in_place(params, fields, &cont.attrs)?
|
||||
}
|
||||
Data::Struct(Style::Tuple, fields) | Data::Struct(Style::Newtype, fields) => {
|
||||
deserialize_tuple_in_place(None, params, fields, &cont.attrs, None)
|
||||
deserialize_tuple_in_place(params, fields, &cont.attrs)
|
||||
}
|
||||
Data::Enum(_) | Data::Struct(Style::Unit, _) => {
|
||||
return None;
|
||||
@@ -582,11 +582,9 @@ fn deserialize_tuple(
|
||||
|
||||
#[cfg(feature = "deserialize_in_place")]
|
||||
fn deserialize_tuple_in_place(
|
||||
variant_ident: Option<syn::Ident>,
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
deserializer: Option<TokenStream>,
|
||||
) -> Fragment {
|
||||
assert!(!cattrs.has_flatten());
|
||||
|
||||
@@ -600,17 +598,25 @@ fn deserialize_tuple_in_place(
|
||||
split_with_de_lifetime(params);
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let is_enum = variant_ident.is_some();
|
||||
let expecting = match variant_ident {
|
||||
Some(variant_ident) => format!("tuple variant {}::{}", params.type_name(), variant_ident),
|
||||
None => format!("tuple struct {}", params.type_name()),
|
||||
};
|
||||
let expecting = format!("tuple struct {}", params.type_name());
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
let nfields = fields.len();
|
||||
|
||||
let visit_newtype_struct = if !is_enum && nfields == 1 {
|
||||
Some(deserialize_newtype_struct_in_place(params, &fields[0]))
|
||||
let visit_newtype_struct = if nfields == 1 {
|
||||
// We do not generate deserialize_in_place if every field has a
|
||||
// deserialize_with.
|
||||
assert!(fields[0].attrs.deserialize_with().is_none());
|
||||
|
||||
Some(quote! {
|
||||
#[inline]
|
||||
fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::__private::Result<Self::Value, __E::Error>
|
||||
where
|
||||
__E: _serde::Deserializer<#delife>,
|
||||
{
|
||||
_serde::Deserialize::deserialize_in_place(__e, &mut self.place.0)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -624,15 +630,10 @@ fn deserialize_tuple_in_place(
|
||||
}
|
||||
};
|
||||
|
||||
let dispatch = if let Some(deserializer) = deserializer {
|
||||
quote!(_serde::Deserializer::deserialize_tuple(#deserializer, #field_count, #visitor_expr))
|
||||
} else if is_enum {
|
||||
quote!(_serde::de::VariantAccess::tuple_variant(__variant, #field_count, #visitor_expr))
|
||||
} else if nfields == 1 {
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
let dispatch = if nfields == 1 {
|
||||
quote!(_serde::Deserializer::deserialize_newtype_struct(__deserializer, #type_name, #visitor_expr))
|
||||
} else {
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
quote!(_serde::Deserializer::deserialize_tuple_struct(__deserializer, #type_name, #field_count, #visitor_expr))
|
||||
};
|
||||
|
||||
@@ -722,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;
|
||||
@@ -810,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -840,7 +823,7 @@ fn deserialize_seq_in_place(
|
||||
self.place.#member = __wrap.value;
|
||||
}
|
||||
_serde::__private::None => {
|
||||
#value_if_none
|
||||
#value_if_none;
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -918,25 +901,6 @@ fn deserialize_newtype_struct(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_in_place")]
|
||||
fn deserialize_newtype_struct_in_place(params: &Parameters, field: &Field) -> TokenStream {
|
||||
// We do not generate deserialize_in_place if every field has a
|
||||
// deserialize_with.
|
||||
assert!(field.attrs.deserialize_with().is_none());
|
||||
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
quote! {
|
||||
#[inline]
|
||||
fn visit_newtype_struct<__E>(self, __e: __E) -> _serde::__private::Result<Self::Value, __E::Error>
|
||||
where
|
||||
__E: _serde::Deserializer<#delife>,
|
||||
{
|
||||
_serde::Deserialize::deserialize_in_place(__e, &mut self.place.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum StructForm<'a> {
|
||||
Struct,
|
||||
/// Contains a variant name
|
||||
@@ -1001,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.
|
||||
@@ -1058,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)]
|
||||
@@ -1133,14 +1092,10 @@ fn deserialize_struct(
|
||||
|
||||
#[cfg(feature = "deserialize_in_place")]
|
||||
fn deserialize_struct_in_place(
|
||||
variant_ident: Option<syn::Ident>,
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
deserializer: Option<TokenStream>,
|
||||
) -> Option<Fragment> {
|
||||
let is_enum = variant_ident.is_some();
|
||||
|
||||
// for now we do not support in_place deserialization for structs that
|
||||
// are represented as map.
|
||||
if cattrs.has_flatten() {
|
||||
@@ -1152,58 +1107,35 @@ fn deserialize_struct_in_place(
|
||||
split_with_de_lifetime(params);
|
||||
let delife = params.borrowed.de_lifetime();
|
||||
|
||||
let expecting = match variant_ident {
|
||||
Some(variant_ident) => format!("struct variant {}::{}", params.type_name(), variant_ident),
|
||||
None => format!("struct {}", params.type_name()),
|
||||
};
|
||||
let expecting = format!("struct {}", params.type_name());
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
|
||||
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting));
|
||||
let field_names_idents: Vec<_> = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, field)| !field.attrs.skip_deserializing())
|
||||
.map(|(i, field)| {
|
||||
(
|
||||
field.attrs.name().deserialize_name(),
|
||||
field_i(i),
|
||||
field.attrs.aliases(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let (field_visitor, fields_stmt, visit_map) =
|
||||
deserialize_struct_as_struct_in_place_visitor(params, fields, cattrs);
|
||||
let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs);
|
||||
|
||||
let field_visitor = Stmts(field_visitor);
|
||||
let fields_stmt = Stmts(fields_stmt);
|
||||
let visit_map = Stmts(visit_map);
|
||||
|
||||
let visitor_expr = quote! {
|
||||
__Visitor {
|
||||
place: __place,
|
||||
lifetime: _serde::__private::PhantomData,
|
||||
}
|
||||
};
|
||||
let dispatch = if let Some(deserializer) = deserializer {
|
||||
quote! {
|
||||
_serde::Deserializer::deserialize_any(#deserializer, #visitor_expr)
|
||||
}
|
||||
} else if is_enum {
|
||||
quote! {
|
||||
_serde::de::VariantAccess::struct_variant(__variant, FIELDS, #visitor_expr)
|
||||
}
|
||||
} else {
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
quote! {
|
||||
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr)
|
||||
}
|
||||
};
|
||||
|
||||
let all_skipped = fields.iter().all(|field| field.attrs.skip_deserializing());
|
||||
let visitor_var = if all_skipped {
|
||||
let mut_seq = if field_names_idents.is_empty() {
|
||||
quote!(_)
|
||||
} else {
|
||||
quote!(mut __seq)
|
||||
};
|
||||
|
||||
let visit_seq = quote! {
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #visitor_var: __A) -> _serde::__private::Result<Self::Value, __A::Error>
|
||||
where
|
||||
__A: _serde::de::SeqAccess<#delife>,
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
};
|
||||
let visit_seq = Stmts(deserialize_seq_in_place(params, fields, cattrs, expecting));
|
||||
let visit_map = Stmts(deserialize_map_in_place(params, fields, cattrs));
|
||||
let field_names = field_names_idents
|
||||
.iter()
|
||||
.flat_map(|&(_, _, aliases)| aliases);
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
|
||||
let in_place_impl_generics = de_impl_generics.in_place();
|
||||
let in_place_ty_generics = de_ty_generics.in_place();
|
||||
@@ -1225,7 +1157,13 @@ fn deserialize_struct_in_place(
|
||||
_serde::__private::Formatter::write_str(__formatter, #expecting)
|
||||
}
|
||||
|
||||
#visit_seq
|
||||
#[inline]
|
||||
fn visit_seq<__A>(self, #mut_seq: __A) -> _serde::__private::Result<Self::Value, __A::Error>
|
||||
where
|
||||
__A: _serde::de::SeqAccess<#delife>,
|
||||
{
|
||||
#visit_seq
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_map<__A>(self, mut __map: __A) -> _serde::__private::Result<Self::Value, __A::Error>
|
||||
@@ -1236,9 +1174,13 @@ fn deserialize_struct_in_place(
|
||||
}
|
||||
}
|
||||
|
||||
#fields_stmt
|
||||
#[doc(hidden)]
|
||||
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
|
||||
|
||||
#dispatch
|
||||
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, __Visitor {
|
||||
place: __place,
|
||||
lifetime: _serde::__private::PhantomData,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1295,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);
|
||||
@@ -1309,7 +1256,8 @@ fn prepare_enum_variant_enum(
|
||||
&variant_names_idents,
|
||||
cattrs,
|
||||
true,
|
||||
other_idx,
|
||||
None,
|
||||
fallthrough,
|
||||
));
|
||||
|
||||
(variants_stmt, variant_visitor)
|
||||
@@ -1490,7 +1438,8 @@ fn deserialize_adjacently_tagged_enum(
|
||||
})
|
||||
.collect();
|
||||
|
||||
let expecting = format!("adjacently tagged enum {}", params.type_name());
|
||||
let rust_name = params.type_name();
|
||||
let expecting = format!("adjacently tagged enum {}", rust_name);
|
||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||
let type_name = cattrs.name().deserialize_name();
|
||||
let deny_unknown_fields = cattrs.deny_unknown_fields();
|
||||
@@ -1510,6 +1459,14 @@ fn deserialize_adjacently_tagged_enum(
|
||||
}
|
||||
};
|
||||
|
||||
let variant_seed = quote! {
|
||||
_serde::__private::de::AdjacentlyTaggedEnumVariantSeed::<__Field> {
|
||||
enum_name: #rust_name,
|
||||
variants: VARIANTS,
|
||||
fields_enum: _serde::__private::PhantomData
|
||||
}
|
||||
};
|
||||
|
||||
let mut missing_content = quote! {
|
||||
_serde::__private::Err(<__A::Error as _serde::de::Error>::missing_field(#content))
|
||||
};
|
||||
@@ -1557,6 +1514,10 @@ fn deserialize_adjacently_tagged_enum(
|
||||
_serde::de::MapAccess::next_key_seed(&mut __map, #tag_or_content)?
|
||||
};
|
||||
|
||||
let variant_from_map = quote! {
|
||||
_serde::de::MapAccess::next_value_seed(&mut __map, #variant_seed)?
|
||||
};
|
||||
|
||||
// When allowing unknown fields, we want to transparently step through keys
|
||||
// we don't care about until we find `tag`, `content`, or run out of keys.
|
||||
let next_relevant_key = if deny_unknown_fields {
|
||||
@@ -1602,11 +1563,11 @@ fn deserialize_adjacently_tagged_enum(
|
||||
|
||||
let finish_content_then_tag = if variant_arms.is_empty() {
|
||||
quote! {
|
||||
match _serde::de::MapAccess::next_value::<__Field>(&mut __map)? {}
|
||||
match #variant_from_map {}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
let __ret = match _serde::de::MapAccess::next_value(&mut __map)? {
|
||||
let __ret = match #variant_from_map {
|
||||
// Deserialize the buffered content now that we know the variant.
|
||||
#(#variant_arms)*
|
||||
}?;
|
||||
@@ -1662,7 +1623,7 @@ fn deserialize_adjacently_tagged_enum(
|
||||
// First key is the tag.
|
||||
_serde::__private::Some(_serde::__private::de::TagOrContentField::Tag) => {
|
||||
// Parse the tag.
|
||||
let __field = _serde::de::MapAccess::next_value(&mut __map)?;
|
||||
let __field = #variant_from_map;
|
||||
// Visit the second key.
|
||||
match #next_relevant_key {
|
||||
// Second key is a duplicate of the tag.
|
||||
@@ -2018,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,
|
||||
@@ -2087,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(
|
||||
@@ -2148,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
|
||||
@@ -2204,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"
|
||||
@@ -2237,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 {
|
||||
@@ -2286,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>
|
||||
@@ -2395,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,
|
||||
}
|
||||
}
|
||||
@@ -2411,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>
|
||||
@@ -2418,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
|
||||
@@ -2433,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
|
||||
@@ -2460,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
|
||||
@@ -2475,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
|
||||
@@ -2707,42 +2667,6 @@ fn deserialize_map(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_in_place")]
|
||||
fn deserialize_struct_as_struct_in_place_visitor(
|
||||
params: &Parameters,
|
||||
fields: &[Field],
|
||||
cattrs: &attr::Container,
|
||||
) -> (Fragment, Fragment, Fragment) {
|
||||
assert!(!cattrs.has_flatten());
|
||||
|
||||
let field_names_idents: Vec<_> = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, field)| !field.attrs.skip_deserializing())
|
||||
.map(|(i, field)| {
|
||||
(
|
||||
field.attrs.name().deserialize_name(),
|
||||
field_i(i),
|
||||
field.attrs.aliases(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let fields_stmt = {
|
||||
let field_names = field_names_idents.iter().map(|(name, _, _)| name);
|
||||
quote_block! {
|
||||
#[doc(hidden)]
|
||||
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
|
||||
}
|
||||
};
|
||||
|
||||
let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, None);
|
||||
|
||||
let visit_map = deserialize_map_in_place(params, fields, cattrs);
|
||||
|
||||
(field_visitor, fields_stmt, visit_map)
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize_in_place")]
|
||||
fn deserialize_map_in_place(
|
||||
params: &Parameters,
|
||||
@@ -3046,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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,20 +396,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 +418,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));
|
||||
}
|
||||
}
|
||||
@@ -977,7 +968,7 @@ impl Variant {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn aliases(&self) -> Vec<String> {
|
||||
pub fn aliases(&self) -> &BTreeSet<String> {
|
||||
self.name.deserialize_aliases()
|
||||
}
|
||||
|
||||
@@ -988,6 +979,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 +1310,7 @@ impl Field {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn aliases(&self) -> Vec<String> {
|
||||
pub fn aliases(&self) -> &BTreeSet<String> {
|
||||
self.name.deserialize_aliases()
|
||||
}
|
||||
|
||||
@@ -1327,6 +1321,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 {
|
||||
|
||||
@@ -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:
|
||||
//
|
||||
|
||||
@@ -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.180")]
|
||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.183")]
|
||||
// Ignored clippy lints
|
||||
#![allow(
|
||||
// clippy false positive: https://github.com/rust-lang/rust-clippy/issues/7054
|
||||
|
||||
+28
-13
@@ -478,7 +478,14 @@ fn serialize_variant(
|
||||
serialize_internally_tagged_variant(params, variant, cattrs, tag)
|
||||
}
|
||||
(attr::TagType::Adjacent { tag, content }, false) => {
|
||||
serialize_adjacently_tagged_variant(params, variant, cattrs, tag, content)
|
||||
serialize_adjacently_tagged_variant(
|
||||
params,
|
||||
variant,
|
||||
cattrs,
|
||||
variant_index,
|
||||
tag,
|
||||
content,
|
||||
)
|
||||
}
|
||||
(attr::TagType::None, _) | (_, true) => {
|
||||
serialize_untagged_variant(params, variant, cattrs)
|
||||
@@ -559,7 +566,7 @@ fn serialize_externally_tagged_variant(
|
||||
},
|
||||
params,
|
||||
&variant.fields,
|
||||
&type_name,
|
||||
type_name,
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -624,7 +631,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"),
|
||||
}
|
||||
@@ -634,12 +641,20 @@ fn serialize_adjacently_tagged_variant(
|
||||
params: &Parameters,
|
||||
variant: &Variant,
|
||||
cattrs: &attr::Container,
|
||||
variant_index: u32,
|
||||
tag: &str,
|
||||
content: &str,
|
||||
) -> Fragment {
|
||||
let this_type = ¶ms.this_type;
|
||||
let type_name = cattrs.name().serialize_name();
|
||||
let variant_name = variant.attrs.name().serialize_name();
|
||||
let serialize_variant = quote! {
|
||||
&_serde::__private::ser::AdjacentlyTaggedEnumVariant {
|
||||
enum_name: #type_name,
|
||||
variant_index: #variant_index,
|
||||
variant_name: #variant_name,
|
||||
}
|
||||
};
|
||||
|
||||
let inner = Stmts(if let Some(path) = variant.attrs.serialize_with() {
|
||||
let ser = wrap_serialize_variant_with(params, path, variant);
|
||||
@@ -653,7 +668,7 @@ fn serialize_adjacently_tagged_variant(
|
||||
let mut __struct = _serde::Serializer::serialize_struct(
|
||||
__serializer, #type_name, 1)?;
|
||||
_serde::ser::SerializeStruct::serialize_field(
|
||||
&mut __struct, #tag, #variant_name)?;
|
||||
&mut __struct, #tag, #serialize_variant)?;
|
||||
_serde::ser::SerializeStruct::end(__struct)
|
||||
};
|
||||
}
|
||||
@@ -670,7 +685,7 @@ fn serialize_adjacently_tagged_variant(
|
||||
let mut __struct = _serde::Serializer::serialize_struct(
|
||||
__serializer, #type_name, 2)?;
|
||||
_serde::ser::SerializeStruct::serialize_field(
|
||||
&mut __struct, #tag, #variant_name)?;
|
||||
&mut __struct, #tag, #serialize_variant)?;
|
||||
#func(
|
||||
&mut __struct, #content, #field_expr)?;
|
||||
_serde::ser::SerializeStruct::end(__struct)
|
||||
@@ -683,7 +698,7 @@ fn serialize_adjacently_tagged_variant(
|
||||
StructVariant::Untagged,
|
||||
params,
|
||||
&variant.fields,
|
||||
&variant_name,
|
||||
variant_name,
|
||||
),
|
||||
}
|
||||
});
|
||||
@@ -735,7 +750,7 @@ fn serialize_adjacently_tagged_variant(
|
||||
let mut __struct = _serde::Serializer::serialize_struct(
|
||||
__serializer, #type_name, 2)?;
|
||||
_serde::ser::SerializeStruct::serialize_field(
|
||||
&mut __struct, #tag, #variant_name)?;
|
||||
&mut __struct, #tag, #serialize_variant)?;
|
||||
_serde::ser::SerializeStruct::serialize_field(
|
||||
&mut __struct, #content, &__AdjacentlyTagged {
|
||||
data: (#(#fields_ident,)*),
|
||||
@@ -779,16 +794,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,
|
||||
}
|
||||
@@ -855,11 +870,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,3 +1,4 @@
|
||||
#![allow(internal_features)]
|
||||
#![feature(lang_items, start)]
|
||||
#![no_std]
|
||||
|
||||
|
||||
@@ -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`",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2108,7 +2108,10 @@ fn test_adjacently_tagged_enum_bytes() {
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::Str("A"),
|
||||
Token::UnitVariant {
|
||||
name: "Data",
|
||||
variant: "A",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Struct { name: "A", len: 1 },
|
||||
Token::Str("a"),
|
||||
@@ -2126,7 +2129,10 @@ fn test_adjacently_tagged_enum_bytes() {
|
||||
len: 2,
|
||||
},
|
||||
Token::Bytes(b"t"),
|
||||
Token::Str("A"),
|
||||
Token::UnitVariant {
|
||||
name: "Data",
|
||||
variant: "A",
|
||||
},
|
||||
Token::Bytes(b"c"),
|
||||
Token::Struct { name: "A", len: 1 },
|
||||
Token::Str("a"),
|
||||
@@ -2167,7 +2173,10 @@ fn test_adjacently_tagged_enum_containing_flatten() {
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::Str("A"),
|
||||
Token::UnitVariant {
|
||||
name: "Data",
|
||||
variant: "A",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Map { len: None },
|
||||
Token::Str("a"),
|
||||
@@ -2757,7 +2766,7 @@ fn test_expecting_message_adjacently_tagged_enum() {
|
||||
// Check that #[serde(expecting = "...")] doesn't affect variant identifier error message
|
||||
assert_de_tokens_error::<Enum>(
|
||||
&[Token::Map { len: None }, Token::Str("tag"), Token::Unit],
|
||||
r#"invalid type: unit value, expected variant identifier"#,
|
||||
r#"invalid type: unit value, expected variant of enum Enum"#,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2992,7 +3001,10 @@ mod flatten {
|
||||
Token::Str("outer"),
|
||||
Token::U32(42),
|
||||
Token::Str("tag"),
|
||||
Token::Str("Struct"),
|
||||
Token::UnitVariant {
|
||||
name: "Enum",
|
||||
variant: "Struct",
|
||||
},
|
||||
Token::Str("content"),
|
||||
Token::Struct {
|
||||
len: 2,
|
||||
@@ -3020,7 +3032,10 @@ mod flatten {
|
||||
Token::Str("outer"),
|
||||
Token::U32(42),
|
||||
Token::Str("tag"),
|
||||
Token::Str("Newtype"),
|
||||
Token::UnitVariant {
|
||||
name: "Enum",
|
||||
variant: "Newtype",
|
||||
},
|
||||
Token::Str("content"),
|
||||
Token::Struct {
|
||||
len: 1,
|
||||
|
||||
@@ -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")]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,7 +472,10 @@ fn test_adjacently_tagged_newtype_struct() {
|
||||
},
|
||||
Token::U32(5),
|
||||
Token::Str("t"),
|
||||
Token::Str("Newtype"),
|
||||
Token::UnitVariant {
|
||||
name: "E",
|
||||
variant: "Newtype",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
@@ -1066,7 +1069,10 @@ fn test_adjacently_tagged_enum() {
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::Str("Unit"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
@@ -1080,7 +1086,10 @@ fn test_adjacently_tagged_enum() {
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::Str("Unit"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
@@ -1094,7 +1103,10 @@ fn test_adjacently_tagged_enum() {
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::Str("Unit"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Unit,
|
||||
Token::StructEnd,
|
||||
@@ -1112,7 +1124,10 @@ fn test_adjacently_tagged_enum() {
|
||||
Token::Str("c"),
|
||||
Token::Unit,
|
||||
Token::Str("t"),
|
||||
Token::Str("Unit"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
@@ -1128,7 +1143,10 @@ fn test_adjacently_tagged_enum() {
|
||||
Token::Str("f"),
|
||||
Token::Unit,
|
||||
Token::Str("t"),
|
||||
Token::Str("Unit"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::Str("g"),
|
||||
Token::Unit,
|
||||
Token::Str("c"),
|
||||
@@ -1148,7 +1166,10 @@ fn test_adjacently_tagged_enum() {
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::Str("Newtype"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Newtype",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::U8(1),
|
||||
Token::StructEnd,
|
||||
@@ -1166,7 +1187,10 @@ fn test_adjacently_tagged_enum() {
|
||||
Token::Str("c"),
|
||||
Token::U8(1),
|
||||
Token::Str("t"),
|
||||
Token::Str("Newtype"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Newtype",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
@@ -1180,7 +1204,10 @@ fn test_adjacently_tagged_enum() {
|
||||
len: 1,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::Str("Newtype"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Newtype",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
@@ -1194,7 +1221,10 @@ fn test_adjacently_tagged_enum() {
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::Str("Tuple"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Tuple",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Tuple { len: 2 },
|
||||
Token::U8(1),
|
||||
@@ -1218,7 +1248,10 @@ fn test_adjacently_tagged_enum() {
|
||||
Token::U8(1),
|
||||
Token::TupleEnd,
|
||||
Token::Str("t"),
|
||||
Token::Str("Tuple"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Tuple",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
@@ -1232,7 +1265,10 @@ fn test_adjacently_tagged_enum() {
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::Str("Struct"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Struct",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Struct {
|
||||
name: "Struct",
|
||||
@@ -1262,7 +1298,10 @@ fn test_adjacently_tagged_enum() {
|
||||
Token::U8(1),
|
||||
Token::StructEnd,
|
||||
Token::Str("t"),
|
||||
Token::Str("Struct"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Struct",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
@@ -1278,7 +1317,10 @@ fn test_adjacently_tagged_enum() {
|
||||
Token::U64(1), // content field
|
||||
Token::U8(1),
|
||||
Token::U64(0), // tag field
|
||||
Token::Str("Newtype"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Newtype",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
@@ -1294,7 +1336,10 @@ fn test_adjacently_tagged_enum() {
|
||||
Token::Bytes(b"c"),
|
||||
Token::U8(1),
|
||||
Token::Bytes(b"t"),
|
||||
Token::Str("Newtype"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Newtype",
|
||||
},
|
||||
Token::StructEnd,
|
||||
],
|
||||
);
|
||||
@@ -1316,7 +1361,10 @@ fn test_adjacently_tagged_enum_deny_unknown_fields() {
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::Str("Unit"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Unit,
|
||||
Token::StructEnd,
|
||||
@@ -1330,7 +1378,10 @@ fn test_adjacently_tagged_enum_deny_unknown_fields() {
|
||||
len: 2,
|
||||
},
|
||||
Token::Str("t"),
|
||||
Token::Str("Unit"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::Str("c"),
|
||||
Token::Unit,
|
||||
Token::Str("h"),
|
||||
@@ -1369,7 +1420,10 @@ fn test_adjacently_tagged_enum_deny_unknown_fields() {
|
||||
len: 2,
|
||||
},
|
||||
Token::U64(0), // tag field
|
||||
Token::Str("Unit"),
|
||||
Token::UnitVariant {
|
||||
name: "AdjacentlyTagged",
|
||||
variant: "Unit",
|
||||
},
|
||||
Token::U64(3),
|
||||
],
|
||||
r#"invalid value: integer `3`, expected "t" or "c""#,
|
||||
@@ -1565,7 +1619,10 @@ fn test_internally_tagged_struct_with_flattened_field() {
|
||||
Token::Str("tag_struct"),
|
||||
Token::Str("Struct"),
|
||||
Token::Str("tag_enum"),
|
||||
Token::Str("A"),
|
||||
Token::UnitVariant {
|
||||
name: "Enum",
|
||||
variant: "A",
|
||||
},
|
||||
Token::Str("content"),
|
||||
Token::U64(0),
|
||||
Token::MapEnd,
|
||||
|
||||
@@ -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);
|
||||
| ^^
|
||||
Reference in New Issue
Block a user