use quote::{format_ident, quote, ToTokens};
use syn::{parse_macro_input, FnArg, ImplItem, ItemImpl, Visibility};
pub fn impl_object_impl(attr: proc_macro::TokenStream, struct_impl: proc_macro::TokenStream) -> proc_macro::TokenStream {
let vis = if attr.is_empty() {
Visibility::Inherited
} else {
parse_macro_input!(attr as Visibility)
};
let struct_impl = parse_macro_input!(struct_impl as ItemImpl);
if struct_impl.trait_.is_some() {
return quote!(compile_error!("Expected struct impl, found trait impl")).into();
}
let items = struct_impl.items.clone().into_iter();
let (non_self_items, self_items): (Vec<ImplItem>, Vec<ImplItem>) = items.partition(|item| match item {
ImplItem::Const(_) | ImplItem::Macro(_) | ImplItem::Type(_) => true,
ImplItem::Fn(func) => {
func.sig.inputs.iter().any(|p| match p {
FnArg::Receiver(_) => true,
_ => false,
})
},
_ => false
});
let struct_ty = struct_impl.self_ty.clone();
let struct_impl_name = &struct_ty.to_token_stream().to_string()
.chars().filter(|c| c.is_alphanumeric())
.collect::<String>();
let struct_impl_name = format_ident!("__{}Impl", struct_impl_name);
let res = quote! {
#[doc(hidden)]
#vis trait #struct_impl_name where Self: oors::IsA<#struct_ty>, Self: Sized {
#(#non_self_items)*
}
impl<T> #struct_impl_name for T where T: oors::IsA<#struct_ty> {}
impl #struct_ty {
#(#self_items)*
}
};
res.into()
}