use std::error::Error;
use std::sync::Arc;
use crate::actor::actor_context::{ActorContext, ContextFlag};
use crate::actor::backup::Backup;
use crate::actor::mailbox::Mailbox;
use crate::actor_system::ActorSystem;
use crate::address::Addr;
use crate::behavior::Behavior;
use crate::message::Message;
#[derive(Clone, Copy, Debug)]
pub enum ExitReason {
Kill,
Restart,
Error
}
pub struct Actor<S: Send + 'static> {
state: S,
behavior: Behavior<S>,
mailbox: Mailbox,
addr: Addr,
context: ActorContext
}
pub enum MailboxType {
Bounded(usize),
Unbounded
}
impl<S: Send + 'static> Actor<S> {
pub fn new(state: S, behavior: Behavior<S>, mailbox_type: MailboxType) -> Self {
let mailbox;
match mailbox_type {
MailboxType::Bounded(buffer_size) => {
mailbox = Mailbox::bounded(buffer_size);
}
MailboxType::Unbounded => {
mailbox = Mailbox::unbounded();
}
}
let addr = mailbox.get_addr();
let ctx = ActorContext::new(addr.clone());
Self {
state,
behavior,
mailbox: mailbox,
addr: addr,
context: ctx
}
}
fn handle(&mut self, m: Message) -> Option<Box<dyn Error>> {
let res = self.behavior.handle(m, &mut self.state, &mut self.context);
match res {
Ok(new_behavior) => {
if let Some(new_behavior) = new_behavior {
self.behavior = new_behavior;
}
None
}
Err(err) => {
Some(err)
}
}
}
fn on_start(&mut self) {
if let Some(f) = self.behavior.on_start {
f(&mut self.state, &mut self.context);
}
}
fn on_error(&mut self) {
if let Some(f) = self.behavior.on_error {
f(&mut self.state, &mut self.context);
}
}
fn on_kill(&mut self) {
if let Some(f) = self.behavior.on_kill {
f(&mut self.state, &mut self.context);
}
}
fn on_restart(&mut self) {
if let Some(f) = self.behavior.on_restart {
f(&mut self.state, &mut self.context);
}
}
pub(crate) async fn run(&mut self) -> ExitReason {
self.on_start();
loop {
match self.context.flag {
ContextFlag::Run => {
if let Some(msg) = self.mailbox.recv().await {
if let Some(_err) = self.handle(msg) {
self.on_error();
return ExitReason::Error;
}
}
}
ContextFlag::Kill => {
self.on_kill();
return ExitReason::Kill;
},
ContextFlag::Restart => {
self.on_restart();
return ExitReason::Restart;
}
}
}
}
pub fn get_addr(&self) -> Addr {
self.addr.clone()
}
pub(crate) fn set_actor_sys(&mut self, sys: Arc<ActorSystem>) {
self.context.set_actor_sys(sys);
}
pub fn check_state(&self, check: fn(&S) -> bool) -> bool {
check(&self.state)
}
}
impl<S: Send + 'static + Clone> Actor<S> {
pub(crate) fn create_backup(&self) -> Backup<S> {
Backup::new(self.state.clone(), self.behavior.clone())
}
pub(crate) fn apply_backup(&mut self, backup: &Backup<S>) {
self.state = backup.get_state();
self.behavior = backup.get_behavior();
}
}