Expand description
§abcgen - Actor’s Boilerplate Code Generator
abcgen helps you to build Actor object by producing all the boilerplate code needed by this patter, meaning that all the code involved in defining/sending/raceiving/unwrapping messages and managing lifetime of the actor is hidden from user.
The user should only focus on the logic of the service that the actor is going to provide.
abcgen produces Actor objects that are based on the async
/await
syntax and the tokio library.
The actor objects generated do not require any scheduler o manager to run, they are standalone and can be used in any (tokio) context.
§Basic example
The following example is minimale and does not shocase all the features of the library. Check the README for more details.
#[abcgen::actor_module]
#[allow(unused)]
mod actor {
use abcgen::{actor, message_handler, send_task, AbcgenError, PinnedFuture, Task};
#[actor]
pub struct MyActor {
pub some_value: i32,
}
impl MyActor {
pub async fn start(&mut self, task_sender: TaskSender) {
println!("Starting");
// here you can spawn some tasks using tokio::spawn
// or enqueue some tasks into the actor's main loop by sending them to task_sender
tokio::spawn(async move {
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
send_task!( task_sender(this) => { this.example_task().await; } );
});
}
pub async fn shutdown(&mut self) {
println!("Shutting down");
}
#[message_handler]
async fn get_value(&mut self, name: &'static str) -> Result<i32, &'static str> {
match name {
"some_value" => Ok(self.some_value),
_ => Err("Invalid name"),
}
}
async fn example_task(&mut self) {
println!("Example task executed");
}
}
}
#[tokio::main]
async fn main() {
let actor: actor::MyActorProxy = actor::MyActor { some_value: 32 }.run();
let the_value = actor.get_value("some_value").await.unwrap();
assert!(matches!(the_value, Ok(32)));
let the_value = actor.get_value("some_other_value").await.unwrap();
assert!(matches!(the_value, Err("Invalid name")));
}
§The user should provide:
- a struct or enum definition marked with
actor
attribute - implement start(…) and shutdown(…) methods for the
actor
- implement, for the
actor
, a set of methods marked withmessage_handler
attribute; these are going to handle the messages that theactor
can receive. - optionally, an enum definition marked with
events
attribute to define the events that theactor
can signal
§The procedural macro will generate:
- implementation of
run(self)
method for theactor
which will return an ActorProxy - implementation of message handling logic for the
actor
:- calling the
start(...)
method before entering theactor
’s loop - calling the
shutdown(&mut self)
method after exiting theactor
’s loop - handling of stop signal
- handling of messages (support replies)
- handling of tasks (functions that can be enqueued to be invoked in the
actor
’s loop so the can access&mut Actor
)
- calling the
- an ActorProxy object that implements all of the methods that were marked with
message_handler
attribute - a message enum that contains all the messages that the
actor
can receive (which is not meant to be used directly by the user)
More details can be found in the README file.
Macros§
- send_
task - A macro to simplify sending tasks to the actor
Following below example you need to provide a refence to
task_sender
and
the name for the reference to the actor (this
in the example). The macro will create a closure that returx aPinnedFuture
expressed with |this| Box::pin(async move { … }) and send it trough thetask_sender
. Example:
Enums§
- Abcgen
Error - Error type for the code generated by the abcgen
Type Aliases§
- Pinned
Future - Helper type for async tasks The tasks that are meant to be sent to the actor need to return this type
- Task
- The type of the tasks that are sent to the actor
Attribute Macros§
- actor
- This attribute is used to mark the struct or enum that is going to be the actor.
- actor_
module - The
actor_module
attribute is used to mark a module that contains the actor definition. It will generate the necessary code to implement the actor pattern, that is: - events
- This attribute is used to mark the enum that defines the events that the actor can signal. It can be applied to
- message_
handler - This attribute is used to mark the methods that are going to handle the messages that the actor can receive.