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};
10
11ast_struct! {
12 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
14 pub struct Path {
15 pub leading_colon: Option<Token![::]>,
16 pub segments: Punctuated<PathSegment, Token![::]>,
17 }
18}
19
20impl<T> From<T> for Path
21where
22 T: Into<PathSegment>,
23{
24 fn from(segment: T) -> Self {
25 let mut path = Path {
26 leading_colon: None,
27 segments: Punctuated::new(),
28 };
29 path.segments.push_value(segment.into());
30 path
31 }
32}
33
34impl Path {
35 pub fn is_ident<I>(&self, ident: &I) -> bool
64 where
65 I: ?Sized,
66 Ident: PartialEq<I>,
67 {
68 match self.get_ident() {
69 Some(id) => id == ident,
70 None => false,
71 }
72 }
73
74 pub fn get_ident(&self) -> Option<&Ident> {
83 if self.leading_colon.is_none()
84 && self.segments.len() == 1
85 && self.segments[0].arguments.is_none()
86 {
87 Some(&self.segments[0].ident)
88 } else {
89 None
90 }
91 }
92
93 #[cfg(feature = "parsing")]
95 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
96 pub fn require_ident(&self) -> Result<&Ident> {
97 self.get_ident().ok_or_else(|| {
98 crate::error::new2(
99 self.segments.first().unwrap().ident.span(),
100 self.segments.last().unwrap().ident.span(),
101 "expected this path to be an identifier",
102 )
103 })
104 }
105}
106
107ast_struct! {
108 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
110 pub struct PathSegment {
111 pub ident: Ident,
112 pub arguments: PathArguments,
113 }
114}
115
116impl<T> From<T> for PathSegment
117where
118 T: Into<Ident>,
119{
120 fn from(ident: T) -> Self {
121 PathSegment {
122 ident: ident.into(),
123 arguments: PathArguments::None,
124 }
125 }
126}
127
128ast_enum! {
129 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
139 pub enum PathArguments {
140 None,
141 AngleBracketed(AngleBracketedGenericArguments),
143 Parenthesized(ParenthesizedGenericArguments),
145 }
146}
147
148impl Default for PathArguments {
149 fn default() -> Self {
150 PathArguments::None
151 }
152}
153
154impl PathArguments {
155 pub fn is_empty(&self) -> bool {
156 match self {
157 PathArguments::None => true,
158 PathArguments::AngleBracketed(bracketed) => bracketed.args.is_empty(),
159 PathArguments::Parenthesized(_) => false,
160 }
161 }
162
163 pub fn is_none(&self) -> bool {
164 match self {
165 PathArguments::None => true,
166 PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false,
167 }
168 }
169}
170
171ast_enum! {
172 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
174 #[non_exhaustive]
175 pub enum GenericArgument {
176 Lifetime(Lifetime),
178 Type(Type),
180 Const(Expr),
185 AssocType(AssocType),
188 AssocConst(AssocConst),
191 Constraint(Constraint),
193 }
194}
195
196ast_struct! {
197 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
200 pub struct AngleBracketedGenericArguments {
201 pub colon2_token: Option<Token![::]>,
202 pub lt_token: Token![<],
203 pub args: Punctuated<GenericArgument, Token![,]>,
204 pub gt_token: Token![>],
205 }
206}
207
208ast_struct! {
209 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
212 pub struct AssocType {
213 pub ident: Ident,
214 pub generics: Option<AngleBracketedGenericArguments>,
215 pub eq_token: Token![=],
216 pub ty: Type,
217 }
218}
219
220ast_struct! {
221 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
224 pub struct AssocConst {
225 pub ident: Ident,
226 pub generics: Option<AngleBracketedGenericArguments>,
227 pub eq_token: Token![=],
228 pub value: Expr,
229 }
230}
231
232ast_struct! {
233 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
235 pub struct Constraint {
236 pub ident: Ident,
237 pub generics: Option<AngleBracketedGenericArguments>,
238 pub colon_token: Token![:],
239 pub bounds: Punctuated<TypeParamBound, Token![+]>,
240 }
241}
242
243ast_struct! {
244 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
247 pub struct ParenthesizedGenericArguments {
248 pub paren_token: token::Paren,
249 pub inputs: Punctuated<Type, Token![,]>,
251 pub output: ReturnType,
253 }
254}
255
256ast_struct! {
257 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
274 pub struct QSelf {
275 pub lt_token: Token![<],
276 pub ty: Box<Type>,
277 pub position: usize,
278 pub as_token: Option<Token![as]>,
279 pub gt_token: Token![>],
280 }
281}
282
283#[cfg(feature = "parsing")]
284pub(crate) mod parsing {
285 use crate::error::Result;
286 #[cfg(feature = "full")]
287 use crate::expr::ExprBlock;
288 use crate::expr::{Expr, ExprPath};
289 use crate::ext::IdentExt as _;
290 #[cfg(feature = "full")]
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 #[cfg(feature = "full")]
297 use crate::path::Constraint;
298 use crate::path::{
299 AngleBracketedGenericArguments, AssocConst, AssocType, GenericArgument,
300 ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
301 };
302 use crate::punctuated::Punctuated;
303 use crate::token;
304 use crate::ty::{ReturnType, Type};
305 #[cfg(not(feature = "full"))]
306 use crate::verbatim;
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(Token![+]) {
319 return Ok(GenericArgument::Lifetime(input.parse()?));
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<Token![=]>>()? {
339 let segment = ty.path.segments.pop().unwrap().into_value();
340 let ident = segment.ident;
341 let generics = match segment.arguments {
342 PathArguments::None => None,
343 PathArguments::AngleBracketed(arguments) => Some(arguments),
344 PathArguments::Parenthesized(_) => 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 #[cfg(feature = "full")]
364 if let Some(colon_token) = input.parse::<Option<Token![:]>>()? {
365 let segment = ty.path.segments.pop().unwrap().into_value();
366 return Ok(GenericArgument::Constraint(Constraint {
367 ident: segment.ident,
368 generics: match segment.arguments {
369 PathArguments::None => None,
370 PathArguments::AngleBracketed(arguments) => Some(arguments),
371 PathArguments::Parenthesized(_) => unreachable!(),
372 },
373 colon_token,
374 bounds: {
375 let mut bounds = Punctuated::new();
376 loop {
377 if input.peek(Token![,]) || input.peek(Token![>]) {
378 break;
379 }
380 bounds.push_value({
381 let allow_precise_capture = false;
382 let allow_tilde_const = true;
383 TypeParamBound::parse_single(
384 input,
385 allow_precise_capture,
386 allow_tilde_const,
387 )?
388 });
389 if !input.peek(Token![+]) {
390 break;
391 }
392 let punct: Token![+] = input.parse()?;
393 bounds.push_punct(punct);
394 }
395 bounds
396 },
397 }));
398 }
399
400 argument = Type::Path(ty);
401 }
402 _ => {}
403 }
404
405 Ok(GenericArgument::Type(argument))
406 }
407 }
408
409 pub(crate) fn const_argument(input: ParseStream) -> Result<Expr> {
410 let lookahead = input.lookahead1();
411
412 if input.peek(Lit) {
413 let lit = input.parse()?;
414 return Ok(Expr::Lit(lit));
415 }
416
417 if input.peek(Ident) {
418 let ident: Ident = input.parse()?;
419 return Ok(Expr::Path(ExprPath {
420 attrs: Vec::new(),
421 qself: None,
422 path: Path::from(ident),
423 }));
424 }
425
426 if input.peek(token::Brace) {
427 #[cfg(feature = "full")]
428 {
429 let block: ExprBlock = input.parse()?;
430 return Ok(Expr::Block(block));
431 }
432
433 #[cfg(not(feature = "full"))]
434 {
435 let begin = input.fork();
436 let content;
437 braced!(content in input);
438 content.parse::<Expr>()?;
439 let verbatim = verbatim::between(&begin, input);
440 return Ok(Expr::Verbatim(verbatim));
441 }
442 }
443
444 Err(lookahead.error())
445 }
446
447 impl AngleBracketedGenericArguments {
448 #[cfg(feature = "full")]
453 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))]
454 pub fn parse_turbofish(input: ParseStream) -> Result<Self> {
455 let colon2_token: Token![::] = input.parse()?;
456 Self::do_parse(Some(colon2_token), input)
457 }
458
459 pub(crate) fn do_parse(
460 colon2_token: Option<Token![::]>,
461 input: ParseStream,
462 ) -> Result<Self> {
463 Ok(AngleBracketedGenericArguments {
464 colon2_token,
465 lt_token: input.parse()?,
466 args: {
467 let mut args = Punctuated::new();
468 loop {
469 if input.peek(Token![>]) {
470 break;
471 }
472 let value: GenericArgument = input.parse()?;
473 args.push_value(value);
474 if input.peek(Token![>]) {
475 break;
476 }
477 let punct: Token![,] = input.parse()?;
478 args.push_punct(punct);
479 }
480 args
481 },
482 gt_token: input.parse()?,
483 })
484 }
485 }
486
487 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
488 impl Parse for AngleBracketedGenericArguments {
489 fn parse(input: ParseStream) -> Result<Self> {
490 let colon2_token: Option<Token![::]> = input.parse()?;
491 Self::do_parse(colon2_token, input)
492 }
493 }
494
495 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
496 impl Parse for ParenthesizedGenericArguments {
497 fn parse(input: ParseStream) -> Result<Self> {
498 let content;
499 Ok(ParenthesizedGenericArguments {
500 paren_token: parenthesized!(content in input),
501 inputs: content.parse_terminated(Type::parse, Token![,])?,
502 output: input.call(ReturnType::without_plus)?,
503 })
504 }
505 }
506
507 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
508 impl Parse for PathSegment {
509 fn parse(input: ParseStream) -> Result<Self> {
510 Self::parse_helper(input, false)
511 }
512 }
513
514 impl PathSegment {
515 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
516 if input.peek(Token![super])
517 || input.peek(Token![self])
518 || input.peek(Token![crate])
519 || cfg!(feature = "full") && input.peek(Token![try])
520 {
521 let ident = input.call(Ident::parse_any)?;
522 return Ok(PathSegment::from(ident));
523 }
524
525 let ident = if input.peek(Token![Self]) {
526 input.call(Ident::parse_any)?
527 } else {
528 input.parse()?
529 };
530
531 if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
532 || input.peek(Token![::]) && input.peek3(Token![<])
533 {
534 Ok(PathSegment {
535 ident,
536 arguments: PathArguments::AngleBracketed(input.parse()?),
537 })
538 } else {
539 Ok(PathSegment::from(ident))
540 }
541 }
542 }
543
544 impl Path {
545 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
576 pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
577 Ok(Path {
578 leading_colon: input.parse()?,
579 segments: {
580 let mut segments = Punctuated::new();
581 loop {
582 if !input.peek(Ident)
583 && !input.peek(Token![super])
584 && !input.peek(Token![self])
585 && !input.peek(Token![Self])
586 && !input.peek(Token![crate])
587 {
588 break;
589 }
590 let ident = Ident::parse_any(input)?;
591 segments.push_value(PathSegment::from(ident));
592 if !input.peek(Token![::]) {
593 break;
594 }
595 let punct = input.parse()?;
596 segments.push_punct(punct);
597 }
598 if segments.is_empty() {
599 return Err(input.parse::<Ident>().unwrap_err());
600 } else if segments.trailing_punct() {
601 return Err(input.error("expected path segment after `::`"));
602 }
603 segments
604 },
605 })
606 }
607
608 pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
609 let mut path = Path {
610 leading_colon: input.parse()?,
611 segments: {
612 let mut segments = Punctuated::new();
613 let value = PathSegment::parse_helper(input, expr_style)?;
614 segments.push_value(value);
615 segments
616 },
617 };
618 Path::parse_rest(input, &mut path, expr_style)?;
619 Ok(path)
620 }
621
622 pub(crate) fn parse_rest(
623 input: ParseStream,
624 path: &mut Self,
625 expr_style: bool,
626 ) -> Result<()> {
627 while input.peek(Token![::]) && !input.peek3(token::Paren) {
628 let punct: Token![::] = input.parse()?;
629 path.segments.push_punct(punct);
630 let value = PathSegment::parse_helper(input, expr_style)?;
631 path.segments.push_value(value);
632 }
633 Ok(())
634 }
635
636 pub(crate) fn is_mod_style(&self) -> bool {
637 self.segments
638 .iter()
639 .all(|segment| segment.arguments.is_none())
640 }
641 }
642
643 pub(crate) fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
644 if input.peek(Token![<]) {
645 let lt_token: Token![<] = input.parse()?;
646 let this: Type = input.parse()?;
647 let path = if input.peek(Token![as]) {
648 let as_token: Token![as] = input.parse()?;
649 let path: Path = input.parse()?;
650 Some((as_token, path))
651 } else {
652 None
653 };
654 let gt_token: Token![>] = input.parse()?;
655 let colon2_token: Token![::] = input.parse()?;
656 let mut rest = Punctuated::new();
657 loop {
658 let path = PathSegment::parse_helper(input, expr_style)?;
659 rest.push_value(path);
660 if !input.peek(Token![::]) {
661 break;
662 }
663 let punct: Token![::] = input.parse()?;
664 rest.push_punct(punct);
665 }
666 let (position, as_token, path) = match path {
667 Some((as_token, mut path)) => {
668 let pos = path.segments.len();
669 path.segments.push_punct(colon2_token);
670 path.segments.extend(rest.into_pairs());
671 (pos, Some(as_token), path)
672 }
673 None => {
674 let path = Path {
675 leading_colon: Some(colon2_token),
676 segments: rest,
677 };
678 (0, None, path)
679 }
680 };
681 let qself = QSelf {
682 lt_token,
683 ty: Box::new(this),
684 position,
685 as_token,
686 gt_token,
687 };
688 Ok((Some(qself), path))
689 } else {
690 let path = Path::parse_helper(input, expr_style)?;
691 Ok((None, path))
692 }
693 }
694}
695
696#[cfg(feature = "printing")]
697pub(crate) mod printing {
698 use crate::generics;
699 use crate::path::{
700 AngleBracketedGenericArguments, AssocConst, AssocType, Constraint, GenericArgument,
701 ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf,
702 };
703 use crate::print::TokensOrDefault;
704 #[cfg(feature = "parsing")]
705 use crate::spanned::Spanned;
706 #[cfg(feature = "parsing")]
707 use proc_macro2::Span;
708 use proc_macro2::TokenStream;
709 use quote::ToTokens;
710 use std::cmp;
711
712 pub(crate) enum PathStyle {
713 Expr,
714 Mod,
715 AsWritten,
716 }
717
718 impl Copy for PathStyle {}
719
720 impl Clone for PathStyle {
721 fn clone(&self) -> Self {
722 *self
723 }
724 }
725
726 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
727 impl ToTokens for Path {
728 fn to_tokens(&self, tokens: &mut TokenStream) {
729 print_path(tokens, self, PathStyle::AsWritten);
730 }
731 }
732
733 pub(crate) fn print_path(tokens: &mut TokenStream, path: &Path, style: PathStyle) {
734 path.leading_colon.to_tokens(tokens);
735 for segment in path.segments.pairs() {
736 print_path_segment(tokens, segment.value(), style);
737 segment.punct().to_tokens(tokens);
738 }
739 }
740
741 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
742 impl ToTokens for PathSegment {
743 fn to_tokens(&self, tokens: &mut TokenStream) {
744 print_path_segment(tokens, self, PathStyle::AsWritten);
745 }
746 }
747
748 fn print_path_segment(tokens: &mut TokenStream, segment: &PathSegment, style: PathStyle) {
749 segment.ident.to_tokens(tokens);
750 print_path_arguments(tokens, &segment.arguments, style);
751 }
752
753 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
754 impl ToTokens for PathArguments {
755 fn to_tokens(&self, tokens: &mut TokenStream) {
756 print_path_arguments(tokens, self, PathStyle::AsWritten);
757 }
758 }
759
760 fn print_path_arguments(tokens: &mut TokenStream, arguments: &PathArguments, style: PathStyle) {
761 match arguments {
762 PathArguments::None => {}
763 PathArguments::AngleBracketed(arguments) => {
764 print_angle_bracketed_generic_arguments(tokens, arguments, style);
765 }
766 PathArguments::Parenthesized(arguments) => {
767 print_parenthesized_generic_arguments(tokens, arguments, style);
768 }
769 }
770 }
771
772 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
773 impl ToTokens for GenericArgument {
774 #[allow(clippy::match_same_arms)]
775 fn to_tokens(&self, tokens: &mut TokenStream) {
776 match self {
777 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
778 GenericArgument::Type(ty) => ty.to_tokens(tokens),
779 GenericArgument::Const(expr) => {
780 generics::printing::print_const_argument(expr, tokens);
781 }
782 GenericArgument::AssocType(assoc) => assoc.to_tokens(tokens),
783 GenericArgument::AssocConst(assoc) => assoc.to_tokens(tokens),
784 GenericArgument::Constraint(constraint) => constraint.to_tokens(tokens),
785 }
786 }
787 }
788
789 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
790 impl ToTokens for AngleBracketedGenericArguments {
791 fn to_tokens(&self, tokens: &mut TokenStream) {
792 print_angle_bracketed_generic_arguments(tokens, self, PathStyle::AsWritten);
793 }
794 }
795
796 pub(crate) fn print_angle_bracketed_generic_arguments(
797 tokens: &mut TokenStream,
798 arguments: &AngleBracketedGenericArguments,
799 style: PathStyle,
800 ) {
801 if let PathStyle::Mod = style {
802 return;
803 }
804
805 conditionally_print_turbofish(tokens, &arguments.colon2_token, style);
806 arguments.lt_token.to_tokens(tokens);
807
808 let mut trailing_or_empty = true;
811 for param in arguments.args.pairs() {
812 match param.value() {
813 GenericArgument::Lifetime(_) => {
814 param.to_tokens(tokens);
815 trailing_or_empty = param.punct().is_some();
816 }
817 GenericArgument::Type(_)
818 | GenericArgument::Const(_)
819 | GenericArgument::AssocType(_)
820 | GenericArgument::AssocConst(_)
821 | GenericArgument::Constraint(_) => {}
822 }
823 }
824 for param in arguments.args.pairs() {
825 match param.value() {
826 GenericArgument::Type(_)
827 | GenericArgument::Const(_)
828 | GenericArgument::AssocType(_)
829 | GenericArgument::AssocConst(_)
830 | GenericArgument::Constraint(_) => {
831 if !trailing_or_empty {
832 <Token![,]>::default().to_tokens(tokens);
833 }
834 param.to_tokens(tokens);
835 trailing_or_empty = param.punct().is_some();
836 }
837 GenericArgument::Lifetime(_) => {}
838 }
839 }
840
841 arguments.gt_token.to_tokens(tokens);
842 }
843
844 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
845 impl ToTokens for AssocType {
846 fn to_tokens(&self, tokens: &mut TokenStream) {
847 self.ident.to_tokens(tokens);
848 self.generics.to_tokens(tokens);
849 self.eq_token.to_tokens(tokens);
850 self.ty.to_tokens(tokens);
851 }
852 }
853
854 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
855 impl ToTokens for AssocConst {
856 fn to_tokens(&self, tokens: &mut TokenStream) {
857 self.ident.to_tokens(tokens);
858 self.generics.to_tokens(tokens);
859 self.eq_token.to_tokens(tokens);
860 generics::printing::print_const_argument(&self.value, tokens);
861 }
862 }
863
864 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
865 impl ToTokens for Constraint {
866 fn to_tokens(&self, tokens: &mut TokenStream) {
867 self.ident.to_tokens(tokens);
868 self.generics.to_tokens(tokens);
869 self.colon_token.to_tokens(tokens);
870 self.bounds.to_tokens(tokens);
871 }
872 }
873
874 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
875 impl ToTokens for ParenthesizedGenericArguments {
876 fn to_tokens(&self, tokens: &mut TokenStream) {
877 print_parenthesized_generic_arguments(tokens, self, PathStyle::AsWritten);
878 }
879 }
880
881 fn print_parenthesized_generic_arguments(
882 tokens: &mut TokenStream,
883 arguments: &ParenthesizedGenericArguments,
884 style: PathStyle,
885 ) {
886 if let PathStyle::Mod = style {
887 return;
888 }
889
890 conditionally_print_turbofish(tokens, &None, style);
891 arguments.paren_token.surround(tokens, |tokens| {
892 arguments.inputs.to_tokens(tokens);
893 });
894 arguments.output.to_tokens(tokens);
895 }
896
897 pub(crate) fn print_qpath(
898 tokens: &mut TokenStream,
899 qself: &Option<QSelf>,
900 path: &Path,
901 style: PathStyle,
902 ) {
903 let qself = match qself {
904 Some(qself) => qself,
905 None => {
906 print_path(tokens, path, style);
907 return;
908 }
909 };
910 qself.lt_token.to_tokens(tokens);
911 qself.ty.to_tokens(tokens);
912
913 let pos = cmp::min(qself.position, path.segments.len());
914 let mut segments = path.segments.pairs();
915 if pos > 0 {
916 TokensOrDefault(&qself.as_token).to_tokens(tokens);
917 path.leading_colon.to_tokens(tokens);
918 for (i, segment) in segments.by_ref().take(pos).enumerate() {
919 print_path_segment(tokens, segment.value(), PathStyle::AsWritten);
920 if i + 1 == pos {
921 qself.gt_token.to_tokens(tokens);
922 }
923 segment.punct().to_tokens(tokens);
924 }
925 } else {
926 qself.gt_token.to_tokens(tokens);
927 path.leading_colon.to_tokens(tokens);
928 }
929 for segment in segments {
930 print_path_segment(tokens, segment.value(), style);
931 segment.punct().to_tokens(tokens);
932 }
933 }
934
935 fn conditionally_print_turbofish(
936 tokens: &mut TokenStream,
937 colon2_token: &Option<Token![::]>,
938 style: PathStyle,
939 ) {
940 match style {
941 PathStyle::Expr => TokensOrDefault(colon2_token).to_tokens(tokens),
942 PathStyle::Mod => unreachable!(),
943 PathStyle::AsWritten => colon2_token.to_tokens(tokens),
944 }
945 }
946
947 #[cfg(feature = "parsing")]
948 #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "printing"))))]
949 impl Spanned for QSelf {
950 fn span(&self) -> Span {
951 struct QSelfDelimiters<'a>(&'a QSelf);
952
953 impl<'a> ToTokens for QSelfDelimiters<'a> {
954 fn to_tokens(&self, tokens: &mut TokenStream) {
955 self.0.lt_token.to_tokens(tokens);
956 self.0.gt_token.to_tokens(tokens);
957 }
958 }
959
960 QSelfDelimiters(self).span()
961 }
962 }
963}