Compare commits

...

7 Commits

Author SHA1 Message Date
David Tolnay c2591e9b39 Release 1.0.82 2018-12-10 22:25:27 -08:00
David Tolnay 8ce0dee6da Fix missing dependency on quote in serde_derive_internals 2018-12-10 22:15:46 -08:00
David Tolnay 16daba8ea9 Format with rustfmt 2018-11-30 2018-12-10 22:09:34 -08:00
David Tolnay 8b4074ee77 Tests for tuple default attribute 2018-12-10 22:09:33 -08:00
David Tolnay 85fbd8793a Support default attr in deserialize_seq_in_place 2018-12-10 22:09:31 -08:00
David Tolnay 65705e2091 Merge pull request #1442 from tcr/master
Adds support for the default attr to tuple variants in enums.
2018-12-10 22:09:21 -08:00
Tim Ryan 385a385c62 Adds support for the default attr to tuple variants in enums. 2018-12-11 00:02:50 -05:00
14 changed files with 350 additions and 172 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde" name = "serde"
version = "1.0.81" # remember to update html_root_url version = "1.0.82" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "A generic serialization/deserialization framework" description = "A generic serialization/deserialization framework"
+1 -1
View File
@@ -75,7 +75,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.81")] #![doc(html_root_url = "https://docs.rs/serde/1.0.82")]
// 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)]
// Unstable functionality only if the user asks for it. For tracking and // Unstable functionality only if the user asks for it. For tracking and
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive" name = "serde_derive"
version = "1.0.81" # remember to update html_root_url version = "1.0.82" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
+27 -8
View File
@@ -89,7 +89,10 @@ fn precondition_sized(cx: &Ctxt, cont: &Container) {
if let Data::Struct(_, ref fields) = cont.data { if let Data::Struct(_, ref fields) = cont.data {
if let Some(last) = fields.last() { if let Some(last) = fields.last() {
if let syn::Type::Slice(_) = *last.ty { if let syn::Type::Slice(_) = *last.ty {
cx.error_spanned_by(cont.original, "cannot deserialize a dynamically sized struct"); cx.error_spanned_by(
cont.original,
"cannot deserialize a dynamically sized struct",
);
} }
} }
} }
@@ -366,7 +369,7 @@ fn deserialize_transparent(cont: &Container, params: &Parameters) -> Fragment {
None => { None => {
let span = transparent_field.original.span(); let span = transparent_field.original.span();
quote_spanned!(span=> _serde::Deserialize::deserialize) quote_spanned!(span=> _serde::Deserialize::deserialize)
}, }
}; };
let assign = fields.iter().map(|field| { let assign = fields.iter().map(|field| {
@@ -661,11 +664,18 @@ fn deserialize_seq(
}) })
} }
}; };
let value_if_none = match *field.attrs.default() {
attr::Default::Default => quote!(_serde::export::Default::default()),
attr::Default::Path(ref path) => quote!(#path()),
attr::Default::None => quote!(
return _serde::export::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting));
),
};
let assign = quote! { let assign = quote! {
let #var = match #visit { let #var = match #visit {
_serde::export::Some(__value) => __value, _serde::export::Some(__value) => __value,
_serde::export::None => { _serde::export::None => {
return _serde::export::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting)); #value_if_none
} }
}; };
}; };
@@ -740,8 +750,16 @@ fn deserialize_seq_in_place(
self.place.#member = #default; self.place.#member = #default;
} }
} else { } else {
let return_invalid_length = quote! { let value_if_none = match *field.attrs.default() {
attr::Default::Default => quote!(
self.place.#member = _serde::export::Default::default();
),
attr::Default::Path(ref path) => quote!(
self.place.#member = #path();
),
attr::Default::None => quote!(
return _serde::export::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting)); return _serde::export::Err(_serde::de::Error::invalid_length(#index_in_seq, &#expecting));
),
}; };
let write = match field.attrs.deserialize_with() { let write = match field.attrs.deserialize_with() {
None => { None => {
@@ -749,7 +767,7 @@ fn deserialize_seq_in_place(
if let _serde::export::None = try!(_serde::de::SeqAccess::next_element_seed(&mut __seq, if let _serde::export::None = try!(_serde::de::SeqAccess::next_element_seed(&mut __seq,
_serde::private::de::InPlaceSeed(&mut self.place.#member))) _serde::private::de::InPlaceSeed(&mut self.place.#member)))
{ {
#return_invalid_length #value_if_none
} }
} }
} }
@@ -762,7 +780,7 @@ fn deserialize_seq_in_place(
self.place.#member = __wrap.value; self.place.#member = __wrap.value;
} }
_serde::export::None => { _serde::export::None => {
#return_invalid_length #value_if_none
} }
} }
}) })
@@ -1815,7 +1833,8 @@ fn deserialize_externally_tagged_newtype_variant(
None => { None => {
let field_ty = field.ty; let field_ty = field.ty;
let span = field.original.span(); let span = field.original.span();
let func = quote_spanned!(span=> _serde::de::VariantAccess::newtype_variant::<#field_ty>); let func =
quote_spanned!(span=> _serde::de::VariantAccess::newtype_variant::<#field_ty>);
quote_expr! { quote_expr! {
_serde::export::Result::map(#func(__variant), #this::#variant_ident) _serde::export::Result::map(#func(__variant), #this::#variant_ident)
} }
@@ -2455,7 +2474,7 @@ fn deserialize_map(
None => { None => {
let span = field.original.span(); let span = field.original.span();
quote_spanned!(span=> _serde::de::Deserialize::deserialize) quote_spanned!(span=> _serde::de::Deserialize::deserialize)
}, }
Some(path) => quote!(#path), Some(path) => quote!(#path),
}; };
quote! { quote! {
+5 -1
View File
@@ -60,7 +60,11 @@ pub enum Style {
impl<'a> Container<'a> { impl<'a> Container<'a> {
/// Convert the raw Syn ast into a parsed container object, collecting errors in `cx`. /// Convert the raw Syn ast into a parsed container object, collecting errors in `cx`.
pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput, derive: Derive) -> Option<Container<'a>> { pub fn from_ast(
cx: &Ctxt,
item: &'a syn::DeriveInput,
derive: Derive,
) -> Option<Container<'a>> {
let mut attrs = attr::Container::from_ast(cx, item); let mut attrs = attr::Container::from_ast(cx, item);
let mut data = match item.data { let mut data = match item.data {
+134 -82
View File
@@ -42,10 +42,8 @@ impl<'c, T> Attr<'c, T> {
let tokens = obj.into_token_stream(); let tokens = obj.into_token_stream();
if self.value.is_some() { if self.value.is_some() {
self.cx.error_spanned_by( self.cx
tokens, .error_spanned_by(tokens, format!("duplicate serde attribute `{}`", self.name));
format!("duplicate serde attribute `{}`", self.name),
);
} else { } else {
self.tokens = tokens; self.tokens = tokens;
self.value = Some(value); self.value = Some(value);
@@ -232,11 +230,14 @@ impl Container {
if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
match RenameRule::from_str(&s.value()) { match RenameRule::from_str(&s.value()) {
Ok(rename_rule) => rename_all.set(&m.ident, rename_rule), Ok(rename_rule) => rename_all.set(&m.ident, rename_rule),
Err(()) => cx.error_spanned_by(s, format!( Err(()) => cx.error_spanned_by(
s,
format!(
"unknown rename rule for #[serde(rename_all \ "unknown rename rule for #[serde(rename_all \
= {:?})]", = {:?})]",
s.value(), s.value(),
)), ),
),
} }
} }
} }
@@ -261,14 +262,17 @@ impl Container {
fields, fields,
"#[serde(default)] can only be used on structs \ "#[serde(default)] can only be used on structs \
with named fields", with named fields",
) ),
}, },
syn::Data::Enum(syn::DataEnum { ref enum_token, .. }) => cx.error_spanned_by( syn::Data::Enum(syn::DataEnum { ref enum_token, .. }) => cx
.error_spanned_by(
enum_token, enum_token,
"#[serde(default)] can only be used on structs \ "#[serde(default)] can only be used on structs \
with named fields", with named fields",
), ),
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => cx.error_spanned_by( syn::Data::Union(syn::DataUnion {
ref union_token, ..
}) => cx.error_spanned_by(
union_token, union_token,
"#[serde(default)] can only be used on structs \ "#[serde(default)] can only be used on structs \
with named fields", with named fields",
@@ -279,22 +283,28 @@ impl Container {
Meta(NameValue(ref m)) if m.ident == "default" => { Meta(NameValue(ref m)) if m.ident == "default" => {
if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) { if let Ok(path) = parse_lit_into_expr_path(cx, &m.ident, &m.lit) {
match item.data { match item.data {
syn::Data::Struct(syn::DataStruct { ref fields, .. }) => match *fields { syn::Data::Struct(syn::DataStruct { ref fields, .. }) => {
match *fields {
syn::Fields::Named(_) => { syn::Fields::Named(_) => {
default.set(&m.ident, Default::Path(path)); default.set(&m.ident, Default::Path(path));
} }
syn::Fields::Unnamed(_) | syn::Fields::Unit => cx.error_spanned_by( syn::Fields::Unnamed(_) | syn::Fields::Unit => cx
.error_spanned_by(
fields, fields,
"#[serde(default = \"...\")] can only be used \ "#[serde(default = \"...\")] can only be used \
on structs with named fields", on structs with named fields",
) ),
}, }
syn::Data::Enum(syn::DataEnum { ref enum_token, .. }) => cx.error_spanned_by( }
syn::Data::Enum(syn::DataEnum { ref enum_token, .. }) => cx
.error_spanned_by(
enum_token, enum_token,
"#[serde(default = \"...\")] can only be used \ "#[serde(default = \"...\")] can only be used \
on structs with named fields", on structs with named fields",
), ),
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => cx.error_spanned_by( syn::Data::Union(syn::DataUnion {
ref union_token, ..
}) => cx.error_spanned_by(
union_token, union_token,
"#[serde(default = \"...\")] can only be used \ "#[serde(default = \"...\")] can only be used \
on structs with named fields", on structs with named fields",
@@ -326,13 +336,17 @@ impl Container {
syn::Data::Enum(_) => { syn::Data::Enum(_) => {
untagged.set_true(word); untagged.set_true(word);
} }
syn::Data::Struct(syn::DataStruct { ref struct_token, .. }) => { syn::Data::Struct(syn::DataStruct {
ref struct_token, ..
}) => {
cx.error_spanned_by( cx.error_spanned_by(
struct_token, struct_token,
"#[serde(untagged)] can only be used on enums", "#[serde(untagged)] can only be used on enums",
); );
} }
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => { syn::Data::Union(syn::DataUnion {
ref union_token, ..
}) => {
cx.error_spanned_by( cx.error_spanned_by(
union_token, union_token,
"#[serde(untagged)] can only be used on enums", "#[serde(untagged)] can only be used on enums",
@@ -347,18 +361,22 @@ impl Container {
syn::Data::Enum(_) => { syn::Data::Enum(_) => {
internal_tag.set(&m.ident, s.value()); internal_tag.set(&m.ident, s.value());
} }
syn::Data::Struct(syn::DataStruct { ref struct_token, .. }) => { syn::Data::Struct(syn::DataStruct {
ref struct_token, ..
}) => {
cx.error_spanned_by( cx.error_spanned_by(
struct_token, struct_token,
"#[serde(tag = \"...\")] can only be used on enums", "#[serde(tag = \"...\")] can only be used on enums",
); );
}, }
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => { syn::Data::Union(syn::DataUnion {
ref union_token, ..
}) => {
cx.error_spanned_by( cx.error_spanned_by(
union_token, union_token,
"#[serde(tag = \"...\")] can only be used on enums", "#[serde(tag = \"...\")] can only be used on enums",
); );
}, }
} }
} }
} }
@@ -370,18 +388,22 @@ impl Container {
syn::Data::Enum(_) => { syn::Data::Enum(_) => {
content.set(&m.ident, s.value()); content.set(&m.ident, s.value());
} }
syn::Data::Struct(syn::DataStruct { ref struct_token, .. }) => { syn::Data::Struct(syn::DataStruct {
ref struct_token, ..
}) => {
cx.error_spanned_by( cx.error_spanned_by(
struct_token, struct_token,
"#[serde(content = \"...\")] can only be used on enums", "#[serde(content = \"...\")] can only be used on enums",
); );
}, }
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => { syn::Data::Union(syn::DataUnion {
ref union_token, ..
}) => {
cx.error_spanned_by( cx.error_spanned_by(
union_token, union_token,
"#[serde(content = \"...\")] can only be used on enums", "#[serde(content = \"...\")] can only be used on enums",
); );
}, }
} }
} }
} }
@@ -422,10 +444,10 @@ impl Container {
} }
Meta(ref meta_item) => { Meta(ref meta_item) => {
cx.error_spanned_by(meta_item.name(), format!( cx.error_spanned_by(
"unknown serde container attribute `{}`", meta_item.name(),
meta_item.name() format!("unknown serde container attribute `{}`", meta_item.name()),
)); );
} }
Literal(ref lit) => { Literal(ref lit) => {
@@ -519,7 +541,11 @@ fn decide_tag(
internal_tag: Attr<String>, internal_tag: Attr<String>,
content: Attr<String>, content: Attr<String>,
) -> EnumTag { ) -> EnumTag {
match (untagged.0.get_with_tokens(), internal_tag.get_with_tokens(), content.get_with_tokens()) { match (
untagged.0.get_with_tokens(),
internal_tag.get_with_tokens(),
content.get_with_tokens(),
) {
(None, None, None) => EnumTag::External, (None, None, None) => EnumTag::External,
(Some(_), None, None) => EnumTag::None, (Some(_), None, None) => EnumTag::None,
(None, Some((_, tag)), None) => { (None, Some((_, tag)), None) => {
@@ -600,7 +626,11 @@ fn decide_identifier(
field_identifier: BoolAttr, field_identifier: BoolAttr,
variant_identifier: BoolAttr, variant_identifier: BoolAttr,
) -> Identifier { ) -> Identifier {
match (&item.data, field_identifier.0.get_with_tokens(), variant_identifier.0.get_with_tokens()) { match (
&item.data,
field_identifier.0.get_with_tokens(),
variant_identifier.0.get_with_tokens(),
) {
(_, None, None) => Identifier::No, (_, None, None) => Identifier::No,
(_, Some((field_identifier_tokens, _)), Some((variant_identifier_tokens, _))) => { (_, Some((field_identifier_tokens, _)), Some((variant_identifier_tokens, _))) => {
cx.error_spanned_by( cx.error_spanned_by(
@@ -615,28 +645,52 @@ fn decide_identifier(
} }
(&syn::Data::Enum(_), Some(_), None) => Identifier::Field, (&syn::Data::Enum(_), Some(_), None) => Identifier::Field,
(&syn::Data::Enum(_), None, Some(_)) => Identifier::Variant, (&syn::Data::Enum(_), None, Some(_)) => Identifier::Variant,
(&syn::Data::Struct(syn::DataStruct { ref struct_token, .. }), Some(_), None) => { (
&syn::Data::Struct(syn::DataStruct {
ref struct_token, ..
}),
Some(_),
None,
) => {
cx.error_spanned_by( cx.error_spanned_by(
struct_token, struct_token,
"#[serde(field_identifier)] can only be used on an enum", "#[serde(field_identifier)] can only be used on an enum",
); );
Identifier::No Identifier::No
} }
(&syn::Data::Union(syn::DataUnion { ref union_token, .. }), Some(_), None) => { (
&syn::Data::Union(syn::DataUnion {
ref union_token, ..
}),
Some(_),
None,
) => {
cx.error_spanned_by( cx.error_spanned_by(
union_token, union_token,
"#[serde(field_identifier)] can only be used on an enum", "#[serde(field_identifier)] can only be used on an enum",
); );
Identifier::No Identifier::No
} }
(&syn::Data::Struct(syn::DataStruct { ref struct_token, .. }), None, Some(_)) => { (
&syn::Data::Struct(syn::DataStruct {
ref struct_token, ..
}),
None,
Some(_),
) => {
cx.error_spanned_by( cx.error_spanned_by(
struct_token, struct_token,
"#[serde(variant_identifier)] can only be used on an enum", "#[serde(variant_identifier)] can only be used on an enum",
); );
Identifier::No Identifier::No
} }
(&syn::Data::Union(syn::DataUnion { ref union_token, .. }), None, Some(_)) => { (
&syn::Data::Union(syn::DataUnion {
ref union_token, ..
}),
None,
Some(_),
) => {
cx.error_spanned_by( cx.error_spanned_by(
union_token, union_token,
"#[serde(variant_identifier)] can only be used on an enum", "#[serde(variant_identifier)] can only be used on an enum",
@@ -700,11 +754,14 @@ impl Variant {
if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) { if let Ok(s) = get_lit_str(cx, &m.ident, &m.ident, &m.lit) {
match RenameRule::from_str(&s.value()) { match RenameRule::from_str(&s.value()) {
Ok(rename_rule) => rename_all.set(&m.ident, rename_rule), Ok(rename_rule) => rename_all.set(&m.ident, rename_rule),
Err(()) => cx.error_spanned_by(s, format!( Err(()) => cx.error_spanned_by(
s,
format!(
"unknown rename rule for #[serde(rename_all \ "unknown rename rule for #[serde(rename_all \
= {:?})]", = {:?})]",
s.value() s.value()
)), ),
),
} }
} }
} }
@@ -794,17 +851,14 @@ impl Variant {
}, },
Meta(ref meta_item) => { Meta(ref meta_item) => {
cx.error_spanned_by(meta_item.name(), format!( cx.error_spanned_by(
"unknown serde variant attribute `{}`", meta_item.name(),
meta_item.name() format!("unknown serde variant attribute `{}`", meta_item.name()),
)); );
} }
Literal(ref lit) => { Literal(ref lit) => {
cx.error_spanned_by( cx.error_spanned_by(lit, "unexpected literal in serde variant attribute");
lit,
"unexpected literal in serde variant attribute",
);
} }
} }
} }
@@ -1071,10 +1125,13 @@ impl Field {
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) {
for lifetime in &lifetimes { for lifetime in &lifetimes {
if !borrowable.contains(lifetime) { if !borrowable.contains(lifetime) {
cx.error_spanned_by(field, format!( cx.error_spanned_by(
field,
format!(
"field `{}` does not have lifetime {}", "field `{}` does not have lifetime {}",
ident, lifetime ident, lifetime
)); ),
);
} }
} }
borrowed_lifetimes.set(&m.ident, lifetimes); borrowed_lifetimes.set(&m.ident, lifetimes);
@@ -1095,17 +1152,14 @@ impl Field {
} }
Meta(ref meta_item) => { Meta(ref meta_item) => {
cx.error_spanned_by(meta_item.name(), format!( cx.error_spanned_by(
"unknown serde field attribute `{}`", meta_item.name(),
meta_item.name() format!("unknown serde field attribute `{}`", meta_item.name()),
)); );
} }
Literal(ref lit) => { Literal(ref lit) => {
cx.error_spanned_by( cx.error_spanned_by(lit, "unexpected literal in serde field attribute");
lit,
"unexpected literal in serde field attribute",
);
} }
} }
} }
@@ -1299,11 +1353,14 @@ where
} }
_ => { _ => {
cx.error_spanned_by(meta, format!( cx.error_spanned_by(
meta,
format!(
"malformed {0} attribute, expected `{0}(serialize = ..., \ "malformed {0} attribute, expected `{0}(serialize = ..., \
deserialize = ...)`", deserialize = ...)`",
attr_name attr_name
)); ),
);
return Err(()); return Err(());
} }
} }
@@ -1349,21 +1406,22 @@ fn get_lit_str<'a>(
if let syn::Lit::Str(ref lit) = *lit { if let syn::Lit::Str(ref lit) = *lit {
Ok(lit) Ok(lit)
} else { } else {
cx.error_spanned_by(lit, format!( cx.error_spanned_by(
lit,
format!(
"expected serde {} attribute to be a string: `{} = \"...\"`", "expected serde {} attribute to be a string: `{} = \"...\"`",
attr_name, meta_item_name attr_name, meta_item_name
)); ),
);
Err(()) Err(())
} }
} }
fn parse_lit_into_path(cx: &Ctxt, attr_name: &Ident, lit: &syn::Lit) -> Result<syn::Path, ()> { fn parse_lit_into_path(cx: &Ctxt, attr_name: &Ident, lit: &syn::Lit) -> Result<syn::Path, ()> {
let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
parse_lit_str(string) parse_lit_str(string).map_err(|_| {
.map_err(|_| cx.error_spanned_by( cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value()))
lit, })
format!("failed to parse path: {:?}", string.value()),
))
} }
fn parse_lit_into_expr_path( fn parse_lit_into_expr_path(
@@ -1372,11 +1430,9 @@ fn parse_lit_into_expr_path(
lit: &syn::Lit, lit: &syn::Lit,
) -> Result<syn::ExprPath, ()> { ) -> Result<syn::ExprPath, ()> {
let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
parse_lit_str(string) parse_lit_str(string).map_err(|_| {
.map_err(|_| cx.error_spanned_by( cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value()))
lit, })
format!("failed to parse path: {:?}", string.value()),
))
} }
fn parse_lit_into_where( fn parse_lit_into_where(
@@ -1401,11 +1457,10 @@ fn parse_lit_into_ty(cx: &Ctxt, attr_name: &Ident, lit: &syn::Lit) -> Result<syn
let string = try!(get_lit_str(cx, attr_name, attr_name, lit)); let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
parse_lit_str(string).map_err(|_| { parse_lit_str(string).map_err(|_| {
cx.error_spanned_by(lit, format!( cx.error_spanned_by(
"failed to parse type: {} = {:?}", lit,
attr_name, format!("failed to parse type: {} = {:?}", attr_name, string.value()),
string.value() )
))
}) })
} }
@@ -1434,19 +1489,16 @@ fn parse_lit_into_lifetimes(
let mut set = BTreeSet::new(); let mut set = BTreeSet::new();
for lifetime in lifetimes { for lifetime in lifetimes {
if !set.insert(lifetime.clone()) { if !set.insert(lifetime.clone()) {
cx.error_spanned_by( cx.error_spanned_by(lit, format!("duplicate borrowed lifetime `{}`", lifetime));
lit,
format!("duplicate borrowed lifetime `{}`", lifetime),
);
} }
} }
return Ok(set); return Ok(set);
} }
cx.error_spanned_by(lit, format!( cx.error_spanned_by(
"failed to parse borrowed lifetimes: {:?}", lit,
string.value() format!("failed to parse borrowed lifetimes: {:?}", string.value()),
)); );
Err(()) Err(())
} }
+34 -14
View File
@@ -198,52 +198,67 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
for variant in variants.iter() { for variant in variants.iter() {
if variant.attrs.serialize_with().is_some() { if variant.attrs.serialize_with().is_some() {
if variant.attrs.skip_serializing() { if variant.attrs.skip_serializing() {
cx.error_spanned_by(variant.original, format!( cx.error_spanned_by(
variant.original,
format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \ "variant `{}` cannot have both #[serde(serialize_with)] and \
#[serde(skip_serializing)]", #[serde(skip_serializing)]",
variant.ident variant.ident
)); ),
);
} }
for field in &variant.fields { for field in &variant.fields {
let member = member_message(&field.member); let member = member_message(&field.member);
if field.attrs.skip_serializing() { if field.attrs.skip_serializing() {
cx.error_spanned_by(variant.original, format!( cx.error_spanned_by(
variant.original,
format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \ "variant `{}` cannot have both #[serde(serialize_with)] and \
a field {} marked with #[serde(skip_serializing)]", a field {} marked with #[serde(skip_serializing)]",
variant.ident, member variant.ident, member
)); ),
);
} }
if field.attrs.skip_serializing_if().is_some() { if field.attrs.skip_serializing_if().is_some() {
cx.error_spanned_by(variant.original, format!( cx.error_spanned_by(
variant.original,
format!(
"variant `{}` cannot have both #[serde(serialize_with)] and \ "variant `{}` cannot have both #[serde(serialize_with)] and \
a field {} marked with #[serde(skip_serializing_if)]", a field {} marked with #[serde(skip_serializing_if)]",
variant.ident, member variant.ident, member
)); ),
);
} }
} }
} }
if variant.attrs.deserialize_with().is_some() { if variant.attrs.deserialize_with().is_some() {
if variant.attrs.skip_deserializing() { if variant.attrs.skip_deserializing() {
cx.error_spanned_by(variant.original, format!( cx.error_spanned_by(
variant.original,
format!(
"variant `{}` cannot have both #[serde(deserialize_with)] and \ "variant `{}` cannot have both #[serde(deserialize_with)] and \
#[serde(skip_deserializing)]", #[serde(skip_deserializing)]",
variant.ident variant.ident
)); ),
);
} }
for field in &variant.fields { for field in &variant.fields {
if field.attrs.skip_deserializing() { if field.attrs.skip_deserializing() {
let member = member_message(&field.member); let member = member_message(&field.member);
cx.error_spanned_by(variant.original, format!( cx.error_spanned_by(
variant.original,
format!(
"variant `{}` cannot have both #[serde(deserialize_with)] \ "variant `{}` cannot have both #[serde(deserialize_with)] \
and a field {} marked with #[serde(skip_deserializing)]", and a field {} marked with #[serde(skip_deserializing)]",
variant.ident, member variant.ident, member
)); ),
);
} }
} }
} }
@@ -265,10 +280,12 @@ fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) {
EnumTag::External | EnumTag::Adjacent { .. } | EnumTag::None => return, EnumTag::External | EnumTag::Adjacent { .. } | EnumTag::None => return,
}; };
let diagnose_conflict = || cx.error_spanned_by( let diagnose_conflict = || {
cx.error_spanned_by(
cont.original, cont.original,
format!("variant field name `{}` conflicts with internal tag", tag), format!("variant field name `{}` conflicts with internal tag", tag),
); )
};
for variant in variants { for variant in variants {
match variant.style { match variant.style {
@@ -303,10 +320,13 @@ fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
}; };
if type_tag == content_tag { if type_tag == content_tag {
cx.error_spanned_by(cont.original, format!( cx.error_spanned_by(
cont.original,
format!(
"enum tags `{}` for type and content conflict with each other", "enum tags `{}` for type and content conflict with each other",
type_tag type_tag
)); ),
);
} }
} }
+1 -1
View File
@@ -14,7 +14,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.81")] #![doc(html_root_url = "https://docs.rs/serde_derive/1.0.82")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints // Whitelisted clippy lints
+1 -1
View File
@@ -206,7 +206,7 @@ fn serialize_transparent(cont: &Container, params: &Parameters) -> Fragment {
None => { None => {
let span = transparent_field.original.span(); let span = transparent_field.original.span();
quote_spanned!(span=> _serde::Serialize::serialize) quote_spanned!(span=> _serde::Serialize::serialize)
}, }
}; };
quote_block! { quote_block! {
+2 -1
View File
@@ -15,7 +15,8 @@ path = "lib.rs"
[dependencies] [dependencies]
proc-macro2 = "0.4" proc-macro2 = "0.4"
syn = { version = "0.15", default-features = false, features = ["derive", "parsing", "clone-impls"] } quote = "0.6.3"
syn = { version = "0.15", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] }
[badges] [badges]
travis-ci = { repository = "serde-rs/serde" } travis-ci = { repository = "serde-rs/serde" }
+1
View File
@@ -14,6 +14,7 @@
extern crate syn; extern crate syn;
extern crate proc_macro2; extern crate proc_macro2;
extern crate quote;
#[path = "src/mod.rs"] #[path = "src/mod.rs"]
mod internals; mod internals;
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_test" name = "serde_test"
version = "1.0.81" # remember to update html_root_url version = "1.0.82" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Token De/Serializer for testing De/Serialize implementations" description = "Token De/Serializer for testing De/Serialize implementations"
+1 -1
View File
@@ -153,7 +153,7 @@
//! # } //! # }
//! ``` //! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.81")] #![doc(html_root_url = "https://docs.rs/serde_test/1.0.82")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))] #![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints // Whitelisted clippy lints
+87 -6
View File
@@ -93,6 +93,15 @@ where
a5: E, a5: E,
} }
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct DefaultTupleStruct<A, B, C>(
A,
#[serde(default)] B,
#[serde(default = "MyDefault::my_default")] C,
)
where
C: MyDefault;
#[derive(Debug, PartialEq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Serialize, Deserialize)]
struct CollectOther { struct CollectOther {
a: u32, a: u32,
@@ -186,8 +195,37 @@ fn test_default_struct() {
); );
} }
#[test]
fn test_default_tuple() {
assert_de_tokens(
&DefaultTupleStruct(1, 2, 3),
&[
Token::TupleStruct {
name: "DefaultTupleStruct",
len: 3,
},
Token::I32(1),
Token::I32(2),
Token::I32(3),
Token::TupleStructEnd,
],
);
assert_de_tokens(
&DefaultTupleStruct(1, 0, 123),
&[
Token::TupleStruct {
name: "DefaultTupleStruct",
len: 3,
},
Token::I32(1),
Token::TupleStructEnd,
],
);
}
#[derive(Debug, PartialEq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Serialize, Deserialize)]
enum DefaultEnum<A, B, C, D, E> enum DefaultStructVariant<A, B, C, D, E>
where where
C: MyDefault, C: MyDefault,
E: MyDefault, E: MyDefault,
@@ -205,10 +243,22 @@ where
}, },
} }
#[derive(Debug, PartialEq, Serialize, Deserialize)]
enum DefaultTupleVariant<A, B, C>
where
C: MyDefault,
{
Tuple(
A,
#[serde(default)] B,
#[serde(default = "MyDefault::my_default")] C,
),
}
#[test] #[test]
fn test_default_enum() { fn test_default_struct_variant() {
assert_de_tokens( assert_de_tokens(
&DefaultEnum::Struct { &DefaultStructVariant::Struct {
a1: 1, a1: 1,
a2: 2, a2: 2,
a3: 3, a3: 3,
@@ -217,7 +267,7 @@ fn test_default_enum() {
}, },
&[ &[
Token::StructVariant { Token::StructVariant {
name: "DefaultEnum", name: "DefaultStructVariant",
variant: "Struct", variant: "Struct",
len: 3, len: 3,
}, },
@@ -236,7 +286,7 @@ fn test_default_enum() {
); );
assert_de_tokens( assert_de_tokens(
&DefaultEnum::Struct { &DefaultStructVariant::Struct {
a1: 1, a1: 1,
a2: 0, a2: 0,
a3: 123, a3: 123,
@@ -245,7 +295,7 @@ fn test_default_enum() {
}, },
&[ &[
Token::StructVariant { Token::StructVariant {
name: "DefaultEnum", name: "DefaultStructVariant",
variant: "Struct", variant: "Struct",
len: 3, len: 3,
}, },
@@ -256,6 +306,37 @@ fn test_default_enum() {
); );
} }
#[test]
fn test_default_tuple_variant() {
assert_de_tokens(
&DefaultTupleVariant::Tuple(1, 2, 3),
&[
Token::TupleVariant {
name: "DefaultTupleVariant",
variant: "Tuple",
len: 3,
},
Token::I32(1),
Token::I32(2),
Token::I32(3),
Token::TupleVariantEnd,
],
);
assert_de_tokens(
&DefaultTupleVariant::Tuple(1, 0, 123),
&[
Token::TupleVariant {
name: "DefaultTupleVariant",
variant: "Tuple",
len: 3,
},
Token::I32(1),
Token::TupleVariantEnd,
],
);
}
// Does not implement std::default::Default. // Does not implement std::default::Default.
#[derive(Debug, PartialEq, Deserialize)] #[derive(Debug, PartialEq, Deserialize)]
struct NoStdDefault(i8); struct NoStdDefault(i8);