blob: 9b4b9ffde88fb3d831df8d0cef788df2667ec797 [file] [log] [blame]
David Tolnay55535012018-01-05 16:39:23 -08001// Copyright 2018 Syn Developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
David Tolnay056de302018-01-05 14:29:05 -08009use super::*;
David Tolnay94d2b792018-04-29 12:26:10 -070010use punctuated::Punctuated;
David Tolnay056de302018-01-05 14:29:05 -080011
12ast_struct! {
David Tolnay05658502018-01-07 09:56:37 -080013 /// A path at which a named item is exported: `std::collections::HashMap`.
David Tolnay461d98e2018-01-07 11:07:19 -080014 ///
15 /// *This type is available if Syn is built with the `"derive"` or `"full"`
16 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -080017 pub struct Path {
David Tolnay056de302018-01-05 14:29:05 -080018 pub leading_colon: Option<Token![::]>,
David Tolnay056de302018-01-05 14:29:05 -080019 pub segments: Punctuated<PathSegment, Token![::]>,
20 }
21}
22
David Tolnay05658502018-01-07 09:56:37 -080023/// A helper for printing a self-type qualified path as tokens.
24///
25/// ```rust
David Tolnay9b00f652018-09-01 10:31:02 -070026/// # extern crate syn;
27/// # extern crate quote;
28/// # extern crate proc_macro2;
29/// #
Alex Crichtonf0fea9a2018-05-17 11:19:34 -070030/// use proc_macro2::TokenStream;
31/// use quote::ToTokens;
David Tolnay9b00f652018-09-01 10:31:02 -070032/// use syn::{QSelf, Path, PathTokens};
David Tolnay05658502018-01-07 09:56:37 -080033///
34/// struct MyNode {
35/// qself: Option<QSelf>,
36/// path: Path,
37/// }
38///
39/// impl ToTokens for MyNode {
Alex Crichtona74a1c82018-05-16 10:20:44 -070040/// fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay05658502018-01-07 09:56:37 -080041/// PathTokens(&self.qself, &self.path).to_tokens(tokens);
42/// }
43/// }
44/// #
45/// # fn main() {}
46/// ```
David Tolnay461d98e2018-01-07 11:07:19 -080047///
48/// *This type is available if Syn is built with the `"derive"` or `"full"`
49/// feature and the `"printing"` feature.*
David Tolnay056de302018-01-05 14:29:05 -080050#[cfg(feature = "printing")]
51#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
52#[cfg_attr(feature = "clone-impls", derive(Clone))]
53pub struct PathTokens<'a>(pub &'a Option<QSelf>, pub &'a Path);
54
55impl<T> From<T> for Path
56where
57 T: Into<PathSegment>,
58{
59 fn from(segment: T) -> Self {
60 let mut path = Path {
61 leading_colon: None,
62 segments: Punctuated::new(),
63 };
David Tolnay56080682018-01-06 14:01:52 -080064 path.segments.push_value(segment.into());
David Tolnay056de302018-01-05 14:29:05 -080065 path
66 }
67}
68
69ast_struct! {
David Tolnay05658502018-01-07 09:56:37 -080070 /// A segment of a path together with any path arguments on that segment.
David Tolnay461d98e2018-01-07 11:07:19 -080071 ///
72 /// *This type is available if Syn is built with the `"derive"` or `"full"`
73 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -080074 pub struct PathSegment {
David Tolnay056de302018-01-05 14:29:05 -080075 pub ident: Ident,
David Tolnay056de302018-01-05 14:29:05 -080076 pub arguments: PathArguments,
77 }
78}
79
80impl<T> From<T> for PathSegment
81where
82 T: Into<Ident>,
83{
84 fn from(ident: T) -> Self {
85 PathSegment {
86 ident: ident.into(),
87 arguments: PathArguments::None,
88 }
89 }
90}
91
92ast_enum! {
David Tolnayc0435192018-01-07 11:46:08 -080093 /// Angle bracketed or parenthesized arguments of a path segment.
David Tolnay461d98e2018-01-07 11:07:19 -080094 ///
95 /// *This type is available if Syn is built with the `"derive"` or `"full"`
96 /// feature.*
David Tolnayc0435192018-01-07 11:46:08 -080097 ///
98 /// ## Angle bracketed
99 ///
100 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
101 ///
102 /// ## Parenthesized
103 ///
104 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
David Tolnay056de302018-01-05 14:29:05 -0800105 pub enum PathArguments {
106 None,
David Tolnaye826d812018-01-06 23:59:39 -0800107 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
David Tolnay056de302018-01-05 14:29:05 -0800108 AngleBracketed(AngleBracketedGenericArguments),
David Tolnayc0435192018-01-07 11:46:08 -0800109 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
David Tolnay056de302018-01-05 14:29:05 -0800110 Parenthesized(ParenthesizedGenericArguments),
111 }
112}
113
114impl Default for PathArguments {
115 fn default() -> Self {
116 PathArguments::None
117 }
118}
119
120impl PathArguments {
121 pub fn is_empty(&self) -> bool {
122 match *self {
123 PathArguments::None => true,
124 PathArguments::AngleBracketed(ref bracketed) => bracketed.args.is_empty(),
125 PathArguments::Parenthesized(_) => false,
126 }
127 }
128}
129
130ast_enum! {
David Tolnaya454c8f2018-01-07 01:01:10 -0800131 /// An individual generic argument, like `'a`, `T`, or `Item = T`.
David Tolnay461d98e2018-01-07 11:07:19 -0800132 ///
133 /// *This type is available if Syn is built with the `"derive"` or `"full"`
134 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800135 pub enum GenericArgument {
David Tolnaye826d812018-01-06 23:59:39 -0800136 /// A lifetime argument.
David Tolnay056de302018-01-05 14:29:05 -0800137 Lifetime(Lifetime),
David Tolnaye826d812018-01-06 23:59:39 -0800138 /// A type argument.
David Tolnay056de302018-01-05 14:29:05 -0800139 Type(Type),
David Tolnayc0435192018-01-07 11:46:08 -0800140 /// A binding (equality constraint) on an associated type: the `Item =
141 /// u8` in `Iterator<Item = u8>`.
David Tolnay056de302018-01-05 14:29:05 -0800142 Binding(Binding),
David Tolnaye826d812018-01-06 23:59:39 -0800143 /// A const expression. Must be inside of a block.
David Tolnay056de302018-01-05 14:29:05 -0800144 ///
145 /// NOTE: Identity expressions are represented as Type arguments, as
146 /// they are indistinguishable syntactically.
147 Const(Expr),
148 }
149}
150
151ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800152 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
153 /// V>`.
David Tolnay461d98e2018-01-07 11:07:19 -0800154 ///
155 /// *This type is available if Syn is built with the `"derive"` or `"full"`
156 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800157 pub struct AngleBracketedGenericArguments {
158 pub colon2_token: Option<Token![::]>,
159 pub lt_token: Token![<],
160 pub args: Punctuated<GenericArgument, Token![,]>,
161 pub gt_token: Token![>],
162 }
163}
164
165ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800166 /// A binding (equality constraint) on an associated type: `Item = u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800167 ///
168 /// *This type is available if Syn is built with the `"derive"` or `"full"`
169 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800170 pub struct Binding {
171 pub ident: Ident,
172 pub eq_token: Token![=],
173 pub ty: Type,
174 }
175}
176
177ast_struct! {
David Tolnayc0435192018-01-07 11:46:08 -0800178 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
179 /// C`.
David Tolnay461d98e2018-01-07 11:07:19 -0800180 ///
181 /// *This type is available if Syn is built with the `"derive"` or `"full"`
182 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800183 pub struct ParenthesizedGenericArguments {
184 pub paren_token: token::Paren,
185 /// `(A, B)`
186 pub inputs: Punctuated<Type, Token![,]>,
187 /// `C`
188 pub output: ReturnType,
189 }
190}
191
192ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800193 /// The explicit Self type in a qualified path: the `T` in `<T as
David Tolnay05658502018-01-07 09:56:37 -0800194 /// Display>::fmt`.
David Tolnaye826d812018-01-06 23:59:39 -0800195 ///
196 /// The actual path, including the trait and the associated item, is stored
197 /// separately. The `position` field represents the index of the associated
David Tolnay056de302018-01-05 14:29:05 -0800198 /// item qualified with this Self type.
199 ///
200 /// ```text
201 /// <Vec<T> as a::b::Trait>::AssociatedItem
202 /// ^~~~~~ ~~~~~~~~~~~~~~^
203 /// ty position = 3
204 ///
205 /// <Vec<T>>::AssociatedItem
206 /// ^~~~~~ ^
207 /// ty position = 0
208 /// ```
David Tolnay461d98e2018-01-07 11:07:19 -0800209 ///
210 /// *This type is available if Syn is built with the `"derive"` or `"full"`
211 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800212 pub struct QSelf {
213 pub lt_token: Token![<],
214 pub ty: Box<Type>,
215 pub position: usize,
216 pub as_token: Option<Token![as]>,
217 pub gt_token: Token![>],
218 }
219}
220
221#[cfg(feature = "parsing")]
222pub mod parsing {
223 use super::*;
David Tolnay94d304f2018-08-30 23:43:53 -0700224
David Tolnay310b3262018-08-30 15:33:00 -0700225 #[cfg(feature = "full")]
226 use expr;
David Tolnay94d304f2018-08-30 23:43:53 -0700227 use ext::IdentExt;
David Tolnay73b7ca12018-08-30 21:05:13 -0700228 use parse::{Parse, ParseStream, Result};
David Tolnay056de302018-01-05 14:29:05 -0800229
David Tolnay4fb71232018-08-25 23:14:50 -0400230 impl Parse for Path {
231 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay60291082018-08-28 09:54:49 -0700232 Self::parse_helper(input, false)
David Tolnay056de302018-01-05 14:29:05 -0800233 }
234 }
235
David Tolnay4fb71232018-08-25 23:14:50 -0400236 impl Parse for GenericArgument {
237 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay66cb0c42018-08-31 09:01:30 -0700238 if input.peek(Lifetime) && !input.peek2(Token![+]) {
David Tolnay4fb71232018-08-25 23:14:50 -0400239 return Ok(GenericArgument::Lifetime(input.parse()?));
240 }
David Tolnay056de302018-01-05 14:29:05 -0800241
David Tolnay4fb71232018-08-25 23:14:50 -0400242 if input.peek(Ident) && input.peek2(Token![=]) {
243 return Ok(GenericArgument::Binding(input.parse()?));
244 }
David Tolnay056de302018-01-05 14:29:05 -0800245
David Tolnay4fb71232018-08-25 23:14:50 -0400246 #[cfg(feature = "full")]
247 {
248 if input.peek(Lit) {
David Tolnay310b3262018-08-30 15:33:00 -0700249 let lit = input.call(expr::parsing::expr_lit)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400250 return Ok(GenericArgument::Const(Expr::Lit(lit)));
251 }
252
253 if input.peek(token::Brace) {
David Tolnay310b3262018-08-30 15:33:00 -0700254 let block = input.call(expr::parsing::expr_block)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400255 return Ok(GenericArgument::Const(Expr::Block(block)));
256 }
257 }
258
David Tolnay8db2d662018-08-30 17:40:59 -0700259 input.parse().map(GenericArgument::Type)
David Tolnay056de302018-01-05 14:29:05 -0800260 }
261 }
262
David Tolnay4fb71232018-08-25 23:14:50 -0400263 impl Parse for AngleBracketedGenericArguments {
264 fn parse(input: ParseStream) -> Result<Self> {
265 Ok(AngleBracketedGenericArguments {
266 colon2_token: input.parse()?,
267 lt_token: input.parse()?,
268 args: {
269 let mut args = Punctuated::new();
270 loop {
271 if input.peek(Token![>]) {
272 break;
273 }
274 let value = input.parse()?;
275 args.push_value(value);
276 if input.peek(Token![>]) {
277 break;
278 }
279 let punct = input.parse()?;
280 args.push_punct(punct);
281 }
282 args
283 },
284 gt_token: input.parse()?,
David Tolnay056de302018-01-05 14:29:05 -0800285 })
David Tolnay056de302018-01-05 14:29:05 -0800286 }
287 }
288
David Tolnay4fb71232018-08-25 23:14:50 -0400289 impl Parse for ParenthesizedGenericArguments {
290 fn parse(input: ParseStream) -> Result<Self> {
291 let content;
292 Ok(ParenthesizedGenericArguments {
293 paren_token: parenthesized!(content in input),
David Tolnayf5ebc192018-08-30 18:23:46 -0700294 inputs: content.parse_terminated(Type::parse)?,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400295 output: input.call(ReturnType::without_plus)?,
David Tolnay056de302018-01-05 14:29:05 -0800296 })
David Tolnay056de302018-01-05 14:29:05 -0800297 }
298 }
299
David Tolnay4fb71232018-08-25 23:14:50 -0400300 impl Parse for PathSegment {
301 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay60291082018-08-28 09:54:49 -0700302 Self::parse_helper(input, false)
303 }
304 }
305
306 impl PathSegment {
307 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
David Tolnay4fb71232018-08-25 23:14:50 -0400308 if input.peek(Token![super])
309 || input.peek(Token![self])
310 || input.peek(Token![Self])
311 || input.peek(Token![crate])
312 || input.peek(Token![extern])
313 {
David Tolnay0dea1b92018-08-30 17:47:29 -0700314 let ident = input.call(Ident::parse_any)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400315 return Ok(PathSegment::from(ident));
316 }
317
318 let ident = input.parse()?;
David Tolnay60291082018-08-28 09:54:49 -0700319 if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
David Tolnay4fb71232018-08-25 23:14:50 -0400320 || input.peek(Token![::]) && input.peek3(Token![<])
321 {
322 Ok(PathSegment {
David Tolnay056de302018-01-05 14:29:05 -0800323 ident: ident,
David Tolnay4fb71232018-08-25 23:14:50 -0400324 arguments: PathArguments::AngleBracketed(input.parse()?),
David Tolnay056de302018-01-05 14:29:05 -0800325 })
David Tolnay4fb71232018-08-25 23:14:50 -0400326 } else {
327 Ok(PathSegment::from(ident))
328 }
David Tolnay056de302018-01-05 14:29:05 -0800329 }
330 }
331
David Tolnay4fb71232018-08-25 23:14:50 -0400332 impl Parse for Binding {
333 fn parse(input: ParseStream) -> Result<Self> {
334 Ok(Binding {
335 ident: input.parse()?,
336 eq_token: input.parse()?,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400337 ty: input.parse()?,
David Tolnay056de302018-01-05 14:29:05 -0800338 })
David Tolnay056de302018-01-05 14:29:05 -0800339 }
340 }
341
342 impl Path {
David Tolnaybbbd5302018-09-01 16:00:42 -0700343 /// Parse a `Path` containing no path arguments on any of its segments.
344 ///
David Tolnay206edfb2018-09-01 16:02:20 -0700345 /// *This function is available if Syn is built with the `"parsing"`
346 /// feature.*
347 ///
David Tolnaybbbd5302018-09-01 16:00:42 -0700348 /// # Example
349 ///
350 /// ```
351 /// # extern crate syn;
352 /// #
353 /// use syn::{Path, Token};
354 /// use syn::parse::{Parse, ParseStream, Result};
355 ///
356 /// // A simplified single `use` statement like:
357 /// //
358 /// // use std::collections::HashMap;
359 /// //
360 /// // Note that generic parameters are not allowed in a `use` statement
361 /// // so the following must not be accepted.
362 /// //
363 /// // use a::<b>::c;
364 /// struct SingleUse {
365 /// use_token: Token![use],
366 /// path: Path,
367 /// }
368 ///
369 /// impl Parse for SingleUse {
370 /// fn parse(input: ParseStream) -> Result<Self> {
371 /// Ok(SingleUse {
372 /// use_token: input.parse()?,
373 /// path: input.call(Path::parse_mod_style)?,
374 /// })
375 /// }
376 /// }
377 /// #
378 /// # fn main() {}
379 /// ```
David Tolnaya7d69fc2018-08-26 13:30:24 -0400380 pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
381 Ok(Path {
382 leading_colon: input.parse()?,
383 segments: {
384 let mut segments = Punctuated::new();
385 loop {
386 if !input.peek(Ident)
387 && !input.peek(Token![super])
388 && !input.peek(Token![self])
389 && !input.peek(Token![Self])
390 && !input.peek(Token![crate])
391 && !input.peek(Token![extern])
392 {
393 break;
394 }
David Tolnay0dea1b92018-08-30 17:47:29 -0700395 let ident = Ident::parse_any(input)?;
David Tolnaya7d69fc2018-08-26 13:30:24 -0400396 segments.push_value(PathSegment::from(ident));
397 if !input.peek(Token![::]) {
398 break;
399 }
400 let punct = input.parse()?;
401 segments.push_punct(punct);
402 }
403 if segments.is_empty() {
404 return Err(input.error("expected path"));
405 } else if segments.trailing_punct() {
406 return Err(input.error("expected path segment"));
407 }
408 segments
409 },
410 })
411 }
412
David Tolnay60291082018-08-28 09:54:49 -0700413 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
414 if input.peek(Token![dyn]) {
415 return Err(input.error("expected path"));
416 }
417
418 Ok(Path {
419 leading_colon: input.parse()?,
420 segments: {
421 let mut segments = Punctuated::new();
422 let value = PathSegment::parse_helper(input, expr_style)?;
423 segments.push_value(value);
424 while input.peek(Token![::]) {
425 let punct: Token![::] = input.parse()?;
426 segments.push_punct(punct);
427 let value = PathSegment::parse_helper(input, expr_style)?;
428 segments.push_value(value);
429 }
430 segments
431 },
432 })
433 }
David Tolnay056de302018-01-05 14:29:05 -0800434 }
435
David Tolnay60291082018-08-28 09:54:49 -0700436 pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
437 if input.peek(Token![<]) {
438 let lt_token: Token![<] = input.parse()?;
439 let this: Type = input.parse()?;
440 let path = if input.peek(Token![as]) {
441 let as_token: Token![as] = input.parse()?;
442 let path: Path = input.parse()?;
443 Some((as_token, path))
444 } else {
445 None
446 };
447 let gt_token: Token![>] = input.parse()?;
448 let colon2_token: Token![::] = input.parse()?;
449 let mut rest = Punctuated::new();
450 loop {
451 let path = PathSegment::parse_helper(input, expr_style)?;
452 rest.push_value(path);
453 if !input.peek(Token![::]) {
454 break;
455 }
456 let punct: Token![::] = input.parse()?;
457 rest.push_punct(punct);
458 }
459 let (position, as_token, path) = match path {
460 Some((as_token, mut path)) => {
461 let pos = path.segments.len();
462 path.segments.push_punct(colon2_token);
463 path.segments.extend(rest.into_pairs());
464 (pos, Some(as_token), path)
465 }
466 None => {
467 let path = Path {
468 leading_colon: Some(colon2_token),
469 segments: rest,
470 };
471 (0, None, path)
472 }
473 };
474 let qself = QSelf {
475 lt_token: lt_token,
476 ty: Box::new(this),
477 position: position,
478 as_token: as_token,
479 gt_token: gt_token,
480 };
481 Ok((Some(qself), path))
482 } else {
483 let path = Path::parse_helper(input, expr_style)?;
484 Ok((None, path))
485 }
486 }
David Tolnay056de302018-01-05 14:29:05 -0800487}
488
489#[cfg(feature = "printing")]
490mod printing {
491 use super::*;
David Tolnay64023912018-08-31 09:51:12 -0700492
Alex Crichtona74a1c82018-05-16 10:20:44 -0700493 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700494 use quote::ToTokens;
David Tolnay056de302018-01-05 14:29:05 -0800495
David Tolnay64023912018-08-31 09:51:12 -0700496 use print::TokensOrDefault;
497
David Tolnay056de302018-01-05 14:29:05 -0800498 impl ToTokens for Path {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700499 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800500 self.leading_colon.to_tokens(tokens);
501 self.segments.to_tokens(tokens);
502 }
503 }
504
505 impl ToTokens for PathSegment {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700506 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800507 self.ident.to_tokens(tokens);
508 self.arguments.to_tokens(tokens);
509 }
510 }
511
512 impl ToTokens for PathArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700513 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800514 match *self {
515 PathArguments::None => {}
516 PathArguments::AngleBracketed(ref arguments) => {
517 arguments.to_tokens(tokens);
518 }
519 PathArguments::Parenthesized(ref arguments) => {
520 arguments.to_tokens(tokens);
521 }
522 }
523 }
524 }
525
526 impl ToTokens for GenericArgument {
527 #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
Alex Crichtona74a1c82018-05-16 10:20:44 -0700528 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800529 match *self {
530 GenericArgument::Lifetime(ref lt) => lt.to_tokens(tokens),
531 GenericArgument::Type(ref ty) => ty.to_tokens(tokens),
532 GenericArgument::Binding(ref tb) => tb.to_tokens(tokens),
533 GenericArgument::Const(ref e) => match *e {
534 Expr::Lit(_) => e.to_tokens(tokens),
535
536 // NOTE: We should probably support parsing blocks with only
537 // expressions in them without the full feature for const
538 // generics.
539 #[cfg(feature = "full")]
540 Expr::Block(_) => e.to_tokens(tokens),
541
542 // ERROR CORRECTION: Add braces to make sure that the
543 // generated code is valid.
544 _ => token::Brace::default().surround(tokens, |tokens| {
545 e.to_tokens(tokens);
546 }),
547 },
548 }
549 }
550 }
551
552 impl ToTokens for AngleBracketedGenericArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700553 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800554 self.colon2_token.to_tokens(tokens);
555 self.lt_token.to_tokens(tokens);
David Tolnay298570b2018-01-11 16:38:36 -0800556
557 // Print lifetimes before types and consts, all before bindings,
558 // regardless of their order in self.args.
559 //
560 // TODO: ordering rules for const arguments vs type arguments have
561 // not been settled yet. https://github.com/rust-lang/rust/issues/44580
562 let mut trailing_or_empty = true;
563 for param in self.args.pairs() {
564 if let GenericArgument::Lifetime(_) = **param.value() {
565 param.to_tokens(tokens);
566 trailing_or_empty = param.punct().is_some();
567 }
568 }
569 for param in self.args.pairs() {
570 match **param.value() {
571 GenericArgument::Type(_) | GenericArgument::Const(_) => {
572 if !trailing_or_empty {
573 <Token![,]>::default().to_tokens(tokens);
574 }
575 param.to_tokens(tokens);
576 trailing_or_empty = param.punct().is_some();
577 }
578 GenericArgument::Lifetime(_) | GenericArgument::Binding(_) => {}
579 }
580 }
581 for param in self.args.pairs() {
582 if let GenericArgument::Binding(_) = **param.value() {
583 if !trailing_or_empty {
584 <Token![,]>::default().to_tokens(tokens);
585 trailing_or_empty = true;
586 }
587 param.to_tokens(tokens);
588 }
589 }
590
David Tolnay056de302018-01-05 14:29:05 -0800591 self.gt_token.to_tokens(tokens);
592 }
593 }
594
595 impl ToTokens for Binding {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700596 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800597 self.ident.to_tokens(tokens);
598 self.eq_token.to_tokens(tokens);
599 self.ty.to_tokens(tokens);
600 }
601 }
602
603 impl ToTokens for ParenthesizedGenericArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700604 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800605 self.paren_token.surround(tokens, |tokens| {
606 self.inputs.to_tokens(tokens);
607 });
608 self.output.to_tokens(tokens);
609 }
610 }
David Tolnay05658502018-01-07 09:56:37 -0800611
612 impl<'a> ToTokens for PathTokens<'a> {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700613 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay05658502018-01-07 09:56:37 -0800614 let qself = match *self.0 {
615 Some(ref qself) => qself,
616 None => return self.1.to_tokens(tokens),
617 };
618 qself.lt_token.to_tokens(tokens);
619 qself.ty.to_tokens(tokens);
620
David Tolnay05658502018-01-07 09:56:37 -0800621 let pos = if qself.position > 0 && qself.position >= self.1.segments.len() {
622 self.1.segments.len() - 1
623 } else {
624 qself.position
625 };
626 let mut segments = self.1.segments.pairs();
627 if pos > 0 {
628 TokensOrDefault(&qself.as_token).to_tokens(tokens);
629 self.1.leading_colon.to_tokens(tokens);
630 for (i, segment) in segments.by_ref().take(pos).enumerate() {
631 if i + 1 == pos {
632 segment.value().to_tokens(tokens);
633 qself.gt_token.to_tokens(tokens);
634 segment.punct().to_tokens(tokens);
635 } else {
636 segment.to_tokens(tokens);
637 }
638 }
639 } else {
640 qself.gt_token.to_tokens(tokens);
641 self.1.leading_colon.to_tokens(tokens);
642 }
643 for segment in segments {
644 segment.to_tokens(tokens);
645 }
646 }
647 }
David Tolnay056de302018-01-05 14:29:05 -0800648}