https://github.com/chillfish8/puppet
A macro-based actor framework for static-dispatch actors.
https://github.com/chillfish8/puppet
Last synced: about 2 months ago
JSON representation
A macro-based actor framework for static-dispatch actors.
- Host: GitHub
- URL: https://github.com/chillfish8/puppet
- Owner: ChillFish8
- License: mit
- Created: 2022-12-04T23:57:13.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2022-12-12T19:03:14.000Z (over 2 years ago)
- Last Synced: 2025-04-14T20:13:03.107Z (about 2 months ago)
- Language: Rust
- Size: 27.3 KB
- Stars: 7
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Puppet - A simple actor framework
Puppet is yet another actor framework built without any boxing or dynamic dispatch of items, instead it uses
a small macro to essentially generate the boilerplate for an enum-based system.## Features
- Generic-aware, which means you can have generic actors return generic messages.
- Box-less, no requirement for `async_trait` or boxing for dynamic dispatch.
- Linter friendly, your editors should be able to easily infer the return types from all exposed methods.
- Sync and Async mailbox methods.## Basic Example
Let's create a small actor for creating hello messages...```rust
use puppet::{puppet_actor, ActorMailbox, Message};pub struct MyActor;
#[puppet_actor]
impl MyActor {
#[puppet]
async fn on_say_hello(&self, msg: SayHello) -> String {
format!("Hello, {}!", msg.name)
}
}pub struct SayHello {
name: String
}
impl Message for SayHello {
type Output = String;
}#[tokio::main]
async fn main() {
// Create the actor.
let actor = MyActor;
// Spawn it on the current runtime, which returns to us a mailbox which
// we can use to communicate with the actor.
let mailbox: ActorMailbox = actor.spawn_actor().await;let message = SayHello {
name: "Harri".to_string(),
};
// Send a message to the actor and wait for a response.
let response = mailbox.send(message).await;
println!("Got message back! {}", response);
}
```## Generic Example
Now what if we want to do some more advanced things with our actors? Well luckily for us, we can use generics.```rust
use puppet::{puppet_actor, ActorMailbox, Message};pub struct AppenderService {
seen_data: Vec,
}#[puppet_actor]
impl AppenderService
where
// The additional `Send` and `'static` bounds are required due to the nature
// of the actor running as a tokio task which has it's own requirements.
T: Clone + Send + 'static,
{
fn new() -> Self {
Self {
seen_data: Vec::new(),
}
}#[puppet]
async fn on_append_and_return(&mut self, msg: AppendAndReturn) -> Vec {
self.seen_data.push(msg.value);
self.seen_data.clone()
}
}#[derive(Clone)]
pub struct AppendAndReturn {
value: T,
}
impl Message for AppendAndReturn
where
T: Clone,
{
type Output = Vec;
}#[tokio::main]
async fn main() {
let actor = AppenderService::::new();
let mailbox: ActorMailbox> = actor.spawn_actor().await;let message = AppendAndReturn {
value: "Harri".to_string(),
};for _ in 0..3 {
let response = mailbox.send(message.clone()).await;
println!("Got values: {:?}", response);
}
}
```