usecrate::attr::Attribute; usecrate::expr::Expr; usecrate::ident::Ident; usecrate::lifetime::Lifetime; usecrate::path::Path; usecrate::punctuated::{Iter, IterMut, Punctuated}; usecrate::token; usecrate::ty::Type; use proc_macro2::TokenStream; #[cfg(all(feature = "printing", feature = "extra-traits"))] use std::fmt::{self, Debug}; #[cfg(all(feature = "printing", feature = "extra-traits"))] use std::hash::{Hash, Hasher};
ast_struct! { /// Lifetimes and type parameters attached to a declaration of a function, /// enum, trait, etc. /// /// This struct represents two distinct optional syntactic elements, /// [generic parameters] and [where clause]. In some locations of the /// grammar, there may be other tokens in between these two things. /// /// [generic parameters]: https://doc.rust-lang.org/stable/reference/items/generics.html#generic-parameters /// [where clause]: https://doc.rust-lang.org/stable/reference/items/generics.html#where-clauses #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pubstruct Generics { pub lt_token: Option<Token![<]>, pub params: Punctuated<GenericParam, Token![,]>, pub gt_token: Option<Token![>]>, pub where_clause: Option<WhereClause>,
}
}
ast_enum_of_structs! { /// A generic type parameter, lifetime, or const generic: `T: Into<String>`, /// `'a: 'b`, `const LEN: usize`. /// /// # Syntax tree enum /// /// This type is a [syntax tree enum]. /// /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pubenum GenericParam { /// A lifetime parameter: `'a: 'b + 'c + 'd`.
Lifetime(LifetimeParam),
/// A generic type parameter: `T: Into<String>`. Type(TypeParam),
impl Generics {
return_impl_trait! { /// Iterator over the lifetime parameters in `self.params`. pub fn lifetimes(&self) -> impl Iterator<Item = &LifetimeParam> [Lifetimes] {
Lifetimes(self.params.iter())
}
}
return_impl_trait! { /// Iterator over the lifetime parameters in `self.params`. pub fn lifetimes_mut(&mutself) -> impl Iterator<Item = &mut LifetimeParam> [LifetimesMut] {
LifetimesMut(self.params.iter_mut())
}
}
return_impl_trait! { /// Iterator over the type parameters in `self.params`. pub fn type_params(&self) -> impl Iterator<Item = &TypeParam> [TypeParams] {
TypeParams(self.params.iter())
}
}
return_impl_trait! { /// Iterator over the type parameters in `self.params`. pub fn type_params_mut(&mutself) -> impl Iterator<Item = &='color:red'>mut TypeParam> [TypeParamsMut] {
TypeParamsMut(self.params.iter_mut())
}
}
return_impl_trait! { /// Iterator over the constant parameters in `self.params`. pub fn const_params(&self) -> impl Iterator<Item = &ConstParam> [ConstParams] {
ConstParams(self.params.iter())
}
}
return_impl_trait! { /// Iterator over the constant parameters in `self.params`. pub fn const_params_mut(&mutself) -> impl Iterator<Item = &e='color:red'>mut ConstParam> [ConstParamsMut] {
ConstParamsMut(self.params.iter_mut())
}
}
/// Initializes an empty `where`-clause if there is not one present already. pub fn make_where_clause(&mutself) -> &mut WhereClause { self.where_clause.get_or_insert_with(|| WhereClause {
where_token: <Token![where]>::default(),
predicates: Punctuated::new(),
})
}
/// Split a type's generics into the pieces required for impl'ing a trait /// for that type. /// /// ``` /// # use proc_macro2::{Span, Ident}; /// # use quote::quote; /// # /// # let generics: syn::Generics = Default::default(); /// # let name = Ident::new("MyType", Span::call_site()); /// # /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); /// quote! { /// impl #impl_generics MyTrait for #name #ty_generics #where_clause { /// // ... /// } /// } /// # ; /// ``` #[cfg(feature = "printing")] #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] pub fn split_for_impl(&self) -> (ImplGenerics, TypeGenerics, Option<&WhereClause>) {
(
ImplGenerics(self),
TypeGenerics(self), self.where_clause.as_ref(),
)
}
}
pubstruct Lifetimes<'a>(Iter<'a, GenericParam>);
impl<'a> Iterator for Lifetimes<'a> { type Item = &'a LifetimeParam;
ast_enum_of_structs! { /// A trait or lifetime used as a bound on a type parameter. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] #[non_exhaustive] pubenum TypeParamBound { Trait(TraitBound),
Lifetime(Lifetime),
PreciseCapture(PreciseCapture),
Verbatim(TokenStream),
}
}
ast_struct! { /// A trait used as a bound on a type parameter. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pubstruct TraitBound { pub paren_token: Option<token::Paren>, pub modifier: TraitBoundModifier, /// The `for<'a>` in `for<'a> Foo<&'a T>` pub lifetimes: Option<BoundLifetimes>, /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>` pub path: Path,
}
}
ast_enum! { /// A modifier on a trait bound, currently only used for the `?` in /// `?Sized`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pubenum TraitBoundModifier {
None,
Maybe(Token![?]),
}
}
ast_enum_of_structs! { /// A single predicate in a `where` clause: `T: Deserialize<'de>`. /// /// # Syntax tree enum /// /// This type is a [syntax tree enum]. /// /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] #[non_exhaustive] pubenum WherePredicate { /// A lifetime predicate in a `where` clause: `'a: 'b + 'c`.
Lifetime(PredicateLifetime),
/// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`. Type(PredicateType),
}
}
let is_conditionally_const = cfg!(feature = "full") && input.peek(token::Bracket); let is_unconditionally_const = cfg!(feature = "full") && input.peek(Token![const]); if is_conditionally_const { let conditionally_const; let bracket_token = bracketed!(conditionally_const in input);
conditionally_const.parse::<Token![const]>()?; if !allow_const { let msg = "`[const]` is not allowed here"; return Err(Error::new(bracket_token.span.join(), msg));
}
} elseif is_unconditionally_const { let const_token: Token![const] = input.parse()?; if !allow_const { let msg = "`const` is not allowed here"; return Err(Error::new(const_token.span, msg));
}
}
let modifier: TraitBoundModifier = input.parse()?; if lifetimes.is_none() && matches!(modifier, TraitBoundModifier::Maybe(_)) {
lifetimes = input.parse()?;
}
letmut path: Path = input.parse()?; if path.segments.last().unwrap().arguments.is_empty()
&& (input.peek(token::Paren) || input.peek(Token![::]) && input.peek3(token::Paren))
{
input.parse::<Option<Token![::]>>()?; let args: ParenthesizedGenericArguments = input.parse()?; let parenthesized = PathArguments::Parenthesized(args);
path.segments.last_mut().unwrap().arguments = parenthesized;
}
if lifetimes.is_some() { match modifier {
TraitBoundModifier::None => {}
TraitBoundModifier::Maybe(maybe) => { let msg = "`for<...>` binder not allowed with `?` trait polarity modifier"; return Err(Error::new(maybe.span, msg));
}
}
}
pub(crate) fn choose_generics_over_qpath(input: ParseStream) -> bool { // Rust syntax has an ambiguity between generic parameters and qualified // paths. In `impl <T> :: Thing<T, U> {}` this may either be a generic // inherent impl `impl<T> ::Thing<T, U>` or a non-generic inherent impl // for an associated type `impl <T>::Thing<T, U>`. // // After `<` the following continuations can only begin generics, not a // qualified path: // // `<` `>` - empty generic parameters // `<` `#` - generic parameters with attribute // `<` LIFETIME `>` - single lifetime parameter // `<` (LIFETIME|IDENT) `,` - first generic parameter in a list // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds // `<` (LIFETIME|IDENT) `=` - generic parameter with a default // `<` const - generic const parameter // // The only truly ambiguous case is: // // `<` IDENT `>` `::` IDENT ... // // which we disambiguate in favor of generics because this is almost // always the expected one in the context of real-world code.
input.peek(Token![<])
&& (input.peek2(Token![>])
|| input.peek2(Token![#])
|| (input.peek2(Lifetime) || input.peek2(Ident))
&& (input.peek3(Token![>])
|| input.peek3(Token![,])
|| input.peek3(Token![:]) && !input.peek3(Token![::])
|| input.peek3(Token![=]))
|| input.peek2(Token![const]))
}
#[cfg(feature = "full")] pub(crate) fn choose_generics_over_qpath_after_keyword(input: ParseStream) -> bool { let input = input.fork();
input.call(Ident::parse_any).unwrap(); // `impl` or `for` or `where`
choose_generics_over_qpath(&input)
}
}
// Print lifetimes before types and consts, regardless of their // order in self.params. letmut trailing_or_empty = true;
for param in self.0.params.pairs() { iflet GenericParam::Lifetime(def) = *param.value() { // Leave off the lifetime bounds and attributes
def.lifetime.to_tokens(tokens);
param.punct().to_tokens(tokens);
trailing_or_empty = param.punct().is_some();
}
}
for param in self.0.params.pairs() { iflet GenericParam::Lifetime(_) = **param.value() { continue;
} if !trailing_or_empty {
<Token![,]>::default().to_tokens(tokens);
trailing_or_empty = true;
} match param.value() {
GenericParam::Lifetime(_) => unreachable!(),
GenericParam::Type(param) => { // Leave off the type parameter defaults
param.ident.to_tokens(tokens);
}
GenericParam::Const(param) => { // Leave off the const parameter defaults
param.ident.to_tokens(tokens);
}
}
param.punct().to_tokens(tokens);
}
// Print lifetimes before types and consts, regardless of their // order in self.params. letmut trailing_or_empty = true;
for param in self.params.pairs() { iflet CapturedParam::Lifetime(_) = **param.value() {
param.to_tokens(tokens);
trailing_or_empty = param.punct().is_some();
}
}
for param in self.params.pairs() { iflet CapturedParam::Ident(_) = **param.value() { if !trailing_or_empty {
<Token![,]>::default().to_tokens(tokens);
trailing_or_empty = true;
}
param.to_tokens(tokens);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.