xtra_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_quote, DeriveInput, GenericParam, WherePredicate};
4
5#[proc_macro_derive(Actor)]
6pub fn actor_derive(input: TokenStream) -> TokenStream {
7    let derive_input = syn::parse::<DeriveInput>(input).expect("macro to be used as custom-derive");
8
9    let send_and_static_bounds = send_and_static_bounds(&derive_input);
10    let actor_ident = derive_input.ident;
11    let (impl_generics, type_generics, where_clause) = derive_input.generics.split_for_impl();
12    let where_clause = match where_clause.cloned() {
13        None => parse_quote! { where #(#send_and_static_bounds),* },
14        Some(mut existing) => {
15            existing.predicates.extend(send_and_static_bounds);
16
17            existing
18        }
19    };
20
21    quote! {
22        impl #impl_generics xtra::Actor for #actor_ident #type_generics #where_clause {
23            type Stop = ();
24
25            async fn stopped(self) { }
26        }
27    }
28    .into()
29}
30
31/// Generics a `: Send + 'static` predicate for each type parameter present in the generics.
32fn send_and_static_bounds(input: &DeriveInput) -> Vec<WherePredicate> {
33    input
34        .generics
35        .params
36        .iter()
37        .filter_map(|gp| match gp {
38            GenericParam::Type(tp) => Some(&tp.ident),
39            GenericParam::Lifetime(_) => None,
40            GenericParam::Const(_) => None,
41        })
42        .map(|ident| {
43            parse_quote! {
44                #ident: Send + 'static
45            }
46        })
47        .collect::<Vec<WherePredicate>>()
48}