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