mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-09 20:11:01 +00:00
Improve overall quality of compile_error! errors
Also updates UI tests.
This commit is contained in:
@@ -26,7 +26,7 @@ proc-macro = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
proc-macro2 = "0.4"
|
proc-macro2 = "0.4"
|
||||||
quote = "0.6.3"
|
quote = "0.6.3"
|
||||||
syn = { version = "0.15", features = ["visit"] }
|
syn = { version = "0.15.22", features = ["visit"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde = { version = "1.0", path = "../serde" }
|
serde = { version = "1.0", path = "../serde" }
|
||||||
|
|||||||
+10
-4
@@ -13,9 +13,12 @@ use try;
|
|||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<TokenStream, String> {
|
pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
|
||||||
let ctxt = Ctxt::new();
|
let ctxt = Ctxt::new();
|
||||||
let cont = Container::from_ast(&ctxt, input, Derive::Deserialize);
|
let cont = match Container::from_ast(&ctxt, input, Derive::Deserialize) {
|
||||||
|
Some(cont) => cont,
|
||||||
|
None => return Err(ctxt.check().unwrap_err()),
|
||||||
|
};
|
||||||
precondition(&ctxt, &cont);
|
precondition(&ctxt, &cont);
|
||||||
try!(ctxt.check());
|
try!(ctxt.check());
|
||||||
|
|
||||||
@@ -86,7 +89,7 @@ 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("cannot deserialize a dynamically sized struct");
|
cx.error_spanned_by(cont.original, "cannot deserialize a dynamically sized struct");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,7 +99,10 @@ fn precondition_no_de_lifetime(cx: &Ctxt, cont: &Container) {
|
|||||||
if let BorrowedLifetimes::Borrowed(_) = borrowed_lifetimes(cont) {
|
if let BorrowedLifetimes::Borrowed(_) = borrowed_lifetimes(cont) {
|
||||||
for param in cont.generics.lifetimes() {
|
for param in cont.generics.lifetimes() {
|
||||||
if param.lifetime.to_string() == "'de" {
|
if param.lifetime.to_string() == "'de" {
|
||||||
cx.error("cannot deserialize when there is a lifetime parameter called 'de");
|
cx.error_spanned_by(
|
||||||
|
¶m.lifetime,
|
||||||
|
"cannot deserialize when there is a lifetime parameter called 'de",
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ pub struct Container<'a> {
|
|||||||
pub data: Data<'a>,
|
pub data: Data<'a>,
|
||||||
/// Any generics on the struct or enum.
|
/// Any generics on the struct or enum.
|
||||||
pub generics: &'a syn::Generics,
|
pub generics: &'a syn::Generics,
|
||||||
|
/// Original input.
|
||||||
|
pub original: &'a syn::DeriveInput,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The fields of a struct or enum.
|
/// The fields of a struct or enum.
|
||||||
@@ -33,6 +35,7 @@ pub struct Variant<'a> {
|
|||||||
pub attrs: attr::Variant,
|
pub attrs: attr::Variant,
|
||||||
pub style: Style,
|
pub style: Style,
|
||||||
pub fields: Vec<Field<'a>>,
|
pub fields: Vec<Field<'a>>,
|
||||||
|
pub original: &'a syn::Variant,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A field of a struct.
|
/// A field of a struct.
|
||||||
@@ -57,7 +60,7 @@ 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) -> 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 {
|
||||||
@@ -69,7 +72,8 @@ impl<'a> Container<'a> {
|
|||||||
Data::Struct(style, fields)
|
Data::Struct(style, fields)
|
||||||
}
|
}
|
||||||
syn::Data::Union(_) => {
|
syn::Data::Union(_) => {
|
||||||
panic!("Serde does not support derive for unions");
|
cx.error_spanned_by(item, "Serde does not support derive for unions");
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -105,9 +109,10 @@ impl<'a> Container<'a> {
|
|||||||
attrs: attrs,
|
attrs: attrs,
|
||||||
data: data,
|
data: data,
|
||||||
generics: &item.generics,
|
generics: &item.generics,
|
||||||
|
original: item,
|
||||||
};
|
};
|
||||||
check::check(cx, &mut item, derive);
|
check::check(cx, &mut item, derive);
|
||||||
item
|
Some(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +147,7 @@ fn enum_from_ast<'a>(
|
|||||||
attrs: attrs,
|
attrs: attrs,
|
||||||
style: style,
|
style: style,
|
||||||
fields: fields,
|
fields: fields,
|
||||||
|
original: variant,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|||||||
+290
-152
@@ -1,5 +1,6 @@
|
|||||||
use internals::Ctxt;
|
use internals::Ctxt;
|
||||||
use proc_macro2::{Group, Span, TokenStream, TokenTree};
|
use proc_macro2::{Group, Span, TokenStream, TokenTree};
|
||||||
|
use quote::ToTokens;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use syn;
|
use syn;
|
||||||
@@ -19,10 +20,11 @@ use syn::NestedMeta::{Literal, Meta};
|
|||||||
|
|
||||||
pub use internals::case::RenameRule;
|
pub use internals::case::RenameRule;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Clone)]
|
||||||
struct Attr<'c, T> {
|
struct Attr<'c, T> {
|
||||||
cx: &'c Ctxt,
|
cx: &'c Ctxt,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
|
tokens: TokenStream,
|
||||||
value: Option<T>,
|
value: Option<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,22 +33,28 @@ impl<'c, T> Attr<'c, T> {
|
|||||||
Attr {
|
Attr {
|
||||||
cx: cx,
|
cx: cx,
|
||||||
name: name,
|
name: name,
|
||||||
|
tokens: TokenStream::new(),
|
||||||
value: None,
|
value: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set(&mut self, value: T) {
|
fn set<A: ToTokens>(&mut self, obj: A, value: T) {
|
||||||
|
let tokens = obj.into_token_stream();
|
||||||
|
|
||||||
if self.value.is_some() {
|
if self.value.is_some() {
|
||||||
self.cx
|
self.cx.error_spanned_by(
|
||||||
.error(format!("duplicate serde attribute `{}`", self.name));
|
tokens,
|
||||||
|
format!("duplicate serde attribute `{}`", self.name),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
|
self.tokens = tokens;
|
||||||
self.value = Some(value);
|
self.value = Some(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_opt(&mut self, value: Option<T>) {
|
fn set_opt<A: ToTokens>(&mut self, obj: A, value: Option<T>) {
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
self.set(value);
|
self.set(obj, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +67,13 @@ impl<'c, T> Attr<'c, T> {
|
|||||||
fn get(self) -> Option<T> {
|
fn get(self) -> Option<T> {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_with_tokens(self) -> Option<(TokenStream, T)> {
|
||||||
|
match self.value {
|
||||||
|
Some(v) => Some((self.tokens, v)),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BoolAttr<'c>(Attr<'c, ()>);
|
struct BoolAttr<'c>(Attr<'c, ()>);
|
||||||
@@ -68,8 +83,8 @@ impl<'c> BoolAttr<'c> {
|
|||||||
BoolAttr(Attr::none(cx, name))
|
BoolAttr(Attr::none(cx, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_true(&mut self) {
|
fn set_true<A: ToTokens>(&mut self, obj: A) {
|
||||||
self.0.set(());
|
self.0.set(obj, ());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self) -> bool {
|
fn get(&self) -> bool {
|
||||||
@@ -199,16 +214,16 @@ impl Container {
|
|||||||
// Parse `#[serde(rename = "foo")]`
|
// Parse `#[serde(rename = "foo")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "rename" => {
|
Meta(NameValue(ref m)) if m.ident == "rename" => {
|
||||||
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) {
|
||||||
ser_name.set(s.value());
|
ser_name.set(&m.ident, s.value());
|
||||||
de_name.set(s.value());
|
de_name.set(&m.ident, s.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
|
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
|
||||||
Meta(List(ref m)) if m.ident == "rename" => {
|
Meta(List(ref m)) if m.ident == "rename" => {
|
||||||
if let Ok((ser, de)) = get_renames(cx, &m.nested) {
|
if let Ok((ser, de)) = get_renames(cx, &m.nested) {
|
||||||
ser_name.set_opt(ser.map(syn::LitStr::value));
|
ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value));
|
||||||
de_name.set_opt(de.map(syn::LitStr::value));
|
de_name.set_opt(&m.ident, de.map(syn::LitStr::value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,11 +231,11 @@ impl Container {
|
|||||||
Meta(NameValue(ref m)) if m.ident == "rename_all" => {
|
Meta(NameValue(ref m)) if m.ident == "rename_all" => {
|
||||||
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(rename_rule),
|
Ok(rename_rule) => rename_all.set(&m.ident, rename_rule),
|
||||||
Err(()) => cx.error(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(),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,23 +243,33 @@ impl Container {
|
|||||||
|
|
||||||
// Parse `#[serde(transparent)]`
|
// Parse `#[serde(transparent)]`
|
||||||
Meta(Word(ref word)) if word == "transparent" => {
|
Meta(Word(ref word)) if word == "transparent" => {
|
||||||
transparent.set_true();
|
transparent.set_true(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(deny_unknown_fields)]`
|
// Parse `#[serde(deny_unknown_fields)]`
|
||||||
Meta(Word(ref word)) if word == "deny_unknown_fields" => {
|
Meta(Word(ref word)) if word == "deny_unknown_fields" => {
|
||||||
deny_unknown_fields.set_true();
|
deny_unknown_fields.set_true(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(default)]`
|
// Parse `#[serde(default)]`
|
||||||
Meta(Word(ref word)) if word == "default" => match item.data {
|
Meta(Word(ref word)) if word == "default" => match item.data {
|
||||||
syn::Data::Struct(syn::DataStruct {
|
syn::Data::Struct(syn::DataStruct { ref fields, .. }) => match *fields {
|
||||||
fields: syn::Fields::Named(_),
|
syn::Fields::Named(_) => {
|
||||||
..
|
default.set(word, Default::Default);
|
||||||
}) => {
|
}
|
||||||
default.set(Default::Default);
|
syn::Fields::Unnamed(_) | syn::Fields::Unit => cx.error_spanned_by(
|
||||||
}
|
fields,
|
||||||
_ => cx.error(
|
"#[serde(default)] can only be used on structs \
|
||||||
|
with named fields",
|
||||||
|
)
|
||||||
|
},
|
||||||
|
syn::Data::Enum(syn::DataEnum { ref enum_token, .. }) => cx.error_spanned_by(
|
||||||
|
enum_token,
|
||||||
|
"#[serde(default)] can only be used on structs \
|
||||||
|
with named fields",
|
||||||
|
),
|
||||||
|
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => cx.error_spanned_by(
|
||||||
|
union_token,
|
||||||
"#[serde(default)] can only be used on structs \
|
"#[serde(default)] can only be used on structs \
|
||||||
with named fields",
|
with named fields",
|
||||||
),
|
),
|
||||||
@@ -254,13 +279,23 @@ 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 {
|
syn::Data::Struct(syn::DataStruct { ref fields, .. }) => match *fields {
|
||||||
fields: syn::Fields::Named(_),
|
syn::Fields::Named(_) => {
|
||||||
..
|
default.set(&m.ident, Default::Path(path));
|
||||||
}) => {
|
}
|
||||||
default.set(Default::Path(path));
|
syn::Fields::Unnamed(_) | syn::Fields::Unit => cx.error_spanned_by(
|
||||||
}
|
fields,
|
||||||
_ => cx.error(
|
"#[serde(default = \"...\")] can only be used \
|
||||||
|
on structs with named fields",
|
||||||
|
)
|
||||||
|
},
|
||||||
|
syn::Data::Enum(syn::DataEnum { ref enum_token, .. }) => cx.error_spanned_by(
|
||||||
|
enum_token,
|
||||||
|
"#[serde(default = \"...\")] can only be used \
|
||||||
|
on structs with named fields",
|
||||||
|
),
|
||||||
|
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => cx.error_spanned_by(
|
||||||
|
union_token,
|
||||||
"#[serde(default = \"...\")] can only be used \
|
"#[serde(default = \"...\")] can only be used \
|
||||||
on structs with named fields",
|
on structs with named fields",
|
||||||
),
|
),
|
||||||
@@ -273,26 +308,35 @@ impl Container {
|
|||||||
if let Ok(where_predicates) =
|
if let Ok(where_predicates) =
|
||||||
parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit)
|
parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit)
|
||||||
{
|
{
|
||||||
ser_bound.set(where_predicates.clone());
|
ser_bound.set(&m.ident, where_predicates.clone());
|
||||||
de_bound.set(where_predicates);
|
de_bound.set(&m.ident, where_predicates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(bound(serialize = "...", deserialize = "..."))]`
|
// Parse `#[serde(bound(serialize = "...", deserialize = "..."))]`
|
||||||
Meta(List(ref m)) if m.ident == "bound" => {
|
Meta(List(ref m)) if m.ident == "bound" => {
|
||||||
if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) {
|
if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) {
|
||||||
ser_bound.set_opt(ser);
|
ser_bound.set_opt(&m.ident, ser);
|
||||||
de_bound.set_opt(de);
|
de_bound.set_opt(&m.ident, de);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(untagged)]`
|
// Parse `#[serde(untagged)]`
|
||||||
Meta(Word(ref word)) if word == "untagged" => match item.data {
|
Meta(Word(ref word)) if word == "untagged" => match item.data {
|
||||||
syn::Data::Enum(_) => {
|
syn::Data::Enum(_) => {
|
||||||
untagged.set_true();
|
untagged.set_true(word);
|
||||||
}
|
}
|
||||||
syn::Data::Struct(_) | syn::Data::Union(_) => {
|
syn::Data::Struct(syn::DataStruct { ref struct_token, .. }) => {
|
||||||
cx.error("#[serde(untagged)] can only be used on enums")
|
cx.error_spanned_by(
|
||||||
|
struct_token,
|
||||||
|
"#[serde(untagged)] can only be used on enums",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => {
|
||||||
|
cx.error_spanned_by(
|
||||||
|
union_token,
|
||||||
|
"#[serde(untagged)] can only be used on enums",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -301,11 +345,20 @@ 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 item.data {
|
match item.data {
|
||||||
syn::Data::Enum(_) => {
|
syn::Data::Enum(_) => {
|
||||||
internal_tag.set(s.value());
|
internal_tag.set(&m.ident, s.value());
|
||||||
}
|
|
||||||
syn::Data::Struct(_) | syn::Data::Union(_) => {
|
|
||||||
cx.error("#[serde(tag = \"...\")] can only be used on enums")
|
|
||||||
}
|
}
|
||||||
|
syn::Data::Struct(syn::DataStruct { ref struct_token, .. }) => {
|
||||||
|
cx.error_spanned_by(
|
||||||
|
struct_token,
|
||||||
|
"#[serde(tag = \"...\")] can only be used on enums",
|
||||||
|
);
|
||||||
|
},
|
||||||
|
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => {
|
||||||
|
cx.error_spanned_by(
|
||||||
|
union_token,
|
||||||
|
"#[serde(tag = \"...\")] can only be used on enums",
|
||||||
|
);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -315,12 +368,20 @@ 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 item.data {
|
match item.data {
|
||||||
syn::Data::Enum(_) => {
|
syn::Data::Enum(_) => {
|
||||||
content.set(s.value());
|
content.set(&m.ident, s.value());
|
||||||
}
|
}
|
||||||
syn::Data::Struct(_) | syn::Data::Union(_) => cx.error(
|
syn::Data::Struct(syn::DataStruct { ref struct_token, .. }) => {
|
||||||
"#[serde(content = \"...\")] can only be used on \
|
cx.error_spanned_by(
|
||||||
enums",
|
struct_token,
|
||||||
),
|
"#[serde(content = \"...\")] can only be used on enums",
|
||||||
|
);
|
||||||
|
},
|
||||||
|
syn::Data::Union(syn::DataUnion { ref union_token, .. }) => {
|
||||||
|
cx.error_spanned_by(
|
||||||
|
union_token,
|
||||||
|
"#[serde(content = \"...\")] can only be used on enums",
|
||||||
|
);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -328,14 +389,14 @@ impl Container {
|
|||||||
// Parse `#[serde(from = "Type")]
|
// Parse `#[serde(from = "Type")]
|
||||||
Meta(NameValue(ref m)) if m.ident == "from" => {
|
Meta(NameValue(ref m)) if m.ident == "from" => {
|
||||||
if let Ok(from_ty) = parse_lit_into_ty(cx, &m.ident, &m.lit) {
|
if let Ok(from_ty) = parse_lit_into_ty(cx, &m.ident, &m.lit) {
|
||||||
type_from.set_opt(Some(from_ty));
|
type_from.set_opt(&m.ident, Some(from_ty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(into = "Type")]
|
// Parse `#[serde(into = "Type")]
|
||||||
Meta(NameValue(ref m)) if m.ident == "into" => {
|
Meta(NameValue(ref m)) if m.ident == "into" => {
|
||||||
if let Ok(into_ty) = parse_lit_into_ty(cx, &m.ident, &m.lit) {
|
if let Ok(into_ty) = parse_lit_into_ty(cx, &m.ident, &m.lit) {
|
||||||
type_into.set_opt(Some(into_ty));
|
type_into.set_opt(&m.ident, Some(into_ty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,32 +404,32 @@ impl Container {
|
|||||||
Meta(NameValue(ref m)) if m.ident == "remote" => {
|
Meta(NameValue(ref m)) if m.ident == "remote" => {
|
||||||
if let Ok(path) = parse_lit_into_path(cx, &m.ident, &m.lit) {
|
if let Ok(path) = parse_lit_into_path(cx, &m.ident, &m.lit) {
|
||||||
if is_primitive_path(&path, "Self") {
|
if is_primitive_path(&path, "Self") {
|
||||||
remote.set(item.ident.clone().into());
|
remote.set(&m.ident, item.ident.clone().into());
|
||||||
} else {
|
} else {
|
||||||
remote.set(path);
|
remote.set(&m.ident, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(field_identifier)]`
|
// Parse `#[serde(field_identifier)]`
|
||||||
Meta(Word(ref word)) if word == "field_identifier" => {
|
Meta(Word(ref word)) if word == "field_identifier" => {
|
||||||
field_identifier.set_true();
|
field_identifier.set_true(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(variant_identifier)]`
|
// Parse `#[serde(variant_identifier)]`
|
||||||
Meta(Word(ref word)) if word == "variant_identifier" => {
|
Meta(Word(ref word)) if word == "variant_identifier" => {
|
||||||
variant_identifier.set_true();
|
variant_identifier.set_true(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
Meta(ref meta_item) => {
|
Meta(ref meta_item) => {
|
||||||
cx.error(format!(
|
cx.error_spanned_by(meta_item.name(), format!(
|
||||||
"unknown serde container attribute `{}`",
|
"unknown serde container attribute `{}`",
|
||||||
meta_item.name()
|
meta_item.name()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal(_) => {
|
Literal(ref lit) => {
|
||||||
cx.error("unexpected literal in serde container attribute");
|
cx.error_spanned_by(lit, "unexpected literal in serde container attribute");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -385,11 +446,11 @@ impl Container {
|
|||||||
rename_all: rename_all.get().unwrap_or(RenameRule::None),
|
rename_all: rename_all.get().unwrap_or(RenameRule::None),
|
||||||
ser_bound: ser_bound.get(),
|
ser_bound: ser_bound.get(),
|
||||||
de_bound: de_bound.get(),
|
de_bound: de_bound.get(),
|
||||||
tag: decide_tag(cx, item, &untagged, internal_tag, content),
|
tag: decide_tag(cx, item, untagged, internal_tag, content),
|
||||||
type_from: type_from.get(),
|
type_from: type_from.get(),
|
||||||
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,
|
has_flatten: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -454,14 +515,14 @@ impl Container {
|
|||||||
fn decide_tag(
|
fn decide_tag(
|
||||||
cx: &Ctxt,
|
cx: &Ctxt,
|
||||||
item: &syn::DeriveInput,
|
item: &syn::DeriveInput,
|
||||||
untagged: &BoolAttr,
|
untagged: BoolAttr,
|
||||||
internal_tag: Attr<String>,
|
internal_tag: Attr<String>,
|
||||||
content: Attr<String>,
|
content: Attr<String>,
|
||||||
) -> EnumTag {
|
) -> EnumTag {
|
||||||
match (untagged.get(), internal_tag.get(), content.get()) {
|
match (untagged.0.get_with_tokens(), internal_tag.get_with_tokens(), content.get_with_tokens()) {
|
||||||
(false, None, None) => EnumTag::External,
|
(None, None, None) => EnumTag::External,
|
||||||
(true, None, None) => EnumTag::None,
|
(Some(_), None, None) => EnumTag::None,
|
||||||
(false, Some(tag), None) => {
|
(None, Some((_, tag)), None) => {
|
||||||
// Check that there are no tuple variants.
|
// Check that there are no tuple variants.
|
||||||
if let syn::Data::Enum(ref data) = item.data {
|
if let syn::Data::Enum(ref data) = item.data {
|
||||||
for variant in &data.variants {
|
for variant in &data.variants {
|
||||||
@@ -469,7 +530,8 @@ fn decide_tag(
|
|||||||
syn::Fields::Named(_) | syn::Fields::Unit => {}
|
syn::Fields::Named(_) | syn::Fields::Unit => {}
|
||||||
syn::Fields::Unnamed(ref fields) => {
|
syn::Fields::Unnamed(ref fields) => {
|
||||||
if fields.unnamed.len() != 1 {
|
if fields.unnamed.len() != 1 {
|
||||||
cx.error(
|
cx.error_spanned_by(
|
||||||
|
variant,
|
||||||
"#[serde(tag = \"...\")] cannot be used with tuple \
|
"#[serde(tag = \"...\")] cannot be used with tuple \
|
||||||
variants",
|
variants",
|
||||||
);
|
);
|
||||||
@@ -481,24 +543,52 @@ fn decide_tag(
|
|||||||
}
|
}
|
||||||
EnumTag::Internal { tag: tag }
|
EnumTag::Internal { tag: tag }
|
||||||
}
|
}
|
||||||
(true, Some(_), None) => {
|
(Some((untagged_tokens, _)), Some((tag_tokens, _)), None) => {
|
||||||
cx.error("enum cannot be both untagged and internally tagged");
|
cx.error_spanned_by(
|
||||||
|
untagged_tokens,
|
||||||
|
"enum cannot be both untagged and internally tagged",
|
||||||
|
);
|
||||||
|
cx.error_spanned_by(
|
||||||
|
tag_tokens,
|
||||||
|
"enum cannot be both untagged and internally tagged",
|
||||||
|
);
|
||||||
EnumTag::External // doesn't matter, will error
|
EnumTag::External // doesn't matter, will error
|
||||||
}
|
}
|
||||||
(false, None, Some(_)) => {
|
(None, None, Some((content_tokens, _))) => {
|
||||||
cx.error("#[serde(tag = \"...\", content = \"...\")] must be used together");
|
cx.error_spanned_by(
|
||||||
|
content_tokens,
|
||||||
|
"#[serde(tag = \"...\", content = \"...\")] must be used together",
|
||||||
|
);
|
||||||
EnumTag::External
|
EnumTag::External
|
||||||
}
|
}
|
||||||
(true, None, Some(_)) => {
|
(Some((untagged_tokens, _)), None, Some((content_tokens, _))) => {
|
||||||
cx.error("untagged enum cannot have #[serde(content = \"...\")]");
|
cx.error_spanned_by(
|
||||||
|
untagged_tokens,
|
||||||
|
"untagged enum cannot have #[serde(content = \"...\")]",
|
||||||
|
);
|
||||||
|
cx.error_spanned_by(
|
||||||
|
content_tokens,
|
||||||
|
"untagged enum cannot have #[serde(content = \"...\")]",
|
||||||
|
);
|
||||||
EnumTag::External
|
EnumTag::External
|
||||||
}
|
}
|
||||||
(false, Some(tag), Some(content)) => EnumTag::Adjacent {
|
(None, Some((_, tag)), Some((_, content))) => EnumTag::Adjacent {
|
||||||
tag: tag,
|
tag: tag,
|
||||||
content: content,
|
content: content,
|
||||||
},
|
},
|
||||||
(true, Some(_), Some(_)) => {
|
(Some((untagged_tokens, _)), Some((tag_tokens, _)), Some((content_tokens, _))) => {
|
||||||
cx.error("untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]");
|
cx.error_spanned_by(
|
||||||
|
untagged_tokens,
|
||||||
|
"untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]",
|
||||||
|
);
|
||||||
|
cx.error_spanned_by(
|
||||||
|
tag_tokens,
|
||||||
|
"untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]",
|
||||||
|
);
|
||||||
|
cx.error_spanned_by(
|
||||||
|
content_tokens,
|
||||||
|
"untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]",
|
||||||
|
);
|
||||||
EnumTag::External
|
EnumTag::External
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -507,23 +597,50 @@ fn decide_tag(
|
|||||||
fn decide_identifier(
|
fn decide_identifier(
|
||||||
cx: &Ctxt,
|
cx: &Ctxt,
|
||||||
item: &syn::DeriveInput,
|
item: &syn::DeriveInput,
|
||||||
field_identifier: &BoolAttr,
|
field_identifier: BoolAttr,
|
||||||
variant_identifier: &BoolAttr,
|
variant_identifier: BoolAttr,
|
||||||
) -> Identifier {
|
) -> Identifier {
|
||||||
match (&item.data, field_identifier.get(), variant_identifier.get()) {
|
match (&item.data, field_identifier.0.get_with_tokens(), variant_identifier.0.get_with_tokens()) {
|
||||||
(_, false, false) => Identifier::No,
|
(_, None, None) => Identifier::No,
|
||||||
(_, true, true) => {
|
(_, Some((field_identifier_tokens, _)), Some((variant_identifier_tokens, _))) => {
|
||||||
cx.error("`field_identifier` and `variant_identifier` cannot both be set");
|
cx.error_spanned_by(
|
||||||
|
field_identifier_tokens,
|
||||||
|
"#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set",
|
||||||
|
);
|
||||||
|
cx.error_spanned_by(
|
||||||
|
variant_identifier_tokens,
|
||||||
|
"#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set",
|
||||||
|
);
|
||||||
Identifier::No
|
Identifier::No
|
||||||
}
|
}
|
||||||
(&syn::Data::Enum(_), true, false) => Identifier::Field,
|
(&syn::Data::Enum(_), Some(_), None) => Identifier::Field,
|
||||||
(&syn::Data::Enum(_), false, true) => Identifier::Variant,
|
(&syn::Data::Enum(_), None, Some(_)) => Identifier::Variant,
|
||||||
(&syn::Data::Struct(_), true, false) | (&syn::Data::Union(_), true, false) => {
|
(&syn::Data::Struct(syn::DataStruct { ref struct_token, .. }), Some(_), None) => {
|
||||||
cx.error("`field_identifier` can only be used on an enum");
|
cx.error_spanned_by(
|
||||||
|
struct_token,
|
||||||
|
"#[serde(field_identifier)] can only be used on an enum",
|
||||||
|
);
|
||||||
Identifier::No
|
Identifier::No
|
||||||
}
|
}
|
||||||
(&syn::Data::Struct(_), false, true) | (&syn::Data::Union(_), false, true) => {
|
(&syn::Data::Union(syn::DataUnion { ref union_token, .. }), Some(_), None) => {
|
||||||
cx.error("`variant_identifier` can only be used on an enum");
|
cx.error_spanned_by(
|
||||||
|
union_token,
|
||||||
|
"#[serde(field_identifier)] can only be used on an enum",
|
||||||
|
);
|
||||||
|
Identifier::No
|
||||||
|
}
|
||||||
|
(&syn::Data::Struct(syn::DataStruct { ref struct_token, .. }), None, Some(_)) => {
|
||||||
|
cx.error_spanned_by(
|
||||||
|
struct_token,
|
||||||
|
"#[serde(variant_identifier)] can only be used on an enum",
|
||||||
|
);
|
||||||
|
Identifier::No
|
||||||
|
}
|
||||||
|
(&syn::Data::Union(syn::DataUnion { ref union_token, .. }), None, Some(_)) => {
|
||||||
|
cx.error_spanned_by(
|
||||||
|
union_token,
|
||||||
|
"#[serde(variant_identifier)] can only be used on an enum",
|
||||||
|
);
|
||||||
Identifier::No
|
Identifier::No
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -565,16 +682,16 @@ impl Variant {
|
|||||||
// Parse `#[serde(rename = "foo")]`
|
// Parse `#[serde(rename = "foo")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "rename" => {
|
Meta(NameValue(ref m)) if m.ident == "rename" => {
|
||||||
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) {
|
||||||
ser_name.set(s.value());
|
ser_name.set(&m.ident, s.value());
|
||||||
de_name.set(s.value());
|
de_name.set(&m.ident, s.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
|
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
|
||||||
Meta(List(ref m)) if m.ident == "rename" => {
|
Meta(List(ref m)) if m.ident == "rename" => {
|
||||||
if let Ok((ser, de)) = get_renames(cx, &m.nested) {
|
if let Ok((ser, de)) = get_renames(cx, &m.nested) {
|
||||||
ser_name.set_opt(ser.map(syn::LitStr::value));
|
ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value));
|
||||||
de_name.set_opt(de.map(syn::LitStr::value));
|
de_name.set_opt(&m.ident, de.map(syn::LitStr::value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -582,8 +699,8 @@ impl Variant {
|
|||||||
Meta(NameValue(ref m)) if m.ident == "rename_all" => {
|
Meta(NameValue(ref m)) if m.ident == "rename_all" => {
|
||||||
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(rename_rule),
|
Ok(rename_rule) => rename_all.set(&m.ident, rename_rule),
|
||||||
Err(()) => cx.error(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()
|
||||||
@@ -594,23 +711,23 @@ impl Variant {
|
|||||||
|
|
||||||
// Parse `#[serde(skip)]`
|
// Parse `#[serde(skip)]`
|
||||||
Meta(Word(ref word)) if word == "skip" => {
|
Meta(Word(ref word)) if word == "skip" => {
|
||||||
skip_serializing.set_true();
|
skip_serializing.set_true(word);
|
||||||
skip_deserializing.set_true();
|
skip_deserializing.set_true(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(skip_deserializing)]`
|
// Parse `#[serde(skip_deserializing)]`
|
||||||
Meta(Word(ref word)) if word == "skip_deserializing" => {
|
Meta(Word(ref word)) if word == "skip_deserializing" => {
|
||||||
skip_deserializing.set_true();
|
skip_deserializing.set_true(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(skip_serializing)]`
|
// Parse `#[serde(skip_serializing)]`
|
||||||
Meta(Word(ref word)) if word == "skip_serializing" => {
|
Meta(Word(ref word)) if word == "skip_serializing" => {
|
||||||
skip_serializing.set_true();
|
skip_serializing.set_true(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(other)]`
|
// Parse `#[serde(other)]`
|
||||||
Meta(Word(ref word)) if word == "other" => {
|
Meta(Word(ref word)) if word == "other" => {
|
||||||
other.set_true();
|
other.set_true(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(bound = "T: SomeBound")]`
|
// Parse `#[serde(bound = "T: SomeBound")]`
|
||||||
@@ -618,16 +735,16 @@ impl Variant {
|
|||||||
if let Ok(where_predicates) =
|
if let Ok(where_predicates) =
|
||||||
parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit)
|
parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit)
|
||||||
{
|
{
|
||||||
ser_bound.set(where_predicates.clone());
|
ser_bound.set(&m.ident, where_predicates.clone());
|
||||||
de_bound.set(where_predicates);
|
de_bound.set(&m.ident, where_predicates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(bound(serialize = "...", deserialize = "..."))]`
|
// Parse `#[serde(bound(serialize = "...", deserialize = "..."))]`
|
||||||
Meta(List(ref m)) if m.ident == "bound" => {
|
Meta(List(ref m)) if m.ident == "bound" => {
|
||||||
if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) {
|
if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) {
|
||||||
ser_bound.set_opt(ser);
|
ser_bound.set_opt(&m.ident, ser);
|
||||||
de_bound.set_opt(de);
|
de_bound.set_opt(&m.ident, de);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,49 +756,55 @@ impl Variant {
|
|||||||
.path
|
.path
|
||||||
.segments
|
.segments
|
||||||
.push(Ident::new("serialize", Span::call_site()).into());
|
.push(Ident::new("serialize", Span::call_site()).into());
|
||||||
serialize_with.set(ser_path);
|
serialize_with.set(&m.ident, ser_path);
|
||||||
let mut de_path = path;
|
let mut de_path = path;
|
||||||
de_path
|
de_path
|
||||||
.path
|
.path
|
||||||
.segments
|
.segments
|
||||||
.push(Ident::new("deserialize", Span::call_site()).into());
|
.push(Ident::new("deserialize", Span::call_site()).into());
|
||||||
deserialize_with.set(de_path);
|
deserialize_with.set(&m.ident, de_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(serialize_with = "...")]`
|
// Parse `#[serde(serialize_with = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "serialize_with" => {
|
Meta(NameValue(ref m)) if m.ident == "serialize_with" => {
|
||||||
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) {
|
||||||
serialize_with.set(path);
|
serialize_with.set(&m.ident, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(deserialize_with = "...")]`
|
// Parse `#[serde(deserialize_with = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "deserialize_with" => {
|
Meta(NameValue(ref m)) if m.ident == "deserialize_with" => {
|
||||||
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) {
|
||||||
deserialize_with.set(path);
|
deserialize_with.set(&m.ident, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]`
|
// Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]`
|
||||||
Meta(ref m) if m.name() == "borrow" => match variant.fields {
|
Meta(ref m) if m.name() == "borrow" => match variant.fields {
|
||||||
syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => {
|
syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => {
|
||||||
borrow.set(m.clone());
|
borrow.set(m.name(), m.clone());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
cx.error("#[serde(borrow)] may only be used on newtype variants");
|
cx.error_spanned_by(
|
||||||
|
variant,
|
||||||
|
"#[serde(borrow)] may only be used on newtype variants",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Meta(ref meta_item) => {
|
Meta(ref meta_item) => {
|
||||||
cx.error(format!(
|
cx.error_spanned_by(meta_item.name(), format!(
|
||||||
"unknown serde variant attribute `{}`",
|
"unknown serde variant attribute `{}`",
|
||||||
meta_item.name()
|
meta_item.name()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal(_) => {
|
Literal(ref lit) => {
|
||||||
cx.error("unexpected literal in serde variant attribute");
|
cx.error_spanned_by(
|
||||||
|
lit,
|
||||||
|
"unexpected literal in serde variant attribute",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -837,65 +960,65 @@ impl Field {
|
|||||||
// Parse `#[serde(rename = "foo")]`
|
// Parse `#[serde(rename = "foo")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "rename" => {
|
Meta(NameValue(ref m)) if m.ident == "rename" => {
|
||||||
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) {
|
||||||
ser_name.set(s.value());
|
ser_name.set(&m.ident, s.value());
|
||||||
de_name.set(s.value());
|
de_name.set(&m.ident, s.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
|
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
|
||||||
Meta(List(ref m)) if m.ident == "rename" => {
|
Meta(List(ref m)) if m.ident == "rename" => {
|
||||||
if let Ok((ser, de)) = get_renames(cx, &m.nested) {
|
if let Ok((ser, de)) = get_renames(cx, &m.nested) {
|
||||||
ser_name.set_opt(ser.map(syn::LitStr::value));
|
ser_name.set_opt(&m.ident, ser.map(syn::LitStr::value));
|
||||||
de_name.set_opt(de.map(syn::LitStr::value));
|
de_name.set_opt(&m.ident, de.map(syn::LitStr::value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(default)]`
|
// Parse `#[serde(default)]`
|
||||||
Meta(Word(ref word)) if word == "default" => {
|
Meta(Word(ref word)) if word == "default" => {
|
||||||
default.set(Default::Default);
|
default.set(word, Default::Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(default = "...")]`
|
// Parse `#[serde(default = "...")]`
|
||||||
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) {
|
||||||
default.set(Default::Path(path));
|
default.set(&m.ident, Default::Path(path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(skip_serializing)]`
|
// Parse `#[serde(skip_serializing)]`
|
||||||
Meta(Word(ref word)) if word == "skip_serializing" => {
|
Meta(Word(ref word)) if word == "skip_serializing" => {
|
||||||
skip_serializing.set_true();
|
skip_serializing.set_true(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(skip_deserializing)]`
|
// Parse `#[serde(skip_deserializing)]`
|
||||||
Meta(Word(ref word)) if word == "skip_deserializing" => {
|
Meta(Word(ref word)) if word == "skip_deserializing" => {
|
||||||
skip_deserializing.set_true();
|
skip_deserializing.set_true(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(skip)]`
|
// Parse `#[serde(skip)]`
|
||||||
Meta(Word(ref word)) if word == "skip" => {
|
Meta(Word(ref word)) if word == "skip" => {
|
||||||
skip_serializing.set_true();
|
skip_serializing.set_true(word);
|
||||||
skip_deserializing.set_true();
|
skip_deserializing.set_true(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(skip_serializing_if = "...")]`
|
// Parse `#[serde(skip_serializing_if = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "skip_serializing_if" => {
|
Meta(NameValue(ref m)) if m.ident == "skip_serializing_if" => {
|
||||||
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) {
|
||||||
skip_serializing_if.set(path);
|
skip_serializing_if.set(&m.ident, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(serialize_with = "...")]`
|
// Parse `#[serde(serialize_with = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "serialize_with" => {
|
Meta(NameValue(ref m)) if m.ident == "serialize_with" => {
|
||||||
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) {
|
||||||
serialize_with.set(path);
|
serialize_with.set(&m.ident, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(deserialize_with = "...")]`
|
// Parse `#[serde(deserialize_with = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "deserialize_with" => {
|
Meta(NameValue(ref m)) if m.ident == "deserialize_with" => {
|
||||||
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) {
|
||||||
deserialize_with.set(path);
|
deserialize_with.set(&m.ident, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -907,13 +1030,13 @@ impl Field {
|
|||||||
.path
|
.path
|
||||||
.segments
|
.segments
|
||||||
.push(Ident::new("serialize", Span::call_site()).into());
|
.push(Ident::new("serialize", Span::call_site()).into());
|
||||||
serialize_with.set(ser_path);
|
serialize_with.set(&m.ident, ser_path);
|
||||||
let mut de_path = path;
|
let mut de_path = path;
|
||||||
de_path
|
de_path
|
||||||
.path
|
.path
|
||||||
.segments
|
.segments
|
||||||
.push(Ident::new("deserialize", Span::call_site()).into());
|
.push(Ident::new("deserialize", Span::call_site()).into());
|
||||||
deserialize_with.set(de_path);
|
deserialize_with.set(&m.ident, de_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -922,39 +1045,39 @@ impl Field {
|
|||||||
if let Ok(where_predicates) =
|
if let Ok(where_predicates) =
|
||||||
parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit)
|
parse_lit_into_where(cx, &m.ident, &m.ident, &m.lit)
|
||||||
{
|
{
|
||||||
ser_bound.set(where_predicates.clone());
|
ser_bound.set(&m.ident, where_predicates.clone());
|
||||||
de_bound.set(where_predicates);
|
de_bound.set(&m.ident, where_predicates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(bound(serialize = "...", deserialize = "..."))]`
|
// Parse `#[serde(bound(serialize = "...", deserialize = "..."))]`
|
||||||
Meta(List(ref m)) if m.ident == "bound" => {
|
Meta(List(ref m)) if m.ident == "bound" => {
|
||||||
if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) {
|
if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) {
|
||||||
ser_bound.set_opt(ser);
|
ser_bound.set_opt(&m.ident, ser);
|
||||||
de_bound.set_opt(de);
|
de_bound.set_opt(&m.ident, de);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(borrow)]`
|
// Parse `#[serde(borrow)]`
|
||||||
Meta(Word(ref word)) if word == "borrow" => {
|
Meta(Word(ref word)) if word == "borrow" => {
|
||||||
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) {
|
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) {
|
||||||
borrowed_lifetimes.set(borrowable);
|
borrowed_lifetimes.set(word, borrowable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(borrow = "'a + 'b")]`
|
// Parse `#[serde(borrow = "'a + 'b")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "borrow" => {
|
Meta(NameValue(ref m)) if m.ident == "borrow" => {
|
||||||
if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, &m.ident, &m.lit) {
|
if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, &m.ident, &m.lit) {
|
||||||
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) {
|
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(format!(
|
cx.error_spanned_by(field, format!(
|
||||||
"field `{}` does not have lifetime {}",
|
"field `{}` does not have lifetime {}",
|
||||||
ident, lifetime
|
ident, lifetime
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
borrowed_lifetimes.set(lifetimes);
|
borrowed_lifetimes.set(&m.ident, lifetimes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -962,24 +1085,27 @@ impl Field {
|
|||||||
// Parse `#[serde(getter = "...")]`
|
// Parse `#[serde(getter = "...")]`
|
||||||
Meta(NameValue(ref m)) if m.ident == "getter" => {
|
Meta(NameValue(ref m)) if m.ident == "getter" => {
|
||||||
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) {
|
||||||
getter.set(path);
|
getter.set(&m.ident, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse `#[serde(flatten)]`
|
// Parse `#[serde(flatten)]`
|
||||||
Meta(Word(ref word)) if word == "flatten" => {
|
Meta(Word(ref word)) if word == "flatten" => {
|
||||||
flatten.set_true();
|
flatten.set_true(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
Meta(ref meta_item) => {
|
Meta(ref meta_item) => {
|
||||||
cx.error(format!(
|
cx.error_spanned_by(meta_item.name(), format!(
|
||||||
"unknown serde field attribute `{}`",
|
"unknown serde field attribute `{}`",
|
||||||
meta_item.name()
|
meta_item.name()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Literal(_) => {
|
Literal(ref lit) => {
|
||||||
cx.error("unexpected literal in serde field attribute");
|
cx.error_spanned_by(
|
||||||
|
lit,
|
||||||
|
"unexpected literal in serde field attribute",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1162,18 +1288,18 @@ where
|
|||||||
match *meta {
|
match *meta {
|
||||||
Meta(NameValue(ref meta)) if meta.ident == "serialize" => {
|
Meta(NameValue(ref meta)) if meta.ident == "serialize" => {
|
||||||
if let Ok(v) = f(cx, &attr_name, &meta.ident, &meta.lit) {
|
if let Ok(v) = f(cx, &attr_name, &meta.ident, &meta.lit) {
|
||||||
ser_meta.set(v);
|
ser_meta.set(&meta.ident, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Meta(NameValue(ref meta)) if meta.ident == "deserialize" => {
|
Meta(NameValue(ref meta)) if meta.ident == "deserialize" => {
|
||||||
if let Ok(v) = f(cx, &attr_name, &meta.ident, &meta.lit) {
|
if let Ok(v) = f(cx, &attr_name, &meta.ident, &meta.lit) {
|
||||||
de_meta.set(v);
|
de_meta.set(&meta.ident, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
cx.error(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
|
||||||
@@ -1223,7 +1349,7 @@ 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(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
|
||||||
));
|
));
|
||||||
@@ -1234,7 +1360,10 @@ fn get_lit_str<'a>(
|
|||||||
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(|_| cx.error(format!("failed to parse path: {:?}", string.value())))
|
.map_err(|_| cx.error_spanned_by(
|
||||||
|
lit,
|
||||||
|
format!("failed to parse path: {:?}", string.value()),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_lit_into_expr_path(
|
fn parse_lit_into_expr_path(
|
||||||
@@ -1244,7 +1373,10 @@ fn parse_lit_into_expr_path(
|
|||||||
) -> 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(|_| cx.error(format!("failed to parse path: {:?}", string.value())))
|
.map_err(|_| cx.error_spanned_by(
|
||||||
|
lit,
|
||||||
|
format!("failed to parse path: {:?}", string.value()),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_lit_into_where(
|
fn parse_lit_into_where(
|
||||||
@@ -1262,14 +1394,14 @@ fn parse_lit_into_where(
|
|||||||
|
|
||||||
parse_lit_str::<syn::WhereClause>(&where_string)
|
parse_lit_str::<syn::WhereClause>(&where_string)
|
||||||
.map(|wh| wh.predicates.into_iter().collect())
|
.map(|wh| wh.predicates.into_iter().collect())
|
||||||
.map_err(|err| cx.error(err))
|
.map_err(|err| cx.error_spanned_by(lit, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_lit_into_ty(cx: &Ctxt, attr_name: &Ident, lit: &syn::Lit) -> Result<syn::Type, ()> {
|
fn parse_lit_into_ty(cx: &Ctxt, attr_name: &Ident, lit: &syn::Lit) -> Result<syn::Type, ()> {
|
||||||
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(format!(
|
cx.error_spanned_by(lit, format!(
|
||||||
"failed to parse type: {} = {:?}",
|
"failed to parse type: {} = {:?}",
|
||||||
attr_name,
|
attr_name,
|
||||||
string.value()
|
string.value()
|
||||||
@@ -1286,7 +1418,7 @@ fn parse_lit_into_lifetimes(
|
|||||||
) -> Result<BTreeSet<syn::Lifetime>, ()> {
|
) -> Result<BTreeSet<syn::Lifetime>, ()> {
|
||||||
let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
|
let string = try!(get_lit_str(cx, attr_name, attr_name, lit));
|
||||||
if string.value().is_empty() {
|
if string.value().is_empty() {
|
||||||
cx.error("at least one lifetime must be borrowed");
|
cx.error_spanned_by(lit, "at least one lifetime must be borrowed");
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1302,13 +1434,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(format!("duplicate borrowed lifetime `{}`", lifetime));
|
cx.error_spanned_by(
|
||||||
|
lit,
|
||||||
|
format!("duplicate borrowed lifetime `{}`", lifetime),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(set);
|
return Ok(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.error(format!(
|
cx.error_spanned_by(lit, format!(
|
||||||
"failed to parse borrowed lifetimes: {:?}",
|
"failed to parse borrowed lifetimes: {:?}",
|
||||||
string.value()
|
string.value()
|
||||||
));
|
));
|
||||||
@@ -1461,12 +1596,15 @@ fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool {
|
|||||||
fn borrowable_lifetimes(
|
fn borrowable_lifetimes(
|
||||||
cx: &Ctxt,
|
cx: &Ctxt,
|
||||||
name: &str,
|
name: &str,
|
||||||
ty: &syn::Type,
|
field: &syn::Field,
|
||||||
) -> Result<BTreeSet<syn::Lifetime>, ()> {
|
) -> Result<BTreeSet<syn::Lifetime>, ()> {
|
||||||
let mut lifetimes = BTreeSet::new();
|
let mut lifetimes = BTreeSet::new();
|
||||||
collect_lifetimes(ty, &mut lifetimes);
|
collect_lifetimes(&field.ty, &mut lifetimes);
|
||||||
if lifetimes.is_empty() {
|
if lifetimes.is_empty() {
|
||||||
cx.error(format!("field `{}` has no lifetimes to borrow", name));
|
cx.error_spanned_by(
|
||||||
|
field,
|
||||||
|
format!("field `{}` has no lifetimes to borrow", name),
|
||||||
|
);
|
||||||
Err(())
|
Err(())
|
||||||
} else {
|
} else {
|
||||||
Ok(lifetimes)
|
Ok(lifetimes)
|
||||||
|
|||||||
@@ -21,12 +21,16 @@ fn check_getter(cx: &Ctxt, cont: &Container) {
|
|||||||
match cont.data {
|
match cont.data {
|
||||||
Data::Enum(_) => {
|
Data::Enum(_) => {
|
||||||
if cont.data.has_getter() {
|
if cont.data.has_getter() {
|
||||||
cx.error("#[serde(getter = \"...\")] is not allowed in an enum");
|
cx.error_spanned_by(
|
||||||
|
cont.original,
|
||||||
|
"#[serde(getter = \"...\")] is not allowed in an enum",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Data::Struct(_, _) => {
|
Data::Struct(_, _) => {
|
||||||
if cont.data.has_getter() && cont.attrs.remote().is_none() {
|
if cont.data.has_getter() && cont.attrs.remote().is_none() {
|
||||||
cx.error(
|
cx.error_spanned_by(
|
||||||
|
cont.original,
|
||||||
"#[serde(getter = \"...\")] can only be used in structs \
|
"#[serde(getter = \"...\")] can only be used in structs \
|
||||||
that have #[serde(remote = \"...\")]",
|
that have #[serde(remote = \"...\")]",
|
||||||
);
|
);
|
||||||
@@ -59,26 +63,35 @@ fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) {
|
|||||||
}
|
}
|
||||||
match style {
|
match style {
|
||||||
Style::Tuple => {
|
Style::Tuple => {
|
||||||
cx.error("#[serde(flatten)] cannot be used on tuple structs");
|
cx.error_spanned_by(
|
||||||
|
field.original,
|
||||||
|
"#[serde(flatten)] cannot be used on tuple structs",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Style::Newtype => {
|
Style::Newtype => {
|
||||||
cx.error("#[serde(flatten)] cannot be used on newtype structs");
|
cx.error_spanned_by(
|
||||||
|
field.original,
|
||||||
|
"#[serde(flatten)] cannot be used on newtype structs",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
if field.attrs.skip_serializing() {
|
if field.attrs.skip_serializing() {
|
||||||
cx.error(
|
cx.error_spanned_by(
|
||||||
"#[serde(flatten] can not be combined with \
|
field.original,
|
||||||
|
"#[serde(flatten)] can not be combined with \
|
||||||
#[serde(skip_serializing)]",
|
#[serde(skip_serializing)]",
|
||||||
);
|
);
|
||||||
} else if field.attrs.skip_serializing_if().is_some() {
|
} else if field.attrs.skip_serializing_if().is_some() {
|
||||||
cx.error(
|
cx.error_spanned_by(
|
||||||
"#[serde(flatten] can not be combined with \
|
field.original,
|
||||||
|
"#[serde(flatten)] can not be combined with \
|
||||||
#[serde(skip_serializing_if = \"...\")]",
|
#[serde(skip_serializing_if = \"...\")]",
|
||||||
);
|
);
|
||||||
} else if field.attrs.skip_deserializing() {
|
} else if field.attrs.skip_deserializing() {
|
||||||
cx.error(
|
cx.error_spanned_by(
|
||||||
"#[serde(flatten] can not be combined with \
|
field.original,
|
||||||
|
"#[serde(flatten)] can not be combined with \
|
||||||
#[serde(skip_deserializing)]",
|
#[serde(skip_deserializing)]",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -107,24 +120,36 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
|
|||||||
) {
|
) {
|
||||||
// The `other` attribute may not be used in a variant_identifier.
|
// The `other` attribute may not be used in a variant_identifier.
|
||||||
(_, Identifier::Variant, true, _) => {
|
(_, Identifier::Variant, true, _) => {
|
||||||
cx.error("#[serde(other)] may not be used on a variant_identifier");
|
cx.error_spanned_by(
|
||||||
|
variant.original,
|
||||||
|
"#[serde(other)] may not be used on a variant identifier",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variant with `other` attribute cannot appear in untagged enum
|
// Variant with `other` attribute cannot appear in untagged enum
|
||||||
(_, Identifier::No, true, &EnumTag::None) => {
|
(_, Identifier::No, true, &EnumTag::None) => {
|
||||||
cx.error("#[serde(other)] cannot appear on untagged enum");
|
cx.error_spanned_by(
|
||||||
|
variant.original,
|
||||||
|
"#[serde(other)] cannot appear on untagged enum",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variant with `other` attribute must be the last one.
|
// Variant with `other` attribute must be the last one.
|
||||||
(Style::Unit, Identifier::Field, true, _) | (Style::Unit, Identifier::No, true, _) => {
|
(Style::Unit, Identifier::Field, true, _) | (Style::Unit, Identifier::No, true, _) => {
|
||||||
if i < variants.len() - 1 {
|
if i < variants.len() - 1 {
|
||||||
cx.error("#[serde(other)] must be the last variant");
|
cx.error_spanned_by(
|
||||||
|
variant.original,
|
||||||
|
"#[serde(other)] must be on the last variant",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variant with `other` attribute must be a unit variant.
|
// Variant with `other` attribute must be a unit variant.
|
||||||
(_, Identifier::Field, true, _) | (_, Identifier::No, true, _) => {
|
(_, Identifier::Field, true, _) | (_, Identifier::No, true, _) => {
|
||||||
cx.error("#[serde(other)] must be on a unit variant");
|
cx.error_spanned_by(
|
||||||
|
variant.original,
|
||||||
|
"#[serde(other)] must be on a unit variant",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any sort of variant is allowed if this is not an identifier.
|
// Any sort of variant is allowed if this is not an identifier.
|
||||||
@@ -136,16 +161,25 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
|
|||||||
// The last field is allowed to be a newtype catch-all.
|
// The last field is allowed to be a newtype catch-all.
|
||||||
(Style::Newtype, Identifier::Field, false, _) => {
|
(Style::Newtype, Identifier::Field, false, _) => {
|
||||||
if i < variants.len() - 1 {
|
if i < variants.len() - 1 {
|
||||||
cx.error(format!("`{}` must be the last variant", variant.ident));
|
cx.error_spanned_by(
|
||||||
|
variant.original,
|
||||||
|
format!("`{}` must be the last variant", variant.ident),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, Identifier::Field, false, _) => {
|
(_, Identifier::Field, false, _) => {
|
||||||
cx.error("field_identifier may only contain unit variants");
|
cx.error_spanned_by(
|
||||||
|
variant.original,
|
||||||
|
"#[serde(field_identifier)] may only contain unit variants",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
(_, Identifier::Variant, false, _) => {
|
(_, Identifier::Variant, false, _) => {
|
||||||
cx.error("variant_identifier may only contain unit variants");
|
cx.error_spanned_by(
|
||||||
|
variant.original,
|
||||||
|
"#[serde(variant_identifier)] may only contain unit variants",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,7 +198,7 @@ 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(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
|
||||||
@@ -175,7 +209,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
|
|||||||
let member = member_message(&field.member);
|
let member = member_message(&field.member);
|
||||||
|
|
||||||
if field.attrs.skip_serializing() {
|
if field.attrs.skip_serializing() {
|
||||||
cx.error(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
|
||||||
@@ -183,7 +217,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if field.attrs.skip_serializing_if().is_some() {
|
if field.attrs.skip_serializing_if().is_some() {
|
||||||
cx.error(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
|
||||||
@@ -194,7 +228,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
|
|||||||
|
|
||||||
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(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
|
||||||
@@ -205,7 +239,7 @@ fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
|
|||||||
if field.attrs.skip_deserializing() {
|
if field.attrs.skip_deserializing() {
|
||||||
let member = member_message(&field.member);
|
let member = member_message(&field.member);
|
||||||
|
|
||||||
cx.error(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
|
||||||
@@ -231,10 +265,10 @@ 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 = || {
|
let diagnose_conflict = || cx.error_spanned_by(
|
||||||
let message = format!("variant field name `{}` conflicts with internal tag", tag);
|
cont.original,
|
||||||
cx.error(message);
|
format!("variant field name `{}` conflicts with internal tag", tag),
|
||||||
};
|
);
|
||||||
|
|
||||||
for variant in variants {
|
for variant in variants {
|
||||||
match variant.style {
|
match variant.style {
|
||||||
@@ -269,11 +303,10 @@ fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if type_tag == content_tag {
|
if type_tag == content_tag {
|
||||||
let message = 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
|
||||||
);
|
));
|
||||||
cx.error(message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,20 +317,32 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cont.attrs.type_from().is_some() {
|
if cont.attrs.type_from().is_some() {
|
||||||
cx.error("#[serde(transparent)] is not allowed with #[serde(from = \"...\")]");
|
cx.error_spanned_by(
|
||||||
|
cont.original,
|
||||||
|
"#[serde(transparent)] is not allowed with #[serde(from = \"...\")]",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if cont.attrs.type_into().is_some() {
|
if cont.attrs.type_into().is_some() {
|
||||||
cx.error("#[serde(transparent)] is not allowed with #[serde(into = \"...\")]");
|
cx.error_spanned_by(
|
||||||
|
cont.original,
|
||||||
|
"#[serde(transparent)] is not allowed with #[serde(into = \"...\")]",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let fields = match cont.data {
|
let fields = match cont.data {
|
||||||
Data::Enum(_) => {
|
Data::Enum(_) => {
|
||||||
cx.error("#[serde(transparent)] is not allowed on an enum");
|
cx.error_spanned_by(
|
||||||
|
cont.original,
|
||||||
|
"#[serde(transparent)] is not allowed on an enum",
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Data::Struct(Style::Unit, _) => {
|
Data::Struct(Style::Unit, _) => {
|
||||||
cx.error("#[serde(transparent)] is not allowed on a unit struct");
|
cx.error_spanned_by(
|
||||||
|
cont.original,
|
||||||
|
"#[serde(transparent)] is not allowed on a unit struct",
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Data::Struct(_, ref mut fields) => fields,
|
Data::Struct(_, ref mut fields) => fields,
|
||||||
@@ -308,7 +353,8 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
|||||||
for field in fields {
|
for field in fields {
|
||||||
if allow_transparent(field, derive) {
|
if allow_transparent(field, derive) {
|
||||||
if transparent_field.is_some() {
|
if transparent_field.is_some() {
|
||||||
cx.error(
|
cx.error_spanned_by(
|
||||||
|
cont.original,
|
||||||
"#[serde(transparent)] requires struct to have at most one transparent field",
|
"#[serde(transparent)] requires struct to have at most one transparent field",
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@@ -321,10 +367,16 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
|||||||
Some(transparent_field) => transparent_field.attrs.mark_transparent(),
|
Some(transparent_field) => transparent_field.attrs.mark_transparent(),
|
||||||
None => match derive {
|
None => match derive {
|
||||||
Derive::Serialize => {
|
Derive::Serialize => {
|
||||||
cx.error("#[serde(transparent)] requires at least one field that is not skipped");
|
cx.error_spanned_by(
|
||||||
|
cont.original,
|
||||||
|
"#[serde(transparent)] requires at least one field that is not skipped",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Derive::Deserialize => {
|
Derive::Deserialize => {
|
||||||
cx.error("#[serde(transparent)] requires at least one field that is neither skipped nor has a default");
|
cx.error_spanned_by(
|
||||||
|
cont.original,
|
||||||
|
"#[serde(transparent)] requires at least one field that is neither skipped nor has a default",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -333,7 +385,7 @@ fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) {
|
|||||||
fn member_message(member: &Member) -> String {
|
fn member_message(member: &Member) -> String {
|
||||||
match *member {
|
match *member {
|
||||||
Member::Named(ref ident) => format!("`{}`", ident),
|
Member::Named(ref ident) => format!("`{}`", ident),
|
||||||
Member::Unnamed(ref i) => i.index.to_string(),
|
Member::Unnamed(ref i) => format!("#{}", i.index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
use quote::ToTokens;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use syn;
|
||||||
|
|
||||||
/// A type to collect errors together and format them.
|
/// A type to collect errors together and format them.
|
||||||
///
|
///
|
||||||
@@ -11,7 +13,7 @@ use std::thread;
|
|||||||
pub struct Ctxt {
|
pub struct Ctxt {
|
||||||
// The contents will be set to `None` during checking. This is so that checking can be
|
// The contents will be set to `None` during checking. This is so that checking can be
|
||||||
// enforced.
|
// enforced.
|
||||||
errors: RefCell<Option<Vec<String>>>,
|
errors: RefCell<Option<Vec<syn::Error>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ctxt {
|
impl Ctxt {
|
||||||
@@ -24,29 +26,24 @@ impl Ctxt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an error to the context object.
|
/// Add an error to the context object with a tokenenizable object.
|
||||||
pub fn error<T: Display>(&self, msg: T) {
|
///
|
||||||
|
/// The object is used for spanning in error messages.
|
||||||
|
pub fn error_spanned_by<A: ToTokens, T: Display>(&self, obj: A, msg: T) {
|
||||||
self.errors
|
self.errors
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.push(msg.to_string());
|
// Curb monomorphization from generating too many identical methods.
|
||||||
|
.push(syn::Error::new_spanned(obj.into_token_stream(), msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume this object, producing a formatted error string if there are errors.
|
/// Consume this object, producing a formatted error string if there are errors.
|
||||||
pub fn check(self) -> Result<(), String> {
|
pub fn check(self) -> Result<(), Vec<syn::Error>> {
|
||||||
let mut errors = self.errors.borrow_mut().take().unwrap();
|
let errors = self.errors.borrow_mut().take().unwrap();
|
||||||
match errors.len() {
|
match errors.len() {
|
||||||
0 => Ok(()),
|
0 => Ok(()),
|
||||||
1 => Err(errors.pop().unwrap()),
|
_ => Err(errors),
|
||||||
n => {
|
|
||||||
let mut msg = format!("{} errors:", n);
|
|
||||||
for err in errors {
|
|
||||||
msg.push_str("\n\t# ");
|
|
||||||
msg.push_str(&err);
|
|
||||||
}
|
|
||||||
Err(msg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ mod internals;
|
|||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use syn::DeriveInput;
|
use syn::DeriveInput;
|
||||||
use syn::spanned::Spanned;
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod bound;
|
mod bound;
|
||||||
@@ -78,7 +77,7 @@ mod try;
|
|||||||
pub fn derive_serialize(input: TokenStream) -> TokenStream {
|
pub fn derive_serialize(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
ser::expand_derive_serialize(&input)
|
ser::expand_derive_serialize(&input)
|
||||||
.unwrap_or_else(|message| compile_error(input.span(), message))
|
.unwrap_or_else(to_compile_errors)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,12 +85,11 @@ pub fn derive_serialize(input: TokenStream) -> TokenStream {
|
|||||||
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
|
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
de::expand_derive_deserialize(&input)
|
de::expand_derive_deserialize(&input)
|
||||||
.unwrap_or_else(|message| compile_error(input.span(), message))
|
.unwrap_or_else(to_compile_errors)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_error(span: proc_macro2::Span, message: String) -> proc_macro2::TokenStream {
|
fn to_compile_errors(errors: Vec<syn::Error>) -> proc_macro2::TokenStream {
|
||||||
quote_spanned! {span=>
|
let compile_errors = errors.iter().map(syn::Error::to_compile_error);
|
||||||
compile_error!(#message);
|
quote!(#(#compile_errors)*)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,12 @@ use internals::{attr, Ctxt, Derive};
|
|||||||
use pretend;
|
use pretend;
|
||||||
use try;
|
use try;
|
||||||
|
|
||||||
pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream, String> {
|
pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
|
||||||
let ctxt = Ctxt::new();
|
let ctxt = Ctxt::new();
|
||||||
let cont = Container::from_ast(&ctxt, input, Derive::Serialize);
|
let cont = match Container::from_ast(&ctxt, input, Derive::Serialize) {
|
||||||
|
Some(cont) => cont,
|
||||||
|
None => return Err(ctxt.check().unwrap_err()),
|
||||||
|
};
|
||||||
precondition(&ctxt, &cont);
|
precondition(&ctxt, &cont);
|
||||||
try!(ctxt.check());
|
try!(ctxt.check());
|
||||||
|
|
||||||
@@ -72,10 +75,10 @@ fn precondition(cx: &Ctxt, cont: &Container) {
|
|||||||
match cont.attrs.identifier() {
|
match cont.attrs.identifier() {
|
||||||
attr::Identifier::No => {}
|
attr::Identifier::No => {}
|
||||||
attr::Identifier::Field => {
|
attr::Identifier::Field => {
|
||||||
cx.error("field identifiers cannot be serialized");
|
cx.error_spanned_by(cont.original, "field identifiers cannot be serialized");
|
||||||
}
|
}
|
||||||
attr::Identifier::Variant => {
|
attr::Identifier::Variant => {
|
||||||
cx.error("variant identifiers cannot be serialized");
|
cx.error_spanned_by(cont.original, "variant identifiers cannot be serialized");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: failed to parse borrowed lifetimes: "zzz"
|
error: failed to parse borrowed lifetimes: "zzz"
|
||||||
--> $DIR/bad_lifetimes.rs:4:10
|
--> $DIR/bad_lifetimes.rs:6:22
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
6 | #[serde(borrow = "zzz")]
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: duplicate borrowed lifetime `'a`
|
error: duplicate borrowed lifetime `'a`
|
||||||
--> $DIR/duplicate_lifetime.rs:4:10
|
--> $DIR/duplicate_lifetime.rs:6:22
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
6 | #[serde(borrow = "'a + 'a")]
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: duplicate serde attribute `borrow`
|
error: duplicate serde attribute `borrow`
|
||||||
--> $DIR/duplicate_variant.rs:7:10
|
--> $DIR/duplicate_variant.rs:9:13
|
||||||
|
|
|
|
||||||
7 | #[derive(Deserialize)]
|
9 | #[serde(borrow)]
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: at least one lifetime must be borrowed
|
error: at least one lifetime must be borrowed
|
||||||
--> $DIR/empty_lifetimes.rs:4:10
|
--> $DIR/empty_lifetimes.rs:6:22
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
6 | #[serde(borrow = "")]
|
||||||
| ^^^^^^^^^^^
|
| ^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
error: field `s` has no lifetimes to borrow
|
error: field `s` has no lifetimes to borrow
|
||||||
--> $DIR/no_lifetimes.rs:4:10
|
--> $DIR/no_lifetimes.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
6 | / #[serde(borrow)]
|
||||||
| ^^^^^^^^^^^
|
7 | | s: String,
|
||||||
|
| |_____________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
error: #[serde(borrow)] may only be used on newtype variants
|
error: #[serde(borrow)] may only be used on newtype variants
|
||||||
--> $DIR/struct_variant.rs:7:10
|
--> $DIR/struct_variant.rs:9:5
|
||||||
|
|
|
|
||||||
7 | #[derive(Deserialize)]
|
9 | / #[serde(borrow)]
|
||||||
| ^^^^^^^^^^^
|
10 | | S { s: Str<'a> },
|
||||||
|
| |____________________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
error: field `s` does not have lifetime 'b
|
error: field `s` does not have lifetime 'b
|
||||||
--> $DIR/wrong_lifetime.rs:4:10
|
--> $DIR/wrong_lifetime.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
6 | / #[serde(borrow = "'b")]
|
||||||
| ^^^^^^^^^^^
|
7 | | s: &'a str,
|
||||||
|
| |______________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
error: enum tags `conflict` for type and content conflict with each other
|
error: enum tags `conflict` for type and content conflict with each other
|
||||||
--> $DIR/adjacent-tag.rs:4:10
|
--> $DIR/adjacent-tag.rs:5:1
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
5 | / #[serde(tag = "conflict", content = "conflict")]
|
||||||
| ^^^^^^^^^
|
6 | | enum E {
|
||||||
|
7 | | A,
|
||||||
|
8 | | B,
|
||||||
|
9 | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: #[serde(flatten)] cannot be used on newtype structs
|
error: #[serde(flatten)] cannot be used on newtype structs
|
||||||
--> $DIR/flatten-newtype-struct.rs:4:10
|
--> $DIR/flatten-newtype-struct.rs:5:12
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
5 | struct Foo(#[serde(flatten)] HashMap<String, String>);
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
error: #[serde(flatten] can not be combined with #[serde(skip_deserializing)]
|
error: #[serde(flatten)] can not be combined with #[serde(skip_deserializing)]
|
||||||
--> $DIR/flatten-skip-deserializing.rs:4:10
|
--> $DIR/flatten-skip-deserializing.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
6 | / #[serde(flatten, skip_deserializing)]
|
||||||
| ^^^^^^^^^^^
|
7 | | other: Other,
|
||||||
|
| |________________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
error: #[serde(flatten] can not be combined with #[serde(skip_serializing_if = "...")]
|
error: #[serde(flatten)] can not be combined with #[serde(skip_serializing_if = "...")]
|
||||||
--> $DIR/flatten-skip-serializing-if.rs:4:10
|
--> $DIR/flatten-skip-serializing-if.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | / #[serde(flatten, skip_serializing_if = "Option::is_none")]
|
||||||
| ^^^^^^^^^
|
7 | | other: Option<Other>,
|
||||||
|
| |________________________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
error: #[serde(flatten] can not be combined with #[serde(skip_serializing)]
|
error: #[serde(flatten)] can not be combined with #[serde(skip_serializing)]
|
||||||
--> $DIR/flatten-skip-serializing.rs:4:10
|
--> $DIR/flatten-skip-serializing.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | / #[serde(flatten, skip_serializing)]
|
||||||
| ^^^^^^^^^
|
7 | | other: Other,
|
||||||
|
| |________________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: #[serde(flatten)] cannot be used on tuple structs
|
error: #[serde(flatten)] cannot be used on tuple structs
|
||||||
--> $DIR/flatten-tuple-struct.rs:4:10
|
--> $DIR/flatten-tuple-struct.rs:5:17
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
5 | struct Foo(u32, #[serde(flatten)] HashMap<String, String>);
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
error: variant field name `conflict` conflicts with internal tag
|
error: variant field name `conflict` conflicts with internal tag
|
||||||
--> $DIR/internal-tag.rs:4:10
|
--> $DIR/internal-tag.rs:5:1
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
5 | / #[serde(tag = "conflict")]
|
||||||
| ^^^^^^^^^
|
6 | | enum E {
|
||||||
|
7 | | A {
|
||||||
|
8 | | #[serde(rename = "conflict")]
|
||||||
|
9 | | x: (),
|
||||||
|
10 | | },
|
||||||
|
11 | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: #[serde(default)] can only be used on structs with named fields
|
error: #[serde(default)] can only be used on structs with named fields
|
||||||
--> $DIR/enum.rs:4:10
|
--> $DIR/enum.rs:6:1
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
6 | enum E {
|
||||||
| ^^^^^^^^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: #[serde(default)] can only be used on structs with named fields
|
error: #[serde(default)] can only be used on structs with named fields
|
||||||
--> $DIR/nameless_struct_fields.rs:4:10
|
--> $DIR/nameless_struct_fields.rs:6:9
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
6 | struct T(u8, u8);
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: unknown serde field attribute `serialize`
|
error: unknown serde field attribute `serialize`
|
||||||
--> $DIR/rename-and-ser.rs:4:10
|
--> $DIR/rename-and-ser.rs:6:27
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | #[serde(rename = "x", serialize = "y")]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: duplicate serde attribute `rename`
|
error: duplicate serde attribute `rename`
|
||||||
--> $DIR/rename-rename-de.rs:4:10
|
--> $DIR/rename-rename-de.rs:7:13
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
7 | #[serde(rename(deserialize = "y"))]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: duplicate serde attribute `rename`
|
error: duplicate serde attribute `rename`
|
||||||
--> $DIR/rename-ser-rename-ser.rs:4:10
|
--> $DIR/rename-ser-rename-ser.rs:6:38
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | #[serde(rename(serialize = "x"), rename(serialize = "y"))]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: duplicate serde attribute `rename`
|
error: duplicate serde attribute `rename`
|
||||||
--> $DIR/rename-ser-rename.rs:4:10
|
--> $DIR/rename-ser-rename.rs:7:13
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
7 | #[serde(rename = "y")]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: duplicate serde attribute `rename`
|
error: duplicate serde attribute `rename`
|
||||||
--> $DIR/rename-ser-ser.rs:4:10
|
--> $DIR/rename-ser-ser.rs:6:37
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | #[serde(rename(serialize = "x", serialize = "y"))]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: duplicate serde attribute `rename`
|
error: duplicate serde attribute `rename`
|
||||||
--> $DIR/two-rename-ser.rs:4:10
|
--> $DIR/two-rename-ser.rs:7:13
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
7 | #[serde(rename(serialize = "y"))]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: duplicate serde attribute `serialize_with`
|
error: duplicate serde attribute `serialize_with`
|
||||||
--> $DIR/with-and-serialize-with.rs:4:10
|
--> $DIR/with-and-serialize-with.rs:6:25
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | #[serde(with = "w", serialize_with = "s")]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: #[serde(tag = "...")] cannot be used with tuple variants
|
error: #[serde(tag = "...")] cannot be used with tuple variants
|
||||||
--> $DIR/internal-tuple-variant.rs:4:10
|
--> $DIR/internal-tuple-variant.rs:7:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
7 | Tuple(u8, u8),
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: #[serde(tag = "...")] can only be used on enums
|
error: #[serde(tag = "...")] can only be used on enums
|
||||||
--> $DIR/internally-tagged-struct.rs:4:10
|
--> $DIR/internally-tagged-struct.rs:6:1
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | struct S;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
error: enum cannot be both untagged and internally tagged
|
error: enum cannot be both untagged and internally tagged
|
||||||
--> $DIR/untagged-and-internal.rs:4:10
|
--> $DIR/untagged-and-internal.rs:5:9
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
5 | #[serde(untagged)]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: enum cannot be both untagged and internally tagged
|
||||||
|
--> $DIR/untagged-and-internal.rs:6:9
|
||||||
|
|
|
||||||
|
6 | #[serde(tag = "type")]
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: #[serde(untagged)] can only be used on enums
|
error: #[serde(untagged)] can only be used on enums
|
||||||
--> $DIR/untagged-struct.rs:4:10
|
--> $DIR/untagged-struct.rs:6:1
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | struct S;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
error: `field_identifier` and `variant_identifier` cannot both be set
|
error: #[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set
|
||||||
--> $DIR/both.rs:4:10
|
--> $DIR/both.rs:5:9
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
5 | #[serde(field_identifier, variant_identifier)]
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: #[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set
|
||||||
|
--> $DIR/both.rs:5:27
|
||||||
|
|
|
||||||
|
5 | #[serde(field_identifier, variant_identifier)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: `field_identifier` can only be used on an enum
|
error: #[serde(field_identifier)] can only be used on an enum
|
||||||
--> $DIR/field_struct.rs:4:10
|
--> $DIR/field_struct.rs:6:1
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
6 | struct S;
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: field_identifier may only contain unit variants
|
error: #[serde(field_identifier)] may only contain unit variants
|
||||||
--> $DIR/field_tuple.rs:4:10
|
--> $DIR/field_tuple.rs:8:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
8 | B(u8, u8),
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: `Other` must be the last variant
|
error: `Other` must be the last variant
|
||||||
--> $DIR/newtype_not_last.rs:4:10
|
--> $DIR/newtype_not_last.rs:8:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
8 | Other(String),
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
error: #[serde(other)] must be on a unit variant
|
error: #[serde(other)] must be on a unit variant
|
||||||
--> $DIR/not_unit.rs:4:10
|
--> $DIR/not_unit.rs:8:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
8 | / #[serde(other)]
|
||||||
| ^^^^^^^^^^^
|
9 | | Other(u8, u8),
|
||||||
|
| |_________________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
error: #[serde(other)] must be the last variant
|
error: #[serde(other)] must be on the last variant
|
||||||
--> $DIR/other_not_last.rs:4:10
|
--> $DIR/other_not_last.rs:8:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
8 | / #[serde(other)]
|
||||||
| ^^^^^^^^^^^
|
9 | | Other,
|
||||||
|
| |_________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
error: field identifiers cannot be serialized
|
error: field identifiers cannot be serialized
|
||||||
--> $DIR/serialize.rs:4:10
|
--> $DIR/serialize.rs:5:1
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
5 | / #[serde(field_identifier)]
|
||||||
| ^^^^^^^^^
|
6 | | enum F {
|
||||||
|
7 | | A,
|
||||||
|
8 | | B,
|
||||||
|
9 | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: `variant_identifier` can only be used on an enum
|
error: #[serde(variant_identifier)] can only be used on an enum
|
||||||
--> $DIR/variant_struct.rs:4:10
|
--> $DIR/variant_struct.rs:6:1
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
6 | struct S;
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: variant_identifier may only contain unit variants
|
error: #[serde(variant_identifier)] may only contain unit variants
|
||||||
--> $DIR/variant_tuple.rs:4:10
|
--> $DIR/variant_tuple.rs:8:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
8 | B(u8, u8),
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: cannot deserialize when there is a lifetime parameter called 'de
|
error: cannot deserialize when there is a lifetime parameter called 'de
|
||||||
--> $DIR/deserialize_de_lifetime.rs:4:10
|
--> $DIR/deserialize_de_lifetime.rs:5:10
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
5 | struct S<'de> {
|
||||||
| ^^^^^^^^^^^
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
error: cannot deserialize a dynamically sized struct
|
error: cannot deserialize a dynamically sized struct
|
||||||
--> $DIR/deserialize_dst.rs:4:10
|
--> $DIR/deserialize_dst.rs:5:1
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
5 | / struct S {
|
||||||
| ^^^^^^^^^^^
|
6 | | string: String,
|
||||||
|
7 | | slice: [u8],
|
||||||
|
8 | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: failed to parse path: "~~~"
|
error: failed to parse path: "~~~"
|
||||||
--> $DIR/bad_getter.rs:10:10
|
--> $DIR/bad_getter.rs:13:22
|
||||||
|
|
|
|
||||||
10 | #[derive(Serialize)]
|
13 | #[serde(getter = "~~~")]
|
||||||
| ^^^^^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: failed to parse path: "~~~"
|
error: failed to parse path: "~~~"
|
||||||
--> $DIR/bad_remote.rs:10:10
|
--> $DIR/bad_remote.rs:11:18
|
||||||
|
|
|
|
||||||
10 | #[derive(Serialize)]
|
11 | #[serde(remote = "~~~")]
|
||||||
| ^^^^^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
error: #[serde(getter = "...")] is not allowed in an enum
|
error: #[serde(getter = "...")] is not allowed in an enum
|
||||||
--> $DIR/enum_getter.rs:10:10
|
--> $DIR/enum_getter.rs:11:1
|
||||||
|
|
|
|
||||||
10 | #[derive(Serialize)]
|
11 | / #[serde(remote = "remote::E")]
|
||||||
| ^^^^^^^^^
|
12 | | pub enum E {
|
||||||
|
13 | | A {
|
||||||
|
14 | | #[serde(getter = "get_a")]
|
||||||
|
15 | | a: u8,
|
||||||
|
16 | | },
|
||||||
|
17 | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
error: #[serde(getter = "...")] can only be used in structs that have #[serde(remote = "...")]
|
error: #[serde(getter = "...")] can only be used in structs that have #[serde(remote = "...")]
|
||||||
--> $DIR/nonremote_getter.rs:4:10
|
--> $DIR/nonremote_getter.rs:5:1
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
5 | / struct S {
|
||||||
| ^^^^^^^^^
|
6 | | #[serde(getter = "S::get")]
|
||||||
|
7 | | a: u8,
|
||||||
|
8 | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
error: #[serde(transparent)] requires struct to have at most one transparent field
|
error: #[serde(transparent)] requires struct to have at most one transparent field
|
||||||
--> $DIR/at_most_one.rs:4:10
|
--> $DIR/at_most_one.rs:5:1
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
5 | / #[serde(transparent)]
|
||||||
| ^^^^^^^^^
|
6 | | struct S {
|
||||||
|
7 | | a: u8,
|
||||||
|
8 | | b: u8,
|
||||||
|
9 | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
error: #[serde(transparent)] requires at least one field that is neither skipped nor has a default
|
error: #[serde(transparent)] requires at least one field that is neither skipped nor has a default
|
||||||
--> $DIR/de_at_least_one.rs:4:10
|
--> $DIR/de_at_least_one.rs:5:1
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
5 | / #[serde(transparent)]
|
||||||
| ^^^^^^^^^^^
|
6 | | struct S {
|
||||||
|
7 | | #[serde(skip)]
|
||||||
|
8 | | a: u8,
|
||||||
|
9 | | #[serde(default)]
|
||||||
|
10 | | b: u8,
|
||||||
|
11 | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
error: #[serde(transparent)] requires at least one field that is not skipped
|
error: #[serde(transparent)] requires at least one field that is not skipped
|
||||||
--> $DIR/ser_at_least_one.rs:4:10
|
--> $DIR/ser_at_least_one.rs:5:1
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
5 | / #[serde(transparent)]
|
||||||
| ^^^^^^^^^
|
6 | | struct S {
|
||||||
|
7 | | #[serde(skip)]
|
||||||
|
8 | | a: u8,
|
||||||
|
9 | | }
|
||||||
|
| |_^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: failed to parse type: from = "Option<T"
|
error: failed to parse type: from = "Option<T"
|
||||||
--> $DIR/from.rs:4:10
|
--> $DIR/from.rs:5:16
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
5 | #[serde(from = "Option<T")]
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: failed to parse type: into = "Option<T"
|
error: failed to parse type: into = "Option<T"
|
||||||
--> $DIR/into.rs:4:10
|
--> $DIR/into.rs:5:16
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
5 | #[serde(into = "Option<T")]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: unknown serde container attribute `abc`
|
error: unknown serde container attribute `abc`
|
||||||
--> $DIR/container.rs:4:10
|
--> $DIR/container.rs:5:9
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
5 | #[serde(abc = "xyz")]
|
||||||
| ^^^^^^^^^
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: unknown serde field attribute `abc`
|
error: unknown serde field attribute `abc`
|
||||||
--> $DIR/field.rs:4:10
|
--> $DIR/field.rs:6:13
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | #[serde(abc = "xyz")]
|
||||||
| ^^^^^^^^^
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
error: unknown serde variant attribute `abc`
|
error: unknown serde variant attribute `abc`
|
||||||
--> $DIR/variant.rs:4:10
|
--> $DIR/variant.rs:6:13
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | #[serde(abc = "xyz")]
|
||||||
| ^^^^^^^^^
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
error: variant `Newtype` cannot have both #[serde(deserialize_with)] and a field 0 marked with #[serde(skip_deserializing)]
|
error: variant `Newtype` cannot have both #[serde(deserialize_with)] and a field #0 marked with #[serde(skip_deserializing)]
|
||||||
--> $DIR/skip_de_newtype_field.rs:4:10
|
--> $DIR/skip_de_newtype_field.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
6 | / #[serde(deserialize_with = "deserialize_some_newtype_variant")]
|
||||||
| ^^^^^^^^^^^
|
7 | | Newtype(#[serde(skip_deserializing)] String),
|
||||||
|
| |________________________________________________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
error: variant `Struct` cannot have both #[serde(deserialize_with)] and a field `f1` marked with #[serde(skip_deserializing)]
|
error: variant `Struct` cannot have both #[serde(deserialize_with)] and a field `f1` marked with #[serde(skip_deserializing)]
|
||||||
--> $DIR/skip_de_struct_field.rs:4:10
|
--> $DIR/skip_de_struct_field.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
6 | / #[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||||
| ^^^^^^^^^^^
|
7 | | Struct {
|
||||||
|
8 | | #[serde(skip_deserializing)]
|
||||||
|
9 | | f1: String,
|
||||||
|
10 | | f2: u8,
|
||||||
|
11 | | },
|
||||||
|
| |_____^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
error: variant `Tuple` cannot have both #[serde(deserialize_with)] and a field 0 marked with #[serde(skip_deserializing)]
|
error: variant `Tuple` cannot have both #[serde(deserialize_with)] and a field #0 marked with #[serde(skip_deserializing)]
|
||||||
--> $DIR/skip_de_tuple_field.rs:4:10
|
--> $DIR/skip_de_tuple_field.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
6 | / #[serde(deserialize_with = "deserialize_some_other_variant")]
|
||||||
| ^^^^^^^^^^^
|
7 | | Tuple(#[serde(skip_deserializing)] String, u8),
|
||||||
|
| |__________________________________________________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
error: variant `Unit` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)]
|
error: variant `Unit` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)]
|
||||||
--> $DIR/skip_de_whole_variant.rs:4:10
|
--> $DIR/skip_de_whole_variant.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Deserialize)]
|
6 | / #[serde(deserialize_with = "deserialize_some_unit_variant")]
|
||||||
| ^^^^^^^^^^^
|
7 | | #[serde(skip_deserializing)]
|
||||||
|
8 | | Unit,
|
||||||
|
| |________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
error: variant `Newtype` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing)]
|
error: variant `Newtype` cannot have both #[serde(serialize_with)] and a field #0 marked with #[serde(skip_serializing)]
|
||||||
--> $DIR/skip_ser_newtype_field.rs:4:10
|
--> $DIR/skip_ser_newtype_field.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | / #[serde(serialize_with = "serialize_some_newtype_variant")]
|
||||||
| ^^^^^^^^^
|
7 | | Newtype(#[serde(skip_serializing)] String),
|
||||||
|
| |______________________________________________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
error: variant `Newtype` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing_if)]
|
error: variant `Newtype` cannot have both #[serde(serialize_with)] and a field #0 marked with #[serde(skip_serializing_if)]
|
||||||
--> $DIR/skip_ser_newtype_field_if.rs:4:10
|
--> $DIR/skip_ser_newtype_field_if.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | / #[serde(serialize_with = "serialize_some_newtype_variant")]
|
||||||
| ^^^^^^^^^
|
7 | | Newtype(#[serde(skip_serializing_if = "always")] String),
|
||||||
|
| |____________________________________________________________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
error: variant `Struct` cannot have both #[serde(serialize_with)] and a field `f1` marked with #[serde(skip_serializing)]
|
error: variant `Struct` cannot have both #[serde(serialize_with)] and a field `f1` marked with #[serde(skip_serializing)]
|
||||||
--> $DIR/skip_ser_struct_field.rs:4:10
|
--> $DIR/skip_ser_struct_field.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | / #[serde(serialize_with = "serialize_some_other_variant")]
|
||||||
| ^^^^^^^^^
|
7 | | Struct {
|
||||||
|
8 | | #[serde(skip_serializing)]
|
||||||
|
9 | | f1: String,
|
||||||
|
10 | | f2: u8,
|
||||||
|
11 | | },
|
||||||
|
| |_____^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
error: variant `Struct` cannot have both #[serde(serialize_with)] and a field `f1` marked with #[serde(skip_serializing_if)]
|
error: variant `Struct` cannot have both #[serde(serialize_with)] and a field `f1` marked with #[serde(skip_serializing_if)]
|
||||||
--> $DIR/skip_ser_struct_field_if.rs:4:10
|
--> $DIR/skip_ser_struct_field_if.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | / #[serde(serialize_with = "serialize_some_newtype_variant")]
|
||||||
| ^^^^^^^^^
|
7 | | Struct {
|
||||||
|
8 | | #[serde(skip_serializing_if = "always")]
|
||||||
|
9 | | f1: String,
|
||||||
|
10 | | f2: u8,
|
||||||
|
11 | | },
|
||||||
|
| |_____^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
error: variant `Tuple` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing)]
|
error: variant `Tuple` cannot have both #[serde(serialize_with)] and a field #0 marked with #[serde(skip_serializing)]
|
||||||
--> $DIR/skip_ser_tuple_field.rs:4:10
|
--> $DIR/skip_ser_tuple_field.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | / #[serde(serialize_with = "serialize_some_other_variant")]
|
||||||
| ^^^^^^^^^
|
7 | | Tuple(#[serde(skip_serializing)] String, u8),
|
||||||
|
| |________________________________________________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
error: variant `Tuple` cannot have both #[serde(serialize_with)] and a field 0 marked with #[serde(skip_serializing_if)]
|
error: variant `Tuple` cannot have both #[serde(serialize_with)] and a field #0 marked with #[serde(skip_serializing_if)]
|
||||||
--> $DIR/skip_ser_tuple_field_if.rs:4:10
|
--> $DIR/skip_ser_tuple_field_if.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | / #[serde(serialize_with = "serialize_some_other_variant")]
|
||||||
| ^^^^^^^^^
|
7 | | Tuple(#[serde(skip_serializing_if = "always")] String, u8),
|
||||||
|
| |______________________________________________________________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
error: variant `Unit` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)]
|
error: variant `Unit` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)]
|
||||||
--> $DIR/skip_ser_whole_variant.rs:4:10
|
--> $DIR/skip_ser_whole_variant.rs:6:5
|
||||||
|
|
|
|
||||||
4 | #[derive(Serialize)]
|
6 | / #[serde(serialize_with = "serialize_some_unit_variant")]
|
||||||
| ^^^^^^^^^
|
7 | | #[serde(skip_serializing)]
|
||||||
|
8 | | Unit,
|
||||||
|
| |________^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user