Solved #1105.
When a field should be skipped during deserialization, it will not use its own Default implementation when the container structure has `#[serde(default)]` set.
This commit is contained in:
parent
0c34e06e51
commit
c887a0b472
@ -447,7 +447,30 @@ fn deserialize_seq(
|
||||
};
|
||||
}
|
||||
|
||||
let let_default = match *cattrs.default() {
|
||||
attr::Default::Default => {
|
||||
Some(
|
||||
quote!(
|
||||
let __default: Self::Value = _serde::export::Default::default();
|
||||
),
|
||||
)
|
||||
}
|
||||
attr::Default::Path(ref path) => {
|
||||
Some(
|
||||
quote!(
|
||||
let __default: Self::Value = #path();
|
||||
),
|
||||
)
|
||||
}
|
||||
attr::Default::None => {
|
||||
// We don't need the default value, to prevent an unused variable warning
|
||||
// we'll leave the line empty.
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
quote_block! {
|
||||
#let_default
|
||||
#(#let_values)*
|
||||
_serde::export::Ok(#result)
|
||||
}
|
||||
|
@ -49,9 +49,9 @@ impl<'a> Container<'a> {
|
||||
let attrs = attr::Container::from_ast(cx, item);
|
||||
|
||||
let mut body = match item.body {
|
||||
syn::Body::Enum(ref variants) => Body::Enum(enum_from_ast(cx, variants)),
|
||||
syn::Body::Enum(ref variants) => Body::Enum(enum_from_ast(cx, variants, &attrs)),
|
||||
syn::Body::Struct(ref variant_data) => {
|
||||
let (style, fields) = struct_from_ast(cx, variant_data, None);
|
||||
let (style, fields) = struct_from_ast(cx, variant_data, None, &attrs);
|
||||
Body::Struct(style, fields)
|
||||
}
|
||||
};
|
||||
@ -98,36 +98,53 @@ impl<'a> Body<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec<Variant<'a>> {
|
||||
fn enum_from_ast<'a>(
|
||||
cx: &Ctxt,
|
||||
variants: &'a [syn::Variant],
|
||||
container: &attr::Container,
|
||||
) -> Vec<Variant<'a>> {
|
||||
variants
|
||||
.iter()
|
||||
.map(
|
||||
|variant| {
|
||||
let attrs = attr::Variant::from_ast(cx, variant);
|
||||
let (style, fields) = struct_from_ast(cx, &variant.data, Some(&attrs));
|
||||
Variant {
|
||||
ident: variant.ident.clone(),
|
||||
attrs: attrs,
|
||||
style: style,
|
||||
fields: fields,
|
||||
}
|
||||
},
|
||||
)
|
||||
.map(|variant| {
|
||||
let attrs = attr::Variant::from_ast(cx, variant);
|
||||
let (style, fields) = struct_from_ast(cx, &variant.data, Some(&attrs), container);
|
||||
Variant {
|
||||
ident: variant.ident.clone(),
|
||||
attrs: attrs,
|
||||
style: style,
|
||||
fields: fields,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn struct_from_ast<'a>(cx: &Ctxt, data: &'a syn::VariantData, attrs: Option<&attr::Variant>) -> (Style, Vec<Field<'a>>) {
|
||||
fn struct_from_ast<'a>(
|
||||
cx: &Ctxt,
|
||||
data: &'a syn::VariantData,
|
||||
attrs: Option<&attr::Variant>,
|
||||
container: &attr::Container,
|
||||
) -> (Style, Vec<Field<'a>>) {
|
||||
match *data {
|
||||
syn::VariantData::Struct(ref fields) => (Style::Struct, fields_from_ast(cx, fields, attrs)),
|
||||
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => {
|
||||
(Style::Newtype, fields_from_ast(cx, fields, attrs))
|
||||
syn::VariantData::Struct(ref fields) => {
|
||||
(Style::Struct, fields_from_ast(cx, fields, attrs, container))
|
||||
}
|
||||
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => (
|
||||
Style::Newtype,
|
||||
fields_from_ast(cx, fields, attrs, container),
|
||||
),
|
||||
syn::VariantData::Tuple(ref fields) => {
|
||||
(Style::Tuple, fields_from_ast(cx, fields, attrs, container))
|
||||
}
|
||||
syn::VariantData::Tuple(ref fields) => (Style::Tuple, fields_from_ast(cx, fields, attrs)),
|
||||
syn::VariantData::Unit => (Style::Unit, Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field], attrs: Option<&attr::Variant>) -> Vec<Field<'a>> {
|
||||
fn fields_from_ast<'a>(
|
||||
cx: &Ctxt,
|
||||
fields: &'a [syn::Field],
|
||||
attrs: Option<&attr::Variant>,
|
||||
container: &attr::Container,
|
||||
) -> Vec<Field<'a>> {
|
||||
fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
@ -135,7 +152,7 @@ fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a [syn::Field], attrs: Option<&attr:
|
||||
|(i, field)| {
|
||||
Field {
|
||||
ident: field.ident.clone(),
|
||||
attrs: attr::Field::from_ast(cx, i, field, attrs),
|
||||
attrs: attr::Field::from_ast(cx, i, field, attrs, container),
|
||||
ty: &field.ty,
|
||||
}
|
||||
},
|
||||
|
@ -714,7 +714,13 @@ pub enum Default {
|
||||
|
||||
impl Field {
|
||||
/// Extract out the `#[serde(...)]` attributes from a struct field.
|
||||
pub fn from_ast(cx: &Ctxt, index: usize, field: &syn::Field, attrs: Option<&Variant>) -> Self {
|
||||
pub fn from_ast(
|
||||
cx: &Ctxt,
|
||||
index: usize,
|
||||
field: &syn::Field,
|
||||
attrs: Option<&Variant>,
|
||||
container: &Container,
|
||||
) -> Self {
|
||||
let mut ser_name = Attr::none(cx, "rename");
|
||||
let mut de_name = Attr::none(cx, "rename");
|
||||
let mut skip_serializing = BoolAttr::none(cx, "skip_serializing");
|
||||
@ -881,9 +887,10 @@ impl Field {
|
||||
}
|
||||
}
|
||||
|
||||
// Is skip_deserializing, initialize the field to Default::default()
|
||||
// unless a different default is specified by `#[serde(default = "...")]`
|
||||
if skip_deserializing.0.value.is_some() {
|
||||
// Is skip_deserializing, initialize the field to Default::default() unless a different
|
||||
// default is specified by `#[serde(default = "...")]` on ourselves or our container (e.g.
|
||||
// the struct we are in).
|
||||
if container.default == Default::None && skip_deserializing.0.value.is_some() {
|
||||
default.set_if_none(Default::Default);
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,20 @@ struct StructSkipAll {
|
||||
#[serde(skip_deserializing)] a: i32,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Deserialize)]
|
||||
#[serde(default)]
|
||||
struct StructSkipDefault {
|
||||
#[serde(skip_deserializing)] a: i32,
|
||||
}
|
||||
|
||||
impl Default for StructSkipDefault {
|
||||
fn default() -> Self {
|
||||
StructSkipDefault {
|
||||
a: 16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct StructSkipAllDenyUnknown {
|
||||
@ -600,6 +614,12 @@ declare_tests! {
|
||||
Token::StructEnd,
|
||||
],
|
||||
}
|
||||
test_struct_skip_default {
|
||||
StructSkipDefault { a: 16 } => &[
|
||||
Token::Struct { name: "StructSkipDefault", len: 0 },
|
||||
Token::StructEnd,
|
||||
],
|
||||
}
|
||||
test_struct_skip_all_deny_unknown {
|
||||
StructSkipAllDenyUnknown { a: 0 } => &[
|
||||
Token::Struct { name: "StructSkipAllDenyUnknown", len: 0 },
|
||||
|
Loading…
x
Reference in New Issue
Block a user