mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-18 14:21:03 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 026e91a68c | |||
| bfbedac919 | |||
| 4036ff88ed | |||
| 1b4da41f97 | |||
| f61d452814 | |||
| f9866097a0 | |||
| 77a6a9d4e1 | |||
| 547d843cca | |||
| 005cb84593 | |||
| fd5b5e9aa5 | |||
| 0647a7c1fe | |||
| 85c73ef8de | |||
| 5ba1796a7e | |||
| e52b7b380f | |||
| 84c7419652 | |||
| 536221b1f9 | |||
| fc55ac70d3 | |||
| 2afe5b4ef9 | |||
| b4ec2595c9 | |||
| c3ac7b675a | |||
| 24614e44bf |
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.205"
|
version = "1.0.208"
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
categories = ["encoding", "no-std", "no-std::no-alloc"]
|
categories = ["encoding", "no-std", "no-std::no-alloc"]
|
||||||
@@ -37,7 +37,7 @@ rustdoc-args = ["--generate-link-to-definition"]
|
|||||||
# is compatible with exactly one serde release because the generated code
|
# is compatible with exactly one serde release because the generated code
|
||||||
# involves nonpublic APIs which are not bound by semver.
|
# involves nonpublic APIs which are not bound by semver.
|
||||||
[target.'cfg(any())'.dependencies]
|
[target.'cfg(any())'.dependencies]
|
||||||
serde_derive = { version = "=1.0.205", path = "../serde_derive" }
|
serde_derive = { version = "=1.0.208", path = "../serde_derive" }
|
||||||
|
|
||||||
|
|
||||||
### FEATURES #################################################################
|
### FEATURES #################################################################
|
||||||
|
|||||||
+1
-1
@@ -95,7 +95,7 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Serde types in rustdoc of other crates get linked to here.
|
// Serde types in rustdoc of other crates get linked to here.
|
||||||
#![doc(html_root_url = "https://docs.rs/serde/1.0.205")]
|
#![doc(html_root_url = "https://docs.rs/serde/1.0.208")]
|
||||||
// Support using Serde without the standard library!
|
// Support using Serde without the standard library!
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
// Show which crate feature enables conditionally compiled APIs in documentation.
|
// Show which crate feature enables conditionally compiled APIs in documentation.
|
||||||
|
|||||||
+11
-1
@@ -2710,6 +2710,17 @@ where
|
|||||||
visitor.visit_unit()
|
visitor.visit_unit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize_unit_struct<V>(
|
||||||
|
self,
|
||||||
|
_name: &'static str,
|
||||||
|
visitor: V,
|
||||||
|
) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
visitor.visit_unit()
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
@@ -2734,7 +2745,6 @@ where
|
|||||||
deserialize_string()
|
deserialize_string()
|
||||||
deserialize_bytes()
|
deserialize_bytes()
|
||||||
deserialize_byte_buf()
|
deserialize_byte_buf()
|
||||||
deserialize_unit_struct(&'static str)
|
|
||||||
deserialize_seq()
|
deserialize_seq()
|
||||||
deserialize_tuple(usize)
|
deserialize_tuple(usize)
|
||||||
deserialize_tuple_struct(&'static str, usize)
|
deserialize_tuple_struct(&'static str, usize)
|
||||||
|
|||||||
@@ -51,8 +51,6 @@ enum Unsupported {
|
|||||||
String,
|
String,
|
||||||
ByteArray,
|
ByteArray,
|
||||||
Optional,
|
Optional,
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
|
||||||
UnitStruct,
|
|
||||||
Sequence,
|
Sequence,
|
||||||
Tuple,
|
Tuple,
|
||||||
TupleStruct,
|
TupleStruct,
|
||||||
@@ -69,8 +67,6 @@ impl Display for Unsupported {
|
|||||||
Unsupported::String => formatter.write_str("a string"),
|
Unsupported::String => formatter.write_str("a string"),
|
||||||
Unsupported::ByteArray => formatter.write_str("a byte array"),
|
Unsupported::ByteArray => formatter.write_str("a byte array"),
|
||||||
Unsupported::Optional => formatter.write_str("an optional"),
|
Unsupported::Optional => formatter.write_str("an optional"),
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
|
||||||
Unsupported::UnitStruct => formatter.write_str("unit struct"),
|
|
||||||
Unsupported::Sequence => formatter.write_str("a sequence"),
|
Unsupported::Sequence => formatter.write_str("a sequence"),
|
||||||
Unsupported::Tuple => formatter.write_str("a tuple"),
|
Unsupported::Tuple => formatter.write_str("a tuple"),
|
||||||
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
|
Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
|
||||||
@@ -1092,7 +1088,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||||
Err(Self::bad_type(Unsupported::UnitStruct))
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_unit_variant(
|
fn serialize_unit_variant(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.205"
|
version = "1.0.208"
|
||||||
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
|
||||||
categories = ["no-std", "no-std::no-alloc"]
|
categories = ["no-std", "no-std::no-alloc"]
|
||||||
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
|
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
|
||||||
|
|||||||
+49
-28
@@ -461,7 +461,10 @@ fn deserialize_tuple(
|
|||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
form: TupleForm,
|
form: TupleForm,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
assert!(!cattrs.has_flatten());
|
assert!(
|
||||||
|
!has_flatten(fields),
|
||||||
|
"tuples and tuple variants cannot have flatten fields"
|
||||||
|
);
|
||||||
|
|
||||||
let field_count = fields
|
let field_count = fields
|
||||||
.iter()
|
.iter()
|
||||||
@@ -579,7 +582,10 @@ fn deserialize_tuple_in_place(
|
|||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
assert!(!cattrs.has_flatten());
|
assert!(
|
||||||
|
!has_flatten(fields),
|
||||||
|
"tuples and tuple variants cannot have flatten fields"
|
||||||
|
);
|
||||||
|
|
||||||
let field_count = fields
|
let field_count = fields
|
||||||
.iter()
|
.iter()
|
||||||
@@ -958,13 +964,15 @@ fn deserialize_struct(
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs);
|
|
||||||
|
let has_flatten = has_flatten(fields);
|
||||||
|
let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs, has_flatten);
|
||||||
|
|
||||||
// untagged struct variants do not get a visit_seq method. The same applies to
|
// untagged struct variants do not get a visit_seq method. The same applies to
|
||||||
// structs that only have a map representation.
|
// structs that only have a map representation.
|
||||||
let visit_seq = match form {
|
let visit_seq = match form {
|
||||||
StructForm::Untagged(..) => None,
|
StructForm::Untagged(..) => None,
|
||||||
_ if cattrs.has_flatten() => None,
|
_ if has_flatten => None,
|
||||||
_ => {
|
_ => {
|
||||||
let mut_seq = if field_names_idents.is_empty() {
|
let mut_seq = if field_names_idents.is_empty() {
|
||||||
quote!(_)
|
quote!(_)
|
||||||
@@ -987,10 +995,16 @@ fn deserialize_struct(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let visit_map = Stmts(deserialize_map(&type_path, params, fields, cattrs));
|
let visit_map = Stmts(deserialize_map(
|
||||||
|
&type_path,
|
||||||
|
params,
|
||||||
|
fields,
|
||||||
|
cattrs,
|
||||||
|
has_flatten,
|
||||||
|
));
|
||||||
|
|
||||||
let visitor_seed = match form {
|
let visitor_seed = match form {
|
||||||
StructForm::ExternallyTagged(..) if cattrs.has_flatten() => Some(quote! {
|
StructForm::ExternallyTagged(..) if has_flatten => Some(quote! {
|
||||||
impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause {
|
impl #de_impl_generics _serde::de::DeserializeSeed<#delife> for __Visitor #de_ty_generics #where_clause {
|
||||||
type Value = #this_type #ty_generics;
|
type Value = #this_type #ty_generics;
|
||||||
|
|
||||||
@@ -1005,7 +1019,7 @@ fn deserialize_struct(
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let fields_stmt = if cattrs.has_flatten() {
|
let fields_stmt = if has_flatten {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let field_names = field_names_idents
|
let field_names = field_names_idents
|
||||||
@@ -1025,7 +1039,7 @@ fn deserialize_struct(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let dispatch = match form {
|
let dispatch = match form {
|
||||||
StructForm::Struct if cattrs.has_flatten() => quote! {
|
StructForm::Struct if has_flatten => quote! {
|
||||||
_serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
|
_serde::Deserializer::deserialize_map(__deserializer, #visitor_expr)
|
||||||
},
|
},
|
||||||
StructForm::Struct => {
|
StructForm::Struct => {
|
||||||
@@ -1034,7 +1048,7 @@ fn deserialize_struct(
|
|||||||
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr)
|
_serde::Deserializer::deserialize_struct(__deserializer, #type_name, FIELDS, #visitor_expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StructForm::ExternallyTagged(_) if cattrs.has_flatten() => quote! {
|
StructForm::ExternallyTagged(_) if has_flatten => quote! {
|
||||||
_serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr)
|
_serde::de::VariantAccess::newtype_variant_seed(__variant, #visitor_expr)
|
||||||
},
|
},
|
||||||
StructForm::ExternallyTagged(_) => quote! {
|
StructForm::ExternallyTagged(_) => quote! {
|
||||||
@@ -1091,7 +1105,7 @@ fn deserialize_struct_in_place(
|
|||||||
) -> Option<Fragment> {
|
) -> Option<Fragment> {
|
||||||
// for now we do not support in_place deserialization for structs that
|
// for now we do not support in_place deserialization for structs that
|
||||||
// are represented as map.
|
// are represented as map.
|
||||||
if cattrs.has_flatten() {
|
if has_flatten(fields) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1116,7 +1130,7 @@ fn deserialize_struct_in_place(
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs);
|
let field_visitor = deserialize_field_identifier(&field_names_idents, cattrs, false);
|
||||||
|
|
||||||
let mut_seq = if field_names_idents.is_empty() {
|
let mut_seq = if field_names_idents.is_empty() {
|
||||||
quote!(_)
|
quote!(_)
|
||||||
@@ -1210,10 +1224,7 @@ fn deserialize_homogeneous_enum(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_enum_variant_enum(
|
fn prepare_enum_variant_enum(variants: &[Variant]) -> (TokenStream, Stmts) {
|
||||||
variants: &[Variant],
|
|
||||||
cattrs: &attr::Container,
|
|
||||||
) -> (TokenStream, Stmts) {
|
|
||||||
let mut deserialized_variants = variants
|
let mut deserialized_variants = variants
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@@ -1247,7 +1258,7 @@ fn prepare_enum_variant_enum(
|
|||||||
|
|
||||||
let variant_visitor = Stmts(deserialize_generated_identifier(
|
let variant_visitor = Stmts(deserialize_generated_identifier(
|
||||||
&variant_names_idents,
|
&variant_names_idents,
|
||||||
cattrs,
|
false, // variant identifiers do not depend on the presence of flatten fields
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
fallthrough,
|
fallthrough,
|
||||||
@@ -1270,7 +1281,7 @@ fn deserialize_externally_tagged_enum(
|
|||||||
let expecting = format!("enum {}", params.type_name());
|
let expecting = format!("enum {}", params.type_name());
|
||||||
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
let expecting = cattrs.expecting().unwrap_or(&expecting);
|
||||||
|
|
||||||
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs);
|
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants);
|
||||||
|
|
||||||
// Match arms to extract a variant from a string
|
// Match arms to extract a variant from a string
|
||||||
let variant_arms = variants
|
let variant_arms = variants
|
||||||
@@ -1355,7 +1366,7 @@ fn deserialize_internally_tagged_enum(
|
|||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
tag: &str,
|
tag: &str,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs);
|
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants);
|
||||||
|
|
||||||
// Match arms to extract a variant from a string
|
// Match arms to extract a variant from a string
|
||||||
let variant_arms = variants
|
let variant_arms = variants
|
||||||
@@ -1409,7 +1420,7 @@ fn deserialize_adjacently_tagged_enum(
|
|||||||
split_with_de_lifetime(params);
|
split_with_de_lifetime(params);
|
||||||
let delife = params.borrowed.de_lifetime();
|
let delife = params.borrowed.de_lifetime();
|
||||||
|
|
||||||
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs);
|
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants);
|
||||||
|
|
||||||
let variant_arms: &Vec<_> = &variants
|
let variant_arms: &Vec<_> = &variants
|
||||||
.iter()
|
.iter()
|
||||||
@@ -1985,7 +1996,7 @@ fn deserialize_untagged_newtype_variant(
|
|||||||
|
|
||||||
fn deserialize_generated_identifier(
|
fn deserialize_generated_identifier(
|
||||||
fields: &[(&str, Ident, &BTreeSet<String>)],
|
fields: &[(&str, Ident, &BTreeSet<String>)],
|
||||||
cattrs: &attr::Container,
|
has_flatten: bool,
|
||||||
is_variant: bool,
|
is_variant: bool,
|
||||||
ignore_variant: Option<TokenStream>,
|
ignore_variant: Option<TokenStream>,
|
||||||
fallthrough: Option<TokenStream>,
|
fallthrough: Option<TokenStream>,
|
||||||
@@ -1999,11 +2010,11 @@ fn deserialize_generated_identifier(
|
|||||||
is_variant,
|
is_variant,
|
||||||
fallthrough,
|
fallthrough,
|
||||||
None,
|
None,
|
||||||
!is_variant && cattrs.has_flatten(),
|
!is_variant && has_flatten,
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
|
|
||||||
let lifetime = if !is_variant && cattrs.has_flatten() {
|
let lifetime = if !is_variant && has_flatten {
|
||||||
Some(quote!(<'de>))
|
Some(quote!(<'de>))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -2043,8 +2054,9 @@ fn deserialize_generated_identifier(
|
|||||||
fn deserialize_field_identifier(
|
fn deserialize_field_identifier(
|
||||||
fields: &[(&str, Ident, &BTreeSet<String>)],
|
fields: &[(&str, Ident, &BTreeSet<String>)],
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
|
has_flatten: bool,
|
||||||
) -> Stmts {
|
) -> Stmts {
|
||||||
let (ignore_variant, fallthrough) = if cattrs.has_flatten() {
|
let (ignore_variant, fallthrough) = if has_flatten {
|
||||||
let ignore_variant = quote!(__other(_serde::__private::de::Content<'de>),);
|
let ignore_variant = quote!(__other(_serde::__private::de::Content<'de>),);
|
||||||
let fallthrough = quote!(_serde::__private::Ok(__Field::__other(__value)));
|
let fallthrough = quote!(_serde::__private::Ok(__Field::__other(__value)));
|
||||||
(Some(ignore_variant), Some(fallthrough))
|
(Some(ignore_variant), Some(fallthrough))
|
||||||
@@ -2058,7 +2070,7 @@ fn deserialize_field_identifier(
|
|||||||
|
|
||||||
Stmts(deserialize_generated_identifier(
|
Stmts(deserialize_generated_identifier(
|
||||||
fields,
|
fields,
|
||||||
cattrs,
|
has_flatten,
|
||||||
false,
|
false,
|
||||||
ignore_variant,
|
ignore_variant,
|
||||||
fallthrough,
|
fallthrough,
|
||||||
@@ -2460,6 +2472,7 @@ fn deserialize_map(
|
|||||||
params: &Parameters,
|
params: &Parameters,
|
||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
|
has_flatten: bool,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
// Create the field names for the fields.
|
// Create the field names for the fields.
|
||||||
let fields_names: Vec<_> = fields
|
let fields_names: Vec<_> = fields
|
||||||
@@ -2480,9 +2493,6 @@ fn deserialize_map(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Collect contents for flatten fields into a buffer
|
// Collect contents for flatten fields into a buffer
|
||||||
let has_flatten = fields
|
|
||||||
.iter()
|
|
||||||
.any(|field| field.attrs.flatten() && !field.attrs.skip_deserializing());
|
|
||||||
let let_collect = if has_flatten {
|
let let_collect = if has_flatten {
|
||||||
Some(quote! {
|
Some(quote! {
|
||||||
let mut __collect = _serde::__private::Vec::<_serde::__private::Option<(
|
let mut __collect = _serde::__private::Vec::<_serde::__private::Option<(
|
||||||
@@ -2681,7 +2691,10 @@ fn deserialize_map_in_place(
|
|||||||
fields: &[Field],
|
fields: &[Field],
|
||||||
cattrs: &attr::Container,
|
cattrs: &attr::Container,
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
assert!(!cattrs.has_flatten());
|
assert!(
|
||||||
|
!has_flatten(fields),
|
||||||
|
"inplace deserialization of maps does not support flatten fields"
|
||||||
|
);
|
||||||
|
|
||||||
// Create the field names for the fields.
|
// Create the field names for the fields.
|
||||||
let fields_names: Vec<_> = fields
|
let fields_names: Vec<_> = fields
|
||||||
@@ -3014,6 +3027,14 @@ fn effective_style(variant: &Variant) -> Style {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// True if there is any field with a `#[serde(flatten)]` attribute, other than
|
||||||
|
/// fields which are skipped.
|
||||||
|
fn has_flatten(fields: &[Field]) -> bool {
|
||||||
|
fields
|
||||||
|
.iter()
|
||||||
|
.any(|field| field.attrs.flatten() && !field.attrs.skip_deserializing())
|
||||||
|
}
|
||||||
|
|
||||||
struct DeImplGenerics<'a>(&'a Parameters);
|
struct DeImplGenerics<'a>(&'a Parameters);
|
||||||
#[cfg(feature = "deserialize_in_place")]
|
#[cfg(feature = "deserialize_in_place")]
|
||||||
struct InPlaceImplGenerics<'a>(&'a Parameters);
|
struct InPlaceImplGenerics<'a>(&'a Parameters);
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ impl<'a> Container<'a> {
|
|||||||
item: &'a syn::DeriveInput,
|
item: &'a syn::DeriveInput,
|
||||||
derive: Derive,
|
derive: Derive,
|
||||||
) -> Option<Container<'a>> {
|
) -> Option<Container<'a>> {
|
||||||
let mut attrs = attr::Container::from_ast(cx, item);
|
let attrs = attr::Container::from_ast(cx, item);
|
||||||
|
|
||||||
let mut data = match &item.data {
|
let mut data = match &item.data {
|
||||||
syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())),
|
syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())),
|
||||||
@@ -77,15 +77,11 @@ impl<'a> Container<'a> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut has_flatten = false;
|
|
||||||
match &mut data {
|
match &mut data {
|
||||||
Data::Enum(variants) => {
|
Data::Enum(variants) => {
|
||||||
for variant in variants {
|
for variant in variants {
|
||||||
variant.attrs.rename_by_rules(attrs.rename_all_rules());
|
variant.attrs.rename_by_rules(attrs.rename_all_rules());
|
||||||
for field in &mut variant.fields {
|
for field in &mut variant.fields {
|
||||||
if field.attrs.flatten() {
|
|
||||||
has_flatten = true;
|
|
||||||
}
|
|
||||||
field.attrs.rename_by_rules(
|
field.attrs.rename_by_rules(
|
||||||
variant
|
variant
|
||||||
.attrs
|
.attrs
|
||||||
@@ -97,18 +93,11 @@ impl<'a> Container<'a> {
|
|||||||
}
|
}
|
||||||
Data::Struct(_, fields) => {
|
Data::Struct(_, fields) => {
|
||||||
for field in fields {
|
for field in fields {
|
||||||
if field.attrs.flatten() {
|
|
||||||
has_flatten = true;
|
|
||||||
}
|
|
||||||
field.attrs.rename_by_rules(attrs.rename_all_rules());
|
field.attrs.rename_by_rules(attrs.rename_all_rules());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if has_flatten {
|
|
||||||
attrs.mark_has_flatten();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut item = Container {
|
let mut item = Container {
|
||||||
ident: item.ident.clone(),
|
ident: item.ident.clone(),
|
||||||
attrs,
|
attrs,
|
||||||
|
|||||||
@@ -216,7 +216,6 @@ pub struct Container {
|
|||||||
type_into: Option<syn::Type>,
|
type_into: Option<syn::Type>,
|
||||||
remote: Option<syn::Path>,
|
remote: Option<syn::Path>,
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
has_flatten: bool,
|
|
||||||
serde_path: Option<syn::Path>,
|
serde_path: Option<syn::Path>,
|
||||||
is_packed: bool,
|
is_packed: bool,
|
||||||
/// Error message generated when type can't be deserialized
|
/// Error message generated when type can't be deserialized
|
||||||
@@ -587,7 +586,6 @@ impl Container {
|
|||||||
type_into: type_into.get(),
|
type_into: type_into.get(),
|
||||||
remote: remote.get(),
|
remote: remote.get(),
|
||||||
identifier: decide_identifier(cx, item, field_identifier, variant_identifier),
|
identifier: decide_identifier(cx, item, field_identifier, variant_identifier),
|
||||||
has_flatten: false,
|
|
||||||
serde_path: serde_path.get(),
|
serde_path: serde_path.get(),
|
||||||
is_packed,
|
is_packed,
|
||||||
expecting: expecting.get(),
|
expecting: expecting.get(),
|
||||||
@@ -655,14 +653,6 @@ impl Container {
|
|||||||
self.identifier
|
self.identifier
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_flatten(&self) -> bool {
|
|
||||||
self.has_flatten
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mark_has_flatten(&mut self) {
|
|
||||||
self.has_flatten = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn custom_serde_path(&self) -> Option<&syn::Path> {
|
pub fn custom_serde_path(&self) -> Option<&syn::Path> {
|
||||||
self.serde_path.as_ref()
|
self.serde_path.as_ref()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
//!
|
//!
|
||||||
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.205")]
|
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.208")]
|
||||||
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
|
#![cfg_attr(not(check_cfg), allow(unexpected_cfgs))]
|
||||||
// Ignored clippy lints
|
// Ignored clippy lints
|
||||||
#![allow(
|
#![allow(
|
||||||
|
|||||||
+12
-21
@@ -289,9 +289,18 @@ fn serialize_tuple_struct(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
|
fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Container) -> Fragment {
|
||||||
assert!(fields.len() as u64 <= u64::from(u32::MAX));
|
assert!(
|
||||||
|
fields.len() as u64 <= u64::from(u32::MAX),
|
||||||
|
"too many fields in {}: {}, maximum supported count is {}",
|
||||||
|
cattrs.name().serialize_name(),
|
||||||
|
fields.len(),
|
||||||
|
u32::MAX,
|
||||||
|
);
|
||||||
|
|
||||||
if cattrs.has_flatten() {
|
let has_non_skipped_flatten = fields
|
||||||
|
.iter()
|
||||||
|
.any(|field| field.attrs.flatten() && !field.attrs.skip_serializing());
|
||||||
|
if has_non_skipped_flatten {
|
||||||
serialize_struct_as_map(params, fields, cattrs)
|
serialize_struct_as_map(params, fields, cattrs)
|
||||||
} else {
|
} else {
|
||||||
serialize_struct_as_struct(params, fields, cattrs)
|
serialize_struct_as_struct(params, fields, cattrs)
|
||||||
@@ -370,26 +379,8 @@ fn serialize_struct_as_map(
|
|||||||
|
|
||||||
let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists);
|
let let_mut = mut_if(serialized_fields.peek().is_some() || tag_field_exists);
|
||||||
|
|
||||||
let len = if cattrs.has_flatten() {
|
|
||||||
quote!(_serde::__private::None)
|
|
||||||
} else {
|
|
||||||
let len = serialized_fields
|
|
||||||
.map(|field| match field.attrs.skip_serializing_if() {
|
|
||||||
None => quote!(1),
|
|
||||||
Some(path) => {
|
|
||||||
let field_expr = get_member(params, field, &field.member);
|
|
||||||
quote!(if #path(#field_expr) { 0 } else { 1 })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.fold(
|
|
||||||
quote!(#tag_field_exists as usize),
|
|
||||||
|sum, expr| quote!(#sum + #expr),
|
|
||||||
);
|
|
||||||
quote!(_serde::__private::Some(#len))
|
|
||||||
};
|
|
||||||
|
|
||||||
quote_block! {
|
quote_block! {
|
||||||
let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, #len)?;
|
let #let_mut __serde_state = _serde::Serializer::serialize_map(__serializer, _serde::__private::None)?;
|
||||||
#tag_field
|
#tag_field
|
||||||
#(#serialize_fields)*
|
#(#serialize_fields)*
|
||||||
_serde::ser::SerializeMap::end(__serde_state)
|
_serde::ser::SerializeMap::end(__serde_state)
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#![allow(dead_code)] // we do not read enum fields
|
||||||
|
|
||||||
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct Nested;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub enum ExternallyTagged1 {
|
||||||
|
Tuple(f64, String),
|
||||||
|
Flatten {
|
||||||
|
#[serde(flatten)]
|
||||||
|
nested: Nested,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub enum ExternallyTagged2 {
|
||||||
|
Flatten {
|
||||||
|
#[serde(flatten)]
|
||||||
|
nested: Nested,
|
||||||
|
},
|
||||||
|
Tuple(f64, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internally tagged enums cannot contain tuple variants so not tested here
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(tag = "tag", content = "content")]
|
||||||
|
pub enum AdjacentlyTagged1 {
|
||||||
|
Tuple(f64, String),
|
||||||
|
Flatten {
|
||||||
|
#[serde(flatten)]
|
||||||
|
nested: Nested,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(tag = "tag", content = "content")]
|
||||||
|
pub enum AdjacentlyTagged2 {
|
||||||
|
Flatten {
|
||||||
|
#[serde(flatten)]
|
||||||
|
nested: Nested,
|
||||||
|
},
|
||||||
|
Tuple(f64, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum Untagged1 {
|
||||||
|
Tuple(f64, String),
|
||||||
|
Flatten {
|
||||||
|
#[serde(flatten)]
|
||||||
|
nested: Nested,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum Untagged2 {
|
||||||
|
Flatten {
|
||||||
|
#[serde(flatten)]
|
||||||
|
nested: Nested,
|
||||||
|
},
|
||||||
|
Tuple(f64, String),
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
use serde_test::{assert_tokens, Token};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
|
enum Enum {
|
||||||
|
Simple {
|
||||||
|
a: i32,
|
||||||
|
},
|
||||||
|
Flatten {
|
||||||
|
#[serde(flatten)]
|
||||||
|
flatten: (),
|
||||||
|
a: i32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_variant() {
|
||||||
|
assert_tokens(
|
||||||
|
&Enum::Simple { a: 42 },
|
||||||
|
&[
|
||||||
|
Token::StructVariant { name: "Enum", variant: "Simple", len: 1 },
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(42),
|
||||||
|
Token::StructVariantEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn flatten_variant() {
|
||||||
|
assert_tokens(
|
||||||
|
&Enum::Flatten { flatten: (), a: 42 },
|
||||||
|
&[
|
||||||
|
Token::NewtypeVariant { name: "Enum", variant: "Flatten" },
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(42),
|
||||||
|
Token::MapEnd,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#![allow(dead_code)] // we do not read enum fields
|
||||||
|
|
||||||
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub enum A {
|
||||||
|
B {
|
||||||
|
c: String,
|
||||||
|
},
|
||||||
|
D {
|
||||||
|
#[serde(flatten)]
|
||||||
|
e: E,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct E {}
|
||||||
@@ -1815,6 +1815,32 @@ fn test_flatten_unit() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_flatten_unit_struct() {
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct Response<T> {
|
||||||
|
#[serde(flatten)]
|
||||||
|
data: T,
|
||||||
|
status: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
struct Unit;
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Response {
|
||||||
|
data: Unit,
|
||||||
|
status: 0,
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("status"),
|
||||||
|
Token::U64(0),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_flatten_unsupported_type() {
|
fn test_flatten_unsupported_type() {
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
@@ -2380,6 +2406,56 @@ fn test_partially_untagged_enum_desugared() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Regression test for https://github.com/serde-rs/serde/issues/1904
|
||||||
|
#[test]
|
||||||
|
fn test_enum_tuple_and_struct_with_flatten() {
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
enum Outer {
|
||||||
|
Tuple(f64, i32),
|
||||||
|
Flatten {
|
||||||
|
#[serde(flatten)]
|
||||||
|
nested: Nested,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
struct Nested {
|
||||||
|
a: i32,
|
||||||
|
b: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_tokens(
|
||||||
|
&Outer::Tuple(1.2, 3),
|
||||||
|
&[
|
||||||
|
Token::TupleVariant {
|
||||||
|
name: "Outer",
|
||||||
|
variant: "Tuple",
|
||||||
|
len: 2,
|
||||||
|
},
|
||||||
|
Token::F64(1.2),
|
||||||
|
Token::I32(3),
|
||||||
|
Token::TupleVariantEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
assert_tokens(
|
||||||
|
&Outer::Flatten {
|
||||||
|
nested: Nested { a: 1, b: 2 },
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
Token::NewtypeVariant {
|
||||||
|
name: "Outer",
|
||||||
|
variant: "Flatten",
|
||||||
|
},
|
||||||
|
Token::Map { len: None },
|
||||||
|
Token::Str("a"),
|
||||||
|
Token::I32(1),
|
||||||
|
Token::Str("b"),
|
||||||
|
Token::I32(2),
|
||||||
|
Token::MapEnd,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_partially_untagged_internally_tagged_enum() {
|
fn test_partially_untagged_internally_tagged_enum() {
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
|||||||
@@ -547,6 +547,12 @@ fn test_gen() {
|
|||||||
}
|
}
|
||||||
assert::<FlattenWith>();
|
assert::<FlattenWith>();
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct Flatten<T> {
|
||||||
|
#[serde(flatten)]
|
||||||
|
t: T,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct FlattenDenyUnknown<T> {
|
pub struct FlattenDenyUnknown<T> {
|
||||||
@@ -554,6 +560,19 @@ fn test_gen() {
|
|||||||
t: T,
|
t: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct SkipDeserializing<T> {
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
flat: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct SkipDeserializingDenyUnknown<T> {
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
flat: T,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct StaticStrStruct<'a> {
|
pub struct StaticStrStruct<'a> {
|
||||||
a: &'a str,
|
a: &'a str,
|
||||||
|
|||||||
Reference in New Issue
Block a user