rsactor_derive/
lib.rs

1// Copyright 2022 Jeff Kim <hiking90@gmail.com>
2// SPDX-License-Identifier: Apache-2.0
3
4//! Derive macros for rsActor framework
5//!
6//! This crate provides derive macros for the rsActor framework, allowing users
7//! to automatically implement common traits with sensible defaults.
8//!
9//! ## Actor Derive Macro
10//!
11//! The `#[derive(Actor)]` macro provides a convenient way to implement the Actor trait
12//! for simple structs and enums that don't require complex initialization logic.
13//!
14//! ### Generated Implementation
15//!
16//! When you use `#[derive(Actor)]`, it generates:
17//! - `Args` type set to `Self` (the struct or enum itself)
18//! - `Error` type set to `std::convert::Infallible` (never fails)
19//! - `on_start` method that simply returns the provided args
20//!
21//! ### Usage
22//!
23//! #### With Structs
24//! ```rust
25//! use rsactor::Actor;
26//!
27//! #[derive(Actor)]
28//! struct MyActor {
29//!     name: String,
30//!     count: u32,
31//! }
32//! ```
33//!
34//! #### With Enums
35//! ```rust
36//! use rsactor::Actor;
37//!
38//! #[derive(Actor)]
39//! enum StateActor {
40//!     Idle,
41//!     Processing(String),
42//!     Completed(i32),
43//! }
44//! ```
45//!
46//! This is equivalent to manually writing:
47//!
48//! ```rust
49//! # struct MyActor { name: String, count: u32 }
50//! use rsactor::{Actor, ActorRef};
51//! use std::convert::Infallible;
52//!
53//! impl Actor for MyActor {
54//!     type Args = Self;
55//!     type Error = Infallible;
56//!
57//!     async fn on_start(
58//!         args: Self::Args,
59//!         _actor_ref: &ActorRef<Self>,
60//!     ) -> std::result::Result<Self, Self::Error> {
61//!         Ok(args)
62//!     }
63//! }
64//! ```
65//!
66//! ### When to Use
67//!
68//! Use the derive macro when:
69//! - Your actor doesn't need complex initialization
70//! - You want to pass a fully constructed instance to `spawn()`
71//! - You don't need custom error handling during initialization
72//!
73//! For complex initialization (async resource setup, validation, etc.),
74//! implement the Actor trait manually.
75
76use proc_macro::TokenStream;
77use proc_macro2::TokenStream as TokenStream2;
78use quote::quote;
79use syn::{parse_macro_input, Data, DeriveInput};
80
81/// Derive macro for automatically implementing the Actor trait.
82///
83/// This macro generates a default implementation of the Actor trait where:
84/// - `Args` type is set to `Self`
85/// - `Error` type is set to `std::convert::Infallible`
86/// - `on_start` method returns the args as the actor instance
87///
88/// # Examples
89///
90/// ## Struct Actor
91/// ```rust
92/// use rsactor::Actor;
93///
94/// #[derive(Actor)]
95/// struct MyActor {
96///     name: String,
97/// }
98/// ```
99///
100/// ## Enum Actor
101/// ```rust
102/// use rsactor::Actor;
103///
104/// #[derive(Actor)]
105/// enum StateActor {
106///     Idle,
107///     Processing(String),
108///     Completed(i32),
109/// }
110/// ```
111///
112/// This generates an implementation equivalent to:
113///
114/// ```rust
115/// # struct MyActor { name: String }
116/// impl rsactor::Actor for MyActor {
117///     type Args = Self;
118///     type Error = std::convert::Infallible;
119///
120///     async fn on_start(
121///         args: Self::Args,
122///         _actor_ref: &rsactor::ActorRef<Self>,
123///     ) -> std::result::Result<Self, Self::Error> {
124///         Ok(args)
125///     }
126/// }
127/// ```
128///
129/// # Limitations
130///
131/// - Only works on structs and enums (not unions)
132/// - Generates a very basic implementation - for complex initialization logic,
133///   implement the Actor trait manually
134#[proc_macro_derive(Actor)]
135pub fn derive_actor(input: TokenStream) -> TokenStream {
136    let input = parse_macro_input!(input as DeriveInput);
137
138    let expanded = match derive_actor_impl(input) {
139        Ok(tokens) => tokens,
140        Err(err) => err.to_compile_error(),
141    };
142
143    TokenStream::from(expanded)
144}
145
146fn derive_actor_impl(input: DeriveInput) -> syn::Result<TokenStream2> {
147    let name = &input.ident;
148
149    // Check if it's a struct or enum
150    match &input.data {
151        Data::Struct(_) | Data::Enum(_) => {
152            // Generate the Actor implementation
153            let expanded = quote! {
154                impl rsactor::Actor for #name {
155                    type Args = Self;
156                    type Error = std::convert::Infallible;
157
158                    async fn on_start(
159                        args: Self::Args,
160                        _actor_ref: &rsactor::ActorRef<Self>,
161                    ) -> std::result::Result<Self, Self::Error> {
162                        Ok(args)
163                    }
164                }
165            };
166
167            Ok(expanded)
168        }
169        _ => Err(syn::Error::new_spanned(
170            name,
171            "Actor derive macro can only be used on structs and enums",
172        )),
173    }
174}