<commit_before>//! Module: czmq-zmsg

use {czmq_sys, Error, ErrorKind, RawInterface, Result, Sockish, ZFrame};
use std::{error, fmt, mem, ptr, result};
use std::ffi::{CStr, CString};

pub struct ZMsg {
    zmsg: *mut czmq_sys::zmsg_t,
    owned: bool,
}

unsafe impl Send for ZMsg {}
unsafe impl Sync for ZMsg {}

impl Drop for ZMsg {
    fn drop(&mut self) {
        if self.owned {
            unsafe { czmq_sys::zmsg_destroy(&mut self.zmsg) };
        }
    }
}

impl ZMsg {
    pub fn new() -> ZMsg {
        ZMsg {
            zmsg: unsafe { czmq_sys::zmsg_new() },
            owned: true,
        }
    }

    pub fn recv<S: Sockish>(source: &S) -> Result<ZMsg> {
        let zmsg = unsafe { czmq_sys::zmsg_recv(source.borrow_raw()) };

        if zmsg == ptr::null_mut() {
            Err(Error::new(ErrorKind::NullPtr, ZMsgError::CmdFailed))
        } else {
            Ok(ZMsg {
                zmsg: zmsg,
                owned: true,
            })
        }
    }

    // XXX We'll have to roll our own here as we can't imitate a C
    // file handle without C boilerplate...which we're not doing!
    // pub fn zmsg_load(file: *mut FILE) -> *mut zmsg_t;

    pub fn encode(&self) -> Result<ZFrame> {
        let zframe = unsafe { czmq_sys::zmsg_encode(self.zmsg) };

        if zframe == ptr::null_mut() {
            Err(Error::new(ErrorKind::NullPtr, ZMsgError::CmdFailed))
        } else {
            Ok(ZFrame::from_raw(zframe, true))
        }
    }

    pub fn decode(frame: &ZFrame) -> Result<ZMsg> {
        let zmsg = unsafe { czmq_sys::zmsg_decode(frame.borrow_raw()) };

        if zmsg == ptr::null_mut() {
            Err(Error::new(ErrorKind::NullPtr, ZMsgError::CmdFailed))
        } else {
            Ok(ZMsg {
                zmsg: zmsg,
                owned: true,
            })
        }
    }

    pub fn new_signal(status: u8) -> Result<ZMsg> {
        let zmsg = unsafe { czmq_sys::zmsg_new_signal(status) };

        if zmsg == ptr::null_mut() {
            Err(Error::new(ErrorKind::NullPtr, ZMsgError::CmdFailed))
        } else {
            Ok(ZMsg {
                zmsg: zmsg,
                owned: true,
            })
        }
    }

    pub fn send<D: Sockish>(self, dest: &D) -> Result<()> {
        let mut zmsg = self;

        let rc = unsafe { czmq_sys::zmsg_send(&mut zmsg.zmsg, dest.borrow_raw()) };
        if rc == -1 {
            Err(Error::new(ErrorKind::NonZero, ZMsgError::CmdFailed))
        } else {
            Ok(())
        }
    }

    // pub fn zmsg_sendm(self_p: *mut *mut zmsg_t,
    //                   dest: *mut ::std::os::raw::c_void)
    //  -> ::std::os::raw::c_int;

    pub fn size(&self) -> usize {
        unsafe { czmq_sys::zmsg_size(self.zmsg) as usize }
    }

    // pub fn zmsg_content_size(_self: *mut zmsg_t) -> size_t;

    pub fn prepend(&self, frame: ZFrame) -> Result<()> {
        let rc = unsafe { czmq_sys::zmsg_prepend(self.zmsg, &mut frame.into_raw()) };

        if rc == 0 {
            Ok(())
        } else {
            Err(Error::new(ErrorKind::NonZero, ZMsgError::CmdFailed))
        }
    }

    pub fn append(&self, frame: ZFrame) -> Result<()> {
        let rc = unsafe { czmq_sys::zmsg_append(self.zmsg, &mut frame.into_raw()) };

        if rc == 0 {
            Ok(())
        } else {
            Err(Error::new(ErrorKind::NonZero, ZMsgError::CmdFailed))
        }
    }

    pub fn pop(&self) -> Option<ZFrame> {
        let ptr = unsafe { czmq_sys::zmsg_pop(self.zmsg) };

        if ptr == ptr::null_mut() {
            None
        } else {
            Some(ZFrame::from_raw(ptr, true))
        }
    }

    // pub fn zmsg_pushmem(_self: *mut zmsg_t,
    //                     src: *const ::std::os::raw::c_void, size: size_t)
    //  -> ::std::os::raw::c_int;
    // pub fn zmsg_addmem(_self: *mut zmsg_t, src: *const ::std::os::raw::c_void,
    //                    size: size_t) -> ::std::os::raw::c_int;

    pub fn pushstr(&self, string: &str) -> Result<()> {
        let string_c = CString::new(string).unwrap_or(CString::new("").unwrap());
        let rc = unsafe { czmq_sys::zmsg_pushstr(self.zmsg, string_c.as_ptr()) };

        // Deliberately leak this memory, which will be managed by C
        mem::forget(string_c);

        if rc == -1 {
            Err(Error::new(ErrorKind::NonZero, ZMsgError::CmdFailed))
        } else {
            Ok(())
        }
    }

    pub fn addstr(&self, string: &str) -> Result<()> {
        let string_c = CString::new(string).unwrap_or(CString::new("").unwrap());
        let rc = unsafe { czmq_sys::zmsg_addstr(self.zmsg, string_c.as_ptr()) };

        // Deliberately leak this memory, which will be managed by C
        mem::forget(string_c);

        if rc == -1 {
            Err(Error::new(ErrorKind::NonZero, ZMsgError::CmdFailed))
        } else {
            Ok(())
        }
    }

    // pub fn zmsg_pushstrf(_self: *mut zmsg_t,
    //                      format: *const ::std::os::raw::c_char, ...)
    //  -> ::std::os::raw::c_int;
    // pub fn zmsg_addstrf(_self: *mut zmsg_t,
    //                     format: *const ::std::os::raw::c_char, ...)
    //  -> ::std::os::raw::c_int;

    pub fn popstr(&self) -> Option<result::Result<String, Vec<u8>>> {
        let ptr = unsafe { czmq_sys::zmsg_popstr(self.zmsg) };

        if ptr == ptr::null_mut() {
            None
        } else {
            let c_string = unsafe { CStr::from_ptr(ptr).to_owned() };
            let bytes = c_string.as_bytes().to_vec();
            match c_string.into_string() {
                Ok(s) => Some(Ok(s)),
                Err(_) => Some(Err(bytes)),
            }
        }
    }

    pub fn popbytes(&self) -> Option<Vec<u8>> {
        let ptr = unsafe { czmq_sys::zmsg_popstr(self.zmsg) };

        if ptr == ptr::null_mut() {
            None
        } else {
            let c_string = unsafe { CStr::from_ptr(ptr).to_owned() };
            Some(c_string.to_bytes().to_vec())
        }
    }

    // pub fn zmsg_addmsg(_self: *mut zmsg_t, msg_p: *mut *mut zmsg_t)
    //  -> ::std::os::raw::c_int;
    // pub fn zmsg_popmsg(_self: *mut zmsg_t) -> *mut zmsg_t;
    // pub fn zmsg_remove(_self: *mut zmsg_t, frame: *mut zframe_t);

    pub fn first(&self) -> Option<ZFrame> {
        let ptr = unsafe { czmq_sys::zmsg_first(self.zmsg) };

        if ptr == ptr::null_mut() {
            None
        } else {
            Some(ZFrame::from_raw(ptr, false))
        }
    }

    pub fn next(&self) -> Option<ZFrame> {
        let ptr = unsafe { czmq_sys::zmsg_next(self.zmsg) };

        if ptr == ptr::null_mut() {
            None
        } else {
            Some(ZFrame::from_raw(ptr, false))
        }
    }

    // We can't call this fn last() as it conflicts with
    // Iterator::last(), which is implemented for ZMsg.
    pub fn ref_last(&self) -> Option<ZFrame> {
        let ptr = unsafe { czmq_sys::zmsg_last(self.zmsg) };

        if ptr == ptr::null_mut() {
            None
        } else {
            Some(ZFrame::from_raw(ptr, false))
        }
    }

    // pub fn zmsg_save(_self: *mut zmsg_t, file: *mut FILE)
    //  -> ::std::os::raw::c_int;
    // pub fn zmsg_dup(_self: *mut zmsg_t) -> *mut zmsg_t;
    // pub fn zmsg_print(_self: *mut zmsg_t);
    // pub fn zmsg_eq(_self: *mut zmsg_t, other: *mut zmsg_t) -> u8;

    pub fn signal(&self) -> Result<u8> {
        let signal = unsafe { czmq_sys::zmsg_signal(self.zmsg) };
        if signal == -1 {
            Err(Error::new(ErrorKind::NonZero, ZMsgError::CmdFailed))
        } else {
            Ok(signal as u8)
        }
    }

    // pub fn zmsg_test(verbose: u8);

    pub fn borrow_raw(&self) -> *mut czmq_sys::zmsg_t {
        self.zmsg
    }
}

impl RawInterface<czmq_sys::zmsg_t> for ZMsg {
    fn from_raw(ptr: *mut czmq_sys::zmsg_t, owned: bool) -> ZMsg {
        ZMsg {
            zmsg: ptr,
            owned: owned,
        }
    }

    fn into_raw(mut self) -> *mut czmq_sys::zmsg_t {
        self.owned = false;
        self.zmsg
    }

    fn borrow_raw(&self) -> *mut czmq_sys::zmsg_t {
        self.zmsg
    }
}

impl Iterator for ZMsg {
    type Item = ZFrame;

    fn next(&mut self) -> Option<Self::Item> {
        ZMsg::next(self)
    }
}

#[derive(Debug)]
pub enum ZMsgError {
    CmdFailed,
}

impl fmt::Display for ZMsgError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ZMsgError::CmdFailed => write!(f, "ZMsg command failed"),
        }
    }
}

impl error::Error for ZMsgError {
    fn description(&self) -> &str {
        match *self {
            ZMsgError::CmdFailed => "ZMsg command failed",
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use {zmq, ZFrame, ZSock, zsys_init};

    #[test]
    fn test_sendrecv_zmq() {
        let mut ctx = zmq::Context::new();

        let mut server = ctx.socket(zmq::REP).unwrap();
        server.bind("inproc://zmsg_sendrecv_zmq").unwrap();

        let mut client = ctx.socket(zmq::REQ).unwrap();
        client.connect("inproc://zmsg_sendrecv_zmq").unwrap();

        let zmsg = ZMsg::new();
        zmsg.addstr("Hello world!").unwrap();
        zmsg.send(&client).unwrap();

        let zmsg_recv = ZMsg::recv(&server).unwrap();
        assert_eq!(zmsg_recv.popstr().unwrap().unwrap(), "Hello world!");
    }

    #[test]
    fn test_sendrecv_zsock() {
        zsys_init();

        let server = ZSock::new_rep("inproc://zmsg_sendrecv_zsock").unwrap();
        let client = ZSock::new_req("inproc://zmsg_sendrecv_zsock").unwrap();

        let zmsg = ZMsg::new();
        zmsg.addstr("Hello world!").unwrap();
        zmsg.send(&client).unwrap();

        let msg = ZMsg::recv(&server).unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "Hello world!");
    }

    #[test]
    fn test_encode_decode() {
        let msg = ZMsg::new();
        msg.addstr("moo").unwrap();
        let msg_decoded = ZMsg::decode(&msg.encode().unwrap()).unwrap();
        assert_eq!(msg_decoded.popstr().unwrap().unwrap(), "moo");
    }

    #[test]
    fn test_signal() {
        let msg = ZMsg::new_signal(97).unwrap();
        assert_eq!(msg.signal().unwrap(), 97);
    }

    #[test]
    fn test_size() {
        let msg = ZMsg::new();
        msg.addstr("123").unwrap();
        assert_eq!(msg.size(), 1);
    }

    #[test]
    fn test_prepend() {
        let msg = ZMsg::new();
        msg.prepend(ZFrame::from("123").unwrap()).unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "123");
    }

    #[test]
    fn test_append() {
        let msg = ZMsg::new();
        msg.append(ZFrame::from("123").unwrap()).unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "123");
    }

    #[test]
    fn test_pop() {
        let msg = ZMsg::new();
        msg.addstr("123").unwrap();
        assert_eq!(msg.pop().unwrap().data().unwrap().unwrap(), "123");
    }

    #[test]
    fn test_pushstr() {
        let msg = ZMsg::new();
        msg.addstr("456").unwrap();
        msg.pushstr("123").unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "123");
    }

    #[test]
    fn test_popstr() {
        let msg = ZMsg::new();
        msg.addstr("123").unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "123");
    }

    #[test]
    fn test_popbytes() {
        let msg = ZMsg::new();
        msg.addstr("123").unwrap();
        assert_eq!(msg.popbytes().unwrap(), "123".as_bytes());
    }

    #[test]
    fn test_iter_fns() {
        let msg = ZMsg::new();
        msg.addstr("1").unwrap();
        msg.addstr("2").unwrap();
        msg.addstr("3").unwrap();

        let frame = msg.first().unwrap();
        assert_eq!(frame.data().unwrap().unwrap(), "1");

        let frame = msg.next().unwrap();
        assert_eq!(frame.data().unwrap().unwrap(), "2");

        let frame = msg.ref_last().unwrap();
        assert_eq!(frame.data().unwrap().unwrap(), "3");
    }

    #[test]
    fn test_iter() {
        let msg = ZMsg::new();
        msg.addstr("1").unwrap();
        msg.addstr("2").unwrap();
        msg.addstr("3").unwrap();

        let mut i = 1;
        for x in msg {
            assert_eq!(x.data().unwrap().unwrap(), i.to_string());
            i += 1;
        }
    }
}
<commit_msg>ZMsg::push/addbytes<commit_after>//! Module: czmq-zmsg

use {czmq_sys, Error, ErrorKind, RawInterface, Result, Sockish, ZFrame};
use std::{error, fmt, mem, ptr, result};
use std::ffi::{CStr, CString};

pub struct ZMsg {
    zmsg: *mut czmq_sys::zmsg_t,
    owned: bool,
}

unsafe impl Send for ZMsg {}
unsafe impl Sync for ZMsg {}

impl Drop for ZMsg {
    fn drop(&mut self) {
        if self.owned {
            unsafe { czmq_sys::zmsg_destroy(&mut self.zmsg) };
        }
    }
}

impl ZMsg {
    pub fn new() -> ZMsg {
        ZMsg {
            zmsg: unsafe { czmq_sys::zmsg_new() },
            owned: true,
        }
    }

    pub fn recv<S: Sockish>(source: &S) -> Result<ZMsg> {
        let zmsg = unsafe { czmq_sys::zmsg_recv(source.borrow_raw()) };

        if zmsg == ptr::null_mut() {
            Err(Error::new(ErrorKind::NullPtr, ZMsgError::CmdFailed))
        } else {
            Ok(ZMsg {
                zmsg: zmsg,
                owned: true,
            })
        }
    }

    // XXX We'll have to roll our own here as we can't imitate a C
    // file handle without C boilerplate...which we're not doing!
    // pub fn zmsg_load(file: *mut FILE) -> *mut zmsg_t;

    pub fn encode(&self) -> Result<ZFrame> {
        let zframe = unsafe { czmq_sys::zmsg_encode(self.zmsg) };

        if zframe == ptr::null_mut() {
            Err(Error::new(ErrorKind::NullPtr, ZMsgError::CmdFailed))
        } else {
            Ok(ZFrame::from_raw(zframe, true))
        }
    }

    pub fn decode(frame: &ZFrame) -> Result<ZMsg> {
        let zmsg = unsafe { czmq_sys::zmsg_decode(frame.borrow_raw()) };

        if zmsg == ptr::null_mut() {
            Err(Error::new(ErrorKind::NullPtr, ZMsgError::CmdFailed))
        } else {
            Ok(ZMsg {
                zmsg: zmsg,
                owned: true,
            })
        }
    }

    pub fn new_signal(status: u8) -> Result<ZMsg> {
        let zmsg = unsafe { czmq_sys::zmsg_new_signal(status) };

        if zmsg == ptr::null_mut() {
            Err(Error::new(ErrorKind::NullPtr, ZMsgError::CmdFailed))
        } else {
            Ok(ZMsg {
                zmsg: zmsg,
                owned: true,
            })
        }
    }

    pub fn send<D: Sockish>(self, dest: &D) -> Result<()> {
        let mut zmsg = self;

        let rc = unsafe { czmq_sys::zmsg_send(&mut zmsg.zmsg, dest.borrow_raw()) };
        if rc == -1 {
            Err(Error::new(ErrorKind::NonZero, ZMsgError::CmdFailed))
        } else {
            Ok(())
        }
    }

    // pub fn zmsg_sendm(self_p: *mut *mut zmsg_t,
    //                   dest: *mut ::std::os::raw::c_void)
    //  -> ::std::os::raw::c_int;

    pub fn size(&self) -> usize {
        unsafe { czmq_sys::zmsg_size(self.zmsg) as usize }
    }

    // pub fn zmsg_content_size(_self: *mut zmsg_t) -> size_t;

    pub fn prepend(&self, frame: ZFrame) -> Result<()> {
        let rc = unsafe { czmq_sys::zmsg_prepend(self.zmsg, &mut frame.into_raw()) };

        if rc == 0 {
            Ok(())
        } else {
            Err(Error::new(ErrorKind::NonZero, ZMsgError::CmdFailed))
        }
    }

    pub fn append(&self, frame: ZFrame) -> Result<()> {
        let rc = unsafe { czmq_sys::zmsg_append(self.zmsg, &mut frame.into_raw()) };

        if rc == 0 {
            Ok(())
        } else {
            Err(Error::new(ErrorKind::NonZero, ZMsgError::CmdFailed))
        }
    }

    pub fn pop(&self) -> Option<ZFrame> {
        let ptr = unsafe { czmq_sys::zmsg_pop(self.zmsg) };

        if ptr == ptr::null_mut() {
            None
        } else {
            Some(ZFrame::from_raw(ptr, true))
        }
    }

    // pub fn zmsg_pushmem(_self: *mut zmsg_t,
    //                     src: *const ::std::os::raw::c_void, size: size_t)
    //  -> ::std::os::raw::c_int;
    // pub fn zmsg_addmem(_self: *mut zmsg_t, src: *const ::std::os::raw::c_void,
    //                    size: size_t) -> ::std::os::raw::c_int;

    pub fn pushstr(&self, string: &str) -> Result<()> {
        let string_c = CString::new(string).unwrap_or(CString::new("").unwrap());
        let rc = unsafe { czmq_sys::zmsg_pushstr(self.zmsg, string_c.as_ptr()) };

        // Deliberately leak this memory, which will be managed by C
        mem::forget(string_c);

        if rc == -1 {
            Err(Error::new(ErrorKind::NonZero, ZMsgError::CmdFailed))
        } else {
            Ok(())
        }
    }

    pub fn addstr(&self, string: &str) -> Result<()> {
        let string_c = CString::new(string).unwrap_or(CString::new("").unwrap());
        let rc = unsafe { czmq_sys::zmsg_addstr(self.zmsg, string_c.as_ptr()) };

        // Deliberately leak this memory, which will be managed by C
        mem::forget(string_c);

        if rc == -1 {
            Err(Error::new(ErrorKind::NonZero, ZMsgError::CmdFailed))
        } else {
            Ok(())
        }
    }

    // pub fn zmsg_pushstrf(_self: *mut zmsg_t,
    //                      format: *const ::std::os::raw::c_char, ...)
    //  -> ::std::os::raw::c_int;
    // pub fn zmsg_addstrf(_self: *mut zmsg_t,
    //                     format: *const ::std::os::raw::c_char, ...)
    //  -> ::std::os::raw::c_int;

    pub fn popstr(&self) -> Option<result::Result<String, Vec<u8>>> {
        let ptr = unsafe { czmq_sys::zmsg_popstr(self.zmsg) };

        if ptr == ptr::null_mut() {
            None
        } else {
            let c_string = unsafe { CStr::from_ptr(ptr).to_owned() };
            let bytes = c_string.as_bytes().to_vec();
            match c_string.into_string() {
                Ok(s) => Some(Ok(s)),
                Err(_) => Some(Err(bytes)),
            }
        }
    }

    pub fn pushbytes(&self, bytes: &[u8]) -> Result<()> {
        let zframe = try!(ZFrame::new(bytes));
        try!(self.prepend(zframe));
        Ok(())
    }

    pub fn addbytes(&self, bytes: &[u8]) -> Result<()> {
        let zframe = try!(ZFrame::new(bytes));
        try!(self.append(zframe));
        Ok(())
    }

    pub fn popbytes(&self) -> Option<Vec<u8>> {
        let ptr = unsafe { czmq_sys::zmsg_popstr(self.zmsg) };

        if ptr == ptr::null_mut() {
            None
        } else {
            let c_string = unsafe { CStr::from_ptr(ptr).to_owned() };
            Some(c_string.to_bytes().to_vec())
        }
    }

    // pub fn zmsg_addmsg(_self: *mut zmsg_t, msg_p: *mut *mut zmsg_t)
    //  -> ::std::os::raw::c_int;
    // pub fn zmsg_popmsg(_self: *mut zmsg_t) -> *mut zmsg_t;
    // pub fn zmsg_remove(_self: *mut zmsg_t, frame: *mut zframe_t);

    pub fn first(&self) -> Option<ZFrame> {
        let ptr = unsafe { czmq_sys::zmsg_first(self.zmsg) };

        if ptr == ptr::null_mut() {
            None
        } else {
            Some(ZFrame::from_raw(ptr, false))
        }
    }

    pub fn next(&self) -> Option<ZFrame> {
        let ptr = unsafe { czmq_sys::zmsg_next(self.zmsg) };

        if ptr == ptr::null_mut() {
            None
        } else {
            Some(ZFrame::from_raw(ptr, false))
        }
    }

    // We can't call this fn last() as it conflicts with
    // Iterator::last(), which is implemented for ZMsg.
    pub fn ref_last(&self) -> Option<ZFrame> {
        let ptr = unsafe { czmq_sys::zmsg_last(self.zmsg) };

        if ptr == ptr::null_mut() {
            None
        } else {
            Some(ZFrame::from_raw(ptr, false))
        }
    }

    // pub fn zmsg_save(_self: *mut zmsg_t, file: *mut FILE)
    //  -> ::std::os::raw::c_int;
    // pub fn zmsg_dup(_self: *mut zmsg_t) -> *mut zmsg_t;
    // pub fn zmsg_print(_self: *mut zmsg_t);
    // pub fn zmsg_eq(_self: *mut zmsg_t, other: *mut zmsg_t) -> u8;

    pub fn signal(&self) -> Result<u8> {
        let signal = unsafe { czmq_sys::zmsg_signal(self.zmsg) };
        if signal == -1 {
            Err(Error::new(ErrorKind::NonZero, ZMsgError::CmdFailed))
        } else {
            Ok(signal as u8)
        }
    }

    // pub fn zmsg_test(verbose: u8);

    pub fn borrow_raw(&self) -> *mut czmq_sys::zmsg_t {
        self.zmsg
    }
}

impl RawInterface<czmq_sys::zmsg_t> for ZMsg {
    fn from_raw(ptr: *mut czmq_sys::zmsg_t, owned: bool) -> ZMsg {
        ZMsg {
            zmsg: ptr,
            owned: owned,
        }
    }

    fn into_raw(mut self) -> *mut czmq_sys::zmsg_t {
        self.owned = false;
        self.zmsg
    }

    fn borrow_raw(&self) -> *mut czmq_sys::zmsg_t {
        self.zmsg
    }
}

impl Iterator for ZMsg {
    type Item = ZFrame;

    fn next(&mut self) -> Option<Self::Item> {
        ZMsg::next(self)
    }
}

#[derive(Debug)]
pub enum ZMsgError {
    CmdFailed,
}

impl fmt::Display for ZMsgError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ZMsgError::CmdFailed => write!(f, "ZMsg command failed"),
        }
    }
}

impl error::Error for ZMsgError {
    fn description(&self) -> &str {
        match *self {
            ZMsgError::CmdFailed => "ZMsg command failed",
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use {zmq, ZFrame, ZSock, zsys_init};

    #[test]
    fn test_sendrecv_zmq() {
        let mut ctx = zmq::Context::new();

        let mut server = ctx.socket(zmq::REP).unwrap();
        server.bind("inproc://zmsg_sendrecv_zmq").unwrap();

        let mut client = ctx.socket(zmq::REQ).unwrap();
        client.connect("inproc://zmsg_sendrecv_zmq").unwrap();

        let zmsg = ZMsg::new();
        zmsg.addstr("Hello world!").unwrap();
        zmsg.send(&client).unwrap();

        let zmsg_recv = ZMsg::recv(&server).unwrap();
        assert_eq!(zmsg_recv.popstr().unwrap().unwrap(), "Hello world!");
    }

    #[test]
    fn test_sendrecv_zsock() {
        zsys_init();

        let server = ZSock::new_rep("inproc://zmsg_sendrecv_zsock").unwrap();
        let client = ZSock::new_req("inproc://zmsg_sendrecv_zsock").unwrap();

        let zmsg = ZMsg::new();
        zmsg.addstr("Hello world!").unwrap();
        zmsg.send(&client).unwrap();

        let msg = ZMsg::recv(&server).unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "Hello world!");
    }

    #[test]
    fn test_encode_decode() {
        let msg = ZMsg::new();
        msg.addstr("moo").unwrap();
        let msg_decoded = ZMsg::decode(&msg.encode().unwrap()).unwrap();
        assert_eq!(msg_decoded.popstr().unwrap().unwrap(), "moo");
    }

    #[test]
    fn test_signal() {
        let msg = ZMsg::new_signal(97).unwrap();
        assert_eq!(msg.signal().unwrap(), 97);
    }

    #[test]
    fn test_size() {
        let msg = ZMsg::new();
        msg.addstr("123").unwrap();
        assert_eq!(msg.size(), 1);
    }

    #[test]
    fn test_prepend() {
        let msg = ZMsg::new();
        msg.prepend(ZFrame::from("123").unwrap()).unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "123");
    }

    #[test]
    fn test_append() {
        let msg = ZMsg::new();
        msg.append(ZFrame::from("123").unwrap()).unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "123");
    }

    #[test]
    fn test_pop() {
        let msg = ZMsg::new();
        msg.addstr("123").unwrap();
        assert_eq!(msg.pop().unwrap().data().unwrap().unwrap(), "123");
    }

    #[test]
    fn test_push_add_popstr() {
        let msg = ZMsg::new();
        msg.addstr("456").unwrap();
        msg.pushstr("123").unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "123");
    }

    #[test]
    fn test_push_add_popbytes() {
        let msg = ZMsg::new();
        msg.addbytes("456".as_bytes()).unwrap();
        msg.pushbytes("123".as_bytes()).unwrap();
        assert_eq!(msg.popbytes().unwrap(), "123".as_bytes());
    }

    #[test]
    fn test_iter_fns() {
        let msg = ZMsg::new();
        msg.addstr("1").unwrap();
        msg.addstr("2").unwrap();
        msg.addstr("3").unwrap();

        let frame = msg.first().unwrap();
        assert_eq!(frame.data().unwrap().unwrap(), "1");

        let frame = msg.next().unwrap();
        assert_eq!(frame.data().unwrap().unwrap(), "2");

        let frame = msg.ref_last().unwrap();
        assert_eq!(frame.data().unwrap().unwrap(), "3");
    }

    #[test]
    fn test_iter() {
        let msg = ZMsg::new();
        msg.addstr("1").unwrap();
        msg.addstr("2").unwrap();
        msg.addstr("3").unwrap();

        let mut i = 1;
        for x in msg {
            assert_eq!(x.data().unwrap().unwrap(), i.to_string());
            i += 1;
        }
    }
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use std::fmt;

#[derive(Debug,Clone,PartialEq)]
pub struct ParseTurnError;

#[derive(Debug,Clone,PartialEq,Eq,PartialOrd,Ord)]
pub enum Turn
{
	StartingRegions(usize,usize,usize,usize,usize,usize),
	Place(String,usize,usize),
	Turn(String,usize,usize,usize),
	Noop,
}

impl FromStr for Turn
{
	type Err = ParseTurnError;

	fn from_str(s: &str) -> Result<Self,Self::Err>
	{
		use self::Turn::*;

		let args = s.split_whitespace().collect::<Vec<_>>();
		match args.len()
		{
			2 => Ok(Noop),
			4 => Ok(Place(args[0].to_owned(),args[2].parse().unwrap(),args[3].parse().unwrap())),
			5 => Ok(Turn(args[0].to_owned(),args[2].parse().unwrap(),args[3].parse().unwrap(),args[4].parse().unwrap())),
			6 =>
			{
				let mut args = args.iter().map(|s|s.parse::<usize>()).map(Result::unwrap);
				Ok(StartingRegions
				(
					args.next().unwrap(),
					args.next().unwrap(),
					args.next().unwrap(),
					args.next().unwrap(),
					args.next().unwrap(),
					args.next().unwrap()
				))
			},
			_ => Err(ParseTurnError),
		}
	}
}

impl fmt::Display for Turn
{
	fn fmt(&self,f: &mut fmt::Formatter) -> fmt::Result
	{
		use self::Turn::*;
		match self
		{
			&StartingRegions(a,b,c,d,e,f_) => write!(f,"{} {} {} {} {} {}",a,b,c,d,e,f_),
			&Place(ref name,region,count) => write!(f,"{} place_armies {} {}",name,region,count),
			&Turn(ref name,source,target,count) => write!(f,"{} attack/transfer {} {} {}",name,source,target,count),
			&Noop => write!(f,"No moves"),
		}
	}
}

<commit_msg>struct for turns<commit_after>use std::str::FromStr;
use std::fmt;

#[derive(Debug,Clone,PartialEq)]
pub struct ParseTurnError;

#[derive(Debug,Clone,PartialEq,Eq,PartialOrd,Ord)]
pub enum Turn
{
	StartingRegions(usize,usize,usize,usize,usize,usize),
	Place
	{
		name: String,
		region: usize,
		count: usize,
	},
	Turn
	{
		name: String,
		source: usize,
		target: usize,
		count: usize,
	},
	Noop,
}

impl FromStr for Turn
{
	type Err = ParseTurnError;

	fn from_str(s: &str) -> Result<Self,Self::Err>
	{
		use self::Turn::*;

		let args = s.split_whitespace().collect::<Vec<_>>();
		match args.len()
		{
			2 => Ok(Noop),
			4 => Ok(
				Place
				{
					name: args[0].to_owned(),
					region: args[2].parse().unwrap(),
					count: args[3].parse().unwrap(),
				}),
			5 => Ok(
				Turn
				{
					name: args[0].to_owned(),
					source: args[2].parse().unwrap(),
					target: args[3].parse().unwrap(),
					count: args[4].parse().unwrap(),
				}),
			6 =>
			{
				let mut args = args.iter().map(|s|s.parse::<usize>()).map(Result::unwrap);
				Ok(StartingRegions
				(
					args.next().unwrap(),
					args.next().unwrap(),
					args.next().unwrap(),
					args.next().unwrap(),
					args.next().unwrap(),
					args.next().unwrap()
				))
			},
			_ => Err(ParseTurnError),
		}
	}
}

impl fmt::Display for Turn
{
	fn fmt(&self,f: &mut fmt::Formatter) -> fmt::Result
	{
		use self::Turn::*;
		match self
		{
			&StartingRegions(a,b,c,d,e,f_) => write!(f,"{} {} {} {} {} {}",a,b,c,d,e,f_),
			&Place{ref name,region,count} => write!(f,"{} place_armies {} {}",name,region,count),
			&Turn{ref name,source,target,count} => write!(f,"{} attack/transfer {} {} {}",name,source,target,count),
			&Noop => write!(f,"No moves"),
		}
	}
}

<|endoftext|>


<commit_before>use colored::*;

// http://stackoverflow.com/questions/5194057/better-way-to-convert-file-sizes-in-python
pub fn iec(n: u64) -> String {
    let units = ["", "k", "M", "G", "T", "P", "E", "Z", "Y"];

    let i = (n as f64).log(1024_f64).floor() as u32;
    let p = 1024_u64.pow(i);
    let s = (n as f64)/(p as f64);
    format!("{:.0}{}", s, units[i as usize])
}

// valid VG/LV characters are: a-z A-Z 0-9 + _ . -
// we use this fact and replace -- with #
// split on - and then switch # back to -
pub fn shorten_lv(path: &str) -> String {
    const MARK: &'static str = "#";

    if path.starts_with("/dev/mapper/") {
        if let Some(lv) = path.split('/').nth(3) {
            let lv = lv.replace("--", MARK);
            let lv_vg: Vec<String> = lv.split("-").map(|x| x.replace(MARK, "-")).collect();
            return format!("/dev/{}/{}", lv_vg[0], lv_vg[1]);
        }
    }

    path.to_string()
}

pub fn bargraph(mut percent: f64) -> String {
    if percent.is_nan() {
        percent = 0.0;
    }
    let chars = "■■■■■■■■■■■■■■■■■■■■";
    let s1 = (percent / 10.0).round() as usize * 2;
    let s2 = 20 - s1;
    format!("{}{}", chars.chars().take(s1).collect::<String>().green(),
            chars.chars().take(s2).collect::<String>().white().dimmed())
}

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

    #[test]
    fn test_shorten_lv() {
        assert_eq!(shorten_lv("/dev/mapper/vg-lv"), "/dev/vg/lv");
        assert_eq!(shorten_lv("/dev/mapper/vg-lv--1"), "/dev/vg/lv-1");
        assert_eq!(shorten_lv("/dev/mapper/vg--one-lv"), "/dev/vg-one/lv");
        assert_eq!(shorten_lv("/dev/mapper/vg--one-lv--one"), "/dev/vg-one/lv-one");
    }
}
<commit_msg>Color bargraphs.<commit_after>use colored::*;

// http://stackoverflow.com/questions/5194057/better-way-to-convert-file-sizes-in-python
pub fn iec(n: u64) -> String {
    let units = ["", "k", "M", "G", "T", "P", "E", "Z", "Y"];

    let i = (n as f64).log(1024_f64).floor() as u32;
    let p = 1024_u64.pow(i);
    let s = (n as f64)/(p as f64);
    format!("{:.0}{}", s, units[i as usize])
}

// valid VG/LV characters are: a-z A-Z 0-9 + _ . -
// we use this fact and replace -- with #
// split on - and then switch # back to -
pub fn shorten_lv(path: &str) -> String {
    const MARK: &'static str = "#";

    if path.starts_with("/dev/mapper/") {
        if let Some(lv) = path.split('/').nth(3) {
            let lv = lv.replace("--", MARK);
            let lv_vg: Vec<String> = lv.split("-").map(|x| x.replace(MARK, "-")).collect();
            return format!("/dev/{}/{}", lv_vg[0], lv_vg[1]);
        }
    }

    path.to_string()
}

pub fn bargraph(mut percent: f64) -> String {
    if percent.is_nan() {
        percent = 0.0;
    }
    let chars = "■■■■■■■■■■■■■■■■■■■■";
    let s1 = (percent / 10.0).round() as usize * 2;
    let s2 = 20 - s1;
    let bar1 = chars.chars().take(s1).collect::<String>();
    let bar1 = if percent > 90.0 {
        bar1.red()
    } else if percent > 75.0 {
        bar1.yellow()
    } else {
        bar1.green()
    };
    let bar2 = chars.chars().take(s2).collect::<String>().white().dimmed();
    format!("{}{}", bar1, bar2)
}

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

    #[test]
    fn test_shorten_lv() {
        assert_eq!(shorten_lv("/dev/mapper/vg-lv"), "/dev/vg/lv");
        assert_eq!(shorten_lv("/dev/mapper/vg-lv--1"), "/dev/vg/lv-1");
        assert_eq!(shorten_lv("/dev/mapper/vg--one-lv"), "/dev/vg-one/lv");
        assert_eq!(shorten_lv("/dev/mapper/vg--one-lv--one"), "/dev/vg-one/lv-one");
    }
}
<|endoftext|>


<commit_before>use libc::c_char;
use std::ffi::{CStr, CString};
use std::str;

/// Cast from one type into another
pub trait CastFrom {
    /// The type that can be casted from.
    type From;
    /// Cast it
    fn cast<'a>(ty: &'a Self::From) -> Option<&'a Self>;
}

#[inline(always)]
pub fn with_cstr<C, R>(text: &str, cb: C) -> R where C:FnOnce(*const c_char) -> R {
    let c_text = CString::new(text).unwrap();
    cb(c_text.as_bytes().as_ptr() as *const c_char)
}

#[inline(always)]
pub unsafe fn to_str<'a>(text: *mut c_char) -> &'a str {
    let c_str = CStr::from_ptr(text);
    str::from_utf8_unchecked(c_str.to_bytes())
}

pub unsafe fn to_null_str<'a>(text: *mut c_char) -> Option<&'a str> {
    if text.is_null() {
        None
    } else {
        Some(to_str(text))
    }
}
pub unsafe fn ptr_to_null<P, T>(ptr: *mut P) -> Option<T> where T:From<*mut P> {
    if ptr.is_null() {
        None
    } else {
        Some(ptr.into())
    }
}
<commit_msg>Reformat util.rs.<commit_after>use libc::c_char;
use std::ffi::{CStr, CString};
use std::str;

/// Cast from one type into another
pub trait CastFrom
{
    /// The type that can be casted from.
    type From;
    /// Cast it
    fn cast<'a>(ty: &'a Self::From) -> Option<&'a Self>;
}

#[inline(always)]
pub fn with_cstr<C, R>(text: &str, cb: C) -> R where C:FnOnce(*const c_char) -> R
{
  let c_text = CString::new(text).unwrap();
  cb(c_text.as_bytes().as_ptr() as *const c_char)
}

#[inline(always)]
pub unsafe fn to_str<'a>(text: *mut c_char) -> &'a str
{
  let c_str = CStr::from_ptr(text);
  str::from_utf8_unchecked(c_str.to_bytes())
}

pub unsafe fn to_null_str<'a>(text: *mut c_char) -> Option<&'a str>
{
  if text.is_null() {
      None
  } else {
      Some(to_str(text))
  }
}

pub unsafe fn ptr_to_null<P, T>(ptr: *mut P) -> Option<T> where T:From<*mut P>
{
  if ptr.is_null() {
      None
  } else {
      Some(ptr.into())
  }
}
<|endoftext|>


<commit_before>// This file is made up largely of utility methods which are invoked by the
// session in its interpret method. They are separate because they don't rely
// on the session (or take what they do need as arguments) and/or they are
// called by the session in multiple places.

use std::env::current_dir;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use regex::Regex;
use walkdir::WalkDir;

use folder::Folder;

#[macro_export]
macro_rules! path_filename_to_str(
    ($p:ident) => (
        match $p.file_name() {
            Some(filename) =>
                match filename.to_str() {
                    Some(fns) => fns,
                    None => "",
                },
            None => ""
        }
    );
);

fn make_absolute(dir: &Path) -> String {
    match current_dir() {
        Err(_) => dir.display().to_string(),
        Ok(absp) => {
            let mut abs_path = absp.clone();
            abs_path.push(dir);
            abs_path.as_path().display().to_string()
        }
    }
}

pub fn perform_select(maildir: &str, select_args: &[&str], examine: bool,
                      tag: &str) -> (Option<Folder>, String) {
    let err_res = (None, "".to_string());
    if select_args.len() < 1 { return err_res; }
    let mbox_name = select_args[0].trim_matches('"').replace("INBOX", ".");
    let mut maildir_path = PathBuf::new();
    maildir_path.push(maildir);
    maildir_path.push(mbox_name);
    let folder =  match Folder::new(maildir_path, examine) {
        None => { return err_res; }
        Some(folder) => folder.clone()
    };

    let ok_res = folder.select_response(tag);
    (Some(folder), ok_res)
}

/// For the given dir, make sure it is a valid mail folder and, if it is,
/// generate the LIST response for it.
fn list_dir(dir: &Path, regex: &Regex, maildir_path: &Path) -> Option<String> {
    let dir_string = dir.display().to_string();
    let dir_name = path_filename_to_str!(dir);

    // These folder names are used to hold mail. Every other folder is
    // valid.
    if  dir_name == "cur" || dir_name == "new" || dir_name == "tmp" {
        return None;
    }

    let abs_dir = make_absolute(dir);

    // If it doesn't have any mail, then it isn't selectable as a mail
    // folder but it may contain subfolders which hold mail.
    let mut flags = match fs::read_dir(&dir.join("cur")) {
        Err(_) => "\\Noselect".to_string(),
        _ => {
            match fs::read_dir(&dir.join("new")) {
                Err(_) => "\\Noselect".to_string(),
                // If there is new mail in the folder, we should inform the
                // client. We do this only because we have to perform the
                // check in order to determine selectability. The RFC says
                // not to perform the check if it would slow down the
                // response time.
                Ok(newlisting) => {
                    if newlisting.count() == 0 {
                        "\\Unmarked".to_string()
                    } else {
                        "\\Marked".to_string()
                    }
                }
            }
        }
    };

    // Changing folders in mutt doesn't work properly if we don't indicate
    // whether or not a given folder has subfolders. Mutt has issues
    // selecting folders with subfolders for reading mail, unfortunately.
    match fs::read_dir(&dir) {
        Err(_) => { return None; }
        Ok(dir_listing) => {
            let mut children = false;
            for subdir_entry in dir_listing {
                if let Ok(subdir) = subdir_entry {
                    if *dir == *maildir_path {
                        break;
                    }
                    let subdir_path = subdir.path();
                    let subdir_str = path_filename_to_str!(subdir_path);
                    if subdir_str != "cur" &&
                        subdir_str != "new" &&
                        subdir_str != "tmp" {
                            if fs::read_dir(&subdir.path().join("cur")).is_err() {
                                continue;
                            }
                            if fs::read_dir(&subdir.path().join("new")).is_err() {
                                continue;
                            }
                            children = true;
                            break;
                        }
                }
            }
            if children {
                flags.push_str(" \\HasChildren");
            } else {
                flags.push_str(" \\HasNoChildren");
            }
        }
    }

    let re_path = make_absolute(maildir_path);
    let re_opt = Regex::new(&(format!("^{}", re_path))[..]);
    match re_opt {
        Err(_) =>  None,
        Ok(re) => {
            match fs::metadata(dir) {
                Err(_) => return None,
                Ok(md) =>
                    if !md.is_dir() {
                        return None;
                    }
            };

            if !regex.is_match(&dir_string[..]) {
                return None;
            }
            let mut list_str = "* LIST (".to_string();
            list_str.push_str(&flags[..]);
            list_str.push_str(") \"/\" ");
            list_str.push_str(&(re.replace(&abs_dir[..], "INBOX").replace("INBOX", ""))[..]);
            Some(list_str)
        }
    }
}

/// Go through the logged in user's maildir and list every folder matching
/// the given regular expression. Returns a list of LIST responses.
pub fn list(maildir: &str, regex: &Regex) -> Vec<String> {
    let maildir_path = Path::new(maildir);
    let mut responses = Vec::new();
    if let Some(list_response) = list_dir(maildir_path, regex, maildir_path) {
        responses.push(list_response);
    }
    for dir_res in WalkDir::new(&maildir_path) {
        if let Ok(dir) = dir_res {
            if let Some(list_response) = list_dir(dir.path(), regex, maildir_path) {
                responses.push(list_response);
            }
        }
    }
    responses
}
<commit_msg>Idiomatic refactor of util module<commit_after>// This file is made up largely of utility methods which are invoked by the
// session in its interpret method. They are separate because they don't rely
// on the session (or take what they do need as arguments) and/or they are
// called by the session in multiple places.

use std::env::current_dir;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use regex::Regex;
use walkdir::WalkDir;

use folder::Folder;

#[macro_export]
macro_rules! path_filename_to_str(
    ($p:ident) => ({
        use std::ffi::OsStr;
        $p.file_name().unwrap_or_else(|| OsStr::new("")).to_str().unwrap_or_else(|| "")
    });
);

fn make_absolute(dir: &Path) -> String {
    match current_dir() {
        Err(_) => dir.display().to_string(),
        Ok(absp) => {
            let mut abs_path = absp.clone();
            abs_path.push(dir);
            abs_path.display().to_string()
        }
    }
}

pub fn perform_select(maildir: &str, select_args: &[&str], examine: bool,
                      tag: &str) -> (Option<Folder>, String) {
    let err_res = (None, "".to_string());
    if select_args.len() < 1 { return err_res; }
    let mbox_name = select_args[0].trim_matches('"').replace("INBOX", ".");
    let mut maildir_path = PathBuf::new();
    maildir_path.push(maildir);
    maildir_path.push(mbox_name);
    let folder =  match Folder::new(maildir_path, examine) {
        None => { return err_res; }
        Some(folder) => folder.clone()
    };

    let ok_res = folder.select_response(tag);
    (Some(folder), ok_res)
}

/// For the given dir, make sure it is a valid mail folder and, if it is,
/// generate the LIST response for it.
fn list_dir(dir: &Path, regex: &Regex, maildir_path: &Path) -> Option<String> {
    let dir_string = dir.display().to_string();
    let dir_name = path_filename_to_str!(dir);

    // These folder names are used to hold mail. Every other folder is
    // valid.
    if  dir_name == "cur" || dir_name == "new" || dir_name == "tmp" {
        return None;
    }

    let abs_dir = make_absolute(dir);

    // If it doesn't have any mail, then it isn't selectable as a mail
    // folder but it may contain subfolders which hold mail.
    let mut flags = match fs::read_dir(&dir.join("cur")) {
        Err(_) => "\\Noselect".to_string(),
        _ => {
            match fs::read_dir(&dir.join("new")) {
                Err(_) => "\\Noselect".to_string(),
                // If there is new mail in the folder, we should inform the
                // client. We do this only because we have to perform the
                // check in order to determine selectability. The RFC says
                // not to perform the check if it would slow down the
                // response time.
                Ok(newlisting) => {
                    if newlisting.count() == 0 {
                        "\\Unmarked".to_string()
                    } else {
                        "\\Marked".to_string()
                    }
                }
            }
        }
    };

    // Changing folders in mutt doesn't work properly if we don't indicate
    // whether or not a given folder has subfolders. Mutt has issues
    // selecting folders with subfolders for reading mail, unfortunately.
    match fs::read_dir(&dir) {
        Err(_) => { return None; }
        Ok(dir_listing) => {
            let mut children = false;
            for subdir_entry in dir_listing {
                if let Ok(subdir) = subdir_entry {
                    if *dir == *maildir_path {
                        break;
                    }
                    let subdir_path = subdir.path();
                    let subdir_str = path_filename_to_str!(subdir_path);
                    if subdir_str != "cur" &&
                        subdir_str != "new" &&
                        subdir_str != "tmp" {
                            if fs::read_dir(&subdir.path().join("cur")).is_err() {
                                continue;
                            }
                            if fs::read_dir(&subdir.path().join("new")).is_err() {
                                continue;
                            }
                            children = true;
                            break;
                        }
                }
            }
            if children {
                flags.push_str(" \\HasChildren");
            } else {
                flags.push_str(" \\HasNoChildren");
            }
        }
    }

    let re_path = make_absolute(maildir_path);
    let re_opt = Regex::new(&(format!("^{}", re_path))[..]);
    match re_opt {
        Err(_) =>  None,
        Ok(re) => {
            match fs::metadata(dir) {
                Err(_) => return None,
                Ok(md) =>
                    if !md.is_dir() {
                        return None;
                    }
            };

            if !regex.is_match(&dir_string[..]) {
                return None;
            }
            let mut list_str = "* LIST (".to_string();
            list_str.push_str(&flags[..]);
            list_str.push_str(") \"/\" ");
            list_str.push_str(&(re.replace(&abs_dir[..], "INBOX").replace("INBOX", ""))[..]);
            Some(list_str)
        }
    }
}

/// Go through the logged in user's maildir and list every folder matching
/// the given regular expression. Returns a list of LIST responses.
pub fn list(maildir: &str, regex: &Regex) -> Vec<String> {
    let maildir_path = Path::new(maildir);
    let mut responses = Vec::new();
    if let Some(list_response) = list_dir(maildir_path, regex, maildir_path) {
        responses.push(list_response);
    }
    for dir_res in WalkDir::new(&maildir_path) {
        if let Ok(dir) = dir_res {
            if let Some(list_response) = list_dir(dir.path(), regex, maildir_path) {
                responses.push(list_response);
            }
        }
    }
    responses
}
<|endoftext|>


<commit_before>use time::{Tm, empty_tm};

pub fn msdos_datetime_to_tm(time: u16, date: u16) -> Tm
{
    let seconds = (time & 0b0000000000011111) << 1;
    let minutes = (time & 0b0000011111100000) >> 5;
    let hours =   (time & 0b1111100000000000) >> 11;
    let days =    (date & 0b0000000000011111) >> 0;
    let months =  (date & 0b0000000111100000) >> 5;
    let years =   (date & 0b1111111000000000) >> 9;

    // Month range: Dos [1..12], Tm [0..11]
    // Year zero: Dos 1980, Tm 1900

    Tm {
        tm_sec: seconds as i32,
        tm_min: minutes as i32,
        tm_hour: hours as i32,
        tm_mday: days as i32,
        tm_mon: months as i32 - 1,
        tm_year: years as i32 + 80,
        ..empty_tm()
    }
}

pub fn tm_to_msdos_time(time: Tm) -> u16
{
    ((time.tm_sec >> 1) | (time.tm_min << 5) | (time.tm_hour << 11)) as u16
}

pub fn tm_to_msdos_date(time: Tm) -> u16
{
    (time.tm_mday | ((time.tm_mon + 1) << 5) | ((time.tm_year - 80) << 9)) as u16
}
<commit_msg>Ensure datetime is always in range, add tests<commit_after>use time::{self, Tm};

pub fn msdos_datetime_to_tm(time: u16, date: u16) -> Tm
{
    let seconds = (time & 0b0000000000011111) << 1;
    let minutes = (time & 0b0000011111100000) >> 5;
    let hours =   (time & 0b1111100000000000) >> 11;
    let days =    (date & 0b0000000000011111) >> 0;
    let months =  (date & 0b0000000111100000) >> 5;
    let years =   (date & 0b1111111000000000) >> 9;

    // Month range: Dos [1..12], Tm [0..11]
    // Year zero: Dos 1980, Tm 1900

    let tm = Tm {
        tm_sec: seconds as i32,
        tm_min: minutes as i32,
        tm_hour: hours as i32,
        tm_mday: days as i32,
        tm_mon: months as i32 - 1,
        tm_year: years as i32 + 80,
        ..time::empty_tm()
    };

    // Re-parse the possibly incorrect timestamp to get a correct one.
    // This every value will be in range
    time::at_utc(tm.to_timespec())
}

pub fn tm_to_msdos_time(time: Tm) -> u16
{
    ((time.tm_sec >> 1) | (time.tm_min << 5) | (time.tm_hour << 11)) as u16
}

pub fn tm_to_msdos_date(time: Tm) -> u16
{
    (time.tm_mday | ((time.tm_mon + 1) << 5) | ((time.tm_year - 80) << 9)) as u16
}

#[cfg(test)]
mod dos_tm_test {
    use super::*;
    use time::{self, Tm};

    fn check_date(input: Tm, day: i32, month: i32, year: i32) {
        assert_eq!(input.tm_mday, day);
        assert_eq!(input.tm_mon + 1, month);
        assert_eq!(input.tm_year + 1900, year);
    }

    fn check_time(input: Tm, hour: i32, minute: i32, second: i32) {
        assert_eq!(input.tm_hour, hour);
        assert_eq!(input.tm_min, minute);
        assert_eq!(input.tm_sec, second);
    }

    #[test]
    fn dos_zero() {
        // The 0 date is actually not a correct msdos date, but we
        // will parse it and adjust accordingly.
        let tm = msdos_datetime_to_tm(0, 0);
        check_date(tm, 30, 11, 1979);
        check_time(tm, 0, 0, 0);

        // This is the actual smallest date possible
        let tm = msdos_datetime_to_tm(0, 0b100001);
        check_date(tm, 1, 1, 1980);
        check_time(tm, 0, 0, 0);
    }

    #[test]
    fn dos_today() {
        let tm = msdos_datetime_to_tm(0b01001_100000_10101, 0b0100011_0110_11110);
        check_date(tm, 30, 6, 2015);
        check_time(tm, 9, 32, 42);
    }

    #[test]
    fn zero_dos() {
        let tm = Tm {
            tm_year: 80,
            tm_mon: 0,
            tm_mday: 1,
            tm_hour: 0,
            tm_min: 0,
            tm_sec: 0,
            ..time::empty_tm()
        };
        assert_eq!(tm_to_msdos_date(tm), 0b100001);
        assert_eq!(tm_to_msdos_time(tm), 0);
    }

    #[test]
    fn today_dos() {
        let tm = Tm {
            tm_year: 115,
            tm_mon: 5,
            tm_mday: 30,
            tm_hour: 9,
            tm_min: 32,
            tm_sec: 42,
            ..time::empty_tm()
        };
        assert_eq!(tm_to_msdos_date(tm), 0b0100011_0110_11110);
        assert_eq!(tm_to_msdos_time(tm), 0b01001_100000_10101);
    }
}
<|endoftext|>


<commit_before>//! CLI tool to use the functions provided by the [cretonne-wasm](../cton_wasm/index.html) crate.
//!
//! Reads Wasm binary files (one Wasm module per file), translates the functions' code to Cretonne
//! IL. Can also executes the `start` function of the module by laying out the memories, globals
//! and tables, then emitting the translated code with hardcoded addresses to memory.

use cton_wasm::{translate_module, DummyRuntime, WasmRuntime};
use std::path::PathBuf;
use cretonne::Context;
use cretonne::settings::FlagsOrIsa;
use std::fs::File;
use std::error::Error;
use std::io;
use std::io::prelude::*;
use std::path::Path;
use std::process::Command;
use tempdir::TempDir;
use term;
use utils::{pretty_verifier_error, pretty_error, parse_sets_and_isa, read_to_end};

macro_rules! vprintln {
    ($x: expr, $($tts:tt)*) => {
        if $x {
            println!($($tts)*);
        }
    }
}

macro_rules! vprint {
    ($x: expr, $($tts:tt)*) => {
        if $x {
            print!($($tts)*);
        }
    }
}

pub fn run(
    files: Vec<String>,
    flag_verbose: bool,
    flag_just_decode: bool,
    flag_check_translation: bool,
    flag_print: bool,
    flag_set: Vec<String>,
    flag_isa: String,
) -> Result<(), String> {
    let parsed = parse_sets_and_isa(flag_set, flag_isa)?;

    for filename in files {
        let path = Path::new(&filename);
        let name = String::from(path.as_os_str().to_string_lossy());
        handle_module(
            flag_verbose,
            flag_just_decode,
            flag_check_translation,
            flag_print,
            path.to_path_buf(),
            name,
            parsed.as_fisa(),
        )?;
    }
    Ok(())
}

fn handle_module(
    flag_verbose: bool,
    flag_just_decode: bool,
    flag_check_translation: bool,
    flag_print: bool,
    path: PathBuf,
    name: String,
    fisa: FlagsOrIsa,
) -> Result<(), String> {
    let mut terminal = term::stdout().unwrap();
    terminal.fg(term::color::YELLOW).unwrap();
    vprint!(flag_verbose, "Handling: ");
    terminal.reset().unwrap();
    vprintln!(flag_verbose, "\"{}\"", name);
    terminal.fg(term::color::MAGENTA).unwrap();
    vprint!(flag_verbose, "Translating... ");
    terminal.reset().unwrap();
    let data = match path.extension() {
        None => {
            return Err(String::from("the file extension is not wasm or wat"));
        }
        Some(ext) => {
            match ext.to_str() {
                Some("wasm") => {
                    read_to_end(path.clone()).map_err(|err| {
                        String::from(err.description())
                    })?
                }
                Some("wat") => {
                    let tmp_dir = TempDir::new("cretonne-wasm").unwrap();
                    let file_path = tmp_dir.path().join("module.wasm");
                    File::create(file_path.clone()).unwrap();
                    Command::new("wat2wasm")
                        .arg(path.clone())
                        .arg("-o")
                        .arg(file_path.to_str().unwrap())
                        .output()
                        .or_else(|e| if let io::ErrorKind::NotFound = e.kind() {
                            return Err(String::from("wat2wasm not found"));
                        } else {
                            return Err(String::from(e.description()));
                        })?;
                    read_to_end(file_path).map_err(
                        |err| String::from(err.description()),
                    )?
                }
                None | Some(&_) => {
                    return Err(String::from("the file extension is not wasm or wat"));
                }
            }
        }
    };
    let mut dummy_runtime = DummyRuntime::with_flags(fisa.flags.clone());
    let translation = {
        let runtime: &mut WasmRuntime = &mut dummy_runtime;
        translate_module(&data, runtime)?
    };
    terminal.fg(term::color::GREEN).unwrap();
    vprintln!(flag_verbose, "ok");
    terminal.reset().unwrap();
    if flag_just_decode {
        return Ok(());
    }
    terminal.fg(term::color::MAGENTA).unwrap();
    if flag_check_translation {
        vprint!(flag_verbose, "Checking... ");
    } else {
        vprint!(flag_verbose, "Compiling... ");
    }
    terminal.reset().unwrap();
    for func in &translation.functions {
        let mut context = Context::new();
        context.func = func.clone();
        if flag_check_translation {
            context.verify(fisa).map_err(|err| {
                pretty_verifier_error(&context.func, fisa.isa, err)
            })?;
            continue;
        }
        if let Some(isa) = fisa.isa {
            context.compile(isa).map_err(|err| {
                pretty_error(&context.func, fisa.isa, err)
            })?;
        } else {
            return Err(String::from("compilation requires a target isa"));
        }
        if flag_print {
            vprintln!(flag_verbose, "");
            println!("{}", context.func.display(fisa.isa));
            vprintln!(flag_verbose, "");
        }
    }
    terminal.fg(term::color::GREEN).unwrap();
    vprintln!(flag_verbose, "ok");
    terminal.reset().unwrap();
    Ok(())
}
<commit_msg>Sniff the wasm magic bytes, rather than relying on the filename extension.<commit_after>//! CLI tool to use the functions provided by the [cretonne-wasm](../cton_wasm/index.html) crate.
//!
//! Reads Wasm binary files (one Wasm module per file), translates the functions' code to Cretonne
//! IL. Can also executes the `start` function of the module by laying out the memories, globals
//! and tables, then emitting the translated code with hardcoded addresses to memory.

use cton_wasm::{translate_module, DummyRuntime, WasmRuntime};
use std::path::PathBuf;
use cretonne::Context;
use cretonne::settings::FlagsOrIsa;
use std::fs::File;
use std::error::Error;
use std::io;
use std::path::Path;
use std::process::Command;
use tempdir::TempDir;
use term;
use utils::{pretty_verifier_error, pretty_error, parse_sets_and_isa, read_to_end};

macro_rules! vprintln {
    ($x: expr, $($tts:tt)*) => {
        if $x {
            println!($($tts)*);
        }
    }
}

macro_rules! vprint {
    ($x: expr, $($tts:tt)*) => {
        if $x {
            print!($($tts)*);
        }
    }
}

pub fn run(
    files: Vec<String>,
    flag_verbose: bool,
    flag_just_decode: bool,
    flag_check_translation: bool,
    flag_print: bool,
    flag_set: Vec<String>,
    flag_isa: String,
) -> Result<(), String> {
    let parsed = parse_sets_and_isa(flag_set, flag_isa)?;

    for filename in files {
        let path = Path::new(&filename);
        let name = String::from(path.as_os_str().to_string_lossy());
        handle_module(
            flag_verbose,
            flag_just_decode,
            flag_check_translation,
            flag_print,
            path.to_path_buf(),
            name,
            parsed.as_fisa(),
        )?;
    }
    Ok(())
}

fn handle_module(
    flag_verbose: bool,
    flag_just_decode: bool,
    flag_check_translation: bool,
    flag_print: bool,
    path: PathBuf,
    name: String,
    fisa: FlagsOrIsa,
) -> Result<(), String> {
    let mut terminal = term::stdout().unwrap();
    terminal.fg(term::color::YELLOW).unwrap();
    vprint!(flag_verbose, "Handling: ");
    terminal.reset().unwrap();
    vprintln!(flag_verbose, "\"{}\"", name);
    terminal.fg(term::color::MAGENTA).unwrap();
    vprint!(flag_verbose, "Translating... ");
    terminal.reset().unwrap();
    let mut data = read_to_end(path.clone()).map_err(|err| {
        String::from(err.description())
    })?;
    if !data.starts_with(&[b'\0', b'a', b's', b'm']) {
        let tmp_dir = TempDir::new("cretonne-wasm").unwrap();
        let file_path = tmp_dir.path().join("module.wasm");
        File::create(file_path.clone()).unwrap();
        Command::new("wat2wasm")
            .arg(path.clone())
            .arg("-o")
            .arg(file_path.to_str().unwrap())
            .output()
            .or_else(|e| if let io::ErrorKind::NotFound = e.kind() {
                return Err(String::from("wat2wasm not found"));
            } else {
                return Err(String::from(e.description()));
            })?;
        data = read_to_end(file_path).map_err(
            |err| String::from(err.description()),
        )?;
    }
    let mut dummy_runtime = DummyRuntime::with_flags(fisa.flags.clone());
    let translation = {
        let runtime: &mut WasmRuntime = &mut dummy_runtime;
        translate_module(&data, runtime)?
    };
    terminal.fg(term::color::GREEN).unwrap();
    vprintln!(flag_verbose, "ok");
    terminal.reset().unwrap();
    if flag_just_decode {
        return Ok(());
    }
    terminal.fg(term::color::MAGENTA).unwrap();
    if flag_check_translation {
        vprint!(flag_verbose, "Checking... ");
    } else {
        vprint!(flag_verbose, "Compiling... ");
    }
    terminal.reset().unwrap();
    for func in &translation.functions {
        let mut context = Context::new();
        context.func = func.clone();
        if flag_check_translation {
            context.verify(fisa).map_err(|err| {
                pretty_verifier_error(&context.func, fisa.isa, err)
            })?;
            continue;
        }
        if let Some(isa) = fisa.isa {
            context.compile(isa).map_err(|err| {
                pretty_error(&context.func, fisa.isa, err)
            })?;
        } else {
            return Err(String::from("compilation requires a target isa"));
        }
        if flag_print {
            vprintln!(flag_verbose, "");
            println!("{}", context.func.display(fisa.isa));
            vprintln!(flag_verbose, "");
        }
    }
    terminal.fg(term::color::GREEN).unwrap();
    vprintln!(flag_verbose, "ok");
    terminal.reset().unwrap();
    Ok(())
}
<|endoftext|>


<commit_before>use nix::Error;
use nix::errno::Errno;
use nix::unistd::getpid;
use nix::sys::ptrace;
#[cfg(any(target_os = "android", target_os = "linux"))]
use nix::sys::ptrace::Options;

#[cfg(any(target_os = "android", target_os = "linux"))]
use std::mem;

#[test]
fn test_ptrace() {
    // Just make sure ptrace can be called at all, for now.
    // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
    require_capability!(CAP_SYS_PTRACE);
    let err = ptrace::attach(getpid()).unwrap_err();
    assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::EINVAL) ||
            err == Error::Sys(Errno::ENOSYS));
}

// Just make sure ptrace_setoptions can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_setoptions() {
    require_capability!(CAP_SYS_PTRACE);
    let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getevent can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_getevent() {
    require_capability!(CAP_SYS_PTRACE);
    let err = ptrace::getevent(getpid()).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getsiginfo can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_getsiginfo() {
    require_capability!(CAP_SYS_PTRACE);
    if let Err(Error::UnsupportedOperation) = ptrace::getsiginfo(getpid()) {
        panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!");
    }
}

// Just make sure ptrace_setsiginfo can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_setsiginfo() {
    require_capability!(CAP_SYS_PTRACE);
    let siginfo = unsafe { mem::zeroed() };
    if let Err(Error::UnsupportedOperation) = ptrace::setsiginfo(getpid(), &siginfo) {
        panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!");
    }
}

#[test]
fn test_ptrace_cont() {
    use nix::sys::ptrace;
    use nix::sys::signal::{raise, Signal};
    use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
    use nix::unistd::fork;
    use nix::unistd::ForkResult::*;

    require_capability!(CAP_SYS_PTRACE);

    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");

    // FIXME: qemu-user doesn't implement ptrace on all architectures
    // and retunrs ENOSYS in this case.
    // We (ab)use this behavior to detect the affected platforms
    // and skip the test then.
    // On valid platforms the ptrace call should return Errno::EPERM, this
    // is already tested by `test_ptrace`.
    let err = ptrace::attach(getpid()).unwrap_err();
    if err == Error::Sys(Errno::ENOSYS) {
        return;
    }

    match fork().expect("Error: Fork Failed") {
        Child => {
            ptrace::traceme().unwrap();
            // As recommended by ptrace(2), raise SIGTRAP to pause the child
            // until the parent is ready to continue
            loop {
                raise(Signal::SIGTRAP).unwrap();
            }

        },
        Parent { child } => {
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
            ptrace::cont(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
            ptrace::cont(child, Some(Signal::SIGKILL)).unwrap();
            match waitpid(child, None) {
                Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => {
                    // FIXME It's been observed on some systems (apple) the
                    // tracee may not be killed but remain as a zombie process
                    // affecting other wait based tests. Add an extra kill just
                    // to make sure there are no zombies.
                    let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
                    while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() {
                        let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
                    }
                }
                _ => panic!("The process should have been killed"),
            }
        },
    }
}

// ptrace::{setoptions, getregs} are only available in these platforms
#[cfg(all(target_os = "linux",
          any(target_arch = "x86_64",
              target_arch = "x86"),
          target_env = "gnu"))]
#[test]
fn test_ptrace_syscall() {
    use nix::sys::signal::kill;
    use nix::sys::ptrace;
    use nix::sys::signal::Signal;
    use nix::sys::wait::{waitpid, WaitStatus};
    use nix::unistd::fork;
    use nix::unistd::getpid;
    use nix::unistd::ForkResult::*;

    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");

    match fork().expect("Error: Fork Failed") {
        Child => {
            ptrace::traceme().unwrap();
            // first sigstop until parent is ready to continue
            let pid = getpid();
            kill(pid, Signal::SIGSTOP).unwrap();
            kill(pid, Signal::SIGTERM).unwrap();
            unsafe { ::libc::_exit(0); }
        },

        Parent { child } => {
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGSTOP)));

            // set this option to recognize syscall-stops
            ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap();

            #[cfg(target_pointer_width = "64")]
            let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as i64;

            #[cfg(target_pointer_width = "32")]
            let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as i32;

            // kill entry
            ptrace::syscall(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
            assert_eq!(get_syscall_id(), ::libc::SYS_kill);

            // kill exit
            ptrace::syscall(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
            assert_eq!(get_syscall_id(), ::libc::SYS_kill);

            // receive signal
            ptrace::syscall(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTERM)));

            // inject signal
            ptrace::syscall(child, Signal::SIGTERM).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false)));
        },
    }
}
<commit_msg>Add a missing require_capability! to a test<commit_after>use nix::Error;
use nix::errno::Errno;
use nix::unistd::getpid;
use nix::sys::ptrace;
#[cfg(any(target_os = "android", target_os = "linux"))]
use nix::sys::ptrace::Options;

#[cfg(any(target_os = "android", target_os = "linux"))]
use std::mem;

#[test]
fn test_ptrace() {
    // Just make sure ptrace can be called at all, for now.
    // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
    require_capability!(CAP_SYS_PTRACE);
    let err = ptrace::attach(getpid()).unwrap_err();
    assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::EINVAL) ||
            err == Error::Sys(Errno::ENOSYS));
}

// Just make sure ptrace_setoptions can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_setoptions() {
    require_capability!(CAP_SYS_PTRACE);
    let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getevent can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_getevent() {
    require_capability!(CAP_SYS_PTRACE);
    let err = ptrace::getevent(getpid()).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getsiginfo can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_getsiginfo() {
    require_capability!(CAP_SYS_PTRACE);
    if let Err(Error::UnsupportedOperation) = ptrace::getsiginfo(getpid()) {
        panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!");
    }
}

// Just make sure ptrace_setsiginfo can be called at all, for now.
#[test]
#[cfg(any(target_os = "android", target_os = "linux"))]
fn test_ptrace_setsiginfo() {
    require_capability!(CAP_SYS_PTRACE);
    let siginfo = unsafe { mem::zeroed() };
    if let Err(Error::UnsupportedOperation) = ptrace::setsiginfo(getpid(), &siginfo) {
        panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!");
    }
}

#[test]
fn test_ptrace_cont() {
    use nix::sys::ptrace;
    use nix::sys::signal::{raise, Signal};
    use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
    use nix::unistd::fork;
    use nix::unistd::ForkResult::*;

    require_capability!(CAP_SYS_PTRACE);

    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");

    // FIXME: qemu-user doesn't implement ptrace on all architectures
    // and retunrs ENOSYS in this case.
    // We (ab)use this behavior to detect the affected platforms
    // and skip the test then.
    // On valid platforms the ptrace call should return Errno::EPERM, this
    // is already tested by `test_ptrace`.
    let err = ptrace::attach(getpid()).unwrap_err();
    if err == Error::Sys(Errno::ENOSYS) {
        return;
    }

    match fork().expect("Error: Fork Failed") {
        Child => {
            ptrace::traceme().unwrap();
            // As recommended by ptrace(2), raise SIGTRAP to pause the child
            // until the parent is ready to continue
            loop {
                raise(Signal::SIGTRAP).unwrap();
            }

        },
        Parent { child } => {
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
            ptrace::cont(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
            ptrace::cont(child, Some(Signal::SIGKILL)).unwrap();
            match waitpid(child, None) {
                Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => {
                    // FIXME It's been observed on some systems (apple) the
                    // tracee may not be killed but remain as a zombie process
                    // affecting other wait based tests. Add an extra kill just
                    // to make sure there are no zombies.
                    let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
                    while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() {
                        let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
                    }
                }
                _ => panic!("The process should have been killed"),
            }
        },
    }
}

// ptrace::{setoptions, getregs} are only available in these platforms
#[cfg(all(target_os = "linux",
          any(target_arch = "x86_64",
              target_arch = "x86"),
          target_env = "gnu"))]
#[test]
fn test_ptrace_syscall() {
    use nix::sys::signal::kill;
    use nix::sys::ptrace;
    use nix::sys::signal::Signal;
    use nix::sys::wait::{waitpid, WaitStatus};
    use nix::unistd::fork;
    use nix::unistd::getpid;
    use nix::unistd::ForkResult::*;

    require_capability!(CAP_SYS_PTRACE);

    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");

    match fork().expect("Error: Fork Failed") {
        Child => {
            ptrace::traceme().unwrap();
            // first sigstop until parent is ready to continue
            let pid = getpid();
            kill(pid, Signal::SIGSTOP).unwrap();
            kill(pid, Signal::SIGTERM).unwrap();
            unsafe { ::libc::_exit(0); }
        },

        Parent { child } => {
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGSTOP)));

            // set this option to recognize syscall-stops
            ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap();

            #[cfg(target_pointer_width = "64")]
            let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as i64;

            #[cfg(target_pointer_width = "32")]
            let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as i32;

            // kill entry
            ptrace::syscall(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
            assert_eq!(get_syscall_id(), ::libc::SYS_kill);

            // kill exit
            ptrace::syscall(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
            assert_eq!(get_syscall_id(), ::libc::SYS_kill);

            // receive signal
            ptrace::syscall(child, None).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTERM)));

            // inject signal
            ptrace::syscall(child, Signal::SIGTERM).unwrap();
            assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false)));
        },
    }
}
<|endoftext|>


<commit_before><commit_msg>Auto merge of #2963 - devnexen:recvmsg_linux_fix, r=JohnTitor<commit_after><|endoftext|>


<commit_before>use std::borrow::ToOwned;
use std::collections::hash_map::{HashMap, Entry};
use std::process;

use csv;
use stats::Frequencies;

use {Csv, CsvData, qcheck_sized};
use workdir::Workdir;

fn setup(name: &str) -> (Workdir, process::Command) {
    let rows = vec![
        svec!["h1", "h2"],
        svec!["a", "z"],
        svec!["a", "y"],
        svec!["a", "y"],
        svec!["b", "z"],
        svec!["", "z"],
        svec!["(NULL)", "x"],
    ];

    let wrk = Workdir::new(name);
    wrk.create("in.csv", rows);

    let mut cmd = wrk.command("frequency");
    cmd.arg("in.csv");

    (wrk, cmd)
}

#[test]
fn frequency_no_headers() {
    let (wrk, mut cmd) = setup("frequency_no_headers");
    cmd.args(&["--limit", "0"]).args(&["--select", "1"]).arg("--no-headers");

    let mut got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
    got = got.into_iter().skip(1).collect();
    got.sort();
    let expected = vec![
        svec!["1", "(NULL)", "1"],
        svec!["1", "(NULL)", "1"],
        svec!["1", "a", "3"],
        svec!["1", "b", "1"],
        svec!["1", "h1", "1"],
    ];
    assert_eq!(got, expected);
}

#[test]
fn frequency_no_nulls() {
    let (wrk, mut cmd) = setup("frequency_no_nulls");
    cmd.arg("--no-nulls").args(&["--limit", "0"]).args(&["--select", "h1"]);

    let mut got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
    got.sort();
    let expected = vec![
        svec!["field", "value", "count"],
        svec!["h1", "(NULL)", "1"],
        svec!["h1", "a", "3"],
        svec!["h1", "b", "1"],
    ];
    assert_eq!(got, expected);
}

#[test]
fn frequency_nulls() {
    let (wrk, mut cmd) = setup("frequency_nulls");
    cmd.args(&["--limit", "0"]).args(&["--select", "h1"]);

    let mut got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
    got.sort();
    let expected = vec![
        svec!["field", "value", "count"],
        svec!["h1", "(NULL)", "1"],
        svec!["h1", "(NULL)", "1"],
        svec!["h1", "a", "3"],
        svec!["h1", "b", "1"],
    ];
    assert_eq!(got, expected);
}

#[test]
fn frequency_limit() {
    let (wrk, mut cmd) = setup("frequency_limit");
    cmd.args(&["--limit", "1"]);

    let mut got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
    got.sort();
    let expected = vec![
        svec!["field", "value", "count"],
        svec!["h1", "a", "3"],
        svec!["h2", "z", "3"],
    ];
    assert_eq!(got, expected);
}

#[test]
fn frequency_asc() {
    let (wrk, mut cmd) = setup("frequency_asc");
    cmd.args(&["--limit", "1"]).args(&["--select", "h2"]).arg("--asc");

    let mut got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
    got.sort();
    let expected = vec![
        svec!["field", "value", "count"],
        svec!["h2", "x", "1"],
    ];
    assert_eq!(got, expected);
}

#[test]
fn frequency_select() {
    let (wrk, mut cmd) = setup("frequency_select");
    cmd.args(&["--limit", "0"]).args(&["--select", "h2"]);

    let mut got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
    got.sort();
    let expected = vec![
        svec!["field", "value", "count"],
        svec!["h2", "x", "1"],
        svec!["h2", "y", "2"],
        svec!["h2", "z", "3"],
    ];
    assert_eq!(got, expected);
}

// This tests that a frequency table computed by `xsv` is always the same
// as the frequency table computed in memory.
#[test]
fn prop_frequency() {
    fn p(rows: CsvData) -> bool {
        param_prop_frequency("prop_frequency", rows, false)
    }
    // Run on really small values because we are incredibly careless
    // with allocation.
    qcheck_sized(p as fn(CsvData) -> bool, 2);
}

// This tests that a frequency table computed by `xsv` (with an index) is
// always the same as the frequency table computed in memory.
#[test]
fn prop_frequency_indexed() {
    fn p(rows: CsvData) -> bool {
        param_prop_frequency("prop_frequency_indxed", rows, true)
    }
    // Run on really small values because we are incredibly careless
    // with allocation.
    qcheck_sized(p as fn(CsvData) -> bool, 2);
}

fn param_prop_frequency(name: &str, rows: CsvData, idx: bool) -> bool {
    let wrk = Workdir::new(name);
    if idx {
        wrk.create_indexed("in.csv", rows.clone());
    } else {
        wrk.create("in.csv", rows.clone());
    }

    let mut cmd = wrk.command("frequency");
    cmd.arg("in.csv").args(&["-j", "4"]).args(&["--limit", "0"]);

    let got_ftables = ftables_from_csv_string(wrk.stdout::<String>(&mut cmd));
    let expected_ftables = ftables_from_rows(rows);
    assert_eq_ftables(&got_ftables, &expected_ftables)
}

type FTables = HashMap<String, Frequencies<String>>;

#[derive(Deserialize, RustcDecodable)]
struct FRow {
    field: String,
    value: String,
    count: usize,
}

fn ftables_from_rows<T: Csv>(rows: T) -> FTables {
    let mut rows = rows.to_vecs();
    if rows.len() <= 1 {
        return HashMap::new();
    }

    let header = rows.remove(0);
    let mut ftables = HashMap::new();
    for field in header.iter() {
        ftables.insert(field.clone(), Frequencies::new());
    }
    for row in rows.into_iter() {
        for (i, mut field) in row.into_iter().enumerate() {
            field = field.trim().to_owned();
            if field.is_empty() {
                field = "(NULL)".to_owned();
            }
            ftables.get_mut(&header[i]).unwrap().add(field);
        }
    }
    ftables
}

fn ftables_from_csv_string(data: String) -> FTables {
    let mut rdr = csv::Reader::from_reader(data.as_bytes());
    let mut ftables = HashMap::new();
    for frow in rdr.deserialize() {
        let frow: FRow = frow.unwrap();
        match ftables.entry(frow.field) {
            Entry::Vacant(v) => {
                let mut ftable = Frequencies::new();
                for _ in 0..frow.count {
                    ftable.add(frow.value.clone());
                }
                v.insert(ftable);
            }
            Entry::Occupied(mut v) => {
                for _ in 0..frow.count {
                    v.get_mut().add(frow.value.clone());
                }
            }
        }
    }
    ftables
}

fn freq_data<T>(ftable: &Frequencies<T>) -> Vec<(&T, u64)>
        where T: ::std::hash::Hash + Ord + Clone {
    let mut freqs = ftable.most_frequent();
    freqs.sort();
    freqs
}

fn assert_eq_ftables(got: &FTables, expected: &FTables) -> bool {
    for (k, v) in got.iter() {
        assert_eq!(freq_data(v), freq_data(expected.get(k).unwrap()));
    }
    for (k, v) in expected.iter() {
        assert_eq!(freq_data(got.get(k).unwrap()), freq_data(v));
    }
    true
}
<commit_msg>frequency: fix BOM bug<commit_after>use std::borrow::ToOwned;
use std::collections::hash_map::{HashMap, Entry};
use std::process;

use csv;
use stats::Frequencies;

use {Csv, CsvData, qcheck_sized};
use workdir::Workdir;

fn setup(name: &str) -> (Workdir, process::Command) {
    let rows = vec![
        svec!["h1", "h2"],
        svec!["a", "z"],
        svec!["a", "y"],
        svec!["a", "y"],
        svec!["b", "z"],
        svec!["", "z"],
        svec!["(NULL)", "x"],
    ];

    let wrk = Workdir::new(name);
    wrk.create("in.csv", rows);

    let mut cmd = wrk.command("frequency");
    cmd.arg("in.csv");

    (wrk, cmd)
}

#[test]
fn frequency_no_headers() {
    let (wrk, mut cmd) = setup("frequency_no_headers");
    cmd.args(&["--limit", "0"]).args(&["--select", "1"]).arg("--no-headers");

    let mut got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
    got = got.into_iter().skip(1).collect();
    got.sort();
    let expected = vec![
        svec!["1", "(NULL)", "1"],
        svec!["1", "(NULL)", "1"],
        svec!["1", "a", "3"],
        svec!["1", "b", "1"],
        svec!["1", "h1", "1"],
    ];
    assert_eq!(got, expected);
}

#[test]
fn frequency_no_nulls() {
    let (wrk, mut cmd) = setup("frequency_no_nulls");
    cmd.arg("--no-nulls").args(&["--limit", "0"]).args(&["--select", "h1"]);

    let mut got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
    got.sort();
    let expected = vec![
        svec!["field", "value", "count"],
        svec!["h1", "(NULL)", "1"],
        svec!["h1", "a", "3"],
        svec!["h1", "b", "1"],
    ];
    assert_eq!(got, expected);
}

#[test]
fn frequency_nulls() {
    let (wrk, mut cmd) = setup("frequency_nulls");
    cmd.args(&["--limit", "0"]).args(&["--select", "h1"]);

    let mut got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
    got.sort();
    let expected = vec![
        svec!["field", "value", "count"],
        svec!["h1", "(NULL)", "1"],
        svec!["h1", "(NULL)", "1"],
        svec!["h1", "a", "3"],
        svec!["h1", "b", "1"],
    ];
    assert_eq!(got, expected);
}

#[test]
fn frequency_limit() {
    let (wrk, mut cmd) = setup("frequency_limit");
    cmd.args(&["--limit", "1"]);

    let mut got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
    got.sort();
    let expected = vec![
        svec!["field", "value", "count"],
        svec!["h1", "a", "3"],
        svec!["h2", "z", "3"],
    ];
    assert_eq!(got, expected);
}

#[test]
fn frequency_asc() {
    let (wrk, mut cmd) = setup("frequency_asc");
    cmd.args(&["--limit", "1"]).args(&["--select", "h2"]).arg("--asc");

    let mut got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
    got.sort();
    let expected = vec![
        svec!["field", "value", "count"],
        svec!["h2", "x", "1"],
    ];
    assert_eq!(got, expected);
}

#[test]
fn frequency_select() {
    let (wrk, mut cmd) = setup("frequency_select");
    cmd.args(&["--limit", "0"]).args(&["--select", "h2"]);

    let mut got: Vec<Vec<String>> = wrk.read_stdout(&mut cmd);
    got.sort();
    let expected = vec![
        svec!["field", "value", "count"],
        svec!["h2", "x", "1"],
        svec!["h2", "y", "2"],
        svec!["h2", "z", "3"],
    ];
    assert_eq!(got, expected);
}

// This tests that a frequency table computed by `xsv` is always the same
// as the frequency table computed in memory.
#[test]
fn prop_frequency() {
    fn p(rows: CsvData) -> bool {
        param_prop_frequency("prop_frequency", rows, false)
    }
    // Run on really small values because we are incredibly careless
    // with allocation.
    qcheck_sized(p as fn(CsvData) -> bool, 2);
}

// This tests that running the frequency command on a CSV file with these two
// rows does not burst in flames:
//
//     \u{FEFF}
//     ""
//
// In this case, the `param_prop_frequency` just ignores this particular test.
// Namely, \u{FEFF} is the UTF-8 BOM, which is ignored by the underlying CSV
// reader.
#[test]
fn frequency_bom() {
    let rows = CsvData {
        data: vec![
            ::CsvRecord(vec!["\u{FEFF}".to_string()]),
            ::CsvRecord(vec!["".to_string()]),
        ],
    };
    assert!(param_prop_frequency("prop_frequency", rows, false))
}

// This tests that a frequency table computed by `xsv` (with an index) is
// always the same as the frequency table computed in memory.
#[test]
fn prop_frequency_indexed() {
    fn p(rows: CsvData) -> bool {
        param_prop_frequency("prop_frequency_indxed", rows, true)
    }
    // Run on really small values because we are incredibly careless
    // with allocation.
    qcheck_sized(p as fn(CsvData) -> bool, 2);
}

fn param_prop_frequency(name: &str, rows: CsvData, idx: bool) -> bool {
    if !rows.is_empty() && rows[0][0].len() == 3 && rows[0][0] == "\u{FEFF}" {
        return true;
    }
    let wrk = Workdir::new(name);
    if idx {
        wrk.create_indexed("in.csv", rows.clone());
    } else {
        wrk.create("in.csv", rows.clone());
    }

    let mut cmd = wrk.command("frequency");
    cmd.arg("in.csv").args(&["-j", "4"]).args(&["--limit", "0"]);

    let stdout = wrk.stdout::<String>(&mut cmd);
    let got_ftables = ftables_from_csv_string(stdout);
    let expected_ftables = ftables_from_rows(rows);
    assert_eq_ftables(&got_ftables, &expected_ftables)
}

type FTables = HashMap<String, Frequencies<String>>;

#[derive(Deserialize, RustcDecodable)]
struct FRow {
    field: String,
    value: String,
    count: usize,
}

fn ftables_from_rows<T: Csv>(rows: T) -> FTables {
    let mut rows = rows.to_vecs();
    if rows.len() <= 1 {
        return HashMap::new();
    }

    let header = rows.remove(0);
    let mut ftables = HashMap::new();
    for field in header.iter() {
        ftables.insert(field.clone(), Frequencies::new());
    }
    for row in rows.into_iter() {
        for (i, mut field) in row.into_iter().enumerate() {
            field = field.trim().to_owned();
            if field.is_empty() {
                field = "(NULL)".to_owned();
            }
            ftables.get_mut(&header[i]).unwrap().add(field);
        }
    }
    ftables
}

fn ftables_from_csv_string(data: String) -> FTables {
    let mut rdr = csv::Reader::from_reader(data.as_bytes());
    let mut ftables = HashMap::new();
    for frow in rdr.deserialize() {
        let frow: FRow = frow.unwrap();
        match ftables.entry(frow.field) {
            Entry::Vacant(v) => {
                let mut ftable = Frequencies::new();
                for _ in 0..frow.count {
                    ftable.add(frow.value.clone());
                }
                v.insert(ftable);
            }
            Entry::Occupied(mut v) => {
                for _ in 0..frow.count {
                    v.get_mut().add(frow.value.clone());
                }
            }
        }
    }
    ftables
}

fn freq_data<T>(ftable: &Frequencies<T>) -> Vec<(&T, u64)>
        where T: ::std::hash::Hash + Ord + Clone {
    let mut freqs = ftable.most_frequent();
    freqs.sort();
    freqs
}

fn assert_eq_ftables(got: &FTables, expected: &FTables) -> bool {
    for (k, v) in got.iter() {
        assert_eq!(freq_data(v), freq_data(expected.get(k).unwrap()));
    }
    for (k, v) in expected.iter() {
        assert_eq!(freq_data(got.get(k).unwrap()), freq_data(v));
    }
    true
}
<|endoftext|>