use syn;
use quote::Tokens;
use model::*;
pub fn build(component: &AutoImpl, ref_ty: Trait) -> Result<Tokens, String> {
let component_ident = &component.ident;
let impl_methods = component.methods.iter()
.map(|method| {
let valid_receiver = match method.arg_self {
Some(ref arg_self) => match *arg_self {
SelfArg::Ref(_, syn::Mutability::Immutable) => true,
_ => false
},
None => false
};
if !valid_receiver {
Err(format!("auto impl for `{}` is only supported for methods with a `&self` reciever", ref_ty))?
}
method.build_impl_item(|method| {
let fn_ident = &method.ident;
let fn_args = &method.arg_pats;
quote!({
self.as_ref().#fn_ident( #(#fn_args),* )
})
})
})
.collect::<Result<Vec<_>, _>>()?;
let impl_associated_types = component.associated_types.iter()
.map(|associated_type| {
associated_type.build_impl_item(|associated_type| {
let ty_ident = &associated_type.ident;
quote!(TAutoImpl :: #ty_ident)
})
})
.collect::<Result<Vec<_>, _>>()?;
let (trait_tys, impl_lifetimes, impl_tys, where_clauses) = component.split_generics();
Ok(quote!(
impl< #(#impl_lifetimes,)* #(#impl_tys,)* TAutoImpl > #component_ident #trait_tys for #ref_ty < TAutoImpl >
where TAutoImpl: #component_ident #trait_tys
#(,#where_clauses)*
{
#(#impl_associated_types)*
#(#impl_methods)*
}
))
}