1 use super::*; 2 use crate::punctuated::Punctuated; 3 4 ast_struct! { 5 /// A path at which a named item is exported (e.g. `std::collections::HashMap`). 6 /// 7 /// *This type is available only if Syn is built with the `"derive"` or `"full"` 8 /// feature.* 9 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 10 pub struct Path { 11 pub leading_colon: Option<Token![::]>, 12 pub segments: Punctuated<PathSegment, Token![::]>, 13 } 14 } 15 16 impl<T> From<T> for Path 17 where 18 T: Into<PathSegment>, 19 { from(segment: T) -> Self20 fn from(segment: T) -> Self { 21 let mut path = Path { 22 leading_colon: None, 23 segments: Punctuated::new(), 24 }; 25 path.segments.push_value(segment.into()); 26 path 27 } 28 } 29 30 ast_struct! { 31 /// A segment of a path together with any path arguments on that segment. 32 /// 33 /// *This type is available only if Syn is built with the `"derive"` or `"full"` 34 /// feature.* 35 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 36 pub struct PathSegment { 37 pub ident: Ident, 38 pub arguments: PathArguments, 39 } 40 } 41 42 impl<T> From<T> for PathSegment 43 where 44 T: Into<Ident>, 45 { from(ident: T) -> Self46 fn from(ident: T) -> Self { 47 PathSegment { 48 ident: ident.into(), 49 arguments: PathArguments::None, 50 } 51 } 52 } 53 54 ast_enum! { 55 /// Angle bracketed or parenthesized arguments of a path segment. 56 /// 57 /// *This type is available only if Syn is built with the `"derive"` or `"full"` 58 /// feature.* 59 /// 60 /// ## Angle bracketed 61 /// 62 /// The `<'a, T>` in `std::slice::iter<'a, T>`. 63 /// 64 /// ## Parenthesized 65 /// 66 /// The `(A, B) -> C` in `Fn(A, B) -> C`. 67 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 68 pub enum PathArguments { 69 None, 70 /// The `<'a, T>` in `std::slice::iter<'a, T>`. 71 AngleBracketed(AngleBracketedGenericArguments), 72 /// The `(A, B) -> C` in `Fn(A, B) -> C`. 73 Parenthesized(ParenthesizedGenericArguments), 74 } 75 } 76 77 impl Default for PathArguments { default() -> Self78 fn default() -> Self { 79 PathArguments::None 80 } 81 } 82 83 impl PathArguments { is_empty(&self) -> bool84 pub fn is_empty(&self) -> bool { 85 match self { 86 PathArguments::None => true, 87 PathArguments::AngleBracketed(bracketed) => bracketed.args.is_empty(), 88 PathArguments::Parenthesized(_) => false, 89 } 90 } 91 92 #[cfg(feature = "parsing")] is_none(&self) -> bool93 fn is_none(&self) -> bool { 94 match *self { 95 PathArguments::None => true, 96 PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false, 97 } 98 } 99 } 100 101 ast_enum! { 102 /// An individual generic argument, like `'a`, `T`, or `Item = T`. 103 /// 104 /// *This type is available only if Syn is built with the `"derive"` or `"full"` 105 /// feature.* 106 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 107 pub enum GenericArgument { 108 /// A lifetime argument. 109 Lifetime(Lifetime), 110 /// A type argument. 111 Type(Type), 112 /// A binding (equality constraint) on an associated type: the `Item = 113 /// u8` in `Iterator<Item = u8>`. 114 Binding(Binding), 115 /// An associated type bound: `Iterator<Item: Display>`. 116 Constraint(Constraint), 117 /// A const expression. Must be inside of a block. 118 /// 119 /// NOTE: Identity expressions are represented as Type arguments, as 120 /// they are indistinguishable syntactically. 121 Const(Expr), 122 } 123 } 124 125 ast_struct! { 126 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K, 127 /// V>`. 128 /// 129 /// *This type is available only if Syn is built with the `"derive"` or `"full"` 130 /// feature.* 131 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 132 pub struct AngleBracketedGenericArguments { 133 pub colon2_token: Option<Token![::]>, 134 pub lt_token: Token![<], 135 pub args: Punctuated<GenericArgument, Token![,]>, 136 pub gt_token: Token![>], 137 } 138 } 139 140 ast_struct! { 141 /// A binding (equality constraint) on an associated type: `Item = u8`. 142 /// 143 /// *This type is available only if Syn is built with the `"derive"` or `"full"` 144 /// feature.* 145 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 146 pub struct Binding { 147 pub ident: Ident, 148 pub eq_token: Token![=], 149 pub ty: Type, 150 } 151 } 152 153 ast_struct! { 154 /// An associated type bound: `Iterator<Item: Display>`. 155 /// 156 /// *This type is available only if Syn is built with the `"derive"` or `"full"` 157 /// feature.* 158 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 159 pub struct Constraint { 160 pub ident: Ident, 161 pub colon_token: Token![:], 162 pub bounds: Punctuated<TypeParamBound, Token![+]>, 163 } 164 } 165 166 ast_struct! { 167 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) -> 168 /// C`. 169 /// 170 /// *This type is available only if Syn is built with the `"derive"` or `"full"` 171 /// feature.* 172 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 173 pub struct ParenthesizedGenericArguments { 174 pub paren_token: token::Paren, 175 /// `(A, B)` 176 pub inputs: Punctuated<Type, Token![,]>, 177 /// `C` 178 pub output: ReturnType, 179 } 180 } 181 182 ast_struct! { 183 /// The explicit Self type in a qualified path: the `T` in `<T as 184 /// Display>::fmt`. 185 /// 186 /// The actual path, including the trait and the associated item, is stored 187 /// separately. The `position` field represents the index of the associated 188 /// item qualified with this Self type. 189 /// 190 /// ```text 191 /// <Vec<T> as a::b::Trait>::AssociatedItem 192 /// ^~~~~~ ~~~~~~~~~~~~~~^ 193 /// ty position = 3 194 /// 195 /// <Vec<T>>::AssociatedItem 196 /// ^~~~~~ ^ 197 /// ty position = 0 198 /// ``` 199 /// 200 /// *This type is available only if Syn is built with the `"derive"` or `"full"` 201 /// feature.* 202 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] 203 pub struct QSelf { 204 pub lt_token: Token![<], 205 pub ty: Box<Type>, 206 pub position: usize, 207 pub as_token: Option<Token![as]>, 208 pub gt_token: Token![>], 209 } 210 } 211 212 #[cfg(feature = "parsing")] 213 pub mod parsing { 214 use super::*; 215 216 use crate::ext::IdentExt; 217 use crate::parse::{Parse, ParseStream, Result}; 218 219 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 220 impl Parse for Path { parse(input: ParseStream) -> Result<Self>221 fn parse(input: ParseStream) -> Result<Self> { 222 Self::parse_helper(input, false) 223 } 224 } 225 226 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 227 impl Parse for GenericArgument { parse(input: ParseStream) -> Result<Self>228 fn parse(input: ParseStream) -> Result<Self> { 229 if input.peek(Lifetime) && !input.peek2(Token![+]) { 230 return Ok(GenericArgument::Lifetime(input.parse()?)); 231 } 232 233 if input.peek(Ident) && input.peek2(Token![=]) { 234 return Ok(GenericArgument::Binding(input.parse()?)); 235 } 236 237 #[cfg(feature = "full")] 238 { 239 if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) { 240 return Ok(GenericArgument::Constraint(input.parse()?)); 241 } 242 } 243 244 if input.peek(Lit) || input.peek(token::Brace) { 245 return const_argument(input).map(GenericArgument::Const); 246 } 247 248 #[cfg(feature = "full")] 249 let begin = input.fork(); 250 251 let argument: Type = input.parse()?; 252 253 #[cfg(feature = "full")] 254 { 255 if match &argument { 256 Type::Path(argument) 257 if argument.qself.is_none() 258 && argument.path.leading_colon.is_none() 259 && argument.path.segments.len() == 1 => 260 { 261 match argument.path.segments[0].arguments { 262 PathArguments::AngleBracketed(_) => true, 263 _ => false, 264 } 265 } 266 _ => false, 267 } && if input.peek(Token![=]) { 268 input.parse::<Token![=]>()?; 269 input.parse::<Type>()?; 270 true 271 } else if input.peek(Token![:]) { 272 input.parse::<Token![:]>()?; 273 input.call(constraint_bounds)?; 274 true 275 } else { 276 false 277 } { 278 let verbatim = verbatim::between(begin, input); 279 return Ok(GenericArgument::Type(Type::Verbatim(verbatim))); 280 } 281 } 282 283 Ok(GenericArgument::Type(argument)) 284 } 285 } 286 const_argument(input: ParseStream) -> Result<Expr>287 pub fn const_argument(input: ParseStream) -> Result<Expr> { 288 let lookahead = input.lookahead1(); 289 290 if input.peek(Lit) { 291 let lit = input.parse()?; 292 return Ok(Expr::Lit(lit)); 293 } 294 295 #[cfg(feature = "full")] 296 { 297 if input.peek(Ident) { 298 let ident: Ident = input.parse()?; 299 return Ok(Expr::Path(ExprPath { 300 attrs: Vec::new(), 301 qself: None, 302 path: Path::from(ident), 303 })); 304 } 305 } 306 307 if input.peek(token::Brace) { 308 #[cfg(feature = "full")] 309 { 310 let block: ExprBlock = input.parse()?; 311 return Ok(Expr::Block(block)); 312 } 313 314 #[cfg(not(feature = "full"))] 315 { 316 let begin = input.fork(); 317 let content; 318 braced!(content in input); 319 content.parse::<Expr>()?; 320 let verbatim = verbatim::between(begin, input); 321 return Ok(Expr::Verbatim(verbatim)); 322 } 323 } 324 325 Err(lookahead.error()) 326 } 327 328 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 329 impl Parse for AngleBracketedGenericArguments { parse(input: ParseStream) -> Result<Self>330 fn parse(input: ParseStream) -> Result<Self> { 331 Ok(AngleBracketedGenericArguments { 332 colon2_token: input.parse()?, 333 lt_token: input.parse()?, 334 args: { 335 let mut args = Punctuated::new(); 336 loop { 337 if input.peek(Token![>]) { 338 break; 339 } 340 let value = input.parse()?; 341 args.push_value(value); 342 if input.peek(Token![>]) { 343 break; 344 } 345 let punct = input.parse()?; 346 args.push_punct(punct); 347 } 348 args 349 }, 350 gt_token: input.parse()?, 351 }) 352 } 353 } 354 355 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 356 impl Parse for ParenthesizedGenericArguments { parse(input: ParseStream) -> Result<Self>357 fn parse(input: ParseStream) -> Result<Self> { 358 let content; 359 Ok(ParenthesizedGenericArguments { 360 paren_token: parenthesized!(content in input), 361 inputs: content.parse_terminated(Type::parse)?, 362 output: input.call(ReturnType::without_plus)?, 363 }) 364 } 365 } 366 367 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 368 impl Parse for PathSegment { parse(input: ParseStream) -> Result<Self>369 fn parse(input: ParseStream) -> Result<Self> { 370 Self::parse_helper(input, false) 371 } 372 } 373 374 impl PathSegment { parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>375 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { 376 if input.peek(Token![super]) || input.peek(Token![self]) || input.peek(Token![crate]) { 377 let ident = input.call(Ident::parse_any)?; 378 return Ok(PathSegment::from(ident)); 379 } 380 381 let ident = if input.peek(Token![Self]) { 382 input.call(Ident::parse_any)? 383 } else { 384 input.parse()? 385 }; 386 387 if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=]) 388 || input.peek(Token![::]) && input.peek3(Token![<]) 389 { 390 Ok(PathSegment { 391 ident, 392 arguments: PathArguments::AngleBracketed(input.parse()?), 393 }) 394 } else { 395 Ok(PathSegment::from(ident)) 396 } 397 } 398 } 399 400 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 401 impl Parse for Binding { parse(input: ParseStream) -> Result<Self>402 fn parse(input: ParseStream) -> Result<Self> { 403 Ok(Binding { 404 ident: input.parse()?, 405 eq_token: input.parse()?, 406 ty: input.parse()?, 407 }) 408 } 409 } 410 411 #[cfg(feature = "full")] 412 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] 413 impl Parse for Constraint { parse(input: ParseStream) -> Result<Self>414 fn parse(input: ParseStream) -> Result<Self> { 415 Ok(Constraint { 416 ident: input.parse()?, 417 colon_token: input.parse()?, 418 bounds: constraint_bounds(input)?, 419 }) 420 } 421 } 422 423 #[cfg(feature = "full")] constraint_bounds(input: ParseStream) -> Result<Punctuated<TypeParamBound, Token![+]>>424 fn constraint_bounds(input: ParseStream) -> Result<Punctuated<TypeParamBound, Token![+]>> { 425 let mut bounds = Punctuated::new(); 426 loop { 427 if input.peek(Token![,]) || input.peek(Token![>]) { 428 break; 429 } 430 let value = input.parse()?; 431 bounds.push_value(value); 432 if !input.peek(Token![+]) { 433 break; 434 } 435 let punct = input.parse()?; 436 bounds.push_punct(punct); 437 } 438 Ok(bounds) 439 } 440 441 impl Path { 442 /// Parse a `Path` containing no path arguments on any of its segments. 443 /// 444 /// *This function is available only if Syn is built with the `"parsing"` 445 /// feature.* 446 /// 447 /// # Example 448 /// 449 /// ``` 450 /// use syn::{Path, Result, Token}; 451 /// use syn::parse::{Parse, ParseStream}; 452 /// 453 /// // A simplified single `use` statement like: 454 /// // 455 /// // use std::collections::HashMap; 456 /// // 457 /// // Note that generic parameters are not allowed in a `use` statement 458 /// // so the following must not be accepted. 459 /// // 460 /// // use a::<b>::c; 461 /// struct SingleUse { 462 /// use_token: Token![use], 463 /// path: Path, 464 /// } 465 /// 466 /// impl Parse for SingleUse { 467 /// fn parse(input: ParseStream) -> Result<Self> { 468 /// Ok(SingleUse { 469 /// use_token: input.parse()?, 470 /// path: input.call(Path::parse_mod_style)?, 471 /// }) 472 /// } 473 /// } 474 /// ``` 475 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] parse_mod_style(input: ParseStream) -> Result<Self>476 pub fn parse_mod_style(input: ParseStream) -> Result<Self> { 477 Ok(Path { 478 leading_colon: input.parse()?, 479 segments: { 480 let mut segments = Punctuated::new(); 481 loop { 482 if !input.peek(Ident) 483 && !input.peek(Token![super]) 484 && !input.peek(Token![self]) 485 && !input.peek(Token![Self]) 486 && !input.peek(Token![crate]) 487 { 488 break; 489 } 490 let ident = Ident::parse_any(input)?; 491 segments.push_value(PathSegment::from(ident)); 492 if !input.peek(Token![::]) { 493 break; 494 } 495 let punct = input.parse()?; 496 segments.push_punct(punct); 497 } 498 if segments.is_empty() { 499 return Err(input.error("expected path")); 500 } else if segments.trailing_punct() { 501 return Err(input.error("expected path segment")); 502 } 503 segments 504 }, 505 }) 506 } 507 508 /// Determines whether this is a path of length 1 equal to the given 509 /// ident. 510 /// 511 /// For them to compare equal, it must be the case that: 512 /// 513 /// - the path has no leading colon, 514 /// - the number of path segments is 1, 515 /// - the first path segment has no angle bracketed or parenthesized 516 /// path arguments, and 517 /// - the ident of the first path segment is equal to the given one. 518 /// 519 /// *This function is available only if Syn is built with the `"parsing"` 520 /// feature.* 521 /// 522 /// # Example 523 /// 524 /// ``` 525 /// use syn::{Attribute, Error, Meta, NestedMeta, Result}; 526 /// # use std::iter::FromIterator; 527 /// 528 /// fn get_serde_meta_items(attr: &Attribute) -> Result<Vec<NestedMeta>> { 529 /// if attr.path.is_ident("serde") { 530 /// match attr.parse_meta()? { 531 /// Meta::List(meta) => Ok(Vec::from_iter(meta.nested)), 532 /// bad => Err(Error::new_spanned(bad, "unrecognized attribute")), 533 /// } 534 /// } else { 535 /// Ok(Vec::new()) 536 /// } 537 /// } 538 /// ``` 539 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] is_ident<I: ?Sized>(&self, ident: &I) -> bool where Ident: PartialEq<I>,540 pub fn is_ident<I: ?Sized>(&self, ident: &I) -> bool 541 where 542 Ident: PartialEq<I>, 543 { 544 match self.get_ident() { 545 Some(id) => id == ident, 546 None => false, 547 } 548 } 549 550 /// If this path consists of a single ident, returns the ident. 551 /// 552 /// A path is considered an ident if: 553 /// 554 /// - the path has no leading colon, 555 /// - the number of path segments is 1, and 556 /// - the first path segment has no angle bracketed or parenthesized 557 /// path arguments. 558 /// 559 /// *This function is available only if Syn is built with the `"parsing"` 560 /// feature.* 561 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))] get_ident(&self) -> Option<&Ident>562 pub fn get_ident(&self) -> Option<&Ident> { 563 if self.leading_colon.is_none() 564 && self.segments.len() == 1 565 && self.segments[0].arguments.is_none() 566 { 567 Some(&self.segments[0].ident) 568 } else { 569 None 570 } 571 } 572 parse_helper(input: ParseStream, expr_style: bool) -> Result<Self>573 pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> { 574 let mut path = Path { 575 leading_colon: input.parse()?, 576 segments: { 577 let mut segments = Punctuated::new(); 578 let value = PathSegment::parse_helper(input, expr_style)?; 579 segments.push_value(value); 580 segments 581 }, 582 }; 583 Path::parse_rest(input, &mut path, expr_style)?; 584 Ok(path) 585 } 586 parse_rest( input: ParseStream, path: &mut Self, expr_style: bool, ) -> Result<()>587 pub(crate) fn parse_rest( 588 input: ParseStream, 589 path: &mut Self, 590 expr_style: bool, 591 ) -> Result<()> { 592 while input.peek(Token![::]) { 593 let punct: Token![::] = input.parse()?; 594 path.segments.push_punct(punct); 595 let value = PathSegment::parse_helper(input, expr_style)?; 596 path.segments.push_value(value); 597 } 598 Ok(()) 599 } 600 } 601 qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)>602 pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> { 603 if input.peek(Token![<]) { 604 let lt_token: Token![<] = input.parse()?; 605 let this: Type = input.parse()?; 606 let path = if input.peek(Token![as]) { 607 let as_token: Token![as] = input.parse()?; 608 let path: Path = input.parse()?; 609 Some((as_token, path)) 610 } else { 611 None 612 }; 613 let gt_token: Token![>] = input.parse()?; 614 let colon2_token: Token![::] = input.parse()?; 615 let mut rest = Punctuated::new(); 616 loop { 617 let path = PathSegment::parse_helper(input, expr_style)?; 618 rest.push_value(path); 619 if !input.peek(Token![::]) { 620 break; 621 } 622 let punct: Token![::] = input.parse()?; 623 rest.push_punct(punct); 624 } 625 let (position, as_token, path) = match path { 626 Some((as_token, mut path)) => { 627 let pos = path.segments.len(); 628 path.segments.push_punct(colon2_token); 629 path.segments.extend(rest.into_pairs()); 630 (pos, Some(as_token), path) 631 } 632 None => { 633 let path = Path { 634 leading_colon: Some(colon2_token), 635 segments: rest, 636 }; 637 (0, None, path) 638 } 639 }; 640 let qself = QSelf { 641 lt_token, 642 ty: Box::new(this), 643 position, 644 as_token, 645 gt_token, 646 }; 647 Ok((Some(qself), path)) 648 } else { 649 let path = Path::parse_helper(input, expr_style)?; 650 Ok((None, path)) 651 } 652 } 653 } 654 655 #[cfg(feature = "printing")] 656 mod printing { 657 use super::*; 658 use crate::print::TokensOrDefault; 659 use proc_macro2::TokenStream; 660 use quote::ToTokens; 661 use std::cmp; 662 663 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 664 impl ToTokens for Path { to_tokens(&self, tokens: &mut TokenStream)665 fn to_tokens(&self, tokens: &mut TokenStream) { 666 self.leading_colon.to_tokens(tokens); 667 self.segments.to_tokens(tokens); 668 } 669 } 670 671 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 672 impl ToTokens for PathSegment { to_tokens(&self, tokens: &mut TokenStream)673 fn to_tokens(&self, tokens: &mut TokenStream) { 674 self.ident.to_tokens(tokens); 675 self.arguments.to_tokens(tokens); 676 } 677 } 678 679 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 680 impl ToTokens for PathArguments { to_tokens(&self, tokens: &mut TokenStream)681 fn to_tokens(&self, tokens: &mut TokenStream) { 682 match self { 683 PathArguments::None => {} 684 PathArguments::AngleBracketed(arguments) => { 685 arguments.to_tokens(tokens); 686 } 687 PathArguments::Parenthesized(arguments) => { 688 arguments.to_tokens(tokens); 689 } 690 } 691 } 692 } 693 694 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 695 impl ToTokens for GenericArgument { 696 #[allow(clippy::match_same_arms)] to_tokens(&self, tokens: &mut TokenStream)697 fn to_tokens(&self, tokens: &mut TokenStream) { 698 match self { 699 GenericArgument::Lifetime(lt) => lt.to_tokens(tokens), 700 GenericArgument::Type(ty) => ty.to_tokens(tokens), 701 GenericArgument::Binding(tb) => tb.to_tokens(tokens), 702 GenericArgument::Constraint(tc) => tc.to_tokens(tokens), 703 GenericArgument::Const(e) => match *e { 704 Expr::Lit(_) => e.to_tokens(tokens), 705 706 // NOTE: We should probably support parsing blocks with only 707 // expressions in them without the full feature for const 708 // generics. 709 #[cfg(feature = "full")] 710 Expr::Block(_) => e.to_tokens(tokens), 711 712 // ERROR CORRECTION: Add braces to make sure that the 713 // generated code is valid. 714 _ => token::Brace::default().surround(tokens, |tokens| { 715 e.to_tokens(tokens); 716 }), 717 }, 718 } 719 } 720 } 721 722 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 723 impl ToTokens for AngleBracketedGenericArguments { to_tokens(&self, tokens: &mut TokenStream)724 fn to_tokens(&self, tokens: &mut TokenStream) { 725 self.colon2_token.to_tokens(tokens); 726 self.lt_token.to_tokens(tokens); 727 728 // Print lifetimes before types and consts, all before bindings, 729 // regardless of their order in self.args. 730 // 731 // TODO: ordering rules for const arguments vs type arguments have 732 // not been settled yet. https://github.com/rust-lang/rust/issues/44580 733 let mut trailing_or_empty = true; 734 for param in self.args.pairs() { 735 match **param.value() { 736 GenericArgument::Lifetime(_) => { 737 param.to_tokens(tokens); 738 trailing_or_empty = param.punct().is_some(); 739 } 740 GenericArgument::Type(_) 741 | GenericArgument::Binding(_) 742 | GenericArgument::Constraint(_) 743 | GenericArgument::Const(_) => {} 744 } 745 } 746 for param in self.args.pairs() { 747 match **param.value() { 748 GenericArgument::Type(_) | GenericArgument::Const(_) => { 749 if !trailing_or_empty { 750 <Token![,]>::default().to_tokens(tokens); 751 } 752 param.to_tokens(tokens); 753 trailing_or_empty = param.punct().is_some(); 754 } 755 GenericArgument::Lifetime(_) 756 | GenericArgument::Binding(_) 757 | GenericArgument::Constraint(_) => {} 758 } 759 } 760 for param in self.args.pairs() { 761 match **param.value() { 762 GenericArgument::Binding(_) | GenericArgument::Constraint(_) => { 763 if !trailing_or_empty { 764 <Token![,]>::default().to_tokens(tokens); 765 } 766 param.to_tokens(tokens); 767 trailing_or_empty = param.punct().is_some(); 768 } 769 GenericArgument::Lifetime(_) 770 | GenericArgument::Type(_) 771 | GenericArgument::Const(_) => {} 772 } 773 } 774 775 self.gt_token.to_tokens(tokens); 776 } 777 } 778 779 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 780 impl ToTokens for Binding { to_tokens(&self, tokens: &mut TokenStream)781 fn to_tokens(&self, tokens: &mut TokenStream) { 782 self.ident.to_tokens(tokens); 783 self.eq_token.to_tokens(tokens); 784 self.ty.to_tokens(tokens); 785 } 786 } 787 788 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 789 impl ToTokens for Constraint { to_tokens(&self, tokens: &mut TokenStream)790 fn to_tokens(&self, tokens: &mut TokenStream) { 791 self.ident.to_tokens(tokens); 792 self.colon_token.to_tokens(tokens); 793 self.bounds.to_tokens(tokens); 794 } 795 } 796 797 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] 798 impl ToTokens for ParenthesizedGenericArguments { to_tokens(&self, tokens: &mut TokenStream)799 fn to_tokens(&self, tokens: &mut TokenStream) { 800 self.paren_token.surround(tokens, |tokens| { 801 self.inputs.to_tokens(tokens); 802 }); 803 self.output.to_tokens(tokens); 804 } 805 } 806 807 impl private { print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path)808 pub(crate) fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) { 809 let qself = match qself { 810 Some(qself) => qself, 811 None => { 812 path.to_tokens(tokens); 813 return; 814 } 815 }; 816 qself.lt_token.to_tokens(tokens); 817 qself.ty.to_tokens(tokens); 818 819 let pos = cmp::min(qself.position, path.segments.len()); 820 let mut segments = path.segments.pairs(); 821 if pos > 0 { 822 TokensOrDefault(&qself.as_token).to_tokens(tokens); 823 path.leading_colon.to_tokens(tokens); 824 for (i, segment) in segments.by_ref().take(pos).enumerate() { 825 if i + 1 == pos { 826 segment.value().to_tokens(tokens); 827 qself.gt_token.to_tokens(tokens); 828 segment.punct().to_tokens(tokens); 829 } else { 830 segment.to_tokens(tokens); 831 } 832 } 833 } else { 834 qself.gt_token.to_tokens(tokens); 835 path.leading_colon.to_tokens(tokens); 836 } 837 for segment in segments { 838 segment.to_tokens(tokens); 839 } 840 } 841 } 842 } 843