use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::HashMap;
use std::default::Default;
use std::hash::BuildHasherDefault;
use std::rc::Rc;
use std::sync::Arc;
use fnv::FnvHasher;
use parking_lot::ReentrantMutex;
use actor::{Actor, Supervised};
use address::Addr;
use arbiter::Arbiter;
use context::Context;
use supervisor::Supervisor;
use system::System;
type AnyMap = HashMap<TypeId, Box<Any>, BuildHasherDefault<FnvHasher>>;
#[derive(Clone)]
pub struct Registry {
registry: Rc<RefCell<AnyMap>>,
}
#[allow(unused_variables)]
pub trait ArbiterService: Actor<Context = Context<Self>> + Supervised + Default {
fn start_service() -> Addr<Self> {
Supervisor::start(|ctx| {
let mut act = Self::default();
act.service_started(ctx);
act
})
}
fn service_started(&mut self, ctx: &mut Context<Self>) {}
fn from_registry() -> Addr<Self> {
Arbiter::registry().get::<Self>()
}
}
impl Registry {
pub(crate) fn new() -> Self {
Registry {
registry: Rc::new(RefCell::new(HashMap::default())),
}
}
pub fn get<A: ArbiterService + Actor<Context = Context<A>>>(&self) -> Addr<A> {
let id = TypeId::of::<A>();
if let Some(addr) = self.registry.borrow().get(&id) {
if let Some(addr) = addr.downcast_ref::<Addr<A>>() {
return addr.clone();
}
}
let addr: Addr<A> = A::start_service();
self.registry
.borrow_mut()
.insert(id, Box::new(addr.clone()));
addr
}
pub fn set<A: ArbiterService + Actor<Context = Context<A>>>(&self, addr: Addr<A>) {
let id = TypeId::of::<A>();
if let Some(addr) = self.registry.borrow().get(&id) {
if addr.downcast_ref::<Addr<A>>().is_some() {
panic!("Actor already started");
}
}
self.registry.borrow_mut().insert(id, Box::new(addr));
}
}
pub struct SystemRegistry {
system: Addr<Arbiter>,
registry: InnerRegistry,
}
type AnyMapSend = HashMap<TypeId, Box<Any + Send>, BuildHasherDefault<FnvHasher>>;
type InnerRegistry = Arc<ReentrantMutex<RefCell<AnyMapSend>>>;
#[allow(unused_variables)]
pub trait SystemService: Actor<Context = Context<Self>> + Supervised + Default {
fn start_service(sys: &Addr<Arbiter>) -> Addr<Self> {
Supervisor::start_in_arbiter(sys, |ctx| {
let mut act = Self::default();
act.service_started(ctx);
act
})
}
fn service_started(&mut self, ctx: &mut Context<Self>) {}
fn from_registry() -> Addr<Self> {
System::with_current(|sys| sys.registry().get::<Self>())
}
}
impl SystemRegistry {
pub(crate) fn new(system: Addr<Arbiter>) -> Self {
SystemRegistry {
system,
registry: Arc::new(ReentrantMutex::new(RefCell::new(HashMap::default()))),
}
}
pub fn get<A: SystemService + Actor<Context = Context<A>>>(&self) -> Addr<A> {
let hm = self.registry.lock();
if let Some(addr) = hm.borrow().get(&TypeId::of::<A>()) {
match addr.downcast_ref::<Addr<A>>() {
Some(addr) => return addr.clone(),
None => panic!("Got unknown value: {:?}", addr),
}
}
let addr = A::start_service(&self.system);
hm.borrow_mut()
.insert(TypeId::of::<A>(), Box::new(addr.clone()));
addr
}
pub fn set<A: SystemService + Actor<Context = Context<A>>>(&self, addr: Addr<A>) {
let hm = self.registry.lock();
if let Some(addr) = hm.borrow().get(&TypeId::of::<A>()) {
if let Some(_) = addr.downcast_ref::<Addr<A>>() {
panic!("Actor already started");
}
}
hm.borrow_mut()
.insert(TypeId::of::<A>(), Box::new(addr.clone()));
}
}
impl Clone for SystemRegistry {
fn clone(&self) -> Self {
SystemRegistry {
system: self.system.clone(),
registry: Arc::clone(&self.registry),
}
}
}