devise_core/
ext.rs

1pub use proc_macro2_diagnostics::SpanDiagnosticExt;
2
3use syn::{*, spanned::Spanned, punctuated::Punctuated, token::Comma};
4use proc_macro2::{Span, TokenStream};
5use crate::Result;
6
7type TypeParamBounds = Punctuated<TypeParamBound, Token![+]>;
8
9type WherePredicates = Punctuated<WherePredicate, Token![,]>;
10
11pub trait PathExt {
12    fn is(&self, global: bool, segments: &[&str]) -> bool;
13    fn is_local(&self, segments: &[&str]) -> bool;
14    fn is_global(&self, segments: &[&str]) -> bool;
15    fn last_ident(&self) -> Option<&Ident>;
16    fn generics(&self) -> Option<&Punctuated<GenericArgument, Comma>>;
17}
18
19pub trait TypeExt {
20    fn strip_lifetimes(&mut self);
21    fn with_stripped_lifetimes(&self) -> Type;
22    fn replace_lifetimes(&mut self, with: Lifetime);
23    fn with_replaced_lifetimes(&self, with: Lifetime) -> Type;
24}
25
26pub trait GenericsExt {
27    fn add_type_bound(&mut self, bounds: TypeParamBound);
28    fn add_type_bounds(&mut self, bounds: TypeParamBounds);
29    fn replace(&mut self, ident: &Ident, with: &Ident);
30    fn replace_lifetime(&mut self, n: usize, with: &Lifetime) -> bool;
31    fn insert_lifetime(&mut self, lifetime: LifetimeParam);
32
33    fn bounded_types(&self, bounds: TypeParamBounds) -> WherePredicates;
34    fn parsed_bounded_types(&self, bounds: TokenStream) -> Result<WherePredicates>;
35    fn add_where_predicates(&mut self, predicates: WherePredicates);
36}
37
38pub trait AstItemExt {
39    fn respanned(&self, span: proc_macro2::Span) -> Self where Self: parse::Parse;
40    fn respanned_tokens(&self, span: proc_macro2::Span) -> TokenStream;
41}
42
43#[macro_export]
44macro_rules! quote_respanned {
45    ($span:expr => $($t:tt)*) => ({
46        use $crate::ext::AstItemExt;
47        let tokens = quote_spanned!($span => $($t)*);
48        tokens.respanned_tokens($span)
49    })
50}
51
52pub use quote_respanned;
53
54impl<T: quote::ToTokens> AstItemExt for T {
55    fn respanned(&self, span: Span) -> T
56        where Self: parse::Parse
57    {
58        syn::parse2(self.respanned_tokens(span)).unwrap()
59    }
60
61    fn respanned_tokens(&self, span: Span) -> TokenStream {
62        self.to_token_stream()
63            .into_iter()
64            .map(|mut token| { token.set_span(span); token })
65            .collect()
66    }
67}
68
69impl GenericsExt for Generics {
70    fn add_type_bound(&mut self, bound: TypeParamBound) {
71        self.add_type_bounds(Some(bound).into_iter().collect());
72    }
73
74    fn add_type_bounds(&mut self, bounds: TypeParamBounds) {
75        self.add_where_predicates(self.bounded_types(bounds))
76    }
77
78    fn replace(&mut self, ident: &Ident, with: &Ident) {
79        IdentReplacer::new(ident, with).visit_generics_mut(self);
80    }
81
82    fn replace_lifetime(&mut self, n: usize, with: &Lifetime) -> bool {
83        let lifetime_ident = self.lifetimes().nth(n)
84            .map(|l| l.lifetime.ident.clone());
85
86        if let Some(ref ident) = lifetime_ident {
87            self.replace(ident, &with.ident);
88        }
89
90        lifetime_ident.is_some()
91    }
92
93    fn insert_lifetime(&mut self, lifetime: LifetimeParam) {
94        self.params.insert(0, lifetime.into());
95    }
96
97    fn parsed_bounded_types(&self, bounds: TokenStream) -> Result<WherePredicates> {
98        use syn::parse::Parser;
99        use quote::ToTokens;
100
101        let tokens = bounds.into_token_stream();
102        TypeParamBounds::parse_separated_nonempty.parse2(tokens)
103            .map(|bounds| self.bounded_types(bounds))
104            .map_err(|e| e.span().error(format!("invalid type param bounds: {}", e)))
105    }
106
107    fn bounded_types(&self, bounds: TypeParamBounds) -> WherePredicates {
108        self.type_params()
109            .map(|ty| {
110                let ident = &ty.ident;
111                let bounds = bounds.respanned_tokens(ty.span());
112                syn::parse2(quote_spanned!(ty.span() => #ident: #bounds))
113            })
114            .collect::<syn::Result<Vec<WherePredicate>>>()
115            .expect("valid where predicates")
116            .into_iter()
117            .collect()
118    }
119
120    fn add_where_predicates(&mut self, predicates: WherePredicates) {
121        for p in predicates {
122            self.make_where_clause().predicates.push(p);
123        }
124    }
125}
126
127pub trait GenericExt {
128    fn kind(&self) -> GenericKind;
129}
130
131pub trait GenericParamExt {
132    fn ident(&self) -> &Ident;
133}
134
135pub trait Split2<A, B>: Sized + Iterator {
136    fn split2(self) -> (Vec<A>, Vec<B>);
137}
138
139pub trait Split3<A, B, C>: Sized + Iterator {
140    fn split3(self) -> (Vec<A>, Vec<B>, Vec<C>);
141}
142
143pub trait Split4<A, B, C, D>: Sized + Iterator {
144    fn split4(self) -> (Vec<A>, Vec<B>, Vec<C>, Vec<D>);
145}
146
147pub trait Split6<A, B, C, D, E, F>: Sized + Iterator {
148    fn split6(self) -> (Vec<A>, Vec<B>, Vec<C>, Vec<D>, Vec<E>, Vec<F>);
149}
150
151#[derive(Copy, Clone)]
152#[non_exhaustive]
153pub enum GenericKind {
154    Lifetime,
155    Type,
156    Const,
157    AssocType,
158    AssocConst,
159    Constraint,
160    Unknown
161}
162
163impl PartialEq for GenericKind {
164    fn eq(&self, other: &Self) -> bool {
165        match (self, other) {
166            (GenericKind::Lifetime, GenericKind::Lifetime) => true,
167            (GenericKind::Type, GenericKind::Type) => true,
168            (GenericKind::Const, GenericKind::Const) => true,
169            (GenericKind::AssocType, GenericKind::AssocType) => true,
170            (GenericKind::AssocConst, GenericKind::AssocConst) => true,
171            (GenericKind::Constraint, GenericKind::Constraint) => true,
172            (GenericKind::Lifetime, _) => false,
173            (GenericKind::Type, _) => false,
174            (GenericKind::Const, _) => false,
175            (GenericKind::AssocType, _) => false,
176            (GenericKind::AssocConst, _) => false,
177            (GenericKind::Constraint, _) => false,
178            (GenericKind::Unknown, _) => false,
179        }
180    }
181}
182
183impl PathExt for Path {
184    fn is(&self, global: bool, segments: &[&str]) -> bool {
185        if self.leading_colon.is_some() != global || self.segments.len() != segments.len() {
186            return false;
187        }
188
189        for (segment, wanted) in self.segments.iter().zip(segments.iter()) {
190            if segment.ident != wanted {
191                return false;
192            }
193        }
194
195        true
196    }
197
198    fn is_local(&self, segments: &[&str]) -> bool {
199        self.is(false, segments)
200    }
201
202    fn is_global(&self, segments: &[&str]) -> bool {
203        self.is(true, segments)
204    }
205
206    fn last_ident(&self) -> Option<&Ident> {
207        self.segments.last().map(|p| &p.ident)
208    }
209
210    fn generics(&self) -> Option<&Punctuated<GenericArgument, Comma>> {
211        self.segments.last().and_then(|last| {
212            match last.arguments {
213                PathArguments::AngleBracketed(ref args) => Some(&args.args),
214                _ => None
215            }
216        })
217    }
218}
219
220impl<A, B, I: IntoIterator<Item = (A, B)> + Iterator> Split2<A, B> for I {
221    fn split2(self) -> (Vec<A>, Vec<B>) {
222        let (mut first, mut second) = (vec![], vec![]);
223        self.into_iter().for_each(|(a, b)| {
224            first.push(a);
225            second.push(b);
226        });
227
228        (first, second)
229    }
230}
231
232impl<A, B, C, I: IntoIterator<Item = (A, B, C)> + Iterator> Split3<A, B, C> for I {
233    fn split3(self) -> (Vec<A>, Vec<B>, Vec<C>) {
234        let (mut first, mut second, mut third) = (vec![], vec![], vec![]);
235        self.into_iter().for_each(|(a, b, c)| {
236            first.push(a);
237            second.push(b);
238            third.push(c);
239        });
240
241        (first, second, third)
242    }
243}
244
245impl<A, B, C, D, I: IntoIterator<Item = (A, B, C, D)> + Iterator> Split4<A, B, C, D> for I {
246    fn split4(self) -> (Vec<A>, Vec<B>, Vec<C>, Vec<D>) {
247        let (mut first, mut second, mut third, mut fourth) = (vec![], vec![], vec![], vec![]);
248        self.into_iter().for_each(|(a, b, c, d)| {
249            first.push(a);
250            second.push(b);
251            third.push(c);
252            fourth.push(d);
253        });
254
255        (first, second, third, fourth)
256    }
257}
258
259impl<A, B, C, D, E, F, I: IntoIterator<Item = (A, B, C, D, E, F)> + Iterator> Split6<A, B, C, D, E, F> for I {
260    fn split6(self) -> (Vec<A>, Vec<B>, Vec<C>, Vec<D>, Vec<E>, Vec<F>) {
261        let (mut v1, mut v2, mut v3, mut v4, mut v5, mut v6)
262            = (vec![], vec![], vec![], vec![], vec![], vec![]);
263
264        self.into_iter().for_each(|(a, b, c, d, e, f)| {
265            v1.push(a); v2.push(b); v3.push(c); v4.push(d); v5.push(e); v6.push(f);
266        });
267
268        (v1, v2, v3, v4, v5, v6)
269    }
270}
271
272impl TypeExt for Type {
273    fn replace_lifetimes(&mut self, with: Lifetime) {
274        let mut r = LifetimeReplacer { with };
275        r.visit_type_mut(self);
276    }
277
278    fn strip_lifetimes(&mut self) {
279        self.replace_lifetimes(syn::parse_quote!('_));
280    }
281
282    fn with_stripped_lifetimes(&self) -> Type {
283        let mut new = self.clone();
284        new.strip_lifetimes();
285        new
286    }
287
288    fn with_replaced_lifetimes(&self, with: Lifetime) -> Type {
289        let mut new = self.clone();
290        new.replace_lifetimes(with);
291        new
292    }
293}
294
295pub struct LifetimeReplacer {
296    pub with: Lifetime,
297}
298
299impl VisitMut for LifetimeReplacer {
300    fn visit_lifetime_mut(&mut self, i: &mut Lifetime) {
301        let mut ident = self.with.ident.clone();
302        ident.set_span(i.ident.span());
303        i.ident = ident;
304    }
305}
306
307impl GenericExt for GenericArgument {
308    fn kind(&self) -> GenericKind {
309        match *self {
310            GenericArgument::Lifetime(..) => GenericKind::Lifetime,
311            GenericArgument::Type(..) => GenericKind::Type,
312            GenericArgument::Constraint(..) => GenericKind::Constraint,
313            GenericArgument::Const(..) => GenericKind::Const,
314            GenericArgument::AssocType(_) => GenericKind::AssocType,
315            GenericArgument::AssocConst(_) => GenericKind::AssocConst,
316            _ => GenericKind::Unknown,
317        }
318    }
319}
320
321impl GenericExt for GenericParam {
322    fn kind(&self) -> GenericKind {
323        match *self {
324            GenericParam::Lifetime(..) => GenericKind::Lifetime,
325            GenericParam::Type(..) => GenericKind::Type,
326            GenericParam::Const(..) => GenericKind::Const,
327        }
328    }
329}
330
331impl GenericParamExt for GenericParam {
332    fn ident(&self) -> &Ident {
333        match self {
334            &GenericParam::Type(ref ty) => &ty.ident,
335            &GenericParam::Lifetime(ref l) => &l.lifetime.ident,
336            &GenericParam::Const(ref c) => &c.ident,
337        }
338    }
339}
340
341use syn::visit_mut::VisitMut;
342
343pub struct IdentReplacer<'a> {
344    pub to_replace: &'a Ident,
345    pub with: &'a Ident,
346    pub replaced: bool
347}
348
349impl<'a> IdentReplacer<'a> {
350    pub fn new(to_replace: &'a Ident, with: &'a Ident) -> Self {
351        IdentReplacer { to_replace, with, replaced: false }
352    }
353}
354
355impl<'a> VisitMut for IdentReplacer<'a> {
356    fn visit_ident_mut(&mut self, i: &mut Ident) {
357        if i == self.to_replace {
358            *i = self.with.clone();
359            self.replaced = true;
360        }
361
362        visit_mut::visit_ident_mut(self, i);
363    }
364}