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