1338 lines
45 KiB
Rust
1338 lines
45 KiB
Rust
use super::*;
|
|
use crate::punctuated::{Iter, IterMut, Punctuated};
|
|
#[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 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 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`.
|
|
///
|
|
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
|
/// feature.*
|
|
///
|
|
/// # Syntax tree enum
|
|
///
|
|
/// This type is a [syntax tree enum].
|
|
///
|
|
/// [syntax tree enum]: Expr#syntax-tree-enums
|
|
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
|
pub enum GenericParam {
|
|
/// A generic type parameter: `T: Into<String>`.
|
|
Type(TypeParam),
|
|
|
|
/// A lifetime definition: `'a: 'b + 'c + 'd`.
|
|
Lifetime(LifetimeDef),
|
|
|
|
/// A const generic parameter: `const LENGTH: usize`.
|
|
Const(ConstParam),
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A generic type parameter: `T: Into<String>`.
|
|
///
|
|
/// *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 TypeParam {
|
|
pub attrs: Vec<Attribute>,
|
|
pub ident: Ident,
|
|
pub colon_token: Option<Token![:]>,
|
|
pub bounds: Punctuated<TypeParamBound, Token![+]>,
|
|
pub eq_token: Option<Token![=]>,
|
|
pub default: Option<Type>,
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A lifetime definition: `'a: 'b + 'c + 'd`.
|
|
///
|
|
/// *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 LifetimeDef {
|
|
pub attrs: Vec<Attribute>,
|
|
pub lifetime: Lifetime,
|
|
pub colon_token: Option<Token![:]>,
|
|
pub bounds: Punctuated<Lifetime, Token![+]>,
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A const generic parameter: `const LENGTH: usize`.
|
|
///
|
|
/// *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 ConstParam {
|
|
pub attrs: Vec<Attribute>,
|
|
pub const_token: Token![const],
|
|
pub ident: Ident,
|
|
pub colon_token: Token![:],
|
|
pub ty: Type,
|
|
pub eq_token: Option<Token![=]>,
|
|
pub default: Option<Expr>,
|
|
}
|
|
}
|
|
|
|
impl Default for Generics {
|
|
fn default() -> Self {
|
|
Generics {
|
|
lt_token: None,
|
|
params: Punctuated::new(),
|
|
gt_token: None,
|
|
where_clause: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Generics {
|
|
/// Returns an
|
|
/// <code
|
|
/// style="padding-right:0;">Iterator<Item = &</code><a
|
|
/// href="struct.TypeParam.html"><code
|
|
/// style="padding-left:0;padding-right:0;">TypeParam</code></a><code
|
|
/// style="padding-left:0;">></code>
|
|
/// over the type parameters in `self.params`.
|
|
pub fn type_params(&self) -> TypeParams {
|
|
TypeParams(self.params.iter())
|
|
}
|
|
|
|
/// Returns an
|
|
/// <code
|
|
/// style="padding-right:0;">Iterator<Item = &mut </code><a
|
|
/// href="struct.TypeParam.html"><code
|
|
/// style="padding-left:0;padding-right:0;">TypeParam</code></a><code
|
|
/// style="padding-left:0;">></code>
|
|
/// over the type parameters in `self.params`.
|
|
pub fn type_params_mut(&mut self) -> TypeParamsMut {
|
|
TypeParamsMut(self.params.iter_mut())
|
|
}
|
|
|
|
/// Returns an
|
|
/// <code
|
|
/// style="padding-right:0;">Iterator<Item = &</code><a
|
|
/// href="struct.LifetimeDef.html"><code
|
|
/// style="padding-left:0;padding-right:0;">LifetimeDef</code></a><code
|
|
/// style="padding-left:0;">></code>
|
|
/// over the lifetime parameters in `self.params`.
|
|
pub fn lifetimes(&self) -> Lifetimes {
|
|
Lifetimes(self.params.iter())
|
|
}
|
|
|
|
/// Returns an
|
|
/// <code
|
|
/// style="padding-right:0;">Iterator<Item = &mut </code><a
|
|
/// href="struct.LifetimeDef.html"><code
|
|
/// style="padding-left:0;padding-right:0;">LifetimeDef</code></a><code
|
|
/// style="padding-left:0;">></code>
|
|
/// over the lifetime parameters in `self.params`.
|
|
pub fn lifetimes_mut(&mut self) -> LifetimesMut {
|
|
LifetimesMut(self.params.iter_mut())
|
|
}
|
|
|
|
/// Returns an
|
|
/// <code
|
|
/// style="padding-right:0;">Iterator<Item = &</code><a
|
|
/// href="struct.ConstParam.html"><code
|
|
/// style="padding-left:0;padding-right:0;">ConstParam</code></a><code
|
|
/// style="padding-left:0;">></code>
|
|
/// over the constant parameters in `self.params`.
|
|
pub fn const_params(&self) -> ConstParams {
|
|
ConstParams(self.params.iter())
|
|
}
|
|
|
|
/// Returns an
|
|
/// <code
|
|
/// style="padding-right:0;">Iterator<Item = &mut </code><a
|
|
/// href="struct.ConstParam.html"><code
|
|
/// style="padding-left:0;padding-right:0;">ConstParam</code></a><code
|
|
/// style="padding-left:0;">></code>
|
|
/// over the constant parameters in `self.params`.
|
|
pub fn const_params_mut(&mut self) -> ConstParamsMut {
|
|
ConstParamsMut(self.params.iter_mut())
|
|
}
|
|
|
|
/// Initializes an empty `where`-clause if there is not one present already.
|
|
pub fn make_where_clause(&mut self) -> &mut WhereClause {
|
|
self.where_clause.get_or_insert_with(|| WhereClause {
|
|
where_token: <Token![where]>::default(),
|
|
predicates: Punctuated::new(),
|
|
})
|
|
}
|
|
}
|
|
|
|
pub struct TypeParams<'a>(Iter<'a, GenericParam>);
|
|
|
|
impl<'a> Iterator for TypeParams<'a> {
|
|
type Item = &'a TypeParam;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let next = match self.0.next() {
|
|
Some(item) => item,
|
|
None => return None,
|
|
};
|
|
if let GenericParam::Type(type_param) = next {
|
|
Some(type_param)
|
|
} else {
|
|
self.next()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct TypeParamsMut<'a>(IterMut<'a, GenericParam>);
|
|
|
|
impl<'a> Iterator for TypeParamsMut<'a> {
|
|
type Item = &'a mut TypeParam;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let next = match self.0.next() {
|
|
Some(item) => item,
|
|
None => return None,
|
|
};
|
|
if let GenericParam::Type(type_param) = next {
|
|
Some(type_param)
|
|
} else {
|
|
self.next()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Lifetimes<'a>(Iter<'a, GenericParam>);
|
|
|
|
impl<'a> Iterator for Lifetimes<'a> {
|
|
type Item = &'a LifetimeDef;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let next = match self.0.next() {
|
|
Some(item) => item,
|
|
None => return None,
|
|
};
|
|
if let GenericParam::Lifetime(lifetime) = next {
|
|
Some(lifetime)
|
|
} else {
|
|
self.next()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct LifetimesMut<'a>(IterMut<'a, GenericParam>);
|
|
|
|
impl<'a> Iterator for LifetimesMut<'a> {
|
|
type Item = &'a mut LifetimeDef;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let next = match self.0.next() {
|
|
Some(item) => item,
|
|
None => return None,
|
|
};
|
|
if let GenericParam::Lifetime(lifetime) = next {
|
|
Some(lifetime)
|
|
} else {
|
|
self.next()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct ConstParams<'a>(Iter<'a, GenericParam>);
|
|
|
|
impl<'a> Iterator for ConstParams<'a> {
|
|
type Item = &'a ConstParam;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let next = match self.0.next() {
|
|
Some(item) => item,
|
|
None => return None,
|
|
};
|
|
if let GenericParam::Const(const_param) = next {
|
|
Some(const_param)
|
|
} else {
|
|
self.next()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct ConstParamsMut<'a>(IterMut<'a, GenericParam>);
|
|
|
|
impl<'a> Iterator for ConstParamsMut<'a> {
|
|
type Item = &'a mut ConstParam;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
let next = match self.0.next() {
|
|
Some(item) => item,
|
|
None => return None,
|
|
};
|
|
if let GenericParam::Const(const_param) = next {
|
|
Some(const_param)
|
|
} else {
|
|
self.next()
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Returned by `Generics::split_for_impl`.
|
|
///
|
|
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
|
/// feature and the `"printing"` feature.*
|
|
#[cfg(feature = "printing")]
|
|
#[cfg_attr(
|
|
doc_cfg,
|
|
doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing")))
|
|
)]
|
|
pub struct ImplGenerics<'a>(&'a Generics);
|
|
|
|
/// Returned by `Generics::split_for_impl`.
|
|
///
|
|
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
|
/// feature and the `"printing"` feature.*
|
|
#[cfg(feature = "printing")]
|
|
#[cfg_attr(
|
|
doc_cfg,
|
|
doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing")))
|
|
)]
|
|
pub struct TypeGenerics<'a>(&'a Generics);
|
|
|
|
/// Returned by `TypeGenerics::as_turbofish`.
|
|
///
|
|
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
|
/// feature and the `"printing"` feature.*
|
|
#[cfg(feature = "printing")]
|
|
#[cfg_attr(
|
|
doc_cfg,
|
|
doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing")))
|
|
)]
|
|
pub struct Turbofish<'a>(&'a Generics);
|
|
|
|
#[cfg(feature = "printing")]
|
|
impl Generics {
|
|
/// 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 {
|
|
/// // ...
|
|
/// }
|
|
/// }
|
|
/// # ;
|
|
/// ```
|
|
///
|
|
/// *This method is available only if Syn is built with the `"derive"` or
|
|
/// `"full"` feature and the `"printing"` feature.*
|
|
#[cfg_attr(
|
|
doc_cfg,
|
|
doc(cfg(all(any(feature = "full", feature = "derive"), feature = "printing")))
|
|
)]
|
|
pub fn split_for_impl(&self) -> (ImplGenerics, TypeGenerics, Option<&WhereClause>) {
|
|
(
|
|
ImplGenerics(self),
|
|
TypeGenerics(self),
|
|
self.where_clause.as_ref(),
|
|
)
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "printing")]
|
|
macro_rules! generics_wrapper_impls {
|
|
($ty:ident) => {
|
|
#[cfg(feature = "clone-impls")]
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "clone-impls")))]
|
|
impl<'a> Clone for $ty<'a> {
|
|
fn clone(&self) -> Self {
|
|
$ty(self.0)
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "extra-traits")]
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
|
impl<'a> Debug for $ty<'a> {
|
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter
|
|
.debug_tuple(stringify!($ty))
|
|
.field(self.0)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "extra-traits")]
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
|
impl<'a> Eq for $ty<'a> {}
|
|
|
|
#[cfg(feature = "extra-traits")]
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
|
impl<'a> PartialEq for $ty<'a> {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.0 == other.0
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "extra-traits")]
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
|
|
impl<'a> Hash for $ty<'a> {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
self.0.hash(state);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
#[cfg(feature = "printing")]
|
|
generics_wrapper_impls!(ImplGenerics);
|
|
#[cfg(feature = "printing")]
|
|
generics_wrapper_impls!(TypeGenerics);
|
|
#[cfg(feature = "printing")]
|
|
generics_wrapper_impls!(Turbofish);
|
|
|
|
#[cfg(feature = "printing")]
|
|
impl<'a> TypeGenerics<'a> {
|
|
/// Turn a type's generics like `<X, Y>` into a turbofish like `::<X, Y>`.
|
|
///
|
|
/// *This method is available only if Syn is built with the `"derive"` or
|
|
/// `"full"` feature and the `"printing"` feature.*
|
|
pub fn as_turbofish(&self) -> Turbofish {
|
|
Turbofish(self.0)
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A set of bound lifetimes: `for<'a, 'b, 'c>`.
|
|
///
|
|
/// *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 BoundLifetimes {
|
|
pub for_token: Token![for],
|
|
pub lt_token: Token![<],
|
|
pub lifetimes: Punctuated<LifetimeDef, Token![,]>,
|
|
pub gt_token: Token![>],
|
|
}
|
|
}
|
|
|
|
impl Default for BoundLifetimes {
|
|
fn default() -> Self {
|
|
BoundLifetimes {
|
|
for_token: Default::default(),
|
|
lt_token: Default::default(),
|
|
lifetimes: Punctuated::new(),
|
|
gt_token: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl LifetimeDef {
|
|
pub fn new(lifetime: Lifetime) -> Self {
|
|
LifetimeDef {
|
|
attrs: Vec::new(),
|
|
lifetime,
|
|
colon_token: None,
|
|
bounds: Punctuated::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Ident> for TypeParam {
|
|
fn from(ident: Ident) -> Self {
|
|
TypeParam {
|
|
attrs: vec![],
|
|
ident,
|
|
colon_token: None,
|
|
bounds: Punctuated::new(),
|
|
eq_token: None,
|
|
default: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
ast_enum_of_structs! {
|
|
/// A trait or lifetime used as a bound on a type parameter.
|
|
///
|
|
/// *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 TypeParamBound {
|
|
Trait(TraitBound),
|
|
Lifetime(Lifetime),
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A trait used as a bound on a type parameter.
|
|
///
|
|
/// *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 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`.
|
|
///
|
|
/// *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 TraitBoundModifier {
|
|
None,
|
|
Maybe(Token![?]),
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A `where` clause in a definition: `where T: Deserialize<'de>, D:
|
|
/// 'static`.
|
|
///
|
|
/// *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 WhereClause {
|
|
pub where_token: Token![where],
|
|
pub predicates: Punctuated<WherePredicate, Token![,]>,
|
|
}
|
|
}
|
|
|
|
ast_enum_of_structs! {
|
|
/// A single predicate in a `where` clause: `T: Deserialize<'de>`.
|
|
///
|
|
/// *This type is available only if Syn is built with the `"derive"` or `"full"`
|
|
/// feature.*
|
|
///
|
|
/// # Syntax tree enum
|
|
///
|
|
/// This type is a [syntax tree enum].
|
|
///
|
|
/// [syntax tree enum]: Expr#syntax-tree-enums
|
|
#[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
|
|
pub enum WherePredicate {
|
|
/// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`.
|
|
Type(PredicateType),
|
|
|
|
/// A lifetime predicate in a `where` clause: `'a: 'b + 'c`.
|
|
Lifetime(PredicateLifetime),
|
|
|
|
/// An equality predicate in a `where` clause (unsupported).
|
|
Eq(PredicateEq),
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`.
|
|
///
|
|
/// *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 PredicateType {
|
|
/// Any lifetimes from a `for` binding
|
|
pub lifetimes: Option<BoundLifetimes>,
|
|
/// The type being bounded
|
|
pub bounded_ty: Type,
|
|
pub colon_token: Token![:],
|
|
/// Trait and lifetime bounds (`Clone+Send+'static`)
|
|
pub bounds: Punctuated<TypeParamBound, Token![+]>,
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// A lifetime predicate in a `where` clause: `'a: 'b + 'c`.
|
|
///
|
|
/// *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 PredicateLifetime {
|
|
pub lifetime: Lifetime,
|
|
pub colon_token: Token![:],
|
|
pub bounds: Punctuated<Lifetime, Token![+]>,
|
|
}
|
|
}
|
|
|
|
ast_struct! {
|
|
/// An equality predicate in a `where` clause (unsupported).
|
|
///
|
|
/// *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 PredicateEq {
|
|
pub lhs_ty: Type,
|
|
pub eq_token: Token![=],
|
|
pub rhs_ty: Type,
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "parsing")]
|
|
pub mod parsing {
|
|
use super::*;
|
|
use crate::ext::IdentExt;
|
|
use crate::parse::{Parse, ParseStream, Result};
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
|
impl Parse for Generics {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
if !input.peek(Token![<]) {
|
|
return Ok(Generics::default());
|
|
}
|
|
|
|
let lt_token: Token![<] = input.parse()?;
|
|
|
|
let mut params = Punctuated::new();
|
|
loop {
|
|
if input.peek(Token![>]) {
|
|
break;
|
|
}
|
|
|
|
let attrs = input.call(Attribute::parse_outer)?;
|
|
let lookahead = input.lookahead1();
|
|
if lookahead.peek(Lifetime) {
|
|
params.push_value(GenericParam::Lifetime(LifetimeDef {
|
|
attrs,
|
|
..input.parse()?
|
|
}));
|
|
} else if lookahead.peek(Ident) {
|
|
params.push_value(GenericParam::Type(TypeParam {
|
|
attrs,
|
|
..input.parse()?
|
|
}));
|
|
} else if lookahead.peek(Token![const]) {
|
|
params.push_value(GenericParam::Const(ConstParam {
|
|
attrs,
|
|
..input.parse()?
|
|
}));
|
|
} else if input.peek(Token![_]) {
|
|
params.push_value(GenericParam::Type(TypeParam {
|
|
attrs,
|
|
ident: input.call(Ident::parse_any)?,
|
|
colon_token: None,
|
|
bounds: Punctuated::new(),
|
|
eq_token: None,
|
|
default: None,
|
|
}));
|
|
} else {
|
|
return Err(lookahead.error());
|
|
}
|
|
|
|
if input.peek(Token![>]) {
|
|
break;
|
|
}
|
|
let punct = input.parse()?;
|
|
params.push_punct(punct);
|
|
}
|
|
|
|
let gt_token: Token![>] = input.parse()?;
|
|
|
|
Ok(Generics {
|
|
lt_token: Some(lt_token),
|
|
params,
|
|
gt_token: Some(gt_token),
|
|
where_clause: None,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
|
impl Parse for GenericParam {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
let attrs = input.call(Attribute::parse_outer)?;
|
|
|
|
let lookahead = input.lookahead1();
|
|
if lookahead.peek(Ident) {
|
|
Ok(GenericParam::Type(TypeParam {
|
|
attrs,
|
|
..input.parse()?
|
|
}))
|
|
} else if lookahead.peek(Lifetime) {
|
|
Ok(GenericParam::Lifetime(LifetimeDef {
|
|
attrs,
|
|
..input.parse()?
|
|
}))
|
|
} else if lookahead.peek(Token![const]) {
|
|
Ok(GenericParam::Const(ConstParam {
|
|
attrs,
|
|
..input.parse()?
|
|
}))
|
|
} else {
|
|
Err(lookahead.error())
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
|
impl Parse for LifetimeDef {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
let has_colon;
|
|
Ok(LifetimeDef {
|
|
attrs: input.call(Attribute::parse_outer)?,
|
|
lifetime: input.parse()?,
|
|
colon_token: {
|
|
if input.peek(Token![:]) {
|
|
has_colon = true;
|
|
Some(input.parse()?)
|
|
} else {
|
|
has_colon = false;
|
|
None
|
|
}
|
|
},
|
|
bounds: {
|
|
let mut bounds = Punctuated::new();
|
|
if has_colon {
|
|
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
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
|
impl Parse for BoundLifetimes {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
Ok(BoundLifetimes {
|
|
for_token: input.parse()?,
|
|
lt_token: input.parse()?,
|
|
lifetimes: {
|
|
let mut lifetimes = Punctuated::new();
|
|
while !input.peek(Token![>]) {
|
|
lifetimes.push_value(input.parse()?);
|
|
if input.peek(Token![>]) {
|
|
break;
|
|
}
|
|
lifetimes.push_punct(input.parse()?);
|
|
}
|
|
lifetimes
|
|
},
|
|
gt_token: input.parse()?,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
|
impl Parse for Option<BoundLifetimes> {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
if input.peek(Token![for]) {
|
|
input.parse().map(Some)
|
|
} else {
|
|
Ok(None)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
|
impl Parse for TypeParam {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
let attrs = input.call(Attribute::parse_outer)?;
|
|
let ident: Ident = input.parse()?;
|
|
let colon_token: Option<Token![:]> = input.parse()?;
|
|
|
|
let begin_bound = input.fork();
|
|
let mut is_maybe_const = false;
|
|
let mut bounds = Punctuated::new();
|
|
if colon_token.is_some() {
|
|
loop {
|
|
if input.peek(Token![,]) || input.peek(Token![>]) || input.peek(Token![=]) {
|
|
break;
|
|
}
|
|
if input.peek(Token![~]) && input.peek2(Token![const]) {
|
|
input.parse::<Token![~]>()?;
|
|
input.parse::<Token![const]>()?;
|
|
is_maybe_const = true;
|
|
}
|
|
let value: TypeParamBound = input.parse()?;
|
|
bounds.push_value(value);
|
|
if !input.peek(Token![+]) {
|
|
break;
|
|
}
|
|
let punct: Token![+] = input.parse()?;
|
|
bounds.push_punct(punct);
|
|
}
|
|
}
|
|
|
|
let mut eq_token: Option<Token![=]> = input.parse()?;
|
|
let mut default = if eq_token.is_some() {
|
|
Some(input.parse::<Type>()?)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
if is_maybe_const {
|
|
bounds.clear();
|
|
eq_token = None;
|
|
default = Some(Type::Verbatim(verbatim::between(begin_bound, input)));
|
|
}
|
|
|
|
Ok(TypeParam {
|
|
attrs,
|
|
ident,
|
|
colon_token,
|
|
bounds,
|
|
eq_token,
|
|
default,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
|
impl Parse for TypeParamBound {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
if input.peek(Lifetime) {
|
|
return input.parse().map(TypeParamBound::Lifetime);
|
|
}
|
|
|
|
if input.peek(token::Paren) {
|
|
let content;
|
|
let paren_token = parenthesized!(content in input);
|
|
let mut bound: TraitBound = content.parse()?;
|
|
bound.paren_token = Some(paren_token);
|
|
return Ok(TypeParamBound::Trait(bound));
|
|
}
|
|
|
|
input.parse().map(TypeParamBound::Trait)
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
|
impl Parse for TraitBound {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
#[cfg(feature = "full")]
|
|
let tilde_const = if input.peek(Token![~]) && input.peek2(Token![const]) {
|
|
let tilde_token = input.parse::<Token![~]>()?;
|
|
let const_token = input.parse::<Token![const]>()?;
|
|
Some((tilde_token, const_token))
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let modifier: TraitBoundModifier = input.parse()?;
|
|
let lifetimes: Option<BoundLifetimes> = input.parse()?;
|
|
|
|
let mut 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;
|
|
}
|
|
|
|
#[cfg(feature = "full")]
|
|
{
|
|
if let Some((tilde_token, const_token)) = tilde_const {
|
|
path.segments.insert(
|
|
0,
|
|
PathSegment {
|
|
ident: Ident::new("const", const_token.span),
|
|
arguments: PathArguments::None,
|
|
},
|
|
);
|
|
let (_const, punct) = path.segments.pairs_mut().next().unwrap().into_tuple();
|
|
*punct.unwrap() = Token;
|
|
}
|
|
}
|
|
|
|
Ok(TraitBound {
|
|
paren_token: None,
|
|
modifier,
|
|
lifetimes,
|
|
path,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
|
impl Parse for TraitBoundModifier {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
if input.peek(Token![?]) {
|
|
input.parse().map(TraitBoundModifier::Maybe)
|
|
} else {
|
|
Ok(TraitBoundModifier::None)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
|
impl Parse for ConstParam {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
let mut default = None;
|
|
Ok(ConstParam {
|
|
attrs: input.call(Attribute::parse_outer)?,
|
|
const_token: input.parse()?,
|
|
ident: input.parse()?,
|
|
colon_token: input.parse()?,
|
|
ty: input.parse()?,
|
|
eq_token: {
|
|
if input.peek(Token![=]) {
|
|
let eq_token = input.parse()?;
|
|
default = Some(path::parsing::const_argument(input)?);
|
|
Some(eq_token)
|
|
} else {
|
|
None
|
|
}
|
|
},
|
|
default,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
|
impl Parse for WhereClause {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
Ok(WhereClause {
|
|
where_token: input.parse()?,
|
|
predicates: {
|
|
let mut predicates = Punctuated::new();
|
|
loop {
|
|
if input.is_empty()
|
|
|| input.peek(token::Brace)
|
|
|| input.peek(Token![,])
|
|
|| input.peek(Token![;])
|
|
|| input.peek(Token![:]) && !input.peek(Token![::])
|
|
|| input.peek(Token![=])
|
|
{
|
|
break;
|
|
}
|
|
let value = input.parse()?;
|
|
predicates.push_value(value);
|
|
if !input.peek(Token![,]) {
|
|
break;
|
|
}
|
|
let punct = input.parse()?;
|
|
predicates.push_punct(punct);
|
|
}
|
|
predicates
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
|
impl Parse for Option<WhereClause> {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
if input.peek(Token![where]) {
|
|
input.parse().map(Some)
|
|
} else {
|
|
Ok(None)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
|
|
impl Parse for WherePredicate {
|
|
fn parse(input: ParseStream) -> Result<Self> {
|
|
if input.peek(Lifetime) && input.peek2(Token![:]) {
|
|
Ok(WherePredicate::Lifetime(PredicateLifetime {
|
|
lifetime: input.parse()?,
|
|
colon_token: input.parse()?,
|
|
bounds: {
|
|
let mut bounds = Punctuated::new();
|
|
loop {
|
|
if input.is_empty()
|
|
|| input.peek(token::Brace)
|
|
|| input.peek(Token![,])
|
|
|| input.peek(Token![;])
|
|
|| 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
|
|
},
|
|
}))
|
|
} else {
|
|
Ok(WherePredicate::Type(PredicateType {
|
|
lifetimes: input.parse()?,
|
|
bounded_ty: input.parse()?,
|
|
colon_token: input.parse()?,
|
|
bounds: {
|
|
let mut bounds = Punctuated::new();
|
|
loop {
|
|
if input.is_empty()
|
|
|| input.peek(token::Brace)
|
|
|| input.peek(Token![,])
|
|
|| input.peek(Token![;])
|
|
|| input.peek(Token![:]) && !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
|
|
},
|
|
}))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "printing")]
|
|
mod printing {
|
|
use super::*;
|
|
use crate::attr::FilterAttrs;
|
|
use crate::print::TokensOrDefault;
|
|
#[cfg(feature = "full")]
|
|
use crate::punctuated::Pair;
|
|
use proc_macro2::TokenStream;
|
|
#[cfg(feature = "full")]
|
|
use proc_macro2::TokenTree;
|
|
use quote::{ToTokens, TokenStreamExt};
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for Generics {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
if self.params.is_empty() {
|
|
return;
|
|
}
|
|
|
|
TokensOrDefault(&self.lt_token).to_tokens(tokens);
|
|
|
|
// Print lifetimes before types and consts, regardless of their
|
|
// order in self.params.
|
|
//
|
|
// TODO: ordering rules for const parameters vs type parameters have
|
|
// not been settled yet. https://github.com/rust-lang/rust/issues/44580
|
|
let mut trailing_or_empty = true;
|
|
for param in self.params.pairs() {
|
|
if let GenericParam::Lifetime(_) = **param.value() {
|
|
param.to_tokens(tokens);
|
|
trailing_or_empty = param.punct().is_some();
|
|
}
|
|
}
|
|
for param in self.params.pairs() {
|
|
match **param.value() {
|
|
GenericParam::Type(_) | GenericParam::Const(_) => {
|
|
if !trailing_or_empty {
|
|
<Token![,]>::default().to_tokens(tokens);
|
|
trailing_or_empty = true;
|
|
}
|
|
param.to_tokens(tokens);
|
|
}
|
|
GenericParam::Lifetime(_) => {}
|
|
}
|
|
}
|
|
|
|
TokensOrDefault(&self.gt_token).to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
impl<'a> ToTokens for ImplGenerics<'a> {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
if self.0.params.is_empty() {
|
|
return;
|
|
}
|
|
|
|
TokensOrDefault(&self.0.lt_token).to_tokens(tokens);
|
|
|
|
// Print lifetimes before types and consts, regardless of their
|
|
// order in self.params.
|
|
//
|
|
// TODO: ordering rules for const parameters vs type parameters have
|
|
// not been settled yet. https://github.com/rust-lang/rust/issues/44580
|
|
let mut trailing_or_empty = true;
|
|
for param in self.0.params.pairs() {
|
|
if let GenericParam::Lifetime(_) = **param.value() {
|
|
param.to_tokens(tokens);
|
|
trailing_or_empty = param.punct().is_some();
|
|
}
|
|
}
|
|
for param in self.0.params.pairs() {
|
|
if let 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
|
|
tokens.append_all(param.attrs.outer());
|
|
param.ident.to_tokens(tokens);
|
|
if !param.bounds.is_empty() {
|
|
TokensOrDefault(¶m.colon_token).to_tokens(tokens);
|
|
param.bounds.to_tokens(tokens);
|
|
}
|
|
}
|
|
GenericParam::Const(param) => {
|
|
// Leave off the const parameter defaults
|
|
tokens.append_all(param.attrs.outer());
|
|
param.const_token.to_tokens(tokens);
|
|
param.ident.to_tokens(tokens);
|
|
param.colon_token.to_tokens(tokens);
|
|
param.ty.to_tokens(tokens);
|
|
}
|
|
}
|
|
param.punct().to_tokens(tokens);
|
|
}
|
|
|
|
TokensOrDefault(&self.0.gt_token).to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
impl<'a> ToTokens for TypeGenerics<'a> {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
if self.0.params.is_empty() {
|
|
return;
|
|
}
|
|
|
|
TokensOrDefault(&self.0.lt_token).to_tokens(tokens);
|
|
|
|
// Print lifetimes before types and consts, regardless of their
|
|
// order in self.params.
|
|
//
|
|
// TODO: ordering rules for const parameters vs type parameters have
|
|
// not been settled yet. https://github.com/rust-lang/rust/issues/44580
|
|
let mut trailing_or_empty = true;
|
|
for param in self.0.params.pairs() {
|
|
if let 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() {
|
|
if let 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);
|
|
}
|
|
|
|
TokensOrDefault(&self.0.gt_token).to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
impl<'a> ToTokens for Turbofish<'a> {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
if !self.0.params.is_empty() {
|
|
<Token![::]>::default().to_tokens(tokens);
|
|
TypeGenerics(self.0).to_tokens(tokens);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for BoundLifetimes {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
self.for_token.to_tokens(tokens);
|
|
self.lt_token.to_tokens(tokens);
|
|
self.lifetimes.to_tokens(tokens);
|
|
self.gt_token.to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for LifetimeDef {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
tokens.append_all(self.attrs.outer());
|
|
self.lifetime.to_tokens(tokens);
|
|
if !self.bounds.is_empty() {
|
|
TokensOrDefault(&self.colon_token).to_tokens(tokens);
|
|
self.bounds.to_tokens(tokens);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for TypeParam {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
tokens.append_all(self.attrs.outer());
|
|
self.ident.to_tokens(tokens);
|
|
if !self.bounds.is_empty() {
|
|
TokensOrDefault(&self.colon_token).to_tokens(tokens);
|
|
self.bounds.to_tokens(tokens);
|
|
}
|
|
if let Some(default) = &self.default {
|
|
#[cfg(feature = "full")]
|
|
{
|
|
if self.eq_token.is_none() {
|
|
if let Type::Verbatim(default) = default {
|
|
let mut iter = default.clone().into_iter().peekable();
|
|
while let Some(token) = iter.next() {
|
|
if let TokenTree::Punct(q) = token {
|
|
if q.as_char() == '~' {
|
|
if let Some(TokenTree::Ident(c)) = iter.peek() {
|
|
if c == "const" {
|
|
if self.bounds.is_empty() {
|
|
TokensOrDefault(&self.colon_token)
|
|
.to_tokens(tokens);
|
|
}
|
|
return default.to_tokens(tokens);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
TokensOrDefault(&self.eq_token).to_tokens(tokens);
|
|
default.to_tokens(tokens);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for TraitBound {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
let to_tokens = |tokens: &mut TokenStream| {
|
|
#[cfg(feature = "full")]
|
|
let skip = match self.path.segments.pairs().next() {
|
|
Some(Pair::Punctuated(t, p)) if t.ident == "const" => {
|
|
Token.to_tokens(tokens);
|
|
t.to_tokens(tokens);
|
|
1
|
|
}
|
|
_ => 0,
|
|
};
|
|
self.modifier.to_tokens(tokens);
|
|
self.lifetimes.to_tokens(tokens);
|
|
#[cfg(feature = "full")]
|
|
{
|
|
self.path.leading_colon.to_tokens(tokens);
|
|
tokens.append_all(self.path.segments.pairs().skip(skip));
|
|
}
|
|
#[cfg(not(feature = "full"))]
|
|
{
|
|
self.path.to_tokens(tokens);
|
|
}
|
|
};
|
|
match &self.paren_token {
|
|
Some(paren) => paren.surround(tokens, to_tokens),
|
|
None => to_tokens(tokens),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for TraitBoundModifier {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
match self {
|
|
TraitBoundModifier::None => {}
|
|
TraitBoundModifier::Maybe(t) => t.to_tokens(tokens),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for ConstParam {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
tokens.append_all(self.attrs.outer());
|
|
self.const_token.to_tokens(tokens);
|
|
self.ident.to_tokens(tokens);
|
|
self.colon_token.to_tokens(tokens);
|
|
self.ty.to_tokens(tokens);
|
|
if let Some(default) = &self.default {
|
|
TokensOrDefault(&self.eq_token).to_tokens(tokens);
|
|
default.to_tokens(tokens);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for WhereClause {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
if !self.predicates.is_empty() {
|
|
self.where_token.to_tokens(tokens);
|
|
self.predicates.to_tokens(tokens);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for PredicateType {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
self.lifetimes.to_tokens(tokens);
|
|
self.bounded_ty.to_tokens(tokens);
|
|
self.colon_token.to_tokens(tokens);
|
|
self.bounds.to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for PredicateLifetime {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
self.lifetime.to_tokens(tokens);
|
|
self.colon_token.to_tokens(tokens);
|
|
self.bounds.to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
|
|
impl ToTokens for PredicateEq {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
self.lhs_ty.to_tokens(tokens);
|
|
self.eq_token.to_tokens(tokens);
|
|
self.rhs_ty.to_tokens(tokens);
|
|
}
|
|
}
|
|
}
|