pupactor 0.2.1

Pupactor is actor model library built with tokio
Documentation

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>>>