// SPDX-License-Identifier: Apache-2.0 OR MIT #[cfg(feature = "parsing")]use crate::error::Result;use crate::expr::Expr;use crate::generics::TypeParamBound;use crate::ident::Ident;use crate::lifetime::Lifetime;use crate::punctuated::Punctuated;use crate::token;use crate::ty::{ReturnType, Type}; ast_struct! { /// A path at which a named item is exported (e.g. `std::collections::HashMap`). #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct Path { pub leading_colon: Option<Token![::]>, pub segments: Punctuated<PathSegment, Token![::]>, }} impl<T> From<T> for Pathwhere T: Into<PathSegment>,{ fn from(segment: T) -> Self { let mut path = Path { leading_colon: None, segments: Punctuated::new(), }; path.segments.push_value(segment.into()); path }} impl Path { /// Determines whether this is a path of length 1 equal to the given /// ident. /// /// For them to compare equal, it must be the case that: /// /// - the path has no leading colon, /// - the number of path segments is 1, /// - the first path segment has no angle bracketed or parenthesized /// path arguments, and /// - the ident of the first path segment is equal to the given one. /// /// # Example /// /// ``` /// use proc_macro2::TokenStream; /// use syn::{Attribute, Error, Meta, Result}; /// /// fn get_serde_meta_item(attr: &Attribute) -> Result<Option<&TokenStream>> { /// if attr.path().is_ident("serde") { /// match &attr.meta { /// Meta::List(meta) => Ok(Some(&meta.tokens)), /// bad => Err(Error::new_spanned(bad, "unrecognized attribute")), /// } /// } else { /// Ok(None) /// } /// } /// ``` pub fn is_ident<I>(&self, ident: &I) -> bool where I: ?Sized, Ident: PartialEq<I>, { match self.get_ident() { Some(id) => id == ident, None => false, } } /// If this path consists of a single ident, returns the ident. /// /// A path is considered an ident if: /// /// - the path has no leading colon, /// - the number of path segments is 1, and /// - the first path segment has no angle bracketed or parenthesized /// path arguments. pub fn get_ident(&self) -> Option<&Ident> { if self.leading_colon.is_none() && self.segments.len() == 1 && self.segments[0].arguments.is_none() { Some(&self.segments[0].ident) } else { None } } /// An error if this path is not a single ident, as defined in `get_ident`. #[cfg(feature = "parsing")] #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub fn require_ident(&self) -> Result<&Ident> { self.get_ident().ok_or_else(|| { crate::error::new2( self.segments.first().unwrap().ident.span(), self.segments.last().unwrap().ident.span(), "expected this path to be an identifier", ) }) }} ast_struct! { /// A segment of a path together with any path arguments on that segment. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct PathSegment { pub ident: Ident, pub arguments: PathArguments, }} impl<T> From<T> for PathSegmentwhere T: Into<Ident>,{ fn from(ident: T) -> Self { PathSegment { ident: ident.into(), arguments: PathArguments::None, } }} ast_enum! { /// Angle bracketed or parenthesized arguments of a path segment. /// /// ## Angle bracketed /// /// The `<'a, T>` in `std::slice::iter<'a, T>`. /// /// ## Parenthesized /// /// The `(A, B) -> C` in `Fn(A, B) -> C`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub enum PathArguments { None, /// The `<'a, T>` in `std::slice::iter<'a, T>`. AngleBracketed(AngleBracketedGenericArguments), /// The `(A, B) -> C` in `Fn(A, B) -> C`. Parenthesized(ParenthesizedGenericArguments), }} impl Default for PathArguments { fn default() -> Self { PathArguments::None }} impl PathArguments { pub fn is_empty(&self) -> bool { match self { PathArguments::None => true, PathArguments::AngleBracketed(bracketed) => bracketed.args.is_empty(), PathArguments::Parenthesized(_) => false, } } pub fn is_none(&self) -> bool { match self { PathArguments::None => true, PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false, } }} ast_enum! { /// An individual generic argument, like `'a`, `T`, or `Item = T`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] #[non_exhaustive] pub enum GenericArgument { /// A lifetime argument. Lifetime(Lifetime), /// A type argument. Type(Type), /// A const expression. Must be inside of a block. /// /// NOTE: Identity expressions are represented as Type arguments, as /// they are indistinguishable syntactically. Const(Expr), /// A binding (equality constraint) on an associated type: the `Item = /// u8` in `Iterator<Item = u8>`. AssocType(AssocType), /// An equality constraint on an associated constant: the `PANIC = /// false` in `Trait<PANIC = false>`. AssocConst(AssocConst), /// An associated type bound: `Iterator<Item: Display>`. Constraint(Constraint), }} ast_struct! { /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K, /// V>`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct AngleBracketedGenericArguments { pub colon2_token: Option<Token![::]>, pub lt_token: Token![<], pub args: Punctuated<GenericArgument, Token![,]>, pub gt_token: Token![>], }} ast_struct! { /// A binding (equality constraint) on an associated type: the `Item = u8` /// in `Iterator<Item = u8>`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct AssocType { pub ident: Ident, pub generics: Option<AngleBracketedGenericArguments>, pub eq_token: Token![=], pub ty: Type, }} ast_struct! { /// An equality constraint on an associated constant: the `PANIC = false` in /// `Trait<PANIC = false>`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct AssocConst { pub ident: Ident, pub generics: Option<AngleBracketedGenericArguments>, pub eq_token: Token![=], pub value: Expr, }} ast_struct! { /// An associated type bound: `Iterator<Item: Display>`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct Constraint { pub ident: Ident, pub generics: Option<AngleBracketedGenericArguments>, pub colon_token: Token![:], pub bounds: Punctuated<TypeParamBound, Token![+]>, }} ast_struct! { /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) -> /// C`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct ParenthesizedGenericArguments { pub paren_token: token::Paren, /// `(A, B)` pub inputs: Punctuated<Type, Token![,]>, /// `C` pub output: ReturnType, }} ast_struct! { /// The explicit Self type in a qualified path: the `T` in `<T as /// Display>::fmt`. /// /// The actual path, including the trait and the associated item, is stored /// separately. The `position` field represents the index of the associated /// item qualified with this Self type. /// /// ```text /// <Vec<T> as a::b::Trait>::AssociatedItem /// ^~~~~~ ~~~~~~~~~~~~~~^ /// ty position = 3 /// /// <Vec<T>>::AssociatedItem /// ^~~~~~ ^ /// ty position = 0 /// ``` #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct QSelf { pub lt_token: Token![<], pub ty: Box<Type>, pub position: usize, pub as_token: Option<Token![as]>, pub gt_token: Token![>], }} #[cfg(feature = "parsing")]pub(crate) mod parsing { use crate::error::Result; #[cfg(feature = "full")] use crate::expr::ExprBlock; use crate::expr::{Expr, ExprPath}; use crate::ext::IdentExt as _; #[cfg(feature = "full")] use crate::generics::TypeParamBound; use crate::ident::Ident; use crate::lifetime::Lifetime; use crate::lit::Lit; use crate::parse::{Parse, ParseStream}; #[cfg(feature = "full")] use crate::path::Constraint; use crate::path::{ AngleBracketedGenericArguments, AssocConst, AssocType, GenericArgument, ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, }; use crate::punctuated::Punctuated; use crate::token; use crate::ty::{ReturnType, Type}; #[cfg(not(feature = "full"))] use crate::verbatim; #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] impl Parse for Path { fn parse(input: ParseStream) -> Result<Self> { Self::parse_helper(input, false) } } #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] impl Parse for GenericArgument { fn parse(input: ParseStream) -> Result<Self> { if input.peek(Lifetime) && !input.peek2(Token![+]) { return Ok(GenericArgument::Lifetime(input.parse()?)); } if input.peek(Lit) || input.peek(token::Brace) { return const_argument(input).map(GenericArgument::Const); } let mut argument: Type = input.parse()?; match argument { Type::Path(mut ty) if ty.qself.is_none() && ty.path.leading_colon.is_none() && ty.path.segments.len() == 1 && match &ty.path.segments[0].arguments { PathArguments::None | PathArguments::AngleBracketed(_) => true, PathArguments::Parenthesized(_) => false, } => { if let Some(eq_token) = input.parse::<Option<Token![=]>>()? { let segment = ty.path.segments.pop().unwrap().into_value(); let ident = segment.ident; let generics = match segment.arguments { PathArguments::None => None, PathArguments::AngleBracketed(arguments) => Some(arguments), PathArguments::Parenthesized(_) => unreachable!(), }; return if input.peek(Lit) || input.peek(token::Brace) { Ok(GenericArgument::AssocConst(AssocConst { ident, generics, eq_token, value: const_argument(input)?, })) } else { Ok(GenericArgument::AssocType(AssocType { ident, generics, eq_token, ty: input.parse()?, })) }; } #[cfg(feature = "full")] if let Some(colon_token) = input.parse::<Option<Token![:]>>()? { let segment = ty.path.segments.pop().unwrap().into_value(); return Ok(GenericArgument::Constraint(Constraint { ident: segment.ident, generics: match segment.arguments { PathArguments::None => None, PathArguments::AngleBracketed(arguments) => Some(arguments), PathArguments::Parenthesized(_) => unreachable!(), }, colon_token, bounds: { let mut bounds = Punctuated::new(); loop { if input.peek(Token![,]) || input.peek(Token![>]) { break; } bounds.push_value({ let allow_precise_capture = false; let allow_const = true; TypeParamBound::parse_single( input, allow_precise_capture, allow_const, )? }); if !input.peek(Token![+]) { break; } let punct: Token![+] = input.parse()?; bounds.push_punct(punct); } bounds }, })); } argument = Type::Path(ty); } _ => {} } Ok(GenericArgument::Type(argument)) } } pub(crate) fn const_argument(input: ParseStream) -> Result<Expr> { let lookahead = input.lookahead1(); if input.peek(Lit) { let lit = input.parse()?; return Ok(Expr::Lit(lit)); } 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()) } impl AngleBracketedGenericArguments { /// Parse `::<…>` with mandatory leading `::`. /// /// The ordinary [`Parse`] impl for `AngleBracketedGenericArguments` /// parses optional leading `::`. #[cfg(feature = "full")] #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))] pub fn parse_turbofish(input: ParseStream) -> Result<Self> { let colon2_token: Token![::] = input.parse()?; Self::do_parse(Some(colon2_token), input) } pub(crate) fn do_parse( colon2_token: Option<Token![::]>, input: ParseStream, ) -> Result<Self> { Ok(AngleBracketedGenericArguments { colon2_token, lt_token: input.parse()?, args: { let mut args = Punctuated::new(); loop { if input.peek(Token![>]) { break; } let value: GenericArgument = input.parse()?; args.push_value(value); if input.peek(Token![>]) { break; } let punct: Token![,] = input.parse()?; args.push_punct(punct); } args }, gt_token: input.parse()?, }) } } #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] impl Parse for AngleBracketedGenericArguments { fn parse(input: ParseStream) -> Result<Self> { let colon2_token: Option<Token![::]> = input.parse()?; Self::do_parse(colon2_token, input) } } #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] impl Parse for ParenthesizedGenericArguments { fn parse(input: ParseStream) -> Result<Self> { let content;Lines 1–500 of 968. Load more
// SPDX-License-Identifier: Apache-2.0 OR MIT #[cfg(feature = "parsing")] use crate::error::Result; use crate::expr::Expr; use crate::generics::TypeParamBound; use crate::ident::Ident; use crate::lifetime::Lifetime; use crate::punctuated::Punctuated; use crate::token; use crate::ty::{ReturnType, Type}; ast_struct! { /// A path at which a named item is exported (e.g. `std::collections::HashMap`). #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct Path { pub leading_colon: Option<Token![::]>, pub segments: Punctuated<PathSegment, Token![::]>, } } impl<T> From<T> for Path where T: Into<PathSegment>, { fn from(segment: T) -> Self { let mut path = Path { leading_colon: None, segments: Punctuated::new(), }; path.segments.push_value(segment.into()); path } } impl Path { /// Determines whether this is a path of length 1 equal to the given /// ident. /// /// For them to compare equal, it must be the case that: /// /// - the path has no leading colon, /// - the number of path segments is 1, /// - the first path segment has no angle bracketed or parenthesized /// path arguments, and /// - the ident of the first path segment is equal to the given one. /// /// # Example /// /// ``` /// use proc_macro2::TokenStream; /// use syn::{Attribute, Error, Meta, Result}; /// /// fn get_serde_meta_item(attr: &Attribute) -> Result<Option<&TokenStream>> { /// if attr.path().is_ident("serde") { /// match &attr.meta { /// Meta::List(meta) => Ok(Some(&meta.tokens)), /// bad => Err(Error::new_spanned(bad, "unrecognized attribute")), /// } /// } else { /// Ok(None) /// } /// } /// ``` pub fn is_ident<I>(&self, ident: &I) -> bool where I: ?Sized, Ident: PartialEq<I>, { match self.get_ident() { Some(id) => id == ident, None => false, } } /// If this path consists of a single ident, returns the ident. /// /// A path is considered an ident if: /// /// - the path has no leading colon, /// - the number of path segments is 1, and /// - the first path segment has no angle bracketed or parenthesized /// path arguments. pub fn get_ident(&self) -> Option<&Ident> { if self.leading_colon.is_none() && self.segments.len() == 1 && self.segments[0].arguments.is_none() { Some(&self.segments[0].ident) } else { None } } /// An error if this path is not a single ident, as defined in `get_ident`. #[cfg(feature = "parsing")] #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub fn require_ident(&self) -> Result<&Ident> { self.get_ident().ok_or_else(|| { crate::error::new2( self.segments.first().unwrap().ident.span(), self.segments.last().unwrap().ident.span(), "expected this path to be an identifier", ) }) } } ast_struct! { /// A segment of a path together with any path arguments on that segment. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct PathSegment { pub ident: Ident, pub arguments: PathArguments, } } impl<T> From<T> for PathSegment where T: Into<Ident>, { fn from(ident: T) -> Self { PathSegment { ident: ident.into(), arguments: PathArguments::None, } } } ast_enum! { /// Angle bracketed or parenthesized arguments of a path segment. /// /// ## Angle bracketed /// /// The `<'a, T>` in `std::slice::iter<'a, T>`. /// /// ## Parenthesized /// /// The `(A, B) -> C` in `Fn(A, B) -> C`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub enum PathArguments { None, /// The `<'a, T>` in `std::slice::iter<'a, T>`. AngleBracketed(AngleBracketedGenericArguments), /// The `(A, B) -> C` in `Fn(A, B) -> C`. Parenthesized(ParenthesizedGenericArguments), } } impl Default for PathArguments { fn default() -> Self { PathArguments::None } } impl PathArguments { pub fn is_empty(&self) -> bool { match self { PathArguments::None => true, PathArguments::AngleBracketed(bracketed) => bracketed.args.is_empty(), PathArguments::Parenthesized(_) => false, } } pub fn is_none(&self) -> bool { match self { PathArguments::None => true, PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => false, } } } ast_enum! { /// An individual generic argument, like `'a`, `T`, or `Item = T`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] #[non_exhaustive] pub enum GenericArgument { /// A lifetime argument. Lifetime(Lifetime), /// A type argument. Type(Type), /// A const expression. Must be inside of a block. /// /// NOTE: Identity expressions are represented as Type arguments, as /// they are indistinguishable syntactically. Const(Expr), /// A binding (equality constraint) on an associated type: the `Item = /// u8` in `Iterator<Item = u8>`. AssocType(AssocType), /// An equality constraint on an associated constant: the `PANIC = /// false` in `Trait<PANIC = false>`. AssocConst(AssocConst), /// An associated type bound: `Iterator<Item: Display>`. Constraint(Constraint), } } ast_struct! { /// Angle bracketed arguments of a path segment: the `<K, V>` in `HashMap<K, /// V>`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct AngleBracketedGenericArguments { pub colon2_token: Option<Token![::]>, pub lt_token: Token![<], pub args: Punctuated<GenericArgument, Token![,]>, pub gt_token: Token![>], } } ast_struct! { /// A binding (equality constraint) on an associated type: the `Item = u8` /// in `Iterator<Item = u8>`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct AssocType { pub ident: Ident, pub generics: Option<AngleBracketedGenericArguments>, pub eq_token: Token![=], pub ty: Type, } } ast_struct! { /// An equality constraint on an associated constant: the `PANIC = false` in /// `Trait<PANIC = false>`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct AssocConst { pub ident: Ident, pub generics: Option<AngleBracketedGenericArguments>, pub eq_token: Token![=], pub value: Expr, } } ast_struct! { /// An associated type bound: `Iterator<Item: Display>`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct Constraint { pub ident: Ident, pub generics: Option<AngleBracketedGenericArguments>, pub colon_token: Token![:], pub bounds: Punctuated<TypeParamBound, Token![+]>, } } ast_struct! { /// Arguments of a function path segment: the `(A, B) -> C` in `Fn(A,B) -> /// C`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct ParenthesizedGenericArguments { pub paren_token: token::Paren, /// `(A, B)` pub inputs: Punctuated<Type, Token![,]>, /// `C` pub output: ReturnType, } } ast_struct! { /// The explicit Self type in a qualified path: the `T` in `<T as /// Display>::fmt`. /// /// The actual path, including the trait and the associated item, is stored /// separately. The `position` field represents the index of the associated /// item qualified with this Self type. /// /// ```text /// <Vec<T> as a::b::Trait>::AssociatedItem /// ^~~~~~ ~~~~~~~~~~~~~~^ /// ty position = 3 /// /// <Vec<T>>::AssociatedItem /// ^~~~~~ ^ /// ty position = 0 /// ``` #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct QSelf { pub lt_token: Token![<], pub ty: Box<Type>, pub position: usize, pub as_token: Option<Token![as]>, pub gt_token: Token![>], } } #[cfg(feature = "parsing")] pub(crate) mod parsing { use crate::error::Result; #[cfg(feature = "full")] use crate::expr::ExprBlock; use crate::expr::{Expr, ExprPath}; use crate::ext::IdentExt as _; #[cfg(feature = "full")] use crate::generics::TypeParamBound; use crate::ident::Ident; use crate::lifetime::Lifetime; use crate::lit::Lit; use crate::parse::{Parse, ParseStream}; #[cfg(feature = "full")] use crate::path::Constraint; use crate::path::{ AngleBracketedGenericArguments, AssocConst, AssocType, GenericArgument, ParenthesizedGenericArguments, Path, PathArguments, PathSegment, QSelf, }; use crate::punctuated::Punctuated; use crate::token; use crate::ty::{ReturnType, Type}; #[cfg(not(feature = "full"))] use crate::verbatim; #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] impl Parse for Path { fn parse(input: ParseStream) -> Result<Self> { Self::parse_helper(input, false) } } #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] impl Parse for GenericArgument { fn parse(input: ParseStream) -> Result<Self> { if input.peek(Lifetime) && !input.peek2(Token![+]) { return Ok(GenericArgument::Lifetime(input.parse()?)); } if input.peek(Lit) || input.peek(token::Brace) { return const_argument(input).map(GenericArgument::Const); } let mut argument: Type = input.parse()?; match argument { Type::Path(mut ty) if ty.qself.is_none() && ty.path.leading_colon.is_none() && ty.path.segments.len() == 1 && match &ty.path.segments[0].arguments { PathArguments::None | PathArguments::AngleBracketed(_) => true, PathArguments::Parenthesized(_) => false, } => { if let Some(eq_token) = input.parse::<Option<Token![=]>>()? { let segment = ty.path.segments.pop().unwrap().into_value(); let ident = segment.ident; let generics = match segment.arguments { PathArguments::None => None, PathArguments::AngleBracketed(arguments) => Some(arguments), PathArguments::Parenthesized(_) => unreachable!(), }; return if input.peek(Lit) || input.peek(token::Brace) { Ok(GenericArgument::AssocConst(AssocConst { ident, generics, eq_token, value: const_argument(input)?, })) } else { Ok(GenericArgument::AssocType(AssocType { ident, generics, eq_token, ty: input.parse()?, })) }; } #[cfg(feature = "full")] if let Some(colon_token) = input.parse::<Option<Token![:]>>()? { let segment = ty.path.segments.pop().unwrap().into_value(); return Ok(GenericArgument::Constraint(Constraint { ident: segment.ident, generics: match segment.arguments { PathArguments::None => None, PathArguments::AngleBracketed(arguments) => Some(arguments), PathArguments::Parenthesized(_) => unreachable!(), }, colon_token, bounds: { let mut bounds = Punctuated::new(); loop { if input.peek(Token![,]) || input.peek(Token![>]) { break; } bounds.push_value({ let allow_precise_capture = false; let allow_const = true; TypeParamBound::parse_single( input, allow_precise_capture, allow_const, )? }); if !input.peek(Token![+]) { break; } let punct: Token![+] = input.parse()?; bounds.push_punct(punct); } bounds }, })); } argument = Type::Path(ty); } _ => {} } Ok(GenericArgument::Type(argument)) } } pub(crate) fn const_argument(input: ParseStream) -> Result<Expr> { let lookahead = input.lookahead1(); if input.peek(Lit) { let lit = input.parse()?; return Ok(Expr::Lit(lit)); } 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()) } impl AngleBracketedGenericArguments { /// Parse `::<…>` with mandatory leading `::`. /// /// The ordinary [`Parse`] impl for `AngleBracketedGenericArguments` /// parses optional leading `::`. #[cfg(feature = "full")] #[cfg_attr(docsrs, doc(cfg(all(feature = "parsing", feature = "full"))))] pub fn parse_turbofish(input: ParseStream) -> Result<Self> { let colon2_token: Token![::] = input.parse()?; Self::do_parse(Some(colon2_token), input) } pub(crate) fn do_parse( colon2_token: Option<Token![::]>, input: ParseStream, ) -> Result<Self> { Ok(AngleBracketedGenericArguments { colon2_token, lt_token: input.parse()?, args: { let mut args = Punctuated::new(); loop { if input.peek(Token![>]) { break; } let value: GenericArgument = input.parse()?; args.push_value(value); if input.peek(Token![>]) { break; } let punct: Token![,] = input.parse()?; args.push_punct(punct); } args }, gt_token: input.parse()?, }) } } #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] impl Parse for AngleBracketedGenericArguments { fn parse(input: ParseStream) -> Result<Self> { let colon2_token: Option<Token![::]> = input.parse()?; Self::do_parse(colon2_token, input) } } #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] impl Parse for ParenthesizedGenericArguments { fn parse(input: ParseStream) -> Result<Self> { let content;