use super::*;
use delimited::Delimited;
ast_struct! {
#[derive(Default)]
pub struct Generics {
pub lt_token: Option<tokens::Lt>,
pub gt_token: Option<tokens::Gt>,
pub lifetimes: Delimited<LifetimeDef, tokens::Comma>,
pub ty_params: Delimited<TyParam, tokens::Comma>,
pub where_clause: WhereClause,
}
}
#[cfg(feature = "printing")]
#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
#[cfg_attr(feature = "clone-impls", derive(Clone))]
pub struct ImplGenerics<'a>(&'a Generics);
#[cfg(feature = "printing")]
#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
#[cfg_attr(feature = "clone-impls", derive(Clone))]
pub struct TyGenerics<'a>(&'a Generics);
#[cfg(feature = "printing")]
#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))]
#[cfg_attr(feature = "clone-impls", derive(Clone))]
pub struct Turbofish<'a>(&'a Generics);
#[cfg(feature = "printing")]
impl Generics {
pub fn split_for_impl(&self) -> (ImplGenerics, TyGenerics, &WhereClause) {
(ImplGenerics(self), TyGenerics(self), &self.where_clause)
}
}
#[cfg(feature = "printing")]
impl<'a> TyGenerics<'a> {
pub fn as_turbofish(&self) -> Turbofish {
Turbofish(self.0)
}
}
ast_struct! {
#[derive(Default)]
pub struct BoundLifetimes {
pub for_token: tokens::For,
pub lt_token: tokens::Lt,
pub lifetimes: Delimited<LifetimeDef, tokens::Comma>,
pub gt_token: tokens::Gt,
}
}
ast_struct! {
pub struct LifetimeDef {
pub attrs: Vec<Attribute>,
pub lifetime: Lifetime,
pub colon_token: Option<tokens::Colon>,
pub bounds: Delimited<Lifetime, tokens::Add>,
}
}
impl LifetimeDef {
pub fn new(lifetime: Lifetime) -> Self {
LifetimeDef {
attrs: Vec::new(),
lifetime: lifetime,
colon_token: None,
bounds: Delimited::new(),
}
}
}
ast_struct! {
pub struct TyParam {
pub attrs: Vec<Attribute>,
pub ident: Ident,
pub colon_token: Option<tokens::Colon>,
pub bounds: Delimited<TyParamBound, tokens::Add>,
pub eq_token: Option<tokens::Eq>,
pub default: Option<Ty>,
}
}
impl From<Ident> for TyParam {
fn from(ident: Ident) -> Self {
TyParam {
attrs: vec![],
ident: ident,
colon_token: None,
bounds: Delimited::new(),
eq_token: None,
default: None,
}
}
}
ast_enum! {
pub enum TyParamBound {
Trait(PolyTraitRef, TraitBoundModifier),
Region(Lifetime),
}
}
ast_enum! {
#[cfg_attr(feature = "clone-impls", derive(Copy))]
pub enum TraitBoundModifier {
None,
Maybe(tokens::Question),
}
}
ast_struct! {
#[derive(Default)]
pub struct WhereClause {
pub where_token: Option<tokens::Where>,
pub predicates: Delimited<WherePredicate, tokens::Comma>,
}
}
impl WhereClause {
pub fn none() -> Self {
WhereClause::default()
}
}
ast_enum_of_structs! {
pub enum WherePredicate {
pub BoundPredicate(WhereBoundPredicate {
pub bound_lifetimes: Option<BoundLifetimes>,
pub bounded_ty: Ty,
pub colon_token: tokens::Colon,
pub bounds: Delimited<TyParamBound, tokens::Add>,
}),
pub RegionPredicate(WhereRegionPredicate {
pub lifetime: Lifetime,
pub colon_token: Option<tokens::Colon>,
pub bounds: Delimited<Lifetime, tokens::Add>,
}),
pub EqPredicate(WhereEqPredicate {
pub lhs_ty: Ty,
pub eq_token: tokens::Eq,
pub rhs_ty: Ty,
}),
}
}
#[cfg(feature = "parsing")]
pub mod parsing {
use super::*;
use synom::Synom;
use synom::tokens::*;
impl Synom for Generics {
named!(parse -> Self, map!(
alt!(
do_parse!(
lt: syn!(Lt) >>
lifetimes: call!(Delimited::parse_terminated) >>
ty_params: cond!(
lifetimes.is_empty() || lifetimes.trailing_delim(),
call!(Delimited::parse_terminated)
) >>
gt: syn!(Gt) >>
(lifetimes, ty_params, Some(lt), Some(gt))
)
|
epsilon!() => { |_| (Delimited::new(), None, None, None) }
),
|(lifetimes, ty_params, lt, gt)| Generics {
lifetimes: lifetimes,
ty_params: ty_params.unwrap_or_default(),
where_clause: WhereClause::default(),
gt_token: gt,
lt_token: lt,
}
));
}
impl Synom for LifetimeDef {
named!(parse -> Self, do_parse!(
attrs: many0!(call!(Attribute::parse_outer)) >>
life: syn!(Lifetime) >>
colon: option!(syn!(Colon)) >>
bounds: cond!(
colon.is_some(),
call!(Delimited::parse_separated_nonempty)
) >>
(LifetimeDef {
attrs: attrs,
lifetime: life,
bounds: bounds.unwrap_or_default(),
colon_token: colon.map(|_| tokens::Colon::default()),
})
));
}
impl Synom for BoundLifetimes {
named!(parse -> Self, do_parse!(
for_: syn!(For) >>
lt: syn!(Lt) >>
lifetimes: call!(Delimited::parse_terminated) >>
gt: syn!(Gt) >>
(BoundLifetimes {
for_token: for_,
lt_token: lt,
gt_token: gt,
lifetimes: lifetimes,
})
));
}
impl Synom for TyParam {
named!(parse -> Self, do_parse!(
attrs: many0!(call!(Attribute::parse_outer)) >>
id: syn!(Ident) >>
colon: option!(syn!(Colon)) >>
bounds: cond!(
colon.is_some(),
call!(Delimited::parse_separated_nonempty)
) >>
default: option!(do_parse!(
eq: syn!(Eq) >>
ty: syn!(Ty) >>
(eq, ty)
)) >>
(TyParam {
attrs: attrs,
ident: id,
bounds: bounds.unwrap_or_default(),
colon_token: colon,
eq_token: default.as_ref().map(|d| tokens::Eq((d.0).0)),
default: default.map(|d| d.1),
})
));
}
impl Synom for TyParamBound {
named!(parse -> Self, alt!(
do_parse!(
question: syn!(Question) >>
poly: syn!(PolyTraitRef) >>
(TyParamBound::Trait(poly, TraitBoundModifier::Maybe(question)))
)
|
syn!(Lifetime) => { TyParamBound::Region }
|
syn!(PolyTraitRef) => {
|poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
}
));
fn description() -> Option<&'static str> {
Some("type parameter buond")
}
}
impl Synom for WhereClause {
named!(parse -> Self, alt!(
do_parse!(
where_: syn!(Where) >>
predicates: call!(Delimited::parse_terminated) >>
(WhereClause {
predicates: predicates,
where_token: Some(where_),
})
)
|
epsilon!() => { |_| WhereClause::default() }
));
fn description() -> Option<&'static str> {
Some("where clause")
}
}
impl Synom for WherePredicate {
named!(parse -> Self, alt!(
do_parse!(
ident: syn!(Lifetime) >>
colon: option!(syn!(Colon)) >>
bounds: cond!(
colon.is_some(),
call!(Delimited::parse_separated)
) >>
(WherePredicate::RegionPredicate(WhereRegionPredicate {
lifetime: ident,
bounds: bounds.unwrap_or_default(),
colon_token: colon,
}))
)
|
do_parse!(
bound_lifetimes: option!(syn!(BoundLifetimes)) >>
bounded_ty: syn!(Ty) >>
colon: syn!(Colon) >>
bounds: call!(Delimited::parse_separated_nonempty) >>
(WherePredicate::BoundPredicate(WhereBoundPredicate {
bound_lifetimes: bound_lifetimes,
bounded_ty: bounded_ty,
bounds: bounds,
colon_token: colon,
}))
)
));
}
}
#[cfg(feature = "printing")]
mod printing {
use super::*;
use attr::FilterAttrs;
use quote::{Tokens, ToTokens};
fn empty_normal_generics(generics: &Generics) -> bool {
generics.lifetimes.is_empty() && generics.ty_params.is_empty()
}
fn maybe_add_lifetime_params_comma(tokens: &mut Tokens, generics: &Generics) {
if !generics.lifetimes.empty_or_trailing() && !generics.ty_params.is_empty() {
tokens::Comma::default().to_tokens(tokens);
}
}
impl ToTokens for Generics {
fn to_tokens(&self, tokens: &mut Tokens) {
if empty_normal_generics(self) {
return;
}
TokensOrDefault(&self.lt_token).to_tokens(tokens);
self.lifetimes.to_tokens(tokens);
maybe_add_lifetime_params_comma(tokens, self);
self.ty_params.to_tokens(tokens);
TokensOrDefault(&self.gt_token).to_tokens(tokens);
}
}
impl<'a> ToTokens for ImplGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
if empty_normal_generics(&self.0) {
return;
}
TokensOrDefault(&self.0.lt_token).to_tokens(tokens);
self.0.lifetimes.to_tokens(tokens);
maybe_add_lifetime_params_comma(tokens, &self.0);
for param in self.0.ty_params.iter() {
let item = param.item();
tokens.append_all(item.attrs.outer());
item.ident.to_tokens(tokens);
if !item.bounds.is_empty() {
TokensOrDefault(&item.colon_token).to_tokens(tokens);
item.bounds.to_tokens(tokens);
}
param.delimiter().to_tokens(tokens);
}
TokensOrDefault(&self.0.gt_token).to_tokens(tokens);
}
}
impl<'a> ToTokens for TyGenerics<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
if empty_normal_generics(&self.0) {
return;
}
TokensOrDefault(&self.0.lt_token).to_tokens(tokens);
for param in self.0.lifetimes.iter() {
param.item().lifetime.to_tokens(tokens);
param.delimiter().to_tokens(tokens);
}
maybe_add_lifetime_params_comma(tokens, &self.0);
for param in self.0.ty_params.iter() {
param.item().ident.to_tokens(tokens);
param.delimiter().to_tokens(tokens);
}
TokensOrDefault(&self.0.gt_token).to_tokens(tokens);
}
}
impl<'a> ToTokens for Turbofish<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
if !empty_normal_generics(&self.0) {
tokens::Colon2::default().to_tokens(tokens);
TyGenerics(self.0).to_tokens(tokens);
}
}
}
impl ToTokens for BoundLifetimes {
fn to_tokens(&self, tokens: &mut Tokens) {
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 Tokens) {
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 TyParam {
fn to_tokens(&self, tokens: &mut Tokens) {
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 self.default.is_some() {
TokensOrDefault(&self.eq_token).to_tokens(tokens);
self.default.to_tokens(tokens);
}
}
}
impl ToTokens for TyParamBound {
fn to_tokens(&self, tokens: &mut Tokens) {
match *self {
TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
TyParamBound::Trait(ref trait_ref, ref modifier) => {
modifier.to_tokens(tokens);
trait_ref.to_tokens(tokens);
}
}
}
}
impl ToTokens for TraitBoundModifier {
fn to_tokens(&self, tokens: &mut Tokens) {
match *self {
TraitBoundModifier::None => {}
TraitBoundModifier::Maybe(ref t) => t.to_tokens(tokens),
}
}
}
impl ToTokens for WhereClause {
fn to_tokens(&self, tokens: &mut Tokens) {
if !self.predicates.is_empty() {
TokensOrDefault(&self.where_token).to_tokens(tokens);
self.predicates.to_tokens(tokens);
}
}
}
impl ToTokens for WhereBoundPredicate {
fn to_tokens(&self, tokens: &mut Tokens) {
self.bound_lifetimes.to_tokens(tokens);
self.bounded_ty.to_tokens(tokens);
self.colon_token.to_tokens(tokens);
self.bounds.to_tokens(tokens);
}
}
impl ToTokens for WhereRegionPredicate {
fn to_tokens(&self, tokens: &mut Tokens) {
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 WhereEqPredicate {
fn to_tokens(&self, tokens: &mut Tokens) {
self.lhs_ty.to_tokens(tokens);
self.eq_token.to_tokens(tokens);
self.rhs_ty.to_tokens(tokens);
}
}
}