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