use crate::common::tsafe::TSafe;
use crate::actors::dispatcher::Dispatcher;
use crate::actors::mailbox::Mailbox;
use crate::actors::actor_context::ActorContext;
use crate::actors::actor::Actor;
use crate::actors::actor_path::ActorPath;
use crate::actors::abstract_actor_system::AbstractActorSystem;
use crate::actors::envelope::Envelope;
use crate::actors::abstract_actor_ref::AbstractActorRef;
use crate::actors::abstract_actor_ref::ActorRef;
use crate::actors::local_actor_ref::LocalActorRef;
use crate::actors::watcher::WatchingEvents;
use crate::actors::message::Message;
use crate::actors::error::Error;
use crate::actors::supervision::SupervisionStrategy;
use std::collections::HashMap;
use std::any::Any;
pub struct ActorCell {
pub dispatcher: TSafe<Dispatcher + Send>,
pub mailbox: TSafe<Mailbox + Send>,
pub bid: usize,
pub actor: TSafe<Actor + Send>,
pub path: TSafe<ActorPath>,
pub system: TSafe<AbstractActorSystem + Send>,
pub suspended: bool,
pub stopped: bool,
pub parent: Option<TSafe<ActorCell>>,
pub childs: HashMap<String, TSafe<ActorCell>>,
pub supervision_strategy: SupervisionStrategy
}
impl ActorCell {
pub fn new(system: TSafe<AbstractActorSystem + Send>,
path: TSafe<ActorPath>,
actor: TSafe<Actor + Send>,
bid: usize,
dispatcher: TSafe<Dispatcher + Send>,
mailbox: TSafe<Mailbox + Send>,
parent: Option<TSafe<ActorCell>>,
supervision_strategy: SupervisionStrategy) -> ActorCell {
ActorCell {
actor,
bid,
dispatcher,
mailbox,
path,
system,
suspended: false,
stopped: true,
parent,
childs: HashMap::new(),
supervision_strategy
}
}
pub fn fail(&mut self, err: Error, boxed_self: TSafe<ActorCell>) -> impl FnOnce() -> () {
let system = self.system.clone();
let path = self.path.clone();
let supervision_strategy = self.supervision_strategy.clone();
move || {
let self_: ActorRef = Box::new(LocalActorRef::new(boxed_self.clone(), path));
let sender = system.lock().unwrap().dead_letters();
let system = system.clone();
let ctx = ActorContext::new(sender, self_.clone(), system, boxed_self.clone());
match supervision_strategy {
SupervisionStrategy::Resume => {
let actor = {
let boxed_self = boxed_self.lock().unwrap();
boxed_self.actor.clone()
};
actor.lock().unwrap().pre_fail(ctx, err, SupervisionStrategy::Resume);
},
SupervisionStrategy::Restart => {
let actor = {
let boxed_self = boxed_self.lock().unwrap();
boxed_self.actor.clone()
};
actor.lock().unwrap().pre_fail(ctx, err, SupervisionStrategy::Restart);
let f = boxed_self.lock().unwrap().restart(boxed_self.clone());
f();
},
SupervisionStrategy::Stop => {
let actor = {
let boxed_self = boxed_self.lock().unwrap();
boxed_self.actor.clone()
};
actor.lock().unwrap().pre_fail(ctx, err, SupervisionStrategy::Stop);
let f = boxed_self.lock().unwrap().stop(boxed_self.clone());
f();
},
SupervisionStrategy::Escalate => {
let (actor, parent) = {
let boxed_self = boxed_self.lock().unwrap();
(boxed_self.actor.clone(), boxed_self.parent.clone())
};
actor.lock().unwrap().pre_fail(ctx, err.clone(), SupervisionStrategy::Escalate);
let parent = parent.unwrap();
let f = parent.lock().unwrap().fail(err, parent.clone());
f();
}
};
}
}
pub fn start(self: &mut Self, boxed_self: TSafe<ActorCell>) -> impl FnOnce() -> () {
self.bid = self.dispatcher.lock().unwrap().obtain_bid();
let self_ = Box::new(LocalActorRef::new(boxed_self.clone(), self.path.clone()));
let sender = self.system.lock().unwrap().dead_letters();
let system = self.system.clone();
let ctx = ActorContext::new(sender, self_, system, boxed_self.clone());
move || {
let actor = {
let boxed_self = boxed_self.lock().unwrap();
boxed_self.actor.clone()
};
actor.lock().unwrap().pre_start(ctx);
boxed_self.lock().unwrap().stopped = false;
}
}
pub fn restart(self: &mut Self, boxed_self: TSafe<ActorCell>) -> impl FnOnce() -> () {
let self_ = Box::new(LocalActorRef::new(boxed_self.clone(), self.path.clone()));
let sender = self.system.lock().unwrap().dead_letters();
let system = self.system.clone();
let ctx = ActorContext::new(sender, self_, system, boxed_self.clone());
move || {
let f = {
let mut boxed_self_o = boxed_self.lock().unwrap();
let f = boxed_self_o.stop(boxed_self.clone());
f
};
f();
let f = {
let mut boxed_self_o = boxed_self.lock().unwrap();
let f = boxed_self_o.start(boxed_self.clone());
f
};
f();
let (actor, system) = {
let boxed_self = boxed_self.lock().unwrap();
(boxed_self.actor.clone(), boxed_self.system.clone())
};
actor.lock().unwrap().post_restart(ctx);
}
}
pub fn stop(self: &mut Self, boxed_self: TSafe<ActorCell>) -> impl FnOnce() -> () {
self.stopped = true;
for (path, cell) in self.childs.iter() {
let cell = cell.clone();
let boxed_cell = cell.clone();
let f = cell.lock().unwrap().stop(boxed_cell);
f();
}
self.childs.clear();
let self_: ActorRef = Box::new(LocalActorRef::new(boxed_self.clone(), self.path.clone()));
let sender = self.system.lock().unwrap().dead_letters();
let system = self.system.clone();
let ctx = ActorContext::new(sender, self_.clone(), system, boxed_self.clone());
move || {
let (actor, system) = {
let boxed_self = boxed_self.lock().unwrap();
(boxed_self.actor.clone(), boxed_self.system.clone())
};
actor.lock().unwrap().post_stop(ctx);
system.lock().unwrap().register_watch_event(&self_, WatchingEvents::Terminated);
}
}
pub fn suspend(self: &mut Self) {
self.suspended = true;
}
pub fn send(self: &mut Self,
boxed_self: &TSafe<ActorCell>,
msg: Message,
rself: Option<ActorRef>,
to_ref: Box<AbstractActorRef + Send>) {
if self.stopped || self.suspended {
let mut dead_letters = self.system.lock().unwrap().dead_letters();
dead_letters.cell().lock().unwrap().send(&dead_letters.cell(),
msg, rself,
to_ref);
} else {
let envelope = Envelope::new(
msg,
rself,
to_ref,
self.system.clone());
self.dispatcher.lock().unwrap().dispatch(
boxed_self.clone(),
self.bid,
self.mailbox.clone(),
self.actor.clone(), envelope);
}
}
pub fn force_send(self: &mut Self,
boxed_self: TSafe<ActorCell>,
msg: Message,
rself: Option<Box<AbstractActorRef + Send>>,
to_ref: Box<AbstractActorRef + Send>) {
let envelope = Envelope::new(
msg,
rself,
to_ref,
self.system.clone());
self.dispatcher.lock().unwrap().dispatch(
boxed_self,
self.bid,
self.mailbox.clone(),
self.actor.clone(), envelope);
}
}