pupactor 0.2.0

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:

```rust
#[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:

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


```rust
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`:

```rust
#[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`

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