///
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
/// feature.*
+ #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
pub struct Path {
pub leading_colon: Option<Token![::]>,
pub segments: Punctuated<PathSegment, Token![::]>,
///
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
/// feature.*
+ #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
pub struct PathSegment {
pub ident: Ident,
pub arguments: PathArguments,
/// ## Parenthesized
///
/// The `(A, B) -> C` in `Fn(A, B) -> C`.
+ #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
pub enum PathArguments {
None,
/// The `<'a, T>` in `std::slice::iter<'a, T>`.
///
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
/// feature.*
+ #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
pub enum GenericArgument {
/// A lifetime argument.
Lifetime(Lifetime),
///
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
/// feature.*
+ #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
pub struct AngleBracketedGenericArguments {
pub colon2_token: Option<Token![::]>,
pub lt_token: Token![<],
///
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
/// feature.*
+ #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
pub struct Binding {
pub ident: Ident,
pub eq_token: Token![=],
///
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
/// feature.*
+ #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
pub struct Constraint {
pub ident: Ident,
pub colon_token: Token![:],
///
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
/// feature.*
+ #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
pub struct ParenthesizedGenericArguments {
pub paren_token: token::Paren,
/// `(A, B)`
///
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
/// feature.*
+ #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
pub struct QSelf {
pub lt_token: Token![<],
pub ty: Box<Type>,
pub mod parsing {
use super::*;
- #[cfg(feature = "full")]
- use crate::expr;
use crate::ext::IdentExt;
use crate::parse::{Parse, ParseStream, Result};
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
impl Parse for Path {
fn parse(input: ParseStream) -> Result<Self> {
Self::parse_helper(input, false)
}
}
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
impl Parse for GenericArgument {
fn parse(input: ParseStream) -> Result<Self> {
if input.peek(Lifetime) && !input.peek2(Token![+]) {
if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) {
return Ok(GenericArgument::Constraint(input.parse()?));
}
+ }
- if input.peek(Lit) {
- let lit = input.parse()?;
- return Ok(GenericArgument::Const(Expr::Lit(lit)));
- }
+ if input.peek(Lit) || input.peek(token::Brace) {
+ return const_argument(input).map(GenericArgument::Const);
+ }
+
+ #[cfg(feature = "full")]
+ let begin = input.fork();
+
+ let argument: Type = input.parse()?;
- if input.peek(token::Brace) {
- let block = input.call(expr::parsing::expr_block)?;
- return Ok(GenericArgument::Const(Expr::Block(block)));
+ #[cfg(feature = "full")]
+ {
+ if match &argument {
+ Type::Path(argument)
+ if argument.qself.is_none()
+ && argument.path.leading_colon.is_none()
+ && argument.path.segments.len() == 1 =>
+ {
+ match argument.path.segments[0].arguments {
+ PathArguments::AngleBracketed(_) => true,
+ _ => false,
+ }
+ }
+ _ => false,
+ } && if input.peek(Token![=]) {
+ input.parse::<Token![=]>()?;
+ input.parse::<Type>()?;
+ true
+ } else if input.peek(Token![:]) {
+ input.parse::<Token![:]>()?;
+ input.call(constraint_bounds)?;
+ true
+ } else {
+ false
+ } {
+ let verbatim = verbatim::between(begin, input);
+ return Ok(GenericArgument::Type(Type::Verbatim(verbatim)));
}
}
- input.parse().map(GenericArgument::Type)
+ Ok(GenericArgument::Type(argument))
+ }
+ }
+
+ pub fn const_argument(input: ParseStream) -> Result<Expr> {
+ let lookahead = input.lookahead1();
+
+ if input.peek(Lit) {
+ let lit = input.parse()?;
+ return Ok(Expr::Lit(lit));
+ }
+
+ #[cfg(feature = "full")]
+ {
+ if input.peek(Ident) {
+ let ident: Ident = input.parse()?;
+ return Ok(Expr::Path(ExprPath {
+ attrs: Vec::new(),
+ qself: None,
+ path: Path::from(ident),
+ }));
+ }
+ }
+
+ if input.peek(token::Brace) {
+ #[cfg(feature = "full")]
+ {
+ let block: ExprBlock = input.parse()?;
+ return Ok(Expr::Block(block));
+ }
+
+ #[cfg(not(feature = "full"))]
+ {
+ let begin = input.fork();
+ let content;
+ braced!(content in input);
+ content.parse::<Expr>()?;
+ let verbatim = verbatim::between(begin, input);
+ return Ok(Expr::Verbatim(verbatim));
+ }
}
+
+ Err(lookahead.error())
}
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
impl Parse for AngleBracketedGenericArguments {
fn parse(input: ParseStream) -> Result<Self> {
Ok(AngleBracketedGenericArguments {
}
}
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
impl Parse for ParenthesizedGenericArguments {
fn parse(input: ParseStream) -> Result<Self> {
let content;
}
}
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
impl Parse for PathSegment {
fn parse(input: ParseStream) -> Result<Self> {
Self::parse_helper(input, false)
}
}
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
impl Parse for Binding {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Binding {
}
#[cfg(feature = "full")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
impl Parse for Constraint {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Constraint {
ident: input.parse()?,
colon_token: input.parse()?,
- bounds: {
- let mut bounds = Punctuated::new();
- loop {
- if input.peek(Token![,]) || input.peek(Token![>]) {
- break;
- }
- let value = input.parse()?;
- bounds.push_value(value);
- if !input.peek(Token![+]) {
- break;
- }
- let punct = input.parse()?;
- bounds.push_punct(punct);
- }
- bounds
- },
+ bounds: constraint_bounds(input)?,
})
}
}
+ #[cfg(feature = "full")]
+ fn constraint_bounds(input: ParseStream) -> Result<Punctuated<TypeParamBound, Token![+]>> {
+ let mut bounds = Punctuated::new();
+ loop {
+ if input.peek(Token![,]) || input.peek(Token![>]) {
+ break;
+ }
+ let value = input.parse()?;
+ bounds.push_value(value);
+ if !input.peek(Token![+]) {
+ break;
+ }
+ let punct = input.parse()?;
+ bounds.push_punct(punct);
+ }
+ Ok(bounds)
+ }
+
impl Path {
/// Parse a `Path` containing no path arguments on any of its segments.
///
/// }
/// }
/// ```
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
pub fn parse_mod_style(input: ParseStream) -> Result<Self> {
Ok(Path {
leading_colon: input.parse()?,
/// }
/// }
/// ```
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
pub fn is_ident<I: ?Sized>(&self, ident: &I) -> bool
where
Ident: PartialEq<I>,
///
/// *This function is available only if Syn is built with the `"parsing"`
/// feature.*
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
pub fn get_ident(&self) -> Option<&Ident> {
if self.leading_colon.is_none()
&& self.segments.len() == 1
}
}
- fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
- Ok(Path {
+ pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
+ let mut path = Path {
leading_colon: input.parse()?,
segments: {
let mut segments = Punctuated::new();
let value = PathSegment::parse_helper(input, expr_style)?;
segments.push_value(value);
- while input.peek(Token![::]) {
- let punct: Token![::] = input.parse()?;
- segments.push_punct(punct);
- let value = PathSegment::parse_helper(input, expr_style)?;
- segments.push_value(value);
- }
segments
},
- })
+ };
+ Path::parse_rest(input, &mut path, expr_style)?;
+ Ok(path)
+ }
+
+ pub(crate) fn parse_rest(
+ input: ParseStream,
+ path: &mut Self,
+ expr_style: bool,
+ ) -> Result<()> {
+ while input.peek(Token![::]) {
+ let punct: Token![::] = input.parse()?;
+ path.segments.push_punct(punct);
+ let value = PathSegment::parse_helper(input, expr_style)?;
+ path.segments.push_value(value);
+ }
+ Ok(())
}
}
use quote::ToTokens;
use std::cmp;
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
impl ToTokens for Path {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.leading_colon.to_tokens(tokens);
}
}
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
impl ToTokens for PathSegment {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.ident.to_tokens(tokens);
}
}
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
impl ToTokens for PathArguments {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
}
}
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
impl ToTokens for GenericArgument {
#[allow(clippy::match_same_arms)]
fn to_tokens(&self, tokens: &mut TokenStream) {
}
}
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
impl ToTokens for AngleBracketedGenericArguments {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.colon2_token.to_tokens(tokens);
GenericArgument::Binding(_) | GenericArgument::Constraint(_) => {
if !trailing_or_empty {
<Token![,]>::default().to_tokens(tokens);
- trailing_or_empty = true;
}
param.to_tokens(tokens);
+ trailing_or_empty = param.punct().is_some();
}
GenericArgument::Lifetime(_)
| GenericArgument::Type(_)
}
}
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
impl ToTokens for Binding {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.ident.to_tokens(tokens);
}
}
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
impl ToTokens for Constraint {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.ident.to_tokens(tokens);
}
}
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
impl ToTokens for ParenthesizedGenericArguments {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.paren_token.surround(tokens, |tokens| {
}
impl private {
- pub fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
+ pub(crate) fn print_path(tokens: &mut TokenStream, qself: &Option<QSelf>, path: &Path) {
let qself = match qself {
Some(qself) => qself,
None => {