use futures::Future;
use futures::sync::oneshot::{channel, Receiver, Sender};
use std::collections::HashMap;
use tokio_core::reactor::{Core, Handle};
use actor::Actor;
use address::{Addr, Syn};
use arbiter::Arbiter;
use context::Context;
use handler::{Handler, Message};
use msgs::{StopArbiter, SystemExit};
pub struct System {
stop: Option<Sender<i32>>,
arbiters: HashMap<String, Addr<Syn, Arbiter>>,
}
impl Actor for System {
type Context = Context<Self>;
}
impl System {
#[cfg_attr(feature = "cargo-clippy", allow(new_ret_no_self))]
pub fn new<T: Into<String>>(name: T) -> SystemRunner {
let name = name.into();
let core = Arbiter::new_system(name.clone());
let (stop_tx, stop) = channel();
let sys = System {
arbiters: HashMap::new(),
stop: Some(stop_tx),
}.start();
Arbiter::set_system(sys, name);
SystemRunner { core, stop }
}
}
#[must_use = "SystemRunner must be run"]
pub struct SystemRunner {
core: Core,
stop: Receiver<i32>,
}
impl SystemRunner {
pub fn handle(&self) -> &Handle {
Arbiter::handle()
}
pub fn run(self) -> i32 {
let SystemRunner {
mut core, stop, ..
} = self;
match core.run(stop) {
Ok(code) => code,
Err(_) => 1,
}
}
pub fn run_until_complete<F, I, E>(&mut self, fut: F) -> Result<I, E>
where
F: Future<Item = I, Error = E>,
{
self.core.run(fut)
}
}
impl Handler<SystemExit> for System {
type Result = ();
fn handle(&mut self, msg: SystemExit, _: &mut Context<Self>) {
for addr in self.arbiters.values() {
addr.do_send(StopArbiter(msg.0));
}
if let Some(stop) = self.stop.take() {
let _ = stop.send(msg.0);
}
}
}
pub(crate) struct RegisterArbiter(pub String, pub Addr<Syn, Arbiter>);
#[doc(hidden)]
impl Message for RegisterArbiter {
type Result = ();
}
#[doc(hidden)]
impl Handler<RegisterArbiter> for System {
type Result = ();
fn handle(&mut self, msg: RegisterArbiter, _: &mut Context<Self>) {
self.arbiters.insert(msg.0, msg.1);
}
}
pub(crate) struct UnregisterArbiter(pub String);
#[doc(hidden)]
impl Message for UnregisterArbiter {
type Result = ();
}
#[doc(hidden)]
impl Handler<UnregisterArbiter> for System {
type Result = ();
fn handle(&mut self, msg: UnregisterArbiter, _: &mut Context<Self>) {
self.arbiters.remove(&msg.0);
}
}