blob: 4872187b61ae00245ed536bba02272ec010d19e0 [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
23impl Path {
24 pub fn global(&self) -> bool {
25 self.leading_colon.is_some()
26 }
27}
28
David Tolnay05658502018-01-07 09:56:37 -080029/// A helper for printing a self-type qualified path as tokens.
30///
31/// ```rust
David Tolnay9b00f652018-09-01 10:31:02 -070032/// # extern crate syn;
33/// # extern crate quote;
34/// # extern crate proc_macro2;
35/// #
Alex Crichtonf0fea9a2018-05-17 11:19:34 -070036/// use proc_macro2::TokenStream;
37/// use quote::ToTokens;
David Tolnay9b00f652018-09-01 10:31:02 -070038/// use syn::{QSelf, Path, PathTokens};
David Tolnay05658502018-01-07 09:56:37 -080039///
40/// struct MyNode {
41/// qself: Option<QSelf>,
42/// path: Path,
43/// }
44///
45/// impl ToTokens for MyNode {
Alex Crichtona74a1c82018-05-16 10:20:44 -070046/// fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay05658502018-01-07 09:56:37 -080047/// PathTokens(&self.qself, &self.path).to_tokens(tokens);
48/// }
49/// }
50/// #
51/// # fn main() {}
52/// ```
David Tolnay461d98e2018-01-07 11:07:19 -080053///
54/// *This type is available if Syn is built with the `"derive"` or `"full"`
55/// feature and the `"printing"` feature.*
David Tolnay056de302018-01-05 14:29:05 -080056#[cfg(feature = "printing")]
57#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
58#[cfg_attr(feature = "clone-impls", derive(Clone))]
59pub struct PathTokens<'a>(pub &'a Option<QSelf>, pub &'a Path);
60
61impl<T> From<T> for Path
62where
63 T: Into<PathSegment>,
64{
65 fn from(segment: T) -> Self {
66 let mut path = Path {
67 leading_colon: None,
68 segments: Punctuated::new(),
69 };
David Tolnay56080682018-01-06 14:01:52 -080070 path.segments.push_value(segment.into());
David Tolnay056de302018-01-05 14:29:05 -080071 path
72 }
73}
74
75ast_struct! {
David Tolnay05658502018-01-07 09:56:37 -080076 /// A segment of a path together with any path arguments on that segment.
David Tolnay461d98e2018-01-07 11:07:19 -080077 ///
78 /// *This type is available if Syn is built with the `"derive"` or `"full"`
79 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -080080 pub struct PathSegment {
David Tolnay056de302018-01-05 14:29:05 -080081 pub ident: Ident,
David Tolnay056de302018-01-05 14:29:05 -080082 pub arguments: PathArguments,
83 }
84}
85
86impl<T> From<T> for PathSegment
87where
88 T: Into<Ident>,
89{
90 fn from(ident: T) -> Self {
91 PathSegment {
92 ident: ident.into(),
93 arguments: PathArguments::None,
94 }
95 }
96}
97
98ast_enum! {
David Tolnayc0435192018-01-07 11:46:08 -080099 /// Angle bracketed or parenthesized arguments of a path segment.
David Tolnay461d98e2018-01-07 11:07:19 -0800100 ///
101 /// *This type is available if Syn is built with the `"derive"` or `"full"`
102 /// feature.*
David Tolnayc0435192018-01-07 11:46:08 -0800103 ///
104 /// ## Angle bracketed
105 ///
106 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
107 ///
108 /// ## Parenthesized
109 ///
110 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
David Tolnay056de302018-01-05 14:29:05 -0800111 pub enum PathArguments {
112 None,
David Tolnaye826d812018-01-06 23:59:39 -0800113 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
David Tolnay056de302018-01-05 14:29:05 -0800114 AngleBracketed(AngleBracketedGenericArguments),
David Tolnayc0435192018-01-07 11:46:08 -0800115 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
David Tolnay056de302018-01-05 14:29:05 -0800116 Parenthesized(ParenthesizedGenericArguments),
117 }
118}
119
120impl Default for PathArguments {
121 fn default() -> Self {
122 PathArguments::None
123 }
124}
125
126impl PathArguments {
127 pub fn is_empty(&self) -> bool {
128 match *self {
129 PathArguments::None => true,
130 PathArguments::AngleBracketed(ref bracketed) => bracketed.args.is_empty(),
131 PathArguments::Parenthesized(_) => false,
132 }
133 }
134}
135
136ast_enum! {
David Tolnaya454c8f2018-01-07 01:01:10 -0800137 /// An individual generic argument, like `'a`, `T`, or `Item = T`.
David Tolnay461d98e2018-01-07 11:07:19 -0800138 ///
139 /// *This type is available if Syn is built with the `"derive"` or `"full"`
140 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800141 pub enum GenericArgument {
David Tolnaye826d812018-01-06 23:59:39 -0800142 /// A lifetime argument.
David Tolnay056de302018-01-05 14:29:05 -0800143 Lifetime(Lifetime),
David Tolnaye826d812018-01-06 23:59:39 -0800144 /// A type argument.
David Tolnay056de302018-01-05 14:29:05 -0800145 Type(Type),
David Tolnayc0435192018-01-07 11:46:08 -0800146 /// A binding (equality constraint) on an associated type: the `Item =
147 /// u8` in `Iterator<Item = u8>`.
David Tolnay056de302018-01-05 14:29:05 -0800148 Binding(Binding),
David Tolnaye826d812018-01-06 23:59:39 -0800149 /// A const expression. Must be inside of a block.
David Tolnay056de302018-01-05 14:29:05 -0800150 ///
151 /// NOTE: Identity expressions are represented as Type arguments, as
152 /// they are indistinguishable syntactically.
153 Const(Expr),
154 }
155}
156
157ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800158 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
159 /// V>`.
David Tolnay461d98e2018-01-07 11:07:19 -0800160 ///
161 /// *This type is available if Syn is built with the `"derive"` or `"full"`
162 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800163 pub struct AngleBracketedGenericArguments {
164 pub colon2_token: Option<Token![::]>,
165 pub lt_token: Token![<],
166 pub args: Punctuated<GenericArgument, Token![,]>,
167 pub gt_token: Token![>],
168 }
169}
170
171ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800172 /// A binding (equality constraint) on an associated type: `Item = u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800173 ///
174 /// *This type is available if Syn is built with the `"derive"` or `"full"`
175 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800176 pub struct Binding {
177 pub ident: Ident,
178 pub eq_token: Token![=],
179 pub ty: Type,
180 }
181}
182
183ast_struct! {
David Tolnayc0435192018-01-07 11:46:08 -0800184 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
185 /// C`.
David Tolnay461d98e2018-01-07 11:07:19 -0800186 ///
187 /// *This type is available if Syn is built with the `"derive"` or `"full"`
188 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800189 pub struct ParenthesizedGenericArguments {
190 pub paren_token: token::Paren,
191 /// `(A, B)`
192 pub inputs: Punctuated<Type, Token![,]>,
193 /// `C`
194 pub output: ReturnType,
195 }
196}
197
198ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800199 /// The explicit Self type in a qualified path: the `T` in `<T as
David Tolnay05658502018-01-07 09:56:37 -0800200 /// Display>::fmt`.
David Tolnaye826d812018-01-06 23:59:39 -0800201 ///
202 /// The actual path, including the trait and the associated item, is stored
203 /// separately. The `position` field represents the index of the associated
David Tolnay056de302018-01-05 14:29:05 -0800204 /// item qualified with this Self type.
205 ///
206 /// ```text
207 /// <Vec<T> as a::b::Trait>::AssociatedItem
208 /// ^~~~~~ ~~~~~~~~~~~~~~^
209 /// ty position = 3
210 ///
211 /// <Vec<T>>::AssociatedItem
212 /// ^~~~~~ ^
213 /// ty position = 0
214 /// ```
David Tolnay461d98e2018-01-07 11:07:19 -0800215 ///
216 /// *This type is available if Syn is built with the `"derive"` or `"full"`
217 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800218 pub struct QSelf {
219 pub lt_token: Token![<],
220 pub ty: Box<Type>,
221 pub position: usize,
222 pub as_token: Option<Token![as]>,
223 pub gt_token: Token![>],
224 }
225}
226
227#[cfg(feature = "parsing")]
228pub mod parsing {
229 use super::*;
David Tolnay94d304f2018-08-30 23:43:53 -0700230
David Tolnay310b3262018-08-30 15:33:00 -0700231 #[cfg(feature = "full")]
232 use expr;
David Tolnay94d304f2018-08-30 23:43:53 -0700233 use ext::IdentExt;
David Tolnay73b7ca12018-08-30 21:05:13 -0700234 use parse::{Parse, ParseStream, Result};
David Tolnay056de302018-01-05 14:29:05 -0800235
David Tolnay4fb71232018-08-25 23:14:50 -0400236 impl Parse for Path {
237 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay60291082018-08-28 09:54:49 -0700238 Self::parse_helper(input, false)
David Tolnay056de302018-01-05 14:29:05 -0800239 }
240 }
241
David Tolnay4fb71232018-08-25 23:14:50 -0400242 impl Parse for GenericArgument {
243 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay66cb0c42018-08-31 09:01:30 -0700244 if input.peek(Lifetime) && !input.peek2(Token![+]) {
David Tolnay4fb71232018-08-25 23:14:50 -0400245 return Ok(GenericArgument::Lifetime(input.parse()?));
246 }
David Tolnay056de302018-01-05 14:29:05 -0800247
David Tolnay4fb71232018-08-25 23:14:50 -0400248 if input.peek(Ident) && input.peek2(Token![=]) {
249 return Ok(GenericArgument::Binding(input.parse()?));
250 }
David Tolnay056de302018-01-05 14:29:05 -0800251
David Tolnay4fb71232018-08-25 23:14:50 -0400252 #[cfg(feature = "full")]
253 {
254 if input.peek(Lit) {
David Tolnay310b3262018-08-30 15:33:00 -0700255 let lit = input.call(expr::parsing::expr_lit)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400256 return Ok(GenericArgument::Const(Expr::Lit(lit)));
257 }
258
259 if input.peek(token::Brace) {
David Tolnay310b3262018-08-30 15:33:00 -0700260 let block = input.call(expr::parsing::expr_block)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400261 return Ok(GenericArgument::Const(Expr::Block(block)));
262 }
263 }
264
David Tolnay8db2d662018-08-30 17:40:59 -0700265 input.parse().map(GenericArgument::Type)
David Tolnay056de302018-01-05 14:29:05 -0800266 }
267 }
268
David Tolnay4fb71232018-08-25 23:14:50 -0400269 impl Parse for AngleBracketedGenericArguments {
270 fn parse(input: ParseStream) -> Result<Self> {
271 Ok(AngleBracketedGenericArguments {
272 colon2_token: input.parse()?,
273 lt_token: input.parse()?,
274 args: {
275 let mut args = Punctuated::new();
276 loop {
277 if input.peek(Token![>]) {
278 break;
279 }
280 let value = input.parse()?;
281 args.push_value(value);
282 if input.peek(Token![>]) {
283 break;
284 }
285 let punct = input.parse()?;
286 args.push_punct(punct);
287 }
288 args
289 },
290 gt_token: input.parse()?,
David Tolnay056de302018-01-05 14:29:05 -0800291 })
David Tolnay056de302018-01-05 14:29:05 -0800292 }
293 }
294
David Tolnay4fb71232018-08-25 23:14:50 -0400295 impl Parse for ParenthesizedGenericArguments {
296 fn parse(input: ParseStream) -> Result<Self> {
297 let content;
298 Ok(ParenthesizedGenericArguments {
299 paren_token: parenthesized!(content in input),
David Tolnayf5ebc192018-08-30 18:23:46 -0700300 inputs: content.parse_terminated(Type::parse)?,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400301 output: input.call(ReturnType::without_plus)?,
David Tolnay056de302018-01-05 14:29:05 -0800302 })
David Tolnay056de302018-01-05 14:29:05 -0800303 }
304 }
305
David Tolnay4fb71232018-08-25 23:14:50 -0400306 impl Parse for PathSegment {
307 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay60291082018-08-28 09:54:49 -0700308 Self::parse_helper(input, false)
309 }
310 }
311
312 impl PathSegment {
313 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
David Tolnay4fb71232018-08-25 23:14:50 -0400314 if input.peek(Token![super])
315 || input.peek(Token![self])
316 || input.peek(Token![Self])
317 || input.peek(Token![crate])
318 || input.peek(Token![extern])
319 {
David Tolnay0dea1b92018-08-30 17:47:29 -0700320 let ident = input.call(Ident::parse_any)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400321 return Ok(PathSegment::from(ident));
322 }
323
324 let ident = input.parse()?;
David Tolnay60291082018-08-28 09:54:49 -0700325 if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
David Tolnay4fb71232018-08-25 23:14:50 -0400326 || input.peek(Token![::]) && input.peek3(Token![<])
327 {
328 Ok(PathSegment {
David Tolnay056de302018-01-05 14:29:05 -0800329 ident: ident,
David Tolnay4fb71232018-08-25 23:14:50 -0400330 arguments: PathArguments::AngleBracketed(input.parse()?),
David Tolnay056de302018-01-05 14:29:05 -0800331 })
David Tolnay4fb71232018-08-25 23:14:50 -0400332 } else {
333 Ok(PathSegment::from(ident))
334 }
David Tolnay056de302018-01-05 14:29:05 -0800335 }
336 }
337
David Tolnay4fb71232018-08-25 23:14:50 -0400338 impl Parse for Binding {
339 fn parse(input: ParseStream) -> Result<Self> {
340 Ok(Binding {
341 ident: input.parse()?,
342 eq_token: input.parse()?,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400343 ty: input.parse()?,
David Tolnay056de302018-01-05 14:29:05 -0800344 })
David Tolnay056de302018-01-05 14:29:05 -0800345 }
346 }
347
348 impl Path {
David Tolnaybbbd5302018-09-01 16:00:42 -0700349 /// Parse a `Path` containing no path arguments on any of its segments.
350 ///
David Tolnay206edfb2018-09-01 16:02:20 -0700351 /// *This function is available if Syn is built with the `"parsing"`
352 /// feature.*
353 ///
David Tolnaybbbd5302018-09-01 16:00:42 -0700354 /// # Example
355 ///
356 /// ```
357 /// # extern crate syn;
358 /// #
359 /// use syn::{Path, Token};
360 /// use syn::parse::{Parse, ParseStream, Result};
361 ///
362 /// // A simplified single `use` statement like:
363 /// //
364 /// // use std::collections::HashMap;
365 /// //
366 /// // Note that generic parameters are not allowed in a `use` statement
367 /// // so the following must not be accepted.
368 /// //
369 /// // use a::<b>::c;
370 /// struct SingleUse {
371 /// use_token: Token![use],
372 /// path: Path,
373 /// }
374 ///
375 /// impl Parse for SingleUse {
376 /// fn parse(input: ParseStream) -> Result<Self> {
377 /// Ok(SingleUse {
378 /// use_token: input.parse()?,
379 /// path: input.call(Path::parse_mod_style)?,
380 /// })
381 /// }
382 /// }
383 /// #
384 /// # fn main() {}
385 /// ```
David Tolnaya7d69fc2018-08-26 13:30:24 -0400386 pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
387 Ok(Path {
388 leading_colon: input.parse()?,
389 segments: {
390 let mut segments = Punctuated::new();
391 loop {
392 if !input.peek(Ident)
393 && !input.peek(Token![super])
394 && !input.peek(Token![self])
395 && !input.peek(Token![Self])
396 && !input.peek(Token![crate])
397 && !input.peek(Token![extern])
398 {
399 break;
400 }
David Tolnay0dea1b92018-08-30 17:47:29 -0700401 let ident = Ident::parse_any(input)?;
David Tolnaya7d69fc2018-08-26 13:30:24 -0400402 segments.push_value(PathSegment::from(ident));
403 if !input.peek(Token![::]) {
404 break;
405 }
406 let punct = input.parse()?;
407 segments.push_punct(punct);
408 }
409 if segments.is_empty() {
410 return Err(input.error("expected path"));
411 } else if segments.trailing_punct() {
412 return Err(input.error("expected path segment"));
413 }
414 segments
415 },
416 })
417 }
418
David Tolnay60291082018-08-28 09:54:49 -0700419 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
420 if input.peek(Token![dyn]) {
421 return Err(input.error("expected path"));
422 }
423
424 Ok(Path {
425 leading_colon: input.parse()?,
426 segments: {
427 let mut segments = Punctuated::new();
428 let value = PathSegment::parse_helper(input, expr_style)?;
429 segments.push_value(value);
430 while input.peek(Token![::]) {
431 let punct: Token![::] = input.parse()?;
432 segments.push_punct(punct);
433 let value = PathSegment::parse_helper(input, expr_style)?;
434 segments.push_value(value);
435 }
436 segments
437 },
438 })
439 }
David Tolnay056de302018-01-05 14:29:05 -0800440 }
441
David Tolnay60291082018-08-28 09:54:49 -0700442 pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
443 if input.peek(Token![<]) {
444 let lt_token: Token![<] = input.parse()?;
445 let this: Type = input.parse()?;
446 let path = if input.peek(Token![as]) {
447 let as_token: Token![as] = input.parse()?;
448 let path: Path = input.parse()?;
449 Some((as_token, path))
450 } else {
451 None
452 };
453 let gt_token: Token![>] = input.parse()?;
454 let colon2_token: Token![::] = input.parse()?;
455 let mut rest = Punctuated::new();
456 loop {
457 let path = PathSegment::parse_helper(input, expr_style)?;
458 rest.push_value(path);
459 if !input.peek(Token![::]) {
460 break;
461 }
462 let punct: Token![::] = input.parse()?;
463 rest.push_punct(punct);
464 }
465 let (position, as_token, path) = match path {
466 Some((as_token, mut path)) => {
467 let pos = path.segments.len();
468 path.segments.push_punct(colon2_token);
469 path.segments.extend(rest.into_pairs());
470 (pos, Some(as_token), path)
471 }
472 None => {
473 let path = Path {
474 leading_colon: Some(colon2_token),
475 segments: rest,
476 };
477 (0, None, path)
478 }
479 };
480 let qself = QSelf {
481 lt_token: lt_token,
482 ty: Box::new(this),
483 position: position,
484 as_token: as_token,
485 gt_token: gt_token,
486 };
487 Ok((Some(qself), path))
488 } else {
489 let path = Path::parse_helper(input, expr_style)?;
490 Ok((None, path))
491 }
492 }
David Tolnay056de302018-01-05 14:29:05 -0800493}
494
495#[cfg(feature = "printing")]
496mod printing {
497 use super::*;
David Tolnay64023912018-08-31 09:51:12 -0700498
Alex Crichtona74a1c82018-05-16 10:20:44 -0700499 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700500 use quote::ToTokens;
David Tolnay056de302018-01-05 14:29:05 -0800501
David Tolnay64023912018-08-31 09:51:12 -0700502 use print::TokensOrDefault;
503
David Tolnay056de302018-01-05 14:29:05 -0800504 impl ToTokens for Path {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700505 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800506 self.leading_colon.to_tokens(tokens);
507 self.segments.to_tokens(tokens);
508 }
509 }
510
511 impl ToTokens for PathSegment {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700512 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800513 self.ident.to_tokens(tokens);
514 self.arguments.to_tokens(tokens);
515 }
516 }
517
518 impl ToTokens for PathArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700519 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800520 match *self {
521 PathArguments::None => {}
522 PathArguments::AngleBracketed(ref arguments) => {
523 arguments.to_tokens(tokens);
524 }
525 PathArguments::Parenthesized(ref arguments) => {
526 arguments.to_tokens(tokens);
527 }
528 }
529 }
530 }
531
532 impl ToTokens for GenericArgument {
533 #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
Alex Crichtona74a1c82018-05-16 10:20:44 -0700534 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800535 match *self {
536 GenericArgument::Lifetime(ref lt) => lt.to_tokens(tokens),
537 GenericArgument::Type(ref ty) => ty.to_tokens(tokens),
538 GenericArgument::Binding(ref tb) => tb.to_tokens(tokens),
539 GenericArgument::Const(ref e) => match *e {
540 Expr::Lit(_) => e.to_tokens(tokens),
541
542 // NOTE: We should probably support parsing blocks with only
543 // expressions in them without the full feature for const
544 // generics.
545 #[cfg(feature = "full")]
546 Expr::Block(_) => e.to_tokens(tokens),
547
548 // ERROR CORRECTION: Add braces to make sure that the
549 // generated code is valid.
550 _ => token::Brace::default().surround(tokens, |tokens| {
551 e.to_tokens(tokens);
552 }),
553 },
554 }
555 }
556 }
557
558 impl ToTokens for AngleBracketedGenericArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700559 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800560 self.colon2_token.to_tokens(tokens);
561 self.lt_token.to_tokens(tokens);
David Tolnay298570b2018-01-11 16:38:36 -0800562
563 // Print lifetimes before types and consts, all before bindings,
564 // regardless of their order in self.args.
565 //
566 // TODO: ordering rules for const arguments vs type arguments have
567 // not been settled yet. https://github.com/rust-lang/rust/issues/44580
568 let mut trailing_or_empty = true;
569 for param in self.args.pairs() {
570 if let GenericArgument::Lifetime(_) = **param.value() {
571 param.to_tokens(tokens);
572 trailing_or_empty = param.punct().is_some();
573 }
574 }
575 for param in self.args.pairs() {
576 match **param.value() {
577 GenericArgument::Type(_) | GenericArgument::Const(_) => {
578 if !trailing_or_empty {
579 <Token![,]>::default().to_tokens(tokens);
580 }
581 param.to_tokens(tokens);
582 trailing_or_empty = param.punct().is_some();
583 }
584 GenericArgument::Lifetime(_) | GenericArgument::Binding(_) => {}
585 }
586 }
587 for param in self.args.pairs() {
588 if let GenericArgument::Binding(_) = **param.value() {
589 if !trailing_or_empty {
590 <Token![,]>::default().to_tokens(tokens);
591 trailing_or_empty = true;
592 }
593 param.to_tokens(tokens);
594 }
595 }
596
David Tolnay056de302018-01-05 14:29:05 -0800597 self.gt_token.to_tokens(tokens);
598 }
599 }
600
601 impl ToTokens for Binding {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700602 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800603 self.ident.to_tokens(tokens);
604 self.eq_token.to_tokens(tokens);
605 self.ty.to_tokens(tokens);
606 }
607 }
608
609 impl ToTokens for ParenthesizedGenericArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700610 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800611 self.paren_token.surround(tokens, |tokens| {
612 self.inputs.to_tokens(tokens);
613 });
614 self.output.to_tokens(tokens);
615 }
616 }
David Tolnay05658502018-01-07 09:56:37 -0800617
618 impl<'a> ToTokens for PathTokens<'a> {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700619 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay05658502018-01-07 09:56:37 -0800620 let qself = match *self.0 {
621 Some(ref qself) => qself,
622 None => return self.1.to_tokens(tokens),
623 };
624 qself.lt_token.to_tokens(tokens);
625 qself.ty.to_tokens(tokens);
626
David Tolnay05658502018-01-07 09:56:37 -0800627 let pos = if qself.position > 0 && qself.position >= self.1.segments.len() {
628 self.1.segments.len() - 1
629 } else {
630 qself.position
631 };
632 let mut segments = self.1.segments.pairs();
633 if pos > 0 {
634 TokensOrDefault(&qself.as_token).to_tokens(tokens);
635 self.1.leading_colon.to_tokens(tokens);
636 for (i, segment) in segments.by_ref().take(pos).enumerate() {
637 if i + 1 == pos {
638 segment.value().to_tokens(tokens);
639 qself.gt_token.to_tokens(tokens);
640 segment.punct().to_tokens(tokens);
641 } else {
642 segment.to_tokens(tokens);
643 }
644 }
645 } else {
646 qself.gt_token.to_tokens(tokens);
647 self.1.leading_colon.to_tokens(tokens);
648 }
649 for segment in segments {
650 segment.to_tokens(tokens);
651 }
652 }
653 }
David Tolnay056de302018-01-05 14:29:05 -0800654}