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"`
9 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
11 pub leading_colon
: Option
<Token
![::]>,
12 pub segments
: Punctuated
<PathSegment
, Token
![::]>,
16 impl<T
> From
<T
> for Path
20 fn from(segment
: T
) -> Self {
23 segments
: Punctuated
::new(),
25 path
.segments
.push_value(segment
.into());
31 /// A segment of a path together with any path arguments on that segment.
33 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
35 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
36 pub struct PathSegment
{
38 pub arguments
: PathArguments
,
42 impl<T
> From
<T
> for PathSegment
46 fn from(ident
: T
) -> Self {
49 arguments
: PathArguments
::None
,
55 /// Angle bracketed or parenthesized arguments of a path segment.
57 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
60 /// ## Angle bracketed
62 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
66 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
67 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
68 pub enum PathArguments
{
70 /// The `<'a, T>` in `std::slice::iter<'a, T>`.
71 AngleBracketed(AngleBracketedGenericArguments
),
72 /// The `(A, B) -> C` in `Fn(A, B) -> C`.
73 Parenthesized(ParenthesizedGenericArguments
),
77 impl Default
for PathArguments
{
78 fn default() -> Self {
84 pub fn is_empty(&self) -> bool
{
86 PathArguments
::None
=> true,
87 PathArguments
::AngleBracketed(bracketed
) => bracketed
.args
.is_empty(),
88 PathArguments
::Parenthesized(_
) => false,
92 #[cfg(feature = "parsing")]
93 fn is_none(&self) -> bool
{
95 PathArguments
::None
=> true,
96 PathArguments
::AngleBracketed(_
) | PathArguments
::Parenthesized(_
) => false,
102 /// An individual generic argument, like `'a`, `T`, or `Item = T`.
104 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
106 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
107 pub enum GenericArgument
{
108 /// A lifetime argument.
112 /// A binding (equality constraint) on an associated type: the `Item =
113 /// u8` in `Iterator<Item = u8>`.
115 /// An associated type bound: `Iterator<Item: Display>`.
116 Constraint(Constraint
),
117 /// A const expression. Must be inside of a block.
119 /// NOTE: Identity expressions are represented as Type arguments, as
120 /// they are indistinguishable syntactically.
126 /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K,
129 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
131 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
132 pub struct AngleBracketedGenericArguments
{
133 pub colon2_token
: Option
<Token
![::]>,
134 pub lt_token
: Token
![<],
135 pub args
: Punctuated
<GenericArgument
, Token
![,]>,
136 pub gt_token
: Token
![>],
141 /// A binding (equality constraint) on an associated type: `Item = u8`.
143 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
145 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
148 pub eq_token
: Token
![=],
154 /// An associated type bound: `Iterator<Item: Display>`.
156 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
158 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
159 pub struct Constraint
{
161 pub colon_token
: Token
![:],
162 pub bounds
: Punctuated
<TypeParamBound
, Token
![+]>,
167 /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) ->
170 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
172 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
173 pub struct ParenthesizedGenericArguments
{
174 pub paren_token
: token
::Paren
,
176 pub inputs
: Punctuated
<Type
, Token
![,]>,
178 pub output
: ReturnType
,
183 /// The explicit Self type in a qualified path: the `T` in `<T as
186 /// The actual path, including the trait and the associated item, is stored
187 /// separately. The `position` field represents the index of the associated
188 /// item qualified with this Self type.
191 /// <Vec<T> as a::b::Trait>::AssociatedItem
192 /// ^~~~~~ ~~~~~~~~~~~~~~^
195 /// <Vec<T>>::AssociatedItem
200 /// *This type is available only if Syn is built with the `"derive"` or `"full"`
202 #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
204 pub lt_token
: Token
![<],
207 pub as_token
: Option
<Token
![as]>,
208 pub gt_token
: Token
![>],
212 #[cfg(feature = "parsing")]
216 use crate::ext
::IdentExt
;
217 use crate::parse
::{Parse, ParseStream, Result}
;
219 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
220 impl Parse
for Path
{
221 fn parse(input
: ParseStream
) -> Result
<Self> {
222 Self::parse_helper(input
, false)
226 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
227 impl Parse
for GenericArgument
{
228 fn parse(input
: ParseStream
) -> Result
<Self> {
229 if input
.peek(Lifetime
) && !input
.peek2(Token
![+]) {
230 return Ok(GenericArgument
::Lifetime(input
.parse()?
));
233 if input
.peek(Ident
) && input
.peek2(Token
![=]) {
234 return Ok(GenericArgument
::Binding(input
.parse()?
));
237 #[cfg(feature = "full")]
239 if input
.peek(Ident
) && input
.peek2(Token
![:]) && !input
.peek2(Token
![::]) {
240 return Ok(GenericArgument
::Constraint(input
.parse()?
));
244 if input
.peek(Lit
) || input
.peek(token
::Brace
) {
245 return const_argument(input
).map(GenericArgument
::Const
);
248 #[cfg(feature = "full")]
249 let begin
= input
.fork();
251 let argument
: Type
= input
.parse()?
;
253 #[cfg(feature = "full")]
257 if argument
.qself
.is_none()
258 && argument
.path
.leading_colon
.is_none()
259 && argument
.path
.segments
.len() == 1 =>
261 match argument
.path
.segments
[0].arguments
{
262 PathArguments
::AngleBracketed(_
) => true,
267 } && if input
.peek(Token
![=]) {
268 input
.parse
::<Token
![=]>()?
;
269 input
.parse
::<Type
>()?
;
271 } else if input
.peek(Token
![:]) {
272 input
.parse
::<Token
![:]>()?
;
273 input
.call(constraint_bounds
)?
;
278 let verbatim
= verbatim
::between(begin
, input
);
279 return Ok(GenericArgument
::Type(Type
::Verbatim(verbatim
)));
283 Ok(GenericArgument
::Type(argument
))
287 pub fn const_argument(input
: ParseStream
) -> Result
<Expr
> {
288 let lookahead
= input
.lookahead1();
291 let lit
= input
.parse()?
;
292 return Ok(Expr
::Lit(lit
));
295 #[cfg(feature = "full")]
297 if input
.peek(Ident
) {
298 let ident
: Ident
= input
.parse()?
;
299 return Ok(Expr
::Path(ExprPath
{
302 path
: Path
::from(ident
),
307 if input
.peek(token
::Brace
) {
308 #[cfg(feature = "full")]
310 let block
: ExprBlock
= input
.parse()?
;
311 return Ok(Expr
::Block(block
));
314 #[cfg(not(feature = "full"))]
316 let begin
= input
.fork();
318 braced
!(content
in input
);
319 content
.parse
::<Expr
>()?
;
320 let verbatim
= verbatim
::between(begin
, input
);
321 return Ok(Expr
::Verbatim(verbatim
));
325 Err(lookahead
.error())
328 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
329 impl Parse
for AngleBracketedGenericArguments
{
330 fn parse(input
: ParseStream
) -> Result
<Self> {
331 Ok(AngleBracketedGenericArguments
{
332 colon2_token
: input
.parse()?
,
333 lt_token
: input
.parse()?
,
335 let mut args
= Punctuated
::new();
337 if input
.peek(Token
![>]) {
340 let value
= input
.parse()?
;
341 args
.push_value(value
);
342 if input
.peek(Token
![>]) {
345 let punct
= input
.parse()?
;
346 args
.push_punct(punct
);
350 gt_token
: input
.parse()?
,
355 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
356 impl Parse
for ParenthesizedGenericArguments
{
357 fn parse(input
: ParseStream
) -> Result
<Self> {
359 Ok(ParenthesizedGenericArguments
{
360 paren_token
: parenthesized
!(content
in input
),
361 inputs
: content
.parse_terminated(Type
::parse
)?
,
362 output
: input
.call(ReturnType
::without_plus
)?
,
367 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
368 impl Parse
for PathSegment
{
369 fn parse(input
: ParseStream
) -> Result
<Self> {
370 Self::parse_helper(input
, false)
375 fn parse_helper(input
: ParseStream
, expr_style
: bool
) -> Result
<Self> {
376 if input
.peek(Token
![super]) || input
.peek(Token
![self]) || input
.peek(Token
![crate]) {
377 let ident
= input
.call(Ident
::parse_any
)?
;
378 return Ok(PathSegment
::from(ident
));
381 let ident
= if input
.peek(Token
![Self]) {
382 input
.call(Ident
::parse_any
)?
387 if !expr_style
&& input
.peek(Token
![<]) && !input
.peek(Token
![<=])
388 || input
.peek(Token
![::]) && input
.peek3(Token
![<])
392 arguments
: PathArguments
::AngleBracketed(input
.parse()?
),
395 Ok(PathSegment
::from(ident
))
400 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
401 impl Parse
for Binding
{
402 fn parse(input
: ParseStream
) -> Result
<Self> {
404 ident
: input
.parse()?
,
405 eq_token
: input
.parse()?
,
411 #[cfg(feature = "full")]
412 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
413 impl Parse
for Constraint
{
414 fn parse(input
: ParseStream
) -> Result
<Self> {
416 ident
: input
.parse()?
,
417 colon_token
: input
.parse()?
,
418 bounds
: constraint_bounds(input
)?
,
423 #[cfg(feature = "full")]
424 fn constraint_bounds(input
: ParseStream
) -> Result
<Punctuated
<TypeParamBound
, Token
![+]>> {
425 let mut bounds
= Punctuated
::new();
427 if input
.peek(Token
![,]) || input
.peek(Token
![>]) {
430 let value
= input
.parse()?
;
431 bounds
.push_value(value
);
432 if !input
.peek(Token
![+]) {
435 let punct
= input
.parse()?
;
436 bounds
.push_punct(punct
);
442 /// Parse a `Path` containing no path arguments on any of its segments.
444 /// *This function is available only if Syn is built with the `"parsing"`
450 /// use syn::{Path, Result, Token};
451 /// use syn::parse::{Parse, ParseStream};
453 /// // A simplified single `use` statement like:
455 /// // use std::collections::HashMap;
457 /// // Note that generic parameters are not allowed in a `use` statement
458 /// // so the following must not be accepted.
460 /// // use a::<b>::c;
461 /// struct SingleUse {
462 /// use_token: Token![use],
466 /// impl Parse for SingleUse {
467 /// fn parse(input: ParseStream) -> Result<Self> {
469 /// use_token: input.parse()?,
470 /// path: input.call(Path::parse_mod_style)?,
475 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
476 pub fn parse_mod_style(input
: ParseStream
) -> Result
<Self> {
478 leading_colon
: input
.parse()?
,
480 let mut segments
= Punctuated
::new();
482 if !input
.peek(Ident
)
483 && !input
.peek(Token
![super])
484 && !input
.peek(Token
![self])
485 && !input
.peek(Token
![Self])
486 && !input
.peek(Token
![crate])
490 let ident
= Ident
::parse_any(input
)?
;
491 segments
.push_value(PathSegment
::from(ident
));
492 if !input
.peek(Token
![::]) {
495 let punct
= input
.parse()?
;
496 segments
.push_punct(punct
);
498 if segments
.is_empty() {
499 return Err(input
.error("expected path"));
500 } else if segments
.trailing_punct() {
501 return Err(input
.error("expected path segment"));
508 /// Determines whether this is a path of length 1 equal to the given
511 /// For them to compare equal, it must be the case that:
513 /// - the path has no leading colon,
514 /// - the number of path segments is 1,
515 /// - the first path segment has no angle bracketed or parenthesized
516 /// path arguments, and
517 /// - the ident of the first path segment is equal to the given one.
519 /// *This function is available only if Syn is built with the `"parsing"`
525 /// use syn::{Attribute, Error, Meta, NestedMeta, Result};
526 /// # use std::iter::FromIterator;
528 /// fn get_serde_meta_items(attr: &Attribute) -> Result<Vec<NestedMeta>> {
529 /// if attr.path.is_ident("serde") {
530 /// match attr.parse_meta()? {
531 /// Meta::List(meta) => Ok(Vec::from_iter(meta.nested)),
532 /// bad => Err(Error::new_spanned(bad, "unrecognized attribute")),
539 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
540 pub fn is_ident
<I
: ?Sized
>(&self, ident
: &I
) -> bool
544 match self.get_ident() {
545 Some(id
) => id
== ident
,
550 /// If this path consists of a single ident, returns the ident.
552 /// A path is considered an ident if:
554 /// - the path has no leading colon,
555 /// - the number of path segments is 1, and
556 /// - the first path segment has no angle bracketed or parenthesized
559 /// *This function is available only if Syn is built with the `"parsing"`
561 #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
562 pub fn get_ident(&self) -> Option
<&Ident
> {
563 if self.leading_colon
.is_none()
564 && self.segments
.len() == 1
565 && self.segments
[0].arguments
.is_none()
567 Some(&self.segments
[0].ident
)
573 pub(crate) fn parse_helper(input
: ParseStream
, expr_style
: bool
) -> Result
<Self> {
574 let mut path
= Path
{
575 leading_colon
: input
.parse()?
,
577 let mut segments
= Punctuated
::new();
578 let value
= PathSegment
::parse_helper(input
, expr_style
)?
;
579 segments
.push_value(value
);
583 Path
::parse_rest(input
, &mut path
, expr_style
)?
;
587 pub(crate) fn parse_rest(
592 while input
.peek(Token
![::]) {
593 let punct
: Token
![::] = input
.parse()?
;
594 path
.segments
.push_punct(punct
);
595 let value
= PathSegment
::parse_helper(input
, expr_style
)?
;
596 path
.segments
.push_value(value
);
602 pub fn qpath(input
: ParseStream
, expr_style
: bool
) -> Result
<(Option
<QSelf
>, Path
)> {
603 if input
.peek(Token
![<]) {
604 let lt_token
: Token
![<] = input
.parse()?
;
605 let this
: Type
= input
.parse()?
;
606 let path
= if input
.peek(Token
![as]) {
607 let as_token
: Token
![as] = input
.parse()?
;
608 let path
: Path
= input
.parse()?
;
609 Some((as_token
, path
))
613 let gt_token
: Token
![>] = input
.parse()?
;
614 let colon2_token
: Token
![::] = input
.parse()?
;
615 let mut rest
= Punctuated
::new();
617 let path
= PathSegment
::parse_helper(input
, expr_style
)?
;
618 rest
.push_value(path
);
619 if !input
.peek(Token
![::]) {
622 let punct
: Token
![::] = input
.parse()?
;
623 rest
.push_punct(punct
);
625 let (position
, as_token
, path
) = match path
{
626 Some((as_token
, mut path
)) => {
627 let pos
= path
.segments
.len();
628 path
.segments
.push_punct(colon2_token
);
629 path
.segments
.extend(rest
.into_pairs());
630 (pos
, Some(as_token
), path
)
634 leading_colon
: Some(colon2_token
),
647 Ok((Some(qself
), path
))
649 let path
= Path
::parse_helper(input
, expr_style
)?
;
655 #[cfg(feature = "printing")]
658 use crate::print
::TokensOrDefault
;
659 use proc_macro2
::TokenStream
;
663 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
664 impl ToTokens
for Path
{
665 fn to_tokens(&self, tokens
: &mut TokenStream
) {
666 self.leading_colon
.to_tokens(tokens
);
667 self.segments
.to_tokens(tokens
);
671 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
672 impl ToTokens
for PathSegment
{
673 fn to_tokens(&self, tokens
: &mut TokenStream
) {
674 self.ident
.to_tokens(tokens
);
675 self.arguments
.to_tokens(tokens
);
679 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
680 impl ToTokens
for PathArguments
{
681 fn to_tokens(&self, tokens
: &mut TokenStream
) {
683 PathArguments
::None
=> {}
684 PathArguments
::AngleBracketed(arguments
) => {
685 arguments
.to_tokens(tokens
);
687 PathArguments
::Parenthesized(arguments
) => {
688 arguments
.to_tokens(tokens
);
694 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
695 impl ToTokens
for GenericArgument
{
696 #[allow(clippy::match_same_arms)]
697 fn to_tokens(&self, tokens
: &mut TokenStream
) {
699 GenericArgument
::Lifetime(lt
) => lt
.to_tokens(tokens
),
700 GenericArgument
::Type(ty
) => ty
.to_tokens(tokens
),
701 GenericArgument
::Binding(tb
) => tb
.to_tokens(tokens
),
702 GenericArgument
::Constraint(tc
) => tc
.to_tokens(tokens
),
703 GenericArgument
::Const(e
) => match *e
{
704 Expr
::Lit(_
) => e
.to_tokens(tokens
),
706 // NOTE: We should probably support parsing blocks with only
707 // expressions in them without the full feature for const
709 #[cfg(feature = "full")]
710 Expr
::Block(_
) => e
.to_tokens(tokens
),
712 // ERROR CORRECTION: Add braces to make sure that the
713 // generated code is valid.
714 _
=> token
::Brace
::default().surround(tokens
, |tokens
| {
722 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
723 impl ToTokens
for AngleBracketedGenericArguments
{
724 fn to_tokens(&self, tokens
: &mut TokenStream
) {
725 self.colon2_token
.to_tokens(tokens
);
726 self.lt_token
.to_tokens(tokens
);
728 // Print lifetimes before types and consts, all before bindings,
729 // regardless of their order in self.args.
731 // TODO: ordering rules for const arguments vs type arguments have
732 // not been settled yet. https://github.com/rust-lang/rust/issues/44580
733 let mut trailing_or_empty
= true;
734 for param
in self.args
.pairs() {
735 match **param
.value() {
736 GenericArgument
::Lifetime(_
) => {
737 param
.to_tokens(tokens
);
738 trailing_or_empty
= param
.punct().is_some();
740 GenericArgument
::Type(_
)
741 | GenericArgument
::Binding(_
)
742 | GenericArgument
::Constraint(_
)
743 | GenericArgument
::Const(_
) => {}
746 for param
in self.args
.pairs() {
747 match **param
.value() {
748 GenericArgument
::Type(_
) | GenericArgument
::Const(_
) => {
749 if !trailing_or_empty
{
750 <Token
![,]>::default().to_tokens(tokens
);
752 param
.to_tokens(tokens
);
753 trailing_or_empty
= param
.punct().is_some();
755 GenericArgument
::Lifetime(_
)
756 | GenericArgument
::Binding(_
)
757 | GenericArgument
::Constraint(_
) => {}
760 for param
in self.args
.pairs() {
761 match **param
.value() {
762 GenericArgument
::Binding(_
) | GenericArgument
::Constraint(_
) => {
763 if !trailing_or_empty
{
764 <Token
![,]>::default().to_tokens(tokens
);
766 param
.to_tokens(tokens
);
767 trailing_or_empty
= param
.punct().is_some();
769 GenericArgument
::Lifetime(_
)
770 | GenericArgument
::Type(_
)
771 | GenericArgument
::Const(_
) => {}
775 self.gt_token
.to_tokens(tokens
);
779 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
780 impl ToTokens
for Binding
{
781 fn to_tokens(&self, tokens
: &mut TokenStream
) {
782 self.ident
.to_tokens(tokens
);
783 self.eq_token
.to_tokens(tokens
);
784 self.ty
.to_tokens(tokens
);
788 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
789 impl ToTokens
for Constraint
{
790 fn to_tokens(&self, tokens
: &mut TokenStream
) {
791 self.ident
.to_tokens(tokens
);
792 self.colon_token
.to_tokens(tokens
);
793 self.bounds
.to_tokens(tokens
);
797 #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
798 impl ToTokens
for ParenthesizedGenericArguments
{
799 fn to_tokens(&self, tokens
: &mut TokenStream
) {
800 self.paren_token
.surround(tokens
, |tokens
| {
801 self.inputs
.to_tokens(tokens
);
803 self.output
.to_tokens(tokens
);
808 pub(crate) fn print_path(tokens
: &mut TokenStream
, qself
: &Option
<QSelf
>, path
: &Path
) {
809 let qself
= match qself
{
810 Some(qself
) => qself
,
812 path
.to_tokens(tokens
);
816 qself
.lt_token
.to_tokens(tokens
);
817 qself
.ty
.to_tokens(tokens
);
819 let pos
= cmp
::min(qself
.position
, path
.segments
.len());
820 let mut segments
= path
.segments
.pairs();
822 TokensOrDefault(&qself
.as_token
).to_tokens(tokens
);
823 path
.leading_colon
.to_tokens(tokens
);
824 for (i
, segment
) in segments
.by_ref().take(pos
).enumerate() {
826 segment
.value().to_tokens(tokens
);
827 qself
.gt_token
.to_tokens(tokens
);
828 segment
.punct().to_tokens(tokens
);
830 segment
.to_tokens(tokens
);
834 qself
.gt_token
.to_tokens(tokens
);
835 path
.leading_colon
.to_tokens(tokens
);
837 for segment
in segments
{
838 segment
.to_tokens(tokens
);