1use super::*;
2use crate::punctuated::Punctuated;
3
4ast_struct! {
5 pub struct Path {
10 pub leading_colon: Option<Token![::]>,
11 pub segments: Punctuated<PathSegment, Token![::]>,
12 }
13}
14
15impl<T> From<T> for Path
16where
17 T: Into<PathSegment>,
18{
19 fn from(segment: T) -> Self {
20 let mut path = Path {
21 leading_colon: None,
22 segments: Punctuated::new(),
23 };
24 path.segments.push_value(segment.into());
25 path
26 }
27}
28
29ast_struct! {
30 pub struct PathSegment {
35 pub ident: Ident,
36 pub arguments: PathArguments,
37 }
38}
39
40impl<T> From<T> for PathSegment
41where
42 T: Into<Ident>,
43{
44 fn from(ident: T) -> Self {
45 PathSegment {
46 ident: ident.into(),
47 arguments: PathArguments::None,
48 }
49 }
50}
51
52ast_enum! {
53 pub enum PathArguments {
66 None,
67 AngleBracketed(AngleBracketedGenericArguments),
69 Parenthesized(ParenthesizedGenericArguments),
71 }
72}
73
74impl Default for PathArguments {
75 fn default() -> Self {
76 PathArguments::None
77 }
78}
79
80impl PathArguments {
81 pub fn is_empty(&self) -> bool {
82 match self {
83 PathArguments::None => true,
84 PathArguments::AngleBracketed(bracketed) => bracketed.args.is_empty(),
85 PathArguments::Parenthesized(_) => false,
86 }
87 }
88
89 #[cfg(feature = "parsing")]
90 fn is_none(&self) -> bool {
91 match *self {
92 PathArguments::None => true,
93 PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false,
94 }
95 }
96}
97
98ast_enum! {
99 pub enum GenericArgument {
104 Lifetime(Lifetime),
106 Type(Type),
108 Binding(Binding),
111 Constraint(Constraint),
113 Const(Expr),
118 }
119}
120
121ast_struct! {
122 pub struct AngleBracketedGenericArguments {
128 pub colon2_token: Option<Token![::]>,
129 pub lt_token: Token![<],
130 pub args: Punctuated<GenericArgument, Token![,]>,
131 pub gt_token: Token![>],
132 }
133}
134
135ast_struct! {
136 pub struct Binding {
141 pub ident: Ident,
142 pub eq_token: Token![=],
143 pub ty: Type,
144 }
145}
146
147ast_struct! {
148 pub struct Constraint {
153 pub ident: Ident,
154 pub colon_token: Token![:],
155 pub bounds: Punctuated<TypeParamBound, Token![+]>,
156 }
157}
158
159ast_struct! {
160 pub struct ParenthesizedGenericArguments {
166 pub paren_token: token::Paren,
167 pub inputs: Punctuated<Type, Token![,]>,
169 pub output: ReturnType,
171 }
172}
173
174ast_struct! {
175 pub struct QSelf {
195 pub lt_token: Token![<],
196 pub ty: Box<Type>,
197 pub position: usize,
198 pub as_token: Option<Token![as]>,
199 pub gt_token: Token![>],
200 }
201}
202
203#[cfg(feature = "parsing")]
204pub mod parsing {
205 use super::*;
206
207 #[cfg(feature = "full")]
208 use crate::expr;
209 use crate::ext::IdentExt;
210 use crate::parse::{Parse, ParseStream, Result};
211
212 impl Parse for Path {
213 fn parse(input: ParseStream) -> Result<Self> {
214 Self::parse_helper(input, false)
215 }
216 }
217
218 impl Parse for GenericArgument {
219 fn parse(input: ParseStream) -> Result<Self> {
220 if input.peek(Lifetime) && !input.peek2(Token![+]) {
221 return Ok(GenericArgument::Lifetime(input.parse()?));
222 }
223
224 if input.peek(Ident) && input.peek2(Token![=]) {
225 return Ok(GenericArgument::Binding(input.parse()?));
226 }
227
228 #[cfg(feature = "full")]
229 {
230 if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) {
231 return Ok(GenericArgument::Constraint(input.parse()?));
232 }
233
234 if input.peek(Lit) {
235 let lit = input.parse()?;
236 return Ok(GenericArgument::Const(Expr::Lit(lit)));
237 }
238
239 if input.peek(token::Brace) {
240 let block = input.call(expr::parsing::expr_block)?;
241 return Ok(GenericArgument::Const(Expr::Block(block)));
242 }
243 }
244
245 input.parse().map(GenericArgument::Type)
246 }
247 }
248
249 impl Parse for AngleBracketedGenericArguments {
250 fn parse(input: ParseStream) -> Result<Self> {
251 Ok(AngleBracketedGenericArguments {
252 colon2_token: input.parse()?,
253 lt_token: input.parse()?,
254 args: {
255 let mut args = Punctuated::new();
256 loop {
257 if input.peek(Token![>]) {
258 break;
259 }
260 let value = input.parse()?;
261 args.push_value(value);
262 if input.peek(Token![>]) {
263 break;
264 }
265 let punct = input.parse()?;
266 args.push_punct(punct);
267 }
268 args
269 },
270 gt_token: input.parse()?,
271 })
272 }
273 }
274
275 impl Parse for ParenthesizedGenericArguments {
276 fn parse(input: ParseStream) -> Result<Self> {
277 let content;
278 Ok(ParenthesizedGenericArguments {
279 paren_token: parenthesized!(content in input),
280 inputs: content.parse_terminated(Type::parse)?,
281 output: input.call(ReturnType::without_plus)?,
282 })
283 }
284 }
285
286 impl Parse for PathSegment {
287 fn parse(input: ParseStream) -> Result<Self> {
288 Self::parse_helper(input, false)
289 }
290 }
291
292 impl PathSegment {
293 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
294 if input.peek(Token![super])
295 || input.peek(Token![self])
296 || input.peek(Token![crate])
297 || input.peek(Token![extern])
298 {
299 let ident = input.call(Ident::parse_any)?;
300 return Ok(PathSegment::from(ident));
301 }
302
303 let ident = if input.peek(Token![Self]) {
304 input.call(Ident::parse_any)?
305 } else {
306 input.parse()?
307 };
308
309 if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
310 || input.peek(Token![::]) && input.peek3(Token![<])
311 {
312 Ok(PathSegment {
313 ident,
314 arguments: PathArguments::AngleBracketed(input.parse()?),
315 })
316 } else {
317 Ok(PathSegment::from(ident))
318 }
319 }
320 }
321
322 impl Parse for Binding {
323 fn parse(input: ParseStream) -> Result<Self> {
324 Ok(Binding {
325 ident: input.parse()?,
326 eq_token: input.parse()?,
327 ty: input.parse()?,
328 })
329 }
330 }
331
332 #[cfg(feature = "full")]
333 impl Parse for Constraint {
334 fn parse(input: ParseStream) -> Result<Self> {
335 Ok(Constraint {
336 ident: input.parse()?,
337 colon_token: input.parse()?,
338 bounds: {
339 let mut bounds = Punctuated::new();
340 loop {
341 if input.peek(Token![,]) || input.peek(Token![>]) {
342 break;
343 }
344 let value = input.parse()?;
345 bounds.push_value(value);
346 if !input.peek(Token![+]) {
347 break;
348 }
349 let punct = input.parse()?;
350 bounds.push_punct(punct);
351 }
352 bounds
353 },
354 })
355 }
356 }
357
358 impl Path {
359 pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
393 Ok(Path {
394 leading_colon: input.parse()?,
395 segments: {
396 let mut segments = Punctuated::new();
397 loop {
398 if !input.peek(Ident)
399 && !input.peek(Token![super])
400 && !input.peek(Token![self])
401 && !input.peek(Token![Self])
402 && !input.peek(Token![crate])
403 && !input.peek(Token![extern])
404 {
405 break;
406 }
407 let ident = Ident::parse_any(input)?;
408 segments.push_value(PathSegment::from(ident));
409 if !input.peek(Token![::]) {
410 break;
411 }
412 let punct = input.parse()?;
413 segments.push_punct(punct);
414 }
415 if segments.is_empty() {
416 return Err(input.error("expected path"));
417 } else if segments.trailing_punct() {
418 return Err(input.error("expected path segment"));
419 }
420 segments
421 },
422 })
423 }
424
425 pub fn is_ident<I: ?Sized>(&self, ident: &I) -> bool
457 where
458 Ident: PartialEq<I>,
459 {
460 match self.get_ident() {
461 Some(id) => id == ident,
462 None => false,
463 }
464 }
465
466 pub fn get_ident(&self) -> Option<&Ident> {
478 if self.leading_colon.is_none()
479 && self.segments.len() == 1
480 && self.segments[0].arguments.is_none()
481 {
482 Some(&self.segments[0].ident)
483 } else {
484 None
485 }
486 }
487
488 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
489 Ok(Path {
490 leading_colon: input.parse()?,
491 segments: {
492 let mut segments = Punctuated::new();
493 let value = PathSegment::parse_helper(input, expr_style)?;
494 segments.push_value(value);
495 while input.peek(Token![::]) {
496 let punct: Token![::] = input.parse()?;
497 segments.push_punct(punct);
498 let value = PathSegment::parse_helper(input, expr_style)?;
499 segments.push_value(value);
500 }
501 segments
502 },
503 })
504 }
505 }
506
507 pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
508 if input.peek(Token![<]) {
509 let lt_token: Token![<] = input.parse()?;
510 let this: Type = input.parse()?;
511 let path = if input.peek(Token![as]) {
512 let as_token: Token![as] = input.parse()?;
513 let path: Path = input.parse()?;
514 Some((as_token, path))
515 } else {
516 None
517 };
518 let gt_token: Token![>] = input.parse()?;
519 let colon2_token: Token![::] = input.parse()?;
520 let mut rest = Punctuated::new();
521 loop {
522 let path = PathSegment::parse_helper(input, expr_style)?;
523 rest.push_value(path);
524 if !input.peek(Token![::]) {
525 break;
526 }
527 let punct: Token![::] = input.parse()?;
528 rest.push_punct(punct);
529 }
530 let (position, as_token, path) = match path {
531 Some((as_token, mut path)) => {
532 let pos = path.segments.len();
533 path.segments.push_punct(colon2_token);
534 path.segments.extend(rest.into_pairs());
535 (pos, Some(as_token), path)
536 }
537 None => {
538 let path = Path {
539 leading_colon: Some(colon2_token),
540 segments: rest,
541 };
542 (0, None, path)
543 }
544 };
545 let qself = QSelf {
546 lt_token,
547 ty: Box::new(this),
548 position,
549 as_token,
550 gt_token,
551 };
552 Ok((Some(qself), path))
553 } else {
554 let path = Path::parse_helper(input, expr_style)?;
555 Ok((None, path))
556 }
557 }
558}
559
560#[cfg(feature = "printing")]
561mod printing {
562 use super::*;
563
564 use proc_macro2::TokenStream;
565 use quote::ToTokens;
566
567 use crate::print::TokensOrDefault;
568
569 impl ToTokens for Path {
570 fn to_tokens(&self, tokens: &mut TokenStream) {
571 self.leading_colon.to_tokens(tokens);
572 self.segments.to_tokens(tokens);
573 }
574 }
575
576 impl ToTokens for PathSegment {
577 fn to_tokens(&self, tokens: &mut TokenStream) {
578 self.ident.to_tokens(tokens);
579 self.arguments.to_tokens(tokens);
580 }
581 }
582
583 impl ToTokens for PathArguments {
584 fn to_tokens(&self, tokens: &mut TokenStream) {
585 match self {
586 PathArguments::None => {}
587 PathArguments::AngleBracketed(arguments) => {
588 arguments.to_tokens(tokens);
589 }
590 PathArguments::Parenthesized(arguments) => {
591 arguments.to_tokens(tokens);
592 }
593 }
594 }
595 }
596
597 impl ToTokens for GenericArgument {
598 #[allow(clippy::match_same_arms)]
599 fn to_tokens(&self, tokens: &mut TokenStream) {
600 match self {
601 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens),
602 GenericArgument::Type(ty) => ty.to_tokens(tokens),
603 GenericArgument::Binding(tb) => tb.to_tokens(tokens),
604 GenericArgument::Constraint(tc) => tc.to_tokens(tokens),
605 GenericArgument::Const(e) => match *e {
606 Expr::Lit(_) => e.to_tokens(tokens),
607
608 #[cfg(feature = "full")]
612 Expr::Block(_) => e.to_tokens(tokens),
613
614 _ => token::Brace::default().surround(tokens, |tokens| {
617 e.to_tokens(tokens);
618 }),
619 },
620 }
621 }
622 }
623
624 impl ToTokens for AngleBracketedGenericArguments {
625 fn to_tokens(&self, tokens: &mut TokenStream) {
626 self.colon2_token.to_tokens(tokens);
627 self.lt_token.to_tokens(tokens);
628
629 let mut trailing_or_empty = true;
635 for param in self.args.pairs() {
636 match **param.value() {
637 GenericArgument::Lifetime(_) => {
638 param.to_tokens(tokens);
639 trailing_or_empty = param.punct().is_some();
640 }
641 GenericArgument::Type(_)
642 | GenericArgument::Binding(_)
643 | GenericArgument::Constraint(_)
644 | GenericArgument::Const(_) => {}
645 }
646 }
647 for param in self.args.pairs() {
648 match **param.value() {
649 GenericArgument::Type(_) | GenericArgument::Const(_) => {
650 if !trailing_or_empty {
651 <Token![,]>::default().to_tokens(tokens);
652 }
653 param.to_tokens(tokens);
654 trailing_or_empty = param.punct().is_some();
655 }
656 GenericArgument::Lifetime(_)
657 | GenericArgument::Binding(_)
658 | GenericArgument::Constraint(_) => {}
659 }
660 }
661 for param in self.args.pairs() {
662 match **param.value() {
663 GenericArgument::Binding(_) | GenericArgument::Constraint(_) => {
664 if !trailing_or_empty {
665 <Token![,]>::default().to_tokens(tokens);
666 trailing_or_empty = true;
667 }
668 param.to_tokens(tokens);
669 }
670 GenericArgument::Lifetime(_)
671 | GenericArgument::Type(_)
672 | GenericArgument::Const(_) => {}
673 }
674 }
675
676 self.gt_token.to_tokens(tokens);
677 }
678 }
679
680 impl ToTokens for Binding {
681 fn to_tokens(&self, tokens: &mut TokenStream) {
682 self.ident.to_tokens(tokens);
683 self.eq_token.to_tokens(tokens);
684 self.ty.to_tokens(tokens);
685 }
686 }
687
688 impl ToTokens for Constraint {
689 fn to_tokens(&self, tokens: &mut TokenStream) {
690 self.ident.to_tokens(tokens);
691 self.colon_token.to_tokens(tokens);
692 self.bounds.to_tokens(tokens);
693 }
694 }
695
696 impl ToTokens for ParenthesizedGenericArguments {
697 fn to_tokens(&self, tokens: &mut TokenStream) {
698 self.paren_token.surround(tokens, |tokens| {
699 self.inputs.to_tokens(tokens);
700 });
701 self.output.to_tokens(tokens);
702 }
703 }
704
705 impl private {
706 pub fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
707 let qself = match qself {
708 Some(qself) => qself,
709 None => {
710 path.to_tokens(tokens);
711 return;
712 }
713 };
714 qself.lt_token.to_tokens(tokens);
715 qself.ty.to_tokens(tokens);
716
717 let pos = if qself.position > 0 && qself.position >= path.segments.len() {
718 path.segments.len() - 1
719 } else {
720 qself.position
721 };
722 let mut segments = path.segments.pairs();
723 if pos > 0 {
724 TokensOrDefault(&qself.as_token).to_tokens(tokens);
725 path.leading_colon.to_tokens(tokens);
726 for (i, segment) in segments.by_ref().take(pos).enumerate() {
727 if i + 1 == pos {
728 segment.value().to_tokens(tokens);
729 qself.gt_token.to_tokens(tokens);
730 segment.punct().to_tokens(tokens);
731 } else {
732 segment.to_tokens(tokens);
733 }
734 }
735 } else {
736 qself.gt_token.to_tokens(tokens);
737 path.leading_colon.to_tokens(tokens);
738 }
739 for segment in segments {
740 segment.to_tokens(tokens);
741 }
742 }
743 }
744}