]>
Commit | Line | Data |
---|---|---|
e74abb32 XL |
1 | use super::*; |
2 | use crate::punctuated::{Iter, IterMut, Punctuated}; | |
3 | ||
4 | ast_struct! { | |
5 | /// Lifetimes and type parameters attached to a declaration of a function, | |
6 | /// enum, trait, etc. | |
7 | /// | |
8 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
9 | /// feature.* | |
10 | #[derive(Default)] | |
11 | pub struct Generics { | |
12 | pub lt_token: Option<Token![<]>, | |
13 | pub params: Punctuated<GenericParam, Token![,]>, | |
14 | pub gt_token: Option<Token![>]>, | |
15 | pub where_clause: Option<WhereClause>, | |
16 | } | |
17 | } | |
18 | ||
19 | ast_enum_of_structs! { | |
20 | /// A generic type parameter, lifetime, or const generic: `T: Into<String>`, | |
21 | /// `'a: 'b`, `const LEN: usize`. | |
22 | /// | |
23 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
24 | /// feature.* | |
25 | /// | |
26 | /// # Syntax tree enum | |
27 | /// | |
28 | /// This type is a [syntax tree enum]. | |
29 | /// | |
30 | /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums | |
31 | // | |
32 | // TODO: change syntax-tree-enum link to an intra rustdoc link, currently | |
33 | // blocked on https://github.com/rust-lang/rust/issues/62833 | |
34 | pub enum GenericParam { | |
35 | /// A generic type parameter: `T: Into<String>`. | |
36 | Type(TypeParam), | |
37 | ||
38 | /// A lifetime definition: `'a: 'b + 'c + 'd`. | |
39 | Lifetime(LifetimeDef), | |
40 | ||
41 | /// A const generic parameter: `const LENGTH: usize`. | |
42 | Const(ConstParam), | |
43 | } | |
44 | } | |
45 | ||
46 | ast_struct! { | |
47 | /// A generic type parameter: `T: Into<String>`. | |
48 | /// | |
49 | /// *This type is available if Syn is built with the `"derive"` or | |
50 | /// `"full"` feature.* | |
51 | pub struct TypeParam { | |
52 | pub attrs: Vec<Attribute>, | |
53 | pub ident: Ident, | |
54 | pub colon_token: Option<Token![:]>, | |
55 | pub bounds: Punctuated<TypeParamBound, Token![+]>, | |
56 | pub eq_token: Option<Token![=]>, | |
57 | pub default: Option<Type>, | |
58 | } | |
59 | } | |
60 | ||
61 | ast_struct! { | |
62 | /// A lifetime definition: `'a: 'b + 'c + 'd`. | |
63 | /// | |
64 | /// *This type is available if Syn is built with the `"derive"` or | |
65 | /// `"full"` feature.* | |
66 | pub struct LifetimeDef { | |
67 | pub attrs: Vec<Attribute>, | |
68 | pub lifetime: Lifetime, | |
69 | pub colon_token: Option<Token![:]>, | |
70 | pub bounds: Punctuated<Lifetime, Token![+]>, | |
71 | } | |
72 | } | |
73 | ||
74 | ast_struct! { | |
75 | /// A const generic parameter: `const LENGTH: usize`. | |
76 | /// | |
77 | /// *This type is available if Syn is built with the `"derive"` or | |
78 | /// `"full"` feature.* | |
79 | pub struct ConstParam { | |
80 | pub attrs: Vec<Attribute>, | |
81 | pub const_token: Token![const], | |
82 | pub ident: Ident, | |
83 | pub colon_token: Token![:], | |
84 | pub ty: Type, | |
85 | pub eq_token: Option<Token![=]>, | |
86 | pub default: Option<Expr>, | |
87 | } | |
88 | } | |
89 | ||
90 | impl Generics { | |
91 | /// Returns an | |
92 | /// <code | |
93 | /// style="padding-right:0;">Iterator<Item = &</code><a | |
94 | /// href="struct.TypeParam.html"><code | |
95 | /// style="padding-left:0;padding-right:0;">TypeParam</code></a><code | |
96 | /// style="padding-left:0;">></code> | |
97 | /// over the type parameters in `self.params`. | |
98 | pub fn type_params(&self) -> TypeParams { | |
99 | TypeParams(self.params.iter()) | |
100 | } | |
101 | ||
102 | /// Returns an | |
103 | /// <code | |
104 | /// style="padding-right:0;">Iterator<Item = &mut </code><a | |
105 | /// href="struct.TypeParam.html"><code | |
106 | /// style="padding-left:0;padding-right:0;">TypeParam</code></a><code | |
107 | /// style="padding-left:0;">></code> | |
108 | /// over the type parameters in `self.params`. | |
109 | pub fn type_params_mut(&mut self) -> TypeParamsMut { | |
110 | TypeParamsMut(self.params.iter_mut()) | |
111 | } | |
112 | ||
113 | /// Returns an | |
114 | /// <code | |
115 | /// style="padding-right:0;">Iterator<Item = &</code><a | |
116 | /// href="struct.LifetimeDef.html"><code | |
117 | /// style="padding-left:0;padding-right:0;">LifetimeDef</code></a><code | |
118 | /// style="padding-left:0;">></code> | |
119 | /// over the lifetime parameters in `self.params`. | |
120 | pub fn lifetimes(&self) -> Lifetimes { | |
121 | Lifetimes(self.params.iter()) | |
122 | } | |
123 | ||
124 | /// Returns an | |
125 | /// <code | |
126 | /// style="padding-right:0;">Iterator<Item = &mut </code><a | |
127 | /// href="struct.LifetimeDef.html"><code | |
128 | /// style="padding-left:0;padding-right:0;">LifetimeDef</code></a><code | |
129 | /// style="padding-left:0;">></code> | |
130 | /// over the lifetime parameters in `self.params`. | |
131 | pub fn lifetimes_mut(&mut self) -> LifetimesMut { | |
132 | LifetimesMut(self.params.iter_mut()) | |
133 | } | |
134 | ||
135 | /// Returns an | |
136 | /// <code | |
137 | /// style="padding-right:0;">Iterator<Item = &</code><a | |
138 | /// href="struct.ConstParam.html"><code | |
139 | /// style="padding-left:0;padding-right:0;">ConstParam</code></a><code | |
140 | /// style="padding-left:0;">></code> | |
141 | /// over the constant parameters in `self.params`. | |
142 | pub fn const_params(&self) -> ConstParams { | |
143 | ConstParams(self.params.iter()) | |
144 | } | |
145 | ||
146 | /// Returns an | |
147 | /// <code | |
148 | /// style="padding-right:0;">Iterator<Item = &mut </code><a | |
149 | /// href="struct.ConstParam.html"><code | |
150 | /// style="padding-left:0;padding-right:0;">ConstParam</code></a><code | |
151 | /// style="padding-left:0;">></code> | |
152 | /// over the constant parameters in `self.params`. | |
153 | pub fn const_params_mut(&mut self) -> ConstParamsMut { | |
154 | ConstParamsMut(self.params.iter_mut()) | |
155 | } | |
156 | ||
157 | /// Initializes an empty `where`-clause if there is not one present already. | |
158 | pub fn make_where_clause(&mut self) -> &mut WhereClause { | |
159 | // This is Option::get_or_insert_with in Rust 1.20. | |
160 | if self.where_clause.is_none() { | |
161 | self.where_clause = Some(WhereClause { | |
162 | where_token: <Token![where]>::default(), | |
163 | predicates: Punctuated::new(), | |
164 | }); | |
165 | } | |
166 | match &mut self.where_clause { | |
167 | Some(where_clause) => where_clause, | |
168 | None => unreachable!(), | |
169 | } | |
170 | } | |
171 | } | |
172 | ||
173 | pub struct TypeParams<'a>(Iter<'a, GenericParam>); | |
174 | ||
175 | impl<'a> Iterator for TypeParams<'a> { | |
176 | type Item = &'a TypeParam; | |
177 | ||
178 | fn next(&mut self) -> Option<Self::Item> { | |
179 | let next = match self.0.next() { | |
180 | Some(item) => item, | |
181 | None => return None, | |
182 | }; | |
183 | if let GenericParam::Type(type_param) = next { | |
184 | Some(type_param) | |
185 | } else { | |
186 | self.next() | |
187 | } | |
188 | } | |
189 | } | |
190 | ||
191 | pub struct TypeParamsMut<'a>(IterMut<'a, GenericParam>); | |
192 | ||
193 | impl<'a> Iterator for TypeParamsMut<'a> { | |
194 | type Item = &'a mut TypeParam; | |
195 | ||
196 | fn next(&mut self) -> Option<Self::Item> { | |
197 | let next = match self.0.next() { | |
198 | Some(item) => item, | |
199 | None => return None, | |
200 | }; | |
201 | if let GenericParam::Type(type_param) = next { | |
202 | Some(type_param) | |
203 | } else { | |
204 | self.next() | |
205 | } | |
206 | } | |
207 | } | |
208 | ||
209 | pub struct Lifetimes<'a>(Iter<'a, GenericParam>); | |
210 | ||
211 | impl<'a> Iterator for Lifetimes<'a> { | |
212 | type Item = &'a LifetimeDef; | |
213 | ||
214 | fn next(&mut self) -> Option<Self::Item> { | |
215 | let next = match self.0.next() { | |
216 | Some(item) => item, | |
217 | None => return None, | |
218 | }; | |
219 | if let GenericParam::Lifetime(lifetime) = next { | |
220 | Some(lifetime) | |
221 | } else { | |
222 | self.next() | |
223 | } | |
224 | } | |
225 | } | |
226 | ||
227 | pub struct LifetimesMut<'a>(IterMut<'a, GenericParam>); | |
228 | ||
229 | impl<'a> Iterator for LifetimesMut<'a> { | |
230 | type Item = &'a mut LifetimeDef; | |
231 | ||
232 | fn next(&mut self) -> Option<Self::Item> { | |
233 | let next = match self.0.next() { | |
234 | Some(item) => item, | |
235 | None => return None, | |
236 | }; | |
237 | if let GenericParam::Lifetime(lifetime) = next { | |
238 | Some(lifetime) | |
239 | } else { | |
240 | self.next() | |
241 | } | |
242 | } | |
243 | } | |
244 | ||
245 | pub struct ConstParams<'a>(Iter<'a, GenericParam>); | |
246 | ||
247 | impl<'a> Iterator for ConstParams<'a> { | |
248 | type Item = &'a ConstParam; | |
249 | ||
250 | fn next(&mut self) -> Option<Self::Item> { | |
251 | let next = match self.0.next() { | |
252 | Some(item) => item, | |
253 | None => return None, | |
254 | }; | |
255 | if let GenericParam::Const(const_param) = next { | |
256 | Some(const_param) | |
257 | } else { | |
258 | self.next() | |
259 | } | |
260 | } | |
261 | } | |
262 | ||
263 | pub struct ConstParamsMut<'a>(IterMut<'a, GenericParam>); | |
264 | ||
265 | impl<'a> Iterator for ConstParamsMut<'a> { | |
266 | type Item = &'a mut ConstParam; | |
267 | ||
268 | fn next(&mut self) -> Option<Self::Item> { | |
269 | let next = match self.0.next() { | |
270 | Some(item) => item, | |
271 | None => return None, | |
272 | }; | |
273 | if let GenericParam::Const(const_param) = next { | |
274 | Some(const_param) | |
275 | } else { | |
276 | self.next() | |
277 | } | |
278 | } | |
279 | } | |
280 | ||
281 | /// Returned by `Generics::split_for_impl`. | |
282 | /// | |
283 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
284 | /// feature and the `"printing"` feature.* | |
285 | #[cfg(feature = "printing")] | |
286 | #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] | |
287 | #[cfg_attr(feature = "clone-impls", derive(Clone))] | |
288 | pub struct ImplGenerics<'a>(&'a Generics); | |
289 | ||
290 | /// Returned by `Generics::split_for_impl`. | |
291 | /// | |
292 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
293 | /// feature and the `"printing"` feature.* | |
294 | #[cfg(feature = "printing")] | |
295 | #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] | |
296 | #[cfg_attr(feature = "clone-impls", derive(Clone))] | |
297 | pub struct TypeGenerics<'a>(&'a Generics); | |
298 | ||
299 | /// Returned by `TypeGenerics::as_turbofish`. | |
300 | /// | |
301 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
302 | /// feature and the `"printing"` feature.* | |
303 | #[cfg(feature = "printing")] | |
304 | #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] | |
305 | #[cfg_attr(feature = "clone-impls", derive(Clone))] | |
306 | pub struct Turbofish<'a>(&'a Generics); | |
307 | ||
308 | #[cfg(feature = "printing")] | |
309 | impl Generics { | |
310 | /// Split a type's generics into the pieces required for impl'ing a trait | |
311 | /// for that type. | |
312 | /// | |
313 | /// ``` | |
314 | /// # use proc_macro2::{Span, Ident}; | |
315 | /// # use quote::quote; | |
316 | /// # | |
60c5eb7d XL |
317 | /// # let generics: syn::Generics = Default::default(); |
318 | /// # let name = Ident::new("MyType", Span::call_site()); | |
e74abb32 XL |
319 | /// # |
320 | /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); | |
321 | /// quote! { | |
322 | /// impl #impl_generics MyTrait for #name #ty_generics #where_clause { | |
323 | /// // ... | |
324 | /// } | |
325 | /// } | |
60c5eb7d | 326 | /// # ; |
e74abb32 XL |
327 | /// ``` |
328 | /// | |
329 | /// *This method is available if Syn is built with the `"derive"` or | |
330 | /// `"full"` feature and the `"printing"` feature.* | |
331 | pub fn split_for_impl(&self) -> (ImplGenerics, TypeGenerics, Option<&WhereClause>) { | |
332 | ( | |
333 | ImplGenerics(self), | |
334 | TypeGenerics(self), | |
335 | self.where_clause.as_ref(), | |
336 | ) | |
337 | } | |
338 | } | |
339 | ||
340 | #[cfg(feature = "printing")] | |
341 | impl<'a> TypeGenerics<'a> { | |
342 | /// Turn a type's generics like `<X, Y>` into a turbofish like `::<X, Y>`. | |
343 | /// | |
344 | /// *This method is available if Syn is built with the `"derive"` or | |
345 | /// `"full"` feature and the `"printing"` feature.* | |
346 | pub fn as_turbofish(&self) -> Turbofish { | |
347 | Turbofish(self.0) | |
348 | } | |
349 | } | |
350 | ||
351 | ast_struct! { | |
352 | /// A set of bound lifetimes: `for<'a, 'b, 'c>`. | |
353 | /// | |
354 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
355 | /// feature.* | |
356 | #[derive(Default)] | |
357 | pub struct BoundLifetimes { | |
358 | pub for_token: Token![for], | |
359 | pub lt_token: Token![<], | |
360 | pub lifetimes: Punctuated<LifetimeDef, Token![,]>, | |
361 | pub gt_token: Token![>], | |
362 | } | |
363 | } | |
364 | ||
365 | impl LifetimeDef { | |
366 | pub fn new(lifetime: Lifetime) -> Self { | |
367 | LifetimeDef { | |
368 | attrs: Vec::new(), | |
369 | lifetime, | |
370 | colon_token: None, | |
371 | bounds: Punctuated::new(), | |
372 | } | |
373 | } | |
374 | } | |
375 | ||
376 | impl From<Ident> for TypeParam { | |
377 | fn from(ident: Ident) -> Self { | |
378 | TypeParam { | |
379 | attrs: vec![], | |
380 | ident, | |
381 | colon_token: None, | |
382 | bounds: Punctuated::new(), | |
383 | eq_token: None, | |
384 | default: None, | |
385 | } | |
386 | } | |
387 | } | |
388 | ||
389 | ast_enum_of_structs! { | |
390 | /// A trait or lifetime used as a bound on a type parameter. | |
391 | /// | |
392 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
393 | /// feature.* | |
394 | pub enum TypeParamBound { | |
395 | Trait(TraitBound), | |
396 | Lifetime(Lifetime), | |
397 | } | |
398 | } | |
399 | ||
400 | ast_struct! { | |
401 | /// A trait used as a bound on a type parameter. | |
402 | /// | |
403 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
404 | /// feature.* | |
405 | pub struct TraitBound { | |
406 | pub paren_token: Option<token::Paren>, | |
407 | pub modifier: TraitBoundModifier, | |
408 | /// The `for<'a>` in `for<'a> Foo<&'a T>` | |
409 | pub lifetimes: Option<BoundLifetimes>, | |
410 | /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>` | |
411 | pub path: Path, | |
412 | } | |
413 | } | |
414 | ||
415 | ast_enum! { | |
416 | /// A modifier on a trait bound, currently only used for the `?` in | |
417 | /// `?Sized`. | |
418 | /// | |
419 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
420 | /// feature.* | |
421 | #[cfg_attr(feature = "clone-impls", derive(Copy))] | |
422 | pub enum TraitBoundModifier { | |
423 | None, | |
424 | Maybe(Token![?]), | |
425 | } | |
426 | } | |
427 | ||
428 | ast_struct! { | |
429 | /// A `where` clause in a definition: `where T: Deserialize<'de>, D: | |
430 | /// 'static`. | |
431 | /// | |
432 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
433 | /// feature.* | |
434 | pub struct WhereClause { | |
435 | pub where_token: Token![where], | |
436 | pub predicates: Punctuated<WherePredicate, Token![,]>, | |
437 | } | |
438 | } | |
439 | ||
440 | ast_enum_of_structs! { | |
441 | /// A single predicate in a `where` clause: `T: Deserialize<'de>`. | |
442 | /// | |
443 | /// *This type is available if Syn is built with the `"derive"` or `"full"` | |
444 | /// feature.* | |
445 | /// | |
446 | /// # Syntax tree enum | |
447 | /// | |
448 | /// This type is a [syntax tree enum]. | |
449 | /// | |
450 | /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums | |
451 | // | |
452 | // TODO: change syntax-tree-enum link to an intra rustdoc link, currently | |
453 | // blocked on https://github.com/rust-lang/rust/issues/62833 | |
454 | pub enum WherePredicate { | |
455 | /// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`. | |
456 | Type(PredicateType), | |
457 | ||
458 | /// A lifetime predicate in a `where` clause: `'a: 'b + 'c`. | |
459 | Lifetime(PredicateLifetime), | |
460 | ||
461 | /// An equality predicate in a `where` clause (unsupported). | |
462 | Eq(PredicateEq), | |
463 | } | |
464 | } | |
465 | ||
466 | ast_struct! { | |
467 | /// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`. | |
468 | /// | |
469 | /// *This type is available if Syn is built with the `"derive"` or | |
470 | /// `"full"` feature.* | |
471 | pub struct PredicateType { | |
472 | /// Any lifetimes from a `for` binding | |
473 | pub lifetimes: Option<BoundLifetimes>, | |
474 | /// The type being bounded | |
475 | pub bounded_ty: Type, | |
476 | pub colon_token: Token![:], | |
477 | /// Trait and lifetime bounds (`Clone+Send+'static`) | |
478 | pub bounds: Punctuated<TypeParamBound, Token![+]>, | |
479 | } | |
480 | } | |
481 | ||
482 | ast_struct! { | |
483 | /// A lifetime predicate in a `where` clause: `'a: 'b + 'c`. | |
484 | /// | |
485 | /// *This type is available if Syn is built with the `"derive"` or | |
486 | /// `"full"` feature.* | |
487 | pub struct PredicateLifetime { | |
488 | pub lifetime: Lifetime, | |
489 | pub colon_token: Token![:], | |
490 | pub bounds: Punctuated<Lifetime, Token![+]>, | |
491 | } | |
492 | } | |
493 | ||
494 | ast_struct! { | |
495 | /// An equality predicate in a `where` clause (unsupported). | |
496 | /// | |
497 | /// *This type is available if Syn is built with the `"derive"` or | |
498 | /// `"full"` feature.* | |
499 | pub struct PredicateEq { | |
500 | pub lhs_ty: Type, | |
501 | pub eq_token: Token![=], | |
502 | pub rhs_ty: Type, | |
503 | } | |
504 | } | |
505 | ||
506 | #[cfg(feature = "parsing")] | |
507 | pub mod parsing { | |
508 | use super::*; | |
509 | ||
510 | use crate::parse::{Parse, ParseStream, Result}; | |
511 | ||
512 | impl Parse for Generics { | |
513 | fn parse(input: ParseStream) -> Result<Self> { | |
514 | if !input.peek(Token![<]) { | |
515 | return Ok(Generics::default()); | |
516 | } | |
517 | ||
518 | let lt_token: Token![<] = input.parse()?; | |
519 | ||
520 | let mut params = Punctuated::new(); | |
521 | let mut allow_lifetime_param = true; | |
522 | let mut allow_type_param = true; | |
523 | loop { | |
524 | if input.peek(Token![>]) { | |
525 | break; | |
526 | } | |
527 | ||
528 | let attrs = input.call(Attribute::parse_outer)?; | |
529 | let lookahead = input.lookahead1(); | |
530 | if allow_lifetime_param && lookahead.peek(Lifetime) { | |
531 | params.push_value(GenericParam::Lifetime(LifetimeDef { | |
532 | attrs, | |
533 | ..input.parse()? | |
534 | })); | |
535 | } else if allow_type_param && lookahead.peek(Ident) { | |
536 | allow_lifetime_param = false; | |
537 | params.push_value(GenericParam::Type(TypeParam { | |
538 | attrs, | |
539 | ..input.parse()? | |
540 | })); | |
541 | } else if lookahead.peek(Token![const]) { | |
542 | allow_lifetime_param = false; | |
543 | allow_type_param = false; | |
544 | params.push_value(GenericParam::Const(ConstParam { | |
545 | attrs, | |
546 | ..input.parse()? | |
547 | })); | |
548 | } else { | |
549 | return Err(lookahead.error()); | |
550 | } | |
551 | ||
552 | if input.peek(Token![>]) { | |
553 | break; | |
554 | } | |
555 | let punct = input.parse()?; | |
556 | params.push_punct(punct); | |
557 | } | |
558 | ||
559 | let gt_token: Token![>] = input.parse()?; | |
560 | ||
561 | Ok(Generics { | |
562 | lt_token: Some(lt_token), | |
563 | params, | |
564 | gt_token: Some(gt_token), | |
565 | where_clause: None, | |
566 | }) | |
567 | } | |
568 | } | |
569 | ||
570 | impl Parse for GenericParam { | |
571 | fn parse(input: ParseStream) -> Result<Self> { | |
572 | let attrs = input.call(Attribute::parse_outer)?; | |
573 | ||
574 | let lookahead = input.lookahead1(); | |
575 | if lookahead.peek(Ident) { | |
576 | Ok(GenericParam::Type(TypeParam { | |
577 | attrs, | |
578 | ..input.parse()? | |
579 | })) | |
580 | } else if lookahead.peek(Lifetime) { | |
581 | Ok(GenericParam::Lifetime(LifetimeDef { | |
582 | attrs, | |
583 | ..input.parse()? | |
584 | })) | |
585 | } else if lookahead.peek(Token![const]) { | |
586 | Ok(GenericParam::Const(ConstParam { | |
587 | attrs, | |
588 | ..input.parse()? | |
589 | })) | |
590 | } else { | |
591 | Err(lookahead.error()) | |
592 | } | |
593 | } | |
594 | } | |
595 | ||
596 | impl Parse for LifetimeDef { | |
597 | fn parse(input: ParseStream) -> Result<Self> { | |
598 | let has_colon; | |
599 | Ok(LifetimeDef { | |
600 | attrs: input.call(Attribute::parse_outer)?, | |
601 | lifetime: input.parse()?, | |
602 | colon_token: { | |
603 | if input.peek(Token![:]) { | |
604 | has_colon = true; | |
605 | Some(input.parse()?) | |
606 | } else { | |
607 | has_colon = false; | |
608 | None | |
609 | } | |
610 | }, | |
611 | bounds: { | |
612 | let mut bounds = Punctuated::new(); | |
613 | if has_colon { | |
614 | loop { | |
615 | if input.peek(Token![,]) || input.peek(Token![>]) { | |
616 | break; | |
617 | } | |
618 | let value = input.parse()?; | |
619 | bounds.push_value(value); | |
620 | if !input.peek(Token![+]) { | |
621 | break; | |
622 | } | |
623 | let punct = input.parse()?; | |
624 | bounds.push_punct(punct); | |
625 | } | |
626 | } | |
627 | bounds | |
628 | }, | |
629 | }) | |
630 | } | |
631 | } | |
632 | ||
633 | impl Parse for BoundLifetimes { | |
634 | fn parse(input: ParseStream) -> Result<Self> { | |
635 | Ok(BoundLifetimes { | |
636 | for_token: input.parse()?, | |
637 | lt_token: input.parse()?, | |
638 | lifetimes: { | |
639 | let mut lifetimes = Punctuated::new(); | |
640 | while !input.peek(Token![>]) { | |
641 | lifetimes.push_value(input.parse()?); | |
642 | if input.peek(Token![>]) { | |
643 | break; | |
644 | } | |
645 | lifetimes.push_punct(input.parse()?); | |
646 | } | |
647 | lifetimes | |
648 | }, | |
649 | gt_token: input.parse()?, | |
650 | }) | |
651 | } | |
652 | } | |
653 | ||
654 | impl Parse for Option<BoundLifetimes> { | |
655 | fn parse(input: ParseStream) -> Result<Self> { | |
656 | if input.peek(Token![for]) { | |
657 | input.parse().map(Some) | |
658 | } else { | |
659 | Ok(None) | |
660 | } | |
661 | } | |
662 | } | |
663 | ||
664 | impl Parse for TypeParam { | |
665 | fn parse(input: ParseStream) -> Result<Self> { | |
666 | let has_colon; | |
667 | let has_default; | |
668 | Ok(TypeParam { | |
669 | attrs: input.call(Attribute::parse_outer)?, | |
670 | ident: input.parse()?, | |
671 | colon_token: { | |
672 | if input.peek(Token![:]) { | |
673 | has_colon = true; | |
674 | Some(input.parse()?) | |
675 | } else { | |
676 | has_colon = false; | |
677 | None | |
678 | } | |
679 | }, | |
680 | bounds: { | |
681 | let mut bounds = Punctuated::new(); | |
682 | if has_colon { | |
683 | loop { | |
684 | if input.peek(Token![,]) | |
685 | || input.peek(Token![>]) | |
686 | || input.peek(Token![=]) | |
687 | { | |
688 | break; | |
689 | } | |
690 | let value = input.parse()?; | |
691 | bounds.push_value(value); | |
692 | if !input.peek(Token![+]) { | |
693 | break; | |
694 | } | |
695 | let punct = input.parse()?; | |
696 | bounds.push_punct(punct); | |
697 | } | |
698 | } | |
699 | bounds | |
700 | }, | |
701 | eq_token: { | |
702 | if input.peek(Token![=]) { | |
703 | has_default = true; | |
704 | Some(input.parse()?) | |
705 | } else { | |
706 | has_default = false; | |
707 | None | |
708 | } | |
709 | }, | |
710 | default: { | |
711 | if has_default { | |
712 | Some(input.parse()?) | |
713 | } else { | |
714 | None | |
715 | } | |
716 | }, | |
717 | }) | |
718 | } | |
719 | } | |
720 | ||
721 | impl Parse for TypeParamBound { | |
722 | fn parse(input: ParseStream) -> Result<Self> { | |
723 | if input.peek(Lifetime) { | |
724 | return input.parse().map(TypeParamBound::Lifetime); | |
725 | } | |
726 | ||
727 | if input.peek(token::Paren) { | |
728 | let content; | |
729 | let paren_token = parenthesized!(content in input); | |
730 | let mut bound: TraitBound = content.parse()?; | |
731 | bound.paren_token = Some(paren_token); | |
732 | return Ok(TypeParamBound::Trait(bound)); | |
733 | } | |
734 | ||
735 | input.parse().map(TypeParamBound::Trait) | |
736 | } | |
737 | } | |
738 | ||
739 | impl Parse for TraitBound { | |
740 | fn parse(input: ParseStream) -> Result<Self> { | |
741 | let modifier: TraitBoundModifier = input.parse()?; | |
742 | let lifetimes: Option<BoundLifetimes> = input.parse()?; | |
743 | ||
744 | let mut path: Path = input.parse()?; | |
745 | if path.segments.last().unwrap().arguments.is_empty() && input.peek(token::Paren) { | |
746 | let parenthesized = PathArguments::Parenthesized(input.parse()?); | |
747 | path.segments.last_mut().unwrap().arguments = parenthesized; | |
748 | } | |
749 | ||
750 | Ok(TraitBound { | |
751 | paren_token: None, | |
752 | modifier, | |
753 | lifetimes, | |
754 | path, | |
755 | }) | |
756 | } | |
757 | } | |
758 | ||
759 | impl Parse for TraitBoundModifier { | |
760 | fn parse(input: ParseStream) -> Result<Self> { | |
761 | if input.peek(Token![?]) { | |
762 | input.parse().map(TraitBoundModifier::Maybe) | |
763 | } else { | |
764 | Ok(TraitBoundModifier::None) | |
765 | } | |
766 | } | |
767 | } | |
768 | ||
769 | impl Parse for ConstParam { | |
770 | fn parse(input: ParseStream) -> Result<Self> { | |
771 | let mut default = None; | |
772 | Ok(ConstParam { | |
773 | attrs: input.call(Attribute::parse_outer)?, | |
774 | const_token: input.parse()?, | |
775 | ident: input.parse()?, | |
776 | colon_token: input.parse()?, | |
777 | ty: input.parse()?, | |
778 | eq_token: { | |
779 | if input.peek(Token![=]) { | |
780 | let eq_token = input.parse()?; | |
781 | default = Some(input.parse::<Expr>()?); | |
782 | Some(eq_token) | |
783 | } else { | |
784 | None | |
785 | } | |
786 | }, | |
787 | default, | |
788 | }) | |
789 | } | |
790 | } | |
791 | ||
792 | impl Parse for WhereClause { | |
793 | fn parse(input: ParseStream) -> Result<Self> { | |
794 | Ok(WhereClause { | |
795 | where_token: input.parse()?, | |
796 | predicates: { | |
797 | let mut predicates = Punctuated::new(); | |
798 | loop { | |
799 | if input.is_empty() | |
800 | || input.peek(token::Brace) | |
801 | || input.peek(Token![,]) | |
802 | || input.peek(Token![;]) | |
803 | || input.peek(Token![:]) && !input.peek(Token![::]) | |
804 | || input.peek(Token![=]) | |
805 | { | |
806 | break; | |
807 | } | |
808 | let value = input.parse()?; | |
809 | predicates.push_value(value); | |
810 | if !input.peek(Token![,]) { | |
811 | break; | |
812 | } | |
813 | let punct = input.parse()?; | |
814 | predicates.push_punct(punct); | |
815 | } | |
816 | predicates | |
817 | }, | |
818 | }) | |
819 | } | |
820 | } | |
821 | ||
822 | impl Parse for Option<WhereClause> { | |
823 | fn parse(input: ParseStream) -> Result<Self> { | |
824 | if input.peek(Token![where]) { | |
825 | input.parse().map(Some) | |
826 | } else { | |
827 | Ok(None) | |
828 | } | |
829 | } | |
830 | } | |
831 | ||
832 | impl Parse for WherePredicate { | |
833 | fn parse(input: ParseStream) -> Result<Self> { | |
834 | if input.peek(Lifetime) && input.peek2(Token![:]) { | |
835 | Ok(WherePredicate::Lifetime(PredicateLifetime { | |
836 | lifetime: input.parse()?, | |
837 | colon_token: input.parse()?, | |
838 | bounds: { | |
839 | let mut bounds = Punctuated::new(); | |
840 | loop { | |
841 | if input.is_empty() | |
842 | || input.peek(token::Brace) | |
843 | || input.peek(Token![,]) | |
844 | || input.peek(Token![;]) | |
845 | || input.peek(Token![:]) | |
846 | || input.peek(Token![=]) | |
847 | { | |
848 | break; | |
849 | } | |
850 | let value = input.parse()?; | |
851 | bounds.push_value(value); | |
852 | if !input.peek(Token![+]) { | |
853 | break; | |
854 | } | |
855 | let punct = input.parse()?; | |
856 | bounds.push_punct(punct); | |
857 | } | |
858 | bounds | |
859 | }, | |
860 | })) | |
861 | } else { | |
862 | Ok(WherePredicate::Type(PredicateType { | |
863 | lifetimes: input.parse()?, | |
864 | bounded_ty: input.parse()?, | |
865 | colon_token: input.parse()?, | |
866 | bounds: { | |
867 | let mut bounds = Punctuated::new(); | |
868 | loop { | |
869 | if input.is_empty() | |
870 | || input.peek(token::Brace) | |
871 | || input.peek(Token![,]) | |
872 | || input.peek(Token![;]) | |
873 | || input.peek(Token![:]) && !input.peek(Token![::]) | |
874 | || input.peek(Token![=]) | |
875 | { | |
876 | break; | |
877 | } | |
878 | let value = input.parse()?; | |
879 | bounds.push_value(value); | |
880 | if !input.peek(Token![+]) { | |
881 | break; | |
882 | } | |
883 | let punct = input.parse()?; | |
884 | bounds.push_punct(punct); | |
885 | } | |
886 | bounds | |
887 | }, | |
888 | })) | |
889 | } | |
890 | } | |
891 | } | |
892 | } | |
893 | ||
894 | #[cfg(feature = "printing")] | |
895 | mod printing { | |
896 | use super::*; | |
897 | ||
898 | use proc_macro2::TokenStream; | |
899 | use quote::{ToTokens, TokenStreamExt}; | |
900 | ||
901 | use crate::attr::FilterAttrs; | |
902 | use crate::print::TokensOrDefault; | |
903 | ||
904 | impl ToTokens for Generics { | |
905 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
906 | if self.params.is_empty() { | |
907 | return; | |
908 | } | |
909 | ||
910 | TokensOrDefault(&self.lt_token).to_tokens(tokens); | |
911 | ||
912 | // Print lifetimes before types and consts, regardless of their | |
913 | // order in self.params. | |
914 | // | |
915 | // TODO: ordering rules for const parameters vs type parameters have | |
916 | // not been settled yet. https://github.com/rust-lang/rust/issues/44580 | |
917 | let mut trailing_or_empty = true; | |
918 | for param in self.params.pairs() { | |
919 | if let GenericParam::Lifetime(_) = **param.value() { | |
920 | param.to_tokens(tokens); | |
921 | trailing_or_empty = param.punct().is_some(); | |
922 | } | |
923 | } | |
924 | for param in self.params.pairs() { | |
925 | match **param.value() { | |
926 | GenericParam::Type(_) | GenericParam::Const(_) => { | |
927 | if !trailing_or_empty { | |
928 | <Token![,]>::default().to_tokens(tokens); | |
929 | trailing_or_empty = true; | |
930 | } | |
931 | param.to_tokens(tokens); | |
932 | } | |
933 | GenericParam::Lifetime(_) => {} | |
934 | } | |
935 | } | |
936 | ||
937 | TokensOrDefault(&self.gt_token).to_tokens(tokens); | |
938 | } | |
939 | } | |
940 | ||
941 | impl<'a> ToTokens for ImplGenerics<'a> { | |
942 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
943 | if self.0.params.is_empty() { | |
944 | return; | |
945 | } | |
946 | ||
947 | TokensOrDefault(&self.0.lt_token).to_tokens(tokens); | |
948 | ||
949 | // Print lifetimes before types and consts, regardless of their | |
950 | // order in self.params. | |
951 | // | |
952 | // TODO: ordering rules for const parameters vs type parameters have | |
953 | // not been settled yet. https://github.com/rust-lang/rust/issues/44580 | |
954 | let mut trailing_or_empty = true; | |
955 | for param in self.0.params.pairs() { | |
956 | if let GenericParam::Lifetime(_) = **param.value() { | |
957 | param.to_tokens(tokens); | |
958 | trailing_or_empty = param.punct().is_some(); | |
959 | } | |
960 | } | |
961 | for param in self.0.params.pairs() { | |
962 | if let GenericParam::Lifetime(_) = **param.value() { | |
963 | continue; | |
964 | } | |
965 | if !trailing_or_empty { | |
966 | <Token![,]>::default().to_tokens(tokens); | |
967 | trailing_or_empty = true; | |
968 | } | |
969 | match *param.value() { | |
970 | GenericParam::Lifetime(_) => unreachable!(), | |
971 | GenericParam::Type(param) => { | |
972 | // Leave off the type parameter defaults | |
973 | tokens.append_all(param.attrs.outer()); | |
974 | param.ident.to_tokens(tokens); | |
975 | if !param.bounds.is_empty() { | |
976 | TokensOrDefault(¶m.colon_token).to_tokens(tokens); | |
977 | param.bounds.to_tokens(tokens); | |
978 | } | |
979 | } | |
980 | GenericParam::Const(param) => { | |
981 | // Leave off the const parameter defaults | |
982 | tokens.append_all(param.attrs.outer()); | |
983 | param.const_token.to_tokens(tokens); | |
984 | param.ident.to_tokens(tokens); | |
985 | param.colon_token.to_tokens(tokens); | |
986 | param.ty.to_tokens(tokens); | |
987 | } | |
988 | } | |
989 | param.punct().to_tokens(tokens); | |
990 | } | |
991 | ||
992 | TokensOrDefault(&self.0.gt_token).to_tokens(tokens); | |
993 | } | |
994 | } | |
995 | ||
996 | impl<'a> ToTokens for TypeGenerics<'a> { | |
997 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
998 | if self.0.params.is_empty() { | |
999 | return; | |
1000 | } | |
1001 | ||
1002 | TokensOrDefault(&self.0.lt_token).to_tokens(tokens); | |
1003 | ||
1004 | // Print lifetimes before types and consts, regardless of their | |
1005 | // order in self.params. | |
1006 | // | |
1007 | // TODO: ordering rules for const parameters vs type parameters have | |
1008 | // not been settled yet. https://github.com/rust-lang/rust/issues/44580 | |
1009 | let mut trailing_or_empty = true; | |
1010 | for param in self.0.params.pairs() { | |
1011 | if let GenericParam::Lifetime(def) = *param.value() { | |
1012 | // Leave off the lifetime bounds and attributes | |
1013 | def.lifetime.to_tokens(tokens); | |
1014 | param.punct().to_tokens(tokens); | |
1015 | trailing_or_empty = param.punct().is_some(); | |
1016 | } | |
1017 | } | |
1018 | for param in self.0.params.pairs() { | |
1019 | if let GenericParam::Lifetime(_) = **param.value() { | |
1020 | continue; | |
1021 | } | |
1022 | if !trailing_or_empty { | |
1023 | <Token![,]>::default().to_tokens(tokens); | |
1024 | trailing_or_empty = true; | |
1025 | } | |
1026 | match *param.value() { | |
1027 | GenericParam::Lifetime(_) => unreachable!(), | |
1028 | GenericParam::Type(param) => { | |
1029 | // Leave off the type parameter defaults | |
1030 | param.ident.to_tokens(tokens); | |
1031 | } | |
1032 | GenericParam::Const(param) => { | |
1033 | // Leave off the const parameter defaults | |
1034 | param.ident.to_tokens(tokens); | |
1035 | } | |
1036 | } | |
1037 | param.punct().to_tokens(tokens); | |
1038 | } | |
1039 | ||
1040 | TokensOrDefault(&self.0.gt_token).to_tokens(tokens); | |
1041 | } | |
1042 | } | |
1043 | ||
1044 | impl<'a> ToTokens for Turbofish<'a> { | |
1045 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
1046 | if !self.0.params.is_empty() { | |
1047 | <Token![::]>::default().to_tokens(tokens); | |
1048 | TypeGenerics(self.0).to_tokens(tokens); | |
1049 | } | |
1050 | } | |
1051 | } | |
1052 | ||
1053 | impl ToTokens for BoundLifetimes { | |
1054 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
1055 | self.for_token.to_tokens(tokens); | |
1056 | self.lt_token.to_tokens(tokens); | |
1057 | self.lifetimes.to_tokens(tokens); | |
1058 | self.gt_token.to_tokens(tokens); | |
1059 | } | |
1060 | } | |
1061 | ||
1062 | impl ToTokens for LifetimeDef { | |
1063 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
1064 | tokens.append_all(self.attrs.outer()); | |
1065 | self.lifetime.to_tokens(tokens); | |
1066 | if !self.bounds.is_empty() { | |
1067 | TokensOrDefault(&self.colon_token).to_tokens(tokens); | |
1068 | self.bounds.to_tokens(tokens); | |
1069 | } | |
1070 | } | |
1071 | } | |
1072 | ||
1073 | impl ToTokens for TypeParam { | |
1074 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
1075 | tokens.append_all(self.attrs.outer()); | |
1076 | self.ident.to_tokens(tokens); | |
1077 | if !self.bounds.is_empty() { | |
1078 | TokensOrDefault(&self.colon_token).to_tokens(tokens); | |
1079 | self.bounds.to_tokens(tokens); | |
1080 | } | |
1081 | if self.default.is_some() { | |
1082 | TokensOrDefault(&self.eq_token).to_tokens(tokens); | |
1083 | self.default.to_tokens(tokens); | |
1084 | } | |
1085 | } | |
1086 | } | |
1087 | ||
1088 | impl ToTokens for TraitBound { | |
1089 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
1090 | let to_tokens = |tokens: &mut TokenStream| { | |
1091 | self.modifier.to_tokens(tokens); | |
1092 | self.lifetimes.to_tokens(tokens); | |
1093 | self.path.to_tokens(tokens); | |
1094 | }; | |
1095 | match &self.paren_token { | |
1096 | Some(paren) => paren.surround(tokens, to_tokens), | |
1097 | None => to_tokens(tokens), | |
1098 | } | |
1099 | } | |
1100 | } | |
1101 | ||
1102 | impl ToTokens for TraitBoundModifier { | |
1103 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
1104 | match self { | |
1105 | TraitBoundModifier::None => {} | |
1106 | TraitBoundModifier::Maybe(t) => t.to_tokens(tokens), | |
1107 | } | |
1108 | } | |
1109 | } | |
1110 | ||
1111 | impl ToTokens for ConstParam { | |
1112 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
1113 | tokens.append_all(self.attrs.outer()); | |
1114 | self.const_token.to_tokens(tokens); | |
1115 | self.ident.to_tokens(tokens); | |
1116 | self.colon_token.to_tokens(tokens); | |
1117 | self.ty.to_tokens(tokens); | |
1118 | if self.default.is_some() { | |
1119 | TokensOrDefault(&self.eq_token).to_tokens(tokens); | |
1120 | self.default.to_tokens(tokens); | |
1121 | } | |
1122 | } | |
1123 | } | |
1124 | ||
1125 | impl ToTokens for WhereClause { | |
1126 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
1127 | if !self.predicates.is_empty() { | |
1128 | self.where_token.to_tokens(tokens); | |
1129 | self.predicates.to_tokens(tokens); | |
1130 | } | |
1131 | } | |
1132 | } | |
1133 | ||
1134 | impl ToTokens for PredicateType { | |
1135 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
1136 | self.lifetimes.to_tokens(tokens); | |
1137 | self.bounded_ty.to_tokens(tokens); | |
1138 | self.colon_token.to_tokens(tokens); | |
1139 | self.bounds.to_tokens(tokens); | |
1140 | } | |
1141 | } | |
1142 | ||
1143 | impl ToTokens for PredicateLifetime { | |
1144 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
1145 | self.lifetime.to_tokens(tokens); | |
1146 | self.colon_token.to_tokens(tokens); | |
1147 | self.bounds.to_tokens(tokens); | |
1148 | } | |
1149 | } | |
1150 | ||
1151 | impl ToTokens for PredicateEq { | |
1152 | fn to_tokens(&self, tokens: &mut TokenStream) { | |
1153 | self.lhs_ty.to_tokens(tokens); | |
1154 | self.eq_token.to_tokens(tokens); | |
1155 | self.rhs_ty.to_tokens(tokens); | |
1156 | } | |
1157 | } | |
1158 | } |