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}