syn/
path.rs

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 {
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) => 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}