use std::fmt::Debug;
use std::sync::Arc;
use dashmap::mapref::entry::Entry::Occupied;
use dashmap::mapref::entry::Entry::Vacant;
use dashmap::DashMap;
use once_cell::sync::OnceCell;
use crate::ActorCell;
use crate::ActorId;
use crate::SupervisionEvent;
#[derive(Clone)]
pub enum PidLifecycleEvent {
Spawn(ActorCell),
Terminate(ActorCell),
}
impl Debug for PidLifecycleEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Spawn(who) => {
write!(f, "Spawn {}", who.get_id())
}
Self::Terminate(who) => {
write!(f, "Terminate {}", who.get_id())
}
}
}
}
static PID_REGISTRY: OnceCell<Arc<DashMap<ActorId, ActorCell>>> = OnceCell::new();
static PID_REGISTRY_LISTENERS: OnceCell<Arc<DashMap<ActorId, ActorCell>>> = OnceCell::new();
fn get_pid_registry<'a>() -> &'a Arc<DashMap<ActorId, ActorCell>> {
PID_REGISTRY.get_or_init(|| Arc::new(DashMap::new()))
}
fn get_pid_listeners<'a>() -> &'a Arc<DashMap<ActorId, ActorCell>> {
PID_REGISTRY_LISTENERS.get_or_init(|| Arc::new(DashMap::new()))
}
pub(crate) fn register_pid(id: ActorId, actor: ActorCell) -> Result<(), super::ActorRegistryErr> {
if id.is_local() {
match get_pid_registry().entry(id) {
Occupied(_o) => Err(super::ActorRegistryErr::AlreadyRegistered(format!(
"PID {id} already alive"
))),
Vacant(v) => {
v.insert(actor.clone());
for listener in get_pid_listeners().iter() {
let _ =
listener
.value()
.send_supervisor_evt(SupervisionEvent::PidLifecycleEvent(
PidLifecycleEvent::Spawn(actor.clone()),
));
}
Ok(())
}
}
} else {
Ok(())
}
}
pub(crate) fn unregister_pid(id: ActorId) {
if id.is_local() {
if let Some((_, cell)) = get_pid_registry().remove(&id) {
for listener in get_pid_listeners().iter() {
let _ = listener
.value()
.send_supervisor_evt(SupervisionEvent::PidLifecycleEvent(
PidLifecycleEvent::Terminate(cell.clone()),
));
}
}
}
}
pub fn get_all_pids() -> Vec<ActorCell> {
get_pid_registry()
.iter()
.map(|v| v.value().clone())
.collect::<Vec<_>>()
}
pub fn where_is_pid(id: ActorId) -> Option<ActorCell> {
if id.is_local() {
get_pid_registry().get(&id).map(|v| v.value().clone())
} else {
None
}
}
pub fn monitor(actor: ActorCell) {
get_pid_listeners().insert(actor.get_id(), actor);
}
pub fn demonitor(actor: ActorId) {
let _ = get_pid_listeners().remove(&actor);
}