1use super::*;
2use crate::punctuated::Punctuated;
3
4ast_struct! {
5 /// A path at which a named item is exported (e.g. `std::collections::HashMap`).
6 ///
7 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
8 /// feature.*
9 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
10 pub struct Path {
11 pub leading_colon: Option<Token![::]>,
12 pub segments: Punctuated<PathSegment, Token![::]>,
13 }
14}
15
16impl<T> From<T> for Path
17where
18 T: Into<PathSegment>,
19{
20 fn from(segment: T) -> Self {
21 let mut path: Path = Path {
22 leading_colon: None,
23 segments: Punctuated::new(),
24 };
25 path.segments.push_value(segment.into());
26 path
27 }
28}
29
30ast_struct! {
31 /// A segment of a path together with any path arguments on that segment.
32 ///
33 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
34 /// feature.*
35 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
36 pub struct PathSegment {
37 pub ident: Ident,
38 pub arguments: PathArguments,
39 }
40}
41
42impl<T> From<T> for PathSegment
43where
44 T: Into<Ident>,
45{
46 fn from(ident: T) -> Self {
47 PathSegment {
48 ident: ident.into(),
49 arguments: PathArguments::None,
50 }
51 }
52}
53
54ast_enum! {
55 /// Angle bracketed or parenthesized arguments of a path segment.
56 ///
57 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
58 /// feature.*
59 ///
60 /// ## Angle bracketed
61 ///
62 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
63 ///
64 /// ## Parenthesized
65 ///
66 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
67 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
68 pub enum PathArguments {
69 None,
70 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
71 AngleBracketed(AngleBracketedGenericArguments),
72 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
73 Parenthesized(ParenthesizedGenericArguments),
74 }
75}
76
77impl Default for PathArguments {
78 fn default() -> Self {
79 PathArguments::None
80 }
81}
82
83impl PathArguments {
84 pub fn is_empty(&self) -> bool {
85 match self {
86 PathArguments::None => true,
87 PathArguments::AngleBracketed(bracketed: &AngleBracketedGenericArguments) => bracketed.args.is_empty(),
88 PathArguments::Parenthesized(_) => false,
89 }
90 }
91
92 pub fn is_none(&self) -> bool {
93 match self {
94 PathArguments::None => true,
95 PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false,
96 }
97 }
98}
99
100ast_enum! {
101 /// An individual generic argument, like `'a`, `T`, or `Item = T`.
102 ///
103 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
104 /// feature.*
105 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
106 pub enum GenericArgument {
107 /// A lifetime argument.
108 Lifetime(Lifetime),
109 /// A type argument.
110 Type(Type),
111 /// A const expression. Must be inside of a block.
112 ///
113 /// NOTE: Identity expressions are represented as Type arguments, as
114 /// they are indistinguishable syntactically.
115 Const(Expr),
116 /// A binding (equality constraint) on an associated type: the `Item =
117 /// u8` in `Iterator<Item = u8>`.
118 Binding(Binding),
119 /// An associated type bound: `Iterator<Item: Display>`.
120 Constraint(Constraint),
121 }
122}
123
124ast_struct! {
125 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
126 /// V>`.
127 ///
128 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
129 /// feature.*
130 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
131 pub struct AngleBracketedGenericArguments {
132 pub colon2_token: Option<Token![::]>,
133 pub lt_token: Token![<],
134 pub args: Punctuated<GenericArgument, Token![,]>,
135 pub gt_token: Token![>],
136 }
137}
138
139ast_struct! {
140 /// A binding (equality constraint) on an associated type: `Item = u8`.
141 ///
142 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
143 /// feature.*
144 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
145 pub struct Binding {
146 pub ident: Ident,
147 pub eq_token: Token![=],
148 pub ty: Type,
149 }
150}
151
152ast_struct! {
153 /// An associated type bound: `Iterator<Item: Display>`.
154 ///
155 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
156 /// feature.*
157 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
158 pub struct Constraint {
159 pub ident: Ident,
160 pub colon_token: Token![:],
161 pub bounds: Punctuated<TypeParamBound, Token![+]>,
162 }
163}
164
165ast_struct! {
166 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
167 /// C`.
168 ///
169 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
170 /// feature.*
171 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
172 pub struct ParenthesizedGenericArguments {
173 pub paren_token: token::Paren,
174 /// `(A, B)`
175 pub inputs: Punctuated<Type, Token![,]>,
176 /// `C`
177 pub output: ReturnType,
178 }
179}
180
181ast_struct! {
182 /// The explicit Self type in a qualified path: the `T` in `<T as
183 /// Display>::fmt`.
184 ///
185 /// The actual path, including the trait and the associated item, is stored
186 /// separately. The `position` field represents the index of the associated
187 /// item qualified with this Self type.
188 ///
189 /// ```text
190 /// <Vec<T> as a::b::Trait>::AssociatedItem
191 /// ^~~~~~ ~~~~~~~~~~~~~~^
192 /// ty position = 3
193 ///
194 /// <Vec<T>>::AssociatedItem
195 /// ^~~~~~ ^
196 /// ty position = 0
197 /// ```
198 ///
199 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
200 /// feature.*
201 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
202 pub struct QSelf {
203 pub lt_token: Token![<],
204 pub ty: Box<Type>,
205 pub position: usize,
206 pub as_token: Option<Token![as]>,
207 pub gt_token: Token![>],
208 }
209}
210
211#[cfg(feature = "parsing")]
212pub mod parsing {
213 use super::*;
214
215 use crate::ext::IdentExt;
216 use crate::parse::{Parse, ParseStream, Result};
217
218 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
219 impl Parse for Path {
220 fn parse(input: ParseStream) -> Result<Self> {
221 Self::parse_helper(input, false)
222 }
223 }
224
225 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
226 impl Parse for GenericArgument {
227 fn parse(input: ParseStream) -> Result<Self> {
228 if input.peek(Lifetime) && !input.peek2(Token![+]) {
229 return Ok(GenericArgument::Lifetime(input.parse()?));
230 }
231
232 if input.peek(Ident) && input.peek2(Token![=]) {
233 let ident: Ident = input.parse()?;
234 let eq_token: Token![=] = input.parse()?;
235
236 let ty = if input.peek(Lit) {
237 let begin = input.fork();
238 input.parse::<Lit>()?;
239 Type::Verbatim(verbatim::between(begin, input))
240 } else if input.peek(token::Brace) {
241 let begin = input.fork();
242
243 #[cfg(feature = "full")]
244 {
245 input.parse::<ExprBlock>()?;
246 }
247
248 #[cfg(not(feature = "full"))]
249 {
250 let content;
251 braced!(content in input);
252 content.parse::<Expr>()?;
253 }
254
255 Type::Verbatim(verbatim::between(begin, input))
256 } else {
257 input.parse()?
258 };
259
260 return Ok(GenericArgument::Binding(Binding {
261 ident,
262 eq_token,
263 ty,
264 }));
265 }
266
267 #[cfg(feature = "full")]
268 {
269 if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) {
270 return Ok(GenericArgument::Constraint(input.parse()?));
271 }
272 }
273
274 if input.peek(Lit) || input.peek(token::Brace) {
275 return const_argument(input).map(GenericArgument::Const);
276 }
277
278 #[cfg(feature = "full")]
279 let begin = input.fork();
280
281 let argument: Type = input.parse()?;
282
283 #[cfg(feature = "full")]
284 {
285 if match &argument {
286 Type::Path(argument)
287 if argument.qself.is_none()
288 && argument.path.leading_colon.is_none()
289 && argument.path.segments.len() == 1 =>
290 {
291 match argument.path.segments[0].arguments {
292 PathArguments::AngleBracketed(_) => true,
293 _ => false,
294 }
295 }
296 _ => false,
297 } && if input.peek(Token![=]) {
298 input.parse::<Token![=]>()?;
299 input.parse::<Type>()?;
300 true
301 } else if input.peek(Token![:]) {
302 input.parse::<Token![:]>()?;
303 input.call(constraint_bounds)?;
304 true
305 } else {
306 false
307 } {
308 let verbatim = verbatim::between(begin, input);
309 return Ok(GenericArgument::Type(Type::Verbatim(verbatim)));
310 }
311 }
312
313 Ok(GenericArgument::Type(argument))
314 }
315 }
316
317 pub fn const_argument(input: ParseStream) -> Result<Expr> {
318 let lookahead = input.lookahead1();
319
320 if input.peek(Lit) {
321 let lit = input.parse()?;
322 return Ok(Expr::Lit(lit));
323 }
324
325 #[cfg(feature = "full")]
326 {
327 if input.peek(Ident) {
328 let ident: Ident = input.parse()?;
329 return Ok(Expr::Path(ExprPath {
330 attrs: Vec::new(),
331 qself: None,
332 path: Path::from(ident),
333 }));
334 }
335 }
336
337 if input.peek(token::Brace) {
338 #[cfg(feature = "full")]
339 {
340 let block: ExprBlock = input.parse()?;
341 return Ok(Expr::Block(block));
342 }
343
344 #[cfg(not(feature = "full"))]
345 {
346 let begin = input.fork();
347 let content;
348 braced!(content in input);
349 content.parse::<Expr>()?;
350 let verbatim = verbatim::between(begin, input);
351 return Ok(Expr::Verbatim(verbatim));
352 }
353 }
354
355 Err(lookahead.error())
356 }
357
358 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
359 impl Parse for AngleBracketedGenericArguments {
360 fn parse(input: ParseStream) -> Result<Self> {
361 Ok(AngleBracketedGenericArguments {
362 colon2_token: input.parse()?,
363 lt_token: input.parse()?,
364 args: {
365 let mut args = Punctuated::new();
366 loop {
367 if input.peek(Token![>]) {
368 break;
369 }
370 let value = input.parse()?;
371 args.push_value(value);
372 if input.peek(Token![>]) {
373 break;
374 }
375 let punct = input.parse()?;
376 args.push_punct(punct);
377 }
378 args
379 },
380 gt_token: input.parse()?,
381 })
382 }
383 }
384
385 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
386 impl Parse for ParenthesizedGenericArguments {
387 fn parse(input: ParseStream) -> Result<Self> {
388 let content;
389 Ok(ParenthesizedGenericArguments {
390 paren_token: parenthesized!(content in input),
391 inputs: content.parse_terminated(Type::parse)?,
392 output: input.call(ReturnType::without_plus)?,
393 })
394 }
395 }
396
397 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
398 impl Parse for PathSegment {
399 fn parse(input: ParseStream) -> Result<Self> {
400 Self::parse_helper(input, false)
401 }
402 }
403
404 impl PathSegment {
405 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
406 if input.peek(Token![super]) || input.peek(Token![self]) || input.peek(Token![crate]) {
407 let ident = input.call(Ident::parse_any)?;
408 return Ok(PathSegment::from(ident));
409 }
410
411 let ident = if input.peek(Token![Self]) {
412 input.call(Ident::parse_any)?
413 } else {
414 input.parse()?
415 };
416
417 if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
418 || input.peek(Token![::]) && input.peek3(Token![<])
419 {
420 Ok(PathSegment {
421 ident,
422 arguments: PathArguments::AngleBracketed(input.parse()?),
423 })
424 } else {
425 Ok(PathSegment::from(ident))
426 }
427 }
428 }
429
430 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
431 impl Parse for Binding {
432 fn parse(input: ParseStream) -> Result<Self> {
433 Ok(Binding {
434 ident: input.parse()?,
435 eq_token: input.parse()?,
436 ty: input.parse()?,
437 })
438 }
439 }
440
441 #[cfg(feature = "full")]
442 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
443 impl Parse for Constraint {
444 fn parse(input: ParseStream) -> Result<Self> {
445 Ok(Constraint {
446 ident: input.parse()?,
447 colon_token: input.parse()?,
448 bounds: constraint_bounds(input)?,
449 })
450 }
451 }
452
453 #[cfg(feature = "full")]
454 fn constraint_bounds(input: ParseStream) -> Result<Punctuated<TypeParamBound, Token![+]>> {
455 let mut bounds = Punctuated::new();
456 loop {
457 if input.peek(Token![,]) || input.peek(Token![>]) {
458 break;
459 }
460 let value = input.parse()?;
461 bounds.push_value(value);
462 if !input.peek(Token![+]) {
463 break;
464 }
465 let punct = input.parse()?;
466 bounds.push_punct(punct);
467 }
468 Ok(bounds)
469 }
470
471 impl Path {
472 /// Parse a `Path` containing no path arguments on any of its segments.
473 ///
474 /// *This function is available only if Syn is built with the `"parsing"`
475 /// feature.*
476 ///
477 /// # Example
478 ///
479 /// ```
480 /// use syn::{Path, Result, Token};
481 /// use syn::parse::{Parse, ParseStream};
482 ///
483 /// // A simplified single `use` statement like:
484 /// //
485 /// // use std::collections::HashMap;
486 /// //
487 /// // Note that generic parameters are not allowed in a `use` statement
488 /// // so the following must not be accepted.
489 /// //
490 /// // use a::<b>::c;
491 /// struct SingleUse {
492 /// use_token: Token![use],
493 /// path: Path,
494 /// }
495 ///
496 /// impl Parse for SingleUse {
497 /// fn parse(input: ParseStream) -> Result<Self> {
498 /// Ok(SingleUse {
499 /// use_token: input.parse()?,
500 /// path: input.call(Path::parse_mod_style)?,
501 /// })
502 /// }
503 /// }
504 /// ```
505 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
506 pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
507 Ok(Path {
508 leading_colon: input.parse()?,
509 segments: {
510 let mut segments = Punctuated::new();
511 loop {
512 if !input.peek(Ident)
513 && !input.peek(Token![super])
514 && !input.peek(Token![self])
515 && !input.peek(Token![Self])
516 && !input.peek(Token![crate])
517 {
518 break;
519 }
520 let ident = Ident::parse_any(input)?;
521 segments.push_value(PathSegment::from(ident));
522 if !input.peek(Token![::]) {
523 break;
524 }
525 let punct = input.parse()?;
526 segments.push_punct(punct);
527 }
528 if segments.is_empty() {
529 return Err(input.error("expected path"));
530 } else if segments.trailing_punct() {
531 return Err(input.error("expected path segment"));
532 }
533 segments
534 },
535 })
536 }
537
538 /// Determines whether this is a path of length 1 equal to the given
539 /// ident.
540 ///
541 /// For them to compare equal, it must be the case that:
542 ///
543 /// - the path has no leading colon,
544 /// - the number of path segments is 1,
545 /// - the first path segment has no angle bracketed or parenthesized
546 /// path arguments, and
547 /// - the ident of the first path segment is equal to the given one.
548 ///
549 /// *This function is available only if Syn is built with the `"parsing"`
550 /// feature.*
551 ///
552 /// # Example
553 ///
554 /// ```
555 /// use syn::{Attribute, Error, Meta, NestedMeta, Result};
556 /// # use std::iter::FromIterator;
557 ///
558 /// fn get_serde_meta_items(attr: &Attribute) -> Result<Vec<NestedMeta>> {
559 /// if attr.path.is_ident("serde") {
560 /// match attr.parse_meta()? {
561 /// Meta::List(meta) => Ok(Vec::from_iter(meta.nested)),
562 /// bad => Err(Error::new_spanned(bad, "unrecognized attribute")),
563 /// }
564 /// } else {
565 /// Ok(Vec::new())
566 /// }
567 /// }
568 /// ```
569 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
570 pub fn is_ident<I: ?Sized>(&self, ident: &I) -> bool
571 where
572 Ident: PartialEq<I>,
573 {
574 match self.get_ident() {
575 Some(id) => id == ident,
576 None => false,
577 }
578 }
579
580 /// If this path consists of a single ident, returns the ident.
581 ///
582 /// A path is considered an ident if:
583 ///
584 /// - the path has no leading colon,
585 /// - the number of path segments is 1, and
586 /// - the first path segment has no angle bracketed or parenthesized
587 /// path arguments.
588 ///
589 /// *This function is available only if Syn is built with the `"parsing"`
590 /// feature.*
591 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
592 pub fn get_ident(&self) -> Option<&Ident> {
593 if self.leading_colon.is_none()
594 && self.segments.len() == 1
595 && self.segments[0].arguments.is_none()
596 {
597 Some(&self.segments[0].ident)
598 } else {
599 None
600 }
601 }
602
603 pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
604 let mut path = Path {
605 leading_colon: input.parse()?,
606 segments: {
607 let mut segments = Punctuated::new();
608 let value = PathSegment::parse_helper(input, expr_style)?;
609 segments.push_value(value);
610 segments
611 },
612 };
613 Path::parse_rest(input, &mut path, expr_style)?;
614 Ok(path)
615 }
616
617 pub(crate) fn parse_rest(
618 input: ParseStream,
619 path: &mut Self,
620 expr_style: bool,
621 ) -> Result<()> {
622 while input.peek(Token![::]) && !input.peek3(token::Paren) {
623 let punct: Token![::] = input.parse()?;
624 path.segments.push_punct(punct);
625 let value = PathSegment::parse_helper(input, expr_style)?;
626 path.segments.push_value(value);
627 }
628 Ok(())
629 }
630 }
631
632 pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
633 if input.peek(Token![<]) {
634 let lt_token: Token![<] = input.parse()?;
635 let this: Type = input.parse()?;
636 let path = if input.peek(Token![as]) {
637 let as_token: Token![as] = input.parse()?;
638 let path: Path = input.parse()?;
639 Some((as_token, path))
640 } else {
641 None
642 };
643 let gt_token: Token![>] = input.parse()?;
644 let colon2_token: Token![::] = input.parse()?;
645 let mut rest = Punctuated::new();
646 loop {
647 let path = PathSegment::parse_helper(input, expr_style)?;
648 rest.push_value(path);
649 if !input.peek(Token![::]) {
650 break;
651 }
652 let punct: Token![::] = input.parse()?;
653 rest.push_punct(punct);
654 }
655 let (position, as_token, path) = match path {
656 Some((as_token, mut path)) => {
657 let pos = path.segments.len();
658 path.segments.push_punct(colon2_token);
659 path.segments.extend(rest.into_pairs());
660 (pos, Some(as_token), path)
661 }
662 None => {
663 let path = Path {
664 leading_colon: Some(colon2_token),
665 segments: rest,
666 };
667 (0, None, path)
668 }
669 };
670 let qself = QSelf {
671 lt_token,
672 ty: Box::new(this),
673 position,
674 as_token,
675 gt_token,
676 };
677 Ok((Some(qself), path))
678 } else {
679 let path = Path::parse_helper(input, expr_style)?;
680 Ok((None, path))
681 }
682 }
683}
684
685#[cfg(feature = "printing")]
686pub(crate) mod printing {
687 use super::*;
688 use crate::print::TokensOrDefault;
689 use proc_macro2::TokenStream;
690 use quote::ToTokens;
691 use std::cmp;
692
693 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
694 impl ToTokens for Path {
695 fn to_tokens(&self, tokens: &mut TokenStream) {
696 self.leading_colon.to_tokens(tokens);
697 self.segments.to_tokens(tokens);
698 }
699 }
700
701 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
702 impl ToTokens for PathSegment {
703 fn to_tokens(&self, tokens: &mut TokenStream) {
704 self.ident.to_tokens(tokens);
705 self.arguments.to_tokens(tokens);
706 }
707 }
708
709 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
710 impl ToTokens for PathArguments {
711 fn to_tokens(&self, tokens: &mut TokenStream) {
712 match self {
713 PathArguments::None => {}
714 PathArguments::AngleBracketed(arguments) => {
715 arguments.to_tokens(tokens);
716 }
717 PathArguments::Parenthesized(arguments) => {
718 arguments.to_tokens(tokens);
719 }
720 }
721 }
722 }
723
724 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
725 impl ToTokens for GenericArgument {
726 #[allow(clippy::match_same_arms)]
727 fn to_tokens(&self, tokens: &mut TokenStream) {
728 match self {
729 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
730 GenericArgument::Type(ty) => ty.to_tokens(tokens),
731 GenericArgument::Const(e) => match *e {
732 Expr::Lit(_) => e.to_tokens(tokens),
733
734 // NOTE: We should probably support parsing blocks with only
735 // expressions in them without the full feature for const
736 // generics.
737 #[cfg(feature = "full")]
738 Expr::Block(_) => e.to_tokens(tokens),
739
740 // ERROR CORRECTION: Add braces to make sure that the
741 // generated code is valid.
742 _ => token::Brace::default().surround(tokens, |tokens| {
743 e.to_tokens(tokens);
744 }),
745 },
746 GenericArgument::Binding(tb) => tb.to_tokens(tokens),
747 GenericArgument::Constraint(tc) => tc.to_tokens(tokens),
748 }
749 }
750 }
751
752 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
753 impl ToTokens for AngleBracketedGenericArguments {
754 fn to_tokens(&self, tokens: &mut TokenStream) {
755 self.colon2_token.to_tokens(tokens);
756 self.lt_token.to_tokens(tokens);
757
758 // Print lifetimes before types/consts/bindings, regardless of their
759 // order in self.args.
760 let mut trailing_or_empty = true;
761 for param in self.args.pairs() {
762 match **param.value() {
763 GenericArgument::Lifetime(_) => {
764 param.to_tokens(tokens);
765 trailing_or_empty = param.punct().is_some();
766 }
767 GenericArgument::Type(_)
768 | GenericArgument::Const(_)
769 | GenericArgument::Binding(_)
770 | GenericArgument::Constraint(_) => {}
771 }
772 }
773 for param in self.args.pairs() {
774 match **param.value() {
775 GenericArgument::Type(_)
776 | GenericArgument::Const(_)
777 | GenericArgument::Binding(_)
778 | GenericArgument::Constraint(_) => {
779 if !trailing_or_empty {
780 <Token![,]>::default().to_tokens(tokens);
781 }
782 param.to_tokens(tokens);
783 trailing_or_empty = param.punct().is_some();
784 }
785 GenericArgument::Lifetime(_) => {}
786 }
787 }
788
789 self.gt_token.to_tokens(tokens);
790 }
791 }
792
793 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
794 impl ToTokens for Binding {
795 fn to_tokens(&self, tokens: &mut TokenStream) {
796 self.ident.to_tokens(tokens);
797 self.eq_token.to_tokens(tokens);
798 self.ty.to_tokens(tokens);
799 }
800 }
801
802 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
803 impl ToTokens for Constraint {
804 fn to_tokens(&self, tokens: &mut TokenStream) {
805 self.ident.to_tokens(tokens);
806 self.colon_token.to_tokens(tokens);
807 self.bounds.to_tokens(tokens);
808 }
809 }
810
811 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
812 impl ToTokens for ParenthesizedGenericArguments {
813 fn to_tokens(&self, tokens: &mut TokenStream) {
814 self.paren_token.surround(tokens, |tokens| {
815 self.inputs.to_tokens(tokens);
816 });
817 self.output.to_tokens(tokens);
818 }
819 }
820
821 pub(crate) fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
822 let qself = match qself {
823 Some(qself) => qself,
824 None => {
825 path.to_tokens(tokens);
826 return;
827 }
828 };
829 qself.lt_token.to_tokens(tokens);
830 qself.ty.to_tokens(tokens);
831
832 let pos = cmp::min(qself.position, path.segments.len());
833 let mut segments = path.segments.pairs();
834 if pos > 0 {
835 TokensOrDefault(&qself.as_token).to_tokens(tokens);
836 path.leading_colon.to_tokens(tokens);
837 for (i, segment) in segments.by_ref().take(pos).enumerate() {
838 if i + 1 == pos {
839 segment.value().to_tokens(tokens);
840 qself.gt_token.to_tokens(tokens);
841 segment.punct().to_tokens(tokens);
842 } else {
843 segment.to_tokens(tokens);
844 }
845 }
846 } else {
847 qself.gt_token.to_tokens(tokens);
848 path.leading_colon.to_tokens(tokens);
849 }
850 for segment in segments {
851 segment.to_tokens(tokens);
852 }
853 }
854}
855