Skip to content

Commit

Permalink
Another major refactor. Main effects: mutable actors cannot be cloned…
Browse files Browse the repository at this point in the history
…, actors begin acting immediately instead of having an action() method.
  • Loading branch information
Lee committed Apr 13, 2015
1 parent f946fa9 commit 3b9023b
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 276 deletions.
96 changes: 53 additions & 43 deletions src/actors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,70 +12,80 @@
// <https://www.gnu.org/licenses/>.

pub mod understudy;
pub mod scene;

use std::marker::PhantomData;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::Sender;

pub use self::understudy::Understudy;
pub use self::scene::{Scene, Scenic};

pub struct Telegram<M: Send + 'static>(pub M, pub u32);

pub struct Null;

pub enum ActorError {
CueError,
Internal(String),
}
pub type Actor<M> = Box<Cueable<Message=M>>;

pub trait Cueable {
type Message: Send;
pub trait Cueable: Send {
type Message: Send + 'static;
fn cue(&self, msg: Self::Message) -> Result<(), ActorError>;
}

pub struct Actor<M: Send + 'static, A: Send + 'static> {
tx: Sender<Telegram<M>>,
tag: u32,
head_count: Arc<Mutex<u32>>,
phantom: PhantomData<*const A>,
#[derive(Clone)]
pub struct ActorStruct<M: Send + 'static>(Sender<M>);

impl<M: Send + 'static> ActorStruct<M> {
pub fn new(tx: Sender<M>) -> Actor<M> {
Box::new(ActorStruct(tx))
}
}

impl<M: Send + 'static> Cueable for ActorStruct<M> {
type Message = M;
fn cue(&self, msg: M) -> Result<(), ActorError> {
self.0.send(msg).map_err(|_| ActorError::CueError)
}
}

impl<M: Send, A: Send> Actor<M, A> {
pub struct ActorStructMut<M: Send + 'static>(Sender<M>);

pub fn new(tx: Sender<Telegram<M>>) -> Actor<M, A> {
Actor {
tx: tx,
tag: 0,
head_count: Arc::new(Mutex::new(0)),
phantom: PhantomData
}
impl<M: Send + 'static> ActorStructMut<M> {
pub fn new(tx: Sender<M>) -> Actor<M> {
Box::new(ActorStruct(tx))
}
}

impl<M: Send, A: Send> Cueable for Actor<M, A> {
impl<M: Send + 'static> Cueable for ActorStructMut<M> {
type Message = M;

fn cue(&self, data: M) -> Result<(), ActorError> {
self.tx.send(Telegram(data, self.tag)).map_err(|_| ActorError::CueError)
fn cue(&self, msg: M) -> Result<(), ActorError> {
self.0.send(msg).map_err(|_| ActorError::CueError)
}
}

pub enum ActorError {
CueError,
Internal(String),
}

impl<M: Send, A: Send> Clone for Actor<M, A> where A: Clone {
fn clone(&self) -> Actor<M, A> {
let tag;
{
let mut n = self.head_count.lock().unwrap();
*n += 1;
tag = *n;
}
Actor {
tx: self.tx.clone(),
tag: tag,
head_count: self.head_count.clone(),
phantom: PhantomData,
}
#[cfg(test)]
mod tests {

use actors::*;

actor!{ Generator(x: u8, next: Actor<u8>) => {
try!(next.cue(x));
}}

actor_mut!{ Summer(x: u8, next: Actor<u8>) :: msg: u8 => {
x += msg;
try!(next.cue(x));
if x == 5 { break_a_leg!(); }
}}

actor!{ Doubler(next: Actor<u8>) :: msg: u8 => {
try!(next.cue(msg * 2));
}}

#[test]
fn actors_work() {
let understudy = Understudy::new();
Generator::new(1, Summer::new(0, Doubler::new(understudy.stage())));
assert_eq!(understudy.read_all(), vec![2,4,6,8,10]);
}

}
51 changes: 0 additions & 51 deletions src/actors/scene.rs

This file was deleted.

47 changes: 18 additions & 29 deletions src/actors/understudy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,50 +12,40 @@
// <https://www.gnu.org/licenses/>.

use std::iter::Unfold;
use std::marker::PhantomData;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver};

use super::{Actor, ActorError, Cueable, Telegram, Null};
use super::{Actor, ActorStruct, ActorError, Cueable};

pub struct Understudy<M: Send + 'static> {
tx: Sender<Telegram<M>>,
rx: Receiver<Telegram<M>>
}
pub struct Understudy<M: Send + 'static>(Sender<M>, Receiver<M>);

impl<M: Send> Understudy<M> {
impl<M: Send + 'static> Understudy<M> {

pub fn new() -> Understudy<M> {
pub fn new() -> Box<Understudy<M>> {
let (tx, rx) = channel();
Understudy { tx: tx, rx: rx }
Box::new(Understudy(tx, rx))
}

pub fn read(&mut self) -> Vec<M> {
Unfold::new(&mut self.rx, |rx| rx.try_recv().map(|gram| gram.0).ok())
Unfold::new(&mut self.1, |rx| rx.try_recv().ok())
.collect::<Vec<_>>()
}

pub fn read_all(self) -> Vec<M> {
drop(self.tx);
self.rx.iter().map(|gram| gram.0).collect::<Vec<_>>()
drop(self.0);
self.1.iter().collect::<Vec<_>>()
}

pub fn stage(&self) -> Actor<M, Null> {
Actor {
tx: self.tx.clone(),
tag: 0,
head_count: Arc::new(Mutex::new(0)),
phantom: PhantomData,
}
pub fn stage(&self) -> Actor<M> {
ActorStruct::new(self.0.clone())
}

}

impl<M: Send> Cueable for Understudy<M> {
impl<M: Send + 'static> Cueable for Understudy<M> {
type Message = M;

fn cue(&self, data: M) -> Result<(), ActorError> {
self.tx.send(Telegram(data, 0)).map_err(|_| ActorError::CueError)
fn cue(&self, msg: M) -> Result<(), ActorError> {
self.0.send(msg).map_err(|_| ActorError::CueError)
}

}
Expand All @@ -72,16 +62,15 @@ mod tests {

#[test]
fn it_collects_messages_sent_to_it() {
let next = super::Understudy::new();
let fount = Fount5::new(next.stage().unwrap());
fount.action();
assert_eq!(next.read_all(), vec![0,1,2,3,4]);
let understudy = super::Understudy::new();
Fount5::new(understudy.stage());
assert_eq!(understudy.read_all(), vec![0,1,2,3,4]);
}

#[test]
fn it_can_be_cued_directly() {
let understudy: Understudy<u8> = super::Understudy::new();
assert!(understudy.cue(0).is_ok());
let understudy = super::Understudy::new();
assert!(understudy.cue(0u8).is_ok());
assert_eq!(understudy.read_all(), vec![0]);
}

Expand Down
10 changes: 0 additions & 10 deletions src/assist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,6 @@

#![macro_use]

use std::thread;
use actors::Scenic;

pub fn from_the_top(scenes: Vec<Box<Scenic>>) {
for scene in scenes {
scene.action();
}
thread::park();
}

#[macro_export]
macro_rules! break_a_leg {
() => ( return Ok(()); );
Expand Down
Loading

0 comments on commit 3b9023b

Please sign in to comment.