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
+160 -96
View File
@@ -9,27 +9,30 @@
use std::collections::HashSet;
use syn::{self, visit};
use syn::punctuated::Punctuated;
use internals::ast::{Body, Container};
use internals::ast::{Data, Container};
use internals::attr;
macro_rules! path {
($($path:tt)+) => {
syn::parse_path(quote!($($path)+).as_str()).unwrap()
};
}
use proc_macro2::{Span, Term};
// Remove the default from every type parameter because in the generated impls
// they look like associated types: "error: associated type bindings are not
// allowed here".
pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
syn::Generics {
ty_params: generics
.ty_params
params: generics
.params
.iter()
.map(|ty_param| syn::TyParam {
default: None,
..ty_param.clone()
.map(|param| match *param {
syn::GenericParam::Type(ref param) => {
syn::GenericParam::Type(syn::TypeParam {
eq_token: None,
default: None,
..param.clone()
})
}
_ => param.clone(),
})
.collect(),
..generics.clone()
@@ -41,10 +44,17 @@ pub fn with_where_predicates(
predicates: &[syn::WherePredicate],
) -> syn::Generics {
let mut generics = generics.clone();
generics
.where_clause
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_from_slice(predicates);
.extend(predicates.into_iter().cloned());
generics
}
@@ -56,13 +66,23 @@ pub fn with_where_predicates_from_fields<F>(
where
F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
{
let predicates = cont.body
let predicates = cont.data
.all_fields()
.flat_map(|field| from_field(&field.attrs))
.flat_map(|predicates| predicates.to_vec());
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
}
@@ -95,22 +115,22 @@ where
// them.
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) {
if let Some(seg) = path.segments.last() {
if seg.ident == "PhantomData" {
if seg.into_value().ident == "PhantomData" {
// Hardcoded exception, because PhantomData<T> implements
// Serialize and Deserialize whether or not T implements it.
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();
if self.all_ty_params.contains(&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.
@@ -119,61 +139,79 @@ where
// mac: 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
.ty_params
.params
.iter()
.map(|ty_param| ty_param.ident.clone())
.filter_map(|param| match *param {
syn::GenericParam::Type(ref param) => Some(param.ident),
_ => None,
})
.collect();
let mut visitor = FindTyParams {
all_ty_params: all_ty_params,
relevant_ty_params: HashSet::new(),
};
match cont.body {
Body::Enum(ref variants) => for variant in variants.iter() {
match cont.data {
Data::Enum(ref variants) => for variant in variants.iter() {
let relevant_fields = variant
.fields
.iter()
.filter(|field| filter(&field.attrs, Some(&variant.attrs)));
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)) {
visit::walk_ty(&mut visitor, field.ty);
visit::visit_type(&mut visitor, field.ty);
}
}
}
let new_predicates = generics
.ty_params
.params
.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))
.map(|id| {
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
bound_lifetimes: Vec::new(),
syn::WherePredicate::Type(syn::PredicateType {
lifetimes: None,
// 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
bounds: vec![
syn::TyParamBound::Trait(
syn::PolyTraitRef {
bound_lifetimes: Vec::new(),
trait_ref: bound.clone(),
},
syn::TraitBoundModifier::None,
),
],
syn::TypeParamBound::Trait(syn::TraitBound {
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path: bound.clone(),
}),
].into_iter().collect(),
})
});
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
}
@@ -183,76 +221,102 @@ pub fn with_self_bound(
bound: &syn::Path,
) -> syn::Generics {
let mut generics = generics.clone();
generics
.where_clause
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
.push(syn::WherePredicate::BoundPredicate(
syn::WhereBoundPredicate {
bound_lifetimes: Vec::new(),
// the type that is being bounded e.g. MyStruct<'a, T>
bounded_ty: type_of_item(cont),
// the bound e.g. Default
bounds: vec![
syn::TyParamBound::Trait(
syn::PolyTraitRef {
bound_lifetimes: Vec::new(),
trait_ref: bound.clone(),
},
syn::TraitBoundModifier::None,
),
],
},
));
.push(syn::WherePredicate::Type(syn::PredicateType {
lifetimes: None,
// the type that is being bounded e.g. MyStruct<'a, T>
bounded_ty: type_of_item(cont),
colon_token: Default::default(),
// the bound e.g. Default
bounds: vec![
syn::TypeParamBound::Trait(syn::TraitBound {
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path: bound.clone(),
}),
].into_iter().collect(),
}));
generics
}
pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
let mut generics = generics.clone();
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 {
let bound = syn::Lifetime::new(Term::intern(lifetime), Span::def_site());
let def = syn::LifetimeDef {
attrs: Vec::new(),
lifetime: syn::Lifetime::new(lifetime),
bounds: Vec::new(),
});
lifetime: bound,
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 {
syn::Ty::Path(
None,
syn::Path {
global: false,
fn type_of_item(cont: &Container) -> syn::Type {
syn::Type::Path(syn::TypePath {
qself: None,
path: syn::Path {
leading_colon: None,
segments: vec![
syn::PathSegment {
ident: cont.ident.clone(),
parameters: syn::PathParameters::AngleBracketed(
syn::AngleBracketedParameterData {
lifetimes: cont.generics
.lifetimes
arguments: syn::PathArguments::AngleBracketed(
syn::AngleBracketedGenericArguments {
colon2_token: None,
lt_token: Default::default(),
args: cont.generics
.params
.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(),
types: cont.generics
.ty_params
.iter()
.map(|param| syn::Ty::Path(None, param.ident.clone().into()))
.collect(),
bindings: Vec::new(),
gt_token: Default::default(),
},
),
},
],
].into_iter().collect(),
},
)
})
}
+107 -61
View File
@@ -6,12 +6,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use syn::{self, Ident};
use quote::{self, ToTokens, Tokens};
use syn::{self, Ident, Member};
use syn::punctuated::Punctuated;
use quote::{ToTokens, Tokens};
use proc_macro2::{Literal, Span, Term};
use bound;
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 std::collections::BTreeSet;
@@ -24,7 +26,7 @@ pub fn expand_derive_deserialize(input: &syn::DeriveInput) -> Result<Tokens, Str
let ident = &cont.ident;
let params = Parameters::new(&cont);
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 delife = params.borrowed.de_lifetime();
@@ -96,7 +98,7 @@ impl Parameters {
};
let borrowed = borrowed_lifetimes(cont);
let generics = build_generics(cont, &borrowed);
let has_getter = cont.body.has_getter();
let has_getter = cont.data.has_getter();
Parameters {
local: local,
@@ -110,7 +112,7 @@ impl Parameters {
/// Type name to use in error messages and `&'static str` arguments to
/// various Deserializer methods.
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 => {
let generics = match *cont.attrs.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,
};
@@ -137,14 +139,14 @@ fn build_generics(cont: &Container, borrowed: &BorrowedLifetimes) -> syn::Generi
cont,
&generics,
needs_deserialize_bound,
&path!(_serde::Deserialize<#delife>),
&parse_quote!(_serde::Deserialize<#delife>),
);
bound::with_bound(
cont,
&generics,
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
// `skip_deserializing` attribute that do not also have `default=...`.
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 {
@@ -173,8 +179,8 @@ enum BorrowedLifetimes {
impl BorrowedLifetimes {
fn de_lifetime(&self) -> syn::Lifetime {
match *self {
BorrowedLifetimes::Borrowed(_) => syn::Lifetime::new("'de"),
BorrowedLifetimes::Static => syn::Lifetime::new("'static"),
BorrowedLifetimes::Borrowed(_) => syn::Lifetime::new(Term::intern("'de"), Span::def_site()),
BorrowedLifetimes::Static => syn::Lifetime::new(Term::intern("'static"), Span::def_site()),
}
}
@@ -182,7 +188,8 @@ impl BorrowedLifetimes {
match *self {
BorrowedLifetimes::Borrowed(ref bounds) => Some(syn::LifetimeDef {
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(),
}),
BorrowedLifetimes::Static => None,
@@ -201,12 +208,12 @@ impl BorrowedLifetimes {
// and we use plain `'static` instead of `'de`.
fn borrowed_lifetimes(cont: &Container) -> BorrowedLifetimes {
let mut lifetimes = BTreeSet::new();
for field in cont.body.all_fields() {
for field in cont.data.all_fields() {
if !field.attrs.skip_deserializing() {
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
} else {
BorrowedLifetimes::Borrowed(lifetimes)
@@ -217,28 +224,28 @@ fn deserialize_body(cont: &Container, params: &Parameters) -> Fragment {
if let Some(from_type) = cont.attrs.from_type() {
deserialize_from(from_type)
} else if let attr::Identifier::No = cont.attrs.identifier() {
match cont.body {
Body::Enum(ref variants) => deserialize_enum(params, variants, &cont.attrs),
Body::Struct(Style::Struct, ref fields) => {
match cont.data {
Data::Enum(ref variants) => deserialize_enum(params, variants, &cont.attrs),
Data::Struct(Style::Struct, ref fields) => {
if fields.iter().any(|field| field.ident.is_none()) {
panic!("struct has unnamed fields");
}
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()) {
panic!("tuple struct has named fields");
}
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 {
match cont.body {
Body::Enum(ref variants) => {
match cont.data {
Data::Enum(ref variants) => {
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);
if cont.attrs.from_type().is_some() || cont.attrs.identifier().is_some()
|| cont.body
|| cont.data
.all_fields()
.all(|f| f.attrs.deserialize_with().is_some())
{
return None;
}
let code = match cont.body {
Body::Struct(Style::Struct, ref fields) => {
let code = match cont.data {
Data::Struct(Style::Struct, ref fields) => {
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)
}
Body::Enum(_) | Body::Struct(Style::Unit, _) => {
Data::Enum(_) | Data::Struct(Style::Unit, _) => {
return None;
}
};
@@ -288,7 +295,7 @@ fn deserialize_in_place_body(_cont: &Container, _params: &Parameters) -> Option<
None
}
fn deserialize_from(from_type: &syn::Ty) -> Fragment {
fn deserialize_from(from_type: &syn::Type) -> Fragment {
quote_block! {
_serde::export::Result::map(
<#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
let field_name = field
.ident
.clone()
.unwrap_or_else(|| Ident::new(field_index.to_string()));
.map(Member::Named)
.unwrap_or_else(|| Member::Unnamed(field_index.into()));
if field.attrs.skip_deserializing() {
let default = Expr(expr_is_missing(&field, cattrs));
@@ -1824,7 +1831,7 @@ fn deserialize_identifier(
fallthrough: Option<Tokens>,
) -> Fragment {
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
.iter()
@@ -2203,7 +2210,7 @@ fn deserialize_map_in_place(
// If missing_expr unconditionally returns an error, don't try
// to assign its value to self.place. Maybe this could be handled
// 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);
quote! {
if !#name {
@@ -2252,7 +2259,7 @@ fn deserialize_map_in_place(
}
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 = "...")]`
@@ -2294,7 +2301,7 @@ fn wrap_deserialize_with(
fn wrap_deserialize_field_with(
params: &Parameters,
field_ty: &syn::Ty,
field_ty: &syn::Type,
deserialize_with: &syn::Path,
) -> (Tokens, Tokens) {
wrap_deserialize_with(params, quote!(#field_ty), deserialize_with)
@@ -2312,7 +2319,7 @@ fn wrap_deserialize_variant_with(
let (wrapper, wrapper_ty) =
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 {
Style::Struct => {
let field_idents = variant
@@ -2385,7 +2392,10 @@ impl<'a> ToTokens for DeImplGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
let mut generics = self.0.generics.clone();
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();
impl_generics.to_tokens(tokens);
@@ -2399,17 +2409,27 @@ impl<'a> ToTokens for InPlaceImplGenerics<'a> {
let mut generics = self.0.generics.clone();
// Add lifetime for `&'place mut Self, and `'a: 'place`
for lifetime in &mut generics.lifetimes {
lifetime.bounds.push(place_lifetime.lifetime.clone());
for param in &mut generics.params {
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 {
generic
.bounds
.push(syn::TyParamBound::Region(place_lifetime.lifetime.clone()));
}
generics.lifetimes.insert(0, place_lifetime);
generics.params = Some(syn::GenericParam::Lifetime(place_lifetime))
.into_iter()
.chain(generics.params)
.collect();
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();
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")]
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) {
let mut generics = self.0.generics.clone();
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();
ty_generics.to_tokens(tokens);
@@ -2439,13 +2468,25 @@ impl<'a> ToTokens for DeTyGenerics<'a> {
}
#[cfg(feature = "deserialize_in_place")]
impl<'a> ToTokens for InPlaceTyGenerics<'a> {
impl<'a> ToTokens for InPlaceTypeGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
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() {
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();
ty_generics.to_tokens(tokens);
@@ -2453,27 +2494,32 @@ impl<'a> ToTokens for InPlaceTyGenerics<'a> {
}
#[cfg(feature = "deserialize_in_place")]
impl<'a> DeTyGenerics<'a> {
fn in_place(self) -> InPlaceTyGenerics<'a> {
InPlaceTyGenerics(self.0)
impl<'a> DeTypeGenerics<'a> {
fn in_place(self) -> InPlaceTypeGenerics<'a> {
InPlaceTypeGenerics(self.0)
}
}
#[cfg(feature = "deserialize_in_place")]
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(
params: &Parameters,
) -> (
DeImplGenerics,
DeTyGenerics,
syn::TyGenerics,
&syn::WhereClause,
DeTypeGenerics,
syn::TypeGenerics,
Option<&syn::WhereClause>,
) {
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();
(de_impl_generics, de_ty_generics, ty_generics, where_clause)
}
+4 -7
View File
@@ -7,6 +7,7 @@
// except according to those terms.
use quote::{ToTokens, Tokens};
use syn::token;
pub enum Fragment {
/// Tokens that can be used as an expression.
@@ -36,9 +37,7 @@ impl ToTokens for Expr {
match self.0 {
Fragment::Expr(ref expr) => expr.to_tokens(out),
Fragment::Block(ref block) => {
out.append("{");
block.to_tokens(out);
out.append("}");
token::Brace::default().surround(out, |out| block.to_tokens(out));
}
}
}
@@ -63,12 +62,10 @@ impl ToTokens for Match {
match self.0 {
Fragment::Expr(ref expr) => {
expr.to_tokens(out);
out.append(",");
<Token![,]>::default().to_tokens(out);
}
Fragment::Block(ref block) => {
out.append("{");
block.to_tokens(out);
out.append("}");
token::Brace::default().surround(out, |out| block.to_tokens(out));
}
}
}
+9 -5
View File
@@ -26,16 +26,20 @@
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "cargo-clippy", allow(used_underscore_binding))]
// The `quote!` macro requires deep recursion.
#![recursion_limit = "192"]
#![recursion_limit = "256"]
#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;
extern crate serde_derive_internals as internals;
extern crate proc_macro;
extern crate proc_macro2;
use proc_macro::TokenStream;
use syn::DeriveInput;
#[macro_use]
mod bound;
@@ -47,18 +51,18 @@ mod de;
#[proc_macro_derive(Serialize, attributes(serde))]
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) {
Ok(expanded) => expanded.parse().unwrap(),
Ok(expanded) => expanded.into(),
Err(msg) => panic!(msg),
}
}
#[proc_macro_derive(Deserialize, attributes(serde))]
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) {
Ok(expanded) => expanded.parse().unwrap(),
Ok(expanded) => expanded.into(),
Err(msg) => panic!(msg),
}
}
+30 -34
View File
@@ -6,12 +6,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use syn::{self, Ident};
use syn::{self, Ident, Member};
use quote::Tokens;
use proc_macro2::Span;
use bound;
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 std::u32;
@@ -25,7 +26,7 @@ pub fn expand_derive_serialize(input: &syn::DeriveInput) -> Result<Tokens, Strin
let ident = &cont.ident;
let params = Parameters::new(&cont);
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 impl_block = if let Some(remote) = cont.attrs.remote() {
@@ -95,9 +96,9 @@ impl Parameters {
fn new(cont: &Container) -> Self {
let is_remote = cont.attrs.remote().is_some();
let self_var = if is_remote {
Ident::new("__self")
Ident::new("__self", Span::def_site())
} else {
Ident::new("self")
Ident::new("self", Span::def_site())
};
let this = match cont.attrs.remote() {
@@ -118,7 +119,7 @@ impl Parameters {
/// Type name to use in error messages and `&'static str` arguments to
/// various Serializer methods.
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,
&generics,
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() {
serialize_into(params, into_type)
} else {
match cont.body {
Body::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs),
Body::Struct(Style::Struct, ref fields) => {
match cont.data {
Data::Enum(ref variants) => serialize_enum(params, variants, &cont.attrs),
Data::Struct(Style::Struct, ref fields) => {
if fields.iter().any(|field| field.ident.is_none()) {
panic!("struct has unnamed fields");
}
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()) {
panic!("tuple struct has named fields");
}
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)
}
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;
quote_block! {
_serde::Serialize::serialize(
@@ -201,7 +202,7 @@ fn serialize_newtype_struct(
) -> Fragment {
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() {
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),
Some(path) => {
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 })
}
})
@@ -333,7 +334,7 @@ fn serialize_variant(
}
Style::Tuple => {
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! {
#this::#variant_ident(#(ref #field_names),*)
}
@@ -566,9 +567,9 @@ fn serialize_adjacently_tagged_variant(
unreachable!()
}
}
Style::Newtype => vec![Ident::new("__field0")],
Style::Newtype => vec![Ident::new("__field0", Span::def_site())],
Style::Tuple => (0..variant.fields.len())
.map(|i| Ident::new(format!("__field{}", i)))
.map(|i| Ident::new(&format!("__field{}", i), Span::def_site()))
.collect(),
Style::Struct => variant
.fields
@@ -813,10 +814,10 @@ fn serialize_tuple_struct_visitor(
.enumerate()
.map(|(i, field)| {
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)
} else {
get_field(params, field, i)
get_member(params, field, Member::Unnamed(i.into()))
};
let skip = field
@@ -855,7 +856,7 @@ fn serialize_struct_visitor(
let mut field_expr = if is_enum {
quote!(#field_ident)
} else {
get_field(params, field, field_ident)
get_member(params, field, Member::Named(field_ident))
};
let key_expr = field.attrs.name().serialize_name();
@@ -891,7 +892,7 @@ fn serialize_struct_visitor(
fn wrap_serialize_field_with(
params: &Parameters,
field_ty: &syn::Ty,
field_ty: &syn::Type,
serialize_with: &syn::Path,
field_expr: Tokens,
) -> Tokens {
@@ -912,7 +913,7 @@ fn wrap_serialize_variant_with(
let id = field
.ident
.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)
})
.collect();
@@ -927,7 +928,7 @@ fn wrap_serialize_variant_with(
fn wrap_serialize_with(
params: &Parameters,
serialize_with: &syn::Path,
field_tys: &[&syn::Ty],
field_tys: &[&syn::Type],
field_exprs: &[Tokens],
) -> Tokens {
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 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!({
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
where
I: Into<Ident>,
{
fn get_member(params: &Parameters, field: &Field, member: Member) -> Tokens {
let self_var = &params.self_var;
match (params.is_remote, field.attrs.getter()) {
(false, None) => {
let ident = ident.into();
quote!(&#self_var.#ident)
quote!(&#self_var.#member)
}
(true, None) => {
let ty = field.ty;
let ident = ident.into();
quote!(_serde::private::ser::constrain::<#ty>(&#self_var.#ident))
quote!(_serde::private::ser::constrain::<#ty>(&#self_var.#member))
}
(true, Some(getter)) => {
let ty = field.ty;