#actor-model #actor #async #tokio #built #macro #listener

pupactor

Pupactor is actor model library built with tokio

4 releases

0.2.0 Nov 27, 2024
0.1.3 Nov 26, 2024
0.1.2 Nov 20, 2024
0.1.1 Sep 19, 2024
0.1.0 Sep 13, 2024

#540 in Asynchronous

Download history 98/week @ 2024-09-09 141/week @ 2024-09-16 45/week @ 2024-09-23 12/week @ 2024-09-30 1/week @ 2024-10-14 133/week @ 2024-11-18 312/week @ 2024-11-25 66/week @ 2024-12-02 26/week @ 2024-12-09

537 downloads per month

MIT/Apache

19KB
529 lines

Pupactor is actor model library built with tokio

Macros and traits could help you to organise actors to look same

Actor body looks like:

#[derive(Pupactor)]
#[actor(cmd = "MyActorShutdown")]
struct MyFirstTestActor {
    some_data: bool,
    some_other_data: usize,
    #[listener]
    interval: Listener<Interval, Instant>,
    #[listener]
    interval2: Listener<Interval, Instant>,
    #[listener]
    channel: Listener<UnboundedReceiver<ActorMsg<Value, MyActorShutdown>>, Value, MyActorShutdown>,
}

where Pupactor macro generates select! macro that listens interval, interval2 and channel

On each income event (Interval, Value) we need create a Handle like this:

impl AsyncHandle<Instant> for MyFirstTestActor {
    async fn async_handle(&mut self, _value: Instant) {
        self.some_other_data += 1;
        println!("New msg, counter: {}", self.some_other_data);
    }
}

Or sync handle if you do not need async

impl Handle<Instant> for MyFirstTestActor {
    fn handle(&mut self, _value: Instant) {
        self.some_other_data += 1;
        println!("New msg, counter: {}", self.some_other_data);
    }
}

For more complex values like enums, there is other macro ActorMsgHandle:

#[derive(ActorMsgHandle)]
#[actor(kind = "MyFirstTestActor")]
pub enum Value {
    MyGreetings(String),
    U32(u32),
    U64(u64),
}

So you will need describe handles only for String, u32 and u64

impl AsyncHandle<u32> for MyFirstTestActor {
    async fn async_handle(&mut self, value: u32) -> Continue {
        println!("New msg: {value}");
    }
}

All handles can return something. All return types:

Continue - actor continue live
Cmd<T> where T is MyActorShutdown - this is your custom command
Break - this command will break the infinite loop { select!{ ... } }
Resut<Continue, Cmd<T>>
Resut<Continue, Break>
Resut<Continue, Result<Break, Cmd<T>>>

Dependencies

~3–11MB
~109K SLoC