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}