1 use syn::{*, punctuated::Punctuated, token::Comma};
2 
3 pub trait PathExt {
is(&self, global: bool, segments: &[&str]) -> bool4     fn is(&self, global: bool, segments: &[&str]) -> bool;
is_local(&self, segments: &[&str]) -> bool5     fn is_local(&self, segments: &[&str]) -> bool;
is_global(&self, segments: &[&str]) -> bool6     fn is_global(&self, segments: &[&str]) -> bool;
last_ident(&self) -> Option<&Ident>7     fn last_ident(&self) -> Option<&Ident>;
generics(&self) -> Option<&Punctuated<GenericArgument, Comma>>8     fn generics(&self) -> Option<&Punctuated<GenericArgument, Comma>>;
9 }
10 
11 pub trait TypeExt {
strip_lifetimes(&mut self)12     fn strip_lifetimes(&mut self);
with_stripped_lifetimes(&self) -> Type13     fn with_stripped_lifetimes(&self) -> Type;
14 }
15 
16 #[derive(Copy, Clone, PartialEq, Eq)]
17 pub enum GenericKind { Lifetime, Type, Binding, Const, Constraint }
18 
19 pub trait GenericExt {
kind(&self) -> GenericKind20     fn kind(&self) -> GenericKind;
21 }
22 
23 pub trait Split2<A, B>: Sized + Iterator {
split2(self) -> (Vec<A>, Vec<B>)24     fn split2(self) -> (Vec<A>, Vec<B>);
25 }
26 
27 pub trait Split3<A, B, C>: Sized + Iterator {
split3(self) -> (Vec<A>, Vec<B>, Vec<C>)28     fn split3(self) -> (Vec<A>, Vec<B>, Vec<C>);
29 }
30 
31 impl PathExt for Path {
is(&self, global: bool, segments: &[&str]) -> bool32     fn is(&self, global: bool, segments: &[&str]) -> bool {
33         if self.leading_colon.is_some() != global || self.segments.len() != segments.len() {
34             return false;
35         }
36 
37         for (segment, wanted) in self.segments.iter().zip(segments.iter()) {
38             if segment.ident != wanted {
39                 return false;
40             }
41         }
42 
43         true
44     }
45 
is_local(&self, segments: &[&str]) -> bool46     fn is_local(&self, segments: &[&str]) -> bool {
47         self.is(false, segments)
48     }
49 
is_global(&self, segments: &[&str]) -> bool50     fn is_global(&self, segments: &[&str]) -> bool {
51         self.is(true, segments)
52     }
53 
last_ident(&self) -> Option<&Ident>54     fn last_ident(&self) -> Option<&Ident> {
55         self.segments.last().map(|p| &p.ident)
56     }
57 
generics(&self) -> Option<&Punctuated<GenericArgument, Comma>>58     fn generics(&self) -> Option<&Punctuated<GenericArgument, Comma>> {
59         self.segments.last().and_then(|last| {
60             match last.arguments {
61                 PathArguments::AngleBracketed(ref args) => Some(&args.args),
62                 _ => None
63             }
64         })
65     }
66 }
67 
68 impl<A, B, I: IntoIterator<Item = (A, B)> + Iterator> Split2<A, B> for I {
split2(self) -> (Vec<A>, Vec<B>)69     fn split2(self) -> (Vec<A>, Vec<B>) {
70         let (mut first, mut second) = (vec![], vec![]);
71         self.into_iter().for_each(|(a, b)| {
72             first.push(a);
73             second.push(b);
74         });
75 
76         (first, second)
77     }
78 }
79 
80 impl<A, B, C, I: IntoIterator<Item = (A, B, C)> + Iterator> Split3<A, B, C> for I {
split3(self) -> (Vec<A>, Vec<B>, Vec<C>)81     fn split3(self) -> (Vec<A>, Vec<B>, Vec<C>) {
82         let (mut first, mut second, mut third) = (vec![], vec![], vec![]);
83         self.into_iter().for_each(|(a, b, c)| {
84             first.push(a);
85             second.push(b);
86             third.push(c);
87         });
88 
89         (first, second, third)
90     }
91 }
92 
93 impl TypeExt for Type {
strip_lifetimes(&mut self)94     fn strip_lifetimes(&mut self) {
95         strip(self);
96     }
97 
with_stripped_lifetimes(&self) -> Type98     fn with_stripped_lifetimes(&self) -> Type {
99         let mut new = self.clone();
100         new.strip_lifetimes();
101         new
102     }
103 }
104 
make_wild(lifetime: &mut Lifetime)105 fn make_wild(lifetime: &mut Lifetime) {
106     lifetime.ident = Ident::new("_", lifetime.ident.span());
107 }
108 
strip(ty: &mut Type)109 fn strip(ty: &mut Type) {
110     match *ty {
111         Type::Reference(ref mut inner) => {
112             inner.lifetime.as_mut().map(make_wild);
113             strip(&mut inner.elem);
114         }
115         Type::Slice(ref mut inner) => strip(&mut inner.elem),
116         Type::Array(ref mut inner) => strip(&mut inner.elem),
117         Type::Ptr(ref mut inner) => strip(&mut inner.elem),
118         Type::Paren(ref mut inner) => strip(&mut inner.elem),
119         Type::Group(ref mut inner) => strip(&mut inner.elem),
120         Type::BareFn(ref mut inner) => {
121             inner.lifetimes.as_mut().map(strip_bound_lifetimes);
122             if let ReturnType::Type(_, ref mut ty) = inner.output {
123                 strip(ty);
124             }
125 
126             inner.inputs.iter_mut().for_each(|input| strip(&mut input.ty));
127         }
128         Type::Tuple(ref mut inner) => {
129             inner.elems.iter_mut().for_each(strip);
130         }
131         Type::Path(ref mut inner) => {
132             if let Some(ref mut qself) = inner.qself {
133                 strip(&mut qself.ty);
134             }
135 
136             strip_path(&mut inner.path);
137         }
138         Type::ImplTrait(ref mut inner) => strip_bounds(&mut inner.bounds),
139         Type::TraitObject(ref mut inner) => strip_bounds(&mut inner.bounds),
140         Type::Infer(_) | Type::Macro(_) | Type::Verbatim(_) | Type::Never(_) => {  }
141         _ => { unimplemented!("unknown type") }
142     }
143 }
144 
strip_bound_lifetimes(bound: &mut BoundLifetimes)145 fn strip_bound_lifetimes(bound: &mut BoundLifetimes) {
146     bound.lifetimes.iter_mut().for_each(|d| make_wild(&mut d.lifetime));
147 }
148 
strip_path(path: &mut Path)149 fn strip_path(path: &mut Path) {
150     for segment in path.segments.iter_mut() {
151         use syn::GenericArgument::*;
152 
153         match segment.arguments {
154             PathArguments::AngleBracketed(ref mut inner) => {
155                 let args = inner.args.clone();
156                 inner.args = args.into_pairs().filter_map(|mut pair| {
157                     match pair.value_mut() {
158                         Lifetime(ref mut l) => make_wild(l),
159                         Type(ref mut ty) => strip(ty),
160                         Binding(ref mut inner) => strip(&mut inner.ty),
161                         Constraint(ref mut inner) => strip_bounds(&mut inner.bounds),
162                         Const(..) => { /* ? */ }
163                     }
164 
165                     Some(pair)
166                 }).collect();
167             }
168             PathArguments::Parenthesized(ref mut args) => {
169                 args.inputs.iter_mut().for_each(strip);
170                 if let ReturnType::Type(_, ref mut ty) = args.output {
171                     strip(ty);
172                 }
173             }
174             PathArguments::None => {  }
175         }
176     }
177 }
178 
strip_bounds(bounds: &mut Punctuated<TypeParamBound, token::Add>)179 fn strip_bounds(bounds: &mut Punctuated<TypeParamBound, token::Add>) {
180     let old_bounds = bounds.clone();
181     *bounds = old_bounds.into_pairs().filter_map(|mut pair| {
182         match pair.value_mut() {
183             TypeParamBound::Lifetime(ref mut l) => make_wild(l),
184             TypeParamBound::Trait(ref mut inner) => {
185                 inner.lifetimes.as_mut().map(strip_bound_lifetimes);
186                 strip_path(&mut inner.path);
187             }
188         }
189 
190         Some(pair)
191     }).collect();
192 }
193 
194 impl GenericExt for GenericArgument {
kind(&self) -> GenericKind195     fn kind(&self) -> GenericKind {
196         match *self {
197             GenericArgument::Lifetime(..) => GenericKind::Lifetime,
198             GenericArgument::Type(..) => GenericKind::Type,
199             GenericArgument::Binding(..) => GenericKind::Binding,
200             GenericArgument::Constraint(..) => GenericKind::Constraint,
201             GenericArgument::Const(..) => GenericKind::Const,
202         }
203     }
204 }
205 
206 impl GenericExt for GenericParam {
kind(&self) -> GenericKind207     fn kind(&self) -> GenericKind {
208         match *self {
209             GenericParam::Lifetime(..) => GenericKind::Lifetime,
210             GenericParam::Type(..) => GenericKind::Type,
211             GenericParam::Const(..) => GenericKind::Const,
212         }
213     }
214 }
215