use std::{
any::{self, Any},
convert::Infallible,
time::Duration,
};
use async_trait::async_trait;
use simpl_actor::{actor, Actor, ActorError, ActorRef, ActorStopReason, ShouldRestart, Spawn};
pub struct CounterActor {
count: i64,
}
#[async_trait]
impl Actor for CounterActor {
type Error = Infallible;
async fn on_start(&mut self, _id: u64) -> Result<(), Self::Error> {
println!("starting actor {}", any::type_name::<Self>());
Ok(())
}
async fn on_panic(&mut self, _err: Box<dyn Any + Send>) -> Result<ShouldRestart, Self::Error> {
println!("restarting actor {}", any::type_name::<Self>());
Ok(ShouldRestart::Yes)
}
async fn on_stop(self, reason: ActorStopReason) -> Result<(), Self::Error> {
println!(
"stopping actor {} because {reason}",
any::type_name::<Self>()
);
Ok(())
}
}
#[actor]
impl CounterActor {
pub fn new() -> Self {
CounterActor { count: 0 }
}
#[message]
pub fn inc(&mut self, amount: i64) {
self.count += amount;
}
#[message]
pub fn count(&self) -> i64 {
self.count
}
#[message]
pub async fn sleep(&self) {
tokio::time::sleep(Duration::from_millis(500)).await;
}
#[message]
pub async fn inc_myself(&self) -> Result<(), ActorError<i64>> {
self.actor_ref().inc_async(1).await
}
#[message]
pub fn force_panic(&self) {
panic!("forced panic, don't worry this is correct and the actor will be restarted")
}
}
#[tokio::main(flavor = "current_thread")]
async fn main() {
let counter = CounterActor::new();
let actor = counter.spawn();
assert_eq!(actor.inc(2).await, Ok(()));
assert_eq!(actor.count().await, Ok(2));
assert_eq!(actor.sleep_async().await, Ok(()));
for _ in 0..CounterActor::mailbox_size() {
assert_eq!(actor.inc_async(1).await, Ok(()));
}
assert_eq!(actor.try_inc(1).await, Err(ActorError::MailboxFull(1)));
assert_eq!(
actor.inc_timeout(1, Duration::from_millis(200)).await,
Err(ActorError::Timeout(1))
);
assert_eq!(actor.force_panic().await, Err(ActorError::ActorStopped));
assert_eq!(actor.inc(1).await, Ok(()));
assert_eq!(actor.count().await, Ok(67));
actor.stop_immediately();
actor.wait_for_stop().await;
assert_eq!(actor.inc(1).await, Err(ActorError::ActorNotRunning(1)));
}