#![forbid(unsafe_code)]
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
fn has_derive(input: &DeriveInput, trait_name: &str) -> bool {
input.attrs.iter().any(|attr| {
if attr.path().is_ident("derive") {
let mut found = false;
let _ = attr.parse_nested_meta(|meta| {
if meta.path.is_ident(trait_name) {
found = true;
}
Ok(())
});
found
} else {
false
}
})
}
#[proc_macro_attribute]
pub fn acton_message(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as DeriveInput);
let name = &input.ident;
let generics = &input.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let clone_attr = if has_derive(&input, "Clone") {
quote!()
} else {
quote!(#[derive(Clone)])
};
let expanded = quote! {
#clone_attr
#input
impl #impl_generics std::fmt::Debug for #name #ty_generics #where_clause {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, stringify!(#name))
}
}
};
TokenStream::from(expanded)
}
#[proc_macro_attribute]
pub fn acton_actor(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as DeriveInput);
let name = &input.ident;
let generics = &input.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let need_default = !has_derive(&input, "Default");
let need_clone = !has_derive(&input, "Clone");
let derives = {
let mut traits = Vec::new();
if need_default { traits.push(quote!(Default)); }
if need_clone { traits.push(quote!(Clone)); }
if traits.is_empty() { quote!() } else { quote!(#[derive(#(#traits),*)]) }
};
let expanded = quote! {
#derives
#input
impl #impl_generics std::fmt::Debug for #name #ty_generics #where_clause {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, stringify!(#name))
}
}
};
TokenStream::from(expanded)
}