<commit_before>use std::sync::mpsc::{channel};
use std::sync::mpsc::{Sender, Receiver, RecvError, SendError, TryRecvError};
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::thread;

/// Represents a pair of channels used for bi-directional communication.
/// T1 represents the type of data sent in one direction
/// T2 represents the type of data sent in the reverse direction
pub struct ChannelPair<T1, T2> {
    sender1 : Arc<Mutex<Sender<T1>>>,
    receiver1 : Arc<Mutex<Receiver<T1>>>,
    sender2 : Arc<Mutex<Sender<T2>>>,
    receiver2 : Arc<Mutex<Receiver<T2>>>
}

/// A sender and receiver pair that through which a thread can send messages and receive messages respectively
/// The sender and receiver are taken from opposite channels of a ChannelPair
pub struct SenderReceiverPair<T1, T2> {
    sender : Arc<Mutex<Sender<T1>>>,
    receiver : Arc<Mutex<Receiver<T2>>>,
    send_count: i64,
    receive_count: i64
}

/// An enumeration type representing either a send error or a receive error
pub struct SendOrReceiveError<T>
{
    send_error: Option<SendError<T>>,
    receive_error: Option<RecvError>
}

/// Implementation of a ChannelPair
impl<T1,T2> ChannelPair<T1, T2> {
    /// Constructs a new `ChannelPair<T1, T2>`.
    ///
    /// Each channel within the pair is constructed with a buffer size of 0.
    /// A buffer size of 0 means that a sender will be blocked from sending additional messages
    /// until any previously sent message has been received.
    ///
    /// # Examples
    ///
    /// ```text
    /// use coact::ChannelPair;
    ///
    /// let channel_pair = ChannelPair::new();
    /// ```
    pub fn new() -> ChannelPair<T1, T2> {
        ChannelPair::new_with_buffer_size(0, 0)
    }

    /// Constructs a new `ChannelPair<T1, T2>` with buffer sizes specified for each channel.
    ///
    /// The buffer size indicates how many messages can exist on the channel before a sender is blocked from adding additional messages
    /// Each channel in the pair can have a different buffer size
    ///
    /// # Examples
    ///
    /// ```text
    /// use coact::ChannelPair;
    ///
    /// let channel_pair = ChannelPair::new_with_buffer_size(5,3);
    /// ```
    pub fn new_with_buffer_size(buffer_size1 : usize, buffer_size2: usize) -> ChannelPair<T1, T2> {

        let (tx, rx) = channel::<T1>();
        let (tx2, rx2) = channel::<T2>();

        ChannelPair {
            sender1 : Arc::new(Mutex::new(tx)),
            receiver1 : Arc::new(Mutex::new(rx)),
            sender2 : Arc::new(Mutex::new(tx2)),
            receiver2 : Arc::new(Mutex::new(rx2))
        }
    }

    /// Constructs a Sender Receiver pair representing one end of the bi-directional communication
    ///
    /// # Examples
    ///
    /// ```text
    /// use coact::ChannelPair;
    ///
    /// let channel_pair : ChannelPair<i64,i32> = ChannelPair::new();
    /// let sr = channel_pair.first_sender_receiver();
    /// ```
    pub fn first_sender_receiver(&self) -> Box<SenderReceiverPair<T1, T2>> {
        Box::new(SenderReceiverPair {
            sender: self.sender1.clone(),
            receiver: self.receiver2.clone(),
            send_count: 0,
            receive_count: 0
        })
    }

    /// Constructs a Sender Receiver pair representing the reverse end of the bi-directional communication
    ///
    /// # Examples
    ///
    /// ```text
    /// use coact::ChannelPair;
    ///
    /// let channel_pair : ChannelPair<i64,i32> = ChannelPair::new();
    /// let sr = channel_pair.second_sender_receiver();
    /// ```
    pub fn second_sender_receiver(&self) -> Box<SenderReceiverPair<T2, T1>> {
        Box::new(SenderReceiverPair {
            sender: self.sender2.clone(),
            receiver: self.receiver1.clone(),
            send_count: 0,
            receive_count: 0
        })
    }
}

/// Implementation of `SenderReceiverPair<T1, T2>`
impl<T1,T2> SenderReceiverPair<T1, T2> {

    /// Sends a message without waiting for a response
    ///
    /// Even though this call can return before a response
    /// is received on the receiver, this call may still block if the buffer associated with the channel is full
    ///
    /// Returns a Result<(), SendError<T1>>
    ///
    /// # Examples
    ///
    /// ```text
    /// let sr = channel_pair.first_sender_receiver();
    /// let result = sr.send(50);
    /// if result.is_err() {
    ///        // do something
    /// }
    /// ```
    pub fn send(&mut self, payload: T1) -> Result<(), SendError<T1>> {
        let result = self.sender.lock().unwrap().send(payload);

        if result.is_ok() {
            self.send_count = self.send_count + 1;
        }

        result
    }

    /// Receive a message
    ///
    /// If there is no message on the channel this call will block until there is one
    ///
    /// Returns a Result<T2, RecvError>
    ///
    /// # Examples
    ///
    /// ```text
    /// let sr = channel_pair.second_sender_receiver();
    /// // . . .
    /// let result = sr.receive();
    /// if result.is_ok() {
    ///     let val = result.ok().unwrap();
    ///     // do something
    /// }
    /// ```
    pub fn receive(&mut self) -> Result<T2, RecvError> {
        let result = self.receiver.lock().unwrap().recv();

        if result.is_ok() {
            self.receive_count = self.receive_count + 1;
        }

        result
    }

    /// Try to receive a message if one is available
    ///
    /// If there is no message on the channel this call will return a result containing a `TryRecvError`
    ///
    /// Returns a Result<T2, TryRecvError>
    ///
    /// # Examples
    ///
    /// ```text
    /// let sr = channel_pair.second_sender_receiver();
    /// // . . .
    /// let result = sr.try_receive();
    /// if result.is_ok() {
    ///     let val = result.ok().unwrap();
    ///     // do something
    /// }
    /// ```
    pub fn try_receive(&mut self) -> Result<T2, TryRecvError> {
        let result = self.receiver.lock().unwrap().try_recv();

        if result.is_ok() {
            self.receive_count = self.receive_count + 1;
        }

        result
    }

    /// Send a message and wait for a response
    ///
    /// This call will block until a response is recieved
    ///
    /// Returns a Result<T2, SendOrReceiveError<T1>>
    ///
    /// # Examples
    ///
    /// ```text
    /// let sr = channel_pair.second_sender_receiver();
    /// // . . .
    /// let result = sr.send_and_receive(56);
    /// if result.is_ok() {
    ///     let val = result.ok().unwrap();
    ///     // do something
    /// }
    /// ```
    pub fn send_and_receive(&mut self, payload: T1) -> Result<T2, SendOrReceiveError<T1>> {
        let send_result = self.send(payload);

        if !send_result.is_ok() {
            return Err(SendOrReceiveError { send_error: send_result.err(), receive_error: None });
        }

        let receive_result = self.receive();

        if !receive_result.is_ok() {
            return Err(SendOrReceiveError { send_error: None, receive_error: receive_result.err() });
        }

        Ok(receive_result.ok().unwrap())
    }
}

/// Indicates the `SenderReceiverPair<T1, T2>` is safe for Sync (multi-threaded) operations
unsafe impl<T1, T2> Sync for SenderReceiverPair<T1, T2>  {}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::{Arc, Mutex};
    use std::thread;

    #[test]
    fn coordinate_via_bidirectional() {

        // create a ChannelPair
        let chan_pair : Arc<ChannelPair<i64,i64>> = Arc::new(ChannelPair::new_with_buffer_size(0, 0));

        // get one end of the bi-direction communication
        let mut controller_receive_responder = chan_pair.first_sender_receiver();

        // get the reverse end of the bi-direction communication
        let mut worker_sender_waiter = chan_pair.second_sender_receiver();

        // spawn a thread to perform work in coordination with the main thread
        {
            thread::spawn(|| {
                let mut sw = worker_sender_waiter;
                let mut x:i64 = 0;
                // send a value to the main thread and get the response
                let rpayload = sw.send_and_receive(x).ok().unwrap();
                // increment the value returned from the main thread
                x =  rpayload + 5;
                // send the new value to the main thread and wait for a response
                let rpayload = sw.send_and_receive(x).ok().unwrap();
                // increment the value returned from the main thread
                x =  rpayload + 3;
                // send the new value to the main thread and wait for a response
                let _ = sw.send_and_receive(x).ok().unwrap();
            });
        }
        // receive a value from the worker thread
        let mut mpayload = controller_receive_responder.receive().ok().unwrap();
        // send an incremented value back
        controller_receive_responder.send(mpayload + 3);
        // receive a value from the worker thread
        mpayload = controller_receive_responder.receive().ok().unwrap();
        // send an incremented value back
        controller_receive_responder.send(mpayload + 3);
        // receive a value from the worker thread
        mpayload = controller_receive_responder.receive().ok().unwrap();
        // send an incremented value back
        controller_receive_responder.send(mpayload + 3);

        // check that the threads have worked together to produce the expected result
        assert_eq!(14, mpayload);
    }
}<commit_msg>Added Pipe with asynchronous and synchronous connectors<commit_after>use std::sync::mpsc::{channel};
use std::sync::mpsc::{Sender, Receiver, RecvError, SendError, TryRecvError};
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::thread;
use std::thread::{JoinHandle};
use std::marker::PhantomData;

pub struct Pipe<I,O: 'static> {
    out_connecter: Arc<Mutex<Connector<O>>>,
    inner_transform: fn(I) -> O
}

unsafe impl<I,O> Send for Pipe<I,O> {}
unsafe impl<O> Send for Connector<O> {}

pub enum Connector<T> {
    SynchronousConnector {
        pipe: Arc<Mutex<Processor<T>>>
    },
    AsynchronousConnector {
        pipe: Arc<Mutex<Processor<T> + Send>>,
        sender : Arc<Mutex<Sender<T>>>,
        receiver : Arc<Mutex<Receiver<T>>>,
        thread_handle: JoinHandle<()>
    },
    DoNothingConnector
}

impl<I: 'static + Send> Connector<I> {
    pub fn sync_connector(pipe: Arc<Mutex<Processor<I>>>) -> Connector<I> {
        Connector::<I>::SynchronousConnector {
            pipe: pipe
        }
    }

    pub fn async_connector(pipe: Arc<Mutex<Processor<I> + Send>>) -> Connector<I> {
        let (tx, rx) = channel::<I>();

        let txarc = Arc::new(Mutex::new(tx));
        let rxarc = Arc::new(Mutex::new(rx));

        let pipearc_clone = pipe.clone();
        let rxarc_clone = rxarc.clone();

        Connector::AsynchronousConnector {
            pipe: pipe,
            sender: txarc,
            receiver: rxarc,
            thread_handle: thread::spawn(move || {
                while(true) {
                    let result = rxarc_clone.lock().unwrap().recv();

                    if result.is_ok() {
                        pipearc_clone.lock().unwrap().process(result.ok().unwrap());
                    }
                }
            })
        }
    }
}

impl<I: 'static + Send, O: 'static> Pipe<I, O> {
    pub fn new(transform: fn(I) -> O) -> Pipe<I, O> {
        let dnc = Connector::DoNothingConnector;
        Pipe::<I,O>::new_with_connector(transform, dnc)
    }

    pub fn new_with_connector(transform: fn(I) -> O, connector: Connector<O>) -> Pipe<I, O> {
        Pipe {
            out_connecter: Arc::new(Mutex::new(connector)),
            inner_transform: transform
        }
    }

    pub fn connect(&mut self, connector: Connector<O>) {
        self.out_connecter = Arc::new(Mutex::new(connector));
    }
}

pub trait Processor<T> {
    fn process(&self, T) -> ();
}

impl<I, O> Processor<I> for Pipe<I, O> {
    fn process(&self, data: I) -> () {
        let output = (self.inner_transform)(data);
        self.out_connecter.lock().unwrap().process(output)
    }
}

impl<T> Processor<T> for Connector<T> {
    fn process(&self, data: T) -> () {
        match *self {
            Connector::DoNothingConnector => (),
            Connector::SynchronousConnector { pipe: ref pipe } => pipe.lock().unwrap().process(data),
            Connector::AsynchronousConnector {
                pipe: ref pipe,
                sender : ref sender,
                receiver : ref receiver,
                thread_handle: ref thread_handle
            }   =>  { sender.lock().unwrap().send(data); },
        }
    }
}

/// Represents a pair of channels used for bi-directional communication.
/// T1 represents the type of data sent in one direction
/// T2 represents the type of data sent in the reverse direction
pub struct ChannelPair<T1, T2> {
    sender1 : Arc<Mutex<Sender<T1>>>,
    receiver1 : Arc<Mutex<Receiver<T1>>>,
    sender2 : Arc<Mutex<Sender<T2>>>,
    receiver2 : Arc<Mutex<Receiver<T2>>>
}

/// A sender and receiver pair that through which a thread can send messages and receive messages respectively
/// The sender and receiver are taken from opposite channels of a ChannelPair
pub struct SenderReceiverPair<T1, T2> {
    sender : Arc<Mutex<Sender<T1>>>,
    receiver : Arc<Mutex<Receiver<T2>>>,
    send_count: i64,
    receive_count: i64
}

/// An enumeration type representing either a send error or a receive error
pub struct SendOrReceiveError<T>
{
    send_error: Option<SendError<T>>,
    receive_error: Option<RecvError>
}

/// Implementation of a ChannelPair
impl<T1,T2> ChannelPair<T1, T2> {
    /// Constructs a new `ChannelPair<T1, T2>`.
    ///
    /// Each channel within the pair is constructed with a buffer size of 0.
    /// A buffer size of 0 means that a sender will be blocked from sending additional messages
    /// until any previously sent message has been received.
    ///
    /// # Examples
    ///
    /// ```text
    /// use coact::ChannelPair;
    ///
    /// let channel_pair = ChannelPair::new();
    /// ```
    pub fn new() -> ChannelPair<T1, T2> {
        ChannelPair::new_with_buffer_size(0, 0)
    }

    /// Constructs a new `ChannelPair<T1, T2>` with buffer sizes specified for each channel.
    ///
    /// The buffer size indicates how many messages can exist on the channel before a sender is blocked from adding additional messages
    /// Each channel in the pair can have a different buffer size
    ///
    /// # Examples
    ///
    /// ```text
    /// use coact::ChannelPair;
    ///
    /// let channel_pair = ChannelPair::new_with_buffer_size(5,3);
    /// ```
    pub fn new_with_buffer_size(buffer_size1 : usize, buffer_size2: usize) -> ChannelPair<T1, T2> {

        let (tx, rx) = channel::<T1>();
        let (tx2, rx2) = channel::<T2>();

        ChannelPair {
            sender1 : Arc::new(Mutex::new(tx)),
            receiver1 : Arc::new(Mutex::new(rx)),
            sender2 : Arc::new(Mutex::new(tx2)),
            receiver2 : Arc::new(Mutex::new(rx2))
        }
    }

    /// Constructs a Sender Receiver pair representing one end of the bi-directional communication
    ///
    /// # Examples
    ///
    /// ```text
    /// use coact::ChannelPair;
    ///
    /// let channel_pair : ChannelPair<i64,i32> = ChannelPair::new();
    /// let sr = channel_pair.first_sender_receiver();
    /// ```
    pub fn first_sender_receiver(&self) -> Box<SenderReceiverPair<T1, T2>> {
        Box::new(SenderReceiverPair {
            sender: self.sender1.clone(),
            receiver: self.receiver2.clone(),
            send_count: 0,
            receive_count: 0
        })
    }

    /// Constructs a Sender Receiver pair representing the reverse end of the bi-directional communication
    ///
    /// # Examples
    ///
    /// ```text
    /// use coact::ChannelPair;
    ///
    /// let channel_pair : ChannelPair<i64,i32> = ChannelPair::new();
    /// let sr = channel_pair.second_sender_receiver();
    /// ```
    pub fn second_sender_receiver(&self) -> Box<SenderReceiverPair<T2, T1>> {
        Box::new(SenderReceiverPair {
            sender: self.sender2.clone(),
            receiver: self.receiver1.clone(),
            send_count: 0,
            receive_count: 0
        })
    }
}

/// Implementation of `SenderReceiverPair<T1, T2>`
impl<T1,T2> SenderReceiverPair<T1, T2> {

    /// Sends a message without waiting for a response
    ///
    /// Even though this call can return before a response
    /// is received on the receiver, this call may still block if the buffer associated with the channel is full
    ///
    /// Returns a Result<(), SendError<T1>>
    ///
    /// # Examples
    ///
    /// ```text
    /// let sr = channel_pair.first_sender_receiver();
    /// let result = sr.send(50);
    /// if result.is_err() {
    ///        // do something
    /// }
    /// ```
    pub fn send(&mut self, payload: T1) -> Result<(), SendError<T1>> {
        let result = self.sender.lock().unwrap().send(payload);

        if result.is_ok() {
            self.send_count = self.send_count + 1;
        }

        result
    }

    /// Receive a message
    ///
    /// If there is no message on the channel this call will block until there is one
    ///
    /// Returns a Result<T2, RecvError>
    ///
    /// # Examples
    ///
    /// ```text
    /// let sr = channel_pair.second_sender_receiver();
    /// // . . .
    /// let result = sr.receive();
    /// if result.is_ok() {
    ///     let val = result.ok().unwrap();
    ///     // do something
    /// }
    /// ```
    pub fn receive(&mut self) -> Result<T2, RecvError> {
        let result = self.receiver.lock().unwrap().recv();

        if result.is_ok() {
            self.receive_count = self.receive_count + 1;
        }

        result
    }

    /// Try to receive a message if one is available
    ///
    /// If there is no message on the channel this call will return a result containing a `TryRecvError`
    ///
    /// Returns a Result<T2, TryRecvError>
    ///
    /// # Examples
    ///
    /// ```text
    /// let sr = channel_pair.second_sender_receiver();
    /// // . . .
    /// let result = sr.try_receive();
    /// if result.is_ok() {
    ///     let val = result.ok().unwrap();
    ///     // do something
    /// }
    /// ```
    pub fn try_receive(&mut self) -> Result<T2, TryRecvError> {
        let result = self.receiver.lock().unwrap().try_recv();

        if result.is_ok() {
            self.receive_count = self.receive_count + 1;
        }

        result
    }

    /// Send a message and wait for a response
    ///
    /// This call will block until a response is recieved
    ///
    /// Returns a Result<T2, SendOrReceiveError<T1>>
    ///
    /// # Examples
    ///
    /// ```text
    /// let sr = channel_pair.second_sender_receiver();
    /// // . . .
    /// let result = sr.send_and_receive(56);
    /// if result.is_ok() {
    ///     let val = result.ok().unwrap();
    ///     // do something
    /// }
    /// ```
    pub fn send_and_receive(&mut self, payload: T1) -> Result<T2, SendOrReceiveError<T1>> {
        let send_result = self.send(payload);

        if !send_result.is_ok() {
            return Err(SendOrReceiveError { send_error: send_result.err(), receive_error: None });
        }

        let receive_result = self.receive();

        if !receive_result.is_ok() {
            return Err(SendOrReceiveError { send_error: None, receive_error: receive_result.err() });
        }

        Ok(receive_result.ok().unwrap())
    }
}

/// Indicates the `SenderReceiverPair<T1, T2>` is safe for Sync (multi-threaded) operations
unsafe impl<T1, T2> Sync for SenderReceiverPair<T1, T2>  {}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::{Arc, Mutex};
    use std::thread;

    fn double(i:i64) -> i64 {
        println!("double");
        format!("Value before double is: {}",i);
        i*2
    }
    fn triple(i:i64) -> i64 {
        println!("triple");
        format!("Value before triple is: {}",i);
        i*3
    }

    #[test]
    fn pipe() {
        println!("starting");
        // create a Pipe
        let mut double_pipe = Arc::new(Mutex::new(Pipe::new(double)));
        let mut triple_pipe = Arc::new(Mutex::new(Pipe::new(triple)));
        let mut second_double_pipe = Arc::new(Mutex::new(Pipe::new(double)));

        let val:i64 = 50;

        let connector1 = Connector::<i64>::sync_connector(triple_pipe.clone());
        let connector2 = Connector::<i64>::sync_connector(second_double_pipe.clone());
        // connect the pipes
        double_pipe.lock().unwrap().connect(connector1);
        triple_pipe.lock().unwrap().connect(connector2);

        double_pipe.lock().unwrap().process(val);
    }

    #[test]
    fn coordinate_via_bidirectional() {

        // create a ChannelPair
        let chan_pair : Arc<ChannelPair<i64,i64>> = Arc::new(ChannelPair::new_with_buffer_size(0, 0));

        // get one end of the bi-direction communication
        let mut controller_receive_responder = chan_pair.first_sender_receiver();

        // get the reverse end of the bi-direction communication
        let mut worker_sender_waiter = chan_pair.second_sender_receiver();

        // spawn a thread to perform work in coordination with the main thread
        {
            thread::spawn(|| {
                let mut sw = worker_sender_waiter;
                let mut x:i64 = 0;
                // send a value to the main thread and get the response
                let rpayload = sw.send_and_receive(x).ok().unwrap();
                // increment the value returned from the main thread
                x =  rpayload + 5;
                // send the new value to the main thread and wait for a response
                let rpayload = sw.send_and_receive(x).ok().unwrap();
                // increment the value returned from the main thread
                x =  rpayload + 3;
                // send the new value to the main thread and wait for a response
                let _ = sw.send_and_receive(x).ok().unwrap();
            });
        }
        // receive a value from the worker thread
        let mut mpayload = controller_receive_responder.receive().ok().unwrap();
        // send an incremented value back
        controller_receive_responder.send(mpayload + 3);
        // receive a value from the worker thread
        mpayload = controller_receive_responder.receive().ok().unwrap();
        // send an incremented value back
        controller_receive_responder.send(mpayload + 3);
        // receive a value from the worker thread
        mpayload = controller_receive_responder.receive().ok().unwrap();
        // send an incremented value back
        controller_receive_responder.send(mpayload + 3);

        // check that the threads have worked together to produce the expected result
        assert_eq!(14, mpayload);
    }
}<|endoftext|>


<commit_before>//! Jamal provides a bi-directional interface for transformations between json and yaml documents.
extern crate serde_json;
extern crate serde_yaml;

use serde_json::Value as JsonValue;
use serde_yaml::Value as YamlValue;
use std::error::Error as StdError;
use std::num::ParseFloatError;
use std::collections::BTreeMap;

/// represents potential errors that can happen during the transformation process
#[derive(Debug)]
pub enum Error {
    /// Occurs when an attempt to parse a `serde_yaml::Real` as an `f64` fails
    ParseFloat(ParseFloatError),
    /// Occurs when a transformation is requested for an invalid value
    InvalidValue,
    /// Occurs when an unsupported transformation is requested
    UnsupportedValue(YamlValue)
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ParseFloat(ref e) => e.description(),
            Error::InvalidValue => "invalid value",
            Error::UnsupportedValue(_) => "supported value",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Error::ParseFloat(ref e) => Some(e),
            _ => None,
        }
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "{:?}", self)
    }
}

/// A result type with a fixed type for `jamal::Errors`
pub type Result<T> = std::result::Result<T, Error>;

impl From<ParseFloatError> for Error {
    fn from(error: ParseFloatError) -> Error {
        Error::ParseFloat(error)
    }
}

/// converts a `serde_json::Value` into a `serde_yaml::Value`
pub fn to_yaml(json: &JsonValue) -> Result<YamlValue> {
    match json {
        &JsonValue::Null => Ok(YamlValue::Null),
        &JsonValue::Bool(ref value) => Ok(YamlValue::Boolean(value.clone())),
        &JsonValue::I64(ref value) => Ok(YamlValue::Integer(value.clone())),
        &JsonValue::U64(ref value) => Ok(YamlValue::Integer(value.clone() as i64)),
        &JsonValue::F64(ref value) => Ok(YamlValue::Real(value.to_string())),
        &JsonValue::String(ref value) => Ok(YamlValue::String(value.clone())),
        &JsonValue::Array(ref values) => {
            let mut yaml_values = vec![];
            for value in values {
                yaml_values.push(try!(to_yaml(&value)));
            }
            Ok(YamlValue::Array(yaml_values))
        }
        &JsonValue::Object(ref value) => {
            let mut yaml_value = BTreeMap::new();
            for (k, v) in value {
                let yaml = try!(to_yaml(&v));
                yaml_value.insert(YamlValue::String(k.clone()), yaml);
            }
            Ok(YamlValue::Hash(yaml_value))
        }
    }
}

/// converts a `serde_yaml::Value` into a `serde_json::Value`
pub fn to_json(yaml: &YamlValue) -> Result<JsonValue> {
    match yaml {
        &YamlValue::Real(ref value) => Ok(JsonValue::F64(try!(value.parse::<f64>()))),
        &YamlValue::Integer(ref value) => Ok(JsonValue::I64(value.clone())),
        &YamlValue::String(ref value) => Ok(JsonValue::String(value.clone())),
        &YamlValue::Boolean(ref value) => Ok(JsonValue::Bool(value.clone())),
        &YamlValue::Array(ref values) => {
            let mut json_values = vec![];
            for value in values {
                let json = try!(to_json(&value));
                json_values.push(json);
            }
            Ok(JsonValue::Array(json_values))
        }
        &YamlValue::Hash(ref value) => {
            let mut json_value = BTreeMap::new();
            for (k, v) in value {
                match k {
                    &YamlValue::String(ref key) => {
                        let json = try!(to_json(&v));
                        json_value.insert(key.clone(), json);
                    }
                    unsupported => return Err(Error::UnsupportedValue(unsupported.clone())),
                }
            }
            Ok(JsonValue::Object(json_value))
        }
        alias @ &YamlValue::Alias(_) => Err(Error::UnsupportedValue(alias.clone())),
        &YamlValue::Null => Ok(JsonValue::Null),
        &YamlValue::BadValue => Err(Error::InvalidValue),
    }
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;
    use super::serde_json;
    use super::serde_yaml;
    use super::{to_json, to_yaml};

    #[test]
    fn json_to_yaml() {
        let input = serde_json::to_value(&vec!["foo"]);
        let output = serde_yaml::Value::Array(vec![serde_yaml::Value::String("foo".to_owned())]);
        assert_eq!(to_yaml(&input).unwrap(), output);
    }

    #[test]
    fn yaml_to_json() {
        let input = serde_yaml::to_value(&vec!["foo"]);
        let output = serde_json::Value::Array(vec![serde_json::Value::String("foo".to_owned())]);
        assert_eq!(to_json(&input).unwrap(), output);
    }
}
<commit_msg>increase test cov<commit_after>//! Jamal provides a bi-directional interface for transformations between json and yaml documents.
extern crate serde_json;
extern crate serde_yaml;

use serde_json::Value as JsonValue;
use serde_yaml::Value as YamlValue;
use std::error::Error as StdError;
use std::num::ParseFloatError;
use std::collections::BTreeMap;

/// represents potential errors that can happen during the transformation process
#[derive(Debug)]
pub enum Error {
    /// Occurs when an attempt to parse a `serde_yaml::Real` as an `f64` fails
    ParseFloat(ParseFloatError),
    /// Occurs when a transformation is requested for an invalid value
    InvalidValue,
    /// Occurs when an unsupported transformation is requested
    UnsupportedValue(YamlValue)
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::ParseFloat(ref e) => e.description(),
            Error::InvalidValue => "invalid value",
            Error::UnsupportedValue(_) => "supported value",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Error::ParseFloat(ref e) => Some(e),
            _ => None,
        }
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "{:?}", self)
    }
}

/// A result type with a fixed type for `jamal::Errors`
pub type Result<T> = std::result::Result<T, Error>;

impl From<ParseFloatError> for Error {
    fn from(error: ParseFloatError) -> Error {
        Error::ParseFloat(error)
    }
}

/// converts a `serde_json::Value` into a `serde_yaml::Value`
pub fn to_yaml(json: &JsonValue) -> Result<YamlValue> {
    match json {
        &JsonValue::Null => Ok(YamlValue::Null),
        &JsonValue::Bool(ref value) => Ok(YamlValue::Boolean(value.clone())),
        &JsonValue::I64(ref value) => Ok(YamlValue::Integer(value.clone())),
        &JsonValue::U64(ref value) => Ok(YamlValue::Integer(value.clone() as i64)),
        &JsonValue::F64(ref value) => Ok(YamlValue::Real(value.to_string())),
        &JsonValue::String(ref value) => Ok(YamlValue::String(value.clone())),
        &JsonValue::Array(ref values) => {
            let mut yaml_values = vec![];
            for value in values {
                yaml_values.push(try!(to_yaml(&value)));
            }
            Ok(YamlValue::Array(yaml_values))
        }
        &JsonValue::Object(ref value) => {
            let mut yaml_value = BTreeMap::new();
            for (k, v) in value {
                let yaml = try!(to_yaml(&v));
                yaml_value.insert(YamlValue::String(k.clone()), yaml);
            }
            Ok(YamlValue::Hash(yaml_value))
        }
    }
}

/// converts a `serde_yaml::Value` into a `serde_json::Value`
pub fn to_json(yaml: &YamlValue) -> Result<JsonValue> {
    match yaml {
        &YamlValue::Real(ref value) => Ok(JsonValue::F64(try!(value.parse::<f64>()))),
        &YamlValue::Integer(ref value) => Ok(JsonValue::I64(value.clone())),
        &YamlValue::String(ref value) => Ok(JsonValue::String(value.clone())),
        &YamlValue::Boolean(ref value) => Ok(JsonValue::Bool(value.clone())),
        &YamlValue::Array(ref values) => {
            let mut json_values = vec![];
            for value in values {
                let json = try!(to_json(&value));
                json_values.push(json);
            }
            Ok(JsonValue::Array(json_values))
        }
        &YamlValue::Hash(ref value) => {
            let mut json_value = BTreeMap::new();
            for (k, v) in value {
                match k {
                    &YamlValue::String(ref key) => {
                        let json = try!(to_json(&v));
                        json_value.insert(key.clone(), json);
                    }
                    unsupported => return Err(Error::UnsupportedValue(unsupported.clone())),
                }
            }
            Ok(JsonValue::Object(json_value))
        }
        alias @ &YamlValue::Alias(_) => Err(Error::UnsupportedValue(alias.clone())),
        &YamlValue::Null => Ok(JsonValue::Null),
        &YamlValue::BadValue => Err(Error::InvalidValue),
    }
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;
    use super::serde_json;
    use super::serde_yaml;
    use super::{to_json, to_yaml};

    #[test]
    fn json_str_vec_to_yaml() {
        let input = serde_json::to_value(&vec!["foo"]);
        let output = serde_yaml::Value::Array(vec![serde_yaml::Value::String("foo".to_owned())]);
        assert_eq!(to_yaml(&input).unwrap(), output);
    }

    #[test]
    fn yaml_str_vec_to_json() {
        let input = serde_yaml::to_value(&vec!["foo"]);
        let output = serde_json::Value::Array(vec![serde_json::Value::String("foo".to_owned())]);
        assert_eq!(to_json(&input).unwrap(), output);
    }

    #[test]
    fn json_obj_to_yaml() {
        let mut json_obj = BTreeMap::new();
        json_obj.insert("foo", 1);
        let input = serde_json::to_value(&json_obj);

        let mut yaml_obj = BTreeMap::new();
        yaml_obj.insert(serde_yaml::Value::String("foo".to_owned()), serde_yaml::Value::Integer(1));
        let output = serde_yaml::Value::Hash(yaml_obj);
        assert_eq!(to_yaml(&input).unwrap(), output);
    }

    #[test]
    fn yaml_obj_to_json() {
        let mut yaml_obj = BTreeMap::new();
        yaml_obj.insert("foo", 1);
        let input = serde_yaml::to_value(&yaml_obj);

        let mut json_obj = BTreeMap::new();
        json_obj.insert("foo".to_owned(), serde_json::Value::I64(1));
        let output = serde_json::Value::Object(json_obj);
        assert_eq!(to_json(&input).unwrap(), output);
    }

}
<|endoftext|>


<commit_before>extern crate libc;
extern crate nix;

use std::io;
use std::io::{Write, Read, Error, ErrorKind};
use nix::errno::Errno;
use nix::Error::Sys;
use nix::sys::termios;
use nix::sys::termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON, OPOST, CS8, ECHO, ICANON, IEXTEN, ISIG, VMIN, VTIME};

static MAX_LINE: i32 = 4096;
static UNSUPPORTED_TERM: [&'static str; 3] = ["dumb","cons25","emacs"];

fn is_a_tty() -> bool {
    let isatty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
    isatty
}

fn is_unsupported_term() -> bool {
    let term = std::env::var("TERM").ok().unwrap();
    let mut unsupported = false;
    for iter in &UNSUPPORTED_TERM {
        unsupported = term == *iter
    }
    unsupported
}

fn enable_raw_mode() -> Result<termios::Termios, nix::Error> {
    if !is_a_tty() {
        Err(Sys(Errno::ENOTTY))
    } else {
        let original_term = try!(termios::tcgetattr(libc::STDIN_FILENO));
        let mut raw = original_term;
        raw.c_iflag = raw.c_iflag   & !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
        raw.c_oflag = raw.c_oflag   & !(OPOST);
        raw.c_cflag = raw.c_cflag   | (CS8);
        raw.c_lflag = raw.c_lflag   & !(ECHO | ICANON | IEXTEN | ISIG);
        raw.c_cc[VMIN] = 1;
        raw.c_cc[VTIME] = 0;
        try!(termios::tcsetattr(libc::STDIN_FILENO, termios::TCSAFLUSH, &raw));
        Ok(original_term)
    }
}

fn disable_raw_mode(original_termios: termios::Termios) -> Result<(), nix::Error> {
    try!(termios::tcsetattr(libc::STDIN_FILENO, termios::TCSAFLUSH, &original_termios));
    Ok(())
}

fn readline_raw() -> Result<String, io::Error> {
    let mut buffer = Vec::new();
    let mut input: [u8; 1] = [0];

    if is_a_tty() {
        let original_termios = match enable_raw_mode() {
            Err(Sys(Errno::ENOTTY)) => return Err(Error::new(ErrorKind::Other, "Not a TTY")),
            Err(Sys(Errno::EBADF))  => return Err(Error::new(ErrorKind::Other, "Not a file descriptor")),
            Err(..)                 => return Err(Error::new(ErrorKind::Other, "Unknown Error")),
            Ok(term)                => term
        };

        let numread = io::stdin().read(&mut input).unwrap();
        buffer.push(input[0]);
        println!("Read #{:?} bytes with a value of{:?}",numread,input[0]);

        match disable_raw_mode(original_termios) {
            Err(..) => return Err(Error::new(ErrorKind::Other, "Failed to revert to original termios")),
            Ok(..)  => ()
        }
        Ok(String::from_utf8(buffer).unwrap())
    } else {

        let mut line = String::new();
        match io::stdin().read_line(&mut line) {
            Ok(_) => Ok(line),
            Err(e) => Err(e),
        }
    }
}

pub fn readline(prompt: &'static str) -> Result<String, io::Error> {
    // Write prompt and flush it to stdout
    let mut stdout = io::stdout();
    try!(stdout.write(prompt.as_bytes()));
    try!(stdout.flush());

    if is_unsupported_term() {
        let mut line = String::new();
        match io::stdin().read_line(&mut line) {
            Ok(_) => Ok(line),
            Err(e) => Err(e),
        }
    } else {
        readline_raw()
    }
}
<commit_msg>Created a readline_edit function that will handle all user input action<commit_after>extern crate libc;
extern crate nix;

use std::io;
use std::io::{Write, Read, Error, ErrorKind};
use nix::errno::Errno;
use nix::Error::Sys;
use nix::sys::termios;
use nix::sys::termios::{BRKINT, ICRNL, INPCK, ISTRIP, IXON, OPOST, CS8, ECHO, ICANON, IEXTEN, ISIG, VMIN, VTIME};

static MAX_LINE: i32 = 4096;
static UNSUPPORTED_TERM: [&'static str; 3] = ["dumb","cons25","emacs"];

fn is_a_tty() -> bool {
    let isatty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;
    isatty
}

fn is_unsupported_term() -> bool {
    let term = std::env::var("TERM").ok().unwrap();
    let mut unsupported = false;
    for iter in &UNSUPPORTED_TERM {
        unsupported = term == *iter
    }
    unsupported
}

fn enable_raw_mode() -> Result<termios::Termios, nix::Error> {
    if !is_a_tty() {
        Err(Sys(Errno::ENOTTY))
    } else {
        let original_term = try!(termios::tcgetattr(libc::STDIN_FILENO));
        let mut raw = original_term;
        raw.c_iflag = raw.c_iflag   & !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
        raw.c_oflag = raw.c_oflag   & !(OPOST);
        raw.c_cflag = raw.c_cflag   | (CS8);
        raw.c_lflag = raw.c_lflag   & !(ECHO | ICANON | IEXTEN | ISIG);
        raw.c_cc[VMIN] = 1;
        raw.c_cc[VTIME] = 0;
        try!(termios::tcsetattr(libc::STDIN_FILENO, termios::TCSAFLUSH, &raw));
        Ok(original_term)
    }
}

fn disable_raw_mode(original_termios: termios::Termios) -> Result<(), nix::Error> {
    try!(termios::tcsetattr(libc::STDIN_FILENO, termios::TCSAFLUSH, &original_termios));
    Ok(())
}

fn readline_edit() -> Result<String, io::Error> {
    let mut buffer = Vec::new();
    let mut input: [u8; 1] = [0];
    let numread = io::stdin().read(&mut input).unwrap();
    buffer.push(input[0]);
    println!("Read #{:?} bytes with a value of{:?}",numread,input[0]);
    Ok(String::from_utf8(buffer).unwrap())
}

fn readline_raw() -> Result<String, io::Error> {
    if is_a_tty() {
        let original_termios = match enable_raw_mode() {
            Err(Sys(Errno::ENOTTY)) => return Err(Error::new(ErrorKind::Other, "Not a TTY")),
            Err(Sys(Errno::EBADF))  => return Err(Error::new(ErrorKind::Other, "Not a file descriptor")),
            Err(..)                 => return Err(Error::new(ErrorKind::Other, "Unknown Error")),
            Ok(term)                => term
        };

        let user_input = readline_edit();

        match disable_raw_mode(original_termios) {
            Err(..) => return Err(Error::new(ErrorKind::Other, "Failed to revert to original termios")),
            Ok(..)  => ()
        }

        user_input
    } else {

        let mut line = String::new();
        match io::stdin().read_line(&mut line) {
            Ok(_) => Ok(line),
            Err(e) => Err(e),
        }
    }
}

pub fn readline(prompt: &'static str) -> Result<String, io::Error> {
    // Write prompt and flush it to stdout
    let mut stdout = io::stdout();
    try!(stdout.write(prompt.as_bytes()));
    try!(stdout.flush());

    if is_unsupported_term() {
        let mut line = String::new();
        match io::stdin().read_line(&mut line) {
            Ok(_) => Ok(line),
            Err(e) => Err(e),
        }
    } else {
        readline_raw()
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_variables)]

#![feature(read_exact)]

extern crate byteorder;
extern crate time;

use std::io;
use std::io::prelude::*;
use std::net::TcpStream;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::thread;
use std::sync::mpsc;
use std::sync::mpsc::Receiver;
use byteorder::{ByteOrder, LittleEndian};
use time::{Duration, PreciseTime};

pub struct Ntr {
    tcp_stream: TcpStream,
    current_seq: AtomicUsize,
    is_heartbeat_sendable: AtomicBool,
    read_mem_rx: Receiver<Vec<u8>>,
}
unsafe impl Sync for Ntr {} // TODO: fix this properly
impl Ntr {
    pub fn connect(address: &str) -> io::Result<Arc<Self>> {
        let tcp_stream = try!(TcpStream::connect(&(address.to_owned() + ":8000") as &str));
        let (read_mem_tx, read_mem_rx) = mpsc::channel();

        let ntr = Arc::new(Ntr {
            tcp_stream: tcp_stream,
            current_seq: AtomicUsize::new(1000),
            is_heartbeat_sendable: AtomicBool::new(true),
            read_mem_rx: read_mem_rx,
        });

        // spawn receiver thread
        {
            let ntr = ntr.clone();
            thread::spawn(move || {
                let mut ntr_stream = NtrStream::new(&ntr);
                let mut buf = [0u8; 84];
                loop {
                    if let Err(_) = ntr_stream.tcp_stream().read_exact(&mut buf) {
                        break;
                    }
                    let seq = LittleEndian::read_u32(&buf[4..8]);
                    let cmd = LittleEndian::read_u32(&buf[12..16]);
                    let data_len = LittleEndian::read_u32(&buf[80..84]) as usize;

                    if data_len != 0 {
                        let mut data_buf = Vec::with_capacity(data_len);
                        ntr_stream.tcp_stream().read_exact(&mut data_buf[0..data_len]).unwrap();
                        if cmd == 0 {
                            ntr_stream.is_heartbeat_sendable().store(true, Ordering::SeqCst);
                        } else if cmd == 9 {
                            read_mem_tx.send(data_buf).unwrap();
                        }
                    }
                }
            });
        }

        // spawn heartbeat thread
        {
            let ntr = ntr.clone();
            thread::spawn(move || {
                let mut ntr_stream = NtrStream::new(&ntr);
                let one_second = Duration::seconds(1);
                let mut heartbeat_sent_time = PreciseTime::now();
                ntr_stream.send_heartbeat_packet().unwrap();
                loop {
                    if heartbeat_sent_time.to(PreciseTime::now()) >= one_second
                     && ntr_stream.is_heartbeat_sendable().compare_and_swap(true, false, Ordering::SeqCst) {
                        ntr_stream.send_heartbeat_packet().unwrap();
                        heartbeat_sent_time = PreciseTime::now();
                    }
                    thread::sleep_ms(100);
                }
            });
        }

        Ok(ntr)
    }

    pub fn disconnect(self) {}

    pub fn read_mem(&mut self, addr: u32, size: u32, pid: u32) -> Result<Vec<u8>, ()> {
        let mut ntr_stream = NtrStream::new(&self);
        try!(ntr_stream.send_read_mem_packet(addr, size, pid).map_err(|_x| ()));
        self.read_mem_rx.recv().map_err(|_x| ())
    }

    pub fn write_mem(&mut self, addr: u32, data: Vec<u8>) {
        unimplemented!();
    }
}

#[derive(Debug)]
struct NtrStream<'a> {
    tcp_stream: TcpStream,
    current_seq: &'a AtomicUsize,
    is_heartbeat_sendable: &'a AtomicBool,
}
impl<'a> NtrStream<'a> {
    fn new(ntr: &'a Ntr) -> Self {
        NtrStream {
            tcp_stream: ntr.tcp_stream.try_clone().unwrap(),
            current_seq: &ntr.current_seq,
            is_heartbeat_sendable: &ntr.is_heartbeat_sendable,
        }
    }

    fn send_packet(&mut self, packet_type: u32, cmd: u32, args: &Vec<u32>, data_len: u32) -> io::Result<usize> {
        let mut buf = [0u8; 84];

        LittleEndian::write_u32(&mut buf[0..4], 0x12345678);
        LittleEndian::write_u32(&mut buf[4..8], self.current_seq.fetch_add(1000, Ordering::SeqCst) as u32);
        LittleEndian::write_u32(&mut buf[8..12], packet_type);
        LittleEndian::write_u32(&mut buf[12..16], cmd);
        for i in 0..16 {
            LittleEndian::write_u32(&mut buf[(4 * i + 16)..(4 * i + 20)], args[i]);
        }
        LittleEndian::write_u32(&mut buf[80..84], data_len);

        self.tcp_stream.write(&buf)
    }

    fn send_read_mem_packet(&mut self, addr: u32, size: u32, pid: u32) -> io::Result<usize> {
        self.send_empty_packet(9, pid, addr, size)
    }

    fn send_write_mem_packet(&mut self, addr: u32, pid: u32, buf: &Vec<u8>) -> io::Result<usize> {
        let args = &mut vec![0u32; 16];
        args[0] = pid;
        args[1] = addr;
        args[2] = buf.len() as u32;
        self.send_packet(1, 10, args, args[2])
            .and(self.tcp_stream.write(buf))
    }

    fn send_heartbeat_packet(&mut self) -> io::Result<usize> {
        self.send_packet(0, 0, &vec![0u32; 16], 0)
    }

    fn send_hello_packet(&mut self) -> io::Result<usize> {
        self.send_packet(0, 3, &vec![0u32; 16], 0)
    }

    fn send_reload_packet(&mut self) -> io::Result<usize> {
        self.send_packet(0, 4, &vec![0u32; 16], 0)
    }

    fn send_empty_packet(&mut self, cmd: u32, arg0: u32, arg1: u32, arg2: u32) -> io::Result<usize> {
        let args = &mut vec![0u32, 16];
        args[0] = arg0;
        args[1] = arg1;
        args[2] = arg2;
        self.send_packet(0, cmd, args, 0)
    }

    fn tcp_stream(&mut self) -> &TcpStream {
        &self.tcp_stream
    }

    fn is_heartbeat_sendable(&self) -> &AtomicBool {
        &self.is_heartbeat_sendable
    }
}<commit_msg>fixed memory reading<commit_after>#![allow(dead_code)]
#![allow(unused_variables)]

#![feature(read_exact)]

extern crate byteorder;
extern crate time;

use std::io;
use std::io::prelude::*;
use std::net::TcpStream;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::thread;
use std::sync::mpsc;
use std::sync::mpsc::Receiver;
use byteorder::{ByteOrder, LittleEndian};
use time::{Duration, PreciseTime};

pub struct Ntr {
    tcp_stream: TcpStream,
    current_seq: AtomicUsize,
    is_heartbeat_sendable: AtomicBool,
    read_mem_rx: Receiver<Vec<u8>>,
}
unsafe impl Sync for Ntr {} // TODO: fix this properly
impl Ntr {
    pub fn connect(address: &str) -> io::Result<Arc<Self>> {
        let tcp_stream = try!(TcpStream::connect(&(address.to_owned() + ":8000") as &str));
        let (read_mem_tx, read_mem_rx) = mpsc::channel();

        let ntr = Arc::new(Ntr {
            tcp_stream: tcp_stream,
            current_seq: AtomicUsize::new(1000),
            is_heartbeat_sendable: AtomicBool::new(true),
            read_mem_rx: read_mem_rx,
        });

        // spawn receiver thread
        {
            let ntr = ntr.clone();
            thread::spawn(move || {
                let mut ntr_stream = NtrStream::new(&ntr);
                let mut buf = [0u8; 84];
                loop {
                    if let Err(_) = ntr_stream.tcp_stream().read_exact(&mut buf) {
                        break;
                    }
                    //let seq = LittleEndian::read_u32(&buf[4..8]);
                    let cmd = LittleEndian::read_u32(&buf[12..16]);
                    let data_len = LittleEndian::read_u32(&buf[80..84]) as usize;

                    if data_len != 0 {
                        let mut data_buf = vec![0u8; data_len];
                        ntr_stream.tcp_stream().read_exact(&mut data_buf[0..data_len]).unwrap();
                        if cmd == 0 {
                            ntr_stream.is_heartbeat_sendable().store(true, Ordering::SeqCst);
                        } else if cmd == 9 {
                            read_mem_tx.send(data_buf).unwrap();
                        }
                    }
                }
            });
        }

        // spawn heartbeat thread
        {
            let ntr = ntr.clone();
            thread::spawn(move || {
                let mut ntr_stream = NtrStream::new(&ntr);
                let one_second = Duration::seconds(1);
                let mut heartbeat_sent_time = PreciseTime::now();
                ntr_stream.send_heartbeat_packet().unwrap();
                loop {
                    if heartbeat_sent_time.to(PreciseTime::now()) >= one_second
                     && ntr_stream.is_heartbeat_sendable().compare_and_swap(true, false, Ordering::SeqCst) {
                        ntr_stream.send_heartbeat_packet().unwrap();
                        heartbeat_sent_time = PreciseTime::now();
                    }
                    thread::sleep_ms(100);
                }
            });
        }

        Ok(ntr)
    }

    pub fn read_mem(&self, addr: u32, size: u32, pid: u32) -> Result<Vec<u8>, ()> {
        let mut ntr_stream = NtrStream::new(&self);
        try!(ntr_stream.send_read_mem_packet(addr, size, pid).map_err(|_x| ()));
        self.read_mem_rx.recv().map_err(|_x| ())
    }

    pub fn write_mem(&self, addr: u32, data: Vec<u8>) {
        unimplemented!();
    }
}

#[derive(Debug)]
struct NtrStream<'a> {
    tcp_stream: TcpStream,
    current_seq: &'a AtomicUsize,
    is_heartbeat_sendable: &'a AtomicBool,
}
impl<'a> NtrStream<'a> {
    fn new(ntr: &'a Ntr) -> Self {
        NtrStream {
            tcp_stream: ntr.tcp_stream.try_clone().unwrap(),
            current_seq: &ntr.current_seq,
            is_heartbeat_sendable: &ntr.is_heartbeat_sendable,
        }
    }

    fn send_packet(&mut self, packet_type: u32, cmd: u32, args: &[u32], data_len: u32) -> io::Result<usize> {
        let mut buf = [0u8; 84];

        LittleEndian::write_u32(&mut buf[0..4], 0x12345678);
        LittleEndian::write_u32(&mut buf[4..8], self.current_seq.fetch_add(1000, Ordering::SeqCst) as u32);
        LittleEndian::write_u32(&mut buf[8..12], packet_type);
        LittleEndian::write_u32(&mut buf[12..16], cmd);
        for i in 0..16 {
            LittleEndian::write_u32(&mut buf[(4 * i + 16)..(4 * i + 20)], args[i]);
        }
        LittleEndian::write_u32(&mut buf[80..84], data_len);

        self.tcp_stream.write(&buf)
    }

    fn send_read_mem_packet(&mut self, addr: u32, size: u32, pid: u32) -> io::Result<usize> {
        self.send_empty_packet(9, pid, addr, size)
    }

    fn send_write_mem_packet(&mut self, addr: u32, pid: u32, buf: &Vec<u8>) -> io::Result<usize> {
        let args = &mut [0u32; 16];
        args[0] = pid;
        args[1] = addr;
        args[2] = buf.len() as u32;
        self.send_packet(1, 10, args, args[2])
            .and(self.tcp_stream.write(buf))
    }

    fn send_heartbeat_packet(&mut self) -> io::Result<usize> {
        self.send_packet(0, 0, &[0u32; 16], 0)
    }

    fn send_hello_packet(&mut self) -> io::Result<usize> {
        self.send_packet(0, 3, &[0u32; 16], 0)
    }

    fn send_reload_packet(&mut self) -> io::Result<usize> {
        self.send_packet(0, 4, &[0u32; 16], 0)
    }

    fn send_empty_packet(&mut self, cmd: u32, arg0: u32, arg1: u32, arg2: u32) -> io::Result<usize> {
        let mut args = [0u32; 16];
        args[0] = arg0;
        args[1] = arg1;
        args[2] = arg2;
        self.send_packet(0, cmd, &args, 0)
    }

    fn tcp_stream(&mut self) -> &TcpStream {
        &self.tcp_stream
    }

    fn is_heartbeat_sendable(&self) -> &AtomicBool {
        &self.is_heartbeat_sendable
    }
}<|endoftext|>


<commit_before>//! A work-stealing fork-join queue used to perform processors' work asynchronously.
//! This is intended to be short-lived. Long running asynchronous tasks should use another method.
//! For infinite loops, the longest-running of tasks, behavior will be as expected.
#![cfg_attr(nightly, feature(core_intrinsics))]

mod job;
mod queue;
mod pool;

use self::job::Job;
use self::pool::Pool;
use self::queue::Queue;

use std::io::Error;
use std::marker::PhantomData;
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;

const MAX_JOBS: usize = 4096;

// messages to workers.
enum ToWorker {
	Start, // start
	Clear, // run all jobs to completion, then reset the pool.
	Shutdown, // all workers are clear and no jobs are running. safe to tear down pools.
}
// messages to the leader from workers.
enum ToLeader {
	Cleared, // done clearing. will wait for start or shutdown
    Panicked,
}

struct WorkerHandle {
	tx: Sender<ToWorker>,
	rx: Receiver<ToLeader>,
	thread: Option<thread::JoinHandle<()>>,
}

// Finite state machine for controlling workers.
#[derive(Clone, Copy, PartialEq)]
enum State {
    Running, // running jobs normally. waiting for state change.
    Paused, // paused, waiting for start or shutdown message.
}

pub struct Worker {
    queues: Arc<Vec<Queue>>,
    pools: Arc<Vec<Pool>>,
    idx: usize, // the index of this worker's queue and pool in the Vec.
}

// TODO: implement !Sync for Worker.

impl Worker {
    // pop a job from the worker's queue, or steal one from the queue with the most work.
    unsafe fn pop_or_steal(&self) -> Option<*mut Job> {
        if let Some(job) = self.queues[self.idx].pop() {
            return Some(job);
        }

        let (mut most_work, mut most_idx) = (0, None);
        for (i, queue) in self.queues.iter().enumerate() {
            let len = queue.len();
            if len > most_work {
                most_work = len;
                most_idx = Some(i);
            }
        }

        if let Some(idx) = most_idx {
            self.queues[idx].steal()
        } else {
            None
        }
    }

    // do a sweep through all the queues, saying whether all
    // were observed to be empty initially.
    fn clear_pass(&self) -> bool {
        let mut all_clear = true;
        for (idx, queue) in self.queues.iter().enumerate() {
            if idx != self.idx {
                while let Some(job) = queue.steal() {
                    all_clear = false;
                    unsafe { (*job).call(self) }
                }
            } else {
                while let Some(job) = unsafe { queue.pop() } {
                    all_clear = false;
                    unsafe { (*job).call(self) }
                }
            }
        }

        all_clear
    }

    fn clear(&self) {
        while !self.clear_pass() {}
    }

    // run the next job.
    unsafe fn run_next(&self) {
        if let Some(job) = self.pop_or_steal() {
            (*job).call(self)
        }
    }

    // This must be called on the thread the worker is active on.
    unsafe fn submit_internal<F>(&self, counter: *const AtomicUsize, f: F) where F: Send + FnOnce(&Worker) {
        let job = Job::new(counter, f);
        let job_ptr = self.pools[self.idx].alloc(job);
        self.queues[self.idx].push(job_ptr);
    }

    // construct a new spawning scope.
    // this waits for all jobs submitted internally
    // to complete.
    fn scope<'pool, 'new, F>(&'pool self, f: F)
    where F: FnOnce(&Spawner<'pool, 'new>) {
        let counter = AtomicUsize::new(0);
        let s = make_spawner(self, &counter);
        f(&s);

        while counter.load(Ordering::Acquire) != 0 {
            unsafe { self.run_next() }
        }
    }
}

/// A job spawner associated with a specific scope.
/// Jobs spawned using this may spawn new jobs with the same lifetime.
pub struct Spawner<'pool, 'scope> {
    worker: &'pool Worker,
    counter: *const AtomicUsize,
    // invariant lifetime.
    _marker: PhantomData<*mut &'scope mut ()>,
}

unsafe impl<'pool, 'scope> Sync for Spawner<'pool, 'scope> {}

impl<'pool, 'scope> Spawner<'pool, 'scope> {
    /// Execute a function which necessarily outlives the scope which
    /// this resides in.
    pub fn submit<F>(&self, f: F)
    where F: 'scope + Send + FnOnce(&Spawner<'pool, 'scope>) {
        use std::mem;

        // for sending the counter pointer across thread boundaries.
        struct SendCounter(*const AtomicUsize);
        unsafe impl Send for SendCounter {}

        unsafe {
            // increment the counter first just in case, somehow, this job
            // gets grabbed before we have a chance to increment it,
            // and we wait for all jobs to complete.
            let counter: SendCounter = SendCounter(self.counter);
            (*self.counter).fetch_add(1, Ordering::AcqRel);
            self.worker.submit_internal(self.counter, move |worker| {
                let SendCounter(count_ptr) = counter;
                // make a new spawner associated with the same scope,
                // but with the correct worker for the thread -- so if
                // this job spawns any children, we won't break any
                // invariants by accessing other workers' queues/pools
                // in unexpected ways.
                let spawner = make_spawner(worker, count_ptr);
                f(&mem::transmute(spawner) )
            });
        }
    }

    /// Construct a new spawning scope smaller than the one this spawner resides in.
    pub fn scope<'new, F>(&self, f: F)
    where 'scope: 'new, F: FnOnce(&Spawner<'pool, 'new>) {
        self.worker.scope(f);
    }
}
fn make_spawner<'a, 'b>(worker: &'a Worker, counter: *const AtomicUsize) -> Spawner<'a, 'b> {
    Spawner {
        worker: worker,
        counter: counter,
        _marker: PhantomData,
    }
}

fn worker_main(tx: Sender<ToLeader>, rx: Receiver<ToWorker>, worker: Worker) {
    struct PanicGuard(Sender<ToLeader>);
    impl Drop for PanicGuard {
        fn drop(&mut self) {
            if thread::panicking() {
                let _ = self.0.send(ToLeader::Panicked);
            }
        }
    }
    // if the worker for this thread panics,
    let _guard = PanicGuard(tx.clone());

    let mut state = State::Paused;
    loop {
        match state {
            State::Running => {
                match rx.recv().expect("Pool hung up on worker") {
                    ToWorker::Clear => {
                        worker.clear();
                        tx.send(ToLeader::Cleared).expect("Pool hung up on worker");
                        state = State::Paused;
                    }

                    _ => unreachable!()
                }

                unsafe { worker.run_next() }
            }

            State::Paused => {
                if let Ok(msg) = rx.recv() {
                    match msg {
                        ToWorker::Start => {
                            state = State::Running;
                            continue;
                        }

                        ToWorker::Shutdown => {
                            break;
                        }

                        _ => unreachable!()
                    }
                } else {
                    panic!("Pool hung up on worker");
                }
            }
        }
    }
}

/// The work pool manages worker threads in a
/// work-stealing fork-join thread pool.
// The fields here are put in Vecs for cache contiguity.
pub struct WorkPool {
	workers: Vec<WorkerHandle>,
    local_worker: Worker,
    state: State,
}

impl WorkPool {
	/// Creates a work pool with `n` worker threads.
	pub fn new(n: usize) -> Result<Self, Error> {
        // one extra queue and pool for the job system.
        let queues = Arc::new((0..n+1).map(|_| Queue::new()).collect::<Vec<_>>());
        let pools = Arc::new((0..n+1).map(|_| Pool::new()).collect::<Vec<_>>());
        let mut workers = Vec::with_capacity(n);

        for i in 0..n {
            let (work_send, work_recv) = channel();
            let (lead_send, lead_recv) = channel();

            let worker = Worker {
                queues: queues.clone(),
                pools: pools.clone(),
                idx: i + 1,
            };

            let builder = thread::Builder::new().name(format!("worker_{}", i));
            let handle = try!(builder.spawn(|| worker_main(lead_send, work_recv, worker)));

            workers.push(WorkerHandle {
                tx: work_send,
                rx: lead_recv,
                thread: Some(handle),
            });
        }

        Ok(WorkPool {
            workers: workers,
            local_worker: Worker {
                queues: queues,
                pools: pools,
                idx: 0,
            },
            state: State::Paused,
        })
	}

    /// Finish all current jobs which are queued, and synchronize the workers until
    /// it's time to start again.
    ///
    /// If any of the threads have panicked, that panic
    /// will be propagated to this thread. Until the next job is submitted,
    /// workers will block, allowing other threads to have higher priority.
    pub fn synchronize(&mut self) {
        self.clear_all();
    }

    /// Create a new spawning scope for submitting jobs.
    /// Any jobs submitted in this scope will be completed
    /// by the end of this function call.
    pub fn scope<'pool, 'new, F>(&'pool mut self, f: F)
    where F: FnOnce(&Spawner<'pool, 'new>) {
        self.spin_up();
        self.local_worker.scope(f);
    }

    /// Execute a job which strictly owns its contents.
    /// The execution of this function may be deferred to beyond
    /// this function call.
    /// In the general case, it is safe to submit jobs which only
    /// strictly outlive the pool. However, there is always the
    /// chance that the pool could be leaked, violating the invariant
    /// that the job is completed before the borrow of the data is.
    pub fn submit<'a, F>(&'a mut self, f: F)
    where F: 'static + Send + FnOnce(&Spawner<'a, 'static>) {
        use std::mem;
        use std::ptr;

        self.spin_up();
        // make a job without a counter.
        unsafe {
                self.local_worker.submit_internal(ptr::null_mut(), move |worker| {
                let spawner = make_spawner(&worker, ptr::null_mut());
                f(&mem::transmute(spawner))
            })
        }
    }

    // spin up all the workers, in case they were in a paused
    // state.
    fn spin_up(&mut self) {
        if self.state != State::Running {
            for worker in &self.workers {
                worker.tx.send(ToWorker::Start).expect("Worker hung up on pool");
            }

            self.state = State::Running;
        }
    }

    // clear all the workers and sets the state to paused.
    fn clear_all(&mut self) {
        if self.state == State::Paused { return; }
        // send every worker a clear message
        for worker in &self.workers {
            worker.tx.send(ToWorker::Clear).ok().expect("Worker hung up on pool.");
        }

        // do a clear run on the local worker as well.
        self.local_worker.clear();

        let mut panicked = false;
        // wait for confirmation from each worker.
        // the queues are not guaranteed to be empty until the last one responds!
        for worker in &self.workers {
            match worker.rx.recv() {
                Ok(msg) => {
                    match msg {
                        ToLeader::Cleared => continue,
                        ToLeader::Panicked => {
                            panicked = true;
                        }
                    }
                }

                Err(_) => panic!("Worker hung up on job system.")
            }
        }

        // reset the counters in every queue so there's no chance of
        // overlap.
        for queue in self.local_worker.queues.iter() {
            // asserts that len == 0 in debug mode.
            queue.reset_counters();
        }

        // reset all the pools.
        for pool in self.local_worker.pools.iter() {
            pool.reset();
        }

        // cleared and panicked workers are waiting for a shutdown message.
        if panicked {
            panic!("Propagating worker thread panic")
        }

        self.state = State::Paused;
    }
}

impl Drop for WorkPool {
    fn drop(&mut self) {
        // finish all work.
        self.clear_all();

        // now tell every worker they can shut down safely.
        for worker in &self.workers {
            worker.tx.send(ToWorker::Shutdown).ok().expect("Worker hung up on job system");
        }

        // join the threads (although they should already be at this point).
        for worker in &mut self.workers {
            worker.thread.take().map(|handle| handle.join());
        }
    }
}

/// Create a pool with `n` worker threads.
pub fn make_pool(n: usize) -> Result<WorkPool, Error> {
    WorkPool::new(n)
}

#[cfg(test)]
mod tests {
	use super::WorkPool;

    #[test]
    fn creation_destruction() {
        for i in 0..32 {
            let _ = WorkPool::new(i).unwrap();
        }
    }

    #[test]
    fn split_work() {
        let mut pool = WorkPool::new(4).unwrap();
        let mut v = vec![0; 1024];
        pool.scope(|spawner| {
            for (idx, v) in v.iter_mut().enumerate() {
                spawner.submit(move |_| {
                    *v += idx;
                });
            }
        });

        assert_eq!(v, (0..1024).collect::<Vec<_>>());
    }

    #[test]
    fn multilevel_scoping() {
        let mut pool = WorkPool::new(4).unwrap();
        pool.scope(|spawner| {
            let mut v = vec![0; 256];
            spawner.scope(|s| {
               for i in &mut v {
                   s.submit(move |_| *i += 1)
               }
            });
            // job is forcibly joined here.

            assert_eq!(v, (0..256).map(|_| 1).collect::<Vec<_>>())
        }); // any other jobs would be forcibly joined here.
    }

    #[test]
    fn multiple_synchronizations() {
        let mut pool = WorkPool::new(4).unwrap();
        for _ in 0..100 {
            pool.synchronize();
        }
    }

    #[test]
    fn outlives_pool() {
        let mut v = vec![0; 256];
        let mut pool = WorkPool::new(4).unwrap();

        // can only execute 'static functions here -- otherwise,
        // some person might make the dumb mistake of calling `forget` the
        // pool before it has the chance to run all submitted jobs.
        pool.submit(move |_| for i in &mut v { *i += 1} );
    }

    #[test]
    #[should_panic]
    fn job_panic() {
        let mut pool = WorkPool::new(4).unwrap();

        pool.submit(|_| panic!("Eep!"));
    }
}<commit_msg>Reset worker pool when queue empty.<commit_after>//! A work-stealing fork-join queue used to perform processors' work asynchronously.
//! This is intended to be short-lived. Long running asynchronous tasks should use another method.
//! For infinite loops, the longest-running of tasks, behavior will be as expected.
#![cfg_attr(nightly, feature(core_intrinsics))]

mod job;
mod queue;
mod pool;

use self::job::Job;
use self::pool::Pool;
use self::queue::Queue;

use std::io::Error;
use std::marker::PhantomData;
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;

const MAX_JOBS: usize = 4096;

// messages to workers.
enum ToWorker {
	Start, // start
	Clear, // run all jobs to completion, then reset the pool.
	Shutdown, // all workers are clear and no jobs are running. safe to tear down pools.
}
// messages to the leader from workers.
enum ToLeader {
	Cleared, // done clearing. will wait for start or shutdown
    Panicked,
}

struct WorkerHandle {
	tx: Sender<ToWorker>,
	rx: Receiver<ToLeader>,
	thread: Option<thread::JoinHandle<()>>,
}

// Finite state machine for controlling workers.
#[derive(Clone, Copy, PartialEq)]
enum State {
    Running, // running jobs normally. waiting for state change.
    Paused, // paused, waiting for start or shutdown message.
}

pub struct Worker {
    queues: Arc<Vec<Queue>>,
    pools: Arc<Vec<Pool>>,
    idx: usize, // the index of this worker's queue and pool in the Vec.
}

// TODO: implement !Sync for Worker.

impl Worker {
    // pop a job from the worker's queue, or steal one from the queue with the most work.
    unsafe fn pop_or_steal(&self) -> Option<*mut Job> {
        if let Some(job) = self.queues[self.idx].pop() {
            return Some(job);
        }

        // if the queue is empty (pop failed), we can clear the pool for this queue.
        // this works only because
        // A) we push pool-allocated jobs only onto the local queue,
        // B) pop gets priority when racing against "steal".
        self.pools[self.idx].reset();

        let (mut most_work, mut most_idx) = (0, None);
        for (i, queue) in self.queues.iter().enumerate() {
            let len = queue.len();
            if len > most_work {
                most_work = len;
                most_idx = Some(i);
            }
        }

        if let Some(idx) = most_idx {
            self.queues[idx].steal()
        } else {
            None
        }
    }

    // do a sweep through all the queues, saying whether all
    // were observed to be empty initially.
    fn clear_pass(&self) -> bool {
        let mut all_clear = true;
        for (idx, queue) in self.queues.iter().enumerate() {
            if idx != self.idx {
                while let Some(job) = queue.steal() {
                    all_clear = false;
                    unsafe { (*job).call(self) }
                }
            } else {
                while let Some(job) = unsafe { queue.pop() } {
                    all_clear = false;
                    unsafe { (*job).call(self) }
                }
            }
        }

        all_clear
    }

    fn clear(&self) {
        while !self.clear_pass() {}
    }

    // run the next job.
    unsafe fn run_next(&self) {
        if let Some(job) = self.pop_or_steal() {
            (*job).call(self)
        }
    }

    // This must be called on the thread the worker is active on.
    unsafe fn submit_internal<F>(&self, counter: *const AtomicUsize, f: F) where F: Send + FnOnce(&Worker) {
        let job = Job::new(counter, f);
        let job_ptr = self.pools[self.idx].alloc(job);
        self.queues[self.idx].push(job_ptr);
    }

    // construct a new spawning scope.
    // this waits for all jobs submitted internally
    // to complete.
    fn scope<'pool, 'new, F>(&'pool self, f: F)
    where F: FnOnce(&Spawner<'pool, 'new>) {
        let counter = AtomicUsize::new(0);
        let s = make_spawner(self, &counter);
        f(&s);

        while counter.load(Ordering::Acquire) != 0 {
            unsafe { self.run_next() }
        }
    }
}

/// A job spawner associated with a specific scope.
/// Jobs spawned using this may spawn new jobs with the same lifetime.
pub struct Spawner<'pool, 'scope> {
    worker: &'pool Worker,
    counter: *const AtomicUsize,
    // invariant lifetime.
    _marker: PhantomData<*mut &'scope mut ()>,
}

unsafe impl<'pool, 'scope> Sync for Spawner<'pool, 'scope> {}

impl<'pool, 'scope> Spawner<'pool, 'scope> {
    /// Execute a function which necessarily outlives the scope which
    /// this resides in.
    pub fn submit<F>(&self, f: F)
    where F: 'scope + Send + FnOnce(&Spawner<'pool, 'scope>) {
        use std::mem;

        // for sending the counter pointer across thread boundaries.
        struct SendCounter(*const AtomicUsize);
        unsafe impl Send for SendCounter {}

        unsafe {
            // increment the counter first just in case, somehow, this job
            // gets grabbed before we have a chance to increment it,
            // and we wait for all jobs to complete.
            let counter: SendCounter = SendCounter(self.counter);
            (*self.counter).fetch_add(1, Ordering::AcqRel);
            self.worker.submit_internal(self.counter, move |worker| {
                let SendCounter(count_ptr) = counter;
                // make a new spawner associated with the same scope,
                // but with the correct worker for the thread -- so if
                // this job spawns any children, we won't break any
                // invariants by accessing other workers' queues/pools
                // in unexpected ways.
                let spawner = make_spawner(worker, count_ptr);
                f(&mem::transmute(spawner) )
            });
        }
    }

    /// Construct a new spawning scope smaller than the one this spawner resides in.
    pub fn scope<'new, F>(&self, f: F)
    where 'scope: 'new, F: FnOnce(&Spawner<'pool, 'new>) {
        self.worker.scope(f);
    }
}
fn make_spawner<'a, 'b>(worker: &'a Worker, counter: *const AtomicUsize) -> Spawner<'a, 'b> {
    Spawner {
        worker: worker,
        counter: counter,
        _marker: PhantomData,
    }
}

fn worker_main(tx: Sender<ToLeader>, rx: Receiver<ToWorker>, worker: Worker) {
    struct PanicGuard(Sender<ToLeader>);
    impl Drop for PanicGuard {
        fn drop(&mut self) {
            if thread::panicking() {
                let _ = self.0.send(ToLeader::Panicked);
            }
        }
    }
    // if the worker for this thread panics,
    let _guard = PanicGuard(tx.clone());

    let mut state = State::Paused;
    loop {
        match state {
            State::Running => {
                match rx.recv().expect("Pool hung up on worker") {
                    ToWorker::Clear => {
                        worker.clear();
                        tx.send(ToLeader::Cleared).expect("Pool hung up on worker");
                        state = State::Paused;
                    }

                    _ => unreachable!()
                }

                unsafe { worker.run_next() }
            }

            State::Paused => {
                if let Ok(msg) = rx.recv() {
                    match msg {
                        ToWorker::Start => {
                            state = State::Running;
                            continue;
                        }

                        ToWorker::Shutdown => {
                            break;
                        }

                        _ => unreachable!()
                    }
                } else {
                    panic!("Pool hung up on worker");
                }
            }
        }
    }
}

/// The work pool manages worker threads in a
/// work-stealing fork-join thread pool.
// The fields here are put in Vecs for cache contiguity.
pub struct WorkPool {
	workers: Vec<WorkerHandle>,
    local_worker: Worker,
    state: State,
}

impl WorkPool {
	/// Creates a work pool with `n` worker threads.
	pub fn new(n: usize) -> Result<Self, Error> {
        // one extra queue and pool for the job system.
        let queues = Arc::new((0..n+1).map(|_| Queue::new()).collect::<Vec<_>>());
        let pools = Arc::new((0..n+1).map(|_| Pool::new()).collect::<Vec<_>>());
        let mut workers = Vec::with_capacity(n);

        for i in 0..n {
            let (work_send, work_recv) = channel();
            let (lead_send, lead_recv) = channel();

            let worker = Worker {
                queues: queues.clone(),
                pools: pools.clone(),
                idx: i + 1,
            };

            let builder = thread::Builder::new().name(format!("worker_{}", i));
            let handle = try!(builder.spawn(|| worker_main(lead_send, work_recv, worker)));

            workers.push(WorkerHandle {
                tx: work_send,
                rx: lead_recv,
                thread: Some(handle),
            });
        }

        Ok(WorkPool {
            workers: workers,
            local_worker: Worker {
                queues: queues,
                pools: pools,
                idx: 0,
            },
            state: State::Paused,
        })
	}

    /// Finish all current jobs which are queued, and synchronize the workers until
    /// it's time to start again.
    ///
    /// If any of the threads have panicked, that panic
    /// will be propagated to this thread. Until the next job is submitted,
    /// workers will block, allowing other threads to have higher priority.
    pub fn synchronize(&mut self) {
        self.clear_all();
    }

    /// Create a new spawning scope for submitting jobs.
    /// Any jobs submitted in this scope will be completed
    /// by the end of this function call.
    pub fn scope<'pool, 'new, F>(&'pool mut self, f: F)
    where F: FnOnce(&Spawner<'pool, 'new>) {
        self.spin_up();
        self.local_worker.scope(f);
    }

    /// Execute a job which strictly owns its contents.
    /// The execution of this function may be deferred to beyond
    /// this function call.
    /// In the general case, it is safe to submit jobs which only
    /// strictly outlive the pool. However, there is always the
    /// chance that the pool could be leaked, violating the invariant
    /// that the job is completed before the borrow of the data is.
    pub fn submit<'a, F>(&'a mut self, f: F)
    where F: 'static + Send + FnOnce(&Spawner<'a, 'static>) {
        use std::mem;
        use std::ptr;

        self.spin_up();
        // make a job without a counter.
        unsafe {
                self.local_worker.submit_internal(ptr::null_mut(), move |worker| {
                let spawner = make_spawner(&worker, ptr::null_mut());
                f(&mem::transmute(spawner))
            })
        }
    }

    // spin up all the workers, in case they were in a paused
    // state.
    fn spin_up(&mut self) {
        if self.state != State::Running {
            for worker in &self.workers {
                worker.tx.send(ToWorker::Start).expect("Worker hung up on pool");
            }

            self.state = State::Running;
        }
    }

    // clear all the workers and sets the state to paused.
    fn clear_all(&mut self) {
        if self.state == State::Paused { return; }
        // send every worker a clear message
        for worker in &self.workers {
            worker.tx.send(ToWorker::Clear).ok().expect("Worker hung up on pool.");
        }

        // do a clear run on the local worker as well.
        self.local_worker.clear();

        let mut panicked = false;
        // wait for confirmation from each worker.
        // the queues are not guaranteed to be empty until the last one responds!
        for worker in &self.workers {
            match worker.rx.recv() {
                Ok(msg) => {
                    match msg {
                        ToLeader::Cleared => continue,
                        ToLeader::Panicked => {
                            panicked = true;
                        }
                    }
                }

                Err(_) => panic!("Worker hung up on job system.")
            }
        }

        // reset the counters in every queue so there's no chance of
        // overlap.
        for queue in self.local_worker.queues.iter() {
            // asserts that len == 0 in debug mode.
            queue.reset_counters();
        }

        // reset all the pools.
        for pool in self.local_worker.pools.iter() {
            pool.reset();
        }

        // cleared and panicked workers are waiting for a shutdown message.
        if panicked {
            panic!("Propagating worker thread panic")
        }

        self.state = State::Paused;
    }
}

impl Drop for WorkPool {
    fn drop(&mut self) {
        // finish all work.
        self.clear_all();

        // now tell every worker they can shut down safely.
        for worker in &self.workers {
            worker.tx.send(ToWorker::Shutdown).ok().expect("Worker hung up on job system");
        }

        // join the threads (although they should already be at this point).
        for worker in &mut self.workers {
            worker.thread.take().map(|handle| handle.join());
        }
    }
}

/// Create a pool with `n` worker threads.
pub fn make_pool(n: usize) -> Result<WorkPool, Error> {
    WorkPool::new(n)
}

#[cfg(test)]
mod tests {
	use super::WorkPool;

    #[test]
    fn creation_destruction() {
        for i in 0..32 {
            let _ = WorkPool::new(i).unwrap();
        }
    }

    #[test]
    fn split_work() {
        let mut pool = WorkPool::new(4).unwrap();
        let mut v = vec![0; 1024];
        pool.scope(|spawner| {
            for (idx, v) in v.iter_mut().enumerate() {
                spawner.submit(move |_| {
                    *v += idx;
                });
            }
        });

        assert_eq!(v, (0..1024).collect::<Vec<_>>());
    }

    #[test]
    fn multilevel_scoping() {
        let mut pool = WorkPool::new(4).unwrap();
        pool.scope(|spawner| {
            let mut v = vec![0; 256];
            spawner.scope(|s| {
               for i in &mut v {
                   s.submit(move |_| *i += 1)
               }
            });
            // job is forcibly joined here.

            assert_eq!(v, (0..256).map(|_| 1).collect::<Vec<_>>())
        }); // any other jobs would be forcibly joined here.
    }

    #[test]
    fn multiple_synchronizations() {
        let mut pool = WorkPool::new(4).unwrap();
        for _ in 0..100 {
            pool.synchronize();
        }
    }

    #[test]
    fn outlives_pool() {
        let mut v = vec![0; 256];
        let mut pool = WorkPool::new(4).unwrap();

        // can only execute 'static functions here -- otherwise,
        // some person might make the dumb mistake of calling `forget` the
        // pool before it has the chance to run all submitted jobs.
        pool.submit(move |_| for i in &mut v { *i += 1} );
    }

    #[test]
    #[should_panic]
    fn job_panic() {
        let mut pool = WorkPool::new(4).unwrap();

        pool.submit(|_| panic!("Eep!"));
    }
}<|endoftext|>


<commit_before>// (c) 2015 Joost Yervante Damad <joost@damad.be>

use std::fmt;
use std::fs::File;
use std::io::Read;

extern crate rustysexp;
use rustysexp::Sexp;
use rustysexp::Atom;

type ERes<T> = Result<T, &'static str>;

fn err<T>(msg: &'static str) -> ERes<T> { Err(msg) }

pub enum Element {
    Layer,
    Descr,
    FpText,
    Pad,
    FpPoly,
    FpLine,
    FpCircle
}

pub struct Module {
    name: String,
    elements: Vec<Element>
}

impl Module {
    fn new(name: &String) -> Module {
        Module { name: name.clone(), elements: vec![] }
    }
}

impl fmt::Display for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "Module({})", self.name)
    }
}

fn parse_module_list(v: Vec<Sexp>) -> ERes<Module> {
    match v[0] {
        Sexp::Atom(Atom::S(ref s)) if s == "module" => {
            match v[1] {
                Sexp::Atom(Atom::S(ref s)) => {
                    Ok(Module::new(s))
                }
                _ => err("expecting module name")
            }
        }
        _ => err("expecting module")
    }
}

fn parse_module(s: Sexp) -> ERes<Module> {
    match s {
        Sexp::List(v) => parse_module_list(v),
        _ => err("expecting top level list")
    }
}

fn parse(s: &str) -> ERes<Module> {
    match rustysexp::parse_str(s) {
        Ok(s) => parse_module(s),
        Err(x) => err("IOError") // TODO...
    }
}

fn read_file(name: &str) -> Result<String,std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_str(s: &str) -> Module {
    parse(s).unwrap()
}

pub fn parse_file(name: &str) -> Module {
    let s = read_file(name).unwrap();
    parse(&s[..]).unwrap()
}

<commit_msg>parsing work<commit_after>// (c) 2015 Joost Yervante Damad <joost@damad.be>

use std::fmt;
use std::fs::File;
use std::io::Read;

extern crate rustysexp;
use rustysexp::Sexp;
use rustysexp::Atom;

type ERes<T> = Result<T, &'static str>;

fn err<T>(msg: &'static str) -> ERes<T> { Err(msg) }

pub enum Element {
    Layer,
    Descr,
    FpText,
    Pad,
    FpPoly,
    FpLine,
    FpCircle
}

pub struct Module {
    name: String,
    elements: Vec<Element>
}

impl Module {
    fn new(name: &String) -> Module {
        Module { name: name.clone(), elements: vec![] }
    }
    fn append(&mut self, e: Element) {
        self.elements.push(e)
    }
}

impl fmt::Display for Module {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(f, "(module {}\n", self.name));
        for e in &self.elements {
            try!(write!(f, "{}\n", e))
        };
        write!(f, ")")
    }
}

impl fmt::Display for Element {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Element::Layer => write!(f, "(layer)"),
            Element::Descr => write!(f, "(desc)"),
            Element::FpText => write!(f, "(fp_text)"),
            Element::Pad => write!(f, "(pad)"),
            Element::FpPoly => write!(f, "(fp_poly)"),
            Element::FpLine => write!(f, "(fp_line)"),
            Element::FpCircle => write!(f, "(fp_circle)"),
        }
    }
}

fn parse_element(s: &Sexp) -> ERes<Element> {
    Ok(Element::Layer)
}

fn parse_module_list(v: Vec<Sexp>) -> ERes<Module> {
    let mut module = (match v[0] {
        Sexp::Atom(Atom::S(ref s)) if s == "module" => {
            match v[1] {
                Sexp::Atom(Atom::S(ref s)) => {
                    Ok(Module::new(s))
                }
                _ => return err("expecting module name")
            }
        }
        _ => err("expecting module")
    }).unwrap();
    for e in &v[2..] {
        let el = try!(parse_element(e));
        module.append(el)
    }
    Ok(module)
}

fn parse_module(s: Sexp) -> ERes<Module> {
    match s {
        Sexp::List(v) => parse_module_list(v),
        _ => err("expecting top level list")
    }
}

fn parse(s: &str) -> ERes<Module> {
    match rustysexp::parse_str(s) {
        Ok(s) => parse_module(s),
        Err(x) => err("IOError") // TODO...
    }
}

fn read_file(name: &str) -> Result<String,std::io::Error> {
    let mut f = try!(File::open(name));
    let mut s = String::new();
    try!(f.read_to_string(&mut s));
    Ok(s)
}

pub fn parse_str(s: &str) -> Module {
    parse(s).unwrap()
}

pub fn parse_file(name: &str) -> Module {
    let s = read_file(name).unwrap();
    parse(&s[..]).unwrap()
}

<|endoftext|>