use super::*;
#[derive(Parse, ToTokens)]
pub struct InputImplInherent {
attrs: Any<Attribute<SynMeta>>,
defaultness: Optional<Token![default]>,
unsafety: Optional<Token![unsafe]>,
impl_token: Token![impl],
generics: Optional<InputGenerics>,
self_ty: Box<Type>,
where_clause: Optional<WhereClause>,
items: Brace<Any<InputImplItem>>,
}
pub fn run(input: InputImplInherent) -> Result<TokenStream> {
let sane = sanitize_input(input)?;
generate_output(sane)
}
struct SaneImplInherent {
attrs: Any<Attribute<SynMeta>>,
defaultness: Optional<Token![default]>,
unsafety: Optional<Token![unsafe]>,
impl_token: Token![impl],
generics: Optional<SaneGenerics>,
self_ty: Box<Type>,
functions: Brace<Any<SaneMethod>>,
}
fn sanitize_input(input: InputImplInherent) -> Result<SaneImplInherent> {
let InputImplInherent {
attrs,
defaultness,
unsafety,
impl_token,
generics,
self_ty,
where_clause,
items,
} = input;
let (brace, item_list) = items.into_parts();
let generics = sanitize_generics(generics, where_clause)?;
let sane_items = item_list
.into_iter()
.map(|item| {
match item {
InputImplItem::Fn(func) => sanitize_fn(func),
InputImplItem::Type(assoc_type) => {
bail!(assoc_type => "Expected function.\n\
Help: Associated types aren't supported in impl blocks that have the `delegate_impl` attribute.")
}
InputImplItem::Const(constant) => {
bail!(constant => "Expected function.\n\
Help: Declare this constant in an impl block that doesn't have the `delegate_impl` attribute.")
}
InputImplItem::Macro(mac) => {
bail!(mac => "Expected function.\n\
Help: Declare this macro in an impl block that doesn't have the `delegate_impl` attribute.")
}
}
})
.try_collect()?;
Ok(SaneImplInherent {
attrs,
defaultness,
unsafety,
impl_token,
generics,
self_ty,
functions: Brace::from((brace, sane_items)),
})
}
fn sanitize_fn(input: Box<InputImplItemFn>) -> Result<SaneMethod> {
let InputImplItemFn {
attrs,
vis,
sig,
body,
} = *input;
let semi_token = match body {
InputImplItemFnBody::Block(block) => {
bail!(block => "Function implementations aren't allowed. \
The implementation will be generated by this macro.\n\
Help: Replace this block with a `;` (semi-colon).")
}
InputImplItemFnBody::SemiColon(semi_token) => semi_token,
};
Ok(SaneMethod {
attrs,
vis,
sig: sanitize_method_signature(sig)?,
_semi_token: semi_token,
})
}
fn generate_output(sane: SaneImplInherent) -> Result<TokenStream> {
let SaneImplInherent {
attrs,
defaultness,
unsafety: impl_unsafety,
impl_token,
generics: impl_generics,
self_ty,
functions,
} = sane;
let (impl_generics, impl_where_clause) = impl_generics.into_pair();
let macro_ident = {
let enum_ident = find_enum_ident(&self_ty)
.ok_or_else(|| Error::new(self_ty.span(), "Could not find main ident in this type."))?;
delegate_macro_ident(enum_ident)
};
let functions_tt = functions
.into_inner()
.into_iter()
.map(|method| sane_method_output(method, ¯o_ident))
.try_collect::<_, Vec<_>, _>()?;
Ok(quote! {
#attrs
#defaultness #impl_unsafety #impl_token #impl_generics #self_ty #impl_where_clause {
#(#functions_tt)*
}
})
}