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