Update to syn 0.12

This commit is contained in:
David Tolnay
2018-01-08 21:49:09 -08:00
parent f7ed967db1
commit ef4dd6c0ec
12 changed files with 609 additions and 444 deletions
+3 -2
View File
@@ -23,9 +23,10 @@ name = "serde_derive"
proc-macro = true proc-macro = true
[dependencies] [dependencies]
quote = "0.3.8" proc-macro2 = "0.2"
quote = "0.4"
serde_derive_internals = { version = "=0.19.0", default-features = false, path = "../serde_derive_internals" } serde_derive_internals = { version = "=0.19.0", default-features = false, path = "../serde_derive_internals" }
syn = { version = "0.11", features = ["visit"] } syn = { version = "0.12", features = ["visit"] }
[dev-dependencies] [dev-dependencies]
serde = { version = "1.0", path = "../serde" } serde = { version = "1.0", path = "../serde" }
+160 -96
View File
@@ -9,27 +9,30 @@
use std::collections::HashSet; use std::collections::HashSet;
use syn::{self, visit}; use syn::{self, visit};
use syn::punctuated::Punctuated;
use internals::ast::{Body, Container}; use internals::ast::{Data, Container};
use internals::attr; use internals::attr;
macro_rules! path { use proc_macro2::{Span, Term};
($($path:tt)+) => {
syn::parse_path(quote!($($path)+).as_str()).unwrap()
};
}
// Remove the default from every type parameter because in the generated impls // Remove the default from every type parameter because in the generated impls
// they look like associated types: "error: associated type bindings are not // they look like associated types: "error: associated type bindings are not
// allowed here". // allowed here".
pub fn without_defaults(generics: &syn::Generics) -> syn::Generics { pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
syn::Generics { syn::Generics {
ty_params: generics params: generics
.ty_params .params
.iter() .iter()
.map(|ty_param| syn::TyParam { .map(|param| match *param {
default: None, syn::GenericParam::Type(ref param) => {
..ty_param.clone() syn::GenericParam::Type(syn::TypeParam {
eq_token: None,
default: None,
..param.clone()
})
}
_ => param.clone(),
}) })
.collect(), .collect(),
..generics.clone() ..generics.clone()
@@ -41,10 +44,17 @@ pub fn with_where_predicates(
predicates: &[syn::WherePredicate], predicates: &[syn::WherePredicate],
) -> syn::Generics { ) -> syn::Generics {
let mut generics = generics.clone(); let mut generics = generics.clone();
generics if generics.where_clause.is_none() {
.where_clause generics.where_clause = Some(syn::WhereClause {
where_token: Default::default(),
predicates: Punctuated::new(),
});
}
generics.where_clause
.as_mut()
.unwrap()
.predicates .predicates
.extend_from_slice(predicates); .extend(predicates.into_iter().cloned());
generics generics
} }
@@ -56,13 +66,23 @@ pub fn with_where_predicates_from_fields<F>(
where where
F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>, F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
{ {
let predicates = cont.body let predicates = cont.data
.all_fields() .all_fields()
.flat_map(|field| from_field(&field.attrs)) .flat_map(|field| from_field(&field.attrs))
.flat_map(|predicates| predicates.to_vec()); .flat_map(|predicates| predicates.to_vec());
let mut generics = generics.clone(); let mut generics = generics.clone();
generics.where_clause.predicates.extend(predicates); if generics.where_clause.is_none() {
generics.where_clause = Some(syn::WhereClause {
where_token: Default::default(),
predicates: Punctuated::new(),
});
}
generics.where_clause
.as_mut()
.unwrap()
.predicates
.extend(predicates);
generics generics
} }
@@ -95,22 +115,22 @@ where
// them. // them.
relevant_ty_params: HashSet<syn::Ident>, relevant_ty_params: HashSet<syn::Ident>,
} }
impl visit::Visitor for FindTyParams { impl<'ast> visit::Visit<'ast> for FindTyParams {
fn visit_path(&mut self, path: &syn::Path) { fn visit_path(&mut self, path: &syn::Path) {
if let Some(seg) = path.segments.last() { if let Some(seg) = path.segments.last() {
if seg.ident == "PhantomData" { if seg.into_value().ident == "PhantomData" {
// Hardcoded exception, because PhantomData<T> implements // Hardcoded exception, because PhantomData<T> implements
// Serialize and Deserialize whether or not T implements it. // Serialize and Deserialize whether or not T implements it.
return; return;
} }
} }
if !path.global && path.segments.len() == 1 { if path.leading_colon.is_none() && path.segments.len() == 1 {
let id = path.segments[0].ident.clone(); let id = path.segments[0].ident.clone();
if self.all_ty_params.contains(&id) { if self.all_ty_params.contains(&id) {
self.relevant_ty_params.insert(id); self.relevant_ty_params.insert(id);
} }
} }
visit::walk_path(self, path); visit::visit_path(self, path);
} }
// Type parameter should not be considered used by a macro path. // Type parameter should not be considered used by a macro path.
@@ -119,61 +139,79 @@ where
// mac: T!(), // mac: T!(),
// marker: PhantomData<T>, // marker: PhantomData<T>,
// } // }
fn visit_mac(&mut self, _mac: &syn::Mac) {} fn visit_macro(&mut self, _mac: &syn::Macro) {}
} }
let all_ty_params: HashSet<_> = generics let all_ty_params: HashSet<_> = generics
.ty_params .params
.iter() .iter()
.map(|ty_param| ty_param.ident.clone()) .filter_map(|param| match *param {
syn::GenericParam::Type(ref param) => Some(param.ident),
_ => None,
})
.collect(); .collect();
let mut visitor = FindTyParams { let mut visitor = FindTyParams {
all_ty_params: all_ty_params, all_ty_params: all_ty_params,
relevant_ty_params: HashSet::new(), relevant_ty_params: HashSet::new(),
}; };
match cont.body { match cont.data {
Body::Enum(ref variants) => for variant in variants.iter() { Data::Enum(ref variants) => for variant in variants.iter() {
let relevant_fields = variant let relevant_fields = variant
.fields .fields
.iter() .iter()
.filter(|field| filter(&field.attrs, Some(&variant.attrs))); .filter(|field| filter(&field.attrs, Some(&variant.attrs)));
for field in relevant_fields { for field in relevant_fields {
visit::walk_ty(&mut visitor, field.ty); visit::visit_type(&mut visitor, field.ty);
} }
}, },
Body::Struct(_, ref fields) => { Data::Struct(_, ref fields) => {
for field in fields.iter().filter(|field| filter(&field.attrs, None)) { for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
visit::walk_ty(&mut visitor, field.ty); visit::visit_type(&mut visitor, field.ty);
} }
} }
} }
let new_predicates = generics let new_predicates = generics
.ty_params .params
.iter() .iter()
.map(|ty_param| ty_param.ident.clone()) .filter_map(|param| match *param {
syn::GenericParam::Type(ref param) => Some(param.ident),
_ => None,
})
.filter(|id| visitor.relevant_ty_params.contains(id)) .filter(|id| visitor.relevant_ty_params.contains(id))
.map(|id| { .map(|id| {
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate { syn::WherePredicate::Type(syn::PredicateType {
bound_lifetimes: Vec::new(), lifetimes: None,
// the type parameter that is being bounded e.g. T // the type parameter that is being bounded e.g. T
bounded_ty: syn::Ty::Path(None, id.into()), bounded_ty: syn::Type::Path(syn::TypePath {
qself: None,
path: id.into(),
}),
colon_token: Default::default(),
// the bound e.g. Serialize // the bound e.g. Serialize
bounds: vec![ bounds: vec![
syn::TyParamBound::Trait( syn::TypeParamBound::Trait(syn::TraitBound {
syn::PolyTraitRef { modifier: syn::TraitBoundModifier::None,
bound_lifetimes: Vec::new(), lifetimes: None,
trait_ref: bound.clone(), path: bound.clone(),
}, }),
syn::TraitBoundModifier::None, ].into_iter().collect(),
),
],
}) })
}); });
let mut generics = generics.clone(); let mut generics = generics.clone();
generics.where_clause.predicates.extend(new_predicates); if generics.where_clause.is_none() {
generics.where_clause = Some(syn::WhereClause {
where_token: Default::default(),
predicates: Punctuated::new(),
});
}
generics.where_clause
.as_mut()
.unwrap()
.predicates
.extend(new_predicates);
generics generics
} }
@@ -183,76 +221,102 @@ pub fn with_self_bound(
bound: &syn::Path, bound: &syn::Path,
) -> syn::Generics { ) -> syn::Generics {
let mut generics = generics.clone(); let mut generics = generics.clone();
generics if generics.where_clause.is_none() {
.where_clause generics.where_clause = Some(syn::WhereClause {
where_token: Default::default(),
predicates: Punctuated::new(),
});
}
generics.where_clause
.as_mut()
.unwrap()
.predicates .predicates
.push(syn::WherePredicate::BoundPredicate( .push(syn::WherePredicate::Type(syn::PredicateType {
syn::WhereBoundPredicate { lifetimes: None,
bound_lifetimes: Vec::new(), // the type that is being bounded e.g. MyStruct<'a, T>
// the type that is being bounded e.g. MyStruct<'a, T> bounded_ty: type_of_item(cont),
bounded_ty: type_of_item(cont), colon_token: Default::default(),
// the bound e.g. Default // the bound e.g. Default
bounds: vec![ bounds: vec![
syn::TyParamBound::Trait( syn::TypeParamBound::Trait(syn::TraitBound {
syn::PolyTraitRef { modifier: syn::TraitBoundModifier::None,
bound_lifetimes: Vec::new(), lifetimes: None,
trait_ref: bound.clone(), path: bound.clone(),
}, }),
syn::TraitBoundModifier::None, ].into_iter().collect(),
), }));
],
},
));
generics generics
} }
pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics { pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
let mut generics = generics.clone(); let bound = syn::Lifetime::new(Term::intern(lifetime), Span::def_site());
let def = syn::LifetimeDef {
for lifetime_def in &mut generics.lifetimes {
lifetime_def.bounds.push(syn::Lifetime::new(lifetime));
}
for ty_param in &mut generics.ty_params {
ty_param
.bounds
.push(syn::TyParamBound::Region(syn::Lifetime::new(lifetime)));
}
generics.lifetimes.push(syn::LifetimeDef {
attrs: Vec::new(), attrs: Vec::new(),
lifetime: syn::Lifetime::new(lifetime), lifetime: bound,
bounds: Vec::new(), colon_token: None,
}); bounds: Punctuated::new(),
};
generics let params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params
.iter()
.cloned()
.map(|mut param| {
match param {
syn::GenericParam::Lifetime(ref mut param) => {
param.bounds.push(bound);
}
syn::GenericParam::Type(ref mut param) => {
param.bounds.push(syn::TypeParamBound::Lifetime(bound));
}
syn::GenericParam::Const(_) => {}
}
param
}))
.collect();
syn::Generics {
params: params,
..generics.clone()
}
} }
fn type_of_item(cont: &Container) -> syn::Ty { fn type_of_item(cont: &Container) -> syn::Type {
syn::Ty::Path( syn::Type::Path(syn::TypePath {
None, qself: None,
syn::Path { path: syn::Path {
global: false, leading_colon: None,
segments: vec![ segments: vec![
syn::PathSegment { syn::PathSegment {
ident: cont.ident.clone(), ident: cont.ident.clone(),
parameters: syn::PathParameters::AngleBracketed( arguments: syn::PathArguments::AngleBracketed(
syn::AngleBracketedParameterData { syn::AngleBracketedGenericArguments {
lifetimes: cont.generics colon2_token: None,
.lifetimes lt_token: Default::default(),
args: cont.generics
.params
.iter() .iter()
.map(|def| def.lifetime.clone()) .map(|param| match *param {
syn::GenericParam::Type(ref param) => {
syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
qself: None,
path: param.ident.into(),
}))
}
syn::GenericParam::Lifetime(ref param) => {
syn::GenericArgument::Lifetime(param.lifetime)
}
syn::GenericParam::Const(_) => {
panic!("Serde does not support const generics yet");
}
})
.collect(), .collect(),
types: cont.generics gt_token: Default::default(),
.ty_params
.iter()
.map(|param| syn::Ty::Path(None, param.ident.clone().into()))
.collect(),
bindings: Vec::new(),
}, },
), ),
}, },
], ].into_iter().collect(),
}, },
) })
} }
+107 -61
View File
@@ -6,12 +6,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use syn::{self, Ident}; use syn::{self, Ident, Member};
use quote::{self, ToTokens, Tokens}; use syn::punctuated::Punctuated;
use quote::{ToTokens, Tokens};
use proc_macro2::{Literal, Span, Term};
use bound; use bound;
use fragment::{Expr, Fragment, Match, Stmts}; use fragment::{Expr, Fragment, Match, Stmts};
use internals::ast::{Body, Container, Field, Style, Variant}; use internals::ast::{Data, Container, Field, Style, Variant};
use internals::{self, attr}; use internals::{self, attr};
use std::collections::BTreeSet; use std::collections::BTreeSet;
@@ -24,7 +26,7 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
let ident = &cont.ident; let ident = &cont.ident;
let params = Parameters::new(&cont); let params = Parameters::new(&cont);
let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(&params); let (de_impl_generics, _, ty_generics, where_clause) = split_with_de_lifetime(&params);
let dummy_const = Ident::new(format!("_IMPL_DESERIALIZE_FOR_{}", ident)); let dummy_const = Ident::new(&format!("_IMPL_DESERIALIZE_FOR_{}", ident), Span::def_site());
let body = Stmts(deserialize_body(&cont, &params)); let body = Stmts(deserialize_body(&cont, &params));
let delife = params.borrowed.de_lifetime(); let delife = params.borrowed.de_lifetime();
@@ -96,7 +98,7 @@ impl Parameters {
}; };
let borrowed = borrowed_lifetimes(cont); let borrowed = borrowed_lifetimes(cont);
let generics = build_generics(cont, &borrowed); let generics = build_generics(cont, &borrowed);
let has_getter = cont.body.has_getter(); let has_getter = cont.data.has_getter();
Parameters { Parameters {
local: local, local: local,
@@ -110,7 +112,7 @@ impl Parameters {
/// Type name to use in error messages and `&'static str` arguments to /// Type name to use in error messages and `&'static str` arguments to
/// various Deserializer methods. /// various Deserializer methods.
fn type_name(&self) -> &str { fn type_name(&self) -> &str {
self.this.segments.last().unwrap().ident.as_ref() self.this.segments.last().unwrap().value().ident.as_ref()
} }
} }
@@ -127,7 +129,7 @@ fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generi
None => { None => {
let generics = match *cont.attrs.default() { let generics = match *cont.attrs.default() {
attr::Default::Default => { attr::Default::Default => {
bound::with_self_bound(cont, &generics, &path!(_serde::export::Default)) bound::with_self_bound(cont, &generics, &parse_quote!(_serde::export::Default))
} }
attr::Default::None | attr::Default::Path(_) => generics, attr::Default::None | attr::Default::Path(_) => generics,
}; };
@@ -137,14 +139,14 @@ fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generi
cont, cont,
&generics, &generics,
needs_deserialize_bound, needs_deserialize_bound,
&path!(_serde::Deserialize<#delife>), &parse_quote!(_serde::Deserialize<#delife>),
); );
bound::with_bound( bound::with_bound(
cont, cont,
&generics, &generics,
requires_default, requires_default,
&path!(_serde::export::Default), &parse_quote!(_serde::export::Default),
) )
} }
} }
@@ -162,7 +164,11 @@ fn needs_deserialize_bound(field: &attr::Field, variant: Option<&attr::Variant>)
// Fields with a `default` attribute (not `default=...`), and fields with a // Fields with a `default` attribute (not `default=...`), and fields with a
// `skip_deserializing` attribute that do not also have `default=...`. // `skip_deserializing` attribute that do not also have `default=...`.
fn requires_default(field: &attr::Field, _variant: Option<&attr::Variant>) -> bool { fn requires_default(field: &attr::Field, _variant: Option<&attr::Variant>) -> bool {
field.default() == &attr::Default::Default if let attr::Default::Default = *field.default() {
true
} else {
false
}
} }
enum BorrowedLifetimes { enum BorrowedLifetimes {
@@ -173,8 +179,8 @@ enum BorrowedLifetimes {
impl BorrowedLifetimes { impl BorrowedLifetimes {
fn de_lifetime(&self) -> syn::Lifetime { fn de_lifetime(&self) -> syn::Lifetime {
match *self { match *self {
BorrowedLifetimes::Borrowed(_) => syn::Lifetime::new("'de"), BorrowedLifetimes::Borrowed(_) => syn::Lifetime::new(Term::intern("'de"), Span::def_site()),
BorrowedLifetimes::Static => syn::Lifetime::new("'static"), BorrowedLifetimes::Static => syn::Lifetime::new(Term::intern("'static"), Span::def_site()),
} }
} }
@@ -182,7 +188,8 @@ impl BorrowedLifetimes {
match *self { match *self {
BorrowedLifetimes::Borrowed(ref bounds) => Some(syn::LifetimeDef { BorrowedLifetimes::Borrowed(ref bounds) => Some(syn::LifetimeDef {
attrs: Vec::new(), attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de"), lifetime: syn::Lifetime::new(Term::intern("'de"), Span::def_site()),
colon_token: None,
bounds: bounds.iter().cloned().collect(), bounds: bounds.iter().cloned().collect(),
}), }),
BorrowedLifetimes::Static => None, BorrowedLifetimes::Static => None,
@@ -201,12 +208,12 @@ impl BorrowedLifetimes {
// and we use plain `'static` instead of `'de`. // and we use plain `'static` instead of `'de`.
fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes { fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes {
let mut lifetimes = BTreeSet::new(); let mut lifetimes = BTreeSet::new();
for field in cont.body.all_fields() { for field in cont.data.all_fields() {
if !field.attrs.skip_deserializing() { if !field.attrs.skip_deserializing() {
lifetimes.extend(field.attrs.borrowed_lifetimes().iter().cloned()); lifetimes.extend(field.attrs.borrowed_lifetimes().iter().cloned());
} }
} }
if lifetimes.iter().any(|b| b.ident == "'static") { if lifetimes.iter().any(|b| b.to_string() == "'static") {
BorrowedLifetimes::Static BorrowedLifetimes::Static
} else { } else {
BorrowedLifetimes::Borrowed(lifetimes) BorrowedLifetimes::Borrowed(lifetimes)
@@ -217,28 +224,28 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
if let Some(from_type) = cont.attrs.from_type() { if let Some(from_type) = cont.attrs.from_type() {
deserialize_from(from_type) deserialize_from(from_type)
} else if let attr::Identifier::No = cont.attrs.identifier() { } else if let attr::Identifier::No = cont.attrs.identifier() {
match cont.body { match cont.data {
Body::Enum(ref variants) => deserialize_enum(params, variants, &cont.attrs), Data::Enum(ref variants) => deserialize_enum(params, variants, &cont.attrs),
Body::Struct(Style::Struct, ref fields) => { Data::Struct(Style::Struct, ref fields) => {
if fields.iter().any(|field| field.ident.is_none()) { if fields.iter().any(|field| field.ident.is_none()) {
panic!("struct has unnamed fields"); panic!("struct has unnamed fields");
} }
deserialize_struct(None, params, fields, &cont.attrs, None, Untagged::No) deserialize_struct(None, params, fields, &cont.attrs, None, Untagged::No)
} }
Body::Struct(Style::Tuple, ref fields) | Body::Struct(Style::Newtype, ref fields) => { Data::Struct(Style::Tuple, ref fields) | Data::Struct(Style::Newtype, ref fields) => {
if fields.iter().any(|field| field.ident.is_some()) { if fields.iter().any(|field| field.ident.is_some()) {
panic!("tuple struct has named fields"); panic!("tuple struct has named fields");
} }
deserialize_tuple(None, params, fields, &cont.attrs, None) deserialize_tuple(None, params, fields, &cont.attrs, None)
} }
Body::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs), Data::Struct(Style::Unit, _) => deserialize_unit_struct(params, &cont.attrs),
} }
} else { } else {
match cont.body { match cont.data {
Body::Enum(ref variants) => { Data::Enum(ref variants) => {
deserialize_custom_identifier(params, variants, &cont.attrs) deserialize_custom_identifier(params, variants, &cont.attrs)
} }
Body::Struct(_, _) => unreachable!("checked in serde_derive_internals"), Data::Struct(_, _) => unreachable!("checked in serde_derive_internals"),
} }
} }
} }
@@ -250,21 +257,21 @@ fn deserialize_in_place_body(cont: &Container, params: &Parameters) -> Option<St
assert!(!params.has_getter); assert!(!params.has_getter);
if cont.attrs.from_type().is_some() || cont.attrs.identifier().is_some() if cont.attrs.from_type().is_some() || cont.attrs.identifier().is_some()
|| cont.body || cont.data
.all_fields() .all_fields()
.all(|f| f.attrs.deserialize_with().is_some()) .all(|f| f.attrs.deserialize_with().is_some())
{ {
return None; return None;
} }
let code = match cont.body { let code = match cont.data {
Body::Struct(Style::Struct, ref fields) => { Data::Struct(Style::Struct, ref fields) => {
deserialize_struct_in_place(None, params, fields, &cont.attrs, None, Untagged::No) deserialize_struct_in_place(None, params, fields, &cont.attrs, None, Untagged::No)
} }
Body::Struct(Style::Tuple, ref fields) | Body::Struct(Style::Newtype, ref fields) => { Data::Struct(Style::Tuple, ref fields) | Data::Struct(Style::Newtype, ref fields) => {
deserialize_tuple_in_place(None, params, fields, &cont.attrs, None) deserialize_tuple_in_place(None, params, fields, &cont.attrs, None)
} }
Body::Enum(_) | Body::Struct(Style::Unit, _) => { Data::Enum(_) | Data::Struct(Style::Unit, _) => {
return None; return None;
} }
}; };
@@ -288,7 +295,7 @@ fn deserialize_in_place_body(_cont: &Container, _params: &Parameters) -> Option<
None None
} }
fn deserialize_from(from_type: &syn::Ty) -> Fragment { fn deserialize_from(from_type: &syn::Type) -> Fragment {
quote_block! { quote_block! {
_serde::export::Result::map( _serde::export::Result::map(
<#from_type as _serde::Deserialize>::deserialize(__deserializer), <#from_type as _serde::Deserialize>::deserialize(__deserializer),
@@ -616,8 +623,8 @@ fn deserialize_seq_in_place(
// If there's no field name, assume we're a tuple-struct and use a numeric index // If there's no field name, assume we're a tuple-struct and use a numeric index
let field_name = field let field_name = field
.ident .ident
.clone() .map(Member::Named)
.unwrap_or_else(|| Ident::new(field_index.to_string())); .unwrap_or_else(|| Member::Unnamed(field_index.into()));
if field.attrs.skip_deserializing() { if field.attrs.skip_deserializing() {
let default = Expr(expr_is_missing(&field, cattrs)); let default = Expr(expr_is_missing(&field, cattrs));
@@ -1824,7 +1831,7 @@ fn deserialize_identifier(
fallthrough: Option<Tokens>, fallthrough: Option<Tokens>,
) -> Fragment { ) -> Fragment {
let field_strs = fields.iter().map(|&(ref name, _)| name); let field_strs = fields.iter().map(|&(ref name, _)| name);
let field_bytes = fields.iter().map(|&(ref name, _)| quote::ByteStr(name)); let field_bytes = fields.iter().map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));
let constructors: &Vec<_> = &fields let constructors: &Vec<_> = &fields
.iter() .iter()
@@ -2203,7 +2210,7 @@ fn deserialize_map_in_place(
// If missing_expr unconditionally returns an error, don't try // If missing_expr unconditionally returns an error, don't try
// to assign its value to self.place. Maybe this could be handled // to assign its value to self.place. Maybe this could be handled
// more elegantly. // more elegantly.
if missing_expr.as_ref().as_str().starts_with("return ") { if missing_expr.as_ref().into_tokens().to_string().starts_with("return ") {
let missing_expr = Stmts(missing_expr); let missing_expr = Stmts(missing_expr);
quote! { quote! {
if !#name { if !#name {
@@ -2252,7 +2259,7 @@ fn deserialize_map_in_place(
} }
fn field_i(i: usize) -> Ident { fn field_i(i: usize) -> Ident {
Ident::new(format!("__field{}", i)) Ident::new(&format!("__field{}", i), Span::def_site())
} }
/// This function wraps the expression in `#[serde(deserialize_with = "...")]` /// This function wraps the expression in `#[serde(deserialize_with = "...")]`
@@ -2294,7 +2301,7 @@ fn wrap_deserialize_with(
fn wrap_deserialize_field_with( fn wrap_deserialize_field_with(
params: &Parameters, params: &Parameters,
field_ty: &syn::Ty, field_ty: &syn::Type,
deserialize_with: &syn::Path, deserialize_with: &syn::Path,
) -> (Tokens, Tokens) { ) -> (Tokens, Tokens) {
wrap_deserialize_with(params, quote!(#field_ty), deserialize_with) wrap_deserialize_with(params, quote!(#field_ty), deserialize_with)
@@ -2312,7 +2319,7 @@ fn wrap_deserialize_variant_with(
let (wrapper, wrapper_ty) = let (wrapper, wrapper_ty) =
wrap_deserialize_with(params, quote!((#(#field_tys),*)), deserialize_with); wrap_deserialize_with(params, quote!((#(#field_tys),*)), deserialize_with);
let field_access = (0..variant.fields.len()).map(|n| Ident::new(format!("{}", n))); let field_access = (0..variant.fields.len()).map(|n| Member::Unnamed(n.into()));
let unwrap_fn = match variant.style { let unwrap_fn = match variant.style {
Style::Struct => { Style::Struct => {
let field_idents = variant let field_idents = variant
@@ -2385,7 +2392,10 @@ impl<'a> ToTokens for DeImplGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) { fn to_tokens(&self, tokens: &mut Tokens) {
let mut generics = self.0.generics.clone(); let mut generics = self.0.generics.clone();
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() { if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() {
generics.lifetimes.insert(0, de_lifetime); generics.params = Some(syn::GenericParam::Lifetime(de_lifetime))
.into_iter()
.chain(generics.params)
.collect();
} }
let (impl_generics, _, _) = generics.split_for_impl(); let (impl_generics, _, _) = generics.split_for_impl();
impl_generics.to_tokens(tokens); impl_generics.to_tokens(tokens);
@@ -2399,17 +2409,27 @@ impl<'a> ToTokens for InPlaceImplGenerics<'a> {
let mut generics = self.0.generics.clone(); let mut generics = self.0.generics.clone();
// Add lifetime for `&'place mut Self, and `'a: 'place` // Add lifetime for `&'place mut Self, and `'a: 'place`
for lifetime in &mut generics.lifetimes { for param in &mut generics.params {
lifetime.bounds.push(place_lifetime.lifetime.clone()); match *param {
syn::GenericParam::Lifetime(ref mut param) => {
param.bounds.push(place_lifetime.lifetime.clone());
}
syn::GenericParam::Type(ref mut param) => {
param.bounds
.push(syn::TypeParamBound::Lifetime(place_lifetime.lifetime.clone()));
}
syn::GenericParam::Const(_) => {}
}
} }
for generic in &mut generics.ty_params { generics.params = Some(syn::GenericParam::Lifetime(place_lifetime))
generic .into_iter()
.bounds .chain(generics.params)
.push(syn::TyParamBound::Region(place_lifetime.lifetime.clone())); .collect();
}
generics.lifetimes.insert(0, place_lifetime);
if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() { if let Some(de_lifetime) = self.0.borrowed.de_lifetime_def() {
generics.lifetimes.insert(0, de_lifetime); generics.params = Some(syn::GenericParam::Lifetime(de_lifetime))
.into_iter()
.chain(generics.params)
.collect();
} }
let (impl_generics, _, _) = generics.split_for_impl(); let (impl_generics, _, _) = generics.split_for_impl();
impl_generics.to_tokens(tokens); impl_generics.to_tokens(tokens);
@@ -2423,15 +2443,24 @@ impl<'a> DeImplGenerics<'a> {
} }
} }
struct DeTyGenerics<'a>(&'a Parameters); struct DeTypeGenerics<'a>(&'a Parameters);
#[cfg(feature = "deserialize_in_place")] #[cfg(feature = "deserialize_in_place")]
struct InPlaceTyGenerics<'a>(&'a Parameters); struct InPlaceTypeGenerics<'a>(&'a Parameters);
impl<'a> ToTokens for DeTyGenerics<'a> { impl<'a> ToTokens for DeTypeGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) { fn to_tokens(&self, tokens: &mut Tokens) {
let mut generics = self.0.generics.clone(); let mut generics = self.0.generics.clone();
if self.0.borrowed.de_lifetime_def().is_some() { if self.0.borrowed.de_lifetime_def().is_some() {
generics.lifetimes.insert(0, syn::LifetimeDef::new("'de")); let def = syn::LifetimeDef {
attrs: Vec::new(),
lifetime: syn::Lifetime::new(Term::intern("'de"), Span::def_site()),
colon_token: None,
bounds: Punctuated::new(),
};
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
} }
let (_, ty_generics, _) = generics.split_for_impl(); let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens); ty_generics.to_tokens(tokens);
@@ -2439,13 +2468,25 @@ impl<'a> ToTokens for DeTyGenerics<'a> {
} }
#[cfg(feature = "deserialize_in_place")] #[cfg(feature = "deserialize_in_place")]
impl<'a> ToTokens for InPlaceTyGenerics<'a> { impl<'a> ToTokens for InPlaceTypeGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) { fn to_tokens(&self, tokens: &mut Tokens) {
let mut generics = self.0.generics.clone(); let mut generics = self.0.generics.clone();
generics.lifetimes.insert(0, place_lifetime()); generics.params = Some(syn::GenericParam::Lifetime(place_lifetime()))
.into_iter()
.chain(generics.params)
.collect();
if self.0.borrowed.de_lifetime_def().is_some() { if self.0.borrowed.de_lifetime_def().is_some() {
generics.lifetimes.insert(0, syn::LifetimeDef::new("'de")); let def = syn::LifetimeDef {
attrs: Vec::new(),
lifetime: syn::Lifetime::new(Term::intern("'de"), Span::def_site()),
colon_token: None,
bounds: Punctuated::new(),
};
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
} }
let (_, ty_generics, _) = generics.split_for_impl(); let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens); ty_generics.to_tokens(tokens);
@@ -2453,27 +2494,32 @@ impl<'a> ToTokens for InPlaceTyGenerics<'a> {
} }
#[cfg(feature = "deserialize_in_place")] #[cfg(feature = "deserialize_in_place")]
impl<'a> DeTyGenerics<'a> { impl<'a> DeTypeGenerics<'a> {
fn in_place(self) -> InPlaceTyGenerics<'a> { fn in_place(self) -> InPlaceTypeGenerics<'a> {
InPlaceTyGenerics(self.0) InPlaceTypeGenerics(self.0)
} }
} }
#[cfg(feature = "deserialize_in_place")] #[cfg(feature = "deserialize_in_place")]
fn place_lifetime() -> syn::LifetimeDef { fn place_lifetime() -> syn::LifetimeDef {
syn::LifetimeDef::new("'place") syn::LifetimeDef {
attrs: Vec::new(),
lifetime: syn::Lifetime::new(Term::intern("'place"), Span::def_site()),
colon_token: None,
bounds: Punctuated::new(),
}
} }
fn split_with_de_lifetime( fn split_with_de_lifetime(
params: &Parameters, params: &Parameters,
) -> ( ) -> (
DeImplGenerics, DeImplGenerics,
DeTyGenerics, DeTypeGenerics,
syn::TyGenerics, syn::TypeGenerics,
&syn::WhereClause, Option<&syn::WhereClause>,
) { ) {
let de_impl_generics = DeImplGenerics(&params); let de_impl_generics = DeImplGenerics(&params);
let de_ty_generics = DeTyGenerics(&params); let de_ty_generics = DeTypeGenerics(&params);
let (_, ty_generics, where_clause) = params.generics.split_for_impl(); let (_, ty_generics, where_clause) = params.generics.split_for_impl();
(de_impl_generics, de_ty_generics, ty_generics, where_clause) (de_impl_generics, de_ty_generics, ty_generics, where_clause)
} }
+4 -7
View File
@@ -7,6 +7,7 @@
// except according to those terms. // except according to those terms.
use quote::{ToTokens, Tokens}; use quote::{ToTokens, Tokens};
use syn::token;
pub enum Fragment { pub enum Fragment {
/// Tokens that can be used as an expression. /// Tokens that can be used as an expression.
@@ -36,9 +37,7 @@ impl ToTokens for Expr {
match self.0 { match self.0 {
Fragment::Expr(ref expr) => expr.to_tokens(out), Fragment::Expr(ref expr) => expr.to_tokens(out),
Fragment::Block(ref block) => { Fragment::Block(ref block) => {
out.append("{"); token::Brace::default().surround(out, |out| block.to_tokens(out));
block.to_tokens(out);
out.append("}");
} }
} }
} }
@@ -63,12 +62,10 @@ impl ToTokens for Match {
match self.0 { match self.0 {
Fragment::Expr(ref expr) => { Fragment::Expr(ref expr) => {
expr.to_tokens(out); expr.to_tokens(out);
out.append(","); <Token![,]>::default().to_tokens(out);
} }
Fragment::Block(ref block) => { Fragment::Block(ref block) => {
out.append("{"); token::Brace::default().surround(out, |out| block.to_tokens(out));
block.to_tokens(out);
out.append("}");
} }
} }
} }
+9 -5
View File
@@ -26,16 +26,20 @@
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] #![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))] #![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
// The `quote!` macro requires deep recursion. // The `quote!` macro requires deep recursion.
#![recursion_limit = "192"] #![recursion_limit = "256"]
#[macro_use] #[macro_use]
extern crate quote; extern crate quote;
#[macro_use]
extern crate syn; extern crate syn;
extern crate serde_derive_internals as internals; extern crate serde_derive_internals as internals;
extern crate proc_macro; extern crate proc_macro;
extern crate proc_macro2;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use syn::DeriveInput;
#[macro_use] #[macro_use]
mod bound; mod bound;
@@ -47,18 +51,18 @@ mod de;
#[proc_macro_derive(Serialize, attributes(serde))] #[proc_macro_derive(Serialize, attributes(serde))]
pub fn derive_serialize(input: TokenStream) -> TokenStream { pub fn derive_serialize(input: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&input.to_string()).unwrap(); let input: DeriveInput = syn::parse(input).unwrap();
match ser::expand_derive_serialize(&input) { match ser::expand_derive_serialize(&input) {
Ok(expanded) => expanded.parse().unwrap(), Ok(expanded) => expanded.into(),
Err(msg) => panic!(msg), Err(msg) => panic!(msg),
} }
} }
#[proc_macro_derive(Deserialize, attributes(serde))] #[proc_macro_derive(Deserialize, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream { pub fn derive_deserialize(input: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&input.to_string()).unwrap(); let input: DeriveInput = syn::parse(input).unwrap();
match de::expand_derive_deserialize(&input) { match de::expand_derive_deserialize(&input) {
Ok(expanded) => expanded.parse().unwrap(), Ok(expanded) => expanded.into(),
Err(msg) => panic!(msg), Err(msg) => panic!(msg),
} }
} }
+30 -34
View File
@@ -6,12 +6,13 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use syn::{self, Ident}; use syn::{self, Ident, Member};
use quote::Tokens; use quote::Tokens;
use proc_macro2::Span;
use bound; use bound;
use fragment::{Fragment, Match, Stmts}; use fragment::{Fragment, Match, Stmts};
use internals::ast::{Body, Container, Field, Style, Variant}; use internals::ast::{Data, Container, Field, Style, Variant};
use internals::{attr, Ctxt}; use internals::{attr, Ctxt};
use std::u32; use std::u32;
@@ -25,7 +26,7 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<Tokens, Strin
let ident = &cont.ident; let ident = &cont.ident;
let params = Parameters::new(&cont); let params = Parameters::new(&cont);
let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = params.generics.split_for_impl();
let dummy_const = Ident::new(format!("_IMPL_SERIALIZE_FOR_{}", ident)); let dummy_const = Ident::new(&format!("_IMPL_SERIALIZE_FOR_{}", ident), Span::def_site());
let body = Stmts(serialize_body(&cont, &params)); let body = Stmts(serialize_body(&cont, &params));
let impl_block = if let Some(remote) = cont.attrs.remote() { let impl_block = if let Some(remote) = cont.attrs.remote() {
@@ -95,9 +96,9 @@ impl Parameters {
fn new(cont: &Container) -> Self { fn new(cont: &Container) -> Self {
let is_remote = cont.attrs.remote().is_some(); let is_remote = cont.attrs.remote().is_some();
let self_var = if is_remote { let self_var = if is_remote {
Ident::new("__self") Ident::new("__self", Span::def_site())
} else { } else {
Ident::new("self") Ident::new("self", Span::def_site())
}; };
let this = match cont.attrs.remote() { let this = match cont.attrs.remote() {
@@ -118,7 +119,7 @@ impl Parameters {
/// Type name to use in error messages and `&'static str` arguments to /// Type name to use in error messages and `&'static str` arguments to
/// various Serializer methods. /// various Serializer methods.
fn type_name(&self) -> &str { fn type_name(&self) -> &str {
self.this.segments.last().unwrap().ident.as_ref() self.this.segments.last().unwrap().value().ident.as_ref()
} }
} }
@@ -136,7 +137,7 @@ fn build_generics(cont: &Container) -> syn::Generics {
cont, cont,
&generics, &generics,
needs_serialize_bound, needs_serialize_bound,
&path!(_serde::Serialize), &parse_quote!(_serde::Serialize),
), ),
} }
} }
@@ -155,29 +156,29 @@ fn serialize_body(cont: &Container, params: &Parameters) -> Fragment {
if let Some(into_type) = cont.attrs.into_type() { if let Some(into_type) = cont.attrs.into_type() {
serialize_into(params, into_type) serialize_into(params, into_type)
} else { } else {
match cont.body { match cont.data {
Body::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs), Data::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs),
Body::Struct(Style::Struct, ref fields) => { Data::Struct(Style::Struct, ref fields) => {
if fields.iter().any(|field| field.ident.is_none()) { if fields.iter().any(|field| field.ident.is_none()) {
panic!("struct has unnamed fields"); panic!("struct has unnamed fields");
} }
serialize_struct(params, fields, &cont.attrs) serialize_struct(params, fields, &cont.attrs)
} }
Body::Struct(Style::Tuple, ref fields) => { Data::Struct(Style::Tuple, ref fields) => {
if fields.iter().any(|field| field.ident.is_some()) { if fields.iter().any(|field| field.ident.is_some()) {
panic!("tuple struct has named fields"); panic!("tuple struct has named fields");
} }
serialize_tuple_struct(params, fields, &cont.attrs) serialize_tuple_struct(params, fields, &cont.attrs)
} }
Body::Struct(Style::Newtype, ref fields) => { Data::Struct(Style::Newtype, ref fields) => {
serialize_newtype_struct(params, &fields[0], &cont.attrs) serialize_newtype_struct(params, &fields[0], &cont.attrs)
} }
Body::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs), Data::Struct(Style::Unit, _) => serialize_unit_struct(&cont.attrs),
} }
} }
} }
fn serialize_into(params: &Parameters, into_type: &syn::Ty) -> Fragment { fn serialize_into(params: &Parameters, into_type: &syn::Type) -> Fragment {
let self_var = &params.self_var; let self_var = &params.self_var;
quote_block! { quote_block! {
_serde::Serialize::serialize( _serde::Serialize::serialize(
@@ -201,7 +202,7 @@ fn serialize_newtype_struct(
) -> Fragment { ) -> Fragment {
let type_name = cattrs.name().serialize_name(); let type_name = cattrs.name().serialize_name();
let mut field_expr = get_field(params, field, 0); let mut field_expr = get_member(params, field, Member::Unnamed(0.into()));
if let Some(path) = field.attrs.serialize_with() { if let Some(path) = field.attrs.serialize_with() {
field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr); field_expr = wrap_serialize_field_with(params, field.ty, path, field_expr);
} }
@@ -259,7 +260,7 @@ fn serialize_struct(params: &Parameters, fields: &[Field], cattrs: &attr::Contai
None => quote!(1), None => quote!(1),
Some(path) => { Some(path) => {
let ident = field.ident.clone().expect("struct has unnamed fields"); let ident = field.ident.clone().expect("struct has unnamed fields");
let field_expr = get_field(params, field, ident); let field_expr = get_member(params, field, Member::Named(ident));
quote!(if #path(#field_expr) { 0 } else { 1 }) quote!(if #path(#field_expr) { 0 } else { 1 })
} }
}) })
@@ -333,7 +334,7 @@ fn serialize_variant(
} }
Style::Tuple => { Style::Tuple => {
let field_names = let field_names =
(0..variant.fields.len()).map(|i| Ident::new(format!("__field{}", i))); (0..variant.fields.len()).map(|i| Ident::new(&format!("__field{}", i), Span::def_site()));
quote! { quote! {
#this::#variant_ident(#(ref #field_names),*) #this::#variant_ident(#(ref #field_names),*)
} }
@@ -566,9 +567,9 @@ fn serialize_adjacently_tagged_variant(
unreachable!() unreachable!()
} }
} }
Style::Newtype => vec![Ident::new("__field0")], Style::Newtype => vec![Ident::new("__field0", Span::def_site())],
Style::Tuple => (0..variant.fields.len()) Style::Tuple => (0..variant.fields.len())
.map(|i| Ident::new(format!("__field{}", i))) .map(|i| Ident::new(&format!("__field{}", i), Span::def_site()))
.collect(), .collect(),
Style::Struct => variant Style::Struct => variant
.fields .fields
@@ -813,10 +814,10 @@ fn serialize_tuple_struct_visitor(
.enumerate() .enumerate()
.map(|(i, field)| { .map(|(i, field)| {
let mut field_expr = if is_enum { let mut field_expr = if is_enum {
let id = Ident::new(format!("__field{}", i)); let id = Ident::new(&format!("__field{}", i), Span::def_site());
quote!(#id) quote!(#id)
} else { } else {
get_field(params, field, i) get_member(params, field, Member::Unnamed(i.into()))
}; };
let skip = field let skip = field
@@ -855,7 +856,7 @@ fn serialize_struct_visitor(
let mut field_expr = if is_enum { let mut field_expr = if is_enum {
quote!(#field_ident) quote!(#field_ident)
} else { } else {
get_field(params, field, field_ident) get_member(params, field, Member::Named(field_ident))
}; };
let key_expr = field.attrs.name().serialize_name(); let key_expr = field.attrs.name().serialize_name();
@@ -891,7 +892,7 @@ fn serialize_struct_visitor(
fn wrap_serialize_field_with( fn wrap_serialize_field_with(
params: &Parameters, params: &Parameters,
field_ty: &syn::Ty, field_ty: &syn::Type,
serialize_with: &syn::Path, serialize_with: &syn::Path,
field_expr: Tokens, field_expr: Tokens,
) -> Tokens { ) -> Tokens {
@@ -912,7 +913,7 @@ fn wrap_serialize_variant_with(
let id = field let id = field
.ident .ident
.as_ref() .as_ref()
.map_or_else(|| Ident::new(format!("__field{}", i)), |id| id.clone()); .map_or_else(|| Ident::new(&format!("__field{}", i), Span::def_site()), |id| id.clone());
quote!(#id) quote!(#id)
}) })
.collect(); .collect();
@@ -927,7 +928,7 @@ fn wrap_serialize_variant_with(
fn wrap_serialize_with( fn wrap_serialize_with(
params: &Parameters, params: &Parameters,
serialize_with: &syn::Path, serialize_with: &syn::Path,
field_tys: &[&syn::Ty], field_tys: &[&syn::Type],
field_exprs: &[Tokens], field_exprs: &[Tokens],
) -> Tokens { ) -> Tokens {
let this = &params.this; let this = &params.this;
@@ -940,7 +941,7 @@ fn wrap_serialize_with(
}; };
let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl(); let (wrapper_impl_generics, wrapper_ty_generics, _) = wrapper_generics.split_for_impl();
let field_access = (0..field_exprs.len()).map(|n| Ident::new(format!("{}", n))); let field_access = (0..field_exprs.len()).map(|n| Member::Unnamed(n.into()));
quote!({ quote!({
struct __SerializeWith #wrapper_impl_generics #where_clause { struct __SerializeWith #wrapper_impl_generics #where_clause {
@@ -977,20 +978,15 @@ fn mut_if(is_mut: bool) -> Option<Tokens> {
} }
} }
fn get_field<I>(params: &Parameters, field: &Field, ident: I) -> Tokens fn get_member(params: &Parameters, field: &Field, member: Member) -> Tokens {
where
I: Into<Ident>,
{
let self_var = &params.self_var; let self_var = &params.self_var;
match (params.is_remote, field.attrs.getter()) { match (params.is_remote, field.attrs.getter()) {
(false, None) => { (false, None) => {
let ident = ident.into(); quote!(&#self_var.#member)
quote!(&#self_var.#ident)
} }
(true, None) => { (true, None) => {
let ty = field.ty; let ty = field.ty;
let ident = ident.into(); quote!(_serde::private::ser::constrain::<#ty>(&#self_var.#member))
quote!(_serde::private::ser::constrain::<#ty>(&#self_var.#ident))
} }
(true, Some(getter)) => { (true, Some(getter)) => {
let ty = field.ty; let ty = field.ty;
+1 -2
View File
@@ -12,8 +12,7 @@ readme = "README.md"
include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
[dependencies] [dependencies]
syn = { version = "0.11.10", default-features = false, features = ["parsing"] } syn = { version = "0.12", default-features = false, features = ["derive", "parsing", "clone-impls"] }
synom = "0.11"
[badges] [badges]
travis-ci = { repository = "serde-rs/serde" } travis-ci = { repository = "serde-rs/serde" }
+32 -28
View File
@@ -10,15 +10,16 @@ use syn;
use attr; use attr;
use check; use check;
use Ctxt; use Ctxt;
use syn::punctuated::Punctuated;
pub struct Container<'a> { pub struct Container<'a> {
pub ident: syn::Ident, pub ident: syn::Ident,
pub attrs: attr::Container, pub attrs: attr::Container,
pub body: Body<'a>, pub data: Data<'a>,
pub generics: &'a syn::Generics, pub generics: &'a syn::Generics,
} }
pub enum Body<'a> { pub enum Data<'a> {
Enum(Vec<Variant<'a>>), Enum(Vec<Variant<'a>>),
Struct(Style, Vec<Field<'a>>), Struct(Style, Vec<Field<'a>>),
} }
@@ -33,7 +34,7 @@ pub struct Variant<'a> {
pub struct Field<'a> { pub struct Field<'a> {
pub ident: Option<syn::Ident>, pub ident: Option<syn::Ident>,
pub attrs: attr::Field, pub attrs: attr::Field,
pub ty: &'a syn::Ty, pub ty: &'a syn::Type,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@@ -48,24 +49,27 @@ impl<'a> Container<'a> {
pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput) -> Container<'a> { pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput) -> Container<'a> {
let attrs = attr::Container::from_ast(cx, item); let attrs = attr::Container::from_ast(cx, item);
let mut body = match item.body { let mut data = match item.data {
syn::Body::Enum(ref variants) => { syn::Data::Enum(ref data) => {
Body::Enum(enum_from_ast(cx, variants, &attrs.default())) Data::Enum(enum_from_ast(cx, &data.variants, &attrs.default()))
} }
syn::Body::Struct(ref variant_data) => { syn::Data::Struct(ref data) => {
let (style, fields) = struct_from_ast(cx, variant_data, None, &attrs.default()); let (style, fields) = struct_from_ast(cx, &data.fields, None, &attrs.default());
Body::Struct(style, fields) Data::Struct(style, fields)
}
syn::Data::Union(_) => {
panic!("Serde does not support derive for unions");
} }
}; };
match body { match data {
Body::Enum(ref mut variants) => for ref mut variant in variants { Data::Enum(ref mut variants) => for ref mut variant in variants {
variant.attrs.rename_by_rule(attrs.rename_all()); variant.attrs.rename_by_rule(attrs.rename_all());
for ref mut field in &mut variant.fields { for ref mut field in &mut variant.fields {
field.attrs.rename_by_rule(variant.attrs.rename_all()); field.attrs.rename_by_rule(variant.attrs.rename_all());
} }
}, },
Body::Struct(_, ref mut fields) => for field in fields { Data::Struct(_, ref mut fields) => for field in fields {
field.attrs.rename_by_rule(attrs.rename_all()); field.attrs.rename_by_rule(attrs.rename_all());
}, },
} }
@@ -73,7 +77,7 @@ impl<'a> Container<'a> {
let item = Container { let item = Container {
ident: item.ident.clone(), ident: item.ident.clone(),
attrs: attrs, attrs: attrs,
body: body, data: data,
generics: &item.generics, generics: &item.generics,
}; };
check::check(cx, &item); check::check(cx, &item);
@@ -81,13 +85,13 @@ impl<'a> Container<'a> {
} }
} }
impl<'a> Body<'a> { impl<'a> Data<'a> {
pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> { pub fn all_fields(&'a self) -> Box<Iterator<Item = &'a Field<'a>> + 'a> {
match *self { match *self {
Body::Enum(ref variants) => { Data::Enum(ref variants) => {
Box::new(variants.iter().flat_map(|variant| variant.fields.iter())) Box::new(variants.iter().flat_map(|variant| variant.fields.iter()))
} }
Body::Struct(_, ref fields) => Box::new(fields.iter()), Data::Struct(_, ref fields) => Box::new(fields.iter()),
} }
} }
@@ -98,7 +102,7 @@ impl<'a> Body<'a> {
fn enum_from_ast<'a>( fn enum_from_ast<'a>(
cx: &Ctxt, cx: &Ctxt,
variants: &'a [syn::Variant], variants: &'a Punctuated<syn::Variant, Token![,]>,
container_default: &attr::Default, container_default: &attr::Default,
) -> Vec<Variant<'a>> { ) -> Vec<Variant<'a>> {
variants variants
@@ -106,7 +110,7 @@ fn enum_from_ast<'a>(
.map(|variant| { .map(|variant| {
let attrs = attr::Variant::from_ast(cx, variant); let attrs = attr::Variant::from_ast(cx, variant);
let (style, fields) = let (style, fields) =
struct_from_ast(cx, &variant.data, Some(&attrs), container_default); struct_from_ast(cx, &variant.fields, Some(&attrs), container_default);
Variant { Variant {
ident: variant.ident.clone(), ident: variant.ident.clone(),
attrs: attrs, attrs: attrs,
@@ -119,30 +123,30 @@ fn enum_from_ast<'a>(
fn struct_from_ast<'a>( fn struct_from_ast<'a>(
cx: &Ctxt, cx: &Ctxt,
data: &'a syn::VariantData, fields: &'a syn::Fields,
attrs: Option<&attr::Variant>, attrs: Option<&attr::Variant>,
container_default: &attr::Default, container_default: &attr::Default,
) -> (Style, Vec<Field<'a>>) { ) -> (Style, Vec<Field<'a>>) {
match *data { match *fields {
syn::VariantData::Struct(ref fields) => ( syn::Fields::Named(ref fields) => (
Style::Struct, Style::Struct,
fields_from_ast(cx, fields, attrs, container_default), fields_from_ast(cx, &fields.named, attrs, container_default),
), ),
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => ( syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => (
Style::Newtype, Style::Newtype,
fields_from_ast(cx, fields, attrs, container_default), fields_from_ast(cx, &fields.unnamed, attrs, container_default),
), ),
syn::VariantData::Tuple(ref fields) => ( syn::Fields::Unnamed(ref fields) => (
Style::Tuple, Style::Tuple,
fields_from_ast(cx, fields, attrs, container_default), fields_from_ast(cx, &fields.unnamed, attrs, container_default),
), ),
syn::VariantData::Unit => (Style::Unit, Vec::new()), syn::Fields::Unit => (Style::Unit, Vec::new()),
} }
} }
fn fields_from_ast<'a>( fn fields_from_ast<'a>(
cx: &Ctxt, cx: &Ctxt,
fields: &'a [syn::Field], fields: &'a Punctuated<syn::Field, Token![,]>,
attrs: Option<&attr::Variant>, attrs: Option<&attr::Variant>,
container_default: &attr::Default, container_default: &attr::Default,
) -> Vec<Field<'a>> { ) -> Vec<Field<'a>> {
+249 -194
View File
@@ -8,9 +8,10 @@
use Ctxt; use Ctxt;
use syn; use syn;
use syn::MetaItem::{List, NameValue, Word}; use syn::Meta::{List, NameValue, Word};
use syn::NestedMetaItem::{Literal, MetaItem}; use syn::NestedMeta::{Literal, Meta};
use synom::IResult; use syn::punctuated::Punctuated;
use syn::synom::Synom;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::str::FromStr; use std::str::FromStr;
@@ -81,7 +82,6 @@ impl<'c> BoolAttr<'c> {
} }
} }
#[derive(Debug)]
pub struct Name { pub struct Name {
serialize: String, serialize: String,
deserialize: String, deserialize: String,
@@ -100,7 +100,6 @@ impl Name {
} }
/// Represents container (e.g. struct) attribute information /// Represents container (e.g. struct) attribute information
#[derive(Debug)]
pub struct Container { pub struct Container {
name: Name, name: Name,
deny_unknown_fields: bool, deny_unknown_fields: bool,
@@ -109,14 +108,13 @@ pub struct Container {
ser_bound: Option<Vec<syn::WherePredicate>>, ser_bound: Option<Vec<syn::WherePredicate>>,
de_bound: Option<Vec<syn::WherePredicate>>, de_bound: Option<Vec<syn::WherePredicate>>,
tag: EnumTag, tag: EnumTag,
from_type: Option<syn::Ty>, from_type: Option<syn::Type>,
into_type: Option<syn::Ty>, into_type: Option<syn::Type>,
remote: Option<syn::Path>, remote: Option<syn::Path>,
identifier: Identifier, identifier: Identifier,
} }
/// Styles of representing an enum. /// Styles of representing an enum.
#[derive(Debug)]
pub enum EnumTag { pub enum EnumTag {
/// The default. /// The default.
/// ///
@@ -149,7 +147,7 @@ pub enum EnumTag {
/// Whether this enum represents the fields of a struct or the variants of an /// Whether this enum represents the fields of a struct or the variants of an
/// enum. /// enum.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone)]
pub enum Identifier { pub enum Identifier {
/// It does not. /// It does not.
No, No,
@@ -196,24 +194,24 @@ impl Container {
for meta_item in meta_items { for meta_item in meta_items {
match meta_item { match meta_item {
// Parse `#[serde(rename = "foo")]` // Parse `#[serde(rename = "foo")]`
MetaItem(NameValue(ref name, ref lit)) if name == "rename" => { Meta(NameValue(ref m)) if m.ident == "rename" => {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { if let Ok(s) = get_string_from_lit(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) {
ser_name.set(s.clone()); ser_name.set(s.clone());
de_name.set(s); de_name.set(s);
} }
} }
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
MetaItem(List(ref name, ref meta_items)) if name == "rename" => { Meta(List(ref m)) if m.ident == "rename" => {
if let Ok((ser, de)) = get_renames(cx, meta_items) { if let Ok((ser, de)) = get_renames(cx, &m.nested) {
ser_name.set_opt(ser); ser_name.set_opt(ser);
de_name.set_opt(de); de_name.set_opt(de);
} }
} }
// Parse `#[serde(rename_all = "foo")]` // Parse `#[serde(rename_all = "foo")]`
MetaItem(NameValue(ref name, ref lit)) if name == "rename_all" => { Meta(NameValue(ref m)) if m.ident == "rename_all" => {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { if let Ok(s) = get_string_from_lit(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) {
match RenameRule::from_str(&s) { match RenameRule::from_str(&s) {
Ok(rename_rule) => rename_all.set(rename_rule), Ok(rename_rule) => rename_all.set(rename_rule),
Err(()) => cx.error(format!( Err(()) => cx.error(format!(
@@ -226,13 +224,13 @@ impl Container {
} }
// Parse `#[serde(deny_unknown_fields)]` // Parse `#[serde(deny_unknown_fields)]`
MetaItem(Word(ref name)) if name == "deny_unknown_fields" => { Meta(Word(word)) if word == "deny_unknown_fields" => {
deny_unknown_fields.set_true(); deny_unknown_fields.set_true();
} }
// Parse `#[serde(default)]` // Parse `#[serde(default)]`
MetaItem(Word(ref name)) if name == "default" => match item.body { Meta(Word(word)) if word == "default" => match item.data {
syn::Body::Struct(syn::VariantData::Struct(_)) => { syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(_), .. }) => {
default.set(Default::Default); default.set(Default::Default);
} }
_ => cx.error( _ => cx.error(
@@ -242,10 +240,10 @@ impl Container {
}, },
// Parse `#[serde(default = "...")]` // Parse `#[serde(default = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "default" => { Meta(NameValue(ref m)) if m.ident == "default" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
match item.body { match item.data {
syn::Body::Struct(syn::VariantData::Struct(_)) => { syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(_), .. }) => {
default.set(Default::Path(path)); default.set(Default::Path(path));
} }
_ => cx.error( _ => cx.error(
@@ -257,9 +255,9 @@ impl Container {
} }
// Parse `#[serde(bound = "D: Serialize")]` // Parse `#[serde(bound = "D: Serialize")]`
MetaItem(NameValue(ref name, ref lit)) if name == "bound" => { Meta(NameValue(ref m)) if m.ident == "bound" => {
if let Ok(where_predicates) = if let Ok(where_predicates) =
parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) parse_lit_into_where(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit)
{ {
ser_bound.set(where_predicates.clone()); ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates); de_bound.set(where_predicates);
@@ -267,31 +265,31 @@ impl Container {
} }
// Parse `#[serde(bound(serialize = "D: Serialize", deserialize = "D: Deserialize"))]` // Parse `#[serde(bound(serialize = "D: Serialize", deserialize = "D: Deserialize"))]`
MetaItem(List(ref name, ref meta_items)) if name == "bound" => { Meta(List(ref m)) if m.ident == "bound" => {
if let Ok((ser, de)) = get_where_predicates(cx, meta_items) { if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) {
ser_bound.set_opt(ser); ser_bound.set_opt(ser);
de_bound.set_opt(de); de_bound.set_opt(de);
} }
} }
// Parse `#[serde(untagged)]` // Parse `#[serde(untagged)]`
MetaItem(Word(ref name)) if name == "untagged" => match item.body { Meta(Word(word)) if word == "untagged" => match item.data {
syn::Body::Enum(_) => { syn::Data::Enum(_) => {
untagged.set_true(); untagged.set_true();
} }
syn::Body::Struct(_) => { syn::Data::Struct(_) | syn::Data::Union(_) => {
cx.error("#[serde(untagged)] can only be used on enums") cx.error("#[serde(untagged)] can only be used on enums")
} }
}, },
// Parse `#[serde(tag = "type")]` // Parse `#[serde(tag = "type")]`
MetaItem(NameValue(ref name, ref lit)) if name == "tag" => { Meta(NameValue(ref m)) if m.ident == "tag" => {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { if let Ok(s) = get_string_from_lit(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) {
match item.body { match item.data {
syn::Body::Enum(_) => { syn::Data::Enum(_) => {
internal_tag.set(s); internal_tag.set(s);
} }
syn::Body::Struct(_) => { syn::Data::Struct(_) | syn::Data::Union(_) => {
cx.error("#[serde(tag = \"...\")] can only be used on enums") cx.error("#[serde(tag = \"...\")] can only be used on enums")
} }
} }
@@ -299,13 +297,13 @@ impl Container {
} }
// Parse `#[serde(content = "c")]` // Parse `#[serde(content = "c")]`
MetaItem(NameValue(ref name, ref lit)) if name == "content" => { Meta(NameValue(ref m)) if m.ident == "content" => {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { if let Ok(s) = get_string_from_lit(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) {
match item.body { match item.data {
syn::Body::Enum(_) => { syn::Data::Enum(_) => {
content.set(s); content.set(s);
} }
syn::Body::Struct(_) => cx.error( syn::Data::Struct(_) | syn::Data::Union(_) => cx.error(
"#[serde(content = \"...\")] can only be used on \ "#[serde(content = \"...\")] can only be used on \
enums", enums",
), ),
@@ -314,37 +312,37 @@ impl Container {
} }
// Parse `#[serde(from = "Type")] // Parse `#[serde(from = "Type")]
MetaItem(NameValue(ref name, ref lit)) if name == "from" => { Meta(NameValue(ref m)) if m.ident == "from" => {
if let Ok(from_ty) = parse_lit_into_ty(cx, name.as_ref(), lit) { if let Ok(from_ty) = parse_lit_into_ty(cx, m.ident.as_ref(), &m.lit) {
from_type.set_opt(Some(from_ty)); from_type.set_opt(Some(from_ty));
} }
} }
// Parse `#[serde(into = "Type")] // Parse `#[serde(into = "Type")]
MetaItem(NameValue(ref name, ref lit)) if name == "into" => { Meta(NameValue(ref m)) if m.ident == "into" => {
if let Ok(into_ty) = parse_lit_into_ty(cx, name.as_ref(), lit) { if let Ok(into_ty) = parse_lit_into_ty(cx, m.ident.as_ref(), &m.lit) {
into_type.set_opt(Some(into_ty)); into_type.set_opt(Some(into_ty));
} }
} }
// Parse `#[serde(remote = "...")]` // Parse `#[serde(remote = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "remote" => { Meta(NameValue(ref m)) if m.ident == "remote" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
remote.set(path); remote.set(path);
} }
} }
// Parse `#[serde(field_identifier)]` // Parse `#[serde(field_identifier)]`
MetaItem(Word(ref name)) if name == "field_identifier" => { Meta(Word(word)) if word == "field_identifier" => {
field_identifier.set_true(); field_identifier.set_true();
} }
// Parse `#[serde(variant_identifier)]` // Parse `#[serde(variant_identifier)]`
MetaItem(Word(ref name)) if name == "variant_identifier" => { Meta(Word(word)) if word == "variant_identifier" => {
variant_identifier.set_true(); variant_identifier.set_true();
} }
MetaItem(ref meta_item) => { Meta(ref meta_item) => {
cx.error(format!( cx.error(format!(
"unknown serde container attribute `{}`", "unknown serde container attribute `{}`",
meta_item.name() meta_item.name()
@@ -404,11 +402,11 @@ impl Container {
&self.tag &self.tag
} }
pub fn from_type(&self) -> Option<&syn::Ty> { pub fn from_type(&self) -> Option<&syn::Type> {
self.from_type.as_ref() self.from_type.as_ref()
} }
pub fn into_type(&self) -> Option<&syn::Ty> { pub fn into_type(&self) -> Option<&syn::Type> {
self.into_type.as_ref() self.into_type.as_ref()
} }
@@ -433,12 +431,12 @@ fn decide_tag(
(true, None, None) => EnumTag::None, (true, None, None) => EnumTag::None,
(false, Some(tag), None) => { (false, Some(tag), None) => {
// Check that there are no tuple variants. // Check that there are no tuple variants.
if let syn::Body::Enum(ref variants) = item.body { if let syn::Data::Enum(ref data) = item.data {
for variant in variants { for variant in &data.variants {
match variant.data { match variant.fields {
syn::VariantData::Struct(_) | syn::VariantData::Unit => {} syn::Fields::Named(_) | syn::Fields::Unit => {}
syn::VariantData::Tuple(ref fields) => { syn::Fields::Unnamed(ref fields) => {
if fields.len() != 1 { if fields.unnamed.len() != 1 {
cx.error( cx.error(
"#[serde(tag = \"...\")] cannot be used with tuple \ "#[serde(tag = \"...\")] cannot be used with tuple \
variants", variants",
@@ -480,27 +478,28 @@ fn decide_identifier(
field_identifier: BoolAttr, field_identifier: BoolAttr,
variant_identifier: BoolAttr, variant_identifier: BoolAttr,
) -> Identifier { ) -> Identifier {
match (&item.body, field_identifier.get(), variant_identifier.get()) { match (&item.data, field_identifier.get(), variant_identifier.get()) {
(_, false, false) => Identifier::No, (_, false, false) => Identifier::No,
(_, true, true) => { (_, true, true) => {
cx.error("`field_identifier` and `variant_identifier` cannot both be set"); cx.error("`field_identifier` and `variant_identifier` cannot both be set");
Identifier::No Identifier::No
} }
(&syn::Body::Struct(_), true, false) => { (&syn::Data::Enum(_), true, false) => Identifier::Field,
(&syn::Data::Enum(_), false, true) => Identifier::Variant,
(&syn::Data::Struct(_), true, false)
| (&syn::Data::Union(_), true, false) => {
cx.error("`field_identifier` can only be used on an enum"); cx.error("`field_identifier` can only be used on an enum");
Identifier::No Identifier::No
} }
(&syn::Body::Struct(_), false, true) => { (&syn::Data::Struct(_), false, true)
| (&syn::Data::Union(_), false, true) => {
cx.error("`variant_identifier` can only be used on an enum"); cx.error("`variant_identifier` can only be used on an enum");
Identifier::No Identifier::No
} }
(&syn::Body::Enum(_), true, false) => Identifier::Field,
(&syn::Body::Enum(_), false, true) => Identifier::Variant,
} }
} }
/// Represents variant attribute information /// Represents variant attribute information
#[derive(Debug)]
pub struct Variant { pub struct Variant {
name: Name, name: Name,
ser_renamed: bool, ser_renamed: bool,
@@ -511,7 +510,7 @@ pub struct Variant {
other: bool, other: bool,
serialize_with: Option<syn::Path>, serialize_with: Option<syn::Path>,
deserialize_with: Option<syn::Path>, deserialize_with: Option<syn::Path>,
borrow: Option<syn::MetaItem>, borrow: Option<syn::Meta>,
} }
impl Variant { impl Variant {
@@ -530,24 +529,24 @@ impl Variant {
for meta_item in meta_items { for meta_item in meta_items {
match meta_item { match meta_item {
// Parse `#[serde(rename = "foo")]` // Parse `#[serde(rename = "foo")]`
MetaItem(NameValue(ref name, ref lit)) if name == "rename" => { Meta(NameValue(ref m)) if m.ident == "rename" => {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { if let Ok(s) = get_string_from_lit(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) {
ser_name.set(s.clone()); ser_name.set(s.clone());
de_name.set(s); de_name.set(s);
} }
} }
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
MetaItem(List(ref name, ref meta_items)) if name == "rename" => { Meta(List(ref m)) if m.ident == "rename" => {
if let Ok((ser, de)) = get_renames(cx, meta_items) { if let Ok((ser, de)) = get_renames(cx, &m.nested) {
ser_name.set_opt(ser); ser_name.set_opt(ser);
de_name.set_opt(de); de_name.set_opt(de);
} }
} }
// Parse `#[serde(rename_all = "foo")]` // Parse `#[serde(rename_all = "foo")]`
MetaItem(NameValue(ref name, ref lit)) if name == "rename_all" => { Meta(NameValue(ref m)) if m.ident == "rename_all" => {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { if let Ok(s) = get_string_from_lit(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) {
match RenameRule::from_str(&s) { match RenameRule::from_str(&s) {
Ok(rename_rule) => rename_all.set(rename_rule), Ok(rename_rule) => rename_all.set(rename_rule),
Err(()) => cx.error(format!( Err(()) => cx.error(format!(
@@ -560,23 +559,23 @@ impl Variant {
} }
// Parse `#[serde(skip_deserializing)]` // Parse `#[serde(skip_deserializing)]`
MetaItem(Word(ref name)) if name == "skip_deserializing" => { Meta(Word(word)) if word == "skip_deserializing" => {
skip_deserializing.set_true(); skip_deserializing.set_true();
} }
// Parse `#[serde(skip_serializing)]` // Parse `#[serde(skip_serializing)]`
MetaItem(Word(ref name)) if name == "skip_serializing" => { Meta(Word(word)) if word == "skip_serializing" => {
skip_serializing.set_true(); skip_serializing.set_true();
} }
// Parse `#[serde(other)]` // Parse `#[serde(other)]`
MetaItem(Word(ref name)) if name == "other" => { Meta(Word(word)) if word == "other" => {
other.set_true(); other.set_true();
} }
// Parse `#[serde(with = "...")]` // Parse `#[serde(with = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "with" => { Meta(NameValue(ref m)) if m.ident == "with" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
let mut ser_path = path.clone(); let mut ser_path = path.clone();
ser_path.segments.push("serialize".into()); ser_path.segments.push("serialize".into());
serialize_with.set(ser_path); serialize_with.set(ser_path);
@@ -587,30 +586,30 @@ impl Variant {
} }
// Parse `#[serde(serialize_with = "...")]` // Parse `#[serde(serialize_with = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "serialize_with" => { Meta(NameValue(ref m)) if m.ident == "serialize_with" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
serialize_with.set(path); serialize_with.set(path);
} }
} }
// Parse `#[serde(deserialize_with = "...")]` // Parse `#[serde(deserialize_with = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "deserialize_with" => { Meta(NameValue(ref m)) if m.ident == "deserialize_with" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
deserialize_with.set(path); deserialize_with.set(path);
} }
} }
// Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]` // Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]`
MetaItem(ref mi) if mi.name() == "borrow" => match variant.data { Meta(ref m) if m.name() == "borrow" => match variant.fields {
syn::VariantData::Tuple(ref fields) if fields.len() == 1 => { syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => {
borrow.set(mi.clone()); borrow.set(m.clone());
} }
_ => { _ => {
cx.error("#[serde(borrow)] may only be used on newtype variants"); cx.error("#[serde(borrow)] may only be used on newtype variants");
} }
}, },
MetaItem(ref meta_item) => { Meta(ref meta_item) => {
cx.error(format!( cx.error(format!(
"unknown serde variant attribute `{}`", "unknown serde variant attribute `{}`",
meta_item.name() meta_item.name()
@@ -684,7 +683,6 @@ impl Variant {
} }
/// Represents field attribute information /// Represents field attribute information
#[derive(Debug)]
pub struct Field { pub struct Field {
name: Name, name: Name,
ser_renamed: bool, ser_renamed: bool,
@@ -702,7 +700,6 @@ pub struct Field {
} }
/// Represents the default to use for a field when deserializing. /// Represents the default to use for a field when deserializing.
#[derive(Debug, PartialEq)]
pub enum Default { pub enum Default {
/// Field must always be specified because it does not have a default. /// Field must always be specified because it does not have a default.
None, None,
@@ -743,7 +740,7 @@ impl Field {
.map(|variant| &variant.borrow) .map(|variant| &variant.borrow)
.unwrap_or(&None) .unwrap_or(&None)
.as_ref() .as_ref()
.map(|borrow| vec![MetaItem(borrow.clone())]); .map(|borrow| vec![Meta(borrow.clone())]);
for meta_items in field for meta_items in field
.attrs .attrs
@@ -754,73 +751,73 @@ impl Field {
for meta_item in meta_items { for meta_item in meta_items {
match meta_item { match meta_item {
// Parse `#[serde(rename = "foo")]` // Parse `#[serde(rename = "foo")]`
MetaItem(NameValue(ref name, ref lit)) if name == "rename" => { Meta(NameValue(ref m)) if m.ident == "rename" => {
if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { if let Ok(s) = get_string_from_lit(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) {
ser_name.set(s.clone()); ser_name.set(s.clone());
de_name.set(s); de_name.set(s);
} }
} }
// Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]`
MetaItem(List(ref name, ref meta_items)) if name == "rename" => { Meta(List(ref m)) if m.ident == "rename" => {
if let Ok((ser, de)) = get_renames(cx, meta_items) { if let Ok((ser, de)) = get_renames(cx, &m.nested) {
ser_name.set_opt(ser); ser_name.set_opt(ser);
de_name.set_opt(de); de_name.set_opt(de);
} }
} }
// Parse `#[serde(default)]` // Parse `#[serde(default)]`
MetaItem(Word(ref name)) if name == "default" => { Meta(Word(word)) if word == "default" => {
default.set(Default::Default); default.set(Default::Default);
} }
// Parse `#[serde(default = "...")]` // Parse `#[serde(default = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "default" => { Meta(NameValue(ref m)) if m.ident == "default" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
default.set(Default::Path(path)); default.set(Default::Path(path));
} }
} }
// Parse `#[serde(skip_serializing)]` // Parse `#[serde(skip_serializing)]`
MetaItem(Word(ref name)) if name == "skip_serializing" => { Meta(Word(word)) if word == "skip_serializing" => {
skip_serializing.set_true(); skip_serializing.set_true();
} }
// Parse `#[serde(skip_deserializing)]` // Parse `#[serde(skip_deserializing)]`
MetaItem(Word(ref name)) if name == "skip_deserializing" => { Meta(Word(word)) if word == "skip_deserializing" => {
skip_deserializing.set_true(); skip_deserializing.set_true();
} }
// Parse `#[serde(skip)]` // Parse `#[serde(skip)]`
MetaItem(Word(ref name)) if name == "skip" => { Meta(Word(word)) if word == "skip" => {
skip_serializing.set_true(); skip_serializing.set_true();
skip_deserializing.set_true(); skip_deserializing.set_true();
} }
// Parse `#[serde(skip_serializing_if = "...")]` // Parse `#[serde(skip_serializing_if = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "skip_serializing_if" => { Meta(NameValue(ref m)) if m.ident == "skip_serializing_if" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
skip_serializing_if.set(path); skip_serializing_if.set(path);
} }
} }
// Parse `#[serde(serialize_with = "...")]` // Parse `#[serde(serialize_with = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "serialize_with" => { Meta(NameValue(ref m)) if m.ident == "serialize_with" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
serialize_with.set(path); serialize_with.set(path);
} }
} }
// Parse `#[serde(deserialize_with = "...")]` // Parse `#[serde(deserialize_with = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "deserialize_with" => { Meta(NameValue(ref m)) if m.ident == "deserialize_with" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
deserialize_with.set(path); deserialize_with.set(path);
} }
} }
// Parse `#[serde(with = "...")]` // Parse `#[serde(with = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "with" => { Meta(NameValue(ref m)) if m.ident == "with" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
let mut ser_path = path.clone(); let mut ser_path = path.clone();
ser_path.segments.push("serialize".into()); ser_path.segments.push("serialize".into());
serialize_with.set(ser_path); serialize_with.set(ser_path);
@@ -831,9 +828,9 @@ impl Field {
} }
// Parse `#[serde(bound = "D: Serialize")]` // Parse `#[serde(bound = "D: Serialize")]`
MetaItem(NameValue(ref name, ref lit)) if name == "bound" => { Meta(NameValue(ref m)) if m.ident == "bound" => {
if let Ok(where_predicates) = if let Ok(where_predicates) =
parse_lit_into_where(cx, name.as_ref(), name.as_ref(), lit) parse_lit_into_where(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit)
{ {
ser_bound.set(where_predicates.clone()); ser_bound.set(where_predicates.clone());
de_bound.set(where_predicates); de_bound.set(where_predicates);
@@ -841,29 +838,29 @@ impl Field {
} }
// Parse `#[serde(bound(serialize = "D: Serialize", deserialize = "D: Deserialize"))]` // Parse `#[serde(bound(serialize = "D: Serialize", deserialize = "D: Deserialize"))]`
MetaItem(List(ref name, ref meta_items)) if name == "bound" => { Meta(List(ref m)) if m.ident == "bound" => {
if let Ok((ser, de)) = get_where_predicates(cx, meta_items) { if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) {
ser_bound.set_opt(ser); ser_bound.set_opt(ser);
de_bound.set_opt(de); de_bound.set_opt(de);
} }
} }
// Parse `#[serde(borrow)]` // Parse `#[serde(borrow)]`
MetaItem(Word(ref name)) if name == "borrow" => { Meta(Word(word)) if word == "borrow" => {
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) { if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) {
borrowed_lifetimes.set(borrowable); borrowed_lifetimes.set(borrowable);
} }
} }
// Parse `#[serde(borrow = "'a + 'b")]` // Parse `#[serde(borrow = "'a + 'b")]`
MetaItem(NameValue(ref name, ref lit)) if name == "borrow" => { Meta(NameValue(ref m)) if m.ident == "borrow" => {
if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, name.as_ref(), lit) { if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, m.ident.as_ref(), &m.lit) {
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) { if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, &field.ty) {
for lifetime in &lifetimes { for lifetime in &lifetimes {
if !borrowable.contains(lifetime) { if !borrowable.contains(lifetime) {
cx.error(format!( cx.error(format!(
"field `{}` does not have lifetime {}", "field `{}` does not have lifetime {}",
ident, lifetime.ident ident, lifetime
)); ));
} }
} }
@@ -873,13 +870,13 @@ impl Field {
} }
// Parse `#[serde(getter = "...")]` // Parse `#[serde(getter = "...")]`
MetaItem(NameValue(ref name, ref lit)) if name == "getter" => { Meta(NameValue(ref m)) if m.ident == "getter" => {
if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) {
getter.set(path); getter.set(path);
} }
} }
MetaItem(ref meta_item) => { Meta(ref meta_item) => {
cx.error(format!( cx.error(format!(
"unknown serde field attribute `{}`", "unknown serde field attribute `{}`",
meta_item.name() meta_item.name()
@@ -896,8 +893,10 @@ impl Field {
// Is skip_deserializing, initialize the field to Default::default() unless a different // Is skip_deserializing, initialize the field to Default::default() unless a different
// default is specified by `#[serde(default = "...")]` on ourselves or our container (e.g. // default is specified by `#[serde(default = "...")]` on ourselves or our container (e.g.
// the struct we are in). // the struct we are in).
if container_default == &Default::None && skip_deserializing.0.value.is_some() { if let Default::None = *container_default {
default.set_if_none(Default::Default); if skip_deserializing.0.value.is_some() {
default.set_if_none(Default::Default);
}
} }
let mut borrowed_lifetimes = borrowed_lifetimes.get().unwrap_or_default(); let mut borrowed_lifetimes = borrowed_lifetimes.get().unwrap_or_default();
@@ -911,14 +910,14 @@ impl Field {
// //
// impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, str> // impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, str>
// impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, [u8]> // impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, [u8]>
if is_cow(&field.ty, "str") { if is_cow(&field.ty, is_str) {
let path = syn::parse_path("_serde::private::de::borrow_cow_str").unwrap(); let path = syn::parse_str("_serde::private::de::borrow_cow_str").unwrap();
deserialize_with.set_if_none(path); deserialize_with.set_if_none(path);
} else if is_cow(&field.ty, "[u8]") { } else if is_cow(&field.ty, is_slice_u8) {
let path = syn::parse_path("_serde::private::de::borrow_cow_bytes").unwrap(); let path = syn::parse_str("_serde::private::de::borrow_cow_bytes").unwrap();
deserialize_with.set_if_none(path); deserialize_with.set_if_none(path);
} }
} else if is_rptr(&field.ty, "str") || is_rptr(&field.ty, "[u8]") { } else if is_rptr(&field.ty, is_str) || is_rptr(&field.ty, is_slice_u8) {
// Types &str and &[u8] are always implicitly borrowed. No need for // Types &str and &[u8] are always implicitly borrowed. No need for
// a #[serde(borrow)]. // a #[serde(borrow)].
borrowed_lifetimes = borrowable_lifetimes(cx, &ident, &field.ty).unwrap(); borrowed_lifetimes = borrowable_lifetimes(cx, &ident, &field.ty).unwrap();
@@ -1007,26 +1006,26 @@ type SerAndDe<T> = (Option<T>, Option<T>);
fn get_ser_and_de<T, F>( fn get_ser_and_de<T, F>(
cx: &Ctxt, cx: &Ctxt,
attr_name: &'static str, attr_name: &'static str,
items: &[syn::NestedMetaItem], metas: &Punctuated<syn::NestedMeta, Token![,]>,
f: F, f: F,
) -> Result<SerAndDe<T>, ()> ) -> Result<SerAndDe<T>, ()>
where where
F: Fn(&Ctxt, &str, &str, &syn::Lit) -> Result<T, ()>, F: Fn(&Ctxt, &str, &str, &syn::Lit) -> Result<T, ()>,
{ {
let mut ser_item = Attr::none(cx, attr_name); let mut ser_meta = Attr::none(cx, attr_name);
let mut de_item = Attr::none(cx, attr_name); let mut de_meta = Attr::none(cx, attr_name);
for item in items { for meta in metas {
match *item { match *meta {
MetaItem(NameValue(ref name, ref lit)) if name == "serialize" => { Meta(NameValue(ref meta)) if meta.ident == "serialize" => {
if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) { if let Ok(v) = f(cx, attr_name, meta.ident.as_ref(), &meta.lit) {
ser_item.set(v); ser_meta.set(v);
} }
} }
MetaItem(NameValue(ref name, ref lit)) if name == "deserialize" => { Meta(NameValue(ref meta)) if meta.ident == "deserialize" => {
if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) { if let Ok(v) = f(cx, attr_name, meta.ident.as_ref(), &meta.lit) {
de_item.set(v); de_meta.set(v);
} }
} }
@@ -1041,24 +1040,31 @@ where
} }
} }
Ok((ser_item.get(), de_item.get())) Ok((ser_meta.get(), de_meta.get()))
} }
fn get_renames(cx: &Ctxt, items: &[syn::NestedMetaItem]) -> Result<SerAndDe<String>, ()> { fn get_renames(cx: &Ctxt, items: &Punctuated<syn::NestedMeta, Token![,]>) -> Result<SerAndDe<String>, ()> {
get_ser_and_de(cx, "rename", items, get_string_from_lit) get_ser_and_de(cx, "rename", items, get_string_from_lit)
} }
fn get_where_predicates( fn get_where_predicates(
cx: &Ctxt, cx: &Ctxt,
items: &[syn::NestedMetaItem], items: &Punctuated<syn::NestedMeta, Token![,]>,
) -> Result<SerAndDe<Vec<syn::WherePredicate>>, ()> { ) -> Result<SerAndDe<Vec<syn::WherePredicate>>, ()> {
get_ser_and_de(cx, "bound", items, parse_lit_into_where) get_ser_and_de(cx, "bound", items, parse_lit_into_where)
} }
pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option<Vec<syn::NestedMetaItem>> { pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option<Vec<syn::NestedMeta>> {
match attr.value { if attr.path.segments.len() == 1 && attr.path.segments[0].ident == "serde" {
List(ref name, ref items) if name == "serde" => Some(items.iter().cloned().collect()), match attr.interpret_meta() {
_ => None, Some(List(ref meta)) => Some(meta.nested.iter().cloned().collect()),
_ => {
// TODO: produce an error
None
}
}
} else {
None
} }
} }
@@ -1068,8 +1074,8 @@ fn get_string_from_lit(
meta_item_name: &str, meta_item_name: &str,
lit: &syn::Lit, lit: &syn::Lit,
) -> Result<String, ()> { ) -> Result<String, ()> {
if let syn::Lit::Str(ref s, _) = *lit { if let syn::Lit::Str(ref lit) = *lit {
Ok(s.clone()) Ok(lit.value())
} else { } else {
cx.error(format!( cx.error(format!(
"expected serde {} attribute to be a string: `{} = \"...\"`", "expected serde {} attribute to be a string: `{} = \"...\"`",
@@ -1081,7 +1087,7 @@ fn get_string_from_lit(
fn parse_lit_into_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::Path, ()> { fn parse_lit_into_path(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::Path, ()> {
let string = try!(get_string_from_lit(cx, attr_name, attr_name, lit)); let string = try!(get_string_from_lit(cx, attr_name, attr_name, lit));
syn::parse_path(&string).map_err(|err| cx.error(err)) syn::parse_str(&string).map_err(|_| cx.error(format!("failed to parse path: {:?}", string)))
} }
fn parse_lit_into_where( fn parse_lit_into_where(
@@ -1097,15 +1103,15 @@ fn parse_lit_into_where(
let where_string = format!("where {}", string); let where_string = format!("where {}", string);
syn::parse_where_clause(&where_string) syn::parse_str::<syn::WhereClause>(&where_string)
.map(|wh| wh.predicates) .map(|wh| wh.predicates.into_iter().collect())
.map_err(|err| cx.error(err)) .map_err(|err| cx.error(err))
} }
fn parse_lit_into_ty(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::Ty, ()> { fn parse_lit_into_ty(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result<syn::Type, ()> {
let string = try!(get_string_from_lit(cx, attr_name, attr_name, lit)); let string = try!(get_string_from_lit(cx, attr_name, attr_name, lit));
syn::parse_type(&string).map_err(|_| { syn::parse_str(&string).map_err(|_| {
cx.error(format!( cx.error(format!(
"failed to parse type: {} = {:?}", "failed to parse type: {} = {:?}",
attr_name, string attr_name, string
@@ -1126,20 +1132,23 @@ fn parse_lit_into_lifetimes(
return Err(()); return Err(());
} }
named!(lifetimes -> Vec<syn::Lifetime>, struct BorrowedLifetimes(Punctuated<syn::Lifetime, Token![+]>);
separated_nonempty_list!(punct!("+"), syn::parse::lifetime)
);
if let IResult::Done(rest, o) = lifetimes(&string) { impl Synom for BorrowedLifetimes {
if rest.trim().is_empty() { named!(parse -> Self, map!(
let mut set = BTreeSet::new(); call!(Punctuated::parse_separated_nonempty),
for lifetime in o { BorrowedLifetimes
if !set.insert(lifetime.clone()) { ));
cx.error(format!("duplicate borrowed lifetime `{}`", lifetime.ident)); }
}
if let Ok(BorrowedLifetimes(lifetimes)) = syn::parse_str(&string) {
let mut set = BTreeSet::new();
for lifetime in lifetimes {
if !set.insert(lifetime.clone()) {
cx.error(format!("duplicate borrowed lifetime `{}`", lifetime));
} }
return Ok(set);
} }
return Ok(set);
} }
Err(cx.error(format!("failed to parse borrowed lifetimes: {:?}", string))) Err(cx.error(format!("failed to parse borrowed lifetimes: {:?}", string)))
} }
@@ -1166,27 +1175,33 @@ fn parse_lit_into_lifetimes(
// #[serde(borrow)] // #[serde(borrow)]
// cow: Cow<'a, str>, // cow: Cow<'a, str>,
// } // }
fn is_cow(ty: &syn::Ty, elem: &str) -> bool { fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
let path = match *ty { let path = match *ty {
syn::Ty::Path(None, ref path) => path, syn::Type::Path(ref ty) => &ty.path,
_ => { _ => {
return false; return false;
} }
}; };
let seg = match path.segments.last() { let seg = match path.segments.last() {
Some(seg) => seg, Some(seg) => seg.into_value(),
None => { None => {
return false; return false;
} }
}; };
let params = match seg.parameters { let args = match seg.arguments {
syn::PathParameters::AngleBracketed(ref params) => params, syn::PathArguments::AngleBracketed(ref bracketed) => &bracketed.args,
_ => { _ => {
return false; return false;
} }
}; };
seg.ident == "Cow" && params.lifetimes.len() == 1 seg.ident == "Cow"
&& params.types == vec![syn::parse_type(elem).unwrap()] && params.bindings.is_empty() && args.len() == 2
&& match (&args[0], &args[1]) {
(&syn::GenericArgument::Lifetime(_), &syn::GenericArgument::Type(ref arg)) => {
elem(arg)
}
_ => false,
}
} }
// Whether the type looks like it might be `&T` where elem="T". This can have // Whether the type looks like it might be `&T` where elem="T". This can have
@@ -1209,11 +1224,34 @@ fn is_cow(ty: &syn::Ty, elem: &str) -> bool {
// struct S<'a> { // struct S<'a> {
// r: &'a str, // r: &'a str,
// } // }
fn is_rptr(ty: &syn::Ty, elem: &str) -> bool { fn is_rptr(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
match *ty { match *ty {
syn::Ty::Rptr(Some(_), ref mut_ty) => { syn::Type::Reference(ref ty) => {
mut_ty.mutability == syn::Mutability::Immutable ty.mutability.is_none() && elem(&ty.elem)
&& mut_ty.ty == syn::parse_type(elem).unwrap() }
_ => false,
}
}
fn is_str(ty: &syn::Type) -> bool {
is_primitive_path(ty, "str")
}
fn is_slice_u8(ty: &syn::Type) -> bool {
match *ty {
syn::Type::Slice(ref ty) => is_primitive_path(&ty.elem, "u8"),
_ => false,
}
}
fn is_primitive_path(ty: &syn::Type, primitive: &str) -> bool {
match *ty {
syn::Type::Path(ref ty) => {
ty.qself.is_none()
&& ty.path.leading_colon.is_none()
&& ty.path.segments.len() == 1
&& ty.path.segments[0].ident == primitive
&& ty.path.segments[0].arguments.is_empty()
} }
_ => false, _ => false,
} }
@@ -1229,7 +1267,7 @@ fn is_rptr(ty: &syn::Ty, elem: &str) -> bool {
fn borrowable_lifetimes( fn borrowable_lifetimes(
cx: &Ctxt, cx: &Ctxt,
name: &str, name: &str,
ty: &syn::Ty, ty: &syn::Type,
) -> 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(ty, &mut lifetimes);
@@ -1240,42 +1278,59 @@ fn borrowable_lifetimes(
} }
} }
fn collect_lifetimes(ty: &syn::Ty, out: &mut BTreeSet<syn::Lifetime>) { fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet<syn::Lifetime>) {
match *ty { match *ty {
syn::Ty::Slice(ref elem) | syn::Ty::Array(ref elem, _) | syn::Ty::Paren(ref elem) => { syn::Type::Slice(ref ty) => {
collect_lifetimes(elem, out); collect_lifetimes(&ty.elem, out);
} }
syn::Ty::Ptr(ref elem) => { syn::Type::Array(ref ty) => {
collect_lifetimes(&elem.ty, out); collect_lifetimes(&ty.elem, out);
} }
syn::Ty::Rptr(ref lifetime, ref elem) => { syn::Type::Ptr(ref ty) => {
out.extend(lifetime.iter().cloned()); collect_lifetimes(&ty.elem, out);
collect_lifetimes(&elem.ty, out);
} }
syn::Ty::Tup(ref elems) => for elem in elems { syn::Type::Reference(ref ty) => {
out.extend(ty.lifetime.iter().cloned());
collect_lifetimes(&ty.elem, out);
}
syn::Type::Tuple(ref ty) => for elem in &ty.elems {
collect_lifetimes(elem, out); collect_lifetimes(elem, out);
}, },
syn::Ty::Path(ref qself, ref path) => { syn::Type::Path(ref ty) => {
if let Some(ref qself) = *qself { if let Some(ref qself) = ty.qself {
collect_lifetimes(&qself.ty, out); collect_lifetimes(&qself.ty, out);
} }
for seg in &path.segments { for seg in &ty.path.segments {
if let syn::PathParameters::AngleBracketed(ref params) = seg.parameters { if let syn::PathArguments::AngleBracketed(ref bracketed) = seg.arguments {
out.extend(params.lifetimes.iter().cloned()); for arg in &bracketed.args {
for ty in &params.types { match *arg {
collect_lifetimes(ty, out); syn::GenericArgument::Lifetime(ref lifetime) => {
} out.insert(lifetime.clone());
for binding in &params.bindings { }
collect_lifetimes(&binding.ty, out); syn::GenericArgument::Type(ref ty) => {
collect_lifetimes(ty, out);
}
syn::GenericArgument::Binding(ref binding) => {
collect_lifetimes(&binding.ty, out);
}
syn::GenericArgument::Const(_) => {}
}
} }
} }
} }
} }
syn::Ty::BareFn(_) syn::Type::Paren(ref ty) => {
| syn::Ty::Never collect_lifetimes(&ty.elem, out);
| syn::Ty::TraitObject(_) }
| syn::Ty::ImplTrait(_) syn::Type::Group(ref ty) => {
| syn::Ty::Infer collect_lifetimes(&ty.elem, out);
| syn::Ty::Mac(_) => {} }
syn::Type::BareFn(_)
| syn::Type::Never(_)
| syn::Type::TraitObject(_)
| syn::Type::ImplTrait(_)
| syn::Type::Infer(_)
| syn::Type::Macro(_)
| syn::Type::Verbatim(_) => {}
} }
} }
+1 -1
View File
@@ -14,7 +14,7 @@ use std::str::FromStr;
use self::RenameRule::*; use self::RenameRule::*;
#[derive(Debug, PartialEq)] #[derive(PartialEq)]
pub enum RenameRule { pub enum RenameRule {
/// Don't apply a default rename rule. /// Don't apply a default rename rule.
None, None,
+12 -12
View File
@@ -6,7 +6,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use ast::{Body, Container, Style}; use ast::{Data, Container, Style};
use attr::Identifier; use attr::Identifier;
use Ctxt; use Ctxt;
@@ -21,14 +21,14 @@ pub fn check(cx: &Ctxt, cont: &Container) {
/// Getters are only allowed inside structs (not enums) with the `remote` /// Getters are only allowed inside structs (not enums) with the `remote`
/// attribute. /// attribute.
fn check_getter(cx: &Ctxt, cont: &Container) { fn check_getter(cx: &Ctxt, cont: &Container) {
match cont.body { match cont.data {
Body::Enum(_) => { Data::Enum(_) => {
if cont.body.has_getter() { if cont.data.has_getter() {
cx.error("#[serde(getter = \"...\")] is not allowed in an enum"); cx.error("#[serde(getter = \"...\")] is not allowed in an enum");
} }
} }
Body::Struct(_, _) => { Data::Struct(_, _) => {
if cont.body.has_getter() && cont.attrs.remote().is_none() { if cont.data.has_getter() && cont.attrs.remote().is_none() {
cx.error( cx.error(
"#[serde(getter = \"...\")] can only be used in structs \ "#[serde(getter = \"...\")] can only be used in structs \
that have #[serde(remote = \"...\")]", that have #[serde(remote = \"...\")]",
@@ -45,9 +45,9 @@ fn check_getter(cx: &Ctxt, cont: &Container) {
/// `field_identifier` all but possibly one variant must be unit variants. The /// `field_identifier` all but possibly one variant must be unit variants. The
/// last variant may be a newtype variant which is an implicit "other" case. /// last variant may be a newtype variant which is an implicit "other" case.
fn check_identifier(cx: &Ctxt, cont: &Container) { fn check_identifier(cx: &Ctxt, cont: &Container) {
let variants = match cont.body { let variants = match cont.data {
Body::Enum(ref variants) => variants, Data::Enum(ref variants) => variants,
Body::Struct(_, _) => { Data::Struct(_, _) => {
return; return;
} }
}; };
@@ -102,9 +102,9 @@ fn check_identifier(cx: &Ctxt, cont: &Container) {
/// Skip-(de)serializing attributes are not allowed on variants marked /// Skip-(de)serializing attributes are not allowed on variants marked
/// (de)serialize_with. /// (de)serialize_with.
fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) {
let variants = match cont.body { let variants = match cont.data {
Body::Enum(ref variants) => variants, Data::Enum(ref variants) => variants,
Body::Struct(_, _) => { Data::Struct(_, _) => {
return; return;
} }
}; };
+1 -2
View File
@@ -8,9 +8,8 @@
#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.19.0")] #![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.19.0")]
extern crate syn;
#[macro_use] #[macro_use]
extern crate synom; extern crate syn;
pub mod ast; pub mod ast;
pub mod attr; pub mod attr;