blob: 443bac6953bb8cb33dcaa30eb92f6df11158fc23 [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 Tolnay056de302018-01-05 14:29:05 -080023impl<T> From<T> for Path
24where
25 T: Into<PathSegment>,
26{
27 fn from(segment: T) -> Self {
28 let mut path = Path {
29 leading_colon: None,
30 segments: Punctuated::new(),
31 };
David Tolnay56080682018-01-06 14:01:52 -080032 path.segments.push_value(segment.into());
David Tolnay056de302018-01-05 14:29:05 -080033 path
34 }
35}
36
37ast_struct! {
David Tolnay05658502018-01-07 09:56:37 -080038 /// A segment of a path together with any path arguments on that segment.
David Tolnay461d98e2018-01-07 11:07:19 -080039 ///
40 /// *This type is available if Syn is built with the `"derive"` or `"full"`
41 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -080042 pub struct PathSegment {
David Tolnay056de302018-01-05 14:29:05 -080043 pub ident: Ident,
David Tolnay056de302018-01-05 14:29:05 -080044 pub arguments: PathArguments,
45 }
46}
47
48impl<T> From<T> for PathSegment
49where
50 T: Into<Ident>,
51{
52 fn from(ident: T) -> Self {
53 PathSegment {
54 ident: ident.into(),
55 arguments: PathArguments::None,
56 }
57 }
58}
59
60ast_enum! {
David Tolnayc0435192018-01-07 11:46:08 -080061 /// Angle bracketed or parenthesized arguments of a path segment.
David Tolnay461d98e2018-01-07 11:07:19 -080062 ///
63 /// *This type is available if Syn is built with the `"derive"` or `"full"`
64 /// feature.*
David Tolnayc0435192018-01-07 11:46:08 -080065 ///
66 /// ## Angle bracketed
67 ///
68 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
69 ///
70 /// ## Parenthesized
71 ///
72 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
David Tolnay056de302018-01-05 14:29:05 -080073 pub enum PathArguments {
74 None,
David Tolnaye826d812018-01-06 23:59:39 -080075 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
David Tolnay056de302018-01-05 14:29:05 -080076 AngleBracketed(AngleBracketedGenericArguments),
David Tolnayc0435192018-01-07 11:46:08 -080077 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
David Tolnay056de302018-01-05 14:29:05 -080078 Parenthesized(ParenthesizedGenericArguments),
79 }
80}
81
82impl Default for PathArguments {
83 fn default() -> Self {
84 PathArguments::None
85 }
86}
87
88impl PathArguments {
89 pub fn is_empty(&self) -> bool {
90 match *self {
91 PathArguments::None => true,
92 PathArguments::AngleBracketed(ref bracketed) => bracketed.args.is_empty(),
93 PathArguments::Parenthesized(_) => false,
94 }
95 }
96}
97
98ast_enum! {
David Tolnaya454c8f2018-01-07 01:01:10 -080099 /// An individual generic argument, like `'a`, `T`, or `Item = T`.
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 Tolnay056de302018-01-05 14:29:05 -0800103 pub enum GenericArgument {
David Tolnaye826d812018-01-06 23:59:39 -0800104 /// A lifetime argument.
David Tolnay056de302018-01-05 14:29:05 -0800105 Lifetime(Lifetime),
David Tolnaye826d812018-01-06 23:59:39 -0800106 /// A type argument.
David Tolnay056de302018-01-05 14:29:05 -0800107 Type(Type),
David Tolnayc0435192018-01-07 11:46:08 -0800108 /// A binding (equality constraint) on an associated type: the `Item =
109 /// u8` in `Iterator<Item = u8>`.
David Tolnay056de302018-01-05 14:29:05 -0800110 Binding(Binding),
David Tolnaye826d812018-01-06 23:59:39 -0800111 /// A const expression. Must be inside of a block.
David Tolnay056de302018-01-05 14:29:05 -0800112 ///
113 /// NOTE: Identity expressions are represented as Type arguments, as
114 /// they are indistinguishable syntactically.
115 Const(Expr),
116 }
117}
118
119ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800120 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
121 /// V>`.
David Tolnay461d98e2018-01-07 11:07:19 -0800122 ///
123 /// *This type is available if Syn is built with the `"derive"` or `"full"`
124 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800125 pub struct AngleBracketedGenericArguments {
126 pub colon2_token: Option<Token![::]>,
127 pub lt_token: Token![<],
128 pub args: Punctuated<GenericArgument, Token![,]>,
129 pub gt_token: Token![>],
130 }
131}
132
133ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800134 /// A binding (equality constraint) on an associated type: `Item = u8`.
David Tolnay461d98e2018-01-07 11:07:19 -0800135 ///
136 /// *This type is available if Syn is built with the `"derive"` or `"full"`
137 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800138 pub struct Binding {
139 pub ident: Ident,
140 pub eq_token: Token![=],
141 pub ty: Type,
142 }
143}
144
145ast_struct! {
David Tolnayc0435192018-01-07 11:46:08 -0800146 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
147 /// C`.
David Tolnay461d98e2018-01-07 11:07:19 -0800148 ///
149 /// *This type is available if Syn is built with the `"derive"` or `"full"`
150 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800151 pub struct ParenthesizedGenericArguments {
152 pub paren_token: token::Paren,
153 /// `(A, B)`
154 pub inputs: Punctuated<Type, Token![,]>,
155 /// `C`
156 pub output: ReturnType,
157 }
158}
159
160ast_struct! {
David Tolnaye826d812018-01-06 23:59:39 -0800161 /// The explicit Self type in a qualified path: the `T` in `<T as
David Tolnay05658502018-01-07 09:56:37 -0800162 /// Display>::fmt`.
David Tolnaye826d812018-01-06 23:59:39 -0800163 ///
164 /// The actual path, including the trait and the associated item, is stored
165 /// separately. The `position` field represents the index of the associated
David Tolnay056de302018-01-05 14:29:05 -0800166 /// item qualified with this Self type.
167 ///
168 /// ```text
169 /// <Vec<T> as a::b::Trait>::AssociatedItem
170 /// ^~~~~~ ~~~~~~~~~~~~~~^
171 /// ty position = 3
172 ///
173 /// <Vec<T>>::AssociatedItem
174 /// ^~~~~~ ^
175 /// ty position = 0
176 /// ```
David Tolnay461d98e2018-01-07 11:07:19 -0800177 ///
178 /// *This type is available if Syn is built with the `"derive"` or `"full"`
179 /// feature.*
David Tolnay056de302018-01-05 14:29:05 -0800180 pub struct QSelf {
181 pub lt_token: Token![<],
182 pub ty: Box<Type>,
183 pub position: usize,
184 pub as_token: Option<Token![as]>,
185 pub gt_token: Token![>],
186 }
187}
188
189#[cfg(feature = "parsing")]
190pub mod parsing {
191 use super::*;
David Tolnay94d304f2018-08-30 23:43:53 -0700192
David Tolnay310b3262018-08-30 15:33:00 -0700193 #[cfg(feature = "full")]
194 use expr;
David Tolnay94d304f2018-08-30 23:43:53 -0700195 use ext::IdentExt;
David Tolnay73b7ca12018-08-30 21:05:13 -0700196 use parse::{Parse, ParseStream, Result};
David Tolnay056de302018-01-05 14:29:05 -0800197
David Tolnay4fb71232018-08-25 23:14:50 -0400198 impl Parse for Path {
199 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay60291082018-08-28 09:54:49 -0700200 Self::parse_helper(input, false)
David Tolnay056de302018-01-05 14:29:05 -0800201 }
202 }
203
David Tolnay4fb71232018-08-25 23:14:50 -0400204 impl Parse for GenericArgument {
205 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay66cb0c42018-08-31 09:01:30 -0700206 if input.peek(Lifetime) && !input.peek2(Token![+]) {
David Tolnay4fb71232018-08-25 23:14:50 -0400207 return Ok(GenericArgument::Lifetime(input.parse()?));
208 }
David Tolnay056de302018-01-05 14:29:05 -0800209
David Tolnay4fb71232018-08-25 23:14:50 -0400210 if input.peek(Ident) && input.peek2(Token![=]) {
211 return Ok(GenericArgument::Binding(input.parse()?));
212 }
David Tolnay056de302018-01-05 14:29:05 -0800213
David Tolnay4fb71232018-08-25 23:14:50 -0400214 #[cfg(feature = "full")]
215 {
216 if input.peek(Lit) {
David Tolnay310b3262018-08-30 15:33:00 -0700217 let lit = input.call(expr::parsing::expr_lit)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400218 return Ok(GenericArgument::Const(Expr::Lit(lit)));
219 }
220
221 if input.peek(token::Brace) {
David Tolnay310b3262018-08-30 15:33:00 -0700222 let block = input.call(expr::parsing::expr_block)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400223 return Ok(GenericArgument::Const(Expr::Block(block)));
224 }
225 }
226
David Tolnay8db2d662018-08-30 17:40:59 -0700227 input.parse().map(GenericArgument::Type)
David Tolnay056de302018-01-05 14:29:05 -0800228 }
229 }
230
David Tolnay4fb71232018-08-25 23:14:50 -0400231 impl Parse for AngleBracketedGenericArguments {
232 fn parse(input: ParseStream) -> Result<Self> {
233 Ok(AngleBracketedGenericArguments {
234 colon2_token: input.parse()?,
235 lt_token: input.parse()?,
236 args: {
237 let mut args = Punctuated::new();
238 loop {
239 if input.peek(Token![>]) {
240 break;
241 }
242 let value = input.parse()?;
243 args.push_value(value);
244 if input.peek(Token![>]) {
245 break;
246 }
247 let punct = input.parse()?;
248 args.push_punct(punct);
249 }
250 args
251 },
252 gt_token: input.parse()?,
David Tolnay056de302018-01-05 14:29:05 -0800253 })
David Tolnay056de302018-01-05 14:29:05 -0800254 }
255 }
256
David Tolnay4fb71232018-08-25 23:14:50 -0400257 impl Parse for ParenthesizedGenericArguments {
258 fn parse(input: ParseStream) -> Result<Self> {
259 let content;
260 Ok(ParenthesizedGenericArguments {
261 paren_token: parenthesized!(content in input),
David Tolnayf5ebc192018-08-30 18:23:46 -0700262 inputs: content.parse_terminated(Type::parse)?,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400263 output: input.call(ReturnType::without_plus)?,
David Tolnay056de302018-01-05 14:29:05 -0800264 })
David Tolnay056de302018-01-05 14:29:05 -0800265 }
266 }
267
David Tolnay4fb71232018-08-25 23:14:50 -0400268 impl Parse for PathSegment {
269 fn parse(input: ParseStream) -> Result<Self> {
David Tolnay60291082018-08-28 09:54:49 -0700270 Self::parse_helper(input, false)
271 }
272 }
273
274 impl PathSegment {
275 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
David Tolnay4fb71232018-08-25 23:14:50 -0400276 if input.peek(Token![super])
277 || input.peek(Token![self])
278 || input.peek(Token![Self])
279 || input.peek(Token![crate])
280 || input.peek(Token![extern])
281 {
David Tolnay0dea1b92018-08-30 17:47:29 -0700282 let ident = input.call(Ident::parse_any)?;
David Tolnay4fb71232018-08-25 23:14:50 -0400283 return Ok(PathSegment::from(ident));
284 }
285
286 let ident = input.parse()?;
David Tolnay60291082018-08-28 09:54:49 -0700287 if !expr_style && input.peek(Token![<]) && !input.peek(Token![<=])
David Tolnay4fb71232018-08-25 23:14:50 -0400288 || input.peek(Token![::]) && input.peek3(Token![<])
289 {
290 Ok(PathSegment {
David Tolnay056de302018-01-05 14:29:05 -0800291 ident: ident,
David Tolnay4fb71232018-08-25 23:14:50 -0400292 arguments: PathArguments::AngleBracketed(input.parse()?),
David Tolnay056de302018-01-05 14:29:05 -0800293 })
David Tolnay4fb71232018-08-25 23:14:50 -0400294 } else {
295 Ok(PathSegment::from(ident))
296 }
David Tolnay056de302018-01-05 14:29:05 -0800297 }
298 }
299
David Tolnay4fb71232018-08-25 23:14:50 -0400300 impl Parse for Binding {
301 fn parse(input: ParseStream) -> Result<Self> {
302 Ok(Binding {
303 ident: input.parse()?,
304 eq_token: input.parse()?,
David Tolnaya7d69fc2018-08-26 13:30:24 -0400305 ty: input.parse()?,
David Tolnay056de302018-01-05 14:29:05 -0800306 })
David Tolnay056de302018-01-05 14:29:05 -0800307 }
308 }
309
310 impl Path {
David Tolnaybbbd5302018-09-01 16:00:42 -0700311 /// Parse a `Path` containing no path arguments on any of its segments.
312 ///
David Tolnay206edfb2018-09-01 16:02:20 -0700313 /// *This function is available if Syn is built with the `"parsing"`
314 /// feature.*
315 ///
David Tolnaybbbd5302018-09-01 16:00:42 -0700316 /// # Example
317 ///
318 /// ```
319 /// # extern crate syn;
320 /// #
321 /// use syn::{Path, Token};
322 /// use syn::parse::{Parse, ParseStream, Result};
323 ///
324 /// // A simplified single `use` statement like:
325 /// //
326 /// // use std::collections::HashMap;
327 /// //
328 /// // Note that generic parameters are not allowed in a `use` statement
329 /// // so the following must not be accepted.
330 /// //
331 /// // use a::<b>::c;
332 /// struct SingleUse {
333 /// use_token: Token![use],
334 /// path: Path,
335 /// }
336 ///
337 /// impl Parse for SingleUse {
338 /// fn parse(input: ParseStream) -> Result<Self> {
339 /// Ok(SingleUse {
340 /// use_token: input.parse()?,
341 /// path: input.call(Path::parse_mod_style)?,
342 /// })
343 /// }
344 /// }
345 /// #
346 /// # fn main() {}
347 /// ```
David Tolnaya7d69fc2018-08-26 13:30:24 -0400348 pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
349 Ok(Path {
350 leading_colon: input.parse()?,
351 segments: {
352 let mut segments = Punctuated::new();
353 loop {
354 if !input.peek(Ident)
355 && !input.peek(Token![super])
356 && !input.peek(Token![self])
357 && !input.peek(Token![Self])
358 && !input.peek(Token![crate])
359 && !input.peek(Token![extern])
360 {
361 break;
362 }
David Tolnay0dea1b92018-08-30 17:47:29 -0700363 let ident = Ident::parse_any(input)?;
David Tolnaya7d69fc2018-08-26 13:30:24 -0400364 segments.push_value(PathSegment::from(ident));
365 if !input.peek(Token![::]) {
366 break;
367 }
368 let punct = input.parse()?;
369 segments.push_punct(punct);
370 }
371 if segments.is_empty() {
372 return Err(input.error("expected path"));
373 } else if segments.trailing_punct() {
374 return Err(input.error("expected path segment"));
375 }
376 segments
377 },
378 })
379 }
380
David Tolnay60291082018-08-28 09:54:49 -0700381 fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
382 if input.peek(Token![dyn]) {
383 return Err(input.error("expected path"));
384 }
385
386 Ok(Path {
387 leading_colon: input.parse()?,
388 segments: {
389 let mut segments = Punctuated::new();
390 let value = PathSegment::parse_helper(input, expr_style)?;
391 segments.push_value(value);
392 while input.peek(Token![::]) {
393 let punct: Token![::] = input.parse()?;
394 segments.push_punct(punct);
395 let value = PathSegment::parse_helper(input, expr_style)?;
396 segments.push_value(value);
397 }
398 segments
399 },
400 })
401 }
David Tolnay056de302018-01-05 14:29:05 -0800402 }
403
David Tolnay60291082018-08-28 09:54:49 -0700404 pub fn qpath(input: ParseStream, expr_style: bool) -> Result<(Option<QSelf>, Path)> {
405 if input.peek(Token![<]) {
406 let lt_token: Token![<] = input.parse()?;
407 let this: Type = input.parse()?;
408 let path = if input.peek(Token![as]) {
409 let as_token: Token![as] = input.parse()?;
410 let path: Path = input.parse()?;
411 Some((as_token, path))
412 } else {
413 None
414 };
415 let gt_token: Token![>] = input.parse()?;
416 let colon2_token: Token![::] = input.parse()?;
417 let mut rest = Punctuated::new();
418 loop {
419 let path = PathSegment::parse_helper(input, expr_style)?;
420 rest.push_value(path);
421 if !input.peek(Token![::]) {
422 break;
423 }
424 let punct: Token![::] = input.parse()?;
425 rest.push_punct(punct);
426 }
427 let (position, as_token, path) = match path {
428 Some((as_token, mut path)) => {
429 let pos = path.segments.len();
430 path.segments.push_punct(colon2_token);
431 path.segments.extend(rest.into_pairs());
432 (pos, Some(as_token), path)
433 }
434 None => {
435 let path = Path {
436 leading_colon: Some(colon2_token),
437 segments: rest,
438 };
439 (0, None, path)
440 }
441 };
442 let qself = QSelf {
443 lt_token: lt_token,
444 ty: Box::new(this),
445 position: position,
446 as_token: as_token,
447 gt_token: gt_token,
448 };
449 Ok((Some(qself), path))
450 } else {
451 let path = Path::parse_helper(input, expr_style)?;
452 Ok((None, path))
453 }
454 }
David Tolnay056de302018-01-05 14:29:05 -0800455}
456
457#[cfg(feature = "printing")]
458mod printing {
459 use super::*;
David Tolnay64023912018-08-31 09:51:12 -0700460
Alex Crichtona74a1c82018-05-16 10:20:44 -0700461 use proc_macro2::TokenStream;
David Tolnay65fb5662018-05-20 20:02:28 -0700462 use quote::ToTokens;
David Tolnay056de302018-01-05 14:29:05 -0800463
David Tolnay64023912018-08-31 09:51:12 -0700464 use print::TokensOrDefault;
465
David Tolnay056de302018-01-05 14:29:05 -0800466 impl ToTokens for Path {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700467 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800468 self.leading_colon.to_tokens(tokens);
469 self.segments.to_tokens(tokens);
470 }
471 }
472
473 impl ToTokens for PathSegment {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700474 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800475 self.ident.to_tokens(tokens);
476 self.arguments.to_tokens(tokens);
477 }
478 }
479
480 impl ToTokens for PathArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700481 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800482 match *self {
483 PathArguments::None => {}
484 PathArguments::AngleBracketed(ref arguments) => {
485 arguments.to_tokens(tokens);
486 }
487 PathArguments::Parenthesized(ref arguments) => {
488 arguments.to_tokens(tokens);
489 }
490 }
491 }
492 }
493
494 impl ToTokens for GenericArgument {
495 #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
Alex Crichtona74a1c82018-05-16 10:20:44 -0700496 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800497 match *self {
498 GenericArgument::Lifetime(ref lt) => lt.to_tokens(tokens),
499 GenericArgument::Type(ref ty) => ty.to_tokens(tokens),
500 GenericArgument::Binding(ref tb) => tb.to_tokens(tokens),
501 GenericArgument::Const(ref e) => match *e {
502 Expr::Lit(_) => e.to_tokens(tokens),
503
504 // NOTE: We should probably support parsing blocks with only
505 // expressions in them without the full feature for const
506 // generics.
507 #[cfg(feature = "full")]
508 Expr::Block(_) => e.to_tokens(tokens),
509
510 // ERROR CORRECTION: Add braces to make sure that the
511 // generated code is valid.
512 _ => token::Brace::default().surround(tokens, |tokens| {
513 e.to_tokens(tokens);
514 }),
515 },
516 }
517 }
518 }
519
520 impl ToTokens for AngleBracketedGenericArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700521 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800522 self.colon2_token.to_tokens(tokens);
523 self.lt_token.to_tokens(tokens);
David Tolnay298570b2018-01-11 16:38:36 -0800524
525 // Print lifetimes before types and consts, all before bindings,
526 // regardless of their order in self.args.
527 //
528 // TODO: ordering rules for const arguments vs type arguments have
529 // not been settled yet. https://github.com/rust-lang/rust/issues/44580
530 let mut trailing_or_empty = true;
531 for param in self.args.pairs() {
532 if let GenericArgument::Lifetime(_) = **param.value() {
533 param.to_tokens(tokens);
534 trailing_or_empty = param.punct().is_some();
535 }
536 }
537 for param in self.args.pairs() {
538 match **param.value() {
539 GenericArgument::Type(_) | GenericArgument::Const(_) => {
540 if !trailing_or_empty {
541 <Token![,]>::default().to_tokens(tokens);
542 }
543 param.to_tokens(tokens);
544 trailing_or_empty = param.punct().is_some();
545 }
546 GenericArgument::Lifetime(_) | GenericArgument::Binding(_) => {}
547 }
548 }
549 for param in self.args.pairs() {
550 if let GenericArgument::Binding(_) = **param.value() {
551 if !trailing_or_empty {
552 <Token![,]>::default().to_tokens(tokens);
553 trailing_or_empty = true;
554 }
555 param.to_tokens(tokens);
556 }
557 }
558
David Tolnay056de302018-01-05 14:29:05 -0800559 self.gt_token.to_tokens(tokens);
560 }
561 }
562
563 impl ToTokens for Binding {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700564 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800565 self.ident.to_tokens(tokens);
566 self.eq_token.to_tokens(tokens);
567 self.ty.to_tokens(tokens);
568 }
569 }
570
571 impl ToTokens for ParenthesizedGenericArguments {
Alex Crichtona74a1c82018-05-16 10:20:44 -0700572 fn to_tokens(&self, tokens: &mut TokenStream) {
David Tolnay056de302018-01-05 14:29:05 -0800573 self.paren_token.surround(tokens, |tokens| {
574 self.inputs.to_tokens(tokens);
575 });
576 self.output.to_tokens(tokens);
577 }
578 }
David Tolnay05658502018-01-07 09:56:37 -0800579
David Tolnay12f3b6f2018-09-01 16:10:53 -0700580 impl private {
581 pub fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
582 let qself = match *qself {
David Tolnay05658502018-01-07 09:56:37 -0800583 Some(ref qself) => qself,
David Tolnay12f3b6f2018-09-01 16:10:53 -0700584 None => {
585 path.to_tokens(tokens);
586 return;
587 }
David Tolnay05658502018-01-07 09:56:37 -0800588 };
589 qself.lt_token.to_tokens(tokens);
590 qself.ty.to_tokens(tokens);
591
David Tolnay12f3b6f2018-09-01 16:10:53 -0700592 let pos = if qself.position > 0 && qself.position >= path.segments.len() {
593 path.segments.len() - 1
David Tolnay05658502018-01-07 09:56:37 -0800594 } else {
595 qself.position
596 };
David Tolnay12f3b6f2018-09-01 16:10:53 -0700597 let mut segments = path.segments.pairs();
David Tolnay05658502018-01-07 09:56:37 -0800598 if pos > 0 {
599 TokensOrDefault(&qself.as_token).to_tokens(tokens);
David Tolnay12f3b6f2018-09-01 16:10:53 -0700600 path.leading_colon.to_tokens(tokens);
David Tolnay05658502018-01-07 09:56:37 -0800601 for (i, segment) in segments.by_ref().take(pos).enumerate() {
602 if i + 1 == pos {
603 segment.value().to_tokens(tokens);
604 qself.gt_token.to_tokens(tokens);
605 segment.punct().to_tokens(tokens);
606 } else {
607 segment.to_tokens(tokens);
608 }
609 }
610 } else {
611 qself.gt_token.to_tokens(tokens);
David Tolnay12f3b6f2018-09-01 16:10:53 -0700612 path.leading_colon.to_tokens(tokens);
David Tolnay05658502018-01-07 09:56:37 -0800613 }
614 for segment in segments {
615 segment.to_tokens(tokens);
616 }
617 }
618 }
David Tolnay056de302018-01-05 14:29:05 -0800619}