<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, X> = result::Result<T, ActorError<X>>;
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<(), T>>,
    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<(), T>>, name: Option<String>) -> Self {
        Actor {
            sender: sender,
            receiver: receiver,
            handle: handle,
            name: name,
        }
    }

    pub fn cast(&self, message: T) -> Result<(), ActorError<T>> {
        match self.sender.send(Message::Cast(message)) {
            Ok(()) => Ok(()),
            Err(err) => Err(ActorError::from(err)),
        }
    }

    pub fn call(&self, message: T) -> Result<T, ActorError<T>> {
        match self.sender.send(Message::Call(message)) {
            Ok(()) => {
                match self.receiver.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(&mut state) {
            Ok(result) => result,
            Err(err) => return Err(err),
        };

        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(&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, &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, &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, &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(itx, orx, handle, name))
    }
}

#[derive(Debug)]
pub enum ActorError<T> where T: Any + Send {
    InitFailure(String),
    AbnormalShutdown(String),
    SendError(mpsc::SendError<Message<T>>),
    RecvError,
}

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

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

#[derive(Debug)]
pub enum StopReason {
    Normal,
    Other(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, state: &mut Self::S) -> InitResult<Self::E>;

    fn handle_call(&self, _message: Self::T, _sender: &Sender<Message<Self::T>>, _state: &mut Self::S) -> HandleResult<Self::T> {
        panic!("handle_call callback not implemented");
    }
    fn handle_cast(&self, _message: Self::T, _state: &mut Self::S) -> HandleResult<Self::T> {
        panic!("handle_cast callback not implemented");
    }
    fn handle_info(&self, _message: Self::T, _state: &mut Self::S) -> HandleResult<Self::T> {
        HandleResult::NoReply(None)
    }
    fn handle_timeout(&self, _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<T>> {
    if let Some(msg) = reply {
        let _result = sender.send(Message::Reply(msg));
    }
    match reason {
        StopReason::Normal => Ok(()),
        StopReason::Other(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, state: &mut MyState) -> InitResult<MyError> {
            if state.initialized {
                Err(MyError::DirtyState)
            } else {
                state.initialized = true;
                Ok(None)
            }
        }

        fn handle_call(&self, msg: MyMessage, _sender: &Sender<Message<MyMessage>>, state: &mut MyState) -> HandleResult<MyMessage> {
            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::Other(String::from("Nope")), None),
            }
        }

        fn handle_cast(&self, msg: MyMessage, state: &mut MyState) -> HandleResult<MyMessage> {
            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>make inner channel sender available in GenServer callbacks<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) -> 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 'self' 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(&itx, &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, &itx, &otx, &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, &itx, &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, &itx, &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>use std::fmt;
use std::ascii::AsciiExt;

use AsciiCast;

/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Copy)]
pub struct Ascii { chr: u8 }

impl Ascii {
    /// Constructs an Ascii character from a `char`.
    ///
    /// # Failure
    ///
    /// Returns `Err(())` if the character can't be ascii encoded.
    ///
    /// # Example
    /// ```
    /// # use ascii::Ascii;
    /// let a = Ascii::from('g').unwrap();
    /// assert_eq!(a.as_char(), 'g');
    /// ```
    #[inline]
    pub fn from(ch: char) -> Result<Ascii, ()> {
        if ch as u32 <= 0x7F {
            return Ok( Ascii { chr: ch as u8 });
        }
        Err(())
    }

    /// Constructs an Ascii character from a `u8`.
    ///
    /// # Failure
    ///
    /// Returns `Err(())` if the character can't be ascii encoded.
    ///
    /// # Example
    ///
    /// ```
    /// # use ascii::Ascii;
    /// let a = Ascii::from_byte(65).unwrap();
    /// assert_eq!(a.as_char(), 'A');
    /// ```
    #[inline]
    pub fn from_byte(ch: u8) -> Result<Ascii, ()> {
        if ch <= 0x7F {
            return Ok( Ascii { chr: ch });
        }
        Err(())
    }

    /// Converts an ascii character into a `u8`.
    #[inline]
    pub fn as_byte(&self) -> u8 {
        self.chr
    }

    /// Converts an ascii character into a `char`.
    #[inline]
    pub fn as_char(&self) -> char {
        self.chr as char
    }

    // the following methods are like ctype, and the implementation is inspired by musl

    /// Check if the character is a letter (a-z, A-Z)
    #[inline]
    pub fn is_alphabetic(&self) -> bool {
        (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
    }

    /// Check if the character is a number (0-9)
    #[inline]
    pub fn is_digit(&self) -> bool {
        self.chr >= 0x30 && self.chr <= 0x39
    }

    /// Check if the character is a letter or number
    #[inline]
    pub fn is_alphanumeric(&self) -> bool {
        self.is_alphabetic() || self.is_digit()
    }

    /// Check if the character is a space or horizontal tab
    #[inline]
    pub fn is_blank(&self) -> bool {
        self.chr == b' ' || self.chr == b'\t'
    }

    /// Check if the character is a control character
    #[inline]
    pub fn is_control(&self) -> bool {
        self.chr < 0x20 || self.chr == 0x7F
    }

    /// Checks if the character is printable (except space)
    #[inline]
    pub fn is_graph(&self) -> bool {
        (self.chr - 0x21) < 0x5E
    }

    /// Checks if the character is printable (including space)
    #[inline]
    pub fn is_print(&self) -> bool {
        (self.chr - 0x20) < 0x5F
    }

    /// Checks if the character is alphabetic and lowercase
    #[inline]
    pub fn is_lowercase(&self) -> bool {
        (self.chr - b'a') < 26
    }

    /// Checks if the character is alphabetic and uppercase
    #[inline]
    pub fn is_uppercase(&self) -> bool {
        (self.chr - b'A') < 26
    }

    /// Checks if the character is punctuation
    #[inline]
    pub fn is_punctuation(&self) -> bool {
        self.is_graph() && !self.is_alphanumeric()
    }

    /// Checks if the character is a valid hex digit
    #[inline]
    pub fn is_hex(&self) -> bool {
        self.is_digit() || ((self.chr | 32u8) - b'a') < 6
    }
}

impl fmt::Display for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_char().fmt(f)
    }
}

impl fmt::Debug for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_char().fmt(f)
     }
}

#[cfg(feature = "unstable")]
impl AsciiExt for Ascii {
    type Owned = Ascii;

    #[inline]
    fn is_ascii(&self) -> bool {
        true
    }

    fn to_ascii_uppercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_uppercase()}
    }

    fn to_ascii_lowercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_lowercase()}
    }

    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        self.chr.eq_ignore_ascii_case(&other.chr)
    }

    #[inline]
    fn make_ascii_uppercase(&mut self) {
        self.chr.make_ascii_uppercase()
    }

    #[inline]
    fn make_ascii_lowercase(&mut self) {
        self.chr.make_ascii_lowercase()
    }
}

impl<'a> AsciiCast<'a> for u8 {
    type Target = Ascii;

    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self }
    }
}

impl<'a> AsciiCast<'a> for char {
    type Target = Ascii;

    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self as u8 }
    }
}

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

    #[test]
    fn to_ascii() {
        assert_eq!(65_u8.to_ascii(), Ok(Ascii { chr: 65_u8 }));
        assert_eq!(255_u8.to_ascii(), Err(()));

        assert_eq!('A'.to_ascii(), Ok(Ascii { chr: 65_u8 }));
        assert_eq!('λ'.to_ascii(), Err(()));
    }

    #[test]
    fn as_byte() {
        assert_eq!(65u8.to_ascii().unwrap().as_byte(), 65u8);
        assert_eq!('A'.to_ascii().unwrap().as_byte(), 65u8);
    }

    #[test]
    fn as_char() {
        assert_eq!(65u8.to_ascii().unwrap().as_char(), 'A');
        assert_eq!('A'.to_ascii().unwrap().as_char(), 'A');
    }

    #[test]
    fn is_digit() {
        assert!('0'.to_ascii().unwrap().is_digit());
        assert!('9'.to_ascii().unwrap().is_digit());
        assert!(!'/'.to_ascii().unwrap().is_digit());
        assert!(!':'.to_ascii().unwrap().is_digit());
    }

    #[test]
    fn is_control() {
        assert!(0x1f_u8.to_ascii().unwrap().is_control());
        assert!(0x7f_u8.to_ascii().unwrap().is_control());
        assert!(!' '.to_ascii().unwrap().is_control());
    }

    #[test]
    fn fmt_display_ascii() {
        let s = Ascii { chr: b't' };
        assert_eq!(format!("{}", s), "t".to_string());
    }

    #[test]
    fn fmt_debug_ascii() {
        let c = Ascii { chr: b't' };
        assert_eq!(format!("{:?}", c), "'t'".to_string());
    }
}
<commit_msg>Fix panics in Ascii's `.is_xxx()` methods by specifying wrapping sub.<commit_after>use std::fmt;
use std::ascii::AsciiExt;

use AsciiCast;

/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero.
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Copy)]
pub struct Ascii { chr: u8 }

impl Ascii {
    /// Constructs an Ascii character from a `char`.
    ///
    /// # Failure
    ///
    /// Returns `Err(())` if the character can't be ascii encoded.
    ///
    /// # Example
    /// ```
    /// # use ascii::Ascii;
    /// let a = Ascii::from('g').unwrap();
    /// assert_eq!(a.as_char(), 'g');
    /// ```
    #[inline]
    pub fn from(ch: char) -> Result<Ascii, ()> {
        if ch as u32 <= 0x7F {
            return Ok( Ascii { chr: ch as u8 });
        }
        Err(())
    }

    /// Constructs an Ascii character from a `u8`.
    ///
    /// # Failure
    ///
    /// Returns `Err(())` if the character can't be ascii encoded.
    ///
    /// # Example
    ///
    /// ```
    /// # use ascii::Ascii;
    /// let a = Ascii::from_byte(65).unwrap();
    /// assert_eq!(a.as_char(), 'A');
    /// ```
    #[inline]
    pub fn from_byte(ch: u8) -> Result<Ascii, ()> {
        if ch <= 0x7F {
            return Ok( Ascii { chr: ch });
        }
        Err(())
    }

    /// Converts an ascii character into a `u8`.
    #[inline]
    pub fn as_byte(&self) -> u8 {
        self.chr
    }

    /// Converts an ascii character into a `char`.
    #[inline]
    pub fn as_char(&self) -> char {
        self.chr as char
    }

    // the following methods are like ctype, and the implementation is inspired by musl

    /// Check if the character is a letter (a-z, A-Z)
    #[inline]
    pub fn is_alphabetic(&self) -> bool {
        (self.chr >= 0x41 && self.chr <= 0x5A) || (self.chr >= 0x61 && self.chr <= 0x7A)
    }

    /// Check if the character is a number (0-9)
    #[inline]
    pub fn is_digit(&self) -> bool {
        self.chr >= 0x30 && self.chr <= 0x39
    }

    /// Check if the character is a letter or number
    #[inline]
    pub fn is_alphanumeric(&self) -> bool {
        self.is_alphabetic() || self.is_digit()
    }

    /// Check if the character is a space or horizontal tab
    #[inline]
    pub fn is_blank(&self) -> bool {
        self.chr == b' ' || self.chr == b'\t'
    }

    /// Check if the character is a control character
    #[inline]
    pub fn is_control(&self) -> bool {
        self.chr < 0x20 || self.chr == 0x7F
    }

    /// Checks if the character is printable (except space)
    #[inline]
    pub fn is_graph(&self) -> bool {
        self.chr.wrapping_sub(0x21) < 0x5E
    }

    /// Checks if the character is printable (including space)
    #[inline]
    pub fn is_print(&self) -> bool {
        self.chr.wrapping_sub(0x20) < 0x5F
    }

    /// Checks if the character is alphabetic and lowercase
    #[inline]
    pub fn is_lowercase(&self) -> bool {
        self.chr.wrapping_sub(b'a') < 26
    }

    /// Checks if the character is alphabetic and uppercase
    #[inline]
    pub fn is_uppercase(&self) -> bool {
        self.chr.wrapping_sub(b'A') < 26
    }

    /// Checks if the character is punctuation
    #[inline]
    pub fn is_punctuation(&self) -> bool {
        self.is_graph() && !self.is_alphanumeric()
    }

    /// Checks if the character is a valid hex digit
    #[inline]
    pub fn is_hex(&self) -> bool {
        self.is_digit() || (self.chr | 32u8).wrapping_sub(b'a') < 6
    }
}

impl fmt::Display for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_char().fmt(f)
    }
}

impl fmt::Debug for Ascii {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_char().fmt(f)
     }
}

#[cfg(feature = "unstable")]
impl AsciiExt for Ascii {
    type Owned = Ascii;

    #[inline]
    fn is_ascii(&self) -> bool {
        true
    }

    fn to_ascii_uppercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_uppercase()}
    }

    fn to_ascii_lowercase(&self) -> Ascii {
        Ascii{chr: self.chr.to_ascii_lowercase()}
    }

    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        self.chr.eq_ignore_ascii_case(&other.chr)
    }

    #[inline]
    fn make_ascii_uppercase(&mut self) {
        self.chr.make_ascii_uppercase()
    }

    #[inline]
    fn make_ascii_lowercase(&mut self) {
        self.chr.make_ascii_lowercase()
    }
}

impl<'a> AsciiCast<'a> for u8 {
    type Target = Ascii;

    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self }
    }
}

impl<'a> AsciiCast<'a> for char {
    type Target = Ascii;

    #[inline]
    unsafe fn to_ascii_nocheck(&self) -> Ascii {
        Ascii{ chr: *self as u8 }
    }
}

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

    #[test]
    fn to_ascii() {
        assert_eq!(65_u8.to_ascii(), Ok(Ascii { chr: 65_u8 }));
        assert_eq!(255_u8.to_ascii(), Err(()));

        assert_eq!('A'.to_ascii(), Ok(Ascii { chr: 65_u8 }));
        assert_eq!('λ'.to_ascii(), Err(()));
    }

    #[test]
    fn as_byte() {
        assert_eq!(65u8.to_ascii().unwrap().as_byte(), 65u8);
        assert_eq!('A'.to_ascii().unwrap().as_byte(), 65u8);
    }

    #[test]
    fn as_char() {
        assert_eq!(65u8.to_ascii().unwrap().as_char(), 'A');
        assert_eq!('A'.to_ascii().unwrap().as_char(), 'A');
    }

    #[test]
    fn is_digit() {
        assert!('0'.to_ascii().unwrap().is_digit());
        assert!('9'.to_ascii().unwrap().is_digit());
        assert!(!'/'.to_ascii().unwrap().is_digit());
        assert!(!':'.to_ascii().unwrap().is_digit());
    }

    #[test]
    fn is_control() {
        assert!(0x1f_u8.to_ascii().unwrap().is_control());
        assert!(0x7f_u8.to_ascii().unwrap().is_control());
        assert!(!' '.to_ascii().unwrap().is_control());
    }

    #[test]
    fn fmt_display_ascii() {
        let s = Ascii { chr: b't' };
        assert_eq!(format!("{}", s), "t".to_string());
    }

    #[test]
    fn fmt_debug_ascii() {
        let c = Ascii { chr: b't' };
        assert_eq!(format!("{:?}", c), "'t'".to_string());
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::fmt::{Debug, Formatter, Result as FmtResult};

use rand::{thread_rng, Rng};
use sdl2::Sdl;
use sdl2::rect::Rect;
use ep::FromPrimitive;

use screen::Screen;
use instruction::{Opcodes, Instruction};

const FONT_SET: [u8; 80] = [
    0xf0, 0x90, 0x90, 0x90, 0xf0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xf0, 0x10, 0xf0, 0x80, 0xf0, // 2
    0xf0, 0x10, 0xf0, 0x10, 0xf0, // 3
    0x90, 0x90, 0xf0, 0x10, 0x10, // 4
    0xf0, 0x80, 0xf0, 0x10, 0xf0, // 5
    0xf0, 0x80, 0xf0, 0x90, 0xf0, // 6
    0xf0, 0x10, 0x20, 0x40, 0x40, // 7
    0xf0, 0x90, 0xf0, 0x90, 0xf0, // 8
    0xf0, 0x90, 0xf0, 0x10, 0xf0, // 9
    0xf0, 0x90, 0xf0, 0x90, 0x90, // A
    0xe0, 0x90, 0xe0, 0x90, 0xe0, // B
    0xf0, 0x80, 0x80, 0x80, 0x80, // C
    0xe0, 0x90, 0x90, 0x90, 0xe0, // D
    0xf0, 0x80, 0xf0, 0x80, 0xf0, // E
    0xf0, 0x80, 0xf0, 0x80, 0x80, // F
];

pub struct Chip8<'a> {
    regs:   [u8; 16],
    i:      u16,
    dt:     u8,
    st:     u8,
    pc:     usize,

    inst:   Instruction,
    jmp:    bool,

    keys:   [u8; 16],
    mem:    [u8; 4096],
    stack:  Vec<usize>,
    screen: Screen<'a>,
}

impl<'a> Debug for Chip8<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        self.regs[..].fmt(f)
    }
}

impl<'a> Chip8<'a> {
    pub fn new(sdl: &Sdl) -> Chip8<'a> {
        Chip8 {
            regs:   [0; 16],
            i:      0,
            dt:     0,
            st:     0,
            pc:     0x200,
            inst:   Instruction::new(),
            jmp:    false,
            keys:   [0; 16],
            mem:    [0; 4096],
            stack:  vec![],
            screen: Screen::new(sdl),
        }
    }

    pub fn load_rom(&mut self, path: &str) {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(Path::new(path)).unwrap();
        file.read_to_end(&mut rom).unwrap();
        for i in 0usize..rom.len() {
            self.mem[0x200 + i] = rom[i];
        }
        // TODO: move this
        for i in 0usize..FONT_SET.len() {
            self.mem[0x00 + i] = FONT_SET[i];
        }
    }

    pub fn run(&mut self) {
        let raw_data = (self.mem[self.pc], self.mem[self.pc +1]);
        self.inst.decode(raw_data);

        self.jmp  = false;

        // println!("{:#x}: {:#x}", self.pc, self.inst.opcode);

        match Opcodes::from_u16(self.inst.opcode).unwrap() {
            Opcodes::CLS    => self.cls(),
            Opcodes::RET    => self.ret(),
            Opcodes::JMP    => self.jmp(),
            Opcodes::JMP_VA => self.jmp_va(),
            Opcodes::CALL   => self.call(),
            Opcodes::SE_VB  => self.se_vb(),
            Opcodes::SE_VV  => self.se_vv(),
            Opcodes::SNE_VB => self.sne_vb(),
            Opcodes::SNE_VV => self.sne_vv(),
            Opcodes::OR     => self.or(),
            Opcodes::ADD_VB => self.add_vb(),
            Opcodes::ADD_VV => self.add_vv(),
            Opcodes::ADD_IV => self.add_iv(),
            Opcodes::SUB    => self.sub(),
            Opcodes::SUBN   => self.subn(),
            Opcodes::XOR    => self.xor(),
            Opcodes::AND    => self.and(),
            Opcodes::LD_VB  => self.ld_vb(),
            Opcodes::LD_BV  => self.ld_bv(),
            Opcodes::LD_VV  => self.ld_vv(),
            Opcodes::LD_VI  => self.ld_vi(),
            Opcodes::LD_VK  => self.ld_vk(),
            Opcodes::LD_IV  => self.ld_iv(),
            Opcodes::LD_FV  => self.ld_fv(),
            Opcodes::LD_IA  => self.ld_ia(),
            Opcodes::LD_VDT => self.ld_vdt(),
            Opcodes::LD_DTV => self.ld_dtv(),
            Opcodes::LD_STV => self.ld_stv(),
            Opcodes::SHL    => self.shl(),
            Opcodes::SKP    => self.skp(),
            Opcodes::SKNP   => self.sknp(),
            Opcodes::RND    => self.rnd(),
            Opcodes::SHR    => self.shr(),
            Opcodes::DRW    => self.drw(),
            _               => panic!("Unrecognized opcode: {:#x}", self.inst.opcode),
        }

        if !self.jmp { self.inc_pc(); }

        if self.dt > 0 { self.dt -= 1; }
        if self.st > 0 { self.st -= 1; }
    }

    fn set_pc(&mut self, addr: u16) {
        self.pc = addr as usize;
    }

    fn inc_pc(&mut self) {
        self.pc += 2;
    }

    fn dec_pc(&mut self) {
        self.pc -= 2;
    }

    fn cls(&mut self) {
        self.screen.clear();
    }

    fn ret(&mut self) {
        let addr = self.stack.pop().unwrap();
        self.set_pc(addr as u16);
    }

    fn jmp(&mut self) {
        let addr = self.inst.nnn;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn jmp_va(&mut self) {
        let offset = self.regs[0] as u16;
        let addr = self.inst.nnn + offset;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn call(&mut self) {
        let new_addr = self.inst.nnn;
        self.stack.push(self.pc);
        self.set_pc(new_addr);
        self.jmp = true;
    }

    fn se_vb(&mut self) {
        if self.regs[self.inst.x] == self.inst.kk {
            self.inc_pc();
        }
    }

    fn se_vv(&mut self) {
        if self.regs[self.inst.x] == self.regs[self.inst.y] {
            self.inc_pc();
        }
    }

    fn sne_vb(&mut self) {
        if self.regs[self.inst.x] != self.inst.kk {
            self.inc_pc();
        }
    }

    fn sne_vv(&mut self) {
        if self.regs[self.inst.x] != self.regs[self.inst.y] {
            self.inc_pc();
        }
    }

    fn or(&mut self) {
        self.regs[self.inst.x] |= self.regs[self.inst.y];
    }

    fn and(&mut self) {
        self.regs[self.inst.x] &= self.regs[self.inst.y];
    }

    fn add_vb(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.regs[idx].wrapping_add(self.inst.kk);
    }

    fn add_vv(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x] as u16;
        let y = self.regs[self.inst.y] as u16;

        let res = x + y;
        self.regs[0xF]   = (res > 255) as u8;
        self.regs[idx_x] = res as u8;
    }

    fn add_iv(&mut self) {
        let x   = self.regs[self.inst.x] as u16;
        self.regs[0xF] = ((self.i + x) > 255) as u8;
        self.i += x;
    }

    fn sub(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x];
        let y = self.regs[self.inst.y];

        self.regs[0xF] = (x > y) as u8;
        self.regs[idx_x] = x.wrapping_sub(y);
    }

    fn subn(&mut self) {
        let x = self.regs[self.inst.x];
        let y = self.regs[self.inst.y];

        self.regs[0xF] = (y > x) as u8;
        self.regs[self.inst.x] = y.wrapping_sub(x);
    }

    fn xor(&mut self) {
        self.regs[self.inst.x] ^= self.regs[self.inst.y];
    }

    fn shr(&mut self) {
        let idx_x = self.inst.x;
        let x     = self.regs[idx_x];
        self.regs[0xF] = x & 0x1;
        self.regs[idx_x] = x >> 1;
    }

    fn shl(&mut self) {
        let x = self.regs[self.inst.x];
        let y = self.regs[self.inst.y];

        self.regs[0xF] = ((x & 0xF0) >> 7 == 1) as u8;
        self.regs[self.inst.x] *= 2;
    }

    fn ld_vv(&mut self) {
        self.regs[self.inst.x] = self.regs[self.inst.y];
    }

    fn ld_vb(&mut self) {
        self.regs[self.inst.x] = self.inst.kk;
    }

    fn ld_bv(&mut self) {
        let x = self.regs[self.inst.x];

        self.mem[self.i as usize]     = x / 100;
        self.mem[self.i as usize + 1] = (x / 100) % 10;
        self.mem[self.i as usize + 2] = (x % 100) % 10;
    }

    fn ld_fv(&mut self) {
        let x = self.regs[self.inst.x];
        self.i = (x * 5) as u16;
    }

    fn ld_vi(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.regs[i] = self.mem[self.i as usize + i];
        }
    }

    fn ld_iv(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.mem[self.i as usize + i] = self.regs[i];
        }
    }

    fn ld_ia(&mut self) {
        self.i = self.inst.nnn;
    }

    fn ld_vk(&mut self) {
        let mut key_pressed = false;

        for i in 0..self.keys.len() {
            if self.keys[i] == 1 {
                self.regs[self.inst.x] = i as u8;
                key_pressed = true;
            }
        }

        if !key_pressed {
            self.dec_pc();
        }
    }

    fn ld_vdt(&mut self) {
        self.regs[self.inst.x] = self.dt;
    }

    fn ld_dtv(&mut self) {
        self.dt = self.regs[self.inst.x];
    }

    fn ld_stv(&mut self) {
        self.st = self.regs[self.inst.x];
    }

    fn rnd(&mut self) {
        self.regs[self.inst.x] = thread_rng().gen::<u8>() & self.inst.kk;
    }

    fn drw(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let (x, y) = (self.regs[idx_x] as usize, self.regs[idx_y] as usize);
        let n = self.inst.n as usize;

        self.screen.renderer.clear();
        self.regs[15] = 0;

        for i in 0..n {
            let px = self.mem[(self.i + i as u16) as usize];
            for j in 0..8 {
                if px & (0x80 >> j) != 0 {
                    if self.screen.buffer[(x+j + (y+i) * 64) as usize] == 1 {
                        self.regs[15] = 1;
                    }
                    self.screen.buffer[(x+j + (y+i) * 64) as usize] ^= 1;
                }
            }
        }

        for i in 0usize..32*10 {
            for j in 0usize..64*10 {
                if self.screen.buffer[(j/10)+(i/10)*64] == 1 {
                    self.screen.renderer.fill_rect(
                        Rect::new(j as i32, i as i32, 1, 1)
                        );
                }
            }
        }

        self.screen.draw();
    }

    fn skp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 1{
            self.inc_pc();
        }
    }

    fn sknp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 0 {
            self.inc_pc();
        }
    }
    pub fn reset_keys(&mut self) {
        self.keys = [0;16];
    }

    pub fn press(&mut self, key: u8) {
        self.keys[key as usize] = 1;
    }
}
<commit_msg>fixed arithmetic overflow on screen buffer indexes<commit_after>#![allow(dead_code)]

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::fmt::{Debug, Formatter, Result as FmtResult};

use rand::{thread_rng, Rng};
use sdl2::Sdl;
use sdl2::rect::Rect;
use ep::FromPrimitive;

use screen::Screen;
use instruction::{Opcodes, Instruction};

const FONT_SET: [u8; 80] = [
    0xf0, 0x90, 0x90, 0x90, 0xf0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xf0, 0x10, 0xf0, 0x80, 0xf0, // 2
    0xf0, 0x10, 0xf0, 0x10, 0xf0, // 3
    0x90, 0x90, 0xf0, 0x10, 0x10, // 4
    0xf0, 0x80, 0xf0, 0x10, 0xf0, // 5
    0xf0, 0x80, 0xf0, 0x90, 0xf0, // 6
    0xf0, 0x10, 0x20, 0x40, 0x40, // 7
    0xf0, 0x90, 0xf0, 0x90, 0xf0, // 8
    0xf0, 0x90, 0xf0, 0x10, 0xf0, // 9
    0xf0, 0x90, 0xf0, 0x90, 0x90, // A
    0xe0, 0x90, 0xe0, 0x90, 0xe0, // B
    0xf0, 0x80, 0x80, 0x80, 0x80, // C
    0xe0, 0x90, 0x90, 0x90, 0xe0, // D
    0xf0, 0x80, 0xf0, 0x80, 0xf0, // E
    0xf0, 0x80, 0xf0, 0x80, 0x80, // F
];

pub struct Chip8<'a> {
    regs:   [u8; 16],
    i:      u16,
    dt:     u8,
    st:     u8,
    pc:     usize,

    inst:   Instruction,
    jmp:    bool,

    keys:   [u8; 16],
    mem:    [u8; 4096],
    stack:  Vec<usize>,
    screen: Screen<'a>,
}

impl<'a> Debug for Chip8<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        self.regs[..].fmt(f)
    }
}

impl<'a> Chip8<'a> {
    pub fn new(sdl: &Sdl) -> Chip8<'a> {
        Chip8 {
            regs:   [0; 16],
            i:      0,
            dt:     0,
            st:     0,
            pc:     0x200,
            inst:   Instruction::new(),
            jmp:    false,
            keys:   [0; 16],
            mem:    [0; 4096],
            stack:  vec![],
            screen: Screen::new(sdl),
        }
    }

    pub fn load_rom(&mut self, path: &str) {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(Path::new(path)).unwrap();
        file.read_to_end(&mut rom).unwrap();
        for i in 0usize..rom.len() {
            self.mem[0x200 + i] = rom[i];
        }
        // TODO: move this
        for i in 0usize..FONT_SET.len() {
            self.mem[0x00 + i] = FONT_SET[i];
        }
    }

    pub fn run(&mut self) {
        let raw_data = (self.mem[self.pc], self.mem[self.pc +1]);
        self.inst.decode(raw_data);

        self.jmp  = false;

        // println!("{:#x}: {:#x}", self.pc, self.inst.opcode);

        match Opcodes::from_u16(self.inst.opcode).unwrap() {
            Opcodes::CLS    => self.cls(),
            Opcodes::RET    => self.ret(),
            Opcodes::JMP    => self.jmp(),
            Opcodes::JMP_VA => self.jmp_va(),
            Opcodes::CALL   => self.call(),
            Opcodes::SE_VB  => self.se_vb(),
            Opcodes::SE_VV  => self.se_vv(),
            Opcodes::SNE_VB => self.sne_vb(),
            Opcodes::SNE_VV => self.sne_vv(),
            Opcodes::OR     => self.or(),
            Opcodes::ADD_VB => self.add_vb(),
            Opcodes::ADD_VV => self.add_vv(),
            Opcodes::ADD_IV => self.add_iv(),
            Opcodes::SUB    => self.sub(),
            Opcodes::SUBN   => self.subn(),
            Opcodes::XOR    => self.xor(),
            Opcodes::AND    => self.and(),
            Opcodes::LD_VB  => self.ld_vb(),
            Opcodes::LD_BV  => self.ld_bv(),
            Opcodes::LD_VV  => self.ld_vv(),
            Opcodes::LD_VI  => self.ld_vi(),
            Opcodes::LD_VK  => self.ld_vk(),
            Opcodes::LD_IV  => self.ld_iv(),
            Opcodes::LD_FV  => self.ld_fv(),
            Opcodes::LD_IA  => self.ld_ia(),
            Opcodes::LD_VDT => self.ld_vdt(),
            Opcodes::LD_DTV => self.ld_dtv(),
            Opcodes::LD_STV => self.ld_stv(),
            Opcodes::SHL    => self.shl(),
            Opcodes::SKP    => self.skp(),
            Opcodes::SKNP   => self.sknp(),
            Opcodes::RND    => self.rnd(),
            Opcodes::SHR    => self.shr(),
            Opcodes::DRW    => self.drw(),
            _               => panic!("Unrecognized opcode: {:#x}", self.inst.opcode),
        }

        if !self.jmp { self.inc_pc(); }

        if self.dt > 0 { self.dt -= 1; }
        if self.st > 0 { self.st -= 1; }
    }

    fn set_pc(&mut self, addr: u16) {
        self.pc = addr as usize;
    }

    fn inc_pc(&mut self) {
        self.pc += 2;
    }

    fn dec_pc(&mut self) {
        self.pc -= 2;
    }

    fn cls(&mut self) {
        self.screen.clear();
    }

    fn ret(&mut self) {
        let addr = self.stack.pop().unwrap();
        self.set_pc(addr as u16);
    }

    fn jmp(&mut self) {
        let addr = self.inst.nnn;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn jmp_va(&mut self) {
        let offset = self.regs[0] as u16;
        let addr = self.inst.nnn + offset;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn call(&mut self) {
        let new_addr = self.inst.nnn;
        self.stack.push(self.pc);
        self.set_pc(new_addr);
        self.jmp = true;
    }

    fn se_vb(&mut self) {
        if self.regs[self.inst.x] == self.inst.kk {
            self.inc_pc();
        }
    }

    fn se_vv(&mut self) {
        if self.regs[self.inst.x] == self.regs[self.inst.y] {
            self.inc_pc();
        }
    }

    fn sne_vb(&mut self) {
        if self.regs[self.inst.x] != self.inst.kk {
            self.inc_pc();
        }
    }

    fn sne_vv(&mut self) {
        if self.regs[self.inst.x] != self.regs[self.inst.y] {
            self.inc_pc();
        }
    }

    fn or(&mut self) {
        self.regs[self.inst.x] |= self.regs[self.inst.y];
    }

    fn and(&mut self) {
        self.regs[self.inst.x] &= self.regs[self.inst.y];
    }

    fn add_vb(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.regs[idx].wrapping_add(self.inst.kk);
    }

    fn add_vv(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x] as u16;
        let y = self.regs[self.inst.y] as u16;

        let res = x + y;
        self.regs[0xF]   = (res > 255) as u8;
        self.regs[idx_x] = res as u8;
    }

    fn add_iv(&mut self) {
        let x   = self.regs[self.inst.x] as u16;
        self.regs[0xF] = ((self.i + x) > 255) as u8;
        self.i += x;
    }

    fn sub(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x];
        let y = self.regs[self.inst.y];

        self.regs[0xF] = (x > y) as u8;
        self.regs[idx_x] = x.wrapping_sub(y);
    }

    fn subn(&mut self) {
        let x = self.regs[self.inst.x];
        let y = self.regs[self.inst.y];

        self.regs[0xF] = (y > x) as u8;
        self.regs[self.inst.x] = y.wrapping_sub(x);
    }

    fn xor(&mut self) {
        self.regs[self.inst.x] ^= self.regs[self.inst.y];
    }

    fn shr(&mut self) {
        let idx_x = self.inst.x;
        let x     = self.regs[idx_x];
        self.regs[0xF] = x & 0x1;
        self.regs[idx_x] = x >> 1;
    }

    fn shl(&mut self) {
        let x = self.regs[self.inst.x];
        let y = self.regs[self.inst.y];

        self.regs[0xF] = ((x & 0xF0) >> 7 == 1) as u8;
        self.regs[self.inst.x] *= 2;
    }

    fn ld_vv(&mut self) {
        self.regs[self.inst.x] = self.regs[self.inst.y];
    }

    fn ld_vb(&mut self) {
        self.regs[self.inst.x] = self.inst.kk;
    }

    fn ld_bv(&mut self) {
        let x = self.regs[self.inst.x];

        self.mem[self.i as usize]     = x / 100;
        self.mem[self.i as usize + 1] = (x / 100) % 10;
        self.mem[self.i as usize + 2] = (x % 100) % 10;
    }

    fn ld_fv(&mut self) {
        let x = self.regs[self.inst.x];
        self.i = (x * 5) as u16;
    }

    fn ld_vi(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.regs[i] = self.mem[self.i as usize + i];
        }
    }

    fn ld_iv(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.mem[self.i as usize + i] = self.regs[i];
        }
    }

    fn ld_ia(&mut self) {
        self.i = self.inst.nnn;
    }

    fn ld_vk(&mut self) {
        let mut key_pressed = false;

        for i in 0..self.keys.len() {
            if self.keys[i] == 1 {
                self.regs[self.inst.x] = i as u8;
                key_pressed = true;
            }
        }

        if !key_pressed {
            self.dec_pc();
        }
    }

    fn ld_vdt(&mut self) {
        self.regs[self.inst.x] = self.dt;
    }

    fn ld_dtv(&mut self) {
        self.dt = self.regs[self.inst.x];
    }

    fn ld_stv(&mut self) {
        self.st = self.regs[self.inst.x];
    }

    fn rnd(&mut self) {
        self.regs[self.inst.x] = thread_rng().gen::<u8>() & self.inst.kk;
    }

    fn drw(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let (x, y) = (self.regs[idx_x] as usize, self.regs[idx_y] as usize);
        let n = self.inst.n as usize;

        self.screen.renderer.clear();
        self.regs[0xF] = 0;

        for i in 0..n {
            let px = self.mem[(self.i + i as u16) as usize];
            for j in 0..8 {
                if px & (0x80 >> j) != 0 {
                    let mut offset = (x+j+(y+i)*64) as u16;

                    offset = if offset >= 64*32 {
                        64*32-1
                    } else {
                        offset
                    };

                    if self.screen.buffer[offset as usize] == 1 {
                        self.regs[0xF] = 1;
                    }
                    self.screen.buffer[offset as usize] ^= 1;
                }
            }
        }

        for i in 0usize..32*10 {
            for j in 0usize..64*10 {
                if self.screen.buffer[(j/10)+(i/10)*64] == 1 {
                    self.screen.renderer.fill_rect(
                        Rect::new(j as i32, i as i32, 1, 1)
                        );
                }
            }
        }

        self.screen.draw();
    }

    fn skp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 1{
            self.inc_pc();
        }
    }

    fn sknp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 0 {
            self.inc_pc();
        }
    }
    pub fn reset_keys(&mut self) {
        self.keys = [0;16];
    }

    pub fn press(&mut self, key: u8) {
        self.keys[key as usize] = 1;
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

const INPUT: &'static str = include_str!("data/day19.txt");

pub fn part1() -> usize {
    calculate_part1(INPUT)
}

pub fn part2() -> usize {
    calculate_part2(INPUT)
}

fn calculate_part1(input: &str) -> usize {
    let (replacements, molecule) = parse(input);
    let mut variations: HashSet<String> = HashSet::new();

    for (target, replacement) in replacements.into_iter() {
        replace(molecule, target, replacement, &mut variations);
    }

    variations.len()
}

fn calculate_part2(_: &str) -> usize {
    0
}

fn parse(input: &str) -> (Vec<(&str, &str)>, &str) {
    let mut replacements: Vec<(&str, &str)> = Vec::new();
    let mut molecule = "";
    let mut last_line = false;

    for line in input.lines() {
        if last_line {
            molecule = line;
            break
        }

        if line.is_empty() {
            last_line = true;
            continue
        }

        let replacement: Vec<&str> = line.split(" => ").collect();
        replacements.push((replacement[0], replacement[1]));
    }

    (replacements, molecule)
}

fn replace(input: &str, target: &str, replacement: &str, variations: &mut HashSet<String>) {
    let splits: Vec<_> = input.split(target).collect();

    if splits.len() < 2 {
        return
    }

    for i in 1..splits.len() {
        let mut result = String::from(splits[0]);
        for j in 1..splits.len() {
            if i == j {
                result.push_str(replacement);
            } else {
                result.push_str(target);
            }
            result.push_str(splits[j]);
        }
        variations.insert(result);
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashSet;
    #[test]
    fn parse() {
        let input = "H => HO\n\
                     H => OH\n\
                     O => HH\n\
                     \n\
                     HOH";

        let (replacements, _) = super::parse(input);
        println!("{:?}", replacements);
        assert_eq!(3, replacements.len());
    }

    #[test]
    fn part1_test1() {
        let input = "H => HO\n\
                     H => OH\n\
                     O => HH\n\
                     \n\
                     HOH";

        let (replacements, molecule) = super::parse(input);
        let mut variations: HashSet<String> = HashSet::new();

        for (target, replacement) in replacements.into_iter() {
            super::replace(molecule, target, replacement, &mut variations);
        }

        assert_eq!(4, variations.len());
    }
}
<commit_msg>improve tests for day 19 part 1<commit_after>use std::collections::HashSet;

const INPUT: &'static str = include_str!("data/day19.txt");

pub fn part1() -> usize {
    calculate_part1(INPUT)
}

pub fn part2() -> usize {
    calculate_part2(INPUT)
}

fn calculate_part1(input: &str) -> usize {
    let (replacements, molecule) = parse(input);
    let mut variations: HashSet<String> = HashSet::new();

    for (target, replacement) in replacements.into_iter() {
        replace(molecule, target, replacement, &mut variations);
    }

    variations.len()
}

fn calculate_part2(_: &str) -> usize {
    0
}

fn parse(input: &str) -> (Vec<(&str, &str)>, &str) {
    let mut replacements: Vec<(&str, &str)> = Vec::new();
    let mut molecule = "";
    let mut last_line = false;

    for line in input.lines() {
        if last_line {
            molecule = line;
            break
        }

        if line.is_empty() {
            last_line = true;
            continue
        }

        let replacement: Vec<&str> = line.split(" => ").collect();
        replacements.push((replacement[0], replacement[1]));
    }

    (replacements, molecule)
}

fn replace(input: &str, target: &str, replacement: &str, variations: &mut HashSet<String>) {
    let splits: Vec<_> = input.split(target).collect();

    if splits.len() < 2 {
        return
    }

    for i in 1..splits.len() {
        let mut result = String::from(splits[0]);
        for j in 1..splits.len() {
            if i == j {
                result.push_str(replacement);
            } else {
                result.push_str(target);
            }
            result.push_str(splits[j]);
        }
        variations.insert(result);
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashSet;
    #[test]
    fn parse() {
        let input = "H => HO\n\
                     H => OH\n\
                     O => HH\n\
                     \n\
                     HOH";

        let (replacements, molecule) = super::parse(input);

        assert_eq!(3, replacements.len());
        assert_eq!("HOH", molecule);
    }

    #[test]
    fn part1_test1() {
        let molecule = "HOH";
        let replacements = vec![("H", "HO"), ("H",  "OH"), ("O", "HH")];
        let mut variations: HashSet<String> = HashSet::new();

        for (target, replacement) in replacements.into_iter() {
            super::replace(molecule, target, replacement, &mut variations);
        }

        assert_eq!(4, variations.len());
    }

    #[test]
    fn part1_test2() {
        let molecule = "HOHOHO";
        let replacements = vec![("H", "HO"), ("H",  "OH"), ("O", "HH")];
        let mut variations: HashSet<String> = HashSet::new();

        for (target, replacement) in replacements.into_iter() {
            super::replace(molecule, target, replacement, &mut variations);
        }

        assert_eq!(7, variations.len());
    }
}
<|endoftext|>


<commit_before>use super::error::{Result, ResultExt};
use super::{Response, ResponseError, ResponseInfo};
use serde::{Deserialize, Serialize};
use xml_rpc::{self, Params, Uri, Value};

pub struct Client {
    master_uri: Uri,
}

impl Client {
    pub fn new(master_uri: &str) -> Result<Client> {
        let master_uri = master_uri.parse().chain_err(|| "Bad Master URI provided")?;
        Ok(Client { master_uri })
    }

    pub fn request_tree_with_tree(&self, name: &str, params: Params) -> Response<Value> {
        let call_result = xml_rpc::call_value(&self.master_uri, name, params);

        let server_response = call_result.map_err(|err| {
            ResponseError::Client(format!("Failed to perform call to server: {}", err))
        })?;

        let response_parameters = server_response.map_err(|fault| {
            ResponseError::Client(format!(
                "Unexpected fault #{} received from server: {}",
                fault.code, fault.message
            ))
        })?;

        let response_parameters = remove_array_wrappers(&response_parameters[..]);

        ResponseInfo::from_array(response_parameters)?.into()
    }

    pub fn request_tree<S>(&self, name: &str, params: &S) -> Response<Value>
    where
        S: Serialize,
    {
        let params = xml_rpc::into_params(params).map_err(bad_request_structure)?;
        self.request_tree_with_tree(name, params)
    }

    pub fn request<'a, S, D>(&self, name: &str, params: &S) -> Response<D>
    where
        S: Serialize,
        D: Deserialize<'a>,
    {
        let data = self.request_tree(name, params)?;
        Deserialize::deserialize(data).map_err(bad_response_structure)
    }
}

fn remove_array_wrappers(mut data: &[Value]) -> &[Value] {
    while let [Value::Array(ref children), _] = data[..] {
        data = children;
    }
    data
}

fn bad_request_structure<T: ::std::fmt::Display>(err: T) -> ResponseError {
    ResponseError::Client(format!("Failed to serialize parameters: {}", err))
}

fn bad_response_structure<T: ::std::fmt::Display>(err: T) -> ResponseError {
    ResponseError::Server(format!("Response data has unexpected structure: {}", err))
}
<commit_msg>Fixes lack of matching when array is size 1.<commit_after>use super::error::{Result, ResultExt};
use super::{Response, ResponseError, ResponseInfo};
use serde::{Deserialize, Serialize};
use xml_rpc::{self, Params, Uri, Value};

pub struct Client {
    master_uri: Uri,
}

impl Client {
    pub fn new(master_uri: &str) -> Result<Client> {
        let master_uri = master_uri.parse().chain_err(|| "Bad Master URI provided")?;
        Ok(Client { master_uri })
    }

    pub fn request_tree_with_tree(&self, name: &str, params: Params) -> Response<Value> {
        let call_result = xml_rpc::call_value(&self.master_uri, name, params);

        let server_response = call_result.map_err(|err| {
            ResponseError::Client(format!("Failed to perform call to server: {}", err))
        })?;

        let response_parameters = server_response.map_err(|fault| {
            ResponseError::Client(format!(
                "Unexpected fault #{} received from server: {}",
                fault.code, fault.message
            ))
        })?;

        let response_parameters = remove_array_wrappers(&response_parameters[..]);

        ResponseInfo::from_array(response_parameters)?.into()
    }

    pub fn request_tree<S>(&self, name: &str, params: &S) -> Response<Value>
    where
        S: Serialize,
    {
        let params = xml_rpc::into_params(params).map_err(bad_request_structure)?;
        self.request_tree_with_tree(name, params)
    }

    pub fn request<'a, S, D>(&self, name: &str, params: &S) -> Response<D>
    where
        S: Serialize,
        D: Deserialize<'a>,
    {
        let data = self.request_tree(name, params)?;
        Deserialize::deserialize(data).map_err(bad_response_structure)
    }
}

fn remove_array_wrappers(mut data: &[Value]) -> &[Value] {
    while let [Value::Array(ref children)] = data[..] {
        data = children;
    }
    data
}

fn bad_request_structure<T: ::std::fmt::Display>(err: T) -> ResponseError {
    ResponseError::Client(format!("Failed to serialize parameters: {}", err))
}

fn bad_response_structure<T: ::std::fmt::Display>(err: T) -> ResponseError {
    ResponseError::Server(format!("Response data has unexpected structure: {}", err))
}
<|endoftext|>


<commit_before>use std::{fs::File, sync::Arc};

use actix_web::{post, web, App, HttpServer, Responder};
use clap::Parser;
use cmd_queue::{
    constants::{self, DEFAULT_PORT},
    CommandFailed, CommandQApp, CommandRequest, CommandResponse, CommandSuccess, ListRequest,
};
use daemonize::Daemonize;

#[derive(Parser, Debug)]
#[clap(name = "cmdq_server")]
#[clap(author = "Jonathan Fok kan <jonathan@fokkan.ca>")]
#[clap(version = "1.0")]
#[clap(about = "cmdq server", long_about = None)]
struct ServerCli {
    #[clap(long, short, help = "Daemonize server process")]
    daemon: bool,
}

#[post("/commands")]
async fn queue_command(
    app: web::Data<Arc<CommandQApp>>,
    command: web::Json<CommandRequest>,
) -> impl Responder {
    println!("queue command {:?}", command);
    // TODO better error handling
    match app.queue.push_cmd(&command) {
        Ok(_) => web::Json(CommandResponse::Success(CommandSuccess {})),
        Err(_) => web::Json(CommandResponse::Failed(CommandFailed {})),
    }
}

#[post("/commands/list")]
async fn list_tasks(
    app: web::Data<Arc<CommandQApp>>,
    request: web::Json<ListRequest>,
) -> impl Responder {
    let tasks = app.queue.list(
        request
            .state_filters
            .as_ref()
            .unwrap_or(&Vec::new())
            .to_vec(),
    );

    web::Json(tasks)
}

async fn health() -> impl Responder {
    "UP"
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let cli = ServerCli::parse();
    if cli.daemon {
        daemonize();
    }
    let cmdq_app = Arc::new(CommandQApp::new());

    HttpServer::new(move || {
        App::new()
            .data(cmdq_app.clone())
            .service(queue_command)
            .service(list_tasks)
            // .service(
            //     web::scope("/commands")
            //         .route("/", web::post().to(queue_command))
            //         .route("/", web::method().to(list_tasks)),
            // )
            .service(web::resource("/health").to(health))
    })
    .bind(format!("127.0.0.1:{}", DEFAULT_PORT))?
    .run()
    .await
}

fn daemonize() {
    std::fs::create_dir_all(constants::SERVER_DAEMON_DIR).unwrap();
    let stdout = File::create(constants::SERVER_DAEMON_OUTFILE).unwrap();
    let stderr = File::create(constants::SERVER_DAEMON_ERRFILE).unwrap();

    let daemonize = Daemonize::new()
        .pid_file(constants::SERVER_DAEMON_PIDFILE) // Every method except `new` and `start`
        .working_directory(constants::SERVER_DAEMON_DIR) // for default behaviour.
        .stdout(stdout) // Redirect stdout to `/tmp/daemon.out`.
        .stderr(stderr) // Redirect stderr to `/tmp/daemon.err`.
        .exit_action(|| println!("Server started as daemon"))
        .privileged_action(|| "Executed before drop privileges");

    match daemonize.start() {
        Ok(_) => println!("Success, daemonized"),
        Err(e) => eprintln!("Error starting server as daemon. error={}", e),
    }
}
<commit_msg>cmd-queue: Fixed server start bug<commit_after>use std::{fs::File, sync::Arc};

use actix_web::{post, web, App, HttpServer, Responder};
use clap::Parser;
use cmd_queue::{
    constants::{self, DEFAULT_PORT},
    CommandFailed, CommandQApp, CommandRequest, CommandResponse, CommandSuccess, ListRequest,
};
use daemonize::Daemonize;

#[derive(Parser, Debug)]
#[clap(name = "cmdq_server")]
#[clap(author = "Jonathan Fok kan <jonathan@fokkan.ca>")]
#[clap(version = "1.0")]
#[clap(about = "cmdq server", long_about = None)]
struct ServerCli {
    #[clap(long, short, help = "Daemonize server process")]
    daemon: bool,
}

#[post("/commands")]
async fn queue_command(
    app: web::Data<Arc<CommandQApp>>,
    command: web::Json<CommandRequest>,
) -> impl Responder {
    println!("queue command {:?}", command);
    // TODO better error handling
    match app.queue.push_cmd(&command) {
        Ok(_) => web::Json(CommandResponse::Success(CommandSuccess {})),
        Err(_) => web::Json(CommandResponse::Failed(CommandFailed {})),
    }
}

#[post("/commands/list")]
async fn list_tasks(
    app: web::Data<Arc<CommandQApp>>,
    request: web::Json<ListRequest>,
) -> impl Responder {
    let tasks = app.queue.list(
        request
            .state_filters
            .as_ref()
            .unwrap_or(&Vec::new())
            .to_vec(),
    );

    web::Json(tasks)
}

async fn health() -> impl Responder {
    "UP"
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let cli = ServerCli::parse();
    if cli.daemon {
        daemonize();
    }
    let cmdq_app = Arc::new(CommandQApp::new().expect("Failed to start server"));

    HttpServer::new(move || {
        App::new()
            .data(cmdq_app.clone())
            .service(queue_command)
            .service(list_tasks)
            // .service(
            //     web::scope("/commands")
            //         .route("/", web::post().to(queue_command))
            //         .route("/", web::method().to(list_tasks)),
            // )
            .service(web::resource("/health").to(health))
    })
    .bind(format!("127.0.0.1:{}", DEFAULT_PORT))?
    .run()
    .await
}

fn daemonize() {
    std::fs::create_dir_all(constants::SERVER_DAEMON_DIR).unwrap();
    let stdout = File::create(constants::SERVER_DAEMON_OUTFILE).unwrap();
    let stderr = File::create(constants::SERVER_DAEMON_ERRFILE).unwrap();

    let daemonize = Daemonize::new()
        .pid_file(constants::SERVER_DAEMON_PIDFILE) // Every method except `new` and `start`
        .working_directory(constants::SERVER_DAEMON_DIR) // for default behaviour.
        .stdout(stdout) // Redirect stdout to `/tmp/daemon.out`.
        .stderr(stderr) // Redirect stderr to `/tmp/daemon.err`.
        .exit_action(|| println!("Server started as daemon"))
        .privileged_action(|| "Executed before drop privileges");

    match daemonize.start() {
        Ok(_) => println!("Success, daemonized"),
        Err(e) => eprintln!("Error starting server as daemon. error={}", e),
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::cmp;
use std::io;
use std::net::{Ipv4Addr, SocketAddr};
use std::rc::{Rc, Weak};
use log::LogLevel;
use mio::{Event, PollOpt, Ready, Token};
use mio::net::TcpStream;

use super::binary;
use super::client::Client;
use super::connection::{self, Connection, ConnectionId};
use super::ipv4_header::IPv4Header;
use super::ipv4_packet::{IPv4Packet, MAX_PACKET_LENGTH};
use super::packetizer::Packetizer;
use super::selector::Selector;
use super::stream_buffer::StreamBuffer;
use super::tcp_header::{self, TCPHeader};
use super::transport_header::{TransportHeader, TransportHeaderMut};

const TAG: &'static str = "TCPConnection";

const MAX_PAYLOAD_LENGTH: u16 = 1400;

pub struct TCPConnection {
    id: ConnectionId,
    client: Weak<RefCell<Client>>,
    stream: TcpStream,
    token: Token,
    client_to_network: StreamBuffer,
    network_to_client: Packetizer,
    packet_for_client_length: Option<u16>,
    closed: bool,
    tcb: TCB,
}

struct TCB {
    state: TCPState,
    syn_sequence_number: u32,
    sequence_number: u32,
    acknowledgement_number: u32,
    their_acknowledgement_number: u32,
    client_window: u16,
    remote_closed: bool,
}

#[derive(PartialEq, Eq)]
enum TCPState {
    Init,
    SynSent,
//    SynReceived,
    Established,
    CloseWait,
    LastAck,
}

impl TCB {
    fn new() -> Self {
        Self {
            state: TCPState::Init,
            syn_sequence_number: 0,
            sequence_number: 0,
            acknowledgement_number: 0,
            their_acknowledgement_number: 0,
            client_window: 0,
            remote_closed: false,
        }
    }

    fn numbers(&self) -> String {
        format!("(seq={}, ack={})", self.sequence_number, self.acknowledgement_number)
    }
}

impl TCPConnection {
    pub fn new(selector: &mut Selector, id: ConnectionId, client: Weak<RefCell<Client>>, ipv4_header: &IPv4Header, transport_header: &TransportHeader) -> io::Result<Rc<RefCell<Self>>> {
        let stream = TCPConnection::create_stream(&id)?;

        if let TransportHeader::TCP(ref tcp_header) = *transport_header {
            // shrink the TCP options to pass a minimal refrence header to the packetizer
            let mut shrinked_tcp_header_raw = [0u8; 20];
            shrinked_tcp_header_raw.copy_from_slice(&tcp_header.raw()[..20]);
            let mut shrinked_tcp_header_data = tcp_header.data().clone();
            {
                let mut shrinked_tcp_header = shrinked_tcp_header_data.bind_mut(&mut shrinked_tcp_header_raw);
                shrinked_tcp_header.shrink_options();
                assert_eq!(20, shrinked_tcp_header.header_length());
            }

            let shrinked_transport_header = shrinked_tcp_header_data.bind(&shrinked_tcp_header_raw).into();

            let packetizer = Packetizer::new(&ipv4_header, &shrinked_transport_header);

            let rc = Rc::new(RefCell::new(Self {
                id: id,
                client: client,
                stream: stream,
                token: Token(0), // default value, will be set afterwards
                client_to_network: StreamBuffer::new(4 * MAX_PACKET_LENGTH),
                network_to_client: packetizer,
                packet_for_client_length: None,
                closed: false,
                tcb: TCB::new(),
            }));

            {
                let rc_clone = rc.clone();
                let handler = move |selector: &mut Selector, ready| {
                    let mut self_ref = rc_clone.borrow_mut();
                    self_ref.on_ready(selector, ready);
                };
                let mut self_ref = rc.borrow_mut();
                let token = selector.register(&self_ref.stream, handler, Ready::readable(), PollOpt::level())?;
                self_ref.token = token;
            }
            Ok(rc)
        } else {
            panic!("Not a TCP header");
        }
    }

    fn create_stream(id: &ConnectionId) -> io::Result<TcpStream> {
        let rewritten_destination = connection::rewritten_destination(id.destination_ip(), id.destination_port()).into();
        TcpStream::connect(&rewritten_destination)
    }

    fn close(&mut self, selector: &mut Selector) {

    }

    fn process_send(&mut self, selector: &mut Selector) {
        match self.client_to_network.write_to(&mut self.stream) {
            Ok(w) => if w == 0 {
                self.close(selector);
            },
            Err(err) => {
                error!(target: TAG, "{} Cannot write: {}", self.id, err);
                self.reset_connection(selector);
            }
        }
    }

    fn process_receive(&mut self, selector: &mut Selector) {
        assert!(self.packet_for_client_length.is_none(), "A pending packet was not sent");
        let remaining_client_window = self.get_remaining_client_window();
        assert!(remaining_client_window > 0, "process_received() must not be called when window == 0");
        let max_payload_length = cmp::min(remaining_client_window, MAX_PAYLOAD_LENGTH) as usize;
        TCPConnection::update_headers(&mut self.network_to_client, &self.tcb, tcp_header::FLAG_ACK | tcp_header::FLAG_PSH);
        // the packet is bound to the lifetime of self, so we cannot borrow self to call methods
        // defer the other branches in a separate match-block
        let non_lexical_lifetime_workaround = match self.network_to_client.packetize_read(&mut self.stream, Some(max_payload_length)) {
            Ok(Some(ipv4_packet)) => {
                // TODO send packet
                Ok(Some(()))
            },
            Ok(None) => Ok(None),
            Err(err) => Err(err),
        };
        match non_lexical_lifetime_workaround {
            Ok(None) => self.eof(selector),
            Err(err) => {
                error!(target: TAG, "{} Cannot read: {}", self.id, err);
                self.reset_connection(selector);
            },
            Ok(Some(_)) => () // already handled
        }
        // TODO
    }

    fn eof(&mut self, selector: &mut Selector) {
        self.tcb.remote_closed = true;
        if self.tcb.state == TCPState::CloseWait {
            let ipv4_packet = TCPConnection::create_empty_response_packet(&self.id, &mut self.network_to_client, &self.tcb, tcp_header::FLAG_FIN);
            self.tcb.sequence_number += 1; // FIN counts for 1 byte

            let client_rc = self.client.upgrade().expect("expected client not found");
            let mut client = client_rc.borrow_mut();
            if let Err(err) = client.send_to_client(selector, &ipv4_packet) {
                warn!(target: TAG, "{} Cannot send packet to client: {}", &self.id, err);
            }
        }
    }

    fn update_headers(packetizer: &mut Packetizer, tcb: &TCB, flags: u16) {
        if let TransportHeaderMut::TCP(ref mut tcp_header) = packetizer.transport_header_mut() {
            tcp_header.set_sequence_number(tcb.sequence_number);
            tcp_header.set_acknowledgement_number(tcb.acknowledgement_number);
            tcp_header.set_flags(flags);
        } else {
            panic!("Not a TCP header");
        }
    }

    fn create_empty_response_packet<'a>(id: &ConnectionId, packetizer: &'a mut Packetizer, tcb: &TCB, flags: u16) -> IPv4Packet<'a> {
        TCPConnection::update_headers(packetizer, tcb, flags);
        debug!(target: TAG, "{} Forging empty response (flags={}) {}", id, flags, tcb.numbers());
        if (flags & tcp_header::FLAG_ACK) != 0 {
            debug!(target: TAG, "{} Acking {}", id, tcb.numbers());
        }
        let ipv4_packet = packetizer.packetize_empty_payload();
        if log_enabled!(target: TAG, LogLevel::Trace) {
            binary::to_string(ipv4_packet.raw());
        }
        ipv4_packet
    }

    fn reset_connection(&mut self, selector: &mut Selector) {
        // TODO
    }

    fn update_interests(&mut self, selector: &mut Selector) {
        if !self.closed {
            let mut ready = Ready::empty();
            if self.may_read() {
                ready = ready | Ready::readable()
            }
            if self.may_write() {
                ready = ready | Ready::writable()
            }
            selector.reregister(&self.stream, self.token, ready, PollOpt::level()).expect("Cannot register on poll");
        }
    }

    fn may_read(&self) -> bool {
        !self.tcb.remote_closed &&
                self.packet_for_client_length.is_some() &&
                self.get_remaining_client_window() > 0
    }

    fn may_write(&self) -> bool {
        !self.client_to_network.is_empty()
    }

    fn on_ready(&mut self, selector: &mut Selector, event: Event) {
        assert!(!self.closed);
        let ready = event.readiness();
        if ready.is_writable() {
            self.process_send(selector);
        }
        if !self.closed && ready.is_readable() {
            self.process_receive(selector);
        }
        if !self.closed {
            self.update_interests(selector);
        }
    }

    fn get_remaining_client_window(&self) -> u16 {
        // TODO
        42
    }
}

impl Connection for TCPConnection {
    fn id(&self) -> &ConnectionId {
        &self.id
    }

    fn send_to_network(&mut self, selector: &mut Selector, ipv4_packet: &IPv4Packet) {
        // TODO
    }

    fn disconnect(&mut self, selector: &mut Selector) {
        info!(target: TAG, "{} Close", self.id);
        selector.deregister(&self.stream, self.token).unwrap();
        // socket will be closed by RAII
    }

    fn is_expired(&self) -> bool {
        // no external timeout expiration
        false
    }
}
<commit_msg>Factorize TCPConnection.send_to_client()<commit_after>use std::cell::RefCell;
use std::cmp;
use std::io;
use std::net::{Ipv4Addr, SocketAddr};
use std::rc::{Rc, Weak};
use log::LogLevel;
use mio::{Event, PollOpt, Ready, Token};
use mio::net::TcpStream;

use super::binary;
use super::client::Client;
use super::connection::{self, Connection, ConnectionId};
use super::ipv4_header::IPv4Header;
use super::ipv4_packet::{IPv4Packet, MAX_PACKET_LENGTH};
use super::packetizer::Packetizer;
use super::selector::Selector;
use super::stream_buffer::StreamBuffer;
use super::tcp_header::{self, TCPHeader};
use super::transport_header::{TransportHeader, TransportHeaderMut};

const TAG: &'static str = "TCPConnection";

const MAX_PAYLOAD_LENGTH: u16 = 1400;

pub struct TCPConnection {
    id: ConnectionId,
    client: Weak<RefCell<Client>>,
    stream: TcpStream,
    token: Token,
    client_to_network: StreamBuffer,
    network_to_client: Packetizer,
    packet_for_client_length: Option<u16>,
    closed: bool,
    tcb: TCB,
}

struct TCB {
    state: TCPState,
    syn_sequence_number: u32,
    sequence_number: u32,
    acknowledgement_number: u32,
    their_acknowledgement_number: u32,
    client_window: u16,
    remote_closed: bool,
}

#[derive(PartialEq, Eq)]
enum TCPState {
    Init,
    SynSent,
//    SynReceived,
    Established,
    CloseWait,
    LastAck,
}

impl TCB {
    fn new() -> Self {
        Self {
            state: TCPState::Init,
            syn_sequence_number: 0,
            sequence_number: 0,
            acknowledgement_number: 0,
            their_acknowledgement_number: 0,
            client_window: 0,
            remote_closed: false,
        }
    }

    fn numbers(&self) -> String {
        format!("(seq={}, ack={})", self.sequence_number, self.acknowledgement_number)
    }
}

impl TCPConnection {
    pub fn new(selector: &mut Selector, id: ConnectionId, client: Weak<RefCell<Client>>, ipv4_header: &IPv4Header, transport_header: &TransportHeader) -> io::Result<Rc<RefCell<Self>>> {
        let stream = TCPConnection::create_stream(&id)?;

        if let TransportHeader::TCP(ref tcp_header) = *transport_header {
            // shrink the TCP options to pass a minimal refrence header to the packetizer
            let mut shrinked_tcp_header_raw = [0u8; 20];
            shrinked_tcp_header_raw.copy_from_slice(&tcp_header.raw()[..20]);
            let mut shrinked_tcp_header_data = tcp_header.data().clone();
            {
                let mut shrinked_tcp_header = shrinked_tcp_header_data.bind_mut(&mut shrinked_tcp_header_raw);
                shrinked_tcp_header.shrink_options();
                assert_eq!(20, shrinked_tcp_header.header_length());
            }

            let shrinked_transport_header = shrinked_tcp_header_data.bind(&shrinked_tcp_header_raw).into();

            let packetizer = Packetizer::new(&ipv4_header, &shrinked_transport_header);

            let rc = Rc::new(RefCell::new(Self {
                id: id,
                client: client,
                stream: stream,
                token: Token(0), // default value, will be set afterwards
                client_to_network: StreamBuffer::new(4 * MAX_PACKET_LENGTH),
                network_to_client: packetizer,
                packet_for_client_length: None,
                closed: false,
                tcb: TCB::new(),
            }));

            {
                let rc_clone = rc.clone();
                let handler = move |selector: &mut Selector, ready| {
                    let mut self_ref = rc_clone.borrow_mut();
                    self_ref.on_ready(selector, ready);
                };
                let mut self_ref = rc.borrow_mut();
                let token = selector.register(&self_ref.stream, handler, Ready::readable(), PollOpt::level())?;
                self_ref.token = token;
            }
            Ok(rc)
        } else {
            panic!("Not a TCP header");
        }
    }

    fn create_stream(id: &ConnectionId) -> io::Result<TcpStream> {
        let rewritten_destination = connection::rewritten_destination(id.destination_ip(), id.destination_port()).into();
        TcpStream::connect(&rewritten_destination)
    }

    fn close(&mut self, selector: &mut Selector) {

    }

    fn process_send(&mut self, selector: &mut Selector) {
        match self.client_to_network.write_to(&mut self.stream) {
            Ok(w) => if w == 0 {
                self.close(selector);
            },
            Err(err) => {
                error!(target: TAG, "{} Cannot write: {}", self.id, err);
                self.reset_connection(selector);
            }
        }
    }

    fn process_receive(&mut self, selector: &mut Selector) {
        assert!(self.packet_for_client_length.is_none(), "A pending packet was not sent");
        let remaining_client_window = self.get_remaining_client_window();
        assert!(remaining_client_window > 0, "process_received() must not be called when window == 0");
        let max_payload_length = cmp::min(remaining_client_window, MAX_PAYLOAD_LENGTH) as usize;
        TCPConnection::update_headers(&mut self.network_to_client, &self.tcb, tcp_header::FLAG_ACK | tcp_header::FLAG_PSH);
        // the packet is bound to the lifetime of self, so we cannot borrow self to call methods
        // defer the other branches in a separate match-block
        let non_lexical_lifetime_workaround = match self.network_to_client.packetize_read(&mut self.stream, Some(max_payload_length)) {
            Ok(Some(ipv4_packet)) => {
                // TODO send packet
                Ok(Some(()))
            },
            Ok(None) => Ok(None),
            Err(err) => Err(err),
        };
        match non_lexical_lifetime_workaround {
            Ok(None) => self.eof(selector),
            Err(err) => {
                error!(target: TAG, "{} Cannot read: {}", self.id, err);
                self.reset_connection(selector);
            },
            Ok(Some(_)) => () // already handled
        }
        // TODO
    }

    fn send_to_client(client: &Weak<RefCell<Client>>, selector: &mut Selector, ipv4_packet: &IPv4Packet) -> io::Result<()> {
        let client_rc = client.upgrade().expect("expected client not found");
        let mut client = client_rc.borrow_mut();
        client.send_to_client(selector, &ipv4_packet)
    }

    fn eof(&mut self, selector: &mut Selector) {
        self.tcb.remote_closed = true;
        if self.tcb.state == TCPState::CloseWait {
            let ipv4_packet = TCPConnection::create_empty_response_packet(&self.id, &mut self.network_to_client, &self.tcb, tcp_header::FLAG_FIN);
            self.tcb.sequence_number += 1; // FIN counts for 1 byte

            if let Err(err) = TCPConnection::send_to_client(&self.client, selector, &ipv4_packet) {
                warn!(target: TAG, "{} Cannot send packet to client: {}", &self.id, err);
            }
        }
    }

    fn update_headers(packetizer: &mut Packetizer, tcb: &TCB, flags: u16) {
        if let TransportHeaderMut::TCP(ref mut tcp_header) = packetizer.transport_header_mut() {
            tcp_header.set_sequence_number(tcb.sequence_number);
            tcp_header.set_acknowledgement_number(tcb.acknowledgement_number);
            tcp_header.set_flags(flags);
        } else {
            panic!("Not a TCP header");
        }
    }

    fn create_empty_response_packet<'a>(id: &ConnectionId, packetizer: &'a mut Packetizer, tcb: &TCB, flags: u16) -> IPv4Packet<'a> {
        TCPConnection::update_headers(packetizer, tcb, flags);
        debug!(target: TAG, "{} Forging empty response (flags={}) {}", id, flags, tcb.numbers());
        if (flags & tcp_header::FLAG_ACK) != 0 {
            debug!(target: TAG, "{} Acking {}", id, tcb.numbers());
        }
        let ipv4_packet = packetizer.packetize_empty_payload();
        if log_enabled!(target: TAG, LogLevel::Trace) {
            binary::to_string(ipv4_packet.raw());
        }
        ipv4_packet
    }

    fn reset_connection(&mut self, selector: &mut Selector) {
        // TODO
    }

    fn update_interests(&mut self, selector: &mut Selector) {
        if !self.closed {
            let mut ready = Ready::empty();
            if self.may_read() {
                ready = ready | Ready::readable()
            }
            if self.may_write() {
                ready = ready | Ready::writable()
            }
            selector.reregister(&self.stream, self.token, ready, PollOpt::level()).expect("Cannot register on poll");
        }
    }

    fn may_read(&self) -> bool {
        !self.tcb.remote_closed &&
                self.packet_for_client_length.is_some() &&
                self.get_remaining_client_window() > 0
    }

    fn may_write(&self) -> bool {
        !self.client_to_network.is_empty()
    }

    fn on_ready(&mut self, selector: &mut Selector, event: Event) {
        assert!(!self.closed);
        let ready = event.readiness();
        if ready.is_writable() {
            self.process_send(selector);
        }
        if !self.closed && ready.is_readable() {
            self.process_receive(selector);
        }
        if !self.closed {
            self.update_interests(selector);
        }
    }

    fn get_remaining_client_window(&self) -> u16 {
        // TODO
        42
    }
}

impl Connection for TCPConnection {
    fn id(&self) -> &ConnectionId {
        &self.id
    }

    fn send_to_network(&mut self, selector: &mut Selector, ipv4_packet: &IPv4Packet) {
        // TODO
    }

    fn disconnect(&mut self, selector: &mut Selector) {
        info!(target: TAG, "{} Close", self.id);
        selector.deregister(&self.stream, self.token).unwrap();
        // socket will be closed by RAII
    }

    fn is_expired(&self) -> bool {
        // no external timeout expiration
        false
    }
}
<|endoftext|>


<commit_before>// Each function in this crate is used in a single place: a corresponding C++ wrapper. It doesn't
// make sense to document these functions because they are basically an internal detail and don't
// stand on their own.
#![allow(clippy::missing_safety_doc)]
// This lint is nitpicky, I don't think it's really important how the literals are written.
#![allow(clippy::unreadable_literal)]

use libc::c_char;
use std::ffi::CString;
use std::panic::{catch_unwind, UnwindSafe};
use std::process::abort;

pub mod cliargsparser;
pub mod configpaths;
pub mod fmtstrformatter;
pub mod fslock;
pub mod history;
pub mod human_panic;
pub mod keymap;
pub mod logger;
pub mod matchererror;
pub mod scopemeasure;
pub mod utils;

/// Runs a Rust function, and if it panics, calls abort(); otherwise returns what function
/// returned.
fn abort_on_panic<F: FnOnce() -> R + UnwindSafe, R>(function: F) -> R {
    match catch_unwind(function) {
        Ok(result) => result,
        Err(_cause) => abort(),
    }
}

#[no_mangle]
pub unsafe extern "C" fn rs_cstring_free(string: *mut c_char) {
    abort_on_panic(|| {
        if string.is_null() {
            return;
        }
        CString::from_raw(string);
    })
}
<commit_msg>Quick-fix of uncaught (by CI) clippy warning<commit_after>// Each function in this crate is used in a single place: a corresponding C++ wrapper. It doesn't
// make sense to document these functions because they are basically an internal detail and don't
// stand on their own.
#![allow(clippy::missing_safety_doc)]
// This lint is nitpicky, I don't think it's really important how the literals are written.
#![allow(clippy::unreadable_literal)]

use libc::c_char;
use std::ffi::CString;
use std::panic::{catch_unwind, UnwindSafe};
use std::process::abort;

pub mod cliargsparser;
pub mod configpaths;
pub mod fmtstrformatter;
pub mod fslock;
pub mod history;
pub mod human_panic;
pub mod keymap;
pub mod logger;
pub mod matchererror;
pub mod scopemeasure;
pub mod utils;

/// Runs a Rust function, and if it panics, calls abort(); otherwise returns what function
/// returned.
fn abort_on_panic<F: FnOnce() -> R + UnwindSafe, R>(function: F) -> R {
    match catch_unwind(function) {
        Ok(result) => result,
        Err(_cause) => abort(),
    }
}

#[no_mangle]
pub unsafe extern "C" fn rs_cstring_free(string: *mut c_char) {
    abort_on_panic(|| {
        if string.is_null() {
            return;
        }
        drop(CString::from_raw(string));
    })
}
<|endoftext|>