2 use crate::punctuated
::Punctuated
;
5 /// A path at which a named item is exported (e.g. `std::collections::HashMap`).
7 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
10 pub leading_colon
: Option
<Token
![::]>,
11 pub segments
: Punctuated
<PathSegment
, Token
![::]>,
15 impl<T
> From
<T
> for Path
19 fn from(segment
: T
) -> Self {
22 segments
: Punctuated
::new(),
24 path
.segments
.push_value(segment
.into());
30 /// A segment of a path together with any path arguments on that segment.
32 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
34 pub struct PathSegment
{
36 pub arguments
: PathArguments
,
40 impl<T
> From
<T
> for PathSegment
44 fn from(ident
: T
) -> Self {
47 arguments
: PathArguments
::None
,
53 /// Angle bracketed or parenthesized arguments of a path segment.
55 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
58 /// ## Angle bracketed
60 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
64 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
65 pub enum PathArguments
{
67 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
68 AngleBracketed(AngleBracketedGenericArguments
),
69 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
70 Parenthesized(ParenthesizedGenericArguments
),
74 impl Default
for PathArguments
{
75 fn default() -> Self {
81 pub fn is_empty(&self) -> bool
{
83 PathArguments
::None
=> true,
84 PathArguments
::AngleBracketed(bracketed
) => bracketed
.args
.is_empty(),
85 PathArguments
::Parenthesized(_
) => false,
89 #[cfg(feature = "parsing")]
90 fn is_none(&self) -> bool
{
92 PathArguments
::None
=> true,
93 PathArguments
::AngleBracketed(_
) | PathArguments
::Parenthesized(_
) => false,
99 /// An individual generic argument, like `'a`, `T`, or `Item = T`.
101 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
103 pub enum GenericArgument
{
104 /// A lifetime argument.
108 /// A binding (equality constraint) on an associated type: the `Item =
109 /// u8` in `Iterator<Item = u8>`.
111 /// An associated type bound: `Iterator<Item: Display>`.
112 Constraint(Constraint
),
113 /// A const expression. Must be inside of a block.
115 /// NOTE: Identity expressions are represented as Type arguments, as
116 /// they are indistinguishable syntactically.
122 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
125 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
127 pub struct AngleBracketedGenericArguments
{
128 pub colon2_token
: Option
<Token
![::]>,
129 pub lt_token
: Token
![<],
130 pub args
: Punctuated
<GenericArgument
, Token
![,]>,
131 pub gt_token
: Token
![>],
136 /// A binding (equality constraint) on an associated type: `Item = u8`.
138 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
142 pub eq_token
: Token
![=],
148 /// An associated type bound: `Iterator<Item: Display>`.
150 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
152 pub struct Constraint
{
154 pub colon_token
: Token
![:],
155 pub bounds
: Punctuated
<TypeParamBound
, Token
![+]>,
160 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
163 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
165 pub struct ParenthesizedGenericArguments
{
166 pub paren_token
: token
::Paren
,
168 pub inputs
: Punctuated
<Type
, Token
![,]>,
170 pub output
: ReturnType
,
175 /// The explicit Self type in a qualified path: the `T` in `<T as
178 /// The actual path, including the trait and the associated item, is stored
179 /// separately. The `position` field represents the index of the associated
180 /// item qualified with this Self type.
183 /// <Vec<T> as a::b::Trait>::AssociatedItem
184 /// ^~~~~~ ~~~~~~~~~~~~~~^
187 /// <Vec<T>>::AssociatedItem
192 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
195 pub lt_token
: Token
![<],
198 pub as_token
: Option
<Token
![as]>,
199 pub gt_token
: Token
![>],
203 #[cfg(feature = "parsing")]
207 #[cfg(feature = "full")]
209 use crate::ext
::IdentExt
;
210 use crate::parse
::{Parse, ParseStream, Result}
;
212 impl Parse
for Path
{
213 fn parse(input
: ParseStream
) -> Result
<Self> {
214 Self::parse_helper(input
, false)
218 impl Parse
for GenericArgument
{
219 fn parse(input
: ParseStream
) -> Result
<Self> {
220 if input
.peek(Lifetime
) && !input
.peek2(Token
![+]) {
221 return Ok(GenericArgument
::Lifetime(input
.parse()?
));
224 if input
.peek(Ident
) && input
.peek2(Token
![=]) {
225 return Ok(GenericArgument
::Binding(input
.parse()?
));
228 #[cfg(feature = "full")]
230 if input
.peek(Ident
) && input
.peek2(Token
![:]) && !input
.peek2(Token
![::]) {
231 return Ok(GenericArgument
::Constraint(input
.parse()?
));
235 let lit
= input
.parse()?
;
236 return Ok(GenericArgument
::Const(Expr
::Lit(lit
)));
239 if input
.peek(token
::Brace
) {
240 let block
= input
.call(expr
::parsing
::expr_block
)?
;
241 return Ok(GenericArgument
::Const(Expr
::Block(block
)));
245 input
.parse().map(GenericArgument
::Type
)
249 impl Parse
for AngleBracketedGenericArguments
{
250 fn parse(input
: ParseStream
) -> Result
<Self> {
251 Ok(AngleBracketedGenericArguments
{
252 colon2_token
: input
.parse()?
,
253 lt_token
: input
.parse()?
,
255 let mut args
= Punctuated
::new();
257 if input
.peek(Token
![>]) {
260 let value
= input
.parse()?
;
261 args
.push_value(value
);
262 if input
.peek(Token
![>]) {
265 let punct
= input
.parse()?
;
266 args
.push_punct(punct
);
270 gt_token
: input
.parse()?
,
275 impl Parse
for ParenthesizedGenericArguments
{
276 fn parse(input
: ParseStream
) -> Result
<Self> {
278 Ok(ParenthesizedGenericArguments
{
279 paren_token
: parenthesized
!(content
in input
),
280 inputs
: content
.parse_terminated(Type
::parse
)?
,
281 output
: input
.call(ReturnType
::without_plus
)?
,
286 impl Parse
for PathSegment
{
287 fn parse(input
: ParseStream
) -> Result
<Self> {
288 Self::parse_helper(input
, false)
293 fn parse_helper(input
: ParseStream
, expr_style
: bool
) -> Result
<Self> {
294 if input
.peek(Token
![super]) || input
.peek(Token
![self]) || input
.peek(Token
![crate]) {
295 let ident
= input
.call(Ident
::parse_any
)?
;
296 return Ok(PathSegment
::from(ident
));
299 let ident
= if input
.peek(Token
![Self]) {
300 input
.call(Ident
::parse_any
)?
305 if !expr_style
&& input
.peek(Token
![<]) && !input
.peek(Token
![<=])
306 || input
.peek(Token
![::]) && input
.peek3(Token
![<])
310 arguments
: PathArguments
::AngleBracketed(input
.parse()?
),
313 Ok(PathSegment
::from(ident
))
318 impl Parse
for Binding
{
319 fn parse(input
: ParseStream
) -> Result
<Self> {
321 ident
: input
.parse()?
,
322 eq_token
: input
.parse()?
,
328 #[cfg(feature = "full")]
329 impl Parse
for Constraint
{
330 fn parse(input
: ParseStream
) -> Result
<Self> {
332 ident
: input
.parse()?
,
333 colon_token
: input
.parse()?
,
335 let mut bounds
= Punctuated
::new();
337 if input
.peek(Token
![,]) || input
.peek(Token
![>]) {
340 let value
= input
.parse()?
;
341 bounds
.push_value(value
);
342 if !input
.peek(Token
![+]) {
345 let punct
= input
.parse()?
;
346 bounds
.push_punct(punct
);
355 /// Parse a `Path` containing no path arguments on any of its segments.
357 /// *This function is available only if Syn is built with the `"parsing"`
363 /// use syn::{Path, Result, Token};
364 /// use syn::parse::{Parse, ParseStream};
366 /// // A simplified single `use` statement like:
368 /// // use std::collections::HashMap;
370 /// // Note that generic parameters are not allowed in a `use` statement
371 /// // so the following must not be accepted.
373 /// // use a::<b>::c;
374 /// struct SingleUse {
375 /// use_token: Token![use],
379 /// impl Parse for SingleUse {
380 /// fn parse(input: ParseStream) -> Result<Self> {
382 /// use_token: input.parse()?,
383 /// path: input.call(Path::parse_mod_style)?,
388 pub fn parse_mod_style(input
: ParseStream
) -> Result
<Self> {
390 leading_colon
: input
.parse()?
,
392 let mut segments
= Punctuated
::new();
394 if !input
.peek(Ident
)
395 && !input
.peek(Token
![super])
396 && !input
.peek(Token
![self])
397 && !input
.peek(Token
![Self])
398 && !input
.peek(Token
![crate])
402 let ident
= Ident
::parse_any(input
)?
;
403 segments
.push_value(PathSegment
::from(ident
));
404 if !input
.peek(Token
![::]) {
407 let punct
= input
.parse()?
;
408 segments
.push_punct(punct
);
410 if segments
.is_empty() {
411 return Err(input
.error("expected path"));
412 } else if segments
.trailing_punct() {
413 return Err(input
.error("expected path segment"));
420 /// Determines whether this is a path of length 1 equal to the given
423 /// For them to compare equal, it must be the case that:
425 /// - the path has no leading colon,
426 /// - the number of path segments is 1,
427 /// - the first path segment has no angle bracketed or parenthesized
428 /// path arguments, and
429 /// - the ident of the first path segment is equal to the given one.
431 /// *This function is available only if Syn is built with the `"parsing"`
437 /// use syn::{Attribute, Error, Meta, NestedMeta, Result};
438 /// # use std::iter::FromIterator;
440 /// fn get_serde_meta_items(attr: &Attribute) -> Result<Vec<NestedMeta>> {
441 /// if attr.path.is_ident("serde") {
442 /// match attr.parse_meta()? {
443 /// Meta::List(meta) => Ok(Vec::from_iter(meta.nested)),
444 /// bad => Err(Error::new_spanned(bad, "unrecognized attribute")),
451 pub fn is_ident
<I
: ?Sized
>(&self, ident
: &I
) -> bool
455 match self.get_ident() {
456 Some(id
) => id
== ident
,
461 /// If this path consists of a single ident, returns the ident.
463 /// A path is considered an ident if:
465 /// - the path has no leading colon,
466 /// - the number of path segments is 1, and
467 /// - the first path segment has no angle bracketed or parenthesized
470 /// *This function is available only if Syn is built with the `"parsing"`
472 pub fn get_ident(&self) -> Option
<&Ident
> {
473 if self.leading_colon
.is_none()
474 && self.segments
.len() == 1
475 && self.segments
[0].arguments
.is_none()
477 Some(&self.segments
[0].ident
)
483 fn parse_helper(input
: ParseStream
, expr_style
: bool
) -> Result
<Self> {
485 leading_colon
: input
.parse()?
,
487 let mut segments
= Punctuated
::new();
488 let value
= PathSegment
::parse_helper(input
, expr_style
)?
;
489 segments
.push_value(value
);
490 while input
.peek(Token
![::]) {
491 let punct
: Token
![::] = input
.parse()?
;
492 segments
.push_punct(punct
);
493 let value
= PathSegment
::parse_helper(input
, expr_style
)?
;
494 segments
.push_value(value
);
502 pub fn qpath(input
: ParseStream
, expr_style
: bool
) -> Result
<(Option
<QSelf
>, Path
)> {
503 if input
.peek(Token
![<]) {
504 let lt_token
: Token
![<] = input
.parse()?
;
505 let this
: Type
= input
.parse()?
;
506 let path
= if input
.peek(Token
![as]) {
507 let as_token
: Token
![as] = input
.parse()?
;
508 let path
: Path
= input
.parse()?
;
509 Some((as_token
, path
))
513 let gt_token
: Token
![>] = input
.parse()?
;
514 let colon2_token
: Token
![::] = input
.parse()?
;
515 let mut rest
= Punctuated
::new();
517 let path
= PathSegment
::parse_helper(input
, expr_style
)?
;
518 rest
.push_value(path
);
519 if !input
.peek(Token
![::]) {
522 let punct
: Token
![::] = input
.parse()?
;
523 rest
.push_punct(punct
);
525 let (position
, as_token
, path
) = match path
{
526 Some((as_token
, mut path
)) => {
527 let pos
= path
.segments
.len();
528 path
.segments
.push_punct(colon2_token
);
529 path
.segments
.extend(rest
.into_pairs());
530 (pos
, Some(as_token
), path
)
534 leading_colon
: Some(colon2_token
),
547 Ok((Some(qself
), path
))
549 let path
= Path
::parse_helper(input
, expr_style
)?
;
555 #[cfg(feature = "printing")]
559 use proc_macro2
::TokenStream
;
562 use crate::print
::TokensOrDefault
;
564 impl ToTokens
for Path
{
565 fn to_tokens(&self, tokens
: &mut TokenStream
) {
566 self.leading_colon
.to_tokens(tokens
);
567 self.segments
.to_tokens(tokens
);
571 impl ToTokens
for PathSegment
{
572 fn to_tokens(&self, tokens
: &mut TokenStream
) {
573 self.ident
.to_tokens(tokens
);
574 self.arguments
.to_tokens(tokens
);
578 impl ToTokens
for PathArguments
{
579 fn to_tokens(&self, tokens
: &mut TokenStream
) {
581 PathArguments
::None
=> {}
582 PathArguments
::AngleBracketed(arguments
) => {
583 arguments
.to_tokens(tokens
);
585 PathArguments
::Parenthesized(arguments
) => {
586 arguments
.to_tokens(tokens
);
592 impl ToTokens
for GenericArgument
{
593 #[allow(clippy::match_same_arms)]
594 fn to_tokens(&self, tokens
: &mut TokenStream
) {
596 GenericArgument
::Lifetime(lt
) => lt
.to_tokens(tokens
),
597 GenericArgument
::Type(ty
) => ty
.to_tokens(tokens
),
598 GenericArgument
::Binding(tb
) => tb
.to_tokens(tokens
),
599 GenericArgument
::Constraint(tc
) => tc
.to_tokens(tokens
),
600 GenericArgument
::Const(e
) => match *e
{
601 Expr
::Lit(_
) => e
.to_tokens(tokens
),
603 // NOTE: We should probably support parsing blocks with only
604 // expressions in them without the full feature for const
606 #[cfg(feature = "full")]
607 Expr
::Block(_
) => e
.to_tokens(tokens
),
609 // ERROR CORRECTION: Add braces to make sure that the
610 // generated code is valid.
611 _
=> token
::Brace
::default().surround(tokens
, |tokens
| {
619 impl ToTokens
for AngleBracketedGenericArguments
{
620 fn to_tokens(&self, tokens
: &mut TokenStream
) {
621 self.colon2_token
.to_tokens(tokens
);
622 self.lt_token
.to_tokens(tokens
);
624 // Print lifetimes before types and consts, all before bindings,
625 // regardless of their order in self.args.
627 // TODO: ordering rules for const arguments vs type arguments have
628 // not been settled yet. https://github.com/rust-lang/rust/issues/44580
629 let mut trailing_or_empty
= true;
630 for param
in self.args
.pairs() {
631 match **param
.value() {
632 GenericArgument
::Lifetime(_
) => {
633 param
.to_tokens(tokens
);
634 trailing_or_empty
= param
.punct().is_some();
636 GenericArgument
::Type(_
)
637 | GenericArgument
::Binding(_
)
638 | GenericArgument
::Constraint(_
)
639 | GenericArgument
::Const(_
) => {}
642 for param
in self.args
.pairs() {
643 match **param
.value() {
644 GenericArgument
::Type(_
) | GenericArgument
::Const(_
) => {
645 if !trailing_or_empty
{
646 <Token
![,]>::default().to_tokens(tokens
);
648 param
.to_tokens(tokens
);
649 trailing_or_empty
= param
.punct().is_some();
651 GenericArgument
::Lifetime(_
)
652 | GenericArgument
::Binding(_
)
653 | GenericArgument
::Constraint(_
) => {}
656 for param
in self.args
.pairs() {
657 match **param
.value() {
658 GenericArgument
::Binding(_
) | GenericArgument
::Constraint(_
) => {
659 if !trailing_or_empty
{
660 <Token
![,]>::default().to_tokens(tokens
);
661 trailing_or_empty
= true;
663 param
.to_tokens(tokens
);
665 GenericArgument
::Lifetime(_
)
666 | GenericArgument
::Type(_
)
667 | GenericArgument
::Const(_
) => {}
671 self.gt_token
.to_tokens(tokens
);
675 impl ToTokens
for Binding
{
676 fn to_tokens(&self, tokens
: &mut TokenStream
) {
677 self.ident
.to_tokens(tokens
);
678 self.eq_token
.to_tokens(tokens
);
679 self.ty
.to_tokens(tokens
);
683 impl ToTokens
for Constraint
{
684 fn to_tokens(&self, tokens
: &mut TokenStream
) {
685 self.ident
.to_tokens(tokens
);
686 self.colon_token
.to_tokens(tokens
);
687 self.bounds
.to_tokens(tokens
);
691 impl ToTokens
for ParenthesizedGenericArguments
{
692 fn to_tokens(&self, tokens
: &mut TokenStream
) {
693 self.paren_token
.surround(tokens
, |tokens
| {
694 self.inputs
.to_tokens(tokens
);
696 self.output
.to_tokens(tokens
);
701 pub fn print_path(tokens
: &mut TokenStream
, qself
: &Option
<QSelf
>, path
: &Path
) {
702 let qself
= match qself
{
703 Some(qself
) => qself
,
705 path
.to_tokens(tokens
);
709 qself
.lt_token
.to_tokens(tokens
);
710 qself
.ty
.to_tokens(tokens
);
712 let pos
= if qself
.position
> 0 && qself
.position
>= path
.segments
.len() {
713 path
.segments
.len() - 1
717 let mut segments
= path
.segments
.pairs();
719 TokensOrDefault(&qself
.as_token
).to_tokens(tokens
);
720 path
.leading_colon
.to_tokens(tokens
);
721 for (i
, segment
) in segments
.by_ref().take(pos
).enumerate() {
723 segment
.value().to_tokens(tokens
);
724 qself
.gt_token
.to_tokens(tokens
);
725 segment
.punct().to_tokens(tokens
);
727 segment
.to_tokens(tokens
);
731 qself
.gt_token
.to_tokens(tokens
);
732 path
.leading_colon
.to_tokens(tokens
);
734 for segment
in segments
{
735 segment
.to_tokens(tokens
);