Attributes on generic formals and split_for_impl
diff --git a/src/generics.rs b/src/generics.rs
index 3d7bd86..0a1dbec 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -9,7 +9,18 @@
pub where_clause: WhereClause,
}
+#[cfg(feature = "printing")]
+/// Returned by `Generics::split_for_impl`.
+#[derive(Debug)]
+pub struct ImplGenerics<'a>(&'a Generics);
+
+#[cfg(feature = "printing")]
+/// Returned by `Generics::split_for_impl`.
+#[derive(Debug)]
+pub struct TyGenerics<'a>(&'a Generics);
+
impl Generics {
+ #[cfg(feature = "printing")]
/// Split a type's generics into the pieces required for impl'ing a trait
/// for that type.
///
@@ -29,50 +40,8 @@
/// # ;
/// # }
/// ```
- pub fn split_for_impl(&self) -> (Generics, Generics, WhereClause) {
- // Remove where clause and type parameter defaults.
- let impl_generics = Generics {
- lifetimes: self.lifetimes.clone(),
- ty_params: self.ty_params
- .iter()
- .map(|ty_param| {
- TyParam {
- ident: ty_param.ident.clone(),
- bounds: ty_param.bounds.clone(),
- default: None,
- }
- })
- .collect(),
- where_clause: WhereClause::none(),
- };
-
- // Remove where clause, type parameter defaults, and bounds.
- let ty_generics = Generics {
- lifetimes: self.lifetimes
- .iter()
- .map(|lifetime_def| {
- LifetimeDef {
- lifetime: lifetime_def.lifetime.clone(),
- bounds: Vec::new(),
- }
- })
- .collect(),
- ty_params: self.ty_params
- .iter()
- .map(|ty_param| {
- TyParam {
- ident: ty_param.ident.clone(),
- bounds: Vec::new(),
- default: None,
- }
- })
- .collect(),
- where_clause: WhereClause::none(),
- };
-
- let where_clause = self.where_clause.clone();
-
- (impl_generics, ty_generics, where_clause)
+ pub fn split_for_impl(&self) -> (ImplGenerics, TyGenerics, &WhereClause) {
+ (ImplGenerics(self), TyGenerics(self), &self.where_clause)
}
}
@@ -96,6 +65,7 @@
/// A lifetime definition, e.g. `'a: 'b+'c+'d`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct LifetimeDef {
+ pub attrs: Vec<Attribute>,
pub lifetime: Lifetime,
pub bounds: Vec<Lifetime>,
}
@@ -103,6 +73,7 @@
impl LifetimeDef {
pub fn new<T: Into<Ident>>(t: T) -> Self {
LifetimeDef {
+ attrs: Vec::new(),
lifetime: Lifetime::new(t),
bounds: Vec::new(),
}
@@ -111,6 +82,7 @@
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TyParam {
+ pub attrs: Vec<Attribute>,
pub ident: Ident,
pub bounds: Vec<TyParamBound>,
pub default: Option<Ty>,
@@ -180,6 +152,7 @@
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
+ use attr::parsing::outer_attr;
use ident::parsing::ident;
use ty::parsing::{ty, poly_trait_ref};
@@ -213,12 +186,14 @@
));
named!(pub lifetime_def -> LifetimeDef, do_parse!(
+ attrs: many0!(outer_attr) >>
life: lifetime >>
bounds: opt_vec!(preceded!(
punct!(":"),
separated_nonempty_list!(punct!("+"), lifetime)
)) >>
(LifetimeDef {
+ attrs: attrs,
lifetime: life,
bounds: bounds,
})
@@ -233,6 +208,7 @@
)));
named!(ty_param -> TyParam, do_parse!(
+ attrs: many0!(outer_attr) >>
id: ident >>
bounds: opt_vec!(preceded!(
punct!(":"),
@@ -243,6 +219,7 @@
ty
)) >>
(TyParam {
+ attrs: attrs,
ident: id,
bounds: bounds,
default: default,
@@ -300,6 +277,7 @@
#[cfg(feature = "printing")]
mod printing {
use super::*;
+ use attr::FilterAttrs;
use quote::{Tokens, ToTokens};
impl ToTokens for Generics {
@@ -318,6 +296,50 @@
}
}
+ impl<'a> ToTokens for ImplGenerics<'a> {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ let has_lifetimes = !self.0.lifetimes.is_empty();
+ let has_ty_params = !self.0.ty_params.is_empty();
+ if has_lifetimes || has_ty_params {
+ tokens.append("<");
+ tokens.append_separated(&self.0.lifetimes, ",");
+ // Leave off the type parameter defaults
+ for (i, ty_param) in self.0.ty_params.iter().enumerate() {
+ if i > 0 || has_lifetimes {
+ tokens.append(",");
+ }
+ tokens.append_all(ty_param.attrs.outer());
+ ty_param.ident.to_tokens(tokens);
+ if !ty_param.bounds.is_empty() {
+ tokens.append(":");
+ tokens.append_separated(&ty_param.bounds, "+");
+ }
+ }
+ tokens.append(">");
+ }
+ }
+ }
+
+ impl<'a> ToTokens for TyGenerics<'a> {
+ fn to_tokens(&self, tokens: &mut Tokens) {
+ let has_lifetimes = !self.0.lifetimes.is_empty();
+ let has_ty_params = !self.0.ty_params.is_empty();
+ if has_lifetimes || has_ty_params {
+ tokens.append("<");
+ // Leave off the lifetime bounds and attributes
+ let lifetimes = self.0.lifetimes.iter().map(|ld| &ld.lifetime);
+ tokens.append_separated(lifetimes, ",");
+ if has_lifetimes && has_ty_params {
+ tokens.append(",");
+ }
+ // Leave off the type parameter bounds, defaults, and attributes
+ let ty_params = self.0.ty_params.iter().map(|tp| &tp.ident);
+ tokens.append_separated(ty_params, ",");
+ tokens.append(">");
+ }
+ }
+ }
+
impl ToTokens for Lifetime {
fn to_tokens(&self, tokens: &mut Tokens) {
self.ident.to_tokens(tokens);
@@ -326,6 +348,7 @@
impl ToTokens for LifetimeDef {
fn to_tokens(&self, tokens: &mut Tokens) {
+ tokens.append_all(self.attrs.outer());
self.lifetime.to_tokens(tokens);
if !self.bounds.is_empty() {
tokens.append(":");
@@ -336,6 +359,7 @@
impl ToTokens for TyParam {
fn to_tokens(&self, tokens: &mut Tokens) {
+ tokens.append_all(self.attrs.outer());
self.ident.to_tokens(tokens);
if !self.bounds.is_empty() {
tokens.append(":");
diff --git a/src/lib.rs b/src/lib.rs
index 40d4825..f331a0b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -36,6 +36,8 @@
mod generics;
pub use generics::{Generics, Lifetime, LifetimeDef, TraitBoundModifier, TyParam, TyParamBound,
WhereBoundPredicate, WhereClause, WherePredicate, WhereRegionPredicate};
+#[cfg(feature = "printing")]
+pub use generics::{ImplGenerics, TyGenerics};
#[cfg(feature = "full")]
mod krate;
diff --git a/tests/test_generics.rs b/tests/test_generics.rs
index c28f044..5c51630 100644
--- a/tests/test_generics.rs
+++ b/tests/test_generics.rs
@@ -1,28 +1,21 @@
extern crate syn;
use syn::*;
-fn simple_path(name: &'static str) -> Path {
- Path {
- global: false,
- segments: vec![
- PathSegment {
- ident: Ident::new(name),
- parameters: PathParameters::none(),
- },
- ],
- }
-}
+#[macro_use]
+extern crate quote;
#[test]
fn test_split_for_impl() {
- // <'a, 'b: 'a, T: 'a = ()> where T: Debug
+ // <'a, 'b: 'a, #[may_dangle] T: 'a = ()> where T: Debug
let generics = Generics {
lifetimes: vec![
LifetimeDef {
+ attrs: Vec::new(),
lifetime: Lifetime::new("'a"),
bounds: Vec::new(),
},
LifetimeDef {
+ attrs: Vec::new(),
lifetime: Lifetime::new("'b"),
bounds: vec![
Lifetime::new("'a"),
@@ -31,6 +24,13 @@
],
ty_params: vec![
TyParam {
+ attrs: vec![
+ Attribute {
+ style: AttrStyle::Outer,
+ value: MetaItem::Word("may_dangle".into()),
+ is_sugared_doc: false,
+ },
+ ],
ident: Ident::new("T"),
bounds: vec![
TyParamBound::Region(Lifetime::new("'a")),
@@ -42,12 +42,12 @@
predicates: vec![
WherePredicate::BoundPredicate(WhereBoundPredicate {
bound_lifetimes: Vec::new(),
- bounded_ty: Ty::Path(None, simple_path("T")),
+ bounded_ty: Ty::Path(None, "T".into()),
bounds: vec![
TyParamBound::Trait(
PolyTraitRef {
bound_lifetimes: Vec::new(),
- trait_ref: simple_path("Debug"),
+ trait_ref: "Debug".into(),
},
TraitBoundModifier::None,
),
@@ -59,55 +59,15 @@
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
- // <'a, 'b: 'a, T: 'a>
- let expected_impl_generics = Generics {
- lifetimes: vec![
- LifetimeDef {
- lifetime: Lifetime::new("'a"),
- bounds: Vec::new(),
- },
- LifetimeDef {
- lifetime: Lifetime::new("'b"),
- bounds: vec![
- Lifetime::new("'a"),
- ],
- },
- ],
- ty_params: vec![
- TyParam {
- ident: Ident::new("T"),
- bounds: vec![
- TyParamBound::Region(Lifetime::new("'a")),
- ],
- default: None,
- },
- ],
- where_clause: WhereClause::none(),
+ let tokens = quote! {
+ impl #impl_generics MyTrait for Test #ty_generics #where_clause {}
};
- // <'a, 'b, T>
- let expected_ty_generics = Generics {
- lifetimes: vec![
- LifetimeDef {
- lifetime: Lifetime::new("'a"),
- bounds: Vec::new(),
- },
- LifetimeDef {
- lifetime: Lifetime::new("'b"),
- bounds: Vec::new(),
- },
- ],
- ty_params: vec![
- TyParam {
- ident: Ident::new("T"),
- bounds: Vec::new(),
- default: None,
- },
- ],
- where_clause: WhereClause::none(),
- };
+ let expected = concat!(
+ "impl < 'a , 'b : 'a , # [ may_dangle ] T : 'a > ",
+ "MyTrait for Test < 'a , 'b , T > ",
+ "where T : Debug { }"
+ );
- assert_eq!(impl_generics, expected_impl_generics);
- assert_eq!(ty_generics, expected_ty_generics);
- assert_eq!(where_clause, generics.where_clause);
+ assert_eq!(expected, tokens.to_string());
}
diff --git a/tests/test_macro_input.rs b/tests/test_macro_input.rs
index 1c25a99..8a0c395 100644
--- a/tests/test_macro_input.rs
+++ b/tests/test_macro_input.rs
@@ -110,11 +110,13 @@
lifetimes: Vec::new(),
ty_params: vec![
TyParam {
+ attrs: Vec::new(),
ident: "T".into(),
bounds: Vec::new(),
default: None,
},
TyParam {
+ attrs: Vec::new(),
ident: "E".into(),
bounds: Vec::new(),
default: None,