From ef4dd6c0ec8d5043c4087d8596a3dfcb2fbcad49 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 8 Jan 2018 21:49:09 -0800 Subject: [PATCH] Update to syn 0.12 --- serde_derive/Cargo.toml | 5 +- serde_derive/src/bound.rs | 256 ++++++++++------ serde_derive/src/de.rs | 168 +++++++---- serde_derive/src/fragment.rs | 11 +- serde_derive/src/lib.rs | 14 +- serde_derive/src/ser.rs | 64 ++-- serde_derive_internals/Cargo.toml | 3 +- serde_derive_internals/src/ast.rs | 60 ++-- serde_derive_internals/src/attr.rs | 443 ++++++++++++++++------------ serde_derive_internals/src/case.rs | 2 +- serde_derive_internals/src/check.rs | 24 +- serde_derive_internals/src/lib.rs | 3 +- 12 files changed, 609 insertions(+), 444 deletions(-) diff --git a/serde_derive/Cargo.toml b/serde_derive/Cargo.toml index 8dd851f2..9eef8933 100644 --- a/serde_derive/Cargo.toml +++ b/serde_derive/Cargo.toml @@ -23,9 +23,10 @@ name = "serde_derive" proc-macro = true [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" } -syn = { version = "0.11", features = ["visit"] } +syn = { version = "0.12", features = ["visit"] } [dev-dependencies] serde = { version = "1.0", path = "../serde" } diff --git a/serde_derive/src/bound.rs b/serde_derive/src/bound.rs index 98f8f475..3974cb4b 100644 --- a/serde_derive/src/bound.rs +++ b/serde_derive/src/bound.rs @@ -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( 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, } - 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 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, // } - 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(), }, - ) + }) } diff --git a/serde_derive/src/de.rs b/serde_derive/src/de.rs index 294d8168..17820d22 100644 --- a/serde_derive/src/de.rs +++ b/serde_derive/src/de.rs @@ -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 &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 { + 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, ) -> 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(¶ms); - let de_ty_generics = DeTyGenerics(¶ms); + let de_ty_generics = DeTypeGenerics(¶ms); let (_, ty_generics, where_clause) = params.generics.split_for_impl(); (de_impl_generics, de_ty_generics, ty_generics, where_clause) } diff --git a/serde_derive/src/fragment.rs b/serde_derive/src/fragment.rs index d333cd5f..1241ab68 100644 --- a/serde_derive/src/fragment.rs +++ b/serde_derive/src/fragment.rs @@ -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(","); + ::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)); } } } diff --git a/serde_derive/src/lib.rs b/serde_derive/src/lib.rs index fc68947b..7fbd4bf7 100644 --- a/serde_derive/src/lib.rs +++ b/serde_derive/src/lib.rs @@ -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), } } diff --git a/serde_derive/src/ser.rs b/serde_derive/src/ser.rs index 56be715d..d26c9e3a 100644 --- a/serde_derive/src/ser.rs +++ b/serde_derive/src/ser.rs @@ -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 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 = ¶ms.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 = ¶ms.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 { } } -fn get_field(params: &Parameters, field: &Field, ident: I) -> Tokens -where - I: Into, -{ +fn get_member(params: &Parameters, field: &Field, member: Member) -> Tokens { let self_var = ¶ms.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; diff --git a/serde_derive_internals/Cargo.toml b/serde_derive_internals/Cargo.toml index f47fdacb..ac601190 100644 --- a/serde_derive_internals/Cargo.toml +++ b/serde_derive_internals/Cargo.toml @@ -12,8 +12,7 @@ readme = "README.md" include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] [dependencies] -syn = { version = "0.11.10", default-features = false, features = ["parsing"] } -synom = "0.11" +syn = { version = "0.12", default-features = false, features = ["derive", "parsing", "clone-impls"] } [badges] travis-ci = { repository = "serde-rs/serde" } diff --git a/serde_derive_internals/src/ast.rs b/serde_derive_internals/src/ast.rs index 698a175c..756e92a3 100644 --- a/serde_derive_internals/src/ast.rs +++ b/serde_derive_internals/src/ast.rs @@ -10,15 +10,16 @@ use syn; use attr; use check; use Ctxt; +use syn::punctuated::Punctuated; pub struct Container<'a> { pub ident: syn::Ident, pub attrs: attr::Container, - pub body: Body<'a>, + pub data: Data<'a>, pub generics: &'a syn::Generics, } -pub enum Body<'a> { +pub enum Data<'a> { Enum(Vec>), Struct(Style, Vec>), } @@ -33,7 +34,7 @@ pub struct Variant<'a> { pub struct Field<'a> { pub ident: Option, pub attrs: attr::Field, - pub ty: &'a syn::Ty, + pub ty: &'a syn::Type, } #[derive(Copy, Clone)] @@ -48,24 +49,27 @@ impl<'a> Container<'a> { pub fn from_ast(cx: &Ctxt, item: &'a syn::DeriveInput) -> Container<'a> { let attrs = attr::Container::from_ast(cx, item); - let mut body = match item.body { - syn::Body::Enum(ref variants) => { - Body::Enum(enum_from_ast(cx, variants, &attrs.default())) + let mut data = match item.data { + syn::Data::Enum(ref data) => { + Data::Enum(enum_from_ast(cx, &data.variants, &attrs.default())) } - syn::Body::Struct(ref variant_data) => { - let (style, fields) = struct_from_ast(cx, variant_data, None, &attrs.default()); - Body::Struct(style, fields) + syn::Data::Struct(ref data) => { + let (style, fields) = struct_from_ast(cx, &data.fields, None, &attrs.default()); + Data::Struct(style, fields) + } + syn::Data::Union(_) => { + panic!("Serde does not support derive for unions"); } }; - match body { - Body::Enum(ref mut variants) => for ref mut variant in variants { + match data { + Data::Enum(ref mut variants) => for ref mut variant in variants { variant.attrs.rename_by_rule(attrs.rename_all()); for ref mut field in &mut variant.fields { 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()); }, } @@ -73,7 +77,7 @@ impl<'a> Container<'a> { let item = Container { ident: item.ident.clone(), attrs: attrs, - body: body, + data: data, generics: &item.generics, }; 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> + 'a> { match *self { - Body::Enum(ref variants) => { + Data::Enum(ref variants) => { 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>( cx: &Ctxt, - variants: &'a [syn::Variant], + variants: &'a Punctuated, container_default: &attr::Default, ) -> Vec> { variants @@ -106,7 +110,7 @@ fn enum_from_ast<'a>( .map(|variant| { let attrs = attr::Variant::from_ast(cx, variant); let (style, fields) = - struct_from_ast(cx, &variant.data, Some(&attrs), container_default); + struct_from_ast(cx, &variant.fields, Some(&attrs), container_default); Variant { ident: variant.ident.clone(), attrs: attrs, @@ -119,30 +123,30 @@ fn enum_from_ast<'a>( fn struct_from_ast<'a>( cx: &Ctxt, - data: &'a syn::VariantData, + fields: &'a syn::Fields, attrs: Option<&attr::Variant>, container_default: &attr::Default, ) -> (Style, Vec>) { - match *data { - syn::VariantData::Struct(ref fields) => ( + match *fields { + syn::Fields::Named(ref fields) => ( 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, - 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, - 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>( cx: &Ctxt, - fields: &'a [syn::Field], + fields: &'a Punctuated, attrs: Option<&attr::Variant>, container_default: &attr::Default, ) -> Vec> { diff --git a/serde_derive_internals/src/attr.rs b/serde_derive_internals/src/attr.rs index ce0ed026..771b4e9e 100644 --- a/serde_derive_internals/src/attr.rs +++ b/serde_derive_internals/src/attr.rs @@ -8,9 +8,10 @@ use Ctxt; use syn; -use syn::MetaItem::{List, NameValue, Word}; -use syn::NestedMetaItem::{Literal, MetaItem}; -use synom::IResult; +use syn::Meta::{List, NameValue, Word}; +use syn::NestedMeta::{Literal, Meta}; +use syn::punctuated::Punctuated; +use syn::synom::Synom; use std::collections::BTreeSet; use std::str::FromStr; @@ -81,7 +82,6 @@ impl<'c> BoolAttr<'c> { } } -#[derive(Debug)] pub struct Name { serialize: String, deserialize: String, @@ -100,7 +100,6 @@ impl Name { } /// Represents container (e.g. struct) attribute information -#[derive(Debug)] pub struct Container { name: Name, deny_unknown_fields: bool, @@ -109,14 +108,13 @@ pub struct Container { ser_bound: Option>, de_bound: Option>, tag: EnumTag, - from_type: Option, - into_type: Option, + from_type: Option, + into_type: Option, remote: Option, identifier: Identifier, } /// Styles of representing an enum. -#[derive(Debug)] pub enum EnumTag { /// The default. /// @@ -149,7 +147,7 @@ pub enum EnumTag { /// Whether this enum represents the fields of a struct or the variants of an /// enum. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone)] pub enum Identifier { /// It does not. No, @@ -196,24 +194,24 @@ impl Container { for meta_item in meta_items { match meta_item { // Parse `#[serde(rename = "foo")]` - MetaItem(NameValue(ref name, ref lit)) if name == "rename" => { - if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "rename" => { + if let Ok(s) = get_string_from_lit(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { ser_name.set(s.clone()); de_name.set(s); } } // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` - MetaItem(List(ref name, ref meta_items)) if name == "rename" => { - if let Ok((ser, de)) = get_renames(cx, meta_items) { + Meta(List(ref m)) if m.ident == "rename" => { + if let Ok((ser, de)) = get_renames(cx, &m.nested) { ser_name.set_opt(ser); de_name.set_opt(de); } } // Parse `#[serde(rename_all = "foo")]` - MetaItem(NameValue(ref name, ref lit)) if name == "rename_all" => { - if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "rename_all" => { + if let Ok(s) = get_string_from_lit(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { match RenameRule::from_str(&s) { Ok(rename_rule) => rename_all.set(rename_rule), Err(()) => cx.error(format!( @@ -226,13 +224,13 @@ impl Container { } // 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(); } // Parse `#[serde(default)]` - MetaItem(Word(ref name)) if name == "default" => match item.body { - syn::Body::Struct(syn::VariantData::Struct(_)) => { + Meta(Word(word)) if word == "default" => match item.data { + syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(_), .. }) => { default.set(Default::Default); } _ => cx.error( @@ -242,10 +240,10 @@ impl Container { }, // Parse `#[serde(default = "...")]` - MetaItem(NameValue(ref name, ref lit)) if name == "default" => { - if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { - match item.body { - syn::Body::Struct(syn::VariantData::Struct(_)) => { + Meta(NameValue(ref m)) if m.ident == "default" => { + if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) { + match item.data { + syn::Data::Struct(syn::DataStruct { fields: syn::Fields::Named(_), .. }) => { default.set(Default::Path(path)); } _ => cx.error( @@ -257,9 +255,9 @@ impl Container { } // 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) = - 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()); de_bound.set(where_predicates); @@ -267,31 +265,31 @@ impl Container { } // Parse `#[serde(bound(serialize = "D: Serialize", deserialize = "D: Deserialize"))]` - MetaItem(List(ref name, ref meta_items)) if name == "bound" => { - if let Ok((ser, de)) = get_where_predicates(cx, meta_items) { + Meta(List(ref m)) if m.ident == "bound" => { + if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { ser_bound.set_opt(ser); de_bound.set_opt(de); } } // Parse `#[serde(untagged)]` - MetaItem(Word(ref name)) if name == "untagged" => match item.body { - syn::Body::Enum(_) => { + Meta(Word(word)) if word == "untagged" => match item.data { + syn::Data::Enum(_) => { untagged.set_true(); } - syn::Body::Struct(_) => { + syn::Data::Struct(_) | syn::Data::Union(_) => { cx.error("#[serde(untagged)] can only be used on enums") } }, // Parse `#[serde(tag = "type")]` - MetaItem(NameValue(ref name, ref lit)) if name == "tag" => { - if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { - match item.body { - syn::Body::Enum(_) => { + Meta(NameValue(ref m)) if m.ident == "tag" => { + if let Ok(s) = get_string_from_lit(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { + match item.data { + syn::Data::Enum(_) => { internal_tag.set(s); } - syn::Body::Struct(_) => { + syn::Data::Struct(_) | syn::Data::Union(_) => { cx.error("#[serde(tag = \"...\")] can only be used on enums") } } @@ -299,13 +297,13 @@ impl Container { } // Parse `#[serde(content = "c")]` - MetaItem(NameValue(ref name, ref lit)) if name == "content" => { - if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { - match item.body { - syn::Body::Enum(_) => { + Meta(NameValue(ref m)) if m.ident == "content" => { + if let Ok(s) = get_string_from_lit(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { + match item.data { + syn::Data::Enum(_) => { content.set(s); } - syn::Body::Struct(_) => cx.error( + syn::Data::Struct(_) | syn::Data::Union(_) => cx.error( "#[serde(content = \"...\")] can only be used on \ enums", ), @@ -314,37 +312,37 @@ impl Container { } // Parse `#[serde(from = "Type")] - MetaItem(NameValue(ref name, ref lit)) if name == "from" => { - if let Ok(from_ty) = parse_lit_into_ty(cx, name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "from" => { + if let Ok(from_ty) = parse_lit_into_ty(cx, m.ident.as_ref(), &m.lit) { from_type.set_opt(Some(from_ty)); } } // Parse `#[serde(into = "Type")] - MetaItem(NameValue(ref name, ref lit)) if name == "into" => { - if let Ok(into_ty) = parse_lit_into_ty(cx, name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "into" => { + if let Ok(into_ty) = parse_lit_into_ty(cx, m.ident.as_ref(), &m.lit) { into_type.set_opt(Some(into_ty)); } } // Parse `#[serde(remote = "...")]` - MetaItem(NameValue(ref name, ref lit)) if name == "remote" => { - if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "remote" => { + if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) { remote.set(path); } } // Parse `#[serde(field_identifier)]` - MetaItem(Word(ref name)) if name == "field_identifier" => { + Meta(Word(word)) if word == "field_identifier" => { field_identifier.set_true(); } // Parse `#[serde(variant_identifier)]` - MetaItem(Word(ref name)) if name == "variant_identifier" => { + Meta(Word(word)) if word == "variant_identifier" => { variant_identifier.set_true(); } - MetaItem(ref meta_item) => { + Meta(ref meta_item) => { cx.error(format!( "unknown serde container attribute `{}`", meta_item.name() @@ -404,11 +402,11 @@ impl Container { &self.tag } - pub fn from_type(&self) -> Option<&syn::Ty> { + pub fn from_type(&self) -> Option<&syn::Type> { 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() } @@ -433,12 +431,12 @@ fn decide_tag( (true, None, None) => EnumTag::None, (false, Some(tag), None) => { // Check that there are no tuple variants. - if let syn::Body::Enum(ref variants) = item.body { - for variant in variants { - match variant.data { - syn::VariantData::Struct(_) | syn::VariantData::Unit => {} - syn::VariantData::Tuple(ref fields) => { - if fields.len() != 1 { + if let syn::Data::Enum(ref data) = item.data { + for variant in &data.variants { + match variant.fields { + syn::Fields::Named(_) | syn::Fields::Unit => {} + syn::Fields::Unnamed(ref fields) => { + if fields.unnamed.len() != 1 { cx.error( "#[serde(tag = \"...\")] cannot be used with tuple \ variants", @@ -480,27 +478,28 @@ fn decide_identifier( field_identifier: BoolAttr, variant_identifier: BoolAttr, ) -> Identifier { - match (&item.body, field_identifier.get(), variant_identifier.get()) { + match (&item.data, field_identifier.get(), variant_identifier.get()) { (_, false, false) => Identifier::No, (_, true, true) => { cx.error("`field_identifier` and `variant_identifier` cannot both be set"); 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"); 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"); Identifier::No } - (&syn::Body::Enum(_), true, false) => Identifier::Field, - (&syn::Body::Enum(_), false, true) => Identifier::Variant, } } /// Represents variant attribute information -#[derive(Debug)] pub struct Variant { name: Name, ser_renamed: bool, @@ -511,7 +510,7 @@ pub struct Variant { other: bool, serialize_with: Option, deserialize_with: Option, - borrow: Option, + borrow: Option, } impl Variant { @@ -530,24 +529,24 @@ impl Variant { for meta_item in meta_items { match meta_item { // Parse `#[serde(rename = "foo")]` - MetaItem(NameValue(ref name, ref lit)) if name == "rename" => { - if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "rename" => { + if let Ok(s) = get_string_from_lit(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { ser_name.set(s.clone()); de_name.set(s); } } // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` - MetaItem(List(ref name, ref meta_items)) if name == "rename" => { - if let Ok((ser, de)) = get_renames(cx, meta_items) { + Meta(List(ref m)) if m.ident == "rename" => { + if let Ok((ser, de)) = get_renames(cx, &m.nested) { ser_name.set_opt(ser); de_name.set_opt(de); } } // Parse `#[serde(rename_all = "foo")]` - MetaItem(NameValue(ref name, ref lit)) if name == "rename_all" => { - if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "rename_all" => { + if let Ok(s) = get_string_from_lit(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { match RenameRule::from_str(&s) { Ok(rename_rule) => rename_all.set(rename_rule), Err(()) => cx.error(format!( @@ -560,23 +559,23 @@ impl Variant { } // Parse `#[serde(skip_deserializing)]` - MetaItem(Word(ref name)) if name == "skip_deserializing" => { + Meta(Word(word)) if word == "skip_deserializing" => { skip_deserializing.set_true(); } // Parse `#[serde(skip_serializing)]` - MetaItem(Word(ref name)) if name == "skip_serializing" => { + Meta(Word(word)) if word == "skip_serializing" => { skip_serializing.set_true(); } // Parse `#[serde(other)]` - MetaItem(Word(ref name)) if name == "other" => { + Meta(Word(word)) if word == "other" => { other.set_true(); } // Parse `#[serde(with = "...")]` - MetaItem(NameValue(ref name, ref lit)) if name == "with" => { - if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "with" => { + if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) { let mut ser_path = path.clone(); ser_path.segments.push("serialize".into()); serialize_with.set(ser_path); @@ -587,30 +586,30 @@ impl Variant { } // Parse `#[serde(serialize_with = "...")]` - MetaItem(NameValue(ref name, ref lit)) if name == "serialize_with" => { - if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "serialize_with" => { + if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) { serialize_with.set(path); } } // Parse `#[serde(deserialize_with = "...")]` - MetaItem(NameValue(ref name, ref lit)) if name == "deserialize_with" => { - if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "deserialize_with" => { + if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) { deserialize_with.set(path); } } // Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]` - MetaItem(ref mi) if mi.name() == "borrow" => match variant.data { - syn::VariantData::Tuple(ref fields) if fields.len() == 1 => { - borrow.set(mi.clone()); + Meta(ref m) if m.name() == "borrow" => match variant.fields { + syn::Fields::Unnamed(ref fields) if fields.unnamed.len() == 1 => { + borrow.set(m.clone()); } _ => { cx.error("#[serde(borrow)] may only be used on newtype variants"); } }, - MetaItem(ref meta_item) => { + Meta(ref meta_item) => { cx.error(format!( "unknown serde variant attribute `{}`", meta_item.name() @@ -684,7 +683,6 @@ impl Variant { } /// Represents field attribute information -#[derive(Debug)] pub struct Field { name: Name, ser_renamed: bool, @@ -702,7 +700,6 @@ pub struct Field { } /// Represents the default to use for a field when deserializing. -#[derive(Debug, PartialEq)] pub enum Default { /// Field must always be specified because it does not have a default. None, @@ -743,7 +740,7 @@ impl Field { .map(|variant| &variant.borrow) .unwrap_or(&None) .as_ref() - .map(|borrow| vec![MetaItem(borrow.clone())]); + .map(|borrow| vec![Meta(borrow.clone())]); for meta_items in field .attrs @@ -754,73 +751,73 @@ impl Field { for meta_item in meta_items { match meta_item { // Parse `#[serde(rename = "foo")]` - MetaItem(NameValue(ref name, ref lit)) if name == "rename" => { - if let Ok(s) = get_string_from_lit(cx, name.as_ref(), name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "rename" => { + if let Ok(s) = get_string_from_lit(cx, m.ident.as_ref(), m.ident.as_ref(), &m.lit) { ser_name.set(s.clone()); de_name.set(s); } } // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` - MetaItem(List(ref name, ref meta_items)) if name == "rename" => { - if let Ok((ser, de)) = get_renames(cx, meta_items) { + Meta(List(ref m)) if m.ident == "rename" => { + if let Ok((ser, de)) = get_renames(cx, &m.nested) { ser_name.set_opt(ser); de_name.set_opt(de); } } // Parse `#[serde(default)]` - MetaItem(Word(ref name)) if name == "default" => { + Meta(Word(word)) if word == "default" => { default.set(Default::Default); } // Parse `#[serde(default = "...")]` - MetaItem(NameValue(ref name, ref lit)) if name == "default" => { - if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "default" => { + if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) { default.set(Default::Path(path)); } } // Parse `#[serde(skip_serializing)]` - MetaItem(Word(ref name)) if name == "skip_serializing" => { + Meta(Word(word)) if word == "skip_serializing" => { skip_serializing.set_true(); } // Parse `#[serde(skip_deserializing)]` - MetaItem(Word(ref name)) if name == "skip_deserializing" => { + Meta(Word(word)) if word == "skip_deserializing" => { skip_deserializing.set_true(); } // Parse `#[serde(skip)]` - MetaItem(Word(ref name)) if name == "skip" => { + Meta(Word(word)) if word == "skip" => { skip_serializing.set_true(); skip_deserializing.set_true(); } // Parse `#[serde(skip_serializing_if = "...")]` - MetaItem(NameValue(ref name, ref lit)) if name == "skip_serializing_if" => { - if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "skip_serializing_if" => { + if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) { skip_serializing_if.set(path); } } // Parse `#[serde(serialize_with = "...")]` - MetaItem(NameValue(ref name, ref lit)) if name == "serialize_with" => { - if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "serialize_with" => { + if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) { serialize_with.set(path); } } // Parse `#[serde(deserialize_with = "...")]` - MetaItem(NameValue(ref name, ref lit)) if name == "deserialize_with" => { - if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "deserialize_with" => { + if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) { deserialize_with.set(path); } } // Parse `#[serde(with = "...")]` - MetaItem(NameValue(ref name, ref lit)) if name == "with" => { - if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "with" => { + if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) { let mut ser_path = path.clone(); ser_path.segments.push("serialize".into()); serialize_with.set(ser_path); @@ -831,9 +828,9 @@ impl Field { } // 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) = - 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()); de_bound.set(where_predicates); @@ -841,29 +838,29 @@ impl Field { } // Parse `#[serde(bound(serialize = "D: Serialize", deserialize = "D: Deserialize"))]` - MetaItem(List(ref name, ref meta_items)) if name == "bound" => { - if let Ok((ser, de)) = get_where_predicates(cx, meta_items) { + Meta(List(ref m)) if m.ident == "bound" => { + if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { ser_bound.set_opt(ser); de_bound.set_opt(de); } } // 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) { borrowed_lifetimes.set(borrowable); } } // Parse `#[serde(borrow = "'a + 'b")]` - MetaItem(NameValue(ref name, ref lit)) if name == "borrow" => { - if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "borrow" => { + 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) { for lifetime in &lifetimes { if !borrowable.contains(lifetime) { cx.error(format!( "field `{}` does not have lifetime {}", - ident, lifetime.ident + ident, lifetime )); } } @@ -873,13 +870,13 @@ impl Field { } // Parse `#[serde(getter = "...")]` - MetaItem(NameValue(ref name, ref lit)) if name == "getter" => { - if let Ok(path) = parse_lit_into_path(cx, name.as_ref(), lit) { + Meta(NameValue(ref m)) if m.ident == "getter" => { + if let Ok(path) = parse_lit_into_path(cx, m.ident.as_ref(), &m.lit) { getter.set(path); } } - MetaItem(ref meta_item) => { + Meta(ref meta_item) => { cx.error(format!( "unknown serde field attribute `{}`", meta_item.name() @@ -896,8 +893,10 @@ impl Field { // 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. // the struct we are in). - if container_default == &Default::None && skip_deserializing.0.value.is_some() { - default.set_if_none(Default::Default); + if let Default::None = *container_default { + if skip_deserializing.0.value.is_some() { + default.set_if_none(Default::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, [u8]> - if is_cow(&field.ty, "str") { - let path = syn::parse_path("_serde::private::de::borrow_cow_str").unwrap(); + if is_cow(&field.ty, is_str) { + let path = syn::parse_str("_serde::private::de::borrow_cow_str").unwrap(); deserialize_with.set_if_none(path); - } else if is_cow(&field.ty, "[u8]") { - let path = syn::parse_path("_serde::private::de::borrow_cow_bytes").unwrap(); + } else if is_cow(&field.ty, is_slice_u8) { + let path = syn::parse_str("_serde::private::de::borrow_cow_bytes").unwrap(); 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 // a #[serde(borrow)]. borrowed_lifetimes = borrowable_lifetimes(cx, &ident, &field.ty).unwrap(); @@ -1007,26 +1006,26 @@ type SerAndDe = (Option, Option); fn get_ser_and_de( cx: &Ctxt, attr_name: &'static str, - items: &[syn::NestedMetaItem], + metas: &Punctuated, f: F, ) -> Result, ()> where F: Fn(&Ctxt, &str, &str, &syn::Lit) -> Result, { - let mut ser_item = Attr::none(cx, attr_name); - let mut de_item = Attr::none(cx, attr_name); + let mut ser_meta = Attr::none(cx, attr_name); + let mut de_meta = Attr::none(cx, attr_name); - for item in items { - match *item { - MetaItem(NameValue(ref name, ref lit)) if name == "serialize" => { - if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) { - ser_item.set(v); + for meta in metas { + match *meta { + Meta(NameValue(ref meta)) if meta.ident == "serialize" => { + if let Ok(v) = f(cx, attr_name, meta.ident.as_ref(), &meta.lit) { + ser_meta.set(v); } } - MetaItem(NameValue(ref name, ref lit)) if name == "deserialize" => { - if let Ok(v) = f(cx, attr_name, name.as_ref(), lit) { - de_item.set(v); + Meta(NameValue(ref meta)) if meta.ident == "deserialize" => { + if let Ok(v) = f(cx, attr_name, meta.ident.as_ref(), &meta.lit) { + 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, ()> { +fn get_renames(cx: &Ctxt, items: &Punctuated) -> Result, ()> { get_ser_and_de(cx, "rename", items, get_string_from_lit) } fn get_where_predicates( cx: &Ctxt, - items: &[syn::NestedMetaItem], + items: &Punctuated, ) -> Result>, ()> { get_ser_and_de(cx, "bound", items, parse_lit_into_where) } -pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option> { - match attr.value { - List(ref name, ref items) if name == "serde" => Some(items.iter().cloned().collect()), - _ => None, +pub fn get_serde_meta_items(attr: &syn::Attribute) -> Option> { + if attr.path.segments.len() == 1 && attr.path.segments[0].ident == "serde" { + match attr.interpret_meta() { + 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, lit: &syn::Lit, ) -> Result { - if let syn::Lit::Str(ref s, _) = *lit { - Ok(s.clone()) + if let syn::Lit::Str(ref lit) = *lit { + Ok(lit.value()) } else { cx.error(format!( "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 { 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( @@ -1097,15 +1103,15 @@ fn parse_lit_into_where( let where_string = format!("where {}", string); - syn::parse_where_clause(&where_string) - .map(|wh| wh.predicates) + syn::parse_str::(&where_string) + .map(|wh| wh.predicates.into_iter().collect()) .map_err(|err| cx.error(err)) } -fn parse_lit_into_ty(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result { +fn parse_lit_into_ty(cx: &Ctxt, attr_name: &str, lit: &syn::Lit) -> Result { 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!( "failed to parse type: {} = {:?}", attr_name, string @@ -1126,20 +1132,23 @@ fn parse_lit_into_lifetimes( return Err(()); } - named!(lifetimes -> Vec, - separated_nonempty_list!(punct!("+"), syn::parse::lifetime) - ); + struct BorrowedLifetimes(Punctuated); - if let IResult::Done(rest, o) = lifetimes(&string) { - if rest.trim().is_empty() { - let mut set = BTreeSet::new(); - for lifetime in o { - if !set.insert(lifetime.clone()) { - cx.error(format!("duplicate borrowed lifetime `{}`", lifetime.ident)); - } + impl Synom for BorrowedLifetimes { + named!(parse -> Self, map!( + call!(Punctuated::parse_separated_nonempty), + BorrowedLifetimes + )); + } + + 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))) } @@ -1166,27 +1175,33 @@ fn parse_lit_into_lifetimes( // #[serde(borrow)] // 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 { - syn::Ty::Path(None, ref path) => path, + syn::Type::Path(ref ty) => &ty.path, _ => { return false; } }; let seg = match path.segments.last() { - Some(seg) => seg, + Some(seg) => seg.into_value(), None => { return false; } }; - let params = match seg.parameters { - syn::PathParameters::AngleBracketed(ref params) => params, + let args = match seg.arguments { + syn::PathArguments::AngleBracketed(ref bracketed) => &bracketed.args, _ => { return false; } }; - seg.ident == "Cow" && params.lifetimes.len() == 1 - && params.types == vec![syn::parse_type(elem).unwrap()] && params.bindings.is_empty() + seg.ident == "Cow" + && 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 @@ -1209,11 +1224,34 @@ fn is_cow(ty: &syn::Ty, elem: &str) -> bool { // struct S<'a> { // 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 { - syn::Ty::Rptr(Some(_), ref mut_ty) => { - mut_ty.mutability == syn::Mutability::Immutable - && mut_ty.ty == syn::parse_type(elem).unwrap() + syn::Type::Reference(ref ty) => { + ty.mutability.is_none() && elem(&ty.elem) + } + _ => 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, } @@ -1229,7 +1267,7 @@ fn is_rptr(ty: &syn::Ty, elem: &str) -> bool { fn borrowable_lifetimes( cx: &Ctxt, name: &str, - ty: &syn::Ty, + ty: &syn::Type, ) -> Result, ()> { let mut lifetimes = BTreeSet::new(); collect_lifetimes(ty, &mut lifetimes); @@ -1240,42 +1278,59 @@ fn borrowable_lifetimes( } } -fn collect_lifetimes(ty: &syn::Ty, out: &mut BTreeSet) { +fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet) { match *ty { - syn::Ty::Slice(ref elem) | syn::Ty::Array(ref elem, _) | syn::Ty::Paren(ref elem) => { - collect_lifetimes(elem, out); + syn::Type::Slice(ref ty) => { + collect_lifetimes(&ty.elem, out); } - syn::Ty::Ptr(ref elem) => { - collect_lifetimes(&elem.ty, out); + syn::Type::Array(ref ty) => { + collect_lifetimes(&ty.elem, out); } - syn::Ty::Rptr(ref lifetime, ref elem) => { - out.extend(lifetime.iter().cloned()); - collect_lifetimes(&elem.ty, out); + syn::Type::Ptr(ref ty) => { + collect_lifetimes(&ty.elem, 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); }, - syn::Ty::Path(ref qself, ref path) => { - if let Some(ref qself) = *qself { + syn::Type::Path(ref ty) => { + if let Some(ref qself) = ty.qself { collect_lifetimes(&qself.ty, out); } - for seg in &path.segments { - if let syn::PathParameters::AngleBracketed(ref params) = seg.parameters { - out.extend(params.lifetimes.iter().cloned()); - for ty in ¶ms.types { - collect_lifetimes(ty, out); - } - for binding in ¶ms.bindings { - collect_lifetimes(&binding.ty, out); + for seg in &ty.path.segments { + if let syn::PathArguments::AngleBracketed(ref bracketed) = seg.arguments { + for arg in &bracketed.args { + match *arg { + syn::GenericArgument::Lifetime(ref lifetime) => { + out.insert(lifetime.clone()); + } + 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::Ty::Never - | syn::Ty::TraitObject(_) - | syn::Ty::ImplTrait(_) - | syn::Ty::Infer - | syn::Ty::Mac(_) => {} + syn::Type::Paren(ref ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::Group(ref ty) => { + collect_lifetimes(&ty.elem, out); + } + syn::Type::BareFn(_) + | syn::Type::Never(_) + | syn::Type::TraitObject(_) + | syn::Type::ImplTrait(_) + | syn::Type::Infer(_) + | syn::Type::Macro(_) + | syn::Type::Verbatim(_) => {} } } diff --git a/serde_derive_internals/src/case.rs b/serde_derive_internals/src/case.rs index 3357debb..658a8664 100644 --- a/serde_derive_internals/src/case.rs +++ b/serde_derive_internals/src/case.rs @@ -14,7 +14,7 @@ use std::str::FromStr; use self::RenameRule::*; -#[derive(Debug, PartialEq)] +#[derive(PartialEq)] pub enum RenameRule { /// Don't apply a default rename rule. None, diff --git a/serde_derive_internals/src/check.rs b/serde_derive_internals/src/check.rs index 2dae42f5..0d6946ff 100644 --- a/serde_derive_internals/src/check.rs +++ b/serde_derive_internals/src/check.rs @@ -6,7 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{Body, Container, Style}; +use ast::{Data, Container, Style}; use attr::Identifier; use Ctxt; @@ -21,14 +21,14 @@ pub fn check(cx: &Ctxt, cont: &Container) { /// Getters are only allowed inside structs (not enums) with the `remote` /// attribute. fn check_getter(cx: &Ctxt, cont: &Container) { - match cont.body { - Body::Enum(_) => { - if cont.body.has_getter() { + match cont.data { + Data::Enum(_) => { + if cont.data.has_getter() { cx.error("#[serde(getter = \"...\")] is not allowed in an enum"); } } - Body::Struct(_, _) => { - if cont.body.has_getter() && cont.attrs.remote().is_none() { + Data::Struct(_, _) => { + if cont.data.has_getter() && cont.attrs.remote().is_none() { cx.error( "#[serde(getter = \"...\")] can only be used in structs \ 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 /// last variant may be a newtype variant which is an implicit "other" case. fn check_identifier(cx: &Ctxt, cont: &Container) { - let variants = match cont.body { - Body::Enum(ref variants) => variants, - Body::Struct(_, _) => { + let variants = match cont.data { + Data::Enum(ref variants) => variants, + Data::Struct(_, _) => { return; } }; @@ -102,9 +102,9 @@ fn check_identifier(cx: &Ctxt, cont: &Container) { /// Skip-(de)serializing attributes are not allowed on variants marked /// (de)serialize_with. fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { - let variants = match cont.body { - Body::Enum(ref variants) => variants, - Body::Struct(_, _) => { + let variants = match cont.data { + Data::Enum(ref variants) => variants, + Data::Struct(_, _) => { return; } }; diff --git a/serde_derive_internals/src/lib.rs b/serde_derive_internals/src/lib.rs index 339341ba..1c85ecd5 100644 --- a/serde_derive_internals/src/lib.rs +++ b/serde_derive_internals/src/lib.rs @@ -8,9 +8,8 @@ #![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.19.0")] -extern crate syn; #[macro_use] -extern crate synom; +extern crate syn; pub mod ast; pub mod attr;