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::{NamedArg, ReturnType, Type};
10use alloc::boxed::Box;
11
12#[doc =
r" A path at which a named item is exported (e.g. `alloc::collections::HashMap`)."]
#[doc(cfg(any(feature = "full", feature = "derive")))]
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."]
#[doc(cfg(any(feature = "full", feature = "derive")))]
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`."]
#[doc(cfg(any(feature = "full", feature = "derive")))]
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`."]
#[doc(cfg(any(feature = "full", feature = "derive")))]
#[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>`."]
#[doc(cfg(any(feature = "full", feature = "derive")))]
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>`."]
#[doc(cfg(any(feature = "full", feature = "derive")))]
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>`."]
#[doc(cfg(any(feature = "full", feature = "derive")))]
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>`."]
#[doc(cfg(any(feature = "full", feature = "derive")))]
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`."]
#[doc(cfg(any(feature = "full", feature = "derive")))]
pub struct ParenthesizedGenericArguments {
pub paren_token: token::Paren,
#[doc = r" `(A, B)`"]
pub inputs: Punctuated<NamedArg, 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<NamedArg, 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" ```"]
#[doc(cfg(any(feature = "full", feature = "derive")))]
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 use crate::generics::TypeParamBound;
292 use crate::ident::Ident;
293 use crate::lifetime::Lifetime;
294 use crate::lit::Lit;
295 use crate::parse::{Parse, ParseStream};
296 use crate::path::{
297 AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,
298 ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
299 };
300 use crate::punctuated::Punctuated;
301 use crate::token;
302 use crate::ty::{NamedArg, ReturnType, Type};
303 #[cfg(not(feature = "full"))]
304 use crate::verbatim;
305 use alloc::boxed::Box;
306 use alloc::vec::Vec;
307
308 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
309 impl Parse for Path {
310 fn parse(input: ParseStream) -> Result<Self> {
311 Self::parse_helper(input, false)
312 }
313 }
314
315 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
316 impl Parse for GenericArgument {
317 fn parse(input: ParseStream) -> Result<Self> {
318 if input.peek(Lifetime) && !input.peek2(crate::token::PlusToken![+]) {
319 return Ok(GenericArgument::Lifetime(Lifetime::parse_any(input)?));
320 }
321
322 if input.peek(Lit) || input.peek(token::Brace) {
323 return const_argument(input).map(GenericArgument::Const);
324 }
325
326 let mut argument: Type = input.parse()?;
327
328 match argument {
329 Type::Path(mut ty)
330 if ty.qself.is_none()
331 && ty.path.leading_colon.is_none()
332 && ty.path.segments.len() == 1
333 && match &ty.path.segments[0].arguments {
334 PathArguments::None | PathArguments::AngleBracketed(_) => true,
335 PathArguments::Parenthesized(_) => false,
336 } =>
337 {
338 if let Some(eq_token) = input.parse::<Option<crate::token::EqToken![=]>>()? {
339 let segment = ty.path.segments.pop().unwrap();
340 let ident = segment.ident;
341 let generics = match segment.arguments {
342 PathArguments::None => None,
343 PathArguments::AngleBracketed(arguments) => Some(arguments),
344 PathArguments::Parenthesized(_) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
345 };
346 return if input.peek(Lit) || input.peek(token::Brace) {
347 Ok(GenericArgument::AssocConst(AssocConst {
348 ident,
349 generics,
350 eq_token,
351 value: const_argument(input)?,
352 }))
353 } else {
354 Ok(GenericArgument::AssocType(AssocType {
355 ident,
356 generics,
357 eq_token,
358 ty: input.parse()?,
359 }))
360 };
361 }
362
363 if let Some(colon_token) = input.parse::<Option<crate::token::ColonToken![:]>>()? {
364 let segment = ty.path.segments.pop().unwrap();
365 return Ok(GenericArgument::Constraint(Constraint {
366 ident: segment.ident,
367 generics: match segment.arguments {
368 PathArguments::None => None,
369 PathArguments::AngleBracketed(arguments) => Some(arguments),
370 PathArguments::Parenthesized(_) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
371 },
372 colon_token,
373 bounds: {
374 let mut bounds = Punctuated::new();
375 loop {
376 if input.peek(crate::token::CommaToken![,]) || input.peek(crate::token::GtToken![>]) {
377 break;
378 }
379 bounds.push_value({
380 let allow_precise_capture = false;
381 let allow_const = true;
382 TypeParamBound::parse_single(
383 input,
384 allow_precise_capture,
385 allow_const,
386 )?
387 });
388 if !input.peek(crate::token::PlusToken![+]) {
389 break;
390 }
391 let punct: crate::token::PlusToken![+] = input.parse()?;
392 bounds.push_punct(punct);
393 }
394 bounds
395 },
396 }));
397 }
398
399 argument = Type::Path(ty);
400 }
401 _ => {}
402 }
403
404 Ok(GenericArgument::Type(argument))
405 }
406 }
407
408 pub(crate) fn const_argument(input: ParseStream) -> Result<Expr> {
409 let lookahead = input.lookahead1();
410
411 if input.peek(Lit) {
412 let lit = input.parse()?;
413 return Ok(Expr::Lit(lit));
414 }
415
416 if input.peek(Ident) {
417 let ident: Ident = input.parse()?;
418 return Ok(Expr::Path(ExprPath {
419 attrs: Vec::new(),
420 qself: None,
421 path: Path::from(ident),
422 }));
423 }
424
425 if input.peek(token::Brace) {
426 #[cfg(feature = "full")]
427 {
428 let block: ExprBlock = input.parse()?;
429 return Ok(Expr::Block(block));
430 }
431
432 #[cfg(not(feature = "full"))]
433 {
434 let begin = input.cursor();
435 let content;
436 braced!(content in input);
437 content.parse::<Expr>()?;
438 let verbatim = verbatim::between(begin, input.cursor());
439 return Ok(Expr::Verbatim(verbatim));
440 }
441 }
442
443 Err(lookahead.error())
444 }
445
446 impl AngleBracketedGenericArguments {
447 #[cfg(feature = "full")]
452 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))]
453 pub fn parse_turbofish(input: ParseStream) -> Result<Self> {
454 let colon2_token: crate::token::PathSepToken![::] = input.parse()?;
455 Self::do_parse(Some(colon2_token), input)
456 }
457
458 pub(crate) fn do_parse(
459 colon2_token: Option<crate::token::PathSepToken![::]>,
460 input: ParseStream,
461 ) -> Result<Self> {
462 Ok(AngleBracketedGenericArguments {
463 colon2_token,
464 lt_token: input.parse()?,
465 args: {
466 let mut args = Punctuated::new();
467 loop {
468 if input.peek(crate::token::GtToken![>]) {
469 break;
470 }
471 let value: GenericArgument = input.parse()?;
472 args.push_value(value);
473 if input.peek(crate::token::GtToken![>]) {
474 break;
475 }
476 let punct: crate::token::CommaToken![,] = input.parse()?;
477 args.push_punct(punct);
478 }
479 args
480 },
481 gt_token: input.parse()?,
482 })
483 }
484 }
485
486 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
487 impl Parse for AngleBracketedGenericArguments {
488 fn parse(input: ParseStream) -> Result<Self> {
489 let colon2_token: Option<crate::token::PathSepToken![::]> = input.parse()?;
490 Self::do_parse(colon2_token, input)
491 }
492 }
493
494 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
495 impl Parse for ParenthesizedGenericArguments {
496 fn parse(input: ParseStream) -> Result<Self> {
497 fn type_as_named_arg(input: ParseStream) -> Result<NamedArg> {
498 Ok(NamedArg {
499 attrs: Vec::new(),
500 name: None,
501 ty: input.parse()?,
502 })
503 }
504 let content;
505 Ok(ParenthesizedGenericArguments {
506 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),
507 inputs: content.parse_terminated(type_as_named_arg, crate::token::CommaToken![,])?,
508 output: input.call(ReturnType::without_plus)?,
509 })
510 }
511 }
512
513 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
514 impl Parse for PathSegment {
515 fn parse(input: ParseStream) -> Result<Self> {
516 Self::parse_helper(input, false)
517 }
518 }
519
520 impl PathSegment {
521 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
522 if input.peek(crate::token::SuperToken![super])
523 || input.peek(crate::token::SelfValueToken![self])
524 || input.peek(crate::token::CrateToken![crate])
525 || truecfg!(feature = "full") && input.peek(crate::token::TryToken![try])
526 {
527 let ident = input.call(Ident::parse_any)?;
528 return Ok(PathSegment::from(ident));
529 }
530
531 let ident = if input.peek(crate::token::SelfTypeToken![Self]) {
532 input.call(Ident::parse_any)?
533 } else {
534 input.parse()?
535 };
536
537 if !expr_style
538 && input.peek(crate::token::LtToken![<])
539 && !input.peek(crate::token::LeToken![<=])
540 && !input.peek(crate::token::ShlEqToken![<<=])
541 || input.peek(crate::token::PathSepToken![::]) && input.peek3(crate::token::LtToken![<])
542 {
543 Ok(PathSegment {
544 ident,
545 arguments: PathArguments::AngleBracketed(input.parse()?),
546 })
547 } else {
548 Ok(PathSegment::from(ident))
549 }
550 }
551 }
552
553 impl Path {
554 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
585 pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
586 Ok(Path {
587 leading_colon: input.parse()?,
588 segments: {
589 let mut segments = Punctuated::new();
590 loop {
591 if !input.peek(Ident)
592 && !input.peek(crate::token::SuperToken![super])
593 && !input.peek(crate::token::SelfValueToken![self])
594 && !input.peek(crate::token::SelfTypeToken![Self])
595 && !input.peek(crate::token::CrateToken![crate])
596 {
597 break;
598 }
599 let ident = Ident::parse_any(input)?;
600 segments.push_value(PathSegment::from(ident));
601 if !input.peek(crate::token::PathSepToken![::]) {
602 break;
603 }
604 let punct = input.parse()?;
605 segments.push_punct(punct);
606 }
607 if segments.is_empty() {
608 return Err(input.parse::<Ident>().unwrap_err());
609 } else if segments.trailing_punct() {
610 return Err(input.error("expected path segment after `::`"));
611 }
612 segments
613 },
614 })
615 }
616
617 pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
618 let mut path = Path {
619 leading_colon: input.parse()?,
620 segments: {
621 let mut segments = Punctuated::new();
622 let value = PathSegment::parse_helper(input, expr_style)?;
623 segments.push_value(value);
624 segments
625 },
626 };
627 Path::parse_rest(input, &mut path, expr_style)?;
628 Ok(path)
629 }
630
631 pub(crate) fn parse_rest(
632 input: ParseStream,
633 path: &mut Self,
634 expr_style: bool,
635 ) -> Result<()> {
636 while input.peek(crate::token::PathSepToken![::]) && !input.peek3(token::Paren) {
637 let punct: crate::token::PathSepToken![::] = input.parse()?;
638 path.segments.push_punct(punct);
639 let value = PathSegment::parse_helper(input, expr_style)?;
640 path.segments.push_value(value);
641 }
642 Ok(())
643 }
644
645 pub(crate) fn is_mod_style(&self) -> bool {
646 self.segments
647 .iter()
648 .all(|segment| segment.arguments.is_none())
649 }
650 }
651
652 pub(crate) fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
653 if input.peek(crate::token::LtToken![<]) {
654 let lt_token: crate::token::LtToken![<] = input.parse()?;
655 let this: Type = input.parse()?;
656 let path = if input.peek(crate::token::AsToken![as]) {
657 let as_token: crate::token::AsToken![as] = input.parse()?;
658 let path: Path = input.parse()?;
659 Some((as_token, path))
660 } else {
661 None
662 };
663 let gt_token: crate::token::GtToken![>] = input.parse()?;
664 let colon2_token: crate::token::PathSepToken![::] = input.parse()?;
665 let mut rest = Punctuated::new();
666 loop {
667 let path = PathSegment::parse_helper(input, expr_style)?;
668 rest.push_value(path);
669 if !input.peek(crate::token::PathSepToken![::]) {
670 break;
671 }
672 let punct: crate::token::PathSepToken![::] = input.parse()?;
673 rest.push_punct(punct);
674 }
675 let (position, as_token, path) = match path {
676 Some((as_token, mut path)) => {
677 let pos = path.segments.len();
678 path.segments.push_punct(colon2_token);
679 path.segments.extend(rest.into_pairs());
680 (pos, Some(as_token), path)
681 }
682 None => {
683 let path = Path {
684 leading_colon: Some(colon2_token),
685 segments: rest,
686 };
687 (0, None, path)
688 }
689 };
690 let qself = QSelf {
691 lt_token,
692 ty: Box::new(this),
693 position,
694 as_token,
695 gt_token,
696 };
697 Ok((Some(qself), path))
698 } else {
699 let path = Path::parse_helper(input, expr_style)?;
700 Ok((None, path))
701 }
702 }
703}
704
705#[cfg(feature = "printing")]
706pub(crate) mod printing {
707 use crate::generics;
708 use crate::path::{
709 AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,
710 ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
711 };
712 use crate::print::TokensOrDefault;
713 #[cfg(feature = "parsing")]
714 use crate::spanned::Spanned;
715 use core::cmp;
716 #[cfg(feature = "parsing")]
717 use proc_macro2::Span;
718 use proc_macro2::TokenStream;
719 use quote::ToTokens;
720
721 pub(crate) enum PathStyle {
722 Expr,
723 Mod,
724 AsWritten,
725 }
726
727 impl Copy for PathStyle {}
728
729 impl Clone for PathStyle {
730 fn clone(&self) -> Self {
731 *self
732 }
733 }
734
735 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
736 impl ToTokens for Path {
737 fn to_tokens(&self, tokens: &mut TokenStream) {
738 print_path(tokens, self, PathStyle::AsWritten);
739 }
740 }
741
742 pub(crate) fn print_path(tokens: &mut TokenStream, path: &Path, style: PathStyle) {
743 path.leading_colon.to_tokens(tokens);
744 for segment in path.segments.pairs() {
745 print_path_segment(tokens, segment.value(), style);
746 segment.punct().to_tokens(tokens);
747 }
748 }
749
750 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
751 impl ToTokens for PathSegment {
752 fn to_tokens(&self, tokens: &mut TokenStream) {
753 print_path_segment(tokens, self, PathStyle::AsWritten);
754 }
755 }
756
757 fn print_path_segment(tokens: &mut TokenStream, segment: &PathSegment, style: PathStyle) {
758 segment.ident.to_tokens(tokens);
759 print_path_arguments(tokens, &segment.arguments, style);
760 }
761
762 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
763 impl ToTokens for PathArguments {
764 fn to_tokens(&self, tokens: &mut TokenStream) {
765 print_path_arguments(tokens, self, PathStyle::AsWritten);
766 }
767 }
768
769 fn print_path_arguments(tokens: &mut TokenStream, arguments: &PathArguments, style: PathStyle) {
770 match arguments {
771 PathArguments::None => {}
772 PathArguments::AngleBracketed(arguments) => {
773 print_angle_bracketed_generic_arguments(tokens, arguments, style);
774 }
775 PathArguments::Parenthesized(arguments) => {
776 print_parenthesized_generic_arguments(tokens, arguments, style);
777 }
778 }
779 }
780
781 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
782 impl ToTokens for GenericArgument {
783 #[allow(clippy::match_same_arms)]
784 fn to_tokens(&self, tokens: &mut TokenStream) {
785 match self {
786 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
787 GenericArgument::Type(ty) => ty.to_tokens(tokens),
788 GenericArgument::Const(expr) => {
789 generics::printing::print_const_argument(expr, tokens);
790 }
791 GenericArgument::AssocType(assoc) => assoc.to_tokens(tokens),
792 GenericArgument::AssocConst(assoc) => assoc.to_tokens(tokens),
793 GenericArgument::Constraint(constraint) => constraint.to_tokens(tokens),
794 }
795 }
796 }
797
798 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
799 impl ToTokens for AngleBracketedGenericArguments {
800 fn to_tokens(&self, tokens: &mut TokenStream) {
801 print_angle_bracketed_generic_arguments(tokens, self, PathStyle::AsWritten);
802 }
803 }
804
805 pub(crate) fn print_angle_bracketed_generic_arguments(
806 tokens: &mut TokenStream,
807 arguments: &AngleBracketedGenericArguments,
808 style: PathStyle,
809 ) {
810 if let PathStyle::Mod = style {
811 return;
812 }
813
814 conditionally_print_turbofish(tokens, &arguments.colon2_token, style);
815 arguments.lt_token.to_tokens(tokens);
816
817 let mut trailing_or_empty = true;
820 for param in arguments.args.pairs() {
821 match param.value() {
822 GenericArgument::Lifetime(_) => {
823 param.to_tokens(tokens);
824 trailing_or_empty = param.punct().is_some();
825 }
826 GenericArgument::Type(_)
827 | GenericArgument::Const(_)
828 | GenericArgument::AssocType(_)
829 | GenericArgument::AssocConst(_)
830 | GenericArgument::Constraint(_) => {}
831 }
832 }
833 for param in arguments.args.pairs() {
834 match param.value() {
835 GenericArgument::Type(_)
836 | GenericArgument::Const(_)
837 | GenericArgument::AssocType(_)
838 | GenericArgument::AssocConst(_)
839 | GenericArgument::Constraint(_) => {
840 if !trailing_or_empty {
841 <crate::token::CommaToken![,]>::default().to_tokens(tokens);
842 }
843 param.to_tokens(tokens);
844 trailing_or_empty = param.punct().is_some();
845 }
846 GenericArgument::Lifetime(_) => {}
847 }
848 }
849
850 arguments.gt_token.to_tokens(tokens);
851 }
852
853 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
854 impl ToTokens for AssocType {
855 fn to_tokens(&self, tokens: &mut TokenStream) {
856 self.ident.to_tokens(tokens);
857 self.generics.to_tokens(tokens);
858 self.eq_token.to_tokens(tokens);
859 self.ty.to_tokens(tokens);
860 }
861 }
862
863 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
864 impl ToTokens for AssocConst {
865 fn to_tokens(&self, tokens: &mut TokenStream) {
866 self.ident.to_tokens(tokens);
867 self.generics.to_tokens(tokens);
868 self.eq_token.to_tokens(tokens);
869 generics::printing::print_const_argument(&self.value, tokens);
870 }
871 }
872
873 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
874 impl ToTokens for Constraint {
875 fn to_tokens(&self, tokens: &mut TokenStream) {
876 self.ident.to_tokens(tokens);
877 self.generics.to_tokens(tokens);
878 self.colon_token.to_tokens(tokens);
879 self.bounds.to_tokens(tokens);
880 }
881 }
882
883 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
884 impl ToTokens for ParenthesizedGenericArguments {
885 fn to_tokens(&self, tokens: &mut TokenStream) {
886 print_parenthesized_generic_arguments(tokens, self, PathStyle::AsWritten);
887 }
888 }
889
890 fn print_parenthesized_generic_arguments(
891 tokens: &mut TokenStream,
892 arguments: &ParenthesizedGenericArguments,
893 style: PathStyle,
894 ) {
895 if let PathStyle::Mod = style {
896 return;
897 }
898
899 conditionally_print_turbofish(tokens, &None, style);
900 arguments.paren_token.surround(tokens, |tokens| {
901 arguments.inputs.to_tokens(tokens);
902 });
903 arguments.output.to_tokens(tokens);
904 }
905
906 pub(crate) fn print_qpath(
907 tokens: &mut TokenStream,
908 qself: &Option<QSelf>,
909 path: &Path,
910 style: PathStyle,
911 ) {
912 let qself = match qself {
913 Some(qself) => qself,
914 None => {
915 print_path(tokens, path, style);
916 return;
917 }
918 };
919 qself.lt_token.to_tokens(tokens);
920 qself.ty.to_tokens(tokens);
921
922 let pos = cmp::min(qself.position, path.segments.len());
923 let mut segments = path.segments.pairs();
924 if pos > 0 {
925 TokensOrDefault(&qself.as_token).to_tokens(tokens);
926 path.leading_colon.to_tokens(tokens);
927 for (i, segment) in segments.by_ref().take(pos).enumerate() {
928 print_path_segment(tokens, segment.value(), PathStyle::AsWritten);
929 if i + 1 == pos {
930 qself.gt_token.to_tokens(tokens);
931 }
932 segment.punct().to_tokens(tokens);
933 }
934 } else {
935 qself.gt_token.to_tokens(tokens);
936 path.leading_colon.to_tokens(tokens);
937 }
938 for segment in segments {
939 print_path_segment(tokens, segment.value(), style);
940 segment.punct().to_tokens(tokens);
941 }
942 }
943
944 fn conditionally_print_turbofish(
945 tokens: &mut TokenStream,
946 colon2_token: &Option<crate::token::PathSepToken![::]>,
947 style: PathStyle,
948 ) {
949 match style {
950 PathStyle::Expr => TokensOrDefault(colon2_token).to_tokens(tokens),
951 PathStyle::Mod => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
952 PathStyle::AsWritten => colon2_token.to_tokens(tokens),
953 }
954 }
955
956 #[cfg(feature = "parsing")]
957 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
958 impl Spanned for QSelf {
959 fn span(&self) -> Span {
960 struct QSelfDelimiters<'a>(&'a QSelf);
961
962 impl<'a> ToTokens for QSelfDelimiters<'a> {
963 fn to_tokens(&self, tokens: &mut TokenStream) {
964 self.0.lt_token.to_tokens(tokens);
965 self.0.gt_token.to_tokens(tokens);
966 }
967 }
968
969 QSelfDelimiters(self).span()
970 }
971 }
972}