use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::HashMap;
use std::default::Default;
use std::sync::{Arc, Mutex};
use actor::{Actor, Supervised};
use arbiter::Arbiter;
use address::{Address, SyncAddress};
use context::Context;
use supervisor::Supervisor;
pub struct Registry {
registry: RefCell<HashMap<TypeId, Box<Any>>>,
}
#[allow(unused_variables)]
pub trait ArbiterService: Actor<Context=Context<Self>> + Supervised + Default {
fn service_started(&mut self, ctx: &mut Context<Self>) {}
}
#[allow(unused_variables)]
pub trait SystemService: Actor<Context=Context<Self>> + Supervised + Default {
fn service_started(&mut self, ctx: &mut Context<Self>) {}
}
impl Registry {
pub(crate) fn new() -> Self {
Registry{registry: RefCell::new(HashMap::new())}
}
pub fn get<A: ArbiterService + Actor<Context=Context<A>>>(&self) -> Address<A> {
let id = TypeId::of::<A>();
if let Some(addr) = self.registry.borrow().get(&id) {
if let Some(addr) = addr.downcast_ref::<Address<A>>() {
return addr.clone()
}
}
let addr: Address<_> = A::create(|ctx| {
let mut act = A::default();
act.service_started(ctx);
act
});
self.registry.borrow_mut().insert(id, Box::new(addr.clone()));
addr
}
}
pub struct SystemRegistry {
#[cfg_attr(feature="cargo-clippy", allow(type_complexity))]
registry: Arc<Mutex<RefCell<HashMap<TypeId, Box<Any>>>>>,
}
unsafe impl Send for SystemRegistry {}
impl SystemRegistry {
pub(crate) fn new() -> Self {
SystemRegistry{registry: Arc::new(Mutex::new(RefCell::new(HashMap::new())))}
}
pub fn get<A: SystemService + Actor<Context=Context<A>>>(&self) -> SyncAddress<A> {
if let Ok(hm) = self.registry.lock() {
if let Some(addr) = hm.borrow().get(&TypeId::of::<A>()) {
match addr.downcast_ref::<SyncAddress<A>>() {
Some(addr) => {
return addr.clone()
},
None =>
error!("Got unknown value: {:?}", addr),
}
}
let addr = Supervisor::start_in(&Arbiter::system_arbiter(), false, |ctx| {
let mut act = A::default();
act.service_started(ctx);
act
}).expect("System is dead");
hm.borrow_mut().insert(TypeId::of::<A>(), Box::new(addr.clone()));
return addr
}
panic!("System registry lock is poisoned");
}
}
impl Clone for SystemRegistry {
fn clone(&self) -> Self {
SystemRegistry{registry: Arc::clone(&self.registry)}
}
}