<commit_before>use std::io::{Result, Error, ErrorKind};
use std::rc::Rc;

use mio;
use mio::{Token, Handler, EventSet, PollOpt};
use mio::tcp::{TcpStream, TcpListener};

use slab::Slab;

use frontend::Frontend;
use connection::{TokenType, ListenerToken, IncomingToken, OutgoingToken, Connection};

type EventLoop = mio::EventLoop<Driver>;

pub struct Driver {
    incoming_connections: Slab<Connection, IncomingToken>,
    outgoing_connections: Slab<Option<IncomingToken>, OutgoingToken>,
    listeners: Slab<Listener, ListenerToken>,
}

pub enum DriverMessage {
    Shutdown,
}

struct Listener {
    listener: TcpListener,
    frontend: Rc<Frontend>,
}

impl Driver {
    pub fn new() -> Driver {
        Driver {
            incoming_connections: Slab::new_starting_at(IncomingToken(1), 4096),
            outgoing_connections: Slab::new_starting_at(OutgoingToken(1), 4096),
            listeners: Slab::new_starting_at(ListenerToken(1), 128),
        }
    }

    pub fn register(&mut self, event_loop: &mut EventLoop, frontend: Rc<Frontend>) -> Result<()> {
        for listen_addr in frontend.listen_addrs() {
            let listener = try!(TcpListener::bind(&listen_addr));
            let token = try!(self.listeners
                                 .insert(Listener {
                                     listener: listener,
                                     frontend: frontend.clone(),
                                 })
                                 .map_err(|_| {
                                     Error::new(ErrorKind::Other, "Listener buffer full")
                                 }));

            try!(event_loop.register_opt(&self.listeners.get(token).unwrap().listener,
                                         token.as_raw_token(),
                                         EventSet::readable(),
                                         PollOpt::edge()));

            debug!("Added listener or {:?}", listen_addr);
        }

        Ok(())
    }

    fn listener_ready(&mut self,
                      event_loop: &mut EventLoop,
                      token: ListenerToken,
                      events: EventSet) {
        assert!(events.is_readable());

        if let Some(listener) = self.listeners.get(token) {
            info!("Accepting connection");

            let incoming = match listener.listener.accept() {
                Ok(Some(client)) => client,
                Ok(None) => {
                    warn!("Accept would block");
                    return;
                }
                Err(e) => {
                    error!("Accept error: {}", e);
                    return;
                }
            };

            let backend = listener.frontend.decide_backend();
            let target = backend.borrow_mut().decide_target();

            let outgoing = match TcpStream::connect(&target) {
                Ok(client) => client,
                Err(e) => {
                    error!("Connect error: {}", e);
                    return;
                }
            };

            let outgoing_token = self.outgoing_connections
                                     .insert(None)
                                     .expect("Outgoing buffer full");

            let incoming_token = self.incoming_connections
                                     .insert_with(|incoming_token| {
                                         Connection::new(incoming,
                                                         incoming_token,
                                                         outgoing,
                                                         outgoing_token)
                                     })
                                     .expect("Incoming buffer full");

            self.outgoing_connections[outgoing_token] = Some(incoming_token);

            let connection = self.incoming_connections.get(incoming_token).unwrap();

            event_loop.register_opt(connection.incoming_stream(),
                                    incoming_token.as_raw_token(),
                                    EventSet::all(),
                                    PollOpt::edge())
                      .unwrap();
            event_loop.register_opt(connection.outgoing_stream(),
                                    outgoing_token.as_raw_token(),
                                    EventSet::all(),
                                    PollOpt::edge())
                      .unwrap();
        } else {
            error!("Listener event on unknown token");
        }
    }

    fn incoming_ready(&mut self,
                      event_loop: &mut EventLoop,
                      token: IncomingToken,
                      events: EventSet) {
        let mut remove = false;

        if let Some(mut connection) = self.incoming_connections.get_mut(token) {
            connection.incoming_ready(events);
            connection.tick();

            if connection.is_incoming_closed() {
                remove = true;
            }
        }

        if remove {
            self.remove_connection(event_loop, token);
        }
    }

    fn outgoing_ready(&mut self,
                      event_loop: &mut EventLoop,
                      token: OutgoingToken,
                      events: EventSet) {
        if let Some(&Some(incoming_token)) = self.outgoing_connections.get(token) {
            let mut remove = false;

            if let Some(mut connection) = self.incoming_connections.get_mut(incoming_token) {
                connection.outgoing_ready(events);
                connection.tick();

                if connection.is_outgoing_closed() {
                    remove = true;
                }
            }

            if remove {
                self.remove_connection(event_loop, incoming_token);
            }
        }
    }

    fn remove_connection(&mut self, event_loop: &mut EventLoop, token: IncomingToken) {
        let connection = self.incoming_connections
                             .remove(token)
                             .expect("Can't remove already removed incoming connection");
        self.outgoing_connections
            .remove(connection.outgoing_token())
            .expect("Can't remove already removed outgoing connection");

        event_loop.deregister(connection.incoming_stream())
                  .expect("Can't deregister already deregistered incoming stream");
        event_loop.deregister(connection.outgoing_stream())
                  .expect("Can't deregister already deregistered outgoing stream");
    }
}

impl Handler for Driver {
    type Timeout = ();
    type Message = DriverMessage;

    fn ready(&mut self, event_loop: &mut EventLoop, token: Token, events: EventSet) {
        if token == Token(0) {
            trace!("Event on token zero");
            return;
        }

        trace!("Event on token {:?}", token);

        match TokenType::from_raw_token(token) {
            TokenType::Listener(token) => self.listener_ready(event_loop, token, events),
            TokenType::Incoming(token) => self.incoming_ready(event_loop, token, events),
            TokenType::Outgoing(token) => self.outgoing_ready(event_loop, token, events),
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop, msg: DriverMessage) {
        match msg {
            DriverMessage::Shutdown => event_loop.shutdown(),
        }
    }
}

#[cfg(test)]
mod test {
    use super::{EventLoop, Driver, DriverMessage};

    use std::thread;
    use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
    use std::net::{TcpStream, TcpListener, SocketAddr};
    use std::str::FromStr;
    use std::io::{Write, BufReader, BufRead};
    use std::time::Duration;

    use env_logger;

    use ::frontend::Frontend;
    use ::backend::Backend;

    static PORT_NUMBER: AtomicUsize = ATOMIC_USIZE_INIT;

    fn next_port() -> u16 {
        let first_port = option_env!("TEST_BASE_PORT")
            .map_or(32328, |v| v.parse::<usize>().unwrap());
        PORT_NUMBER.compare_and_swap(0, first_port, Ordering::SeqCst);

        PORT_NUMBER.fetch_add(1, Ordering::SeqCst) as u16
    }

    fn listen_addr() -> SocketAddr {
        let addr = format!("127.0.0.1:{}", next_port());
        FromStr::from_str(&addr).unwrap()
    }

    #[test]
    fn start_stop_driver() {
        let mut event_loop = EventLoop::new().unwrap();
        let sender = event_loop.channel();

        let t = thread::spawn(move || {
            let mut driver = Driver::new();
            event_loop.run(&mut driver).unwrap();
        });

        sender.send(DriverMessage::Shutdown).unwrap();
        t.join().unwrap();
    }

    #[test]
    fn single_backend() {
        env_logger::init().unwrap();

        let mut event_loop = EventLoop::new().unwrap();
        let sender = event_loop.channel();
        let frontend_addr = listen_addr();
        let backend_addr = listen_addr();

        let t1 = thread::spawn(move || {
            let mut driver = Driver::new();
            let backend = Backend::new(vec![backend_addr]);
            let frontend = Frontend::new(frontend_addr, vec![backend]);

            driver.register(&mut event_loop, frontend).unwrap();
            debug!("Starting event loop");

            event_loop.run(&mut driver).unwrap();
        });

        let t2 = thread::spawn(move || {
            debug!("Starting backend listener");

            let listener = TcpListener::bind(backend_addr).unwrap();
            let (mut client, _) = listener.accept().unwrap();

            write!(client, "sent by backend\n").unwrap();
            client.flush().unwrap();

            debug!("Backend wrote data, waiting for data now");

            let mut reader = BufReader::new(client);
            let mut buffer = String::new();
            reader.read_line(&mut buffer).unwrap();

            debug!("Backend done");

            assert_eq!(buffer, "sent by frontend\n");
        });

        thread::sleep(Duration::from_millis(100));

        {
            debug!("Connecting to frontend...");
            let client = TcpStream::connect(frontend_addr).unwrap();
            debug!("Frontend connected, waiting for data...");

            let mut reader = BufReader::new(client);
            let mut buffer = String::new();
            reader.read_line(&mut buffer).unwrap();

            debug!("Frontend read data, sending response");

            assert_eq!(buffer, "sent by backend\n");

            write!(reader.get_mut(), "sent by frontend\n").unwrap();
            reader.get_mut().flush().unwrap();

            debug!("Frontend done");
        }

        sender.send(DriverMessage::Shutdown).unwrap();

        t1.join().unwrap();
        t2.join().unwrap();
    }
}
<commit_msg>rustfmt<commit_after>use std::io::{Result, Error, ErrorKind};
use std::rc::Rc;

use mio;
use mio::{Token, Handler, EventSet, PollOpt};
use mio::tcp::{TcpStream, TcpListener};

use slab::Slab;

use frontend::Frontend;
use connection::{TokenType, ListenerToken, IncomingToken, OutgoingToken, Connection};

type EventLoop = mio::EventLoop<Driver>;

pub struct Driver {
    incoming_connections: Slab<Connection, IncomingToken>,
    outgoing_connections: Slab<Option<IncomingToken>, OutgoingToken>,
    listeners: Slab<Listener, ListenerToken>,
}

pub enum DriverMessage {
    Shutdown,
}

struct Listener {
    listener: TcpListener,
    frontend: Rc<Frontend>,
}

impl Driver {
    pub fn new() -> Driver {
        Driver {
            incoming_connections: Slab::new_starting_at(IncomingToken(1), 4096),
            outgoing_connections: Slab::new_starting_at(OutgoingToken(1), 4096),
            listeners: Slab::new_starting_at(ListenerToken(1), 128),
        }
    }

    pub fn register(&mut self, event_loop: &mut EventLoop, frontend: Rc<Frontend>) -> Result<()> {
        for listen_addr in frontend.listen_addrs() {
            let listener = try!(TcpListener::bind(&listen_addr));
            let token = try!(self.listeners
                                 .insert(Listener {
                                     listener: listener,
                                     frontend: frontend.clone(),
                                 })
                                 .map_err(|_| {
                                     Error::new(ErrorKind::Other, "Listener buffer full")
                                 }));

            try!(event_loop.register_opt(&self.listeners.get(token).unwrap().listener,
                                         token.as_raw_token(),
                                         EventSet::readable(),
                                         PollOpt::edge()));

            debug!("Added listener or {:?}", listen_addr);
        }

        Ok(())
    }

    fn listener_ready(&mut self,
                      event_loop: &mut EventLoop,
                      token: ListenerToken,
                      events: EventSet) {
        assert!(events.is_readable());

        if let Some(listener) = self.listeners.get(token) {
            info!("Accepting connection");

            let incoming = match listener.listener.accept() {
                Ok(Some(client)) => client,
                Ok(None) => {
                    warn!("Accept would block");
                    return;
                }
                Err(e) => {
                    error!("Accept error: {}", e);
                    return;
                }
            };

            let backend = listener.frontend.decide_backend();
            let target = backend.borrow_mut().decide_target();

            let outgoing = match TcpStream::connect(&target) {
                Ok(client) => client,
                Err(e) => {
                    error!("Connect error: {}", e);
                    return;
                }
            };

            let outgoing_token = self.outgoing_connections
                                     .insert(None)
                                     .expect("Outgoing buffer full");

            let incoming_token = self.incoming_connections
                                     .insert_with(|incoming_token| {
                                         Connection::new(incoming,
                                                         incoming_token,
                                                         outgoing,
                                                         outgoing_token)
                                     })
                                     .expect("Incoming buffer full");

            self.outgoing_connections[outgoing_token] = Some(incoming_token);

            let connection = self.incoming_connections.get(incoming_token).unwrap();

            event_loop.register_opt(connection.incoming_stream(),
                                    incoming_token.as_raw_token(),
                                    EventSet::all(),
                                    PollOpt::edge())
                      .unwrap();
            event_loop.register_opt(connection.outgoing_stream(),
                                    outgoing_token.as_raw_token(),
                                    EventSet::all(),
                                    PollOpt::edge())
                      .unwrap();
        } else {
            error!("Listener event on unknown token");
        }
    }

    fn incoming_ready(&mut self,
                      event_loop: &mut EventLoop,
                      token: IncomingToken,
                      events: EventSet) {
        let mut remove = false;

        if let Some(mut connection) = self.incoming_connections.get_mut(token) {
            connection.incoming_ready(events);
            connection.tick();

            if connection.is_incoming_closed() {
                remove = true;
            }
        }

        if remove {
            self.remove_connection(event_loop, token);
        }
    }

    fn outgoing_ready(&mut self,
                      event_loop: &mut EventLoop,
                      token: OutgoingToken,
                      events: EventSet) {
        if let Some(&Some(incoming_token)) = self.outgoing_connections.get(token) {
            let mut remove = false;

            if let Some(mut connection) = self.incoming_connections.get_mut(incoming_token) {
                connection.outgoing_ready(events);
                connection.tick();

                if connection.is_outgoing_closed() {
                    remove = true;
                }
            }

            if remove {
                self.remove_connection(event_loop, incoming_token);
            }
        }
    }

    fn remove_connection(&mut self, event_loop: &mut EventLoop, token: IncomingToken) {
        let connection = self.incoming_connections
                             .remove(token)
                             .expect("Can't remove already removed incoming connection");
        self.outgoing_connections
            .remove(connection.outgoing_token())
            .expect("Can't remove already removed outgoing connection");

        event_loop.deregister(connection.incoming_stream())
                  .expect("Can't deregister already deregistered incoming stream");
        event_loop.deregister(connection.outgoing_stream())
                  .expect("Can't deregister already deregistered outgoing stream");
    }
}

impl Handler for Driver {
    type Timeout = ();
    type Message = DriverMessage;

    fn ready(&mut self, event_loop: &mut EventLoop, token: Token, events: EventSet) {
        if token == Token(0) {
            trace!("Event on token zero");
            return;
        }

        trace!("Event on token {:?}", token);

        match TokenType::from_raw_token(token) {
            TokenType::Listener(token) => self.listener_ready(event_loop, token, events),
            TokenType::Incoming(token) => self.incoming_ready(event_loop, token, events),
            TokenType::Outgoing(token) => self.outgoing_ready(event_loop, token, events),
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop, msg: DriverMessage) {
        match msg {
            DriverMessage::Shutdown => event_loop.shutdown(),
        }
    }
}

#[cfg(test)]
mod test {
    use super::{EventLoop, Driver, DriverMessage};

    use std::thread;
    use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
    use std::net::{TcpStream, TcpListener, SocketAddr};
    use std::str::FromStr;
    use std::io::{Write, BufReader, BufRead};
    use std::time::Duration;

    use env_logger;

    use frontend::Frontend;
    use backend::Backend;

    static PORT_NUMBER: AtomicUsize = ATOMIC_USIZE_INIT;

    fn next_port() -> u16 {
        let first_port = option_env!("TEST_BASE_PORT")
                             .map_or(32328, |v| v.parse::<usize>().unwrap());
        PORT_NUMBER.compare_and_swap(0, first_port, Ordering::SeqCst);

        PORT_NUMBER.fetch_add(1, Ordering::SeqCst) as u16
    }

    fn listen_addr() -> SocketAddr {
        let addr = format!("127.0.0.1:{}", next_port());
        FromStr::from_str(&addr).unwrap()
    }

    #[test]
    fn start_stop_driver() {
        let mut event_loop = EventLoop::new().unwrap();
        let sender = event_loop.channel();

        let t = thread::spawn(move || {
            let mut driver = Driver::new();
            event_loop.run(&mut driver).unwrap();
        });

        sender.send(DriverMessage::Shutdown).unwrap();
        t.join().unwrap();
    }

    #[test]
    fn single_backend() {
        env_logger::init().unwrap();

        let mut event_loop = EventLoop::new().unwrap();
        let sender = event_loop.channel();
        let frontend_addr = listen_addr();
        let backend_addr = listen_addr();

        let t1 = thread::spawn(move || {
            let mut driver = Driver::new();
            let backend = Backend::new(vec![backend_addr]);
            let frontend = Frontend::new(frontend_addr, vec![backend]);

            driver.register(&mut event_loop, frontend).unwrap();
            debug!("Starting event loop");

            event_loop.run(&mut driver).unwrap();
        });

        let t2 = thread::spawn(move || {
            debug!("Starting backend listener");

            let listener = TcpListener::bind(backend_addr).unwrap();
            let (mut client, _) = listener.accept().unwrap();

            write!(client, "sent by backend\n").unwrap();
            client.flush().unwrap();

            debug!("Backend wrote data, waiting for data now");

            let mut reader = BufReader::new(client);
            let mut buffer = String::new();
            reader.read_line(&mut buffer).unwrap();

            debug!("Backend done");

            assert_eq!(buffer, "sent by frontend\n");
        });

        thread::sleep(Duration::from_millis(100));

        {
            debug!("Connecting to frontend...");
            let client = TcpStream::connect(frontend_addr).unwrap();
            debug!("Frontend connected, waiting for data...");

            let mut reader = BufReader::new(client);
            let mut buffer = String::new();
            reader.read_line(&mut buffer).unwrap();

            debug!("Frontend read data, sending response");

            assert_eq!(buffer, "sent by backend\n");

            write!(reader.get_mut(), "sent by frontend\n").unwrap();
            reader.get_mut().flush().unwrap();

            debug!("Frontend done");
        }

        sender.send(DriverMessage::Shutdown).unwrap();

        t1.join().unwrap();
        t2.join().unwrap();
    }
}
<|endoftext|>


<commit_before>//! Various error types used internally, and in our public APIs.

use std::error::{self, Error};
use std::fmt;
use std::io;
use std::ops::Deref;

//=========================================================================
// BoxedError

/// A generic error type which can contain any error caused by any of the
/// libraries we call.  This is used by our backend APIs for simplicity and
/// extensibility, and because we don't really care very much about why
/// things fail (at least not at this level).
pub type BoxedError = Box<error::Error+Send+Sync>;

/// Create a `BoxedError` with a simple string error.  We use this for
/// internal errors that we want to keep simple.
pub fn err<T: Into<String>>(message: T) -> BoxedError {
    From::from(message.into())
}

/// Create a `BoxedError` from a format string and format arguments.
macro_rules! err {
    ($( $e:expr ),*) =>
        ($crate::errors::err(format!($( $e ),*)));
}

//=========================================================================
// CredentialError

/// Represents an error which occurred accessing credentials.
#[derive(Debug)]
pub struct CredentialError {
    credential: String,
    original: Option<BoxedError>,
}

/// These methods are public inside the crate, but not visible outside.
pub trait CredentialErrorNew {
    /// Wrap an existing error.
    fn new(credential: String, err: BoxedError) -> CredentialError;
}

impl CredentialErrorNew for CredentialError {
    /// Wrap an existing error.
    fn new(credential: String, err: BoxedError) -> CredentialError {
        CredentialError {
            credential: credential,
            original: Some(err),
        }
    }
}

impl error::Error for CredentialError {
    fn description(&self) -> &str { "can't access secure credential" }
    fn cause(&self) -> Option<&error::Error> {
        match self.original {
            None => None,
            Some(ref bx) => Some(bx.deref() as &error::Error),
        }
    }
}

impl fmt::Display for CredentialError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.original.is_none() {
            write!(f, "{} {}", self.description(), self.credential)
        } else {
            write!(f, "{} {}: {}", self.description(), self.credential,
                   self.cause().unwrap())
        }
    }
}

//=========================================================================
// SecretfileError

/// Represents an error which occurred parsing a `Secretfile`.
#[derive(Debug)]
pub struct SecretfileError {
    original: Option<BoxedError>,
}

/// These methods are public inside the crate, but not visible outside.
pub trait SecretfileErrorNew {
    /// Wrap an existing error.
    fn new(err: BoxedError) -> SecretfileError;
}

impl SecretfileErrorNew for SecretfileError {
    fn new(err: BoxedError) -> SecretfileError {
        SecretfileError { original: Some(err) }
    }
}

impl error::Error for SecretfileError {
    fn description(&self) -> &str { "error parsing Secretfile" }
    fn cause(&self) -> Option<&error::Error> {
        match self.original {
            None => None,
            Some(ref bx) => Some(bx.deref() as &error::Error),
        }
    }
}

impl fmt::Display for SecretfileError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.original.is_none() {
            write!(f, "{}", self.description())
        } else {
            write!(f, "{}: {}", self.description(), self.cause().unwrap())
        }
    }
}

impl From<BoxedError> for SecretfileError {
    fn from(err: BoxedError) -> SecretfileError {
        SecretfileError { original: Some(err) }
    }
}

impl From<io::Error> for SecretfileError {
    fn from(err: io::Error) -> SecretfileError {
        SecretfileError { original: Some(Box::new(err)) }
    }
}
<commit_msg>Simplify error implementations<commit_after>//! Various error types used internally, and in our public APIs.

use std::error::{self, Error};
use std::fmt;
use std::io;
use std::ops::Deref;

//=========================================================================
// BoxedError

/// A generic error type which can contain any error caused by any of the
/// libraries we call.  This is used by our backend APIs for simplicity and
/// extensibility, and because we don't really care very much about why
/// things fail (at least not at this level).
pub type BoxedError = Box<error::Error+Send+Sync>;

/// Create a `BoxedError` with a simple string error.  We use this for
/// internal errors that we want to keep simple.
pub fn err<T: Into<String>>(message: T) -> BoxedError {
    From::from(message.into())
}

/// Create a `BoxedError` from a format string and format arguments.
macro_rules! err {
    ($( $e:expr ),*) =>
        ($crate::errors::err(format!($( $e ),*)));
}

//=========================================================================
// CredentialError

/// Represents an error which occurred accessing credentials.
#[derive(Debug)]
pub struct CredentialError {
    credential: String,
    original: BoxedError,
}

/// These methods are public inside the crate, but not visible outside.
pub trait CredentialErrorNew {
    /// Wrap an existing error.
    fn new(credential: String, err: BoxedError) -> CredentialError;
}

impl CredentialErrorNew for CredentialError {
    /// Wrap an existing error.
    fn new(credential: String, err: BoxedError) -> CredentialError {
        CredentialError {
            credential: credential,
            original: err,
        }
    }
}

impl error::Error for CredentialError {
    fn description(&self) -> &str { "can't access secure credential" }
    fn cause(&self) -> Option<&error::Error> {
        Some(self.original.deref() as &error::Error)
    }
}

impl fmt::Display for CredentialError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {}: {}", self.description(), self.credential,
               self.cause().unwrap())
    }
}

//=========================================================================
// SecretfileError

/// Represents an error which occurred parsing a `Secretfile`.
#[derive(Debug)]
pub struct SecretfileError {
    original: BoxedError,
}

/// These methods are public inside the crate, but not visible outside.
pub trait SecretfileErrorNew {
    /// Wrap an existing error.
    fn new(err: BoxedError) -> SecretfileError;
}

impl SecretfileErrorNew for SecretfileError {
    fn new(err: BoxedError) -> SecretfileError {
        SecretfileError { original: err }
    }
}

impl error::Error for SecretfileError {
    fn description(&self) -> &str { "error parsing Secretfile" }
    fn cause(&self) -> Option<&error::Error> {
        Some(self.original.deref() as &error::Error)
    }
}

impl fmt::Display for SecretfileError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}: {}", self.description(), self.cause().unwrap())
    }
}

impl From<BoxedError> for SecretfileError {
    fn from(err: BoxedError) -> SecretfileError {
        SecretfileError { original: err }
    }
}

impl From<io::Error> for SecretfileError {
    fn from(err: io::Error) -> SecretfileError {
        SecretfileError { original: Box::new(err) }
    }
}
<|endoftext|>


<commit_before>
use std::ops::{
    Add, Sub, Mul, Div, Rem, Neg, Not, Shr, Shl,
    BitAnd,
    BitOr,
    BitXor,
};
use imp_prelude::*;
// array OPERATORS

macro_rules! impl_binary_op_inplace(
    ($trt:ident, $mth:ident, $imethod:ident, $imth_scalar:ident, $doc:expr) => (
    /// Perform elementwise
    #[doc=$doc]
    /// between `self` and `rhs`,
    /// *in place*.
    ///
    /// If their shapes disagree, `rhs` is broadcast to the shape of `self`.
    ///
    /// **Panics** if broadcasting isn’t possible.
    pub fn $imethod <E: Dimension, S2> (&mut self, rhs: &ArrayBase<S2, E>)
        where A: Clone + $trt<A, Output=A>,
              S2: Data<Elem=A>,
    {
        self.zip_mut_with(rhs, |x, y| {
            *x = x.clone().$mth(y.clone());
        });
    }

    /// Perform elementwise
    #[doc=$doc]
    /// between `self` and the scalar `x`,
    /// *in place*.
    pub fn $imth_scalar (&mut self, x: &A)
        where A: Clone + $trt<A, Output=A>,
    {
        self.unordered_foreach_mut(move |elt| {
            *elt = elt.clone(). $mth (x.clone());
        });
    }
    );
);

/// *In-place* arithmetic operations.
impl<A, S, D> ArrayBase<S, D>
    where S: DataMut<Elem=A>,
          D: Dimension,
{

impl_binary_op_inplace!(Add, add, iadd, iadd_scalar, "addition");
impl_binary_op_inplace!(Sub, sub, isub, isub_scalar, "subtraction");
impl_binary_op_inplace!(Mul, mul, imul, imul_scalar, "multiplication");
impl_binary_op_inplace!(Div, div, idiv, idiv_scalar, "division");
impl_binary_op_inplace!(Rem, rem, irem, irem_scalar, "remainder");
impl_binary_op_inplace!(BitAnd, bitand, ibitand, ibitand_scalar, "bit and");
impl_binary_op_inplace!(BitOr, bitor, ibitor, ibitor_scalar, "bit or");
impl_binary_op_inplace!(BitXor, bitxor, ibitxor, ibitxor_scalar, "bit xor");
impl_binary_op_inplace!(Shl, shl, ishl, ishl_scalar, "left shift");
impl_binary_op_inplace!(Shr, shr, ishr, ishr_scalar, "right shift");

    /// Perform an elementwise negation of `self`, *in place*.
    pub fn ineg(&mut self)
        where A: Clone + Neg<Output=A>,
    {
        self.unordered_foreach_mut(|elt| {
            *elt = elt.clone().neg()
        });
    }

    /// Perform an elementwise unary not of `self`, *in place*.
    pub fn inot(&mut self)
        where A: Clone + Not<Output=A>,
    {
        self.unordered_foreach_mut(|elt| {
            *elt = elt.clone().not()
        });
    }

}

<commit_msg>Add forward compat note to the section with .iadd() and similar methods<commit_after>
use std::ops::{
    Add, Sub, Mul, Div, Rem, Neg, Not, Shr, Shl,
    BitAnd,
    BitOr,
    BitXor,
};
use imp_prelude::*;
// array OPERATORS

macro_rules! impl_binary_op_inplace(
    ($trt:ident, $mth:ident, $imethod:ident, $imth_scalar:ident, $doc:expr) => (
    /// Perform elementwise
    #[doc=$doc]
    /// between `self` and `rhs`,
    /// *in place*.
    ///
    /// If their shapes disagree, `rhs` is broadcast to the shape of `self`.
    ///
    /// **Panics** if broadcasting isn’t possible.
    pub fn $imethod <E: Dimension, S2> (&mut self, rhs: &ArrayBase<S2, E>)
        where A: Clone + $trt<A, Output=A>,
              S2: Data<Elem=A>,
    {
        self.zip_mut_with(rhs, |x, y| {
            *x = x.clone().$mth(y.clone());
        });
    }

    /// Perform elementwise
    #[doc=$doc]
    /// between `self` and the scalar `x`,
    /// *in place*.
    pub fn $imth_scalar (&mut self, x: &A)
        where A: Clone + $trt<A, Output=A>,
    {
        self.unordered_foreach_mut(move |elt| {
            *elt = elt.clone(). $mth (x.clone());
        });
    }
    );
);

/// In-place arithmetic operations.
///
/// ***Note: These will be deprecated in favour of overloaded `@=` operators
/// when Rust 1.8 is released.***
impl<A, S, D> ArrayBase<S, D>
    where S: DataMut<Elem=A>,
          D: Dimension,
{

impl_binary_op_inplace!(Add, add, iadd, iadd_scalar, "addition");
impl_binary_op_inplace!(Sub, sub, isub, isub_scalar, "subtraction");
impl_binary_op_inplace!(Mul, mul, imul, imul_scalar, "multiplication");
impl_binary_op_inplace!(Div, div, idiv, idiv_scalar, "division");
impl_binary_op_inplace!(Rem, rem, irem, irem_scalar, "remainder");
impl_binary_op_inplace!(BitAnd, bitand, ibitand, ibitand_scalar, "bit and");
impl_binary_op_inplace!(BitOr, bitor, ibitor, ibitor_scalar, "bit or");
impl_binary_op_inplace!(BitXor, bitxor, ibitxor, ibitxor_scalar, "bit xor");
impl_binary_op_inplace!(Shl, shl, ishl, ishl_scalar, "left shift");
impl_binary_op_inplace!(Shr, shr, ishr, ishr_scalar, "right shift");

    /// Perform an elementwise negation of `self`, *in place*.
    pub fn ineg(&mut self)
        where A: Clone + Neg<Output=A>,
    {
        self.unordered_foreach_mut(|elt| {
            *elt = elt.clone().neg()
        });
    }

    /// Perform an elementwise unary not of `self`, *in place*.
    pub fn inot(&mut self)
        where A: Clone + Not<Output=A>,
    {
        self.unordered_foreach_mut(|elt| {
            *elt = elt.clone().not()
        });
    }

}

<|endoftext|>


<commit_before>use std::ops::{Add, Div, Mul, Rem, Sub};
use typedef::*;

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, PartialOrd)]
pub enum Type {
    Boolean,
    Float,
    Integer,
    Color,
    Char,
    Undefined,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, PartialOrd)]
pub enum Value {
    Boolean(bool), // true | false
    Float(Float), // -1.33 | 0.23114 | 3.141 | ...
    Integer(Integer), // 12 | 42 | 1 | 0 | 24 | ...
    Color(u8, u8, u8), // #FF00FF | #bd37b3 | ...
    Char(char), // 'a' | 'b' | 'c' | 'd' | ...
    Undefined, // The Undefined value symbolizes an internal error or a wrong use of the bytecode
}

impl Default for Value {
    fn default() -> Self {
        Value::Undefined
    }
}

impl Value {
    pub fn is_undefined(&self) -> bool {
        match self {
            &Value::Undefined => true,
            _ => false,
        }
    }

    pub fn get_type(&self) -> Type {
        match *self {
            Value::Boolean(..) => Type::Boolean,
            Value::Float(..) => Type::Float,
            Value::Integer(..) => Type::Integer,
            Value::Color(..) => Type::Color,
            Value::Char(..) => Type::Char,
            _ => Type::Undefined,
        }
    }

    pub fn is_a(&self, val_type: &Type) -> bool {
        &self.get_type() == val_type
    }

    pub fn convert_to(&self, val_type: &Type) -> Self {
        match *self {
            Value::Boolean(boolean) => Value::Boolean(boolean),
            Value::Float(float) => Self::float_to(float, val_type),
            Value::Integer(integer) => Self::integer_to(integer, val_type),
            Value::Color(r, g, b) => Self::color_to((r, g, b), val_type),
            Value::Char(character) => Self::char_to(character, val_type),
            _ => Value::Undefined,
        }
    }

    fn float_to(float: Float, val_type: &Type) -> Value {
        match *val_type {
            Type::Integer => Value::Integer(float as Integer),
            _ => Value::Float(float),
        }
    }

    fn integer_to(integer: Integer, val_type: &Type) -> Value {
        match *val_type {
            Type::Float => Value::Float(integer as Float),
            Type::Color => {
                let integer = integer as u32;

                let r = (integer >> 16) as u8;
                let g = (integer >> 8) as u8;
                let b = integer as u8;

                Value::Color(r, g, b)
            }
            Type::Char => {
                let integer = integer as u8;

                Value::Char(integer as char)
            }
            _ => Value::Integer(integer),
        }
    }

    fn color_to((r, g, b): Color, val_type: &Type) -> Value {
        match *val_type {
            Type::Integer => {
                let mut integer: u32 = (r as u32) << 16;
                integer |= (g as u32) << 8;
                integer |= b as u32;

                Value::Integer(integer as Integer)
            }
            _ => Value::Color(r, g, b),
        }
    }

    fn char_to(character: char, val_type: &Type) -> Value {
        match *val_type {
            Type::Integer => Value::Integer(character as Integer),
            _ => Value::Char(character),
        }
    }
}

impl Add for Value {
    type Output = Value;

    fn add(self, rhs: Self) -> Self::Output {
        match (self, rhs) {
            (Value::Float(lhs_float), Value::Float(rhs_float)) => Value::Float(lhs_float + rhs_float,),
            (Value::Integer(lhs_integer), Value::Integer(rhs_integer)) => {
                Value::Integer(lhs_integer + rhs_integer)
            }
            _ => Value::Undefined,
        }
    }
}

impl Sub for Value {
    type Output = Value;

    fn sub(self, rhs: Self) -> Self::Output {
        match (self, rhs) {
            (Value::Float(lhs_float), Value::Float(rhs_float)) => Value::Float(lhs_float - rhs_float,),
            (Value::Integer(lhs_integer), Value::Integer(rhs_integer)) => {
                Value::Integer(lhs_integer - rhs_integer)
            }
            _ => Value::Undefined,
        }
    }
}

impl Mul for Value {
    type Output = Value;

    fn mul(self, rhs: Self) -> Self::Output {
        match (self, rhs) {
            (Value::Float(lhs_float), Value::Float(rhs_float)) => Value::Float(lhs_float * rhs_float,),
            (Value::Integer(lhs_integer), Value::Integer(rhs_integer)) => {
                Value::Integer(lhs_integer * rhs_integer)
            }
            _ => Value::Undefined,
        }
    }
}

impl Div for Value {
    type Output = Value;

    fn div(self, rhs: Self) -> Self::Output {
        match (self, rhs) {
            (Value::Float(lhs_float), Value::Float(rhs_float)) => Value::Float(lhs_float / rhs_float,),
            _ => Value::Undefined,
        }
    }
}

impl Rem for Value {
    type Output = Value;

    fn rem(self, rhs: Self) -> Self::Output {
        match (self, rhs) {
            (Value::Float(lhs_float), Value::Float(rhs_float)) => Value::Float(lhs_float % rhs_float,),
            (Value::Integer(lhs_integer), Value::Integer(rhs_integer)) => {
                Value::Integer(lhs_integer % rhs_integer)
            }
            _ => Value::Undefined,
        }
    }
}

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

    #[test]
    fn comparison() {
        assert!(Value::Float(1.3) < Value::Float(1.4));
        assert!(Value::Float(3.1) > Value::Float(2.4));
        assert!(Value::Float(9.6) == Value::Float(9.6));

        assert!(Value::Integer(124) < Value::Integer(234));
        assert!(Value::Integer(4) > Value::Integer(1));
        assert!(Value::Integer(839) == Value::Integer(839));
    }
}
<commit_msg>Added new conversion test<commit_after>use std::ops::{Add, Div, Mul, Rem, Sub};
use typedef::*;

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, PartialOrd)]
pub enum Type {
    Boolean,
    Float,
    Integer,
    Color,
    Char,
    Undefined,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, PartialOrd)]
pub enum Value {
    Boolean(bool), // true | false
    Float(Float), // -1.33 | 0.23114 | 3.141 | ...
    Integer(Integer), // 12 | 42 | 1 | 0 | 24 | ...
    Color(u8, u8, u8), // #FF00FF | #bd37b3 | ...
    Char(char), // 'a' | 'b' | 'c' | 'd' | ...
    Undefined, // The Undefined value symbolizes an internal error or a wrong use of the bytecode
}

impl Default for Value {
    fn default() -> Self {
        Value::Undefined
    }
}

impl Value {
    pub fn is_undefined(&self) -> bool {
        match self {
            &Value::Undefined => true,
            _ => false,
        }
    }

    pub fn get_type(&self) -> Type {
        match *self {
            Value::Boolean(..) => Type::Boolean,
            Value::Float(..) => Type::Float,
            Value::Integer(..) => Type::Integer,
            Value::Color(..) => Type::Color,
            Value::Char(..) => Type::Char,
            _ => Type::Undefined,
        }
    }

    pub fn is_a(&self, val_type: &Type) -> bool {
        &self.get_type() == val_type
    }

    pub fn convert_to(&self, val_type: &Type) -> Self {
        match *self {
            Value::Boolean(boolean) => Value::Boolean(boolean),
            Value::Float(float) => Self::float_to(float, val_type),
            Value::Integer(integer) => Self::integer_to(integer, val_type),
            Value::Color(r, g, b) => Self::color_to((r, g, b), val_type),
            Value::Char(character) => Self::char_to(character, val_type),
            _ => Value::Undefined,
        }
    }

    fn float_to(float: Float, val_type: &Type) -> Value {
        match *val_type {
            Type::Integer => Value::Integer(float as Integer),
            _ => Value::Float(float),
        }
    }

    fn integer_to(integer: Integer, val_type: &Type) -> Value {
        match *val_type {
            Type::Float => Value::Float(integer as Float),
            Type::Color => {
                let integer = integer as u32;

                let r = (integer >> 16) as u8;
                let g = (integer >> 8) as u8;
                let b = integer as u8;

                Value::Color(r, g, b)
            }
            Type::Char => {
                let integer = integer as u8;

                Value::Char(integer as char)
            }
            _ => Value::Integer(integer),
        }
    }

    fn color_to((r, g, b): Color, val_type: &Type) -> Value {
        match *val_type {
            Type::Integer => {
                let mut integer: u32 = (r as u32) << 16;
                integer |= (g as u32) << 8;
                integer |= b as u32;

                Value::Integer(integer as Integer)
            }
            _ => Value::Color(r, g, b),
        }
    }

    fn char_to(character: char, val_type: &Type) -> Value {
        match *val_type {
            Type::Integer => Value::Integer(character as Integer),
            _ => Value::Char(character),
        }
    }
}

impl Add for Value {
    type Output = Value;

    fn add(self, rhs: Self) -> Self::Output {
        match (self, rhs) {
            (Value::Float(lhs_float), Value::Float(rhs_float)) => Value::Float(lhs_float + rhs_float,),
            (Value::Integer(lhs_integer), Value::Integer(rhs_integer)) => {
                Value::Integer(lhs_integer + rhs_integer)
            }
            _ => Value::Undefined,
        }
    }
}

impl Sub for Value {
    type Output = Value;

    fn sub(self, rhs: Self) -> Self::Output {
        match (self, rhs) {
            (Value::Float(lhs_float), Value::Float(rhs_float)) => Value::Float(lhs_float - rhs_float,),
            (Value::Integer(lhs_integer), Value::Integer(rhs_integer)) => {
                Value::Integer(lhs_integer - rhs_integer)
            }
            _ => Value::Undefined,
        }
    }
}

impl Mul for Value {
    type Output = Value;

    fn mul(self, rhs: Self) -> Self::Output {
        match (self, rhs) {
            (Value::Float(lhs_float), Value::Float(rhs_float)) => Value::Float(lhs_float * rhs_float,),
            (Value::Integer(lhs_integer), Value::Integer(rhs_integer)) => {
                Value::Integer(lhs_integer * rhs_integer)
            }
            _ => Value::Undefined,
        }
    }
}

impl Div for Value {
    type Output = Value;

    fn div(self, rhs: Self) -> Self::Output {
        match (self, rhs) {
            (Value::Float(lhs_float), Value::Float(rhs_float)) => Value::Float(lhs_float / rhs_float,),
            _ => Value::Undefined,
        }
    }
}

impl Rem for Value {
    type Output = Value;

    fn rem(self, rhs: Self) -> Self::Output {
        match (self, rhs) {
            (Value::Float(lhs_float), Value::Float(rhs_float)) => Value::Float(lhs_float % rhs_float,),
            (Value::Integer(lhs_integer), Value::Integer(rhs_integer)) => {
                Value::Integer(lhs_integer % rhs_integer)
            }
            _ => Value::Undefined,
        }
    }
}

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

    #[test]
    fn comparison() {
        assert!(Value::Float(1.3) < Value::Float(1.4));
        assert!(Value::Float(3.1) > Value::Float(2.4));
        assert!(Value::Float(9.6) == Value::Float(9.6));

        assert!(Value::Integer(124) < Value::Integer(234));
        assert!(Value::Integer(4) > Value::Integer(1));
        assert!(Value::Integer(839) == Value::Integer(839));
    }

    #[test]
    fn conversion() {
        let initial_color = Value::Integer(0xFF4422).convert_to(&Type::Color);

        assert_eq!(
            Value::Integer(0xFF4422),
            initial_color.convert_to(&Type::Integer)
        );
    }
}
<|endoftext|>


<commit_before>/*!
The ignore module is responsible for managing the state required to determine
whether a *single* file path should be searched or not.

In general, there are two ways to ignore a particular file:

1. Specify an ignore rule in some "global" configuration, such as a
   $HOME/.rgignore or on the command line.
2. A specific ignore file (like .gitignore) found during directory traversal.

The `IgnoreDir` type handles ignore patterns for any one particular directory
(including "global" ignore patterns), while the `Ignore` type handles a stack
of `IgnoreDir`s for use during directory traversal.
*/

use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::path::{Path, PathBuf};

use gitignore::{self, Gitignore, GitignoreBuilder, Match, Pattern};
use types::Types;

const IGNORE_NAMES: &'static [&'static str] = &[
    ".gitignore",
    ".rgignore",
];

/// Represents an error that can occur when parsing a gitignore file.
#[derive(Debug)]
pub enum Error {
    Gitignore(gitignore::Error),
    Io {
        path: PathBuf,
        err: io::Error,
    },
}

impl Error {
    fn from_io<P: AsRef<Path>>(path: P, err: io::Error) -> Error {
        Error::Io { path: path.as_ref().to_path_buf(), err: err }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Gitignore(ref err) => err.description(),
            Error::Io { ref err, .. } => err.description(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Gitignore(ref err) => err.fmt(f),
            Error::Io { ref path, ref err } => {
                write!(f, "{}: {}", path.display(), err)
            }
        }
    }
}

impl From<gitignore::Error> for Error {
    fn from(err: gitignore::Error) -> Error {
        Error::Gitignore(err)
    }
}

/// Ignore represents a collection of ignore patterns organized by directory.
/// In particular, a stack is maintained, where the top of the stack
/// corresponds to the current directory being searched and the bottom of the
/// stack represents the root of a search. Ignore patterns at the top of the
/// stack take precedence over ignore patterns at the bottom of the stack.
pub struct Ignore {
    /// A stack of ignore patterns at each directory level of traversal.
    /// A directory that contributes no ignore patterns is `None`.
    stack: Vec<Option<IgnoreDir>>,
    /// A set of override globs that are always checked first. A match (whether
    /// it's whitelist or blacklist) trumps anything in stack.
    overrides: Overrides,
    /// A file type matcher.
    types: Types,
    ignore_hidden: bool,
    no_ignore: bool,
}

impl Ignore {
    /// Create an empty set of ignore patterns.
    pub fn new() -> Ignore {
        Ignore {
            stack: vec![],
            overrides: Overrides::new(None),
            types: Types::empty(),
            ignore_hidden: true,
            no_ignore: false,
        }
    }

    /// Set whether hidden files/folders should be ignored (defaults to true).
    pub fn ignore_hidden(&mut self, yes: bool) -> &mut Ignore {
        self.ignore_hidden = yes;
        self
    }

    /// When set, ignore files are ignored.
    pub fn no_ignore(&mut self, yes: bool) -> &mut Ignore {
        self.no_ignore = yes;
        self
    }

    /// Add a set of globs that overrides all other match logic.
    pub fn add_override(&mut self, gi: Gitignore) -> &mut Ignore {
        self.overrides = Overrides::new(Some(gi));
        self
    }

    /// Add a file type matcher. The file type matcher has the lowest
    /// precedence.
    pub fn add_types(&mut self, types: Types) -> &mut Ignore {
        self.types = types;
        self
    }

    /// Push parent directories of `path` on to the stack.
    pub fn push_parents<P: AsRef<Path>>(
        &mut self,
        path: P,
    ) -> Result<(), Error> {
        let path = try!(path.as_ref().canonicalize().map_err(|err| {
            Error::from_io(path.as_ref(), err)
        }));
        let mut path = &*path;
        let mut saw_git = path.join(".git").is_dir();
        let mut ignore_names = IGNORE_NAMES.to_vec();
        let mut ignore_dir_results = vec![];
        while let Some(parent) = path.parent() {
            if self.no_ignore {
                ignore_dir_results.push(Ok(None));
            } else {
                if saw_git {
                    ignore_names.retain(|&name| name != ".gitignore");
                } else {
                    saw_git = parent.join(".git").is_dir();
                }
                let ignore_dir_result =
                    IgnoreDir::with_ignore_names(parent, ignore_names.iter());
                ignore_dir_results.push(ignore_dir_result);
            }
            path = parent;
        }

        for ignore_dir_result in ignore_dir_results.into_iter().rev() {
            try!(self.push_ignore_dir(ignore_dir_result));
        }
        Ok(())
    }

    /// Add a directory to the stack.
    ///
    /// Note that even if this returns an error, the directory is added to the
    /// stack (and therefore should be popped).
    pub fn push<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
        if self.no_ignore {
            self.stack.push(None);
            return Ok(());
        }
        self.push_ignore_dir(IgnoreDir::new(path))
    }

    /// Pushes the result of building a directory matcher on to the stack.
    ///
    /// If the result given contains an error, then it is returned.
    pub fn push_ignore_dir(
        &mut self,
        result: Result<Option<IgnoreDir>, Error>,
    ) -> Result<(), Error> {
        match result {
            Ok(id) => {
                self.stack.push(id);
                Ok(())
            }
            Err(err) => {
                // Don't leave the stack in an inconsistent state.
                self.stack.push(None);
                Err(err)
            }
        }
    }

    /// Pop a directory from the stack.
    ///
    /// This panics if the stack is empty.
    pub fn pop(&mut self) {
        self.stack.pop().expect("non-empty stack");
    }

    /// Returns true if and only if the given file path should be ignored.
    pub fn ignored<P: AsRef<Path>>(&self, path: P, is_dir: bool) -> bool {
        let path = path.as_ref();
        let mat = self.overrides.matched(path, is_dir);
        if let Some(is_ignored) = self.ignore_match(path, mat) {
            return is_ignored;
        }
        if self.ignore_hidden && is_hidden(&path) {
            debug!("{} ignored because it is hidden", path.display());
            return true;
        }
        for id in self.stack.iter().rev().filter_map(|id| id.as_ref()) {
            let mat = id.matched(path, is_dir);
            if let Some(is_ignored) = self.ignore_match(path, mat) {
                if is_ignored {
                    return true;
                }
                // If this path is whitelisted by an ignore, then fallthrough
                // and let the file type matcher have a say.
                break;
            }
        }
        let mat = self.types.matched(path, is_dir);
        if let Some(is_ignored) = self.ignore_match(path, mat) {
            return is_ignored;
        }
        false
    }

    /// Returns true if the given match says the given pattern should be
    /// ignored or false if the given pattern should be explicitly whitelisted.
    /// Returns None otherwise.
    pub fn ignore_match<P: AsRef<Path>>(
        &self,
        path: P,
        mat: Match,
    ) -> Option<bool> {
        let path = path.as_ref();
        match mat {
            Match::Whitelist(ref pat) => {
                debug!("{} whitelisted by {:?}", path.display(), pat);
                Some(false)
            }
            Match::Ignored(ref pat) => {
                debug!("{} ignored by {:?}", path.display(), pat);
                Some(true)
            }
            Match::None => None,
        }
    }
}

/// IgnoreDir represents a set of ignore patterns retrieved from a single
/// directory.
pub struct IgnoreDir {
    /// The path to this directory as given.
    path: PathBuf,
    /// A single accumulation of glob patterns for this directory, matched
    /// using gitignore semantics.
    ///
    /// This will include patterns from rgignore as well. The patterns are
    /// ordered so that precedence applies automatically (e.g., rgignore
    /// patterns procede gitignore patterns).
    gi: Option<Gitignore>,
    // TODO(burntsushi): Matching other types of glob patterns that don't
    // conform to gitignore will probably require refactoring this approach.
}

impl IgnoreDir {
    /// Create a new matcher for the given directory.
    ///
    /// If no ignore glob patterns could be found in the directory then `None`
    /// is returned.
    pub fn new<P: AsRef<Path>>(path: P) -> Result<Option<IgnoreDir>, Error> {
        IgnoreDir::with_ignore_names(path, IGNORE_NAMES.iter())
    }

    /// Create a new matcher for the given directory using only the ignore
    /// patterns found in the file names given.
    ///
    /// If no ignore glob patterns could be found in the directory then `None`
    /// is returned.
    ///
    /// Note that the order of the names given is meaningful. Names appearing
    /// later in the list have precedence over names appearing earlier in the
    /// list.
    pub fn with_ignore_names<P: AsRef<Path>, S, I>(
        path: P,
        names: I,
    ) -> Result<Option<IgnoreDir>, Error>
    where P: AsRef<Path>, S: AsRef<str>, I: Iterator<Item=S> {
        let mut id = IgnoreDir {
            path: path.as_ref().to_path_buf(),
            gi: None,
        };
        let mut ok = false;
        let mut builder = GitignoreBuilder::new(&id.path);
        // The ordering here is important. Later globs have higher precedence.
        for name in names {
            ok = builder.add_path(id.path.join(name.as_ref())).is_ok() || ok;
        }
        if !ok {
            Ok(None)
        } else {
            id.gi = Some(try!(builder.build()));
            Ok(Some(id))
        }
    }

    /// Returns true if and only if the given file path should be ignored
    /// according to the globs in this directory. `is_dir` should be true if
    /// the path refers to a directory and false otherwise.
    ///
    /// Before matching path, its prefix (as determined by a common suffix
    /// of this directory) is stripped. If there is
    /// no common suffix/prefix overlap, then path is assumed to reside
    /// directly in this directory.
    ///
    /// If the given path has a `./` prefix then it is stripped before
    /// matching.
    pub fn matched<P: AsRef<Path>>(&self, path: P, is_dir: bool) -> Match {
        self.gi.as_ref()
            .map(|gi| gi.matched(path, is_dir))
            .unwrap_or(Match::None)
    }
}

/// Manages a set of overrides provided explicitly by the end user.
struct Overrides {
    gi: Option<Gitignore>,
    unmatched_pat: Pattern,
}

impl Overrides {
    /// Creates a new set of overrides from the gitignore matcher provided.
    /// If no matcher is provided, then the resulting overrides have no effect.
    fn new(gi: Option<Gitignore>) -> Overrides {
        Overrides {
            gi: gi,
            unmatched_pat: Pattern {
                from: Path::new("<argv>").to_path_buf(),
                original: "<none>".to_string(),
                pat: "<none>".to_string(),
                whitelist: false,
                only_dir: false,
            },
        }
    }

    /// Returns a match for the given path against this set of overrides.
    ///
    /// If there are no overrides, then this always returns Match::None.
    ///
    /// If there is at least one positive override, then this never returns
    /// Match::None (and interpreting non-matches as ignored) unless is_dir
    /// is true.
    pub fn matched<P: AsRef<Path>>(&self, path: P, is_dir: bool) -> Match {
        // File types don't apply to directories.
        if is_dir {
            return Match::None;
        }
        let path = path.as_ref();
        self.gi.as_ref()
            .map(|gi| {
                let path = &*path.to_string_lossy();
                let mat = gi.matched_utf8(path, is_dir).invert();
                if mat.is_none() && !is_dir {
                    if gi.num_ignores() > 0 {
                        return Match::Ignored(&self.unmatched_pat);
                    }
                }
                mat
            })
            .unwrap_or(Match::None)
    }
}

fn is_hidden<P: AsRef<Path>>(path: P) -> bool {
    if let Some(name) = path.as_ref().file_name() {
        name.to_str().map(|s| s.starts_with(".")).unwrap_or(false)
    } else {
        false
    }
}

#[cfg(test)]
mod tests {
    use std::path::Path;
    use gitignore::GitignoreBuilder;
    use super::IgnoreDir;

    macro_rules! ignored_dir {
        ($name:ident, $root:expr, $gi:expr, $xi:expr, $path:expr) => {
            #[test]
            fn $name() {
                let mut builder = GitignoreBuilder::new(&$root);
                builder.add_str($gi).unwrap();
                builder.add_str($xi).unwrap();
                let gi = builder.build().unwrap();
                let id = IgnoreDir {
                    path: Path::new($root).to_path_buf(),
                    gi: Some(gi),
                };
                assert!(id.matched($path, false).is_ignored());
            }
        };
    }

    macro_rules! not_ignored_dir {
        ($name:ident, $root:expr, $gi:expr, $xi:expr, $path:expr) => {
            #[test]
            fn $name() {
                let mut builder = GitignoreBuilder::new(&$root);
                builder.add_str($gi).unwrap();
                builder.add_str($xi).unwrap();
                let gi = builder.build().unwrap();
                let id = IgnoreDir {
                    path: Path::new($root).to_path_buf(),
                    gi: Some(gi),
                };
                assert!(!id.matched($path, false).is_ignored());
            }
        };
    }

    const ROOT: &'static str = "/home/foobar/rust/rg";

    ignored_dir!(id1, ROOT, "src/main.rs", "", "src/main.rs");
    ignored_dir!(id2, ROOT, "", "src/main.rs", "src/main.rs");
    ignored_dir!(id3, ROOT, "!src/main.rs", "*.rs", "src/main.rs");

    not_ignored_dir!(idnot1, ROOT, "*.rs", "!src/main.rs", "src/main.rs");
}
<commit_msg>Don't traverse directory stack if we don't need to.<commit_after>/*!
The ignore module is responsible for managing the state required to determine
whether a *single* file path should be searched or not.

In general, there are two ways to ignore a particular file:

1. Specify an ignore rule in some "global" configuration, such as a
   $HOME/.rgignore or on the command line.
2. A specific ignore file (like .gitignore) found during directory traversal.

The `IgnoreDir` type handles ignore patterns for any one particular directory
(including "global" ignore patterns), while the `Ignore` type handles a stack
of `IgnoreDir`s for use during directory traversal.
*/

use std::error::Error as StdError;
use std::fmt;
use std::io;
use std::path::{Path, PathBuf};

use gitignore::{self, Gitignore, GitignoreBuilder, Match, Pattern};
use types::Types;

const IGNORE_NAMES: &'static [&'static str] = &[
    ".gitignore",
    ".rgignore",
];

/// Represents an error that can occur when parsing a gitignore file.
#[derive(Debug)]
pub enum Error {
    Gitignore(gitignore::Error),
    Io {
        path: PathBuf,
        err: io::Error,
    },
}

impl Error {
    fn from_io<P: AsRef<Path>>(path: P, err: io::Error) -> Error {
        Error::Io { path: path.as_ref().to_path_buf(), err: err }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Gitignore(ref err) => err.description(),
            Error::Io { ref err, .. } => err.description(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Gitignore(ref err) => err.fmt(f),
            Error::Io { ref path, ref err } => {
                write!(f, "{}: {}", path.display(), err)
            }
        }
    }
}

impl From<gitignore::Error> for Error {
    fn from(err: gitignore::Error) -> Error {
        Error::Gitignore(err)
    }
}

/// Ignore represents a collection of ignore patterns organized by directory.
/// In particular, a stack is maintained, where the top of the stack
/// corresponds to the current directory being searched and the bottom of the
/// stack represents the root of a search. Ignore patterns at the top of the
/// stack take precedence over ignore patterns at the bottom of the stack.
pub struct Ignore {
    /// A stack of ignore patterns at each directory level of traversal.
    /// A directory that contributes no ignore patterns is `None`.
    stack: Vec<Option<IgnoreDir>>,
    /// A set of override globs that are always checked first. A match (whether
    /// it's whitelist or blacklist) trumps anything in stack.
    overrides: Overrides,
    /// A file type matcher.
    types: Types,
    /// Whether to ignore hidden files or not.
    ignore_hidden: bool,
    /// When true, don't look at .gitignore or .agignore files for ignore
    /// rules.
    no_ignore: bool,
}

impl Ignore {
    /// Create an empty set of ignore patterns.
    pub fn new() -> Ignore {
        Ignore {
            stack: vec![],
            overrides: Overrides::new(None),
            types: Types::empty(),
            ignore_hidden: true,
            no_ignore: false,
        }
    }

    /// Set whether hidden files/folders should be ignored (defaults to true).
    pub fn ignore_hidden(&mut self, yes: bool) -> &mut Ignore {
        self.ignore_hidden = yes;
        self
    }

    /// When set, ignore files are ignored.
    pub fn no_ignore(&mut self, yes: bool) -> &mut Ignore {
        self.no_ignore = yes;
        self
    }

    /// Add a set of globs that overrides all other match logic.
    pub fn add_override(&mut self, gi: Gitignore) -> &mut Ignore {
        self.overrides = Overrides::new(Some(gi));
        self
    }

    /// Add a file type matcher. The file type matcher has the lowest
    /// precedence.
    pub fn add_types(&mut self, types: Types) -> &mut Ignore {
        self.types = types;
        self
    }

    /// Push parent directories of `path` on to the stack.
    pub fn push_parents<P: AsRef<Path>>(
        &mut self,
        path: P,
    ) -> Result<(), Error> {
        let path = try!(path.as_ref().canonicalize().map_err(|err| {
            Error::from_io(path.as_ref(), err)
        }));
        let mut path = &*path;
        let mut saw_git = path.join(".git").is_dir();
        let mut ignore_names = IGNORE_NAMES.to_vec();
        let mut ignore_dir_results = vec![];
        while let Some(parent) = path.parent() {
            if self.no_ignore {
                ignore_dir_results.push(Ok(None));
            } else {
                if saw_git {
                    ignore_names.retain(|&name| name != ".gitignore");
                } else {
                    saw_git = parent.join(".git").is_dir();
                }
                let ignore_dir_result =
                    IgnoreDir::with_ignore_names(parent, ignore_names.iter());
                ignore_dir_results.push(ignore_dir_result);
            }
            path = parent;
        }

        for ignore_dir_result in ignore_dir_results.into_iter().rev() {
            try!(self.push_ignore_dir(ignore_dir_result));
        }
        Ok(())
    }

    /// Add a directory to the stack.
    ///
    /// Note that even if this returns an error, the directory is added to the
    /// stack (and therefore should be popped).
    pub fn push<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
        if self.no_ignore {
            self.stack.push(None);
            return Ok(());
        }
        self.push_ignore_dir(IgnoreDir::new(path))
    }

    /// Pushes the result of building a directory matcher on to the stack.
    ///
    /// If the result given contains an error, then it is returned.
    pub fn push_ignore_dir(
        &mut self,
        result: Result<Option<IgnoreDir>, Error>,
    ) -> Result<(), Error> {
        match result {
            Ok(id) => {
                self.stack.push(id);
                Ok(())
            }
            Err(err) => {
                // Don't leave the stack in an inconsistent state.
                self.stack.push(None);
                Err(err)
            }
        }
    }

    /// Pop a directory from the stack.
    ///
    /// This panics if the stack is empty.
    pub fn pop(&mut self) {
        self.stack.pop().expect("non-empty stack");
    }

    /// Returns true if and only if the given file path should be ignored.
    pub fn ignored<P: AsRef<Path>>(&self, path: P, is_dir: bool) -> bool {
        let path = path.as_ref();
        let mat = self.overrides.matched(path, is_dir);
        if let Some(is_ignored) = self.ignore_match(path, mat) {
            return is_ignored;
        }
        if self.ignore_hidden && is_hidden(&path) {
            debug!("{} ignored because it is hidden", path.display());
            return true;
        }
        if !self.no_ignore {
            for id in self.stack.iter().rev().filter_map(|id| id.as_ref()) {
                let mat = id.matched(path, is_dir);
                if let Some(is_ignored) = self.ignore_match(path, mat) {
                    if is_ignored {
                        return true;
                    }
                    // If this path is whitelisted by an ignore, then
                    // fallthrough and let the file type matcher have a say.
                    break;
                }
            }
        }
        let mat = self.types.matched(path, is_dir);
        if let Some(is_ignored) = self.ignore_match(path, mat) {
            return is_ignored;
        }
        false
    }

    /// Returns true if the given match says the given pattern should be
    /// ignored or false if the given pattern should be explicitly whitelisted.
    /// Returns None otherwise.
    pub fn ignore_match<P: AsRef<Path>>(
        &self,
        path: P,
        mat: Match,
    ) -> Option<bool> {
        let path = path.as_ref();
        match mat {
            Match::Whitelist(ref pat) => {
                debug!("{} whitelisted by {:?}", path.display(), pat);
                Some(false)
            }
            Match::Ignored(ref pat) => {
                debug!("{} ignored by {:?}", path.display(), pat);
                Some(true)
            }
            Match::None => None,
        }
    }
}

/// IgnoreDir represents a set of ignore patterns retrieved from a single
/// directory.
pub struct IgnoreDir {
    /// The path to this directory as given.
    path: PathBuf,
    /// A single accumulation of glob patterns for this directory, matched
    /// using gitignore semantics.
    ///
    /// This will include patterns from rgignore as well. The patterns are
    /// ordered so that precedence applies automatically (e.g., rgignore
    /// patterns procede gitignore patterns).
    gi: Option<Gitignore>,
    // TODO(burntsushi): Matching other types of glob patterns that don't
    // conform to gitignore will probably require refactoring this approach.
}

impl IgnoreDir {
    /// Create a new matcher for the given directory.
    ///
    /// If no ignore glob patterns could be found in the directory then `None`
    /// is returned.
    pub fn new<P: AsRef<Path>>(path: P) -> Result<Option<IgnoreDir>, Error> {
        IgnoreDir::with_ignore_names(path, IGNORE_NAMES.iter())
    }

    /// Create a new matcher for the given directory using only the ignore
    /// patterns found in the file names given.
    ///
    /// If no ignore glob patterns could be found in the directory then `None`
    /// is returned.
    ///
    /// Note that the order of the names given is meaningful. Names appearing
    /// later in the list have precedence over names appearing earlier in the
    /// list.
    pub fn with_ignore_names<P: AsRef<Path>, S, I>(
        path: P,
        names: I,
    ) -> Result<Option<IgnoreDir>, Error>
    where P: AsRef<Path>, S: AsRef<str>, I: Iterator<Item=S> {
        let mut id = IgnoreDir {
            path: path.as_ref().to_path_buf(),
            gi: None,
        };
        let mut ok = false;
        let mut builder = GitignoreBuilder::new(&id.path);
        // The ordering here is important. Later globs have higher precedence.
        for name in names {
            ok = builder.add_path(id.path.join(name.as_ref())).is_ok() || ok;
        }
        if !ok {
            Ok(None)
        } else {
            id.gi = Some(try!(builder.build()));
            Ok(Some(id))
        }
    }

    /// Returns true if and only if the given file path should be ignored
    /// according to the globs in this directory. `is_dir` should be true if
    /// the path refers to a directory and false otherwise.
    ///
    /// Before matching path, its prefix (as determined by a common suffix
    /// of this directory) is stripped. If there is
    /// no common suffix/prefix overlap, then path is assumed to reside
    /// directly in this directory.
    ///
    /// If the given path has a `./` prefix then it is stripped before
    /// matching.
    pub fn matched<P: AsRef<Path>>(&self, path: P, is_dir: bool) -> Match {
        self.gi.as_ref()
            .map(|gi| gi.matched(path, is_dir))
            .unwrap_or(Match::None)
    }
}

/// Manages a set of overrides provided explicitly by the end user.
struct Overrides {
    gi: Option<Gitignore>,
    unmatched_pat: Pattern,
}

impl Overrides {
    /// Creates a new set of overrides from the gitignore matcher provided.
    /// If no matcher is provided, then the resulting overrides have no effect.
    fn new(gi: Option<Gitignore>) -> Overrides {
        Overrides {
            gi: gi,
            unmatched_pat: Pattern {
                from: Path::new("<argv>").to_path_buf(),
                original: "<none>".to_string(),
                pat: "<none>".to_string(),
                whitelist: false,
                only_dir: false,
            },
        }
    }

    /// Returns a match for the given path against this set of overrides.
    ///
    /// If there are no overrides, then this always returns Match::None.
    ///
    /// If there is at least one positive override, then this never returns
    /// Match::None (and interpreting non-matches as ignored) unless is_dir
    /// is true.
    pub fn matched<P: AsRef<Path>>(&self, path: P, is_dir: bool) -> Match {
        // File types don't apply to directories.
        if is_dir {
            return Match::None;
        }
        let path = path.as_ref();
        self.gi.as_ref()
            .map(|gi| {
                let path = &*path.to_string_lossy();
                let mat = gi.matched_utf8(path, is_dir).invert();
                if mat.is_none() && !is_dir {
                    if gi.num_ignores() > 0 {
                        return Match::Ignored(&self.unmatched_pat);
                    }
                }
                mat
            })
            .unwrap_or(Match::None)
    }
}

fn is_hidden<P: AsRef<Path>>(path: P) -> bool {
    if let Some(name) = path.as_ref().file_name() {
        name.to_str().map(|s| s.starts_with(".")).unwrap_or(false)
    } else {
        false
    }
}

#[cfg(test)]
mod tests {
    use std::path::Path;
    use gitignore::GitignoreBuilder;
    use super::IgnoreDir;

    macro_rules! ignored_dir {
        ($name:ident, $root:expr, $gi:expr, $xi:expr, $path:expr) => {
            #[test]
            fn $name() {
                let mut builder = GitignoreBuilder::new(&$root);
                builder.add_str($gi).unwrap();
                builder.add_str($xi).unwrap();
                let gi = builder.build().unwrap();
                let id = IgnoreDir {
                    path: Path::new($root).to_path_buf(),
                    gi: Some(gi),
                };
                assert!(id.matched($path, false).is_ignored());
            }
        };
    }

    macro_rules! not_ignored_dir {
        ($name:ident, $root:expr, $gi:expr, $xi:expr, $path:expr) => {
            #[test]
            fn $name() {
                let mut builder = GitignoreBuilder::new(&$root);
                builder.add_str($gi).unwrap();
                builder.add_str($xi).unwrap();
                let gi = builder.build().unwrap();
                let id = IgnoreDir {
                    path: Path::new($root).to_path_buf(),
                    gi: Some(gi),
                };
                assert!(!id.matched($path, false).is_ignored());
            }
        };
    }

    const ROOT: &'static str = "/home/foobar/rust/rg";

    ignored_dir!(id1, ROOT, "src/main.rs", "", "src/main.rs");
    ignored_dir!(id2, ROOT, "", "src/main.rs", "src/main.rs");
    ignored_dir!(id3, ROOT, "!src/main.rs", "*.rs", "src/main.rs");

    not_ignored_dir!(idnot1, ROOT, "*.rs", "!src/main.rs", "src/main.rs");
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! rotor_compose {
    /* TODO(tailhook) make and check generic combinators
    (pub enum $name:ident { $($x:ident ($y:ty),)* }) => {
        pub enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name C [] $($x($y),)*);
    };
    (enum $name:ident { $($x:ident ($y:ty),)* }) => {
        enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name $($x($y),)*);
    };
    */
    (pub enum $name:ident/$cname:ident <$context_type:ident>
        { $($x:ident ($y:ty),)* })
    => {
        pub enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name/$cname
            $context_type [] $($x($y),)*);
    };
    (enum $name:ident/$cname:ident <$context_type:ident>
        { $($x:ident ($y:ty),)* })
    => {
        enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name/$cname
            $context_type [] $($x($y),)*);
    };
    (@machine $name:ident/$cname:ident $ctx_typ:ident
        [ $(<$ctx_name:ident $(: $ctx_bound:ident)*>)* ]
        $($iname:ident ($itype:ty),)*)
    => {
        enum $cname {
            $( $iname (<$itype as $crate::Machine>::Seed), )*
        }
        impl $( <$ctx_name:$ctx_bound> )* $crate::Machine for $name {
            type Context = $ctx_typ;
            type Seed = $cname;
            fn create(seed: $cname, scope: &mut $crate::Scope<$ctx_typ>)
                -> Result<Self, Box<::std::error::Error>>
            {
                match seed {
                    $( $cname::$iname (x)
                        => $crate::Machine::create(x, scope).map($name::$iname),
                    )*
                }
            }
            fn ready(self, events: $crate::EventSet,
                scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.ready(events, scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn spawned(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.spawned(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn timeout(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.timeout(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn wakeup(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.wakeup(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
        }

    }
}
<commit_msg>Add minimal documentation for `rotor_compose!`<commit_after>/// Compose multiple state machines into single type
///
/// Composition requires two types: the state machine itself and Seed which
/// is used to create children state machines.
///
/// Mostly because of limitations of Rust macro system composition only works
/// on concrete context type.
///
/// # Example
/// ```ignore
/// rotor_compose!{
///     pub enum Fsm/Seed<Context> {
///         Http(HttpMachine)
///         Dns(DnsMachine)
///     }
/// }
/// ```
///
/// This creates a an `Fsm` state machine type which is enum with two options.
/// And `Seed` state machine type, which is also enum with same option names
/// but uses `<HttpMachine as rotor::Machine>::Seed` for the wrapped type.
#[macro_export]
macro_rules! rotor_compose {
    /* TODO(tailhook) make and check generic combinators
    (pub enum $name:ident { $($x:ident ($y:ty),)* }) => {
        pub enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name C [] $($x($y),)*);
    };
    (enum $name:ident { $($x:ident ($y:ty),)* }) => {
        enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name $($x($y),)*);
    };
    */
    (pub enum $name:ident/$cname:ident <$context_type:ident>
        { $($x:ident ($y:ty),)* })
    => {
        pub enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name/$cname
            $context_type [] $($x($y),)*);
    };
    (enum $name:ident/$cname:ident <$context_type:ident>
        { $($x:ident ($y:ty),)* })
    => {
        enum $name { $($x ($y),)* }
        rotor_compose!(@machine $name/$cname
            $context_type [] $($x($y),)*);
    };
    (@machine $name:ident/$cname:ident $ctx_typ:ident
        [ $(<$ctx_name:ident $(: $ctx_bound:ident)*>)* ]
        $($iname:ident ($itype:ty),)*)
    => {
        enum $cname {
            $( $iname (<$itype as $crate::Machine>::Seed), )*
        }
        impl $( <$ctx_name:$ctx_bound> )* $crate::Machine for $name {
            type Context = $ctx_typ;
            type Seed = $cname;
            fn create(seed: $cname, scope: &mut $crate::Scope<$ctx_typ>)
                -> Result<Self, Box<::std::error::Error>>
            {
                match seed {
                    $( $cname::$iname (x)
                        => $crate::Machine::create(x, scope).map($name::$iname),
                    )*
                }
            }
            fn ready(self, events: $crate::EventSet,
                scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.ready(events, scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn spawned(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.spawned(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn timeout(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.timeout(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
            fn wakeup(self, scope: &mut $crate::Scope<$ctx_typ>)
                -> $crate::Response<Self, Self::Seed>
            {
                match self {
                    $(
                        $name::$iname(m) => {
                            m.wakeup(scope)
                                .map($name::$iname, $cname::$iname)
                        }
                    )*
                }
            }
        }

    }
}
<|endoftext|>


<commit_before>//! Provides a macro for creating an rpc service and client stub.

#[macro_export]
macro_rules! rpc_service { ($server:ident:
    $( $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty;)*) => {
        #[allow(dead_code)]
        mod $server {
            use std::net::ToSocketAddrs;
            use std::io;
            use std::sync::Arc;
            use $crate::protocol::{
                self,
                ServeHandle,
                serve_async,
            };

            #[doc="An RPC error that occurred during serving an RPC request."]
            #[derive(Debug)]
            pub enum Error {
                #[doc="An IO error occurred."]
                Io(io::Error),

                #[doc="An unexpected internal error. Typically a bug in the server impl."]
                InternalError,
            }

            impl ::std::convert::From<protocol::Error> for Error {
                fn from(err: protocol::Error) -> Error {
                    match err {
                        protocol::Error::Io(err) => Error::Io(err),
                        _ => Error::InternalError,
                    }
                }
            }

            impl ::std::convert::From<io::Error> for Error {
                fn from(err: io::Error) -> Error {
                    Error::Io(err)
                }
            }

            #[doc="The result of an RPC call; either the successful result or the error."]
            pub type Result<T> = ::std::result::Result<T, Error>;

            #[doc="The provided RPC service."]
            pub trait Service: Send + Sync {
                $(
                    fn $fn_name(&self, $($arg:$in_),*) -> $out;
                )*
            }

            #[allow(non_camel_case_types)]
            #[derive(Debug, Serialize, Deserialize)]
            enum Request {
                $(
                    $fn_name($($in_),*),
                )*
            }

            #[allow(non_camel_case_types)]
            #[derive(Debug, Serialize, Deserialize)]
            enum Reply {
                $(
                    $fn_name($out),
                )*
                Impossible,
            }

            #[doc="The client stub that makes RPC calls to the server."]
            pub struct Client(protocol::Client<Request, Reply>);

            impl Client {
                #[doc="Create a new client that connects to the given address."]
                pub fn new<A>(addr: A) -> Result<Self>
                    where A: ToSocketAddrs,
                {
                    let inner = try!(protocol::Client::new(addr));
                    Ok(Client(inner))
                }

                $(
                    pub fn $fn_name(&self, $($arg: $in_),*) -> Result<$out> {
                        let reply = try!((self.0).rpc(&Request::$fn_name($($arg),*)));
                        if let Reply::$fn_name(reply) = reply {
                            Ok(reply)
                        } else {
                            Err(Error::InternalError)
                        }
                    }
                )*
            }

            struct Server<S: 'static + Service>(S);

            impl<S> protocol::Serve<Request, Reply> for Server<S>
                where S: 'static + Service
            {
                fn serve(&self, request: Request) -> Reply {
                    match request {
                        $(
                            Request::$fn_name($($arg),*) =>
                                Reply::$fn_name((self.0).$fn_name($($arg),*)),
                         )*
                    }
                }
            }

            #[doc="Start a running service."]
            pub fn serve<A, S>(addr: A, service: S) -> Result<ServeHandle>
                where A: ToSocketAddrs,
                      S: 'static + Service
            {
                let server = Arc::new(Server(service));
                Ok(try!(serve_async(addr, server)))
            }
        }
    }
}

#[cfg(test)]
mod test {

    rpc_service!(my_server:
        hello(foo: super::Foo) -> super::Foo;

        add(x: i32, y: i32) -> i32;
    );

    use self::my_server::*;

    #[derive(PartialEq, Debug, Serialize, Deserialize)]
    pub struct Foo {
        message: String
    }

    impl Service for () {
        fn hello(&self, s: Foo) -> Foo {
            Foo{message: format!("Hello, {}", &s.message)}
        }

        fn add(&self, x: i32, y: i32) -> i32 {
            x + y
        }
    }

    #[test]
    fn simple_test() {
        println!("Starting");
        let addr = "127.0.0.1:9000";
        let shutdown = my_server::serve(addr, ()).unwrap();
        let client = Client::new(addr).unwrap();
        assert_eq!(3, client.add(1, 2).unwrap());
        let foo = Foo{message: "Adam".into()};
        let want = Foo{message: format!("Hello, {}", &foo.message)};
        assert_eq!(want, client.hello(Foo{message: "Adam".into()}).unwrap());
        drop(client);
        shutdown.shutdown();
    }
}
<commit_msg>Make the generated rpc module public<commit_after>//! Provides a macro for creating an rpc service and client stub.

#[macro_export]
macro_rules! rpc_service { ($server:ident:
    $( $fn_name:ident( $( $arg:ident : $in_:ty ),* ) -> $out:ty;)*) => {
        #[allow(dead_code)]
        pub mod $server {
            use std::net::ToSocketAddrs;
            use std::io;
            use std::sync::Arc;
            use $crate::protocol::{
                self,
                ServeHandle,
                serve_async,
            };

            #[doc="An RPC error that occurred during serving an RPC request."]
            #[derive(Debug)]
            pub enum Error {
                #[doc="An IO error occurred."]
                Io(io::Error),

                #[doc="An unexpected internal error. Typically a bug in the server impl."]
                InternalError,
            }

            impl ::std::convert::From<protocol::Error> for Error {
                fn from(err: protocol::Error) -> Error {
                    match err {
                        protocol::Error::Io(err) => Error::Io(err),
                        _ => Error::InternalError,
                    }
                }
            }

            impl ::std::convert::From<io::Error> for Error {
                fn from(err: io::Error) -> Error {
                    Error::Io(err)
                }
            }

            #[doc="The result of an RPC call; either the successful result or the error."]
            pub type Result<T> = ::std::result::Result<T, Error>;

            #[doc="The provided RPC service."]
            pub trait Service: Send + Sync {
                $(
                    fn $fn_name(&self, $($arg:$in_),*) -> $out;
                )*
            }

            #[allow(non_camel_case_types)]
            #[derive(Debug, Serialize, Deserialize)]
            enum Request {
                $(
                    $fn_name($($in_),*),
                )*
            }

            #[allow(non_camel_case_types)]
            #[derive(Debug, Serialize, Deserialize)]
            enum Reply {
                $(
                    $fn_name($out),
                )*
                Impossible,
            }

            #[doc="The client stub that makes RPC calls to the server."]
            pub struct Client(protocol::Client<Request, Reply>);

            impl Client {
                #[doc="Create a new client that connects to the given address."]
                pub fn new<A>(addr: A) -> Result<Self>
                    where A: ToSocketAddrs,
                {
                    let inner = try!(protocol::Client::new(addr));
                    Ok(Client(inner))
                }

                $(
                    pub fn $fn_name(&self, $($arg: $in_),*) -> Result<$out> {
                        let reply = try!((self.0).rpc(&Request::$fn_name($($arg),*)));
                        if let Reply::$fn_name(reply) = reply {
                            Ok(reply)
                        } else {
                            Err(Error::InternalError)
                        }
                    }
                )*
            }

            struct Server<S: 'static + Service>(S);

            impl<S> protocol::Serve<Request, Reply> for Server<S>
                where S: 'static + Service
            {
                fn serve(&self, request: Request) -> Reply {
                    match request {
                        $(
                            Request::$fn_name($($arg),*) =>
                                Reply::$fn_name((self.0).$fn_name($($arg),*)),
                         )*
                    }
                }
            }

            #[doc="Start a running service."]
            pub fn serve<A, S>(addr: A, service: S) -> Result<ServeHandle>
                where A: ToSocketAddrs,
                      S: 'static + Service
            {
                let server = Arc::new(Server(service));
                Ok(try!(serve_async(addr, server)))
            }
        }
    }
}

#[cfg(test)]
mod test {

    rpc_service!(my_server:
        hello(foo: super::Foo) -> super::Foo;

        add(x: i32, y: i32) -> i32;
    );

    use self::my_server::*;

    #[derive(PartialEq, Debug, Serialize, Deserialize)]
    pub struct Foo {
        message: String
    }

    impl Service for () {
        fn hello(&self, s: Foo) -> Foo {
            Foo{message: format!("Hello, {}", &s.message)}
        }

        fn add(&self, x: i32, y: i32) -> i32 {
            x + y
        }
    }

    #[test]
    fn simple_test() {
        println!("Starting");
        let addr = "127.0.0.1:9000";
        let shutdown = my_server::serve(addr, ()).unwrap();
        let client = Client::new(addr).unwrap();
        assert_eq!(3, client.add(1, 2).unwrap());
        let foo = Foo{message: "Adam".into()};
        let want = Foo{message: format!("Hello, {}", &foo.message)};
        assert_eq!(want, client.hello(Foo{message: "Adam".into()}).unwrap());
        drop(client);
        shutdown.shutdown();
    }
}
<|endoftext|>