use std::any::Any;
use std::sync::Arc;
use actors::{InnerMessage, Message, SystemMessage};
use actors::actor_cell::ActorCell;
use actors::cthulhu::Cthulhu;
#[derive(Debug, Eq, Hash, PartialEq)]
pub enum ActorPath {
Local(String),
Distant(ConnectionInfo),
}
impl ActorPath {
pub fn new_local(path: String) -> Arc<ActorPath> {
Arc::new(ActorPath::Local(path))
}
pub fn new_distant(distant_logical_path: String, addr_port: String) -> Arc<ActorPath> {
Arc::new(ActorPath::Distant(
ConnectionInfo {
distant_logical_path: distant_logical_path,
addr_port: addr_port,
}))
}
pub fn logical_path(&self) -> &String {
match *self {
ActorPath::Local(ref s) => s,
ActorPath::Distant(ref c) => &(c.distant_logical_path),
}
}
pub fn child(&self, name: String) -> Arc<ActorPath> {
match *self {
ActorPath::Local(ref s) => {
let path = format!("{}/{}", s, name);
ActorPath::new_local(path)
},
ActorPath::Distant(_) => panic!("Cannot create a child for a distant actor."),
}
}
}
#[derive(Debug, Eq, Hash, PartialEq)]
pub struct ConnectionInfo {
distant_logical_path: String,
addr_port: String,
}
impl ConnectionInfo {
pub fn distant_logical_path(&self) -> &String {
&self.distant_logical_path
}
pub fn addr_port(&self) -> &String {
&self.addr_port
}
}
#[derive(Clone)]
enum InnerActor {
Cthulhu(Cthulhu),
Actor(ActorCell),
}
pub struct ActorRef {
inner_actor: Option<InnerActor>,
path: Arc<ActorPath>,
}
impl ActorRef {
pub fn new_distant(path: Arc<ActorPath>) -> ActorRef {
ActorRef {
inner_actor: None,
path: path,
}
}
pub fn with_cthulhu(cthulhu: Cthulhu) -> ActorRef {
let path = ActorPath::new_local("/".to_owned());
ActorRef {
inner_actor: Some(InnerActor::Cthulhu(cthulhu)),
path: path,
}
}
pub fn with_cell(cell: ActorCell, path: Arc<ActorPath>) -> ActorRef {
ActorRef {
inner_actor: Some(InnerActor::Actor(cell)),
path: path,
}
}
pub fn receive_system_message(&self, system_message: SystemMessage) {
info!("{} receiving a system message", self.path().logical_path());
let inner = self.inner_actor.as_ref().expect("Tried to put a system message in the mailbox of a distant actor.");
match *inner {
InnerActor::Actor(ref actor) => actor.receive_system_message(system_message),
InnerActor::Cthulhu(ref cthulhu) => cthulhu.receive_system_message(),
};
}
pub fn receive(&self, message: InnerMessage, sender: ActorRef) {
info!("{} receiving a message", self.path().logical_path());
let inner = self.inner_actor.as_ref().expect("Tried to put a message in the mailbox of a distant actor.");
match *inner {
InnerActor::Actor(ref actor) => actor.receive_message(message, sender),
InnerActor::Cthulhu(ref cthulhu) => cthulhu.receive(),
};
}
pub fn handle(&self) {
info!("{} handling a message", self.path().logical_path());
let inner = self.inner_actor.as_ref().expect("");
match *inner {
InnerActor::Actor(ref actor) => actor.handle_envelope(),
InnerActor::Cthulhu(ref cthulhu) => cthulhu.handle(),
};
}
pub fn path(&self) -> Arc<ActorPath> {
self.path.clone()
}
pub fn tell_to<MessageTo: Message>(&self, to: ActorRef, message: MessageTo) {
info!("{} is sending a message to {}", self.path().logical_path(), to.path().logical_path());
let message: Box<Any + Send> = Box::new(message);
to.receive(InnerMessage::Message(message), self.clone())
}
}
impl Clone for ActorRef {
fn clone(&self) -> ActorRef {
ActorRef {
inner_actor: self.inner_actor.clone(),
path: self.path.clone(),
}
}
}