blob: db6de9d209c7079a57b9860a100b1f5512f41f37 [file] [log] [blame]
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.*
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]: enum.Expr.html#syntax-tree-enums
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.*
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.*
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.*
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&lt;Item = &amp;</code><a
/// href="struct.TypeParam.html"><code
/// style="padding-left:0;padding-right:0;">TypeParam</code></a><code
/// style="padding-left:0;">&gt;</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&lt;Item = &amp;mut </code><a
/// href="struct.TypeParam.html"><code
/// style="padding-left:0;padding-right:0;">TypeParam</code></a><code
/// style="padding-left:0;">&gt;</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&lt;Item = &amp;</code><a
/// href="struct.LifetimeDef.html"><code
/// style="padding-left:0;padding-right:0;">LifetimeDef</code></a><code
/// style="padding-left:0;">&gt;</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&lt;Item = &amp;mut </code><a
/// href="struct.LifetimeDef.html"><code
/// style="padding-left:0;padding-right:0;">LifetimeDef</code></a><code
/// style="padding-left:0;">&gt;</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&lt;Item = &amp;</code><a
/// href="struct.ConstParam.html"><code
/// style="padding-left:0;padding-right:0;">ConstParam</code></a><code
/// style="padding-left:0;">&gt;</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&lt;Item = &amp;mut </code><a
/// href="struct.ConstParam.html"><code
/// style="padding-left:0;padding-right:0;">ConstParam</code></a><code
/// style="padding-left:0;">&gt;</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 {
// This is Option::get_or_insert_with in Rust 1.20.
if self.where_clause.is_none() {
self.where_clause = Some(WhereClause {
where_token: <Token![where]>::default(),
predicates: Punctuated::new(),
});
}
match &mut self.where_clause {
Some(where_clause) => where_clause,
None => unreachable!(),
}
}
}
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")]
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")]
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")]
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.*
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")]
impl<'a> Clone for $ty<'a> {
fn clone(&self) -> Self {
$ty(self.0)
}
}
#[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")]
impl<'a> Eq for $ty<'a> {}
#[cfg(feature = "extra-traits")]
impl<'a> PartialEq for $ty<'a> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
#[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.*
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.*
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.*
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.*
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.*
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]: enum.Expr.html#syntax-tree-enums
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.*
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.*
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.*
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::parse::{Parse, ParseStream, Result};
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();
let mut allow_lifetime_param = true;
loop {
if input.peek(Token![>]) {
break;
}
let attrs = input.call(Attribute::parse_outer)?;
let lookahead = input.lookahead1();
if allow_lifetime_param && lookahead.peek(Lifetime) {
params.push_value(GenericParam::Lifetime(LifetimeDef {
attrs,
..input.parse()?
}));
} else if lookahead.peek(Ident) {
allow_lifetime_param = false;
params.push_value(GenericParam::Type(TypeParam {
attrs,
..input.parse()?
}));
} else if lookahead.peek(Token![const]) {
allow_lifetime_param = false;
params.push_value(GenericParam::Const(ConstParam {
attrs,
..input.parse()?
}));
} 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,
})
}
}
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())
}
}
}
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
},
})
}
}
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()?,
})
}
}
impl Parse for Option<BoundLifetimes> {
fn parse(input: ParseStream) -> Result<Self> {
if input.peek(Token![for]) {
input.parse().map(Some)
} else {
Ok(None)
}
}
}
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,
})
}
}
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)
}
}
impl Parse for TraitBound {
fn parse(input: ParseStream) -> Result<Self> {
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) {
let parenthesized = PathArguments::Parenthesized(input.parse()?);
path.segments.last_mut().unwrap().arguments = parenthesized;
}
Ok(TraitBound {
paren_token: None,
modifier,
lifetimes,
path,
})
}
}
impl Parse for TraitBoundModifier {
fn parse(input: ParseStream) -> Result<Self> {
if input.peek(Token![?]) {
input.parse().map(TraitBoundModifier::Maybe)
} else {
Ok(TraitBoundModifier::None)
}
}
}
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(input.parse::<Expr>()?);
Some(eq_token)
} else {
None
}
},
default,
})
}
}
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
},
})
}
}
impl Parse for Option<WhereClause> {
fn parse(input: ParseStream) -> Result<Self> {
if input.peek(Token![where]) {
input.parse().map(Some)
} else {
Ok(None)
}
}
}
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;
use proc_macro2::TokenStream;
#[cfg(feature = "full")]
use proc_macro2::TokenTree;
use quote::{ToTokens, TokenStreamExt};
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(&param.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);
}
}
}
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);
}
}
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);
}
}
}
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();
match (iter.next(), iter.next()) {
(Some(TokenTree::Punct(ref q)), Some(TokenTree::Ident(ref c)))
if q.as_char() == '?' && c == "const" =>
{
return default.to_tokens(tokens);
}
_ => {}
}
}
}
}
TokensOrDefault(&self.eq_token).to_tokens(tokens);
default.to_tokens(tokens);
}
}
}
impl ToTokens for TraitBound {
fn to_tokens(&self, tokens: &mut TokenStream) {
let to_tokens = |tokens: &mut TokenStream| {
self.modifier.to_tokens(tokens);
self.lifetimes.to_tokens(tokens);
self.path.to_tokens(tokens);
};
match &self.paren_token {
Some(paren) => paren.surround(tokens, to_tokens),
None => to_tokens(tokens),
}
}
}
impl ToTokens for TraitBoundModifier {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
TraitBoundModifier::None => {}
TraitBoundModifier::Maybe(t) => t.to_tokens(tokens),
}
}
}
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);
}
}
}
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);
}
}
}
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);
}
}
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);
}
}
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);
}
}
}