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