diff --git a/serde_codegen_internals/src/attr.rs b/serde_codegen_internals/src/attr.rs index ae3af449..de7a997d 100644 --- a/serde_codegen_internals/src/attr.rs +++ b/serde_codegen_internals/src/attr.rs @@ -90,7 +90,7 @@ impl Name { pub struct Item { name: Name, deny_unknown_fields: bool, - default: bool, + default: Default, ser_bound: Option>, de_bound: Option>, tag: EnumTag, @@ -134,7 +134,7 @@ impl Item { let mut ser_name = Attr::none(cx, "rename"); let mut de_name = Attr::none(cx, "rename"); let mut deny_unknown_fields = BoolAttr::none(cx, "deny_unknown_fields"); - let mut default = BoolAttr::none(cx, "default"); + let mut default = Attr::none(cx, "default"); let mut ser_bound = Attr::none(cx, "bound"); let mut de_bound = Attr::none(cx, "bound"); let mut untagged = BoolAttr::none(cx, "untagged"); @@ -168,11 +168,27 @@ impl Item { // Parse `#[serde(default)]` MetaItem(Word(ref name)) if name == "default" => { match item.body { - syn::Body::Struct(_) => { - default.set_true(); + syn::Body::Struct(syn::VariantData::Struct(_)) => { + default.set(Default::Default); } _ => { - cx.error("#[serde(default)] can only be used on structs") + cx.error("#[serde(default)] can only be used on structs \ + with named fields") + } + } + } + + // Parse `#[serde(default="...")]` + MetaItem(NameValue(ref name, ref lit)) if name == "default" => { + if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + match item.body { + syn::Body::Struct(syn::VariantData::Struct(_)) => { + default.set(Default::Path(path)); + } + _ => { + cx.error("#[serde(default = \"...\")] can only be used \ + on structs with named fields") + } } } } @@ -295,7 +311,7 @@ impl Item { deserialize: de_name.get().unwrap_or_else(|| item.ident.to_string()), }, deny_unknown_fields: deny_unknown_fields.get(), - default: default.get(), + default: default.get().unwrap_or(Default::None), ser_bound: ser_bound.get(), de_bound: de_bound.get(), tag: tag, @@ -310,8 +326,8 @@ impl Item { self.deny_unknown_fields } - pub fn default(&self) -> bool { - self.default + pub fn default(&self) -> &Default { + &self.default } pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { @@ -410,7 +426,7 @@ pub struct Field { skip_serializing: bool, skip_deserializing: bool, skip_serializing_if: Option, - default: FieldDefault, + default: Default, serialize_with: Option, deserialize_with: Option, ser_bound: Option>, @@ -419,7 +435,7 @@ pub struct Field { /// Represents the default to use for a field when deserializing. #[derive(Debug, PartialEq)] -pub enum FieldDefault { +pub enum Default { /// Field must always be specified because it does not have a default. None, /// The default is given by `std::default::Default::default()`. @@ -468,13 +484,13 @@ impl Field { // Parse `#[serde(default)]` MetaItem(Word(ref name)) if name == "default" => { - default.set(FieldDefault::Default); + default.set(Default::Default); } // Parse `#[serde(default="...")]` MetaItem(NameValue(ref name, ref lit)) if name == "default" => { if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { - default.set(FieldDefault::Path(path)); + default.set(Default::Path(path)); } } @@ -552,7 +568,7 @@ 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() { - default.set_if_none(FieldDefault::Default); + default.set_if_none(Default::Default); } Field { @@ -563,7 +579,7 @@ impl Field { skip_serializing: skip_serializing.get(), skip_deserializing: skip_deserializing.get(), skip_serializing_if: skip_serializing_if.get(), - default: default.get().unwrap_or(FieldDefault::None), + default: default.get().unwrap_or(Default::None), serialize_with: serialize_with.get(), deserialize_with: deserialize_with.get(), ser_bound: ser_bound.get(), @@ -587,7 +603,7 @@ impl Field { self.skip_serializing_if.as_ref() } - pub fn default(&self) -> &FieldDefault { + pub fn default(&self) -> &Default { &self.default } diff --git a/serde_derive/src/bound.rs b/serde_derive/src/bound.rs index 1a7f1998..2fe797a1 100644 --- a/serde_derive/src/bound.rs +++ b/serde_derive/src/bound.rs @@ -157,6 +157,30 @@ pub fn with_bound(item: &Item, generics } +pub fn with_self_bound(item: &Item, + generics: &syn::Generics, + bound: &syn::Path) + -> syn::Generics +{ + let mut generics = generics.clone(); + generics.where_clause.predicates.push( + syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate { + bound_lifetimes: Vec::new(), + // the type that is being bounded e.g. MyStruct<'a, T> + bounded_ty: type_of_item(item), + // the bound e.g. Default + bounds: vec![syn::TyParamBound::Trait( + syn::PolyTraitRef { + bound_lifetimes: Vec::new(), + trait_ref: bound.clone(), + }, + syn::TraitBoundModifier::None + )], + }) + ); + generics +} + pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics { @@ -179,3 +203,26 @@ pub fn with_lifetime_bound(generics: &syn::Generics, generics } +fn type_of_item(item: &Item) -> syn::Ty { + syn::Ty::Path(None, syn::Path { + global: false, + segments: vec![ + syn::PathSegment { + ident: item.ident.clone(), + parameters: syn::PathParameters::AngleBracketed(syn::AngleBracketedParameterData { + lifetimes: item.generics + .lifetimes + .iter() + .map(|def| def.lifetime.clone()) + .collect(), + types: item.generics + .ty_params + .iter() + .map(|param| syn::Ty::Path(None, param.ident.clone().into())) + .collect(), + bindings: Vec::new(), + }), + } + ] + }) +} diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 4d6bf85d..65605a50 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -46,11 +46,19 @@ fn build_generics(item: &Item) -> syn::Generics { match item.attrs.de_bound() { Some(predicates) => bound::with_where_predicates(&generics, predicates), None => { + let generics = match *item.attrs.default() { + attr::Default::Default => { + bound::with_self_bound(item, &generics, &path!(_serde::export::Default)) + } + attr::Default::None | attr::Default::Path(_) => generics, + }; + let generics = bound::with_bound(item, &generics, needs_deserialize_bound, &path!(_serde::Deserialize)); + bound::with_bound(item, &generics, requires_default, @@ -70,7 +78,7 @@ fn needs_deserialize_bound(attrs: &attr::Field) -> bool { // Fields with a `default` attribute (not `default=...`), and fields with a // `skip_deserializing` attribute that do not also have `default=...`. fn requires_default(attrs: &attr::Field) -> bool { - attrs.default() == &attr::FieldDefault::Default + attrs.default() == &attr::Default::Default } fn deserialize_body(item: &Item, generics: &syn::Generics) -> Tokens { @@ -168,7 +176,7 @@ fn deserialize_tuple(ident: &syn::Ident, None }; - let visit_seq = deserialize_seq(ident, &type_path, generics, fields, false); + let visit_seq = deserialize_seq(ident, &type_path, generics, fields, false, item_attrs); let visitor_expr = quote! { __Visitor { marker: _serde::export::PhantomData::<#ident #ty_generics> } @@ -222,7 +230,8 @@ fn deserialize_seq(ident: &syn::Ident, type_path: &Tokens, generics: &syn::Generics, fields: &[Field], - is_struct: bool) + is_struct: bool, + item_attrs: &attr::Item) -> Tokens { let vars = (0..fields.len()).map(field_i as fn(_) -> _); @@ -235,7 +244,7 @@ fn deserialize_seq(ident: &syn::Ident, let let_values = vars.clone().zip(fields) .map(|(var, field)| { if field.attrs.skip_deserializing() { - let default = expr_is_missing(&field.attrs, false, ""); + let default = expr_is_missing(&field, item_attrs); quote! { let #var = #default; } @@ -337,7 +346,7 @@ fn deserialize_struct(ident: &syn::Ident, None => format!("struct {}", ident), }; - let visit_seq = deserialize_seq(ident, &type_path, generics, fields, true); + let visit_seq = deserialize_seq(ident, &type_path, generics, fields, true, item_attrs); let (field_visitor, fields_stmt, visit_map) = deserialize_struct_visitor(ident, type_path, generics, fields, item_attrs); @@ -1012,11 +1021,7 @@ fn deserialize_map(ident: &syn::Ident, let extract_values = fields_names.iter() .filter(|&&(field, _)| !field.attrs.skip_deserializing()) .map(|&(field, ref name)| { - // Use the ident as field name, since the user can rename the field - // in the attributes using `#[serde(rename = "name")]`, but we need - // the original (in code) name of the field. - let ident = field.ident.clone().expect("struct contains unnamed fields"); - let missing_expr = expr_is_missing(&field.attrs, item_attrs.default(), ident.as_ref()); + let missing_expr = expr_is_missing(&field, item_attrs); quote! { let #name = match #name { @@ -1030,21 +1035,29 @@ fn deserialize_map(ident: &syn::Ident, .map(|&(field, ref name)| { let ident = field.ident.clone().expect("struct contains unnamed fields"); let value = if field.attrs.skip_deserializing() { - expr_is_missing(&field.attrs, item_attrs.default(), ident.as_ref()) + expr_is_missing(&field, item_attrs) } else { quote!(#name) }; quote!(#ident: #value) }); - let default = if item_attrs.default() { - quote!( - let default: #struct_path = _serde::export::Default::default(); - ) - } else { - // We don't need the default value, to prevent an unused variable warning - // we'll leave the line empty. - quote!() + let let_default = match *item_attrs.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! { @@ -1052,7 +1065,7 @@ fn deserialize_map(ident: &syn::Ident, #match_keys - #default + #let_default #(#extract_values)* @@ -1097,27 +1110,27 @@ fn wrap_deserialize_with(ident: &syn::Ident, (wrapper, wrapper_ty) } -fn expr_is_missing(attrs: &attr::Field, use_default: bool, field_name: &str) -> Tokens { - match *attrs.default() { - attr::FieldDefault::Default => { +fn expr_is_missing(field: &Field, item_attrs: &attr::Item) -> Tokens { + match *field.attrs.default() { + attr::Default::Default => { return quote!(_serde::export::Default::default()); } - attr::FieldDefault::Path(ref path) => { + attr::Default::Path(ref path) => { return quote!(#path()); } - attr::FieldDefault::None => { /* below */ } + attr::Default::None => { /* below */ } } - if use_default { - // Field name without the qoutes. - let field_name = quote::Ident::new(field_name); - return quote!( - default.#field_name - ) + match *item_attrs.default() { + attr::Default::Default | attr::Default::Path(_) => { + let ident = &field.ident; + return quote!(__default.#ident); + } + attr::Default::None => { /* below */ } } - let name = attrs.name().deserialize_name(); - match attrs.deserialize_with() { + let name = field.attrs.name().deserialize_name(); + match field.attrs.deserialize_with() { None => { quote! { try!(_serde::de::private::missing_field(#name)) diff --git a/test_suite/tests/test_de.rs b/test_suite/tests/test_de.rs index d742d684..b531a051 100644 --- a/test_suite/tests/test_de.rs +++ b/test_suite/tests/test_de.rs @@ -43,14 +43,14 @@ struct StructDenyUnknown { #[derive(PartialEq, Debug, Deserialize)] #[serde(default)] -struct StructDefault { +struct StructDefault { a: i32, - b: String, + b: T, } -impl Default for StructDefault { - fn default() -> StructDefault { - StructDefault{ +impl Default for StructDefault { + fn default() -> Self { + StructDefault { a: 100, b: "default".to_string(), } @@ -746,7 +746,7 @@ declare_tests! { ], } test_struct_default { - StructDefault{ a: 50, b: "overwritten".to_string() } => &[ + StructDefault { a: 50, b: "overwritten".to_string() } => &[ Token::StructStart("StructDefault", 1), Token::StructSep, Token::Str("a"), @@ -757,7 +757,7 @@ declare_tests! { Token::String("overwritten".to_string()), Token::StructEnd, ], - StructDefault{ a: 100, b: "default".to_string() } => &[ + StructDefault { a: 100, b: "default".to_string() } => &[ Token::StructStart("StructDefault", 0), Token::StructEnd, ],