dsl_ractor/
lib.rs

1mod ast;
2mod expand;
3mod kw;
4mod parse;
5mod validate;
6
7use expand::expand::expand;
8use parse::actor_args::parse_actor_args;
9use proc_macro::TokenStream;
10use proc_macro2::TokenStream as TokenStream2;
11use syn::{DeriveInput, parse_macro_input, spanned::Spanned};
12use validate::args::validate_actor_args;
13
14/// Parses input as either a `Block` or an `Expr`.
15/// Falls back to wrapping the `Expr` in a block if no block is found.
16macro_rules! parse_block_or_expr {
17    ($input:expr) => {
18        if let Ok(block) = syn::parse::<syn::Block>($input.clone()) {
19            block
20        } else {
21            let expr: syn::Expr = syn::parse($input).expect("expected block or expression");
22            syn::parse_quote!({ #expr })
23        }
24    };
25}
26
27/// Attribute macro to define an `Actor`.
28/// Parses and validates arguments, then expands into the actor implementation.
29/// Emits a compile error on invalid input.
30#[proc_macro_attribute]
31pub fn actor(attr: TokenStream, item: TokenStream) -> TokenStream {
32    let input = parse_macro_input!(item as DeriveInput);
33    let attr_ts: TokenStream2 = attr.into();
34    let out = || -> syn::Result<_> {
35        let raw = parse_actor_args(input.span(), attr_ts)?;
36        let val = validate_actor_args(raw)?;
37        Ok(expand(&input, &val))
38    }();
39
40    match out {
41        Ok(ts) => ts.into(),
42        Err(e) => e.to_compile_error().into(),
43    }
44}
45
46/// Procedural macro to define the actor's `on_start` handler.
47/// Expands the given block or expression into the async `on_start` method.
48#[allow(unexpected_cfgs)]
49#[proc_macro]
50pub fn actor_pre_start(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
51    let body = parse_block_or_expr!(input);
52    quote::quote! {
53        #[allow(unexpected_cfgs)]
54        #[cfg(feature="async-trait")]
55        pub async fn on_start(
56            &self,
57            myself: ractor::ActorRef<<Self as ractor::Actor>::Msg>,
58            args: <Self as ractor::Actor>::Arguments,
59        ) -> ::core::result::Result<(<Self as ractor::Actor>::State), ractor::ActorProcessingErr> {
60            #body
61        }
62
63        #[allow(unexpected_cfgs)]
64        #[cfg(not(feature="async-trait"))]
65        pub fn on_start(
66            &self,
67            myself: ractor::ActorRef<<Self as ractor::Actor>::Msg>,
68            args: <Self as ractor::Actor>::Arguments,
69        ) -> impl ::core::future::Future<Output=::core::result::Result<(<Self as ractor::Actor>::State), ractor::ActorProcessingErr>> + Send {
70            async move {
71                #body
72            }
73        }
74    }.into()
75}
76
77/// Procedural macro to define the actor's `handle_msg` handler.
78/// Expands the given block or expression into the async `handle_msg` method.
79#[allow(unexpected_cfgs)]
80#[proc_macro]
81pub fn actor_handle(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
82    let body = parse_block_or_expr!(input);
83    quote::quote! {
84        #[allow(unexpected_cfgs)]
85        #[cfg(feature="async-trait")]
86        pub async fn handle_msg(
87            &self,
88            myself: ractor::ActorRef<<Self as ractor::Actor>::Msg>,
89            msg: <Self as ractor::Actor>::Msg,
90            state: &mut <Self as ractor::Actor>::State,
91        ) -> ::core::result::Result<(), ractor::ActorProcessingErr> {
92            #body
93        }
94
95        #[allow(unexpected_cfgs)]
96        #[cfg(not(feature="async-trait"))]
97        pub fn handle_msg(
98            &self,
99            myself: ractor::ActorRef<<Self as ractor::Actor>::Msg>,
100            msg: <Self as ractor::Actor>::Msg,
101            state: &mut <Self as ractor::Actor>::State,
102        ) -> impl ::core::future::Future<Output=::core::result::Result<(), ractor::ActorProcessingErr>> + Send {
103            async move {
104                #body
105            }
106        }
107    }.into()
108}