1use super::*;
2use 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(ref 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 expr;
209 use ext::IdentExt;
210 use 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 pub 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![Self])
297 || input.peek(Token![crate])
298 || input.peek(Token![extern])
299 {
300 let ident = input.call(Ident::parse_any)?;
301 return Ok(PathSegment::from(ident));
302 }
303
304 let ident = input.parse()?;
305 if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
306 || input.peek(Token![::]) && input.peek3(Token![<])
307 {
308 Ok(PathSegment {
309 ident: ident,
310 arguments: PathArguments::AngleBracketed(input.parse()?),
311 })
312 } else {
313 Ok(PathSegment::from(ident))
314 }
315 }
316 }
317
318 impl Parse for Binding {
319 fn parse(input: ParseStream) -> Result<Self> {
320 Ok(Binding {
321 ident: input.parse()?,
322 eq_token: input.parse()?,
323 ty: input.parse()?,
324 })
325 }
326 }
327
328 #[cfg(feature = "full")]
329 impl Parse for Constraint {
330 fn parse(input: ParseStream) -> Result<Self> {
331 Ok(Constraint {
332 ident: input.parse()?,
333 colon_token: input.parse()?,
334 bounds: {
335 let mut bounds = Punctuated::new();
336 loop {
337 if input.peek(Token![,]) || input.peek(Token![>]) {
338 break;
339 }
340 let value = input.parse()?;
341 bounds.push_value(value);
342 if !input.peek(Token![+]) {
343 break;
344 }
345 let punct = input.parse()?;
346 bounds.push_punct(punct);
347 }
348 bounds
349 },
350 })
351 }
352 }
353
354 impl Path {
355 pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
389 Ok(Path {
390 leading_colon: input.parse()?,
391 segments: {
392 let mut segments = Punctuated::new();
393 loop {
394 if !input.peek(Ident)
395 && !input.peek(Token![super])
396 && !input.peek(Token![self])
397 && !input.peek(Token![Self])
398 && !input.peek(Token![crate])
399 && !input.peek(Token![extern])
400 {
401 break;
402 }
403 let ident = Ident::parse_any(input)?;
404 segments.push_value(PathSegment::from(ident));
405 if !input.peek(Token![::]) {
406 break;
407 }
408 let punct = input.parse()?;
409 segments.push_punct(punct);
410 }
411 if segments.is_empty() {
412 return Err(input.error("expected path"));
413 } else if segments.trailing_punct() {
414 return Err(input.error("expected path segment"));
415 }
416 segments
417 },
418 })
419 }
420
421 pub fn is_ident<I>(&self, ident: I) -> bool
435 where
436 Ident: PartialEq<I>,
437 {
438 self.leading_colon.is_none()
439 && self.segments.len() == 1
440 && self.segments[0].arguments.is_none()
441 && self.segments[0].ident == ident
442 }
443
444 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
445 if input.peek(Token![dyn]) {
446 return Err(input.error("expected path"));
447 }
448
449 Ok(Path {
450 leading_colon: input.parse()?,
451 segments: {
452 let mut segments = Punctuated::new();
453 let value = PathSegment::parse_helper(input, expr_style)?;
454 segments.push_value(value);
455 while input.peek(Token![::]) {
456 let punct: Token![::] = input.parse()?;
457 segments.push_punct(punct);
458 let value = PathSegment::parse_helper(input, expr_style)?;
459 segments.push_value(value);
460 }
461 segments
462 },
463 })
464 }
465 }
466
467 pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
468 if input.peek(Token![<]) {
469 let lt_token: Token![<] = input.parse()?;
470 let this: Type = input.parse()?;
471 let path = if input.peek(Token![as]) {
472 let as_token: Token![as] = input.parse()?;
473 let path: Path = input.parse()?;
474 Some((as_token, path))
475 } else {
476 None
477 };
478 let gt_token: Token![>] = input.parse()?;
479 let colon2_token: Token![::] = input.parse()?;
480 let mut rest = Punctuated::new();
481 loop {
482 let path = PathSegment::parse_helper(input, expr_style)?;
483 rest.push_value(path);
484 if !input.peek(Token![::]) {
485 break;
486 }
487 let punct: Token![::] = input.parse()?;
488 rest.push_punct(punct);
489 }
490 let (position, as_token, path) = match path {
491 Some((as_token, mut path)) => {
492 let pos = path.segments.len();
493 path.segments.push_punct(colon2_token);
494 path.segments.extend(rest.into_pairs());
495 (pos, Some(as_token), path)
496 }
497 None => {
498 let path = Path {
499 leading_colon: Some(colon2_token),
500 segments: rest,
501 };
502 (0, None, path)
503 }
504 };
505 let qself = QSelf {
506 lt_token: lt_token,
507 ty: Box::new(this),
508 position: position,
509 as_token: as_token,
510 gt_token: gt_token,
511 };
512 Ok((Some(qself), path))
513 } else {
514 let path = Path::parse_helper(input, expr_style)?;
515 Ok((None, path))
516 }
517 }
518}
519
520#[cfg(feature = "printing")]
521mod printing {
522 use super::*;
523
524 use proc_macro2::TokenStream;
525 use quote::ToTokens;
526
527 use print::TokensOrDefault;
528
529 impl ToTokens for Path {
530 fn to_tokens(&self, tokens: &mut TokenStream) {
531 self.leading_colon.to_tokens(tokens);
532 self.segments.to_tokens(tokens);
533 }
534 }
535
536 impl ToTokens for PathSegment {
537 fn to_tokens(&self, tokens: &mut TokenStream) {
538 self.ident.to_tokens(tokens);
539 self.arguments.to_tokens(tokens);
540 }
541 }
542
543 impl ToTokens for PathArguments {
544 fn to_tokens(&self, tokens: &mut TokenStream) {
545 match *self {
546 PathArguments::None => {}
547 PathArguments::AngleBracketed(ref arguments) => {
548 arguments.to_tokens(tokens);
549 }
550 PathArguments::Parenthesized(ref arguments) => {
551 arguments.to_tokens(tokens);
552 }
553 }
554 }
555 }
556
557 impl ToTokens for GenericArgument {
558 #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
559 fn to_tokens(&self, tokens: &mut TokenStream) {
560 match *self {
561 GenericArgument::Lifetime(ref lt) => lt.to_tokens(tokens),
562 GenericArgument::Type(ref ty) => ty.to_tokens(tokens),
563 GenericArgument::Binding(ref tb) => tb.to_tokens(tokens),
564 GenericArgument::Constraint(ref tc) => tc.to_tokens(tokens),
565 GenericArgument::Const(ref e) => match *e {
566 Expr::Lit(_) => e.to_tokens(tokens),
567
568 #[cfg(feature = "full")]
572 Expr::Block(_) => e.to_tokens(tokens),
573
574 _ => token::Brace::default().surround(tokens, |tokens| {
577 e.to_tokens(tokens);
578 }),
579 },
580 }
581 }
582 }
583
584 impl ToTokens for AngleBracketedGenericArguments {
585 fn to_tokens(&self, tokens: &mut TokenStream) {
586 self.colon2_token.to_tokens(tokens);
587 self.lt_token.to_tokens(tokens);
588
589 let mut trailing_or_empty = true;
595 for param in self.args.pairs() {
596 match **param.value() {
597 GenericArgument::Lifetime(_) => {
598 param.to_tokens(tokens);
599 trailing_or_empty = param.punct().is_some();
600 }
601 GenericArgument::Type(_)
602 | GenericArgument::Binding(_)
603 | GenericArgument::Constraint(_)
604 | GenericArgument::Const(_) => {}
605 }
606 }
607 for param in self.args.pairs() {
608 match **param.value() {
609 GenericArgument::Type(_) | GenericArgument::Const(_) => {
610 if !trailing_or_empty {
611 <Token![,]>::default().to_tokens(tokens);
612 }
613 param.to_tokens(tokens);
614 trailing_or_empty = param.punct().is_some();
615 }
616 GenericArgument::Lifetime(_)
617 | GenericArgument::Binding(_)
618 | GenericArgument::Constraint(_) => {}
619 }
620 }
621 for param in self.args.pairs() {
622 match **param.value() {
623 GenericArgument::Binding(_) | GenericArgument::Constraint(_) => {
624 if !trailing_or_empty {
625 <Token![,]>::default().to_tokens(tokens);
626 trailing_or_empty = true;
627 }
628 param.to_tokens(tokens);
629 }
630 GenericArgument::Lifetime(_)
631 | GenericArgument::Type(_)
632 | GenericArgument::Const(_) => {}
633 }
634 }
635
636 self.gt_token.to_tokens(tokens);
637 }
638 }
639
640 impl ToTokens for Binding {
641 fn to_tokens(&self, tokens: &mut TokenStream) {
642 self.ident.to_tokens(tokens);
643 self.eq_token.to_tokens(tokens);
644 self.ty.to_tokens(tokens);
645 }
646 }
647
648 impl ToTokens for Constraint {
649 fn to_tokens(&self, tokens: &mut TokenStream) {
650 self.ident.to_tokens(tokens);
651 self.colon_token.to_tokens(tokens);
652 self.bounds.to_tokens(tokens);
653 }
654 }
655
656 impl ToTokens for ParenthesizedGenericArguments {
657 fn to_tokens(&self, tokens: &mut TokenStream) {
658 self.paren_token.surround(tokens, |tokens| {
659 self.inputs.to_tokens(tokens);
660 });
661 self.output.to_tokens(tokens);
662 }
663 }
664
665 impl private {
666 pub fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
667 let qself = match *qself {
668 Some(ref qself) => qself,
669 None => {
670 path.to_tokens(tokens);
671 return;
672 }
673 };
674 qself.lt_token.to_tokens(tokens);
675 qself.ty.to_tokens(tokens);
676
677 let pos = if qself.position > 0 && qself.position >= path.segments.len() {
678 path.segments.len() - 1
679 } else {
680 qself.position
681 };
682 let mut segments = path.segments.pairs();
683 if pos > 0 {
684 TokensOrDefault(&qself.as_token).to_tokens(tokens);
685 path.leading_colon.to_tokens(tokens);
686 for (i, segment) in segments.by_ref().take(pos).enumerate() {
687 if i + 1 == pos {
688 segment.value().to_tokens(tokens);
689 qself.gt_token.to_tokens(tokens);
690 segment.punct().to_tokens(tokens);
691 } else {
692 segment.to_tokens(tokens);
693 }
694 }
695 } else {
696 qself.gt_token.to_tokens(tokens);
697 path.leading_colon.to_tokens(tokens);
698 }
699 for segment in segments {
700 segment.to_tokens(tokens);
701 }
702 }
703 }
704}