1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
use ::proc_macro::TokenStream; use ::quote::quote; use ::syn::{ parse_macro_input, punctuated::Punctuated, Attribute, DeriveInput, Ident, NestedMeta, Token, }; const PUBLISHES_ATTRIBUTE: &str = "publish"; const HANDLES_ATTRIBUTE: &str = "handle"; #[proc_macro_derive(Actor, attributes(publish, handle))] pub fn actor_derive(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input); process_actor_derive(ast) } fn process_actor_derive(input: DeriveInput) -> TokenStream { let publishes = get_idents(PUBLISHES_ATTRIBUTE, &input); let handles = get_idents(HANDLES_ATTRIBUTE, &input); let name = &input.ident; TokenStream::from(quote! { impl ::yaaf::Actor for #name { type Publishes = (#(#publishes, )*); type Handles = (#(#handles, )*); } #( impl ::yaaf::HandlerRegistered<#handles> for #name {} )* #( impl ::yaaf::Publisher<#publishes> for #name {} )* }) } #[proc_macro_derive(Source, attributes(publish))] pub fn source_derive(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input); process_source_derive(ast) } fn process_source_derive(input: DeriveInput) -> TokenStream { let publishes = get_idents(PUBLISHES_ATTRIBUTE, &input); let name = &input.ident; TokenStream::from(quote! { impl ::yaaf::SourceMeta for #name { type Publishes = (#(#publishes, )*); } #( impl ::yaaf::Publisher<#publishes> for #name {} )* }) } fn get_idents(label: &str, input: &DeriveInput) -> Vec<Ident> { let mut result = vec![]; for att in input.attrs.iter().filter(|a| a.path.is_ident(label)) { result.extend(parse_attr(&att)); } result } fn parse_attr(attr: &Attribute) -> Vec<Ident> { let list = attr .parse_args_with(Punctuated::<NestedMeta, Token![,]>::parse_terminated) .expect("failed to parse attribute"); let mut result = vec![]; for item in list { match item { ::syn::NestedMeta::Meta(m) => { result.push(m.path().get_ident().unwrap().clone()); } ::syn::NestedMeta::Lit(_) => { panic!("Identifier required"); } } } result }