diff --git a/serde/Cargo.toml b/serde/Cargo.toml index 0e44a8db..a8984a27 100644 --- a/serde/Cargo.toml +++ b/serde/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde" -version = "1.0.23" # remember to update html_root_url +version = "1.0.24" # remember to update html_root_url authors = ["Erick Tryzelaar ", "David Tolnay "] license = "MIT/Apache-2.0" description = "A generic serialization/deserialization framework" diff --git a/serde/src/lib.rs b/serde/src/lib.rs index 5aa38ce1..53d4596d 100644 --- a/serde/src/lib.rs +++ b/serde/src/lib.rs @@ -79,7 +79,7 @@ //////////////////////////////////////////////////////////////////////////////// // Serde types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/serde/1.0.23")] +#![doc(html_root_url = "https://docs.rs/serde/1.0.24")] // Support using Serde without the standard library! #![cfg_attr(not(feature = "std"), no_std)] diff --git a/serde_derive/Cargo.toml b/serde_derive/Cargo.toml index 1b868d8d..a93411c1 100644 --- a/serde_derive/Cargo.toml +++ b/serde_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_derive" -version = "1.0.23" # remember to update html_root_url +version = "1.0.24" # remember to update html_root_url authors = ["Erick Tryzelaar ", "David Tolnay "] license = "MIT/Apache-2.0" description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" @@ -24,7 +24,7 @@ proc-macro = true [dependencies] quote = "0.3.8" -serde_derive_internals = { version = "=0.17.0", default-features = false, path = "../serde_derive_internals" } +serde_derive_internals = { version = "=0.18.0", default-features = false, path = "../serde_derive_internals" } syn = { version = "0.11", features = ["visit"] } [dev-dependencies] diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index b0edc267..6425d4e1 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -583,7 +583,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) } @@ -2034,15 +2057,15 @@ fn deserialize_map( attr::Default::Default => { Some( quote!( - let __default: Self::Value = _serde::export::Default::default(); - ), + let __default: Self::Value = _serde::export::Default::default(); + ), ) } attr::Default::Path(ref path) => { Some( quote!( - let __default: Self::Value = #path(); - ), + let __default: Self::Value = #path(); + ), ) } attr::Default::None => { diff --git a/serde_derive/src/lib.rs b/serde_derive/src/lib.rs index aac34ff8..b3e49c63 100644 --- a/serde_derive/src/lib.rs +++ b/serde_derive/src/lib.rs @@ -22,7 +22,7 @@ //! //! [https://serde.rs/derive.html]: https://serde.rs/derive.html -#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.23")] +#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.24")] #![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] #![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))] diff --git a/serde_derive_internals/Cargo.toml b/serde_derive_internals/Cargo.toml index 6148cda6..e8f11cf5 100644 --- a/serde_derive_internals/Cargo.toml +++ b/serde_derive_internals/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_derive_internals" -version = "0.17.0" # remember to update html_root_url +version = "0.18.0" # remember to update html_root_url authors = ["Erick Tryzelaar ", "David Tolnay "] license = "MIT/Apache-2.0" description = "AST representation used by Serde derive macros. Unstable." diff --git a/serde_derive_internals/src/ast.rs b/serde_derive_internals/src/ast.rs index dce1acc1..83243bcb 100644 --- a/serde_derive_internals/src/ast.rs +++ b/serde_derive_internals/src/ast.rs @@ -49,9 +49,11 @@ 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.default())) + } 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.default()); Body::Struct(style, fields) } }; @@ -98,36 +100,54 @@ impl<'a> Body<'a> { } } -fn enum_from_ast<'a>(cx: &Ctxt, variants: &'a [syn::Variant]) -> Vec> { +fn enum_from_ast<'a>( + cx: &Ctxt, + variants: &'a [syn::Variant], + container_default: &attr::Default, +) -> Vec> { 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_default); + 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>) { +fn struct_from_ast<'a>( + cx: &Ctxt, + data: &'a syn::VariantData, + attrs: Option<&attr::Variant>, + container_default: &attr::Default, +) -> (Style, Vec>) { 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_default)) + } + syn::VariantData::Tuple(ref fields) if fields.len() == 1 => ( + Style::Newtype, + fields_from_ast(cx, fields, attrs, container_default), + ), + syn::VariantData::Tuple(ref fields) => { + (Style::Tuple, fields_from_ast(cx, fields, attrs, container_default)) } - 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> { +fn fields_from_ast<'a>( + cx: &Ctxt, + fields: &'a [syn::Field], + attrs: Option<&attr::Variant>, + container_default: &attr::Default, +) -> Vec> { fields .iter() .enumerate() @@ -135,7 +155,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_default), ty: &field.ty, } }, diff --git a/serde_derive_internals/src/attr.rs b/serde_derive_internals/src/attr.rs index 3cf7e74d..efe9dff8 100644 --- a/serde_derive_internals/src/attr.rs +++ b/serde_derive_internals/src/attr.rs @@ -723,7 +723,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_default: &Default, + ) -> 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"); @@ -890,9 +896,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); } diff --git a/serde_derive_internals/src/lib.rs b/serde_derive_internals/src/lib.rs index 0667936a..b657e6fa 100644 --- a/serde_derive_internals/src/lib.rs +++ b/serde_derive_internals/src/lib.rs @@ -6,7 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.17.0")] +#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.18.0")] extern crate syn; #[macro_use] diff --git a/serde_test/Cargo.toml b/serde_test/Cargo.toml index 63de886c..ce0455ad 100644 --- a/serde_test/Cargo.toml +++ b/serde_test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_test" -version = "1.0.23" # remember to update html_root_url +version = "1.0.24" # remember to update html_root_url authors = ["Erick Tryzelaar ", "David Tolnay "] license = "MIT/Apache-2.0" description = "Token De/Serializer for testing De/Serialize implementations" diff --git a/serde_test/src/configure.rs b/serde_test/src/configure.rs index a9d281e8..fed06224 100644 --- a/serde_test/src/configure.rs +++ b/serde_test/src/configure.rs @@ -11,17 +11,17 @@ pub struct Compact(T); /// Trait to determine whether a value is represented in human-readable or /// compact form. -/// +/// /// ``` /// extern crate serde; /// extern crate serde_test; -/// +/// /// use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// use serde_test::{Configure, Token, assert_tokens}; -/// +/// /// #[derive(Debug, PartialEq)] /// struct Example(u8, u8); -/// +/// /// impl Serialize for Example { /// fn serialize(&self, serializer: S) -> Result /// where S: Serializer, @@ -33,7 +33,7 @@ pub struct Compact(T); /// } /// } /// } -/// +/// /// impl<'de> Deserialize<'de> for Example { /// fn deserialize(deserializer: D) -> Result /// where D: Deserializer<'de>, @@ -52,7 +52,7 @@ pub struct Compact(T); /// } /// } /// } -/// +/// /// fn main() { /// assert_tokens( /// &Example(1, 0).compact(), diff --git a/serde_test/src/lib.rs b/serde_test/src/lib.rs index e50b1423..606bdf2e 100644 --- a/serde_test/src/lib.rs +++ b/serde_test/src/lib.rs @@ -155,7 +155,7 @@ //! # } //! ``` -#![doc(html_root_url = "https://docs.rs/serde_test/1.0.23")] +#![doc(html_root_url = "https://docs.rs/serde_test/1.0.24")] #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] // Whitelisted clippy lints diff --git a/test_suite/tests/test_de.rs b/test_suite/tests/test_de.rs index b95b9c49..4c801d62 100644 --- a/test_suite/tests/test_de.rs +++ b/test_suite/tests/test_de.rs @@ -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 },