<commit_before>use std::any::Any;
use std::error::Error;
use std::fmt;
use std::fmt::Debug;
use std::result;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver, TryRecvError, RecvError, SendError};
use std::thread;

use time::{Duration, SteadyTime};

pub type InitResult<E> = result::Result<Option<u64>, E>;
pub type ActorResult<T> = result::Result<T, ActorError>;
pub type StartResult<T, E> = result::Result<Actor<T>, E>;

pub struct Actor<T> where T: Any + Send {
    pub sender: Sender<Message<T>>,
    pub receiver: Receiver<Message<T>>,
    pub handle: thread::JoinHandle<ActorResult<()>>,
    pub name: Option<String>,
}

impl<T> Actor<T> where T: Any + Send {
    /// Create a new actor handler struct.
    pub fn new(sender: Sender<Message<T>>, receiver: Receiver<Message<T>>,
        handle: thread::JoinHandle<ActorResult<()>>, name: Option<String>) -> Self {
        Actor {
            sender: sender,
            receiver: receiver,
            handle: handle,
            name: name,
        }
    }

    pub fn cast(&self, message: T) -> Result<(), ActorError> {
        self::cast(&self.sender, message)
    }

    pub fn call(&self, message: T) -> Result<T, ActorError> {
        self::call(&self.sender, &self.receiver, message)
    }
}

pub fn cast<T: Any + Send>(tx: &Sender<Message<T>>, message: T) -> Result<(), ActorError> {
    match tx.send(Message::Cast(message)) {
        Ok(()) => Ok(()),
        Err(err) => Err(ActorError::from(err)),
    }
}

pub fn call<T: Any + Send>(tx: &Sender<Message<T>>, rx: &Receiver<Message<T>>, message: T) -> Result<T, ActorError> {
    match tx.send(Message::Call(message)) {
        Ok(()) => {
            match rx.recv() {
                Ok(Message::Reply(msg)) => Ok(msg),
                Ok(_) => panic!("must reply from a call!"),
                Err(err) => Err(ActorError::from(err)),
            }
        },
        Err(err) => Err(ActorError::from(err)),
    }
}

pub struct Builder<T: GenServer> {
    name: Option<String>,
    spec: T,
}

impl<A: GenServer> Builder<A> {
    pub fn new(spec: A) -> Self {
        Builder {
            name: None,
            spec: spec,
        }
    }

    pub fn name(mut self, name: String) -> Builder<A> {
        self.name = Some(name);
        self
    }

    /// Start an actor on a new thread and return an Actor.
    pub fn start(self, mut state: A::S) -> StartResult<A::T, A::E> {
        let (otx, orx) = mpsc::channel::<Message<A::T>>();
        let (itx, irx) = mpsc::channel::<Message<A::T>>();
        let initial_wait_ms = match self.spec.init(&itx, &mut state) {
            Ok(result) => result,
            Err(err) => return Err(err),
        };
        let itx2 = itx.clone(); // clone inner receive loop's sender for actor struct
        let name = self.name.clone();
        let thread_name = name.clone().unwrap_or("GenServer".to_string());
        let handle = thread::Builder::new().name(thread_name.clone()).spawn(move || {
            let mut timeout: Option<SteadyTime> = None;
            if let Some(ms) = initial_wait_ms {
                set_timeout(ms, &mut timeout);
            }
            loop {
                if let Some(go_time) = timeout {
                    if go_time >= SteadyTime::now() {
                        match self.spec.handle_timeout(&otx, &mut state) {
                            HandleResult::Stop(reason, None) => return shutdown(reason, None, &otx),
                            HandleResult::NoReply(Some(0)) => {
                                set_timeout(0, &mut timeout);
                                continue;
                            },
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            hr => panic!("unexpected `HandleResult` returned from handle_timeout: {:?}", hr),
                        }
                    }
                }
                match irx.try_recv() {
                    Ok(Message::Call(msg)) => {
                        match self.spec.handle_call(msg, &otx, &itx, &mut state) {
                            HandleResult::Reply(msg, new_timeout) => {
                                try!(otx.send(Message::Reply(msg)));
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            HandleResult::Stop(reason, reply) => return shutdown(reason, reply, &otx),
                        }
                    },
                    Ok(Message::Cast(msg)) => {
                        match self.spec.handle_cast(msg, &otx, &mut state) {
                            HandleResult::Stop(reason, reply) => return shutdown(reason, reply, &otx),
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            hr => panic!("unexpected `HandleResult` returned from handle_cast: {:?}", hr),
                        }
                    },
                    Ok(Message::Info(msg)) => {
                        match self.spec.handle_info(msg, &otx, &mut state) {
                            HandleResult::Stop(reason, reply) => return shutdown(reason, reply, &otx),
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            hr => panic!("unexpected `HandleResult` returned from handle_info: {:?}", hr),
                        }
                    },
                    Ok(hr) => panic!("received unexpected message type: {:?}", hr),
                    Err(TryRecvError::Disconnected) => { break; },
                    Err(TryRecvError::Empty) => { },
                }
            }
            Ok(())
        }).unwrap();
        Ok(Actor::new(itx2, orx, handle, name))
    }
}

#[derive(Debug)]
pub enum ActorError {
    InitFailure(String),
    AbnormalShutdown(String),
    SendError,
    RecvError,
}

impl<T: Any + Send> From<mpsc::SendError<Message<T>>> for ActorError {
    fn from(_err: mpsc::SendError<Message<T>>) -> Self {
        ActorError::SendError
    }
}

impl From<mpsc::RecvError> for ActorError {
    fn from(_err: mpsc::RecvError) -> Self {
        ActorError::RecvError
    }
}

#[derive(Debug)]
pub enum StopReason {
    Normal,
    Fatal(String),
}

#[derive(Debug)]
pub enum HandleResult<T> where T: Any + Send {
    Reply(T, Option<u64>),
    NoReply(Option<u64>),
    Stop(StopReason, Option<T>),
}

pub enum Message<T> where T: Any + Send {
    Call(T),
    Cast(T),
    Info(T),
    Reply(T),
}

impl<T> Debug for Message<T> where T: Any + Send + Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Message::Call(ref msg) => write!(f, "CALL: {:?}", msg),
            &Message::Cast(ref msg) => write!(f, "CAST: {:?}", msg),
            &Message::Info(ref msg) => write!(f, "INFO: {:?}", msg),
            &Message::Reply(ref msg) => write!(f, "REPLY: {:?}", msg)
        }
    }
}

pub trait GenServer : Send + 'static {
    type T: Send + Any + Debug;
    type S: Send + Any;
    type E: Error + 'static;

    fn init(&self, _tx: &Sender<Message<Self::T>>, state: &mut Self::S) -> InitResult<Self::E>;

    fn handle_call(&self, _message: Self::T, _tx: &Sender<Message<Self::T>>, _caller: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        panic!("handle_call callback not implemented");
    }
    fn handle_cast(&self, _message: Self::T, _tx: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        panic!("handle_cast callback not implemented");
    }
    fn handle_info(&self, _message: Self::T, _tx: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        HandleResult::NoReply(None)
    }
    fn handle_timeout(&self, _tx: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        HandleResult::NoReply(None)
    }
}

fn set_timeout(wait_ms: u64, current_timeout: &mut Option<SteadyTime>) {
    *current_timeout = Some(SteadyTime::now() + Duration::milliseconds(wait_ms as i64));
}

fn shutdown<T: Any + Send>(reason: StopReason, reply: Option<T>, sender: &Sender<Message<T>>) -> Result<(), ActorError> {
    if let Some(msg) = reply {
        let _result = sender.send(Message::Reply(msg));
    }
    match reason {
        StopReason::Normal => Ok(()),
        StopReason::Fatal(e) => Err(ActorError::AbnormalShutdown(e)),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fmt;
    use std::error::Error;
    use std::sync::mpsc::Sender;

    struct Worker;

    struct MyState {
        pub initialized: bool,
    }

    impl MyState {
        pub fn new() -> Self {
            MyState {
                initialized: false,
            }
        }
    }

    #[derive(Debug)]
    enum MyError {
        DirtyState,
    }

    #[derive(Debug)]
    enum MyMessage {
        Ok,
        Stop,
        State(bool),
        GetState,
        SetState(bool),
    }

    impl GenServer for Worker {
        type T = MyMessage;
        type S = MyState;
        type E = MyError;

        fn init(&self, _tx: &Sender<Message<Self::T>>, state: &mut Self::S) -> InitResult<Self::E> {
            if state.initialized {
                Err(MyError::DirtyState)
            } else {
                state.initialized = true;
                Ok(None)
            }
        }

        fn handle_call(&self, msg: Self::T, _: &Sender<Message<Self::T>>, _: &Sender<Message<Self::T>>, state: &mut Self::S) -> HandleResult<Self::T> {
            match msg {
                MyMessage::Stop => HandleResult::Stop(StopReason::Normal, Some(MyMessage::Ok)),
                MyMessage::GetState => HandleResult::Reply(MyMessage::State(state.initialized), None),
                MyMessage::SetState(value) => {
                    state.initialized = value;
                    HandleResult::Reply(MyMessage::Ok, None)
                }
                _ => HandleResult::Stop(StopReason::Fatal(String::from("Nope")), None),
            }
        }

        fn handle_cast(&self, msg: Self::T, _: &Sender<Message<Self::T>>, state: &mut Self::S) -> HandleResult<Self::T> {
            match msg {
                MyMessage::SetState(value) => {
                    state.initialized = value;
                    HandleResult::NoReply(None)
                },
                _ => HandleResult::NoReply(None)
            }
        }
    }

    impl fmt::Display for MyError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            match *self {
                MyError::DirtyState => write!(f, "state already initialized"),
            }
        }
    }

    impl Error for MyError {
        fn description(&self) -> &str {
            match *self {
                MyError::DirtyState => "state already initialized"
            }
        }
    }

    #[test]
    fn error_on_init() {
        let mut state = MyState::new();
        state.initialized = true;
        match Builder::new(Worker).start(state) {
            Err(MyError::DirtyState) => assert!(true),
            Ok(_) => assert!(false),
        }
    }

    #[test]
    fn call_set_get_state() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        match actor.call(MyMessage::GetState) {
            Ok(MyMessage::State(true)) => assert!(true),
            _ => assert!(false),
        }
        assert!(actor.call(MyMessage::SetState(false)).is_ok());
        match actor.call(MyMessage::GetState) {
            Ok(MyMessage::State(false)) => assert!(true),
            _ => assert!(false),
        }
    }

    #[test]
    fn multiple_cast_and_call_ordered() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        assert!(actor.cast(MyMessage::SetState(false)).is_ok());
        assert!(actor.cast(MyMessage::SetState(true)).is_ok());
        assert!(actor.cast(MyMessage::SetState(false)).is_ok());
        match actor.call(MyMessage::GetState) {
            Ok(MyMessage::State(result)) => assert_eq!(result, false),
            _ => assert!(false),
        }
    }

    #[test]
    fn stopping_an_actor() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        match actor.call(MyMessage::Stop) {
            Ok(MyMessage::Ok) => assert!(true),
            _ => assert!(false),
        }
        match actor.handle.join() {
            Ok(_) => assert!(true),
            Err(_) => assert!(false),
        }
    }

    #[test]
    fn explicitly_naming_actor() {
        let state = MyState::new();
        let actor = Builder::new(Worker).name("batman".to_string()).start(state).unwrap();
        assert!(actor.name.is_some());
        assert_eq!(actor.name.unwrap(), "batman".to_string());
    }

    #[test]
    fn default_named_actor() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        assert!(actor.name.is_none());
    }
}
<commit_msg>return ActorResult alias on callbacks instead of raw Result<commit_after>use std::any::Any;
use std::error::Error;
use std::fmt;
use std::fmt::Debug;
use std::result;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver, TryRecvError, RecvError, SendError};
use std::thread;

use time::{Duration, SteadyTime};

pub type InitResult<E> = result::Result<Option<u64>, E>;
pub type ActorResult<T> = result::Result<T, ActorError>;
pub type StartResult<T, E> = result::Result<Actor<T>, E>;

pub struct Actor<T> where T: Any + Send {
    pub sender: Sender<Message<T>>,
    pub receiver: Receiver<Message<T>>,
    pub handle: thread::JoinHandle<ActorResult<()>>,
    pub name: Option<String>,
}

impl<T> Actor<T> where T: Any + Send {
    /// Create a new actor handler struct.
    pub fn new(sender: Sender<Message<T>>, receiver: Receiver<Message<T>>,
        handle: thread::JoinHandle<ActorResult<()>>, name: Option<String>) -> Self {
        Actor {
            sender: sender,
            receiver: receiver,
            handle: handle,
            name: name,
        }
    }

    pub fn cast(&self, message: T) -> ActorResult<()> {
        self::cast(&self.sender, message)
    }

    pub fn call(&self, message: T) -> ActorResult<T> {
        self::call(&self.sender, &self.receiver, message)
    }
}

pub fn cast<T: Any + Send>(tx: &Sender<Message<T>>, message: T) -> ActorResult<()> {
    match tx.send(Message::Cast(message)) {
        Ok(()) => Ok(()),
        Err(err) => Err(ActorError::from(err)),
    }
}

pub fn call<T: Any + Send>(tx: &Sender<Message<T>>, rx: &Receiver<Message<T>>, message: T) -> ActorResult<T> {
    match tx.send(Message::Call(message)) {
        Ok(()) => {
            match rx.recv() {
                Ok(Message::Reply(msg)) => Ok(msg),
                Ok(_) => panic!("must reply from a call!"),
                Err(err) => Err(ActorError::from(err)),
            }
        },
        Err(err) => Err(ActorError::from(err)),
    }
}

pub struct Builder<T: GenServer> {
    name: Option<String>,
    spec: T,
}

impl<A: GenServer> Builder<A> {
    pub fn new(spec: A) -> Self {
        Builder {
            name: None,
            spec: spec,
        }
    }

    pub fn name(mut self, name: String) -> Builder<A> {
        self.name = Some(name);
        self
    }

    /// Start an actor on a new thread and return an Actor.
    pub fn start(self, mut state: A::S) -> StartResult<A::T, A::E> {
        let (otx, orx) = mpsc::channel::<Message<A::T>>();
        let (itx, irx) = mpsc::channel::<Message<A::T>>();
        let initial_wait_ms = match self.spec.init(&itx, &mut state) {
            Ok(result) => result,
            Err(err) => return Err(err),
        };
        let itx2 = itx.clone(); // clone inner receive loop's sender for actor struct
        let name = self.name.clone();
        let thread_name = name.clone().unwrap_or("GenServer".to_string());
        let handle = thread::Builder::new().name(thread_name.clone()).spawn(move || {
            let mut timeout: Option<SteadyTime> = None;
            if let Some(ms) = initial_wait_ms {
                set_timeout(ms, &mut timeout);
            }
            loop {
                if let Some(go_time) = timeout {
                    if go_time >= SteadyTime::now() {
                        match self.spec.handle_timeout(&otx, &mut state) {
                            HandleResult::Stop(reason, None) => return shutdown(reason, None, &otx),
                            HandleResult::NoReply(Some(0)) => {
                                set_timeout(0, &mut timeout);
                                continue;
                            },
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            hr => panic!("unexpected `HandleResult` returned from handle_timeout: {:?}", hr),
                        }
                    }
                }
                match irx.try_recv() {
                    Ok(Message::Call(msg)) => {
                        match self.spec.handle_call(msg, &otx, &itx, &mut state) {
                            HandleResult::Reply(msg, new_timeout) => {
                                try!(otx.send(Message::Reply(msg)));
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            HandleResult::Stop(reason, reply) => return shutdown(reason, reply, &otx),
                        }
                    },
                    Ok(Message::Cast(msg)) => {
                        match self.spec.handle_cast(msg, &otx, &mut state) {
                            HandleResult::Stop(reason, reply) => return shutdown(reason, reply, &otx),
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            hr => panic!("unexpected `HandleResult` returned from handle_cast: {:?}", hr),
                        }
                    },
                    Ok(Message::Info(msg)) => {
                        match self.spec.handle_info(msg, &otx, &mut state) {
                            HandleResult::Stop(reason, reply) => return shutdown(reason, reply, &otx),
                            HandleResult::NoReply(new_timeout) => {
                                if let Some(ms) = new_timeout {
                                    set_timeout(ms, &mut timeout);
                                }
                            },
                            hr => panic!("unexpected `HandleResult` returned from handle_info: {:?}", hr),
                        }
                    },
                    Ok(hr) => panic!("received unexpected message type: {:?}", hr),
                    Err(TryRecvError::Disconnected) => { break; },
                    Err(TryRecvError::Empty) => { },
                }
            }
            Ok(())
        }).unwrap();
        Ok(Actor::new(itx2, orx, handle, name))
    }
}

#[derive(Debug)]
pub enum ActorError {
    InitFailure(String),
    AbnormalShutdown(String),
    SendError,
    RecvError,
}

impl<T: Any + Send> From<mpsc::SendError<Message<T>>> for ActorError {
    fn from(_err: mpsc::SendError<Message<T>>) -> Self {
        ActorError::SendError
    }
}

impl From<mpsc::RecvError> for ActorError {
    fn from(_err: mpsc::RecvError) -> Self {
        ActorError::RecvError
    }
}

#[derive(Debug)]
pub enum StopReason {
    Normal,
    Fatal(String),
}

#[derive(Debug)]
pub enum HandleResult<T> where T: Any + Send {
    Reply(T, Option<u64>),
    NoReply(Option<u64>),
    Stop(StopReason, Option<T>),
}

pub enum Message<T> where T: Any + Send {
    Call(T),
    Cast(T),
    Info(T),
    Reply(T),
}

impl<T> Debug for Message<T> where T: Any + Send + Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Message::Call(ref msg) => write!(f, "CALL: {:?}", msg),
            &Message::Cast(ref msg) => write!(f, "CAST: {:?}", msg),
            &Message::Info(ref msg) => write!(f, "INFO: {:?}", msg),
            &Message::Reply(ref msg) => write!(f, "REPLY: {:?}", msg)
        }
    }
}

pub trait GenServer : Send + 'static {
    type T: Send + Any + Debug;
    type S: Send + Any;
    type E: Error + 'static;

    fn init(&self, _tx: &Sender<Message<Self::T>>, state: &mut Self::S) -> InitResult<Self::E>;

    fn handle_call(&self, _message: Self::T, _tx: &Sender<Message<Self::T>>, _caller: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        panic!("handle_call callback not implemented");
    }
    fn handle_cast(&self, _message: Self::T, _tx: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        panic!("handle_cast callback not implemented");
    }
    fn handle_info(&self, _message: Self::T, _tx: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        HandleResult::NoReply(None)
    }
    fn handle_timeout(&self, _tx: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        HandleResult::NoReply(None)
    }
}

fn set_timeout(wait_ms: u64, current_timeout: &mut Option<SteadyTime>) {
    *current_timeout = Some(SteadyTime::now() + Duration::milliseconds(wait_ms as i64));
}

fn shutdown<T: Any + Send>(reason: StopReason, reply: Option<T>, sender: &Sender<Message<T>>) -> Result<(), ActorError> {
    if let Some(msg) = reply {
        let _result = sender.send(Message::Reply(msg));
    }
    match reason {
        StopReason::Normal => Ok(()),
        StopReason::Fatal(e) => Err(ActorError::AbnormalShutdown(e)),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fmt;
    use std::error::Error;
    use std::sync::mpsc::Sender;

    struct Worker;

    struct MyState {
        pub initialized: bool,
    }

    impl MyState {
        pub fn new() -> Self {
            MyState {
                initialized: false,
            }
        }
    }

    #[derive(Debug)]
    enum MyError {
        DirtyState,
    }

    #[derive(Debug)]
    enum MyMessage {
        Ok,
        Stop,
        State(bool),
        GetState,
        SetState(bool),
    }

    impl GenServer for Worker {
        type T = MyMessage;
        type S = MyState;
        type E = MyError;

        fn init(&self, _tx: &Sender<Message<Self::T>>, state: &mut Self::S) -> InitResult<Self::E> {
            if state.initialized {
                Err(MyError::DirtyState)
            } else {
                state.initialized = true;
                Ok(None)
            }
        }

        fn handle_call(&self, msg: Self::T, _: &Sender<Message<Self::T>>, _: &Sender<Message<Self::T>>, state: &mut Self::S) -> HandleResult<Self::T> {
            match msg {
                MyMessage::Stop => HandleResult::Stop(StopReason::Normal, Some(MyMessage::Ok)),
                MyMessage::GetState => HandleResult::Reply(MyMessage::State(state.initialized), None),
                MyMessage::SetState(value) => {
                    state.initialized = value;
                    HandleResult::Reply(MyMessage::Ok, None)
                }
                _ => HandleResult::Stop(StopReason::Fatal(String::from("Nope")), None),
            }
        }

        fn handle_cast(&self, msg: Self::T, _: &Sender<Message<Self::T>>, state: &mut Self::S) -> HandleResult<Self::T> {
            match msg {
                MyMessage::SetState(value) => {
                    state.initialized = value;
                    HandleResult::NoReply(None)
                },
                _ => HandleResult::NoReply(None)
            }
        }
    }

    impl fmt::Display for MyError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            match *self {
                MyError::DirtyState => write!(f, "state already initialized"),
            }
        }
    }

    impl Error for MyError {
        fn description(&self) -> &str {
            match *self {
                MyError::DirtyState => "state already initialized"
            }
        }
    }

    #[test]
    fn error_on_init() {
        let mut state = MyState::new();
        state.initialized = true;
        match Builder::new(Worker).start(state) {
            Err(MyError::DirtyState) => assert!(true),
            Ok(_) => assert!(false),
        }
    }

    #[test]
    fn call_set_get_state() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        match actor.call(MyMessage::GetState) {
            Ok(MyMessage::State(true)) => assert!(true),
            _ => assert!(false),
        }
        assert!(actor.call(MyMessage::SetState(false)).is_ok());
        match actor.call(MyMessage::GetState) {
            Ok(MyMessage::State(false)) => assert!(true),
            _ => assert!(false),
        }
    }

    #[test]
    fn multiple_cast_and_call_ordered() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        assert!(actor.cast(MyMessage::SetState(false)).is_ok());
        assert!(actor.cast(MyMessage::SetState(true)).is_ok());
        assert!(actor.cast(MyMessage::SetState(false)).is_ok());
        match actor.call(MyMessage::GetState) {
            Ok(MyMessage::State(result)) => assert_eq!(result, false),
            _ => assert!(false),
        }
    }

    #[test]
    fn stopping_an_actor() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        match actor.call(MyMessage::Stop) {
            Ok(MyMessage::Ok) => assert!(true),
            _ => assert!(false),
        }
        match actor.handle.join() {
            Ok(_) => assert!(true),
            Err(_) => assert!(false),
        }
    }

    #[test]
    fn explicitly_naming_actor() {
        let state = MyState::new();
        let actor = Builder::new(Worker).name("batman".to_string()).start(state).unwrap();
        assert!(actor.name.is_some());
        assert_eq!(actor.name.unwrap(), "batman".to_string());
    }

    #[test]
    fn default_named_actor() {
        let state = MyState::new();
        let actor = Builder::new(Worker).start(state).unwrap();
        assert!(actor.name.is_none());
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std;
use std::mem;
use libc::c_char;

use rparser::*;

use ipsec_parser::*;
use num_traits::cast::FromPrimitive;

use nom::IResult;

pub struct IPsecParser<'a> {
    _name: Option<&'a[u8]>,

    pub client_proposals : Vec<IkeV2Transform>,

    pub dh_group: Option<IkeTransformDHType>,
}

impl<'a> RParser for IPsecParser<'a> {
    fn parse(&mut self, i: &[u8], _direction: u8) -> u32 {
        match parse_ikev2_header(i) {
            IResult::Done(rem,ref hdr) => {
                debug!("parse_ikev2_header: {:?}",hdr);
                if rem.len() == 0 && hdr.length == 28 {
                    return R_STATUS_OK;
                }
                match parse_ikev2_payload_list(rem,hdr.next_payload) {
                    IResult::Done(_,Ok(ref p)) => {
                        debug!("parse_ikev2_payload_with_type: {:?}",p);
                        for payload in p {
                            match payload.content {
                                IkeV2PayloadContent::SA(ref prop) => {
                                    if hdr.flags & IKEV2_FLAG_INITIATOR != 0 {
                                        self.add_client_proposals(prop);
                                    }
                                },
                                IkeV2PayloadContent::KE(ref kex) => {
                                    self.dh_group = IkeTransformDHType::from_u16(kex.dh_group);
                                    // XXX if self.dh_group == None, raise decoder event
                                    debug!("KEX {}/{:?}", kex.dh_group, self.dh_group);
                                },
                                IkeV2PayloadContent::Nonce(ref n) => {
                                    debug!("Nonce: {:?}", n);
                                },
                                IkeV2PayloadContent::Notify(ref n) => {
                                    debug!("Notify: {:?}", n);
                                },
                                _ => {
                                    debug!("Unknown payload content {:?}", payload.content);
                                },
                            }
                        }
                    },
                    e @ _ => warn!("parse_ikev2_payload_with_type: {:?}",e),
                };
            },
            e @ _ => warn!("parse_ikev2_header: {:?}",e),
        };
        R_STATUS_OK
    }
}

impl<'a> IPsecParser<'a> {
    pub fn new(name: &'a[u8]) -> IPsecParser<'a> {
        IPsecParser{
            _name: Some(name),
            client_proposals: Vec::new(),
            dh_group: None,
        }
    }

    fn add_client_proposals(&mut self, prop: &Vec<IkeV2Proposal>) {
        debug!("num_proposals: {}",prop.len());
        for ref p in prop {
            debug!("proposal: {:?}",p);
            debug!("num_transforms: {}",p.num_transforms);
            for ref xform in &p.transforms {
                debug!("transform: {:?}",xform);
                let xty = IkeTransformType::from_u8(xform.transform_type);
                debug!("\ttype: {:?} / {}",xty,xform.transform_type);
                match xty {
                    Some(IkeTransformType::EncryptionAlgorithm) => {
                        debug!("\tEncryptionAlgorithm: {:?}",IkeTransformEncType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::PseudoRandomFunction) => {
                        debug!("\tPseudoRandomFunction: {:?}",IkeTransformPRFType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::IntegrityAlgorithm) => {
                        debug!("\tIntegrityAlgorithm: {:?}",IkeTransformAuthType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::DiffieHellmanGroup) => {
                        debug!("\tDiffieHellmanGroup: {:?}",IkeTransformDHType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::ExtendedSequenceNumbers) => {
                        debug!("\tExtendedSequenceNumbers: {:?}",IkeTransformESNType::from_u16(xform.transform_id));
                    },
                    _ => warn!("\tUnknown transform type {}",xform.transform_type),
                }
                if xform.transform_id == 0 {
                    warn!("\tTransform ID == 0 (choice left to responder)");
                };
            }
            let client_proposals : Vec<IkeV2Transform> = p.transforms.iter().map(|x| x.into()).collect();
            debug!("Client proposals\n{:?}",client_proposals);
            // Rule 1: warn on weak or unknown transforms
            for prop in &client_proposals {
                match prop {
                    &IkeV2Transform::Encryption(ref enc) => {
                        match enc {
                            &IkeTransformEncType::DesIV64 |
                            &IkeTransformEncType::Des |
                            &IkeTransformEncType::TripleDes |
                            &IkeTransformEncType::Rc5 |
                            &IkeTransformEncType::Idea |
                            &IkeTransformEncType::Cast |
                            &IkeTransformEncType::Blowfish |
                            &IkeTransformEncType::TripleIdea |
                            &IkeTransformEncType::DesIV32 |
                            &IkeTransformEncType::Null => {
                                warn!("Weak Encryption: {:?}", enc);
                            },
                            _ => (),
                        }
                    },
                    &IkeV2Transform::DH(ref dh) => {
                        match dh {
                            &IkeTransformDHType::None => {
                                warn!("'None' DH transform proposed");
                            },
                            &IkeTransformDHType::Modp768 |
                            &IkeTransformDHType::Modp1024 |
                            &IkeTransformDHType::Modp1024s160 => {
                                warn!("Weak DH: {:?}", dh);
                            },
                            _ => (),
                        }
                    },
                    &IkeV2Transform::Unknown(tx_type,tx_id) => {
                        warn!("Unknown proposal: type={}, id={}", tx_type, tx_id);
                    },
                    _ => (),
                }
            }
            // Rule 2: check if no DH was proposed
            if ! client_proposals.iter().any(|x| {
                if let &IkeV2Transform::DH(_) = x { true } else { false }
            })
            {
                warn!("No DH transform found");
            }
            // finally
            self.client_proposals = client_proposals;
        }
    }
}

fn ipsec_probe(i: &[u8]) -> bool {
    if i.len() <= 2 { return false; }
    true
}

r_declare_state_new!(r_ipsec_state_new,IPsecParser,b"IPsec state");
r_declare_state_free!(r_ipsec_state_free,IPsecParser,{ () });

r_implement_probe!(r_ipsec_probe,ipsec_probe);
r_implement_parse!(r_ipsec_parse,IPsecParser);

<commit_msg>IKEv2: check version, weak integrity, and if AH only is used<commit_after>extern crate libc;

use std;
use std::mem;
use libc::c_char;

use rparser::*;

use ipsec_parser::*;
use num_traits::cast::FromPrimitive;

use nom::IResult;

pub struct IPsecParser<'a> {
    _name: Option<&'a[u8]>,

    pub client_proposals : Vec<IkeV2Transform>,

    pub dh_group: Option<IkeTransformDHType>,
}

impl<'a> RParser for IPsecParser<'a> {
    fn parse(&mut self, i: &[u8], _direction: u8) -> u32 {
        match parse_ikev2_header(i) {
            IResult::Done(rem,ref hdr) => {
                debug!("parse_ikev2_header: {:?}",hdr);
                if rem.len() == 0 && hdr.length == 28 {
                    return R_STATUS_OK;
                }
                // Rule 0: check version
                if hdr.maj_ver != 2 || hdr.min_ver != 0 {
                    warn!("Unknown header version: {}.{}", hdr.maj_ver, hdr.min_ver);
                }
                match parse_ikev2_payload_list(rem,hdr.next_payload) {
                    IResult::Done(_,Ok(ref p)) => {
                        debug!("parse_ikev2_payload_with_type: {:?}",p);
                        for payload in p {
                            match payload.content {
                                IkeV2PayloadContent::SA(ref prop) => {
                                    if hdr.flags & IKEV2_FLAG_INITIATOR != 0 {
                                        self.add_client_proposals(prop);
                                    }
                                },
                                IkeV2PayloadContent::KE(ref kex) => {
                                    self.dh_group = IkeTransformDHType::from_u16(kex.dh_group);
                                    // XXX if self.dh_group == None, raise decoder event
                                    debug!("KEX {}/{:?}", kex.dh_group, self.dh_group);
                                },
                                IkeV2PayloadContent::Nonce(ref n) => {
                                    debug!("Nonce: {:?}", n);
                                },
                                IkeV2PayloadContent::Notify(ref n) => {
                                    debug!("Notify: {:?}", n);
                                },
                                _ => {
                                    debug!("Unknown payload content {:?}", payload.content);
                                },
                            }
                        }
                    },
                    e @ _ => warn!("parse_ikev2_payload_with_type: {:?}",e),
                };
            },
            e @ _ => warn!("parse_ikev2_header: {:?}",e),
        };
        R_STATUS_OK
    }
}

impl<'a> IPsecParser<'a> {
    pub fn new(name: &'a[u8]) -> IPsecParser<'a> {
        IPsecParser{
            _name: Some(name),
            client_proposals: Vec::new(),
            dh_group: None,
        }
    }

    fn add_client_proposals(&mut self, prop: &Vec<IkeV2Proposal>) {
        debug!("num_proposals: {}",prop.len());
        for ref p in prop {
            debug!("proposal: {:?}",p);
            debug!("num_transforms: {}",p.num_transforms);
            for ref xform in &p.transforms {
                debug!("transform: {:?}",xform);
                let xty = IkeTransformType::from_u8(xform.transform_type);
                debug!("\ttype: {:?} / {}",xty,xform.transform_type);
                match xty {
                    Some(IkeTransformType::EncryptionAlgorithm) => {
                        debug!("\tEncryptionAlgorithm: {:?}",IkeTransformEncType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::PseudoRandomFunction) => {
                        debug!("\tPseudoRandomFunction: {:?}",IkeTransformPRFType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::IntegrityAlgorithm) => {
                        debug!("\tIntegrityAlgorithm: {:?}",IkeTransformAuthType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::DiffieHellmanGroup) => {
                        debug!("\tDiffieHellmanGroup: {:?}",IkeTransformDHType::from_u16(xform.transform_id));
                    },
                    Some(IkeTransformType::ExtendedSequenceNumbers) => {
                        debug!("\tExtendedSequenceNumbers: {:?}",IkeTransformESNType::from_u16(xform.transform_id));
                    },
                    _ => warn!("\tUnknown transform type {}",xform.transform_type),
                }
                if xform.transform_id == 0 {
                    warn!("\tTransform ID == 0 (choice left to responder)");
                };
            }
            let client_proposals : Vec<IkeV2Transform> = p.transforms.iter().map(|x| x.into()).collect();
            debug!("Client proposals\n{:?}",client_proposals);
            // Rule 1: warn on weak or unknown transforms
            for prop in &client_proposals {
                match prop {
                    &IkeV2Transform::Encryption(ref enc) => {
                        match enc {
                            &IkeTransformEncType::DesIV64 |
                            &IkeTransformEncType::Des |
                            &IkeTransformEncType::TripleDes |
                            &IkeTransformEncType::Rc5 |
                            &IkeTransformEncType::Idea |
                            &IkeTransformEncType::Cast |
                            &IkeTransformEncType::Blowfish |
                            &IkeTransformEncType::TripleIdea |
                            &IkeTransformEncType::DesIV32 |
                            &IkeTransformEncType::Null => {
                                warn!("Weak Encryption: {:?}", enc);
                            },
                            _ => (),
                        }
                    },
                    &IkeV2Transform::Auth(ref auth) => {
                        match auth {
                            &IkeTransformAuthType::None => {
                                warn!("'None' Auth transform proposed");
                            },
                            &IkeTransformAuthType::HmacMd5s96 |
                            &IkeTransformAuthType::HmacSha1s96 |
                            &IkeTransformAuthType::DesMac |
                            &IkeTransformAuthType::KpdkMd5 |
                            &IkeTransformAuthType::AesXCBC96 |
                            &IkeTransformAuthType::HmacMd5s128 |
                            &IkeTransformAuthType::HmacMd5s160 => {
                                warn!("Weak auth: {:?}", auth);
                            },
                            _ => (),
                        }
                    },
                    &IkeV2Transform::DH(ref dh) => {
                        match dh {
                            &IkeTransformDHType::None => {
                                warn!("'None' DH transform proposed");
                            },
                            &IkeTransformDHType::Modp768 |
                            &IkeTransformDHType::Modp1024 |
                            &IkeTransformDHType::Modp1024s160 |
                            &IkeTransformDHType::Modp1536 => {
                                warn!("Weak DH: {:?}", dh);
                            },
                            _ => (),
                        }
                    },
                    &IkeV2Transform::Unknown(tx_type,tx_id) => {
                        warn!("Unknown proposal: type={}, id={}", tx_type, tx_id);
                    },
                    _ => (),
                }
            }
            // Rule 2: check if no DH was proposed
            if ! client_proposals.iter().any(|x| {
                if let &IkeV2Transform::DH(_) = x { true } else { false }
            })
            {
                warn!("No DH transform found");
            }
            // Rule 3: check if proposing AH ([RFC7296] section 3.3.1)
            if p.protocol_id == 2 {
                warn!("Proposal uses protocol AH - no confidentiality");
            }
            // finally
            self.client_proposals = client_proposals;
        }
    }
}

fn ipsec_probe(i: &[u8]) -> bool {
    if i.len() <= 2 { return false; }
    true
}

r_declare_state_new!(r_ipsec_state_new,IPsecParser,b"IPsec state");
r_declare_state_free!(r_ipsec_state_free,IPsecParser,{ () });

r_implement_probe!(r_ipsec_probe,ipsec_probe);
r_implement_parse!(r_ipsec_parse,IPsecParser);

<|endoftext|>


<commit_before>/*!
General Admin commands
*/
use std::env;

use clap::ArgMatches;
use migrant_lib::{self, Config};

use sweep;
use errors::*;

fn sweep_files() -> Result<()> {
    unimplemented!()
}

pub fn handle(matches: &ArgMatches) -> Result<()> {
    if let Some(db_matches) = matches.subcommand_matches("database") {
        let dir = env::current_dir()?;
        let config_path = match migrant_lib::search_for_config(&dir) {
            None => {
                Config::init_in(&dir)
                    .for_database(Some("postgres"))?
                    .initialize()?;
                match migrant_lib::search_for_config(&dir) {
                    None => bail!("Unable to find `.migrant.toml` even though it was just saved."),
                    Some(p) => p,
                }
            }
            Some(p) => p,
        };

        let config = Config::load_file_only(&config_path)?;

        if db_matches.is_present("setup") {
            config.setup()?;
            return Ok(())
        }

        // load applied migrations from the database
        let config = config.reload()?;

        match db_matches.subcommand() {
            ("shell", _) => {
                migrant_lib::shell(&config)?;
            }
            ("migrate", _) => {
                let res = migrant_lib::Migrator::with_config(&config)
                    .direction(migrant_lib::Direction::Up)
                    .all(true)
                    .apply();
                if let Err(ref err) = res {
                    if let migrant_lib::Error::MigrationComplete(_) = *err {
                        println!("Database is up-to-date!");
                        return Ok(());
                    }
                }
                let _ = res?;
                return Ok(())
            }
            _ => println!("see `--help`"),
        }

        return Ok(())
    }

    if let Some(_) = matches.subcommand_matches("sweep-files") {
        sweep_files()?;
        return Ok(())
    }

    println!("See: {} admin --help", super::APPNAME);
    Ok(())
}

<commit_msg>admin: file sweeping<commit_after>/*!
General Admin commands
*/
use std::env;

use clap::ArgMatches;
use migrant_lib::{self, Config};

use sweep;
use errors::*;

fn sweep_files() -> Result<()> {
    let dir = env::current_dir()?;
    let upload_dir = dir.join("uploads");
    if upload_dir.is_dir() && upload_dir.exists() {
        let n = sweep::sweep_fs(&upload_dir)?;
        info!("** Cleaned up {} orphaned files **", n);
    } else {
        bail!("Provided upload dir is invalid: {:?}", upload_dir);
    }
    Ok(())
}

pub fn handle(matches: &ArgMatches) -> Result<()> {
    if let Some(db_matches) = matches.subcommand_matches("database") {
        let dir = env::current_dir()?;
        let config_path = match migrant_lib::search_for_config(&dir) {
            None => {
                Config::init_in(&dir)
                    .for_database(Some("postgres"))?
                    .initialize()?;
                match migrant_lib::search_for_config(&dir) {
                    None => bail!("Unable to find `.migrant.toml` even though it was just saved."),
                    Some(p) => p,
                }
            }
            Some(p) => p,
        };

        let config = Config::load_file_only(&config_path)?;

        if db_matches.is_present("setup") {
            config.setup()?;
            return Ok(())
        }

        // load applied migrations from the database
        let config = config.reload()?;

        match db_matches.subcommand() {
            ("shell", _) => {
                migrant_lib::shell(&config)?;
            }
            ("migrate", _) => {
                let res = migrant_lib::Migrator::with_config(&config)
                    .direction(migrant_lib::Direction::Up)
                    .all(true)
                    .apply();
                if let Err(ref err) = res {
                    if let migrant_lib::Error::MigrationComplete(_) = *err {
                        println!("Database is up-to-date!");
                        return Ok(());
                    }
                }
                let _ = res?;
                return Ok(())
            }
            _ => println!("see `--help`"),
        }

        return Ok(())
    }

    if let Some(_) = matches.subcommand_matches("sweep-files") {
        sweep_files()?;
        return Ok(())
    }

    println!("See: {} admin --help", super::APPNAME);
    Ok(())
}

<|endoftext|>


<commit_before>use std::convert::TryInto;
use std::fmt::{Debug, Error, Formatter};

/// Maximum size of a [`Memory`](struct.Memory.html) block in
/// [`Word`](struct.Word.html)s
///
/// = 2^24
const MAX_MEM_SIZE: u32 = 16_777_216;

#[derive(Clone, Copy, Default)]
pub struct Word {
    val: [u8; 3],
}

impl Word {
    pub fn new() -> Self {
        Word { val: [0; 3] }
    }
}

impl Debug for Word {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.debug_struct("Word")
            .field("val", &format_args!("[{:?}, {:?}, {:?}]",
                                        &self.val[0],
                                        &self.val[1],
                                        &self.val[2]))
            .finish()
    }
}

#[derive(Debug)]
pub struct Memory {
    data: Vec<Word>,
    size: u32,
}

impl Memory {
    /// Creates a new `Memory` block of the given `size`.
    ///
    /// The maximum size of a `Memory` block is
    /// [`MAX_MEM_SIZE`](constant.MAX_MEM_SIZE.html). If `size` is greater
    /// than that, the created `Memory` block will be
    /// [`MAX_MEM_SIZE`](constant.MAX_MEM_SIZE.html) long.
    pub fn new(size: u32) -> Self {
        let size = if size > MAX_MEM_SIZE {
            MAX_MEM_SIZE
        } else {
            size
        };
        Memory { data: vec![Word::default(); size.try_into().unwrap()], size }
    }
}
<commit_msg>Word is little endian by index. Make Debug for Word read left to right.<commit_after>use std::convert::TryInto;
use std::fmt::{Debug, Error, Formatter};

/// Maximum size of a [`Memory`](struct.Memory.html) block in
/// [`Word`](struct.Word.html)s
///
/// = 2^24
const MAX_MEM_SIZE: u32 = 16_777_216;

#[derive(Clone, Copy, Default)]
pub struct Word {
    // little endian
    val: [u8; 3],
}

impl Word {
    pub fn new() -> Self {
        Word { val: [0; 3] }
    }
}

impl Debug for Word {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.debug_struct("Word")
            .field("val", &format_args!("[{:?}, {:?}, {:?}]",
                                        &self.val[2],
                                        &self.val[1],
                                        &self.val[0]))
            .finish()
    }
}

#[derive(Debug)]
pub struct Memory {
    data: Vec<Word>,
    size: u32,
}

impl Memory {
    /// Creates a new `Memory` block of the given `size`.
    ///
    /// The maximum size of a `Memory` block is
    /// [`MAX_MEM_SIZE`](constant.MAX_MEM_SIZE.html). If `size` is greater
    /// than that, the created `Memory` block will be
    /// [`MAX_MEM_SIZE`](constant.MAX_MEM_SIZE.html) long.
    pub fn new(size: u32) -> Self {
        let size = if size > MAX_MEM_SIZE {
            MAX_MEM_SIZE
        } else {
            size
        };
        Memory { data: vec![Word::default(); size.try_into().unwrap()], size }
    }
}
<|endoftext|>


<commit_before>use std::{mem, fmt, thread};
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use super::{Value, Error, Version, Id, SyncOutput, SyncResponse, Output, Success, Failure};

type Res = Result<Value, Error>;

pub struct AsyncResultHandler {
	result: Mutex<Option<Res>>,
	listeners: Mutex<Vec<Box<Fn() + Send>>>
}

impl fmt::Debug for AsyncResultHandler {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
		write!(
			formatter,
			"AsyncResult: {:?}, Listeners: {}",
			self.result,
			self.listeners.lock().unwrap().len()
		)
	}
}

impl AsyncResultHandler {
	pub fn new() -> Arc<Self> {
		Arc::new(AsyncResultHandler {
			result: Mutex::new(None),
			listeners: Mutex::new(Vec::new()),
		})
	}

	pub fn set_result(&self, res: Res) {
		{
			let mut result = self.result.lock().unwrap();
			*result = Some(res);
		}

		let listeners = {
			let mut listeners = self.listeners.lock().unwrap();
			mem::replace(&mut *listeners, Vec::new())
		};

		for on_result in listeners.into_iter() {
			on_result();
		}
	}

	pub fn on_result<F>(&self, f: F) where F: Fn() + Send + 'static {
		if self.result.lock().unwrap().is_some() {
			f();
		} else {
			self.listeners.lock().unwrap().push(Box::new(f));
		}
	}

	pub fn await(&self) -> Res {
		// Check if there is a result already
		{
			if let Some(ref res) = *self.result.lock().unwrap() {
				return res.clone();
			}
		}
		// Park the thread
		let current = thread::current();
		self.on_result(move || {
			current.unpark();
		});

		loop {
			if let Some(ref res) = *self.result.lock().unwrap() {
				return res.clone();
			}
			thread::park();
		}
	}

}

pub type AsyncResult = Arc<AsyncResultHandler>;

#[derive(Debug)]
pub struct AsyncOutput {
	result: AsyncResult,
	id: Id,
	jsonrpc: Version,
}

impl AsyncOutput {
	pub fn await(self) -> SyncOutput {
		let result = self.result.await();
		SyncOutput::from(result, self.id, self.jsonrpc)
	}

	pub fn on_result<F>(&self, f: F) where F: Fn() + Send + 'static {
		self.result.on_result(f)
	}

	pub fn from(result: AsyncResult, id: Id, jsonrpc: Version) -> Self {
		AsyncOutput {
			result: result,
			id: id,
			jsonrpc: jsonrpc,
		}
	}
}

#[derive(Debug)]
pub enum Response {
	Single(Output),
	Batch(Vec<Output>),
}

impl Response {
	pub fn on_result<F>(&self, f: F) where F: Fn() + Send + Sync + 'static {
		match *self {
			Response::Single(Output::Sync(_)) => {
				f();
			},
			Response::Single(Output::Async(ref output)) => {
				output.on_result(f);
			},
			Response::Batch(ref outputs) => {
				let mut async = true;
				let callback = Arc::new(f);
				let count = Arc::new(AtomicUsize::new(0));
				for output in outputs {
					if let Output::Async(ref output) = *output {
						async = true;
						count.fetch_add(1, Ordering::Relaxed);

						let count = count.clone();
						let callback = callback.clone();
						output.on_result(move || {
							let res = count.fetch_sub(1, Ordering::Relaxed);
							// Last output resolved
							if res == 1 {
								callback();
								return;
							}
						});
					}
				}
				if !async {
					callback()
				}
			}
		}
	}

	pub fn await(self) -> SyncResponse {
		match self {
			Response::Single(Output::Sync(output)) => SyncResponse::Single(output),
			Response::Single(Output::Async(output)) => SyncResponse::Single(output.await()),
			Response::Batch(outputs) => {
				let mut res = Vec::new();
				for output in outputs.into_iter() {
					match output {
						// unwrap sync responses
						Output::Sync(output) => res.push(output),
						// await response
						Output::Async(output) => res.push(output.await()),
					};
				}
				SyncResponse::Batch(res)
			},
		}
	}
}

impl From<Failure> for Response {
	fn from(res: Failure) -> Self {
		Response::Single(Output::Sync(SyncOutput::Failure(res)))
	}
}

impl From<Success> for Response {
	fn from(res: Success) -> Self {
		Response::Single(Output::Sync(SyncOutput::Success(res)))
	}
}

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

	#[test]
	fn should_wait_for_all_results_in_batch() {
		// given
		let res1 = AsyncResultHandler::new();
		let res2 = AsyncResultHandler::new();
		let output1 = AsyncOutput::from(res1.clone(), Id::Null, Version::V2);
		let output2 = AsyncOutput::from(res2.clone(), Id::Null, Version::V2);

		let response = Response::Batch(vec![Output::Async(output1), Output::Async(output2)]);
		let val = Arc::new(AtomicBool::new(false));
		let v = val.clone();
		response.on_result(move || { v.store(true, Ordering::Relaxed) });
		assert_eq!(val.load(Ordering::Relaxed), false);

		// when
		// resolve first
		res1.set_result(Ok(Value::U64(1)));
		assert_eq!(val.load(Ordering::Relaxed), false);
		// resolve second
		res2.set_result(Ok(Value::U64(2)));
		assert_eq!(val.load(Ordering::Relaxed), true);

		// then
		assert_eq!(response.await(), SyncResponse::Batch(vec![
			SyncOutput::Success(Success { result: Value::U64(1), id: Id::Null, jsonrpc: Version::V2 }),
			SyncOutput::Success(Success { result: Value::U64(2), id: Id::Null, jsonrpc: Version::V2 }),
		]));
	}

	#[test]
	fn should_call_on_result_if_available() {
		let res = AsyncResultHandler::new();
		let output = AsyncOutput::from(res.clone(), Id::Null, Version::V2);
		res.set_result(Ok(Value::String("hello".into())));

		let val = Arc::new(AtomicBool::new(false));
		let v = val.clone();
		res.on_result(move || { v.store(true, Ordering::Relaxed) });

		assert_eq!(val.load(Ordering::Relaxed), true);
	}

	#[test]
	fn should_wait_for_output() {
		let res = AsyncResultHandler::new();
		let output = AsyncOutput::from(res.clone(), Id::Null, Version::V2);
		thread::spawn(move || {
			res.set_result(Ok(Value::String("hello".into())));
		});
		assert_eq!(output.await(), SyncOutput::Success(Success {
			id: Id::Null,
			jsonrpc: Version::V2,
			result: Value::String("hello".into()),
		}));
	}

	#[test]
	fn should_return_output_if_available() {
		let res = AsyncResultHandler::new();
		let output = AsyncOutput::from(res.clone(), Id::Null, Version::V2);
		res.set_result(Ok(Value::String("hello".into())));

		assert_eq!(output.await(), SyncOutput::Success(Success {
			id: Id::Null,
			jsonrpc: Version::V2,
			result: Value::String("hello".into()),
		}));
	}
}
<commit_msg>Return from on_result<commit_after>use std::{mem, fmt, thread};
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use super::{Value, Error, Version, Id, SyncOutput, SyncResponse, Output, Success, Failure};

type Res = Result<Value, Error>;

pub struct AsyncResultHandler {
	result: Mutex<Option<Res>>,
	listeners: Mutex<Vec<Box<Fn() + Send>>>
}

impl fmt::Debug for AsyncResultHandler {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
		write!(
			formatter,
			"AsyncResult: {:?}, Listeners: {}",
			self.result,
			self.listeners.lock().unwrap().len()
		)
	}
}

impl AsyncResultHandler {
	pub fn new() -> Arc<Self> {
		Arc::new(AsyncResultHandler {
			result: Mutex::new(None),
			listeners: Mutex::new(Vec::new()),
		})
	}

	pub fn set_result(&self, res: Res) {
		{
			let mut result = self.result.lock().unwrap();
			*result = Some(res);
		}

		let listeners = {
			let mut listeners = self.listeners.lock().unwrap();
			mem::replace(&mut *listeners, Vec::new())
		};

		for on_result in listeners.into_iter() {
			on_result();
		}
	}

	/// Adds closure to be invoked when result is available.
	/// Callback is invoked right away if result is instantly available and `true` is returned.
	/// `false` is returned when listener has been added
	pub fn on_result<F>(&self, f: F) -> bool where F: Fn() + Send + 'static {
		if self.result.lock().unwrap().is_some() {
			f();
			true
		} else {
			self.listeners.lock().unwrap().push(Box::new(f));
			false
		}
	}

	pub fn await(&self) -> Res {
		// Check if there is a result already
		{
			if let Some(ref res) = *self.result.lock().unwrap() {
				return res.clone();
			}
		}
		// Park the thread
		let current = thread::current();
		self.on_result(move || {
			current.unpark();
		});

		loop {
			if let Some(ref res) = *self.result.lock().unwrap() {
				return res.clone();
			}
			thread::park();
		}
	}

}

pub type AsyncResult = Arc<AsyncResultHandler>;

#[derive(Debug)]
pub struct AsyncOutput {
	result: AsyncResult,
	id: Id,
	jsonrpc: Version,
}

impl AsyncOutput {
	pub fn await(self) -> SyncOutput {
		let result = self.result.await();
		SyncOutput::from(result, self.id, self.jsonrpc)
	}

	/// Adds closure to be invoked when result is available.
	/// Callback is invoked right away if result is instantly available and `true` is returned.
	/// `false` is returned when listener has been added
	pub fn on_result<F>(&self, f: F) -> bool where F: Fn() + Send + 'static {
		self.result.on_result(f)
	}

	pub fn from(result: AsyncResult, id: Id, jsonrpc: Version) -> Self {
		AsyncOutput {
			result: result,
			id: id,
			jsonrpc: jsonrpc,
		}
	}
}

#[derive(Debug)]
pub enum Response {
	Single(Output),
	Batch(Vec<Output>),
}

impl Response {
	/// Adds closure to be invoked when result is available.
	/// Callback is invoked right away if result is instantly available and `true` is returned.
	/// `false` is returned when listener has been added
	pub fn on_result<F>(&self, f: F) -> bool where F: Fn() + Send + Sync + 'static {
		match *self {
			Response::Single(Output::Sync(_)) => {
				f();
				true
			},
			Response::Single(Output::Async(ref output)) => {
				output.on_result(f)
			},
			Response::Batch(ref outputs) => {
				let mut async = true;
				let callback = Arc::new(f);
				let count = Arc::new(AtomicUsize::new(0));

				for output in outputs {
					if let Output::Async(ref output) = *output {
						async = true;
						count.fetch_add(1, Ordering::Relaxed);

						let count = count.clone();
						let callback = callback.clone();
						output.on_result(move || {
							let res = count.fetch_sub(1, Ordering::Relaxed);
							// Last output resolved
							if res == 1 {
								callback();
							}
						});
					}
				}

				// If there are no async calls just fire callback
				if !async {
					callback();
					true
				} else {
					// if all async calls were already available
					count.load(Ordering::Relaxed) == 0
				}
			}
		}
	}

	pub fn await(self) -> SyncResponse {
		match self {
			Response::Single(Output::Sync(output)) => SyncResponse::Single(output),
			Response::Single(Output::Async(output)) => SyncResponse::Single(output.await()),
			Response::Batch(outputs) => {
				let mut res = Vec::new();
				for output in outputs.into_iter() {
					match output {
						// unwrap sync responses
						Output::Sync(output) => res.push(output),
						// await response
						Output::Async(output) => res.push(output.await()),
					};
				}
				SyncResponse::Batch(res)
			},
		}
	}
}

impl From<Failure> for Response {
	fn from(res: Failure) -> Self {
		Response::Single(Output::Sync(SyncOutput::Failure(res)))
	}
}

impl From<Success> for Response {
	fn from(res: Success) -> Self {
		Response::Single(Output::Sync(SyncOutput::Success(res)))
	}
}

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

	#[test]
	fn should_wait_for_all_results_in_batch() {
		// given
		let res1 = AsyncResultHandler::new();
		let res2 = AsyncResultHandler::new();
		let output1 = AsyncOutput::from(res1.clone(), Id::Null, Version::V2);
		let output2 = AsyncOutput::from(res2.clone(), Id::Null, Version::V2);

		let response = Response::Batch(vec![Output::Async(output1), Output::Async(output2)]);
		let val = Arc::new(AtomicBool::new(false));
		let v = val.clone();
		assert!(!response.on_result(move || { v.store(true, Ordering::Relaxed) }));
		assert_eq!(val.load(Ordering::Relaxed), false);

		// when
		// resolve first
		res1.set_result(Ok(Value::U64(1)));
		assert_eq!(val.load(Ordering::Relaxed), false);
		// resolve second
		res2.set_result(Ok(Value::U64(2)));
		assert_eq!(val.load(Ordering::Relaxed), true);

		// then
		assert_eq!(response.await(), SyncResponse::Batch(vec![
			SyncOutput::Success(Success { result: Value::U64(1), id: Id::Null, jsonrpc: Version::V2 }),
			SyncOutput::Success(Success { result: Value::U64(2), id: Id::Null, jsonrpc: Version::V2 }),
		]));
	}

	#[test]
	fn should_call_on_result_if_available() {
		let res = AsyncResultHandler::new();
		let output = AsyncOutput::from(res.clone(), Id::Null, Version::V2);
		res.set_result(Ok(Value::String("hello".into())));

		let val = Arc::new(AtomicBool::new(false));
		let v = val.clone();

		assert!(output.on_result(move || { v.store(true, Ordering::Relaxed) }));
		assert_eq!(val.load(Ordering::Relaxed), true);
	}

	#[test]
	fn should_wait_for_output() {
		let res = AsyncResultHandler::new();
		let output = AsyncOutput::from(res.clone(), Id::Null, Version::V2);
		thread::spawn(move || {
			res.set_result(Ok(Value::String("hello".into())));
		});
		assert_eq!(output.await(), SyncOutput::Success(Success {
			id: Id::Null,
			jsonrpc: Version::V2,
			result: Value::String("hello".into()),
		}));
	}

	#[test]
	fn should_return_output_if_available() {
		let res = AsyncResultHandler::new();
		let output = AsyncOutput::from(res.clone(), Id::Null, Version::V2);
		res.set_result(Ok(Value::String("hello".into())));

		assert_eq!(output.await(), SyncOutput::Success(Success {
			id: Id::Null,
			jsonrpc: Version::V2,
			result: Value::String("hello".into()),
		}));
	}
}
<|endoftext|>


<commit_before>use std::str::CharIndices;
use std::iter::Peekable;

#[derive(Debug, PartialEq)]
pub enum Token {
	Identifier(String),
	Value(i32),
	Register(usize),

}

pub fn tokenize(input: &str) -> Vec<Token> {
	let mut tokens: Vec<Token> = Vec::new();
	let mut tokenizer = Lexer::new(input);

	loop {
		match tokenizer.next() {
			Some(t) => {

				tokens.push(t);

			},
			None => break
		}
	}
	tokens
}

pub struct Lexer<'a> {
	input: &'a str,
	iter: Peekable<CharIndices<'a>>,
	pos: usize,
	line: u32,
	column: u32,
}

impl<'a> Lexer<'a> {
	fn new(input : &str) -> Lexer {
		Lexer {
			input: input,
			iter: input.char_indices().peekable(),
			pos: 0,
			line: 1,
			column: 1
		}
	}
	fn advance(&mut self) -> Option<char> {

		if let Some((i, c)) = self.iter.next() {
			match c  {
				'\n' => {
					self.column = 1;
					self.line  += 1;
				},

				'\t' => {
					self.column  += 4;

				},
				_ => self.column += 1

			}
			self.pos = i;
			return Some(c);
		}
		None
	}
	fn advance_while<P: Fn(char) -> bool>(&mut self, p: P) {
		loop {

			match self.peek() {
				Some(c) => {

					match p(c) {
						false => break,
						true => continue
					}
				}
				None => break
			}
			self.advance();
		}
	}
	fn peek(&mut self) -> Option<char> {
		if let Some(&(_, c)) = self.iter.peek() {
			return Some(c);
		}
		None
	}
	fn handle_alphabetic(&mut self) -> Token {
		//todo
		unimplemented!()
	}
	fn handle_number(&mut self) -> Token {
		let start = self.pos;
		self.advance_while(is_numeric);

		Token::Value(self.input[start..self.pos].parse().unwrap())

	}
	fn handle_other(&mut self) -> Token {
		//todo
		unimplemented!()
	}
}

impl<'a> Iterator for Lexer<'a> {
	type Item = Token;
	fn next(&mut self) -> Option<Token> {
		let token = match self.peek() {
			Some(c) if is_alphabetic(c) => self.handle_alphabetic(),
			Some(c) if is_numeric(c) => self.handle_number(),
			Some(c) if !is_numeric(c) && !is_alphabetic(c) => self.handle_other(),
			_ =>  unreachable!()
		};
		Some(token)

	}
}

fn is_numeric(c: char) -> bool {
	match c {
		'0'...'9' => true,
		_ => false
	}
}
fn is_alphabetic(c: char) -> bool {
	match c {
		'a' ... 'z' | 'A' ... 'Z' => true,
		_ => false
	}
}
<commit_msg>advance and advance_while tests<commit_after>use std::str::CharIndices;
use std::iter::Peekable;

#[derive(Debug, PartialEq)]
pub enum Token {
	Identifier(String),
	Value(i32),
	Register(usize),

}

pub fn tokenize(input: &str) -> Vec<Token> {
	let mut tokens: Vec<Token> = Vec::new();
	let mut tokenizer = Lexer::new(input);

	loop {
		match tokenizer.next() {
			Some(t) => {

				tokens.push(t);

			},
			None => break
		}
	}
	tokens
}

pub struct Lexer<'a> {
	input: &'a str,
	iter: Peekable<CharIndices<'a>>,
	pos: usize,
	line: u32,
	column: u32,
}

impl<'a> Lexer<'a> {
	fn new(input : &str) -> Lexer {
		Lexer {
			input: input,
			iter: input.char_indices().peekable(),
			pos: 0,
			line: 1,
			column: 1
		}
	}
	fn advance(&mut self) -> Option<char> {

		if let Some((i, c)) = self.iter.next() {
			match c  {
				'\n' => {
					self.column = 1;
					self.line  += 1;
				},

				'\t' => {
					self.column  += 4;

				},
				_ => self.column += 1

			}
			self.pos = i + 1;
			return Some(c);
		}
		None
	}
	fn advance_while<P: Fn(char) -> bool>(&mut self, p: P) {
		loop {

			match self.peek() {
				Some(c) => {

					match p(c) {
						false => break,
						true => {}
					}
				}
				None => break
			}
			self.advance();
		}
	}
	fn peek(&mut self) -> Option<char> {
		if let Some(&(_, c)) = self.iter.peek() {
			return Some(c);
		}
		None
	}
	fn handle_alphabetic(&mut self) -> Token {
		//todo
		unimplemented!()
	}
	fn handle_number(&mut self) -> Token {
		let start = self.pos;
		self.advance_while(is_numeric);

		Token::Value(self.input[start..self.pos].parse().unwrap())
	}
	fn handle_other(&mut self) -> Token {
		//todo
		unimplemented!()
	}
}

impl<'a> Iterator for Lexer<'a> {
	type Item = Token;
	fn next(&mut self) -> Option<Token> {
		let token = match self.peek() {
			Some(c) if is_alphabetic(c) => self.handle_alphabetic(),
			Some(c) if is_numeric(c) => self.handle_number(),
			Some(c) if !is_numeric(c) && !is_alphabetic(c) => self.handle_other(),
			_ =>  unreachable!()
		};
		Some(token)

	}
}

fn is_numeric(c: char) -> bool {
	match c {
		'0'...'9' => true,
		_ => false
	}
}
fn is_alphabetic(c: char) -> bool {
	match c {
		'a' ... 'z' | 'A' ... 'Z' => true,
		_ => false
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use super::{is_numeric, is_alphabetic};
	#[test]
	fn advance(){
		let mut lexer = Lexer::new("test 14 @\ntesting\ntest\ttesting");
		let mut output = String::new();

		loop {
			match lexer.advance() {
				Some(c) => {
					output.push(c);

				},
				None => break
			}
		}
		assert_eq!(output, "test 14 @\ntesting\ntest\ttesting");
		assert_eq!(lexer.line, 3);
		assert_eq!(lexer.column, 16);
	}
	#[test]
	fn advance_while_numeric(){
		let mut lexer = Lexer::new("4532test s34");
		let start = lexer.pos;
		lexer.advance_while(is_numeric);
		assert_eq!(&lexer.input[start..lexer.pos], "4532");
	}
	#[test]
	fn advance_while_alphabetic(){
		let mut lexer = Lexer::new("test3 3test");
		let start = lexer.pos;
		lexer.advance_while(is_alphabetic);
		assert_eq!(&lexer.input[start..lexer.pos], "test");
	}

}

<|endoftext|>


<commit_before>use peruse::slice_parsers::*;
use peruse::string_parsers::*;

use grammar_lexer::*;
use grammar::*;
use std::str::FromStr;

//type Lexer = SliceParser<I=str, O=Token>;

pub fn token() -> Box<SliceParser<I=str, O=Vec<Token>>> {

  fn lt(s: &str, t: Token) -> RegexLiteralParser<Token> {
    str_lit((String::from_str(r"^[ \t]*").unwrap() + s).as_str(), t)
  }

  let ident = capture(r"^[ \t]*([a-zA-Z]\w*)[ \t]*", |caps| Token::Ident(String::from_str(caps.at(1).unwrap()).unwrap()));

  let number = capture(r"^[ \t]*(\d+)[ \t]*", |caps| Token::Number(FromStr::from_str(caps.at(1).unwrap()).unwrap()));

  let lits = one_of(vec![
    lt("out",         Token::OutputCmd),
    lt("if",          Token::IfKeyword),
    lt("else",        Token::ElseKeyword),
    lt("while",       Token::WhileKeyword),
    lt("loop",       Token::WhileKeyword),
    lt(r"\r?\n\s*",   Token::NewLine),
    lt(r"\(\s*",      Token::OpenParen),
    lt(r"\)",         Token::CloseParen),
    lt(r"\}",         Token::CloseBrace),
    lt("==",          Token::Cmp(Comparator::CEq)),
    lt("!=",          Token::Cmp(Comparator::CNeq)),
    lt(">=",          Token::Cmp(Comparator::CGeq)),
    lt(r"\{\s*",      Token::OpenBrace),
    lt("<=",          Token::Cmp(Comparator::CLeq)),
    lt(">",           Token::Cmp(Comparator::CGt)),
    lt("<",           Token::Cmp(Comparator::CLt)),
    lt(r"\+",         Token::PlusSign),
    lt("-",           Token::MinusSign),
    lt("=",           Token::Equals),
    lt(r"\*",         Token::MultSign),
    lt("/",           Token::DivideSign),
    lt(r"%",           Token::ModuloSign)
  ]);

  let options = lits.or(number).or(ident).repeat();
  Box::new(options)

}
<commit_msg>Fixed rule for loop keyword<commit_after>use peruse::slice_parsers::*;
use peruse::string_parsers::*;

use grammar_lexer::*;
use grammar::*;
use std::str::FromStr;

//type Lexer = SliceParser<I=str, O=Token>;

pub fn token() -> Box<SliceParser<I=str, O=Vec<Token>>> {

  fn lt(s: &str, t: Token) -> RegexLiteralParser<Token> {
    str_lit((String::from_str(r"^[ \t]*").unwrap() + s).as_str(), t)
  }

  let ident = capture(r"^[ \t]*([a-zA-Z]\w*)[ \t]*", |caps| Token::Ident(String::from_str(caps.at(1).unwrap()).unwrap()));

  let number = capture(r"^[ \t]*(\d+)[ \t]*", |caps| Token::Number(FromStr::from_str(caps.at(1).unwrap()).unwrap()));

  let lits = one_of(vec![
    lt("out",         Token::OutputCmd),
    lt("if",          Token::IfKeyword),
    lt("else",        Token::ElseKeyword),
    lt("while",       Token::WhileKeyword),
    lt("loop",       Token::LoopKeyword),
    lt(r"\r?\n\s*",   Token::NewLine),
    lt(r"\(\s*",      Token::OpenParen),
    lt(r"\)",         Token::CloseParen),
    lt(r"\}",         Token::CloseBrace),
    lt("==",          Token::Cmp(Comparator::CEq)),
    lt("!=",          Token::Cmp(Comparator::CNeq)),
    lt(">=",          Token::Cmp(Comparator::CGeq)),
    lt(r"\{\s*",      Token::OpenBrace),
    lt("<=",          Token::Cmp(Comparator::CLeq)),
    lt(">",           Token::Cmp(Comparator::CGt)),
    lt("<",           Token::Cmp(Comparator::CLt)),
    lt(r"\+",         Token::PlusSign),
    lt("-",           Token::MinusSign),
    lt("=",           Token::Equals),
    lt(r"\*",         Token::MultSign),
    lt("/",           Token::DivideSign),
    lt(r"%",           Token::ModuloSign)
  ]);

  let options = lits.or(number).or(ident).repeat();
  Box::new(options)

}
<|endoftext|>


<commit_before>use rustc::lint::*;
use syntax::ast::*;
use syntax::visit::{Visitor, walk_expr};
use rustc::middle::ty;
use std::collections::HashSet;

use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, walk_ptrs_ty,
            in_external_macro, expr_block, span_help_and_lint};
use utils::{VEC_PATH, LL_PATH};

declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn,
               "for-looping over a range of indices where an iterator over items would do" }

declare_lint!{ pub EXPLICIT_ITER_LOOP, Warn,
               "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do" }

declare_lint!{ pub ITER_NEXT_LOOP, Warn,
               "for-looping over `_.next()` which is probably not intended" }

declare_lint!{ pub WHILE_LET_LOOP, Warn,
               "`loop { if let { ... } else break }` can be written as a `while let` loop" }

declare_lint!{ pub UNUSED_COLLECT, Warn,
               "`collect()`ing an iterator without using the result; this is usually better \
                written as a for loop" }

#[derive(Copy, Clone)]
pub struct LoopsPass;

impl LintPass for LoopsPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP,
                    WHILE_LET_LOOP, UNUSED_COLLECT)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let Some((pat, arg, body)) = recover_for_loop(expr) {
            // check for looping over a range and then indexing a sequence with it
            // -> the iteratee must be a range literal
            if let ExprRange(_, _) = arg.node {
                // the var must be a single name
                if let PatIdent(_, ref ident, _) = pat.node {
                    let mut visitor = VarVisitor { cx: cx, var: ident.node.name,
                                                   indexed: HashSet::new(), nonindex: false };
                    walk_expr(&mut visitor, body);
                    // linting condition: we only indexed one variable
                    if visitor.indexed.len() == 1 {
                        let indexed = visitor.indexed.into_iter().next().expect(
                            "Len was nonzero, but no contents found");
                        if visitor.nonindex {
                            span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!(
                                "the loop variable `{}` is used to index `{}`. Consider using \
                                 `for ({}, item) in {}.iter().enumerate()` or similar iterators",
                                ident.node.name, indexed, ident.node.name, indexed));
                        } else {
                            span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!(
                                "the loop variable `{}` is only used to index `{}`. \
                                 Consider using `for item in &{}` or similar iterators",
                                ident.node.name, indexed, indexed));
                        }
                    }
                }
            }

            if let ExprMethodCall(ref method, _, ref args) = arg.node {
                // just the receiver, no arguments
                if args.len() == 1 {
                    let method_name = method.node.name;
                    // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
                    if method_name == "iter" || method_name == "iter_mut" {
                        if is_ref_iterable_type(cx, &args[0]) {
                            let object = snippet(cx, args[0].span, "_");
                            span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!(
                                "it is more idiomatic to loop over `&{}{}` instead of `{}.{}()`",
                                if method_name == "iter_mut" { "mut " } else { "" },
                                object, object, method_name));
                        }
                    }
                    // check for looping over Iterator::next() which is not what you want
                    else if method_name == "next" {
                        if match_trait_method(cx, arg, &["core", "iter", "Iterator"]) {
                            span_lint(cx, ITER_NEXT_LOOP, expr.span,
                                      "you are iterating over `Iterator::next()` which is an Option; \
                                       this will compile but is probably not what you want");
                        }
                    }
                }
            }
        }
        // check for `loop { if let {} else break }` that could be `while let`
        // (also matches explicit "match" instead of "if let")
        if let ExprLoop(ref block, _) = expr.node {
            // extract a single expression
            if let Some(inner) = extract_single_expr(block) {
                if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node {
                    // ensure "if let" compatible match structure
                    match *source {
                        MatchSource::Normal | MatchSource::IfLetDesugar{..} => if
                            arms.len() == 2 &&
                            arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
                            arms[1].pats.len() == 1 && arms[1].guard.is_none() &&
                            // finally, check for "break" in the second clause
                            is_break_expr(&arms[1].body)
                        {
                            if in_external_macro(cx, expr.span) { return; }
                            span_help_and_lint(cx, WHILE_LET_LOOP, expr.span,
                                               "this loop could be written as a `while let` loop",
                                               &format!("try\nwhile let {} = {} {}",
                                                        snippet(cx, arms[0].pats[0].span, ".."),
                                                        snippet(cx, matchexpr.span, ".."),
                                                        expr_block(cx, &arms[0].body, "..")));
                        },
                        _ => ()
                    }
                }
            }
        }
    }

    fn check_stmt(&mut self, cx: &Context, stmt: &Stmt) {
        if let StmtSemi(ref expr, _) = stmt.node {
            if let ExprMethodCall(ref method, _, ref args) = expr.node {
                if args.len() == 1 && method.node.name == "collect" {
                    if match_trait_method(cx, expr, &["core", "iter", "Iterator"]) {
                        span_lint(cx, UNUSED_COLLECT, expr.span, &format!(
                            "you are collect()ing an iterator and throwing away the result. \
                             Consider using an explicit for loop to exhaust the iterator"));
                    }
                }
            }
        }
    }
}

/// Recover the essential nodes of a desugared for loop:
/// `for pat in arg { body }` becomes `(pat, arg, body)`.
fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> {
    if_let_chain! {
        [
            let ExprMatch(ref iterexpr, ref arms, _) = expr.node,
            let ExprCall(_, ref iterargs) = iterexpr.node,
            iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(),
            let ExprLoop(ref block, _) = arms[0].body.node,
            block.stmts.is_empty(),
            let Some(ref loopexpr) = block.expr,
            let ExprMatch(_, ref innerarms, MatchSource::ForLoopDesugar) = loopexpr.node,
            innerarms.len() == 2 && innerarms[0].pats.len() == 1,
            let PatEnum(_, Some(ref somepats)) = innerarms[0].pats[0].node,
            somepats.len() == 1
        ], {
            return Some((&somepats[0],
                         &iterargs[0],
                         &innerarms[0].body));
        }
    }
    None
}

struct VarVisitor<'v, 't: 'v> {
    cx: &'v Context<'v, 't>, // context reference
    var: Name,               // var name to look for as index
    indexed: HashSet<Name>,  // indexed variables
    nonindex: bool,          // has the var been used otherwise?
}

impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> {
    fn visit_expr(&mut self, expr: &'v Expr) {
        if let ExprPath(None, ref path) = expr.node {
            if path.segments.len() == 1 && path.segments[0].identifier.name == self.var {
                // we are referencing our variable! now check if it's as an index
                if_let_chain! {
                    [
                        let Some(parexpr) = get_parent_expr(self.cx, expr),
                        let ExprIndex(ref seqexpr, _) = parexpr.node,
                        let ExprPath(None, ref seqvar) = seqexpr.node,
                        seqvar.segments.len() == 1
                    ], {
                        self.indexed.insert(seqvar.segments[0].identifier.name);
                        return;  // no need to walk further
                    }
                }
                // we are not indexing anything, record that
                self.nonindex = true;
                return;
            }
        }
        walk_expr(self, expr);
    }
}

/// Return true if the type of expr is one that provides IntoIterator impls
/// for &T and &mut T, such as Vec.
fn is_ref_iterable_type(cx: &Context, e: &Expr) -> bool {
    let ty = walk_ptrs_ty(cx.tcx.expr_ty(e));
    println!("mt {:?} {:?}", e, ty);
    is_array(ty) ||
        match_type(cx, ty, &VEC_PATH) ||
        match_type(cx, ty, &LL_PATH) ||
        match_type(cx, ty, &["std", "collections", "hash", "map", "HashMap"]) ||
        match_type(cx, ty, &["std", "collections", "hash", "set", "HashSet"]) ||
        match_type(cx, ty, &["collections", "vec_deque", "VecDeque"]) ||
        match_type(cx, ty, &["collections", "binary_heap", "BinaryHeap"]) ||
        match_type(cx, ty, &["collections", "btree", "map", "BTreeMap"]) ||
        match_type(cx, ty, &["collections", "btree", "set", "BTreeSet"])
}

fn is_array(ty: ty::Ty) -> bool {
    match ty.sty {
        ty::TyArray(..) => true,
        _ => false
    }
}

/// If block consists of a single expression (with or without semicolon), return it.
fn extract_single_expr(block: &Block) -> Option<&Expr> {
    match (&block.stmts.len(), &block.expr) {
        (&1, &None) => match block.stmts[0].node {
            StmtExpr(ref expr, _) |
            StmtSemi(ref expr, _) => Some(expr),
            _ => None,
        },
        (&0, &Some(ref expr)) => Some(expr),
        _ => None
    }
}

/// Return true if expr contains a single break expr (maybe within a block).
fn is_break_expr(expr: &Expr) -> bool {
    match expr.node {
        ExprBreak(None) => true,
        ExprBlock(ref b) => match extract_single_expr(b) {
            Some(ref subexpr) => is_break_expr(subexpr),
            None => false,
        },
        _ => false,
    }
}
<commit_msg>loops: remove debugging print<commit_after>use rustc::lint::*;
use syntax::ast::*;
use syntax::visit::{Visitor, walk_expr};
use rustc::middle::ty;
use std::collections::HashSet;

use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, walk_ptrs_ty,
            in_external_macro, expr_block, span_help_and_lint};
use utils::{VEC_PATH, LL_PATH};

declare_lint!{ pub NEEDLESS_RANGE_LOOP, Warn,
               "for-looping over a range of indices where an iterator over items would do" }

declare_lint!{ pub EXPLICIT_ITER_LOOP, Warn,
               "for-looping over `_.iter()` or `_.iter_mut()` when `&_` or `&mut _` would do" }

declare_lint!{ pub ITER_NEXT_LOOP, Warn,
               "for-looping over `_.next()` which is probably not intended" }

declare_lint!{ pub WHILE_LET_LOOP, Warn,
               "`loop { if let { ... } else break }` can be written as a `while let` loop" }

declare_lint!{ pub UNUSED_COLLECT, Warn,
               "`collect()`ing an iterator without using the result; this is usually better \
                written as a for loop" }

#[derive(Copy, Clone)]
pub struct LoopsPass;

impl LintPass for LoopsPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, ITER_NEXT_LOOP,
                    WHILE_LET_LOOP, UNUSED_COLLECT)
    }

    fn check_expr(&mut self, cx: &Context, expr: &Expr) {
        if let Some((pat, arg, body)) = recover_for_loop(expr) {
            // check for looping over a range and then indexing a sequence with it
            // -> the iteratee must be a range literal
            if let ExprRange(_, _) = arg.node {
                // the var must be a single name
                if let PatIdent(_, ref ident, _) = pat.node {
                    let mut visitor = VarVisitor { cx: cx, var: ident.node.name,
                                                   indexed: HashSet::new(), nonindex: false };
                    walk_expr(&mut visitor, body);
                    // linting condition: we only indexed one variable
                    if visitor.indexed.len() == 1 {
                        let indexed = visitor.indexed.into_iter().next().expect(
                            "Len was nonzero, but no contents found");
                        if visitor.nonindex {
                            span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!(
                                "the loop variable `{}` is used to index `{}`. Consider using \
                                 `for ({}, item) in {}.iter().enumerate()` or similar iterators",
                                ident.node.name, indexed, ident.node.name, indexed));
                        } else {
                            span_lint(cx, NEEDLESS_RANGE_LOOP, expr.span, &format!(
                                "the loop variable `{}` is only used to index `{}`. \
                                 Consider using `for item in &{}` or similar iterators",
                                ident.node.name, indexed, indexed));
                        }
                    }
                }
            }

            if let ExprMethodCall(ref method, _, ref args) = arg.node {
                // just the receiver, no arguments
                if args.len() == 1 {
                    let method_name = method.node.name;
                    // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
                    if method_name == "iter" || method_name == "iter_mut" {
                        if is_ref_iterable_type(cx, &args[0]) {
                            let object = snippet(cx, args[0].span, "_");
                            span_lint(cx, EXPLICIT_ITER_LOOP, expr.span, &format!(
                                "it is more idiomatic to loop over `&{}{}` instead of `{}.{}()`",
                                if method_name == "iter_mut" { "mut " } else { "" },
                                object, object, method_name));
                        }
                    }
                    // check for looping over Iterator::next() which is not what you want
                    else if method_name == "next" {
                        if match_trait_method(cx, arg, &["core", "iter", "Iterator"]) {
                            span_lint(cx, ITER_NEXT_LOOP, expr.span,
                                      "you are iterating over `Iterator::next()` which is an Option; \
                                       this will compile but is probably not what you want");
                        }
                    }
                }
            }
        }
        // check for `loop { if let {} else break }` that could be `while let`
        // (also matches explicit "match" instead of "if let")
        if let ExprLoop(ref block, _) = expr.node {
            // extract a single expression
            if let Some(inner) = extract_single_expr(block) {
                if let ExprMatch(ref matchexpr, ref arms, ref source) = inner.node {
                    // ensure "if let" compatible match structure
                    match *source {
                        MatchSource::Normal | MatchSource::IfLetDesugar{..} => if
                            arms.len() == 2 &&
                            arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
                            arms[1].pats.len() == 1 && arms[1].guard.is_none() &&
                            // finally, check for "break" in the second clause
                            is_break_expr(&arms[1].body)
                        {
                            if in_external_macro(cx, expr.span) { return; }
                            span_help_and_lint(cx, WHILE_LET_LOOP, expr.span,
                                               "this loop could be written as a `while let` loop",
                                               &format!("try\nwhile let {} = {} {}",
                                                        snippet(cx, arms[0].pats[0].span, ".."),
                                                        snippet(cx, matchexpr.span, ".."),
                                                        expr_block(cx, &arms[0].body, "..")));
                        },
                        _ => ()
                    }
                }
            }
        }
    }

    fn check_stmt(&mut self, cx: &Context, stmt: &Stmt) {
        if let StmtSemi(ref expr, _) = stmt.node {
            if let ExprMethodCall(ref method, _, ref args) = expr.node {
                if args.len() == 1 && method.node.name == "collect" {
                    if match_trait_method(cx, expr, &["core", "iter", "Iterator"]) {
                        span_lint(cx, UNUSED_COLLECT, expr.span, &format!(
                            "you are collect()ing an iterator and throwing away the result. \
                             Consider using an explicit for loop to exhaust the iterator"));
                    }
                }
            }
        }
    }
}

/// Recover the essential nodes of a desugared for loop:
/// `for pat in arg { body }` becomes `(pat, arg, body)`.
fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> {
    if_let_chain! {
        [
            let ExprMatch(ref iterexpr, ref arms, _) = expr.node,
            let ExprCall(_, ref iterargs) = iterexpr.node,
            iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(),
            let ExprLoop(ref block, _) = arms[0].body.node,
            block.stmts.is_empty(),
            let Some(ref loopexpr) = block.expr,
            let ExprMatch(_, ref innerarms, MatchSource::ForLoopDesugar) = loopexpr.node,
            innerarms.len() == 2 && innerarms[0].pats.len() == 1,
            let PatEnum(_, Some(ref somepats)) = innerarms[0].pats[0].node,
            somepats.len() == 1
        ], {
            return Some((&somepats[0],
                         &iterargs[0],
                         &innerarms[0].body));
        }
    }
    None
}

struct VarVisitor<'v, 't: 'v> {
    cx: &'v Context<'v, 't>, // context reference
    var: Name,               // var name to look for as index
    indexed: HashSet<Name>,  // indexed variables
    nonindex: bool,          // has the var been used otherwise?
}

impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> {
    fn visit_expr(&mut self, expr: &'v Expr) {
        if let ExprPath(None, ref path) = expr.node {
            if path.segments.len() == 1 && path.segments[0].identifier.name == self.var {
                // we are referencing our variable! now check if it's as an index
                if_let_chain! {
                    [
                        let Some(parexpr) = get_parent_expr(self.cx, expr),
                        let ExprIndex(ref seqexpr, _) = parexpr.node,
                        let ExprPath(None, ref seqvar) = seqexpr.node,
                        seqvar.segments.len() == 1
                    ], {
                        self.indexed.insert(seqvar.segments[0].identifier.name);
                        return;  // no need to walk further
                    }
                }
                // we are not indexing anything, record that
                self.nonindex = true;
                return;
            }
        }
        walk_expr(self, expr);
    }
}

/// Return true if the type of expr is one that provides IntoIterator impls
/// for &T and &mut T, such as Vec.
fn is_ref_iterable_type(cx: &Context, e: &Expr) -> bool {
    let ty = walk_ptrs_ty(cx.tcx.expr_ty(e));
    is_array(ty) ||
        match_type(cx, ty, &VEC_PATH) ||
        match_type(cx, ty, &LL_PATH) ||
        match_type(cx, ty, &["std", "collections", "hash", "map", "HashMap"]) ||
        match_type(cx, ty, &["std", "collections", "hash", "set", "HashSet"]) ||
        match_type(cx, ty, &["collections", "vec_deque", "VecDeque"]) ||
        match_type(cx, ty, &["collections", "binary_heap", "BinaryHeap"]) ||
        match_type(cx, ty, &["collections", "btree", "map", "BTreeMap"]) ||
        match_type(cx, ty, &["collections", "btree", "set", "BTreeSet"])
}

fn is_array(ty: ty::Ty) -> bool {
    match ty.sty {
        ty::TyArray(..) => true,
        _ => false
    }
}

/// If block consists of a single expression (with or without semicolon), return it.
fn extract_single_expr(block: &Block) -> Option<&Expr> {
    match (&block.stmts.len(), &block.expr) {
        (&1, &None) => match block.stmts[0].node {
            StmtExpr(ref expr, _) |
            StmtSemi(ref expr, _) => Some(expr),
            _ => None,
        },
        (&0, &Some(ref expr)) => Some(expr),
        _ => None
    }
}

/// Return true if expr contains a single break expr (maybe within a block).
fn is_break_expr(expr: &Expr) -> bool {
    match expr.node {
        ExprBreak(None) => true,
        ExprBlock(ref b) => match extract_single_expr(b) {
            Some(ref subexpr) => is_break_expr(subexpr),
            None => false,
        },
        _ => false,
    }
}
<|endoftext|>