<commit_before>#![allow(unstable)]

extern crate libc;
extern crate "termbox-sys" as termbox;

pub use self::running::running;
pub use self::style::{Style, RB_BOLD, RB_UNDERLINE, RB_REVERSE, RB_NORMAL};

use std::error::Error;
use std::fmt;
use std::marker;
use std::time::duration::Duration;
use std::num::FromPrimitive;

use termbox::RawEvent;
use libc::{c_int, c_uint};

#[derive(Copy)]
pub enum Event {
    KeyEvent(u8, u16, u32),
    ResizeEvent(i32, i32),
    NoEvent
}

#[derive(Copy, PartialEq)]
#[repr(C,u16)]
pub enum Color {
    Default =  0x00,
    Black =    0x01,
    Red =      0x02,
    Green =    0x03,
    Yellow =   0x04,
    Blue =     0x05,
    Magenta =  0x06,
    Cyan =     0x07,
    White =    0x08,
}

mod style {
    bitflags! {
        #[repr(C)]
        flags Style: u16 {
            const TB_NORMAL_COLOR = 0x000F,
            const RB_BOLD = 0x0100,
            const RB_UNDERLINE = 0x0200,
            const RB_REVERSE = 0x0400,
            const RB_NORMAL = 0x0000,
            const TB_ATTRIB = RB_BOLD.bits | RB_UNDERLINE.bits | RB_REVERSE.bits,
        }
    }

    impl Style {
        pub fn from_color(color: super::Color) -> Style {
            Style { bits: color as u16 & TB_NORMAL_COLOR.bits }
        }
    }
}

const NIL_RAW_EVENT: RawEvent = RawEvent { etype: 0, emod: 0, key: 0, ch: 0, w: 0, h: 0 };

// FIXME: Rust doesn't support this enum representation.
// #[derive(Copy,FromPrimitive,Show)]
// #[repr(C,int)]
// pub enum EventErrorKind {
//     Error = -1,
// }
// pub type EventError = Option<EventErrorKind>;
#[allow(non_snake_case)]
pub mod EventErrorKind {
    #[derive(Copy,Show)]
    pub struct Error;
}

pub type EventError = Option<EventErrorKind::Error>;

pub type EventResult<T> = Result<T, EventError>;

impl Error for EventError {
    fn description(&self) -> &str {
        match *self {
            // TODO: Check errno here
            Some(EventErrorKind::Error) => "Unknown error.",
            None => "Unexpected return code."
        }
    }
}

fn unpack_event(ev_type: c_int, ev: &RawEvent) -> EventResult<Event> {
    match ev_type {
        0 => Ok(Event::NoEvent),
        1 => Ok(Event::KeyEvent(ev.emod, ev.key, ev.ch)),
        2 => Ok(Event::ResizeEvent(ev.w, ev.h)),
        // FIXME: Rust doesn't support this error representation
        // res => FromPrimitive::from_int(res as isize),
        -1 => Err(Some(EventErrorKind::Error)),
        _ => Err(None)
    }
}

#[derive(Copy,FromPrimitive,Show)]
#[repr(C,isize)]
pub enum InitErrorKind {
    UnsupportedTerminal = -1,
    FailedToOpenTty = -2,
    PipeTrapError = -3,
}

pub enum InitError {
    Opt(InitOption, Option<Box<Error>>),
    AlreadyOpen,
    TermBox(Option<InitErrorKind>),
}

impl fmt::Show for InitError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.description())
    }
}

impl Error for InitError {
    fn description(&self) -> &str {
        match *self {
            InitError::Opt(InitOption::BufferStderr, _) => "Could not redirect stderr.",
            InitError::AlreadyOpen => "RustBox is already open.",
            InitError::TermBox(e) => e.map_or("Unexpected TermBox return code.", |e| match e {
                InitErrorKind::UnsupportedTerminal => "Unsupported terminal.",
                InitErrorKind::FailedToOpenTty => "Failed to open TTY.",
                InitErrorKind::PipeTrapError => "Pipe trap error.",
            }),
        }
    }

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

mod running {
    use std::sync::atomic::{self, AtomicBool};

    // The state of the RustBox is protected by the lock.  Yay, global state!
    static RUSTBOX_RUNNING: AtomicBool = atomic::ATOMIC_BOOL_INIT;

    /// true iff RustBox is currently running.  Beware of races here--don't rely on this for anything
    /// critical unless you happen to know that RustBox cannot change state when it is called (a good
    /// usecase would be checking to see if it's worth risking double printing backtraces to avoid
    /// having them swallowed up by RustBox).
    pub fn running() -> bool {
        RUSTBOX_RUNNING.load(atomic::Ordering::SeqCst)
    }

    // Internal RAII guard used to ensure we release the running lock whenever we acquire it.
    #[allow(missing_copy_implementations)]
    pub struct RunningGuard(());

    pub fn run() -> Option<RunningGuard> {
        // Ensure that we are not already running and simultaneously set RUSTBOX_RUNNING using an
        // atomic swap.  This ensures that contending threads don't trample each other.
        if RUSTBOX_RUNNING.swap(true, atomic::Ordering::SeqCst) {
            // The Rustbox was already running.
            None
        } else {
            // The RustBox was not already running, and now we have the lock.
            Some(RunningGuard(()))
        }
    }

    impl Drop for RunningGuard {
        fn drop(&mut self) {
            // Indicate that we're free now.  We could probably get away with lower atomicity here,
            // but there's no reason to take that chance.
            RUSTBOX_RUNNING.store(false, atomic::Ordering::SeqCst);
        }
    }
}

// RAII guard for input redirection
#[cfg(unix)]
mod redirect {
    use std::error::Error;

    use libc;
    use std::io::{util, IoError, PipeStream};
    use std::io::pipe::PipePair;
    use std::os::unix::AsRawFd;
    use super::{InitError, InitOption};
    use super::running::RunningGuard;

    pub struct Redirect {
        pair: PipePair,
        fd: PipeStream,
    }

    impl Drop for Redirect {
        fn drop(&mut self) {
            // We make sure that we never actually create the Redirect without also taking a
            // RunningGuard.  This means that we know that this will always be dropped immediately
            // before the RunningGuard is destroyed, and *after* a RustBox containing one is
            // destroyed.
            //
            // We rely on destructor order here: destructors are always executed top-down,  so as
            // long as this is included above the RunningGuard in the RustBox struct, we can be
            // confident that it is destroyed while we're still holding onto the lock.
            unsafe {
                let old_fd = self.pair.writer.as_raw_fd();
                let new_fd = self.fd.as_raw_fd();
                // Reopen new_fd as writer.
                // (Note that if we fail here, we can't really do anything about it, so just ignore any
                // errors).
                if libc::dup2(old_fd, new_fd) != new_fd { return }
            }
            // Copy from reader to writer.
            drop(util::copy(&mut self.pair.reader, &mut self.pair.writer));
        }
    }

    // The reason we take the RunningGuard is to make sure we don't try to redirect before the
    // TermBox is set up.  Otherwise it is possible to race with other threads trying to set up the
    // RustBox.
    fn redirect(new: PipeStream, _: &RunningGuard) -> Result<Redirect, Option<Box<Error>>> {
        // Create a pipe pair.
        let mut pair = try!(PipeStream::pair().map_err( |e| Some(Box::new(e) as Box<Error>)));
        unsafe {
            let new_fd = new.as_raw_fd();
            // Copy new_fd to dup_fd.
            let dup_fd = match libc::dup(new_fd) {
                -1 => return Err(Some(Box::new(IoError::last_error()) as Box<Error>)),
                fd => try!(PipeStream::open(fd).map_err( |e| Some(Box::new(e) as Box<Error>))),
            };
            // Make the writer nonblocking.  This means that even if the stderr pipe fills up,
            // exceptions from stack traces will not block the program.  Unfortunately, if this
            // does happen stderr outputwill be lost until RustBox exits.
            let old_fd = pair.writer.as_raw_fd();
            let res = libc::fcntl(old_fd, libc::F_SETFL, libc::O_NONBLOCK);
            if res != 0 {
                return Err(if res == -1 {
                    Some(Box::new(IoError::last_error()) as Box<Error>)
                } else { None }) // This should really never happen, but no reason to unwind here.
            }
            // Reopen new_fd as writer.
            let fd = libc::dup2(old_fd, new_fd);
            if fd == new_fd {
                // On success, the new file descriptor should be returned.  Replace the old one
                // with dup_fd, since we no longer need an explicit reference to the writer.
                // Note that it is *possible* that some other thread tried to take over stderr
                // between when we did and now, causing a race here.  RustBox won't do it, though.
                // And it's honestly not clear how to guarantee correct behavior there anyway,
                // since if the change had come a fraction of a second later we still probably
                // wouldn't want to overwite it.  In general this is a good argument for why the
                // redirect behavior is optional.
                pair.writer = dup_fd;
                Ok(Redirect {
                    pair: pair,
                    fd: new,
                })
            } else {
                Err(if fd == -1 { Some(Box::new(IoError::last_error()) as Box<Error>) } else { None })
            }
        }
    }

    pub fn redirect_stderr(stderr: &mut Option<Redirect>,
                           rg: &RunningGuard) -> Result<(), InitError> {
        match *stderr {
            Some(_) => {
                // Can only redirect once.
                Err(InitError::Opt(InitOption::BufferStderr, None))
            },
            None => {
                *stderr = Some(try!(redirect(
                            try!(PipeStream::open(libc::STDERR_FILENO)
                            .map_err( |e| InitError::Opt(InitOption::BufferStderr,
                                                         Some(Box::new(e) as Box<Error>)) )),
                            rg)
                        .map_err( |e| InitError::Opt(InitOption::BufferStderr, e))));
                Ok(())
            }
        }
    }
}

#[cfg(not(unix))]
// Not sure how we'll do this on Windows, unimplemented for now.
mod redirect {
    pub enum Redirect { }

    pub fn redirect_stderr(_: &mut Option<Redirect>,
                           _: &super::RunningGuard) -> Result<(), super::InitError> {
        Err(super::InitError::Opt(super::InitOption::BufferStderr, None))
    }
}

#[allow(missing_copy_implementations)]
pub struct RustBox {
    // Termbox is not thread safe
    no_sync: marker::NoSync,

    // We only bother to redirect stderr for the moment, since it's used for panic!
    _stderr: Option<redirect::Redirect>,

    // RAII lock.
    //
    // Note that running *MUST* be the last field in the destructor, since destructors run in
    // top-down order.  Otherwise it will not properly protect the above fields.
    _running: running::RunningGuard,
}

#[derive(Copy,Show)]
pub enum InitOption {
    /// Use this option to automatically buffer stderr while RustBox is running.  It will be
    /// written when RustBox exits.
    ///
    /// This option uses a nonblocking OS pipe to buffer stderr output.  This means that if the
    /// pipe fills up, subsequent writes will fail until RustBox exits.  If this is a concern for
    /// your program, don't use RustBox's default pipe-based redirection; instead, redirect stderr
    /// to a log file or another process that is capable of handling it better.
    BufferStderr,
}

impl RustBox {
    pub fn init(opts: &[Option<InitOption>]) -> Result<RustBox, InitError> {
        // Acquire RAII lock.  This might seem like overkill, but it is easy to forget to release
        // it in the maze of error conditions below.
        let running = match running::run() {
            Some(r) => r,
            None => return Err(InitError::AlreadyOpen)
        };
        // Time to check our options.
        let mut stderr = None;
        for opt in opts.iter().filter_map(|&opt| opt) {
            match opt {
                InitOption::BufferStderr => try!(redirect::redirect_stderr(&mut stderr, &running)),
            }
        }
        // Create the RustBox.
        Ok(unsafe {
            match termbox::tb_init() {
                0 => RustBox {
                    no_sync: marker::NoSync,
                    _stderr: stderr,
                    _running: running,
                },
                res => {
                    return Err(InitError::TermBox(FromPrimitive::from_int(res as isize)))
                }
            }
        })
    }

    pub fn width(&self) -> usize {
        unsafe { termbox::tb_width() as usize }
    }

    pub fn height(&self) -> usize {
        unsafe { termbox::tb_height() as usize }
    }

    pub fn clear(&self) {
        unsafe { termbox::tb_clear() }
    }

    pub fn present(&self) {
        unsafe { termbox::tb_present() }
    }

    pub fn set_cursor(&self, x: isize, y: isize) {
        unsafe { termbox::tb_set_cursor(x as c_int, y as c_int) }
    }

    // Unsafe because u8 is not guaranteed to be a UTF-8 character
    pub unsafe fn change_cell(&self, x: usize, y: usize, ch: u32, fg: u16, bg: u16) {
        termbox::tb_change_cell(x as c_uint, y as c_uint, ch, fg, bg)
    }

    pub fn print(&self, x: usize, y: usize, sty: Style, fg: Color, bg: Color, s: &str) {
        let fg = Style::from_color(fg) | (sty & style::TB_ATTRIB);
        let bg = Style::from_color(bg);
        for (i, ch) in s.chars().enumerate() {
            unsafe {
                self.change_cell(x+i, y, ch as u32, fg.bits(), bg.bits());
            }
        }
    }

    pub fn print_char(&self, x: usize, y: usize, sty: Style, fg: Color, bg: Color, ch: char) {
        let fg = Style::from_color(fg) | (sty & style::TB_ATTRIB);
        let bg = Style::from_color(bg);
        unsafe {
            self.change_cell(x, y, ch as u32, fg.bits(), bg.bits());
        }
    }

    pub fn poll_event(&self) -> EventResult<Event> {
        let ev = NIL_RAW_EVENT;
        let rc = unsafe {
            termbox::tb_poll_event(&ev as *const RawEvent)
        };
        unpack_event(rc, &ev)
    }

    pub fn peek_event(&self, timeout: Duration) -> EventResult<Event> {
        let ev = NIL_RAW_EVENT;
        let rc = unsafe {
            termbox::tb_peek_event(&ev as *const RawEvent, timeout.num_milliseconds() as c_uint)
        };
        unpack_event(rc, &ev)
    }
}

impl Drop for RustBox {
    fn drop(&mut self) {
        // Since only one instance of the RustBox is ever accessible, we should not
        // need to do this atomically.
        // Note: we should definitely have RUSTBOX_RUNNING = true here.
        unsafe {
            termbox::tb_shutdown();
        }
    }
}
<commit_msg>Added set_input_mode<commit_after>#![allow(unstable)]

extern crate libc;
extern crate "termbox-sys" as termbox;

pub use self::running::running;
pub use self::style::{Style, RB_BOLD, RB_UNDERLINE, RB_REVERSE, RB_NORMAL};

use std::error::Error;
use std::fmt;
use std::marker;
use std::time::duration::Duration;
use std::num::FromPrimitive;

use termbox::RawEvent;
use libc::{c_int, c_uint};

#[derive(Copy)]
pub enum Event {
    KeyEvent(u8, u16, u32),
    ResizeEvent(i32, i32),
    NoEvent
}

#[derive(Copy)]
pub enum InputMode {
    Current = 0x00,
    Esc     = 0x01,
    Alt     = 0x02,
}

#[derive(Copy, PartialEq)]
#[repr(C,u16)]
pub enum Color {
    Default =  0x00,
    Black =    0x01,
    Red =      0x02,
    Green =    0x03,
    Yellow =   0x04,
    Blue =     0x05,
    Magenta =  0x06,
    Cyan =     0x07,
    White =    0x08,
}

mod style {
    bitflags! {
        #[repr(C)]
        flags Style: u16 {
            const TB_NORMAL_COLOR = 0x000F,
            const RB_BOLD = 0x0100,
            const RB_UNDERLINE = 0x0200,
            const RB_REVERSE = 0x0400,
            const RB_NORMAL = 0x0000,
            const TB_ATTRIB = RB_BOLD.bits | RB_UNDERLINE.bits | RB_REVERSE.bits,
        }
    }

    impl Style {
        pub fn from_color(color: super::Color) -> Style {
            Style { bits: color as u16 & TB_NORMAL_COLOR.bits }
        }
    }
}

const NIL_RAW_EVENT: RawEvent = RawEvent { etype: 0, emod: 0, key: 0, ch: 0, w: 0, h: 0 };

// FIXME: Rust doesn't support this enum representation.
// #[derive(Copy,FromPrimitive,Show)]
// #[repr(C,int)]
// pub enum EventErrorKind {
//     Error = -1,
// }
// pub type EventError = Option<EventErrorKind>;
#[allow(non_snake_case)]
pub mod EventErrorKind {
    #[derive(Copy,Show)]
    pub struct Error;
}

pub type EventError = Option<EventErrorKind::Error>;

pub type EventResult<T> = Result<T, EventError>;

impl Error for EventError {
    fn description(&self) -> &str {
        match *self {
            // TODO: Check errno here
            Some(EventErrorKind::Error) => "Unknown error.",
            None => "Unexpected return code."
        }
    }
}

fn unpack_event(ev_type: c_int, ev: &RawEvent) -> EventResult<Event> {
    match ev_type {
        0 => Ok(Event::NoEvent),
        1 => Ok(Event::KeyEvent(ev.emod, ev.key, ev.ch)),
        2 => Ok(Event::ResizeEvent(ev.w, ev.h)),
        // FIXME: Rust doesn't support this error representation
        // res => FromPrimitive::from_int(res as isize),
        -1 => Err(Some(EventErrorKind::Error)),
        _ => Err(None)
    }
}

#[derive(Copy,FromPrimitive,Show)]
#[repr(C,isize)]
pub enum InitErrorKind {
    UnsupportedTerminal = -1,
    FailedToOpenTty = -2,
    PipeTrapError = -3,
}

pub enum InitError {
    Opt(InitOption, Option<Box<Error>>),
    AlreadyOpen,
    TermBox(Option<InitErrorKind>),
}

impl fmt::Show for InitError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.description())
    }
}

impl Error for InitError {
    fn description(&self) -> &str {
        match *self {
            InitError::Opt(InitOption::BufferStderr, _) => "Could not redirect stderr.",
            InitError::AlreadyOpen => "RustBox is already open.",
            InitError::TermBox(e) => e.map_or("Unexpected TermBox return code.", |e| match e {
                InitErrorKind::UnsupportedTerminal => "Unsupported terminal.",
                InitErrorKind::FailedToOpenTty => "Failed to open TTY.",
                InitErrorKind::PipeTrapError => "Pipe trap error.",
            }),
        }
    }

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

mod running {
    use std::sync::atomic::{self, AtomicBool};

    // The state of the RustBox is protected by the lock.  Yay, global state!
    static RUSTBOX_RUNNING: AtomicBool = atomic::ATOMIC_BOOL_INIT;

    /// true iff RustBox is currently running.  Beware of races here--don't rely on this for anything
    /// critical unless you happen to know that RustBox cannot change state when it is called (a good
    /// usecase would be checking to see if it's worth risking double printing backtraces to avoid
    /// having them swallowed up by RustBox).
    pub fn running() -> bool {
        RUSTBOX_RUNNING.load(atomic::Ordering::SeqCst)
    }

    // Internal RAII guard used to ensure we release the running lock whenever we acquire it.
    #[allow(missing_copy_implementations)]
    pub struct RunningGuard(());

    pub fn run() -> Option<RunningGuard> {
        // Ensure that we are not already running and simultaneously set RUSTBOX_RUNNING using an
        // atomic swap.  This ensures that contending threads don't trample each other.
        if RUSTBOX_RUNNING.swap(true, atomic::Ordering::SeqCst) {
            // The Rustbox was already running.
            None
        } else {
            // The RustBox was not already running, and now we have the lock.
            Some(RunningGuard(()))
        }
    }

    impl Drop for RunningGuard {
        fn drop(&mut self) {
            // Indicate that we're free now.  We could probably get away with lower atomicity here,
            // but there's no reason to take that chance.
            RUSTBOX_RUNNING.store(false, atomic::Ordering::SeqCst);
        }
    }
}

// RAII guard for input redirection
#[cfg(unix)]
mod redirect {
    use std::error::Error;

    use libc;
    use std::io::{util, IoError, PipeStream};
    use std::io::pipe::PipePair;
    use std::os::unix::AsRawFd;
    use super::{InitError, InitOption};
    use super::running::RunningGuard;

    pub struct Redirect {
        pair: PipePair,
        fd: PipeStream,
    }

    impl Drop for Redirect {
        fn drop(&mut self) {
            // We make sure that we never actually create the Redirect without also taking a
            // RunningGuard.  This means that we know that this will always be dropped immediately
            // before the RunningGuard is destroyed, and *after* a RustBox containing one is
            // destroyed.
            //
            // We rely on destructor order here: destructors are always executed top-down,  so as
            // long as this is included above the RunningGuard in the RustBox struct, we can be
            // confident that it is destroyed while we're still holding onto the lock.
            unsafe {
                let old_fd = self.pair.writer.as_raw_fd();
                let new_fd = self.fd.as_raw_fd();
                // Reopen new_fd as writer.
                // (Note that if we fail here, we can't really do anything about it, so just ignore any
                // errors).
                if libc::dup2(old_fd, new_fd) != new_fd { return }
            }
            // Copy from reader to writer.
            drop(util::copy(&mut self.pair.reader, &mut self.pair.writer));
        }
    }

    // The reason we take the RunningGuard is to make sure we don't try to redirect before the
    // TermBox is set up.  Otherwise it is possible to race with other threads trying to set up the
    // RustBox.
    fn redirect(new: PipeStream, _: &RunningGuard) -> Result<Redirect, Option<Box<Error>>> {
        // Create a pipe pair.
        let mut pair = try!(PipeStream::pair().map_err( |e| Some(Box::new(e) as Box<Error>)));
        unsafe {
            let new_fd = new.as_raw_fd();
            // Copy new_fd to dup_fd.
            let dup_fd = match libc::dup(new_fd) {
                -1 => return Err(Some(Box::new(IoError::last_error()) as Box<Error>)),
                fd => try!(PipeStream::open(fd).map_err( |e| Some(Box::new(e) as Box<Error>))),
            };
            // Make the writer nonblocking.  This means that even if the stderr pipe fills up,
            // exceptions from stack traces will not block the program.  Unfortunately, if this
            // does happen stderr outputwill be lost until RustBox exits.
            let old_fd = pair.writer.as_raw_fd();
            let res = libc::fcntl(old_fd, libc::F_SETFL, libc::O_NONBLOCK);
            if res != 0 {
                return Err(if res == -1 {
                    Some(Box::new(IoError::last_error()) as Box<Error>)
                } else { None }) // This should really never happen, but no reason to unwind here.
            }
            // Reopen new_fd as writer.
            let fd = libc::dup2(old_fd, new_fd);
            if fd == new_fd {
                // On success, the new file descriptor should be returned.  Replace the old one
                // with dup_fd, since we no longer need an explicit reference to the writer.
                // Note that it is *possible* that some other thread tried to take over stderr
                // between when we did and now, causing a race here.  RustBox won't do it, though.
                // And it's honestly not clear how to guarantee correct behavior there anyway,
                // since if the change had come a fraction of a second later we still probably
                // wouldn't want to overwite it.  In general this is a good argument for why the
                // redirect behavior is optional.
                pair.writer = dup_fd;
                Ok(Redirect {
                    pair: pair,
                    fd: new,
                })
            } else {
                Err(if fd == -1 { Some(Box::new(IoError::last_error()) as Box<Error>) } else { None })
            }
        }
    }

    pub fn redirect_stderr(stderr: &mut Option<Redirect>,
                           rg: &RunningGuard) -> Result<(), InitError> {
        match *stderr {
            Some(_) => {
                // Can only redirect once.
                Err(InitError::Opt(InitOption::BufferStderr, None))
            },
            None => {
                *stderr = Some(try!(redirect(
                            try!(PipeStream::open(libc::STDERR_FILENO)
                            .map_err( |e| InitError::Opt(InitOption::BufferStderr,
                                                         Some(Box::new(e) as Box<Error>)) )),
                            rg)
                        .map_err( |e| InitError::Opt(InitOption::BufferStderr, e))));
                Ok(())
            }
        }
    }
}

#[cfg(not(unix))]
// Not sure how we'll do this on Windows, unimplemented for now.
mod redirect {
    pub enum Redirect { }

    pub fn redirect_stderr(_: &mut Option<Redirect>,
                           _: &super::RunningGuard) -> Result<(), super::InitError> {
        Err(super::InitError::Opt(super::InitOption::BufferStderr, None))
    }
}

#[allow(missing_copy_implementations)]
pub struct RustBox {
    // Termbox is not thread safe
    no_sync: marker::NoSync,

    // We only bother to redirect stderr for the moment, since it's used for panic!
    _stderr: Option<redirect::Redirect>,

    // RAII lock.
    //
    // Note that running *MUST* be the last field in the destructor, since destructors run in
    // top-down order.  Otherwise it will not properly protect the above fields.
    _running: running::RunningGuard,
}

#[derive(Copy,Show)]
pub enum InitOption {
    /// Use this option to automatically buffer stderr while RustBox is running.  It will be
    /// written when RustBox exits.
    ///
    /// This option uses a nonblocking OS pipe to buffer stderr output.  This means that if the
    /// pipe fills up, subsequent writes will fail until RustBox exits.  If this is a concern for
    /// your program, don't use RustBox's default pipe-based redirection; instead, redirect stderr
    /// to a log file or another process that is capable of handling it better.
    BufferStderr,
}

impl RustBox {
    pub fn init(opts: &[Option<InitOption>]) -> Result<RustBox, InitError> {
        // Acquire RAII lock.  This might seem like overkill, but it is easy to forget to release
        // it in the maze of error conditions below.
        let running = match running::run() {
            Some(r) => r,
            None => return Err(InitError::AlreadyOpen)
        };
        // Time to check our options.
        let mut stderr = None;
        for opt in opts.iter().filter_map(|&opt| opt) {
            match opt {
                InitOption::BufferStderr => try!(redirect::redirect_stderr(&mut stderr, &running)),
            }
        }
        // Create the RustBox.
        Ok(unsafe {
            match termbox::tb_init() {
                0 => RustBox {
                    no_sync: marker::NoSync,
                    _stderr: stderr,
                    _running: running,
                },
                res => {
                    return Err(InitError::TermBox(FromPrimitive::from_int(res as isize)))
                }
            }
        })
    }

    pub fn width(&self) -> usize {
        unsafe { termbox::tb_width() as usize }
    }

    pub fn height(&self) -> usize {
        unsafe { termbox::tb_height() as usize }
    }

    pub fn clear(&self) {
        unsafe { termbox::tb_clear() }
    }

    pub fn present(&self) {
        unsafe { termbox::tb_present() }
    }

    pub fn set_cursor(&self, x: isize, y: isize) {
        unsafe { termbox::tb_set_cursor(x as c_int, y as c_int) }
    }

    // Unsafe because u8 is not guaranteed to be a UTF-8 character
    pub unsafe fn change_cell(&self, x: usize, y: usize, ch: u32, fg: u16, bg: u16) {
        termbox::tb_change_cell(x as c_uint, y as c_uint, ch, fg, bg)
    }

    pub fn print(&self, x: usize, y: usize, sty: Style, fg: Color, bg: Color, s: &str) {
        let fg = Style::from_color(fg) | (sty & style::TB_ATTRIB);
        let bg = Style::from_color(bg);
        for (i, ch) in s.chars().enumerate() {
            unsafe {
                self.change_cell(x+i, y, ch as u32, fg.bits(), bg.bits());
            }
        }
    }

    pub fn print_char(&self, x: usize, y: usize, sty: Style, fg: Color, bg: Color, ch: char) {
        let fg = Style::from_color(fg) | (sty & style::TB_ATTRIB);
        let bg = Style::from_color(bg);
        unsafe {
            self.change_cell(x, y, ch as u32, fg.bits(), bg.bits());
        }
    }

    pub fn poll_event(&self) -> EventResult<Event> {
        let ev = NIL_RAW_EVENT;
        let rc = unsafe {
            termbox::tb_poll_event(&ev as *const RawEvent)
        };
        unpack_event(rc, &ev)
    }

    pub fn peek_event(&self, timeout: Duration) -> EventResult<Event> {
        let ev = NIL_RAW_EVENT;
        let rc = unsafe {
            termbox::tb_peek_event(&ev as *const RawEvent, timeout.num_milliseconds() as c_uint)
        };
        unpack_event(rc, &ev)
    }

    pub fn set_input_mode(&self, mode: InputMode) {
        unsafe {
            termbox::tb_select_input_mode(mode as c_int);
        }
    }
}

impl Drop for RustBox {
    fn drop(&mut self) {
        // Since only one instance of the RustBox is ever accessible, we should not
        // need to do this atomically.
        // Note: we should definitely have RUSTBOX_RUNNING = true here.
        unsafe {
            termbox::tb_shutdown();
        }
    }
}
<|endoftext|>


<commit_before>extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

trait ElementUtils {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str);
    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>);
}

impl ElementUtils for Element {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str) {
        self.tag(elem_with_text(child_name, child_body));
    }

    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>) {
        if let Some(ref c) = *child_body {
            self.tag_with_text(child_name, &c);
        }
    }
}

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name.to_string(), None, vec![]);
    elem.text(chars.to_string());
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss".to_string(), None, vec![("version".to_string(), None, "2.0".to_string())]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    pub fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    pub fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        if let Err(..) = reader.read_to_string(&mut rss_string) {
            return Err("Error reading string from reader");
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            if let Some(Ok(element)) = builder.handle_event(event) {
                return ViaXml::from_xml(element);
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
/// use std::default::Default;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    pub image: Option<String>,
    pub rating: Option<String>,
    // pub text_input:
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel".to_string(), None, vec![]);

        channel.tag_with_text("title", &self.title);
        channel.tag_with_text("link", &self.link);
        channel.tag_with_text("description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel.tag_with_text_opt("language", &self.language);
        channel.tag_with_text_opt("copyright", &self.copyright);
        channel.tag_with_text_opt("managingEditor", &self.managing_editor);
        channel.tag_with_text_opt("webMaster", &self.web_master);
        channel.tag_with_text_opt("pubDate", &self.pub_date);
        channel.tag_with_text_opt("lastBuildDate", &self.last_build_date);
        channel.tag_with_text_opt("generator", &self.generator);
        channel.tag_with_text_opt("docs", &self.docs);
        channel.tag_with_text_opt("image", &self.image);
        channel.tag_with_text_opt("rating", &self.rating);
        channel.tag_with_text_opt("skipHours", &self.skip_hours);
        channel.tag_with_text_opt("skipDays", &self.skip_days);

        for category in &self.categories {
            channel.tag(category.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = match element.get_child("title", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        };

        let link = match element.get_child("link", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        };

        let description = match element.get_child("description", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        };

        let items = element.get_children("item", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Channel {
            title: title,
            link: link,
            description: description,
            items: items,
            categories: categories,
            ..Default::default()  // TODO
        })
    }
}

#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    pub categories: Vec<Category>,
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item".to_string(), None, vec![]);

        item.tag_with_text_opt("title", &self.title);
        item.tag_with_text_opt("link", &self.link);
        item.tag_with_text_opt("description", &self.description);

        for category in &self.categories {
            item.tag(category.to_xml());
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = element.get_child("title", None).map(|e| e.content_str());
        let link = element.get_child("link", None).map(|e| e.content_str());
        let description = element.get_child("description", None).map(|e| e.content_str());

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Item {
            title: title,
            link: link,
            description: description,
            categories: categories,
        })
    }
}

/// Category
///
/// [RSS 2.0 Specification § Category]
/// (http://cyber.law.harvard.edu/rss/rss.html#ltcategorygtSubelementOfLtitemgt)
#[derive(Default)]
pub struct Category {
    pub domain: Option<String>,
    pub value: String,
}

impl ViaXml for Category {
    fn to_xml(&self) -> Element {
        let mut category = match self.domain {
            Some(ref d) => Element::new("category".to_string(), None, vec![("domain".to_string(), None, d.clone())]),
            None => Element::new("category".to_string(), None, vec![]),
        };
        category.text(self.value.clone());
        category
    }

    fn from_xml(elem: Element) -> Result<Self, &'static str> {
        let domain = elem.get_attribute("domain", None).map(|s| s.to_string());
        let value = elem.content_str();

        Ok(Category {
            domain: domain,
            value: value,
        })
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
            ..Default::default()
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
            ..Default::default()
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_read(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_panic]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_from_read_one_channel_no_properties() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<commit_msg>Simplify a few Option::map<commit_after>extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

trait ElementUtils {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str);
    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>);
}

impl ElementUtils for Element {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str) {
        self.tag(elem_with_text(child_name, child_body));
    }

    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>) {
        if let Some(ref c) = *child_body {
            self.tag_with_text(child_name, &c);
        }
    }
}

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name.to_string(), None, vec![]);
    elem.text(chars.to_string());
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss".to_string(), None, vec![("version".to_string(), None, "2.0".to_string())]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    pub fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    pub fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        if let Err(..) = reader.read_to_string(&mut rss_string) {
            return Err("Error reading string from reader");
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            if let Some(Ok(element)) = builder.handle_event(event) {
                return ViaXml::from_xml(element);
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
/// use std::default::Default;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    pub image: Option<String>,
    pub rating: Option<String>,
    // pub text_input:
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel".to_string(), None, vec![]);

        channel.tag_with_text("title", &self.title);
        channel.tag_with_text("link", &self.link);
        channel.tag_with_text("description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel.tag_with_text_opt("language", &self.language);
        channel.tag_with_text_opt("copyright", &self.copyright);
        channel.tag_with_text_opt("managingEditor", &self.managing_editor);
        channel.tag_with_text_opt("webMaster", &self.web_master);
        channel.tag_with_text_opt("pubDate", &self.pub_date);
        channel.tag_with_text_opt("lastBuildDate", &self.last_build_date);
        channel.tag_with_text_opt("generator", &self.generator);
        channel.tag_with_text_opt("docs", &self.docs);
        channel.tag_with_text_opt("image", &self.image);
        channel.tag_with_text_opt("rating", &self.rating);
        channel.tag_with_text_opt("skipHours", &self.skip_hours);
        channel.tag_with_text_opt("skipDays", &self.skip_days);

        for category in &self.categories {
            channel.tag(category.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = match element.get_child("title", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        };

        let link = match element.get_child("link", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        };

        let description = match element.get_child("description", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        };

        let items = element.get_children("item", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Channel {
            title: title,
            link: link,
            description: description,
            items: items,
            categories: categories,
            ..Default::default()  // TODO
        })
    }
}

#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    pub categories: Vec<Category>,
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item".to_string(), None, vec![]);

        item.tag_with_text_opt("title", &self.title);
        item.tag_with_text_opt("link", &self.link);
        item.tag_with_text_opt("description", &self.description);

        for category in &self.categories {
            item.tag(category.to_xml());
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = element.get_child("title", None).map(Element::content_str);
        let link = element.get_child("link", None).map(Element::content_str);
        let description = element.get_child("description", None).map(Element::content_str);

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Item {
            title: title,
            link: link,
            description: description,
            categories: categories,
        })
    }
}

/// Category
///
/// [RSS 2.0 Specification § Category]
/// (http://cyber.law.harvard.edu/rss/rss.html#ltcategorygtSubelementOfLtitemgt)
#[derive(Default)]
pub struct Category {
    pub domain: Option<String>,
    pub value: String,
}

impl ViaXml for Category {
    fn to_xml(&self) -> Element {
        let mut category = match self.domain {
            Some(ref d) => Element::new("category".to_string(), None, vec![("domain".to_string(), None, d.clone())]),
            None => Element::new("category".to_string(), None, vec![]),
        };
        category.text(self.value.clone());
        category
    }

    fn from_xml(elem: Element) -> Result<Self, &'static str> {
        let domain = elem.get_attribute("domain", None).map(|s| s.to_string());
        let value = elem.content_str();

        Ok(Category {
            domain: domain,
            value: value,
        })
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
            ..Default::default()
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
            ..Default::default()
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_read(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_panic]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_from_read_one_channel_no_properties() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::ops::{
    Deref,
    DerefMut,
};
use std::slice;
use std::convert::From;

/// Make sure the non-nullable pointer optimization does not occur!
enum Flag<T> {
    Alive(T),
    Dropped,
    _Unused,
}

#[derive(Debug)]
struct Dud(i32);

impl Drop for Dud {
    fn drop(&mut self) {
        let Dud(ref i) = *self;
        println!("Drop Dud({})", *i);
    }
}

/// Trait for fixed size arrays.
pub unsafe trait Array {
    #[doc(hidden)]
    type Item;
    #[doc(hidden)]
    unsafe fn new() -> Self;
    #[doc(hidden)]
    fn as_ptr(&self) -> *const Self::Item;
    #[doc(hidden)]
    fn as_mut_ptr(&mut self) -> *mut Self::Item;
    #[doc(hidden)]
    fn capacity() -> usize;
}

macro_rules! fix_array_impl {
    ($len:expr ) => (
        unsafe impl<T> Array for [T; $len] {
            type Item = T;
            unsafe fn new() -> [T; $len] { mem::uninitialized() }
            #[inline]
            fn as_ptr(&self) -> *const T { self as *const _ as *const _ }
            fn as_mut_ptr(&mut self) -> *mut T { self as *mut _ as *mut _}
            #[inline]
            fn capacity() -> usize { $len }
        }
    )
}

macro_rules! fix_array_impl_recursive {
    () => ();
    ($len:expr, $($more:expr,)*) => (
        fix_array_impl!($len);
        fix_array_impl_recursive!($($more,)*);
    );
}

fix_array_impl_recursive!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
                          16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
                          32, 40, 48, 56, 64, 72, 96, 128, 160, 192, 224,);

/// A vector with a fixed capacity.
///
/// The **ArrayVec** is a vector backed by a fixed size array and keeps track of
/// the number of initialized elements.
///
/// The vector is a contiguous value that you can store directly on the stack
/// if needed.
///
/// It offers a simple API of *.push()* and *.pop()* but also dereferences to a slice, so
/// that the full slice API is available.
///
/// The vector also implements a by value iterator.
pub struct ArrayVec<A: Array> {
    len: u8,
    xs: Flag<A>,
}

impl<A: Array> Drop for ArrayVec<A> {
    fn drop(&mut self) {
        // clear all elements, then inhibit drop of inner array
        while let Some(_) = self.pop() { }
        unsafe {
            ptr::write(&mut self.xs, Flag::Dropped);
        }
    }
}

impl<A: Array> ArrayVec<A> {
    /// Create a new empty **ArrayVec**.
    ///
    /// Capacity is inferred from the type parameter.
    ///
    /// ## Examples
    ///
    /// ```
    /// use arrayvec::ArrayVec;
    ///
    /// let mut array = ArrayVec::<[_; 16]>::new();
    /// array.push(1);
    /// array.push(2);
    /// assert_eq!(&array[..], &[1, 2]);
    /// assert_eq!(array.capacity(), 16);
    /// ```
    pub fn new() -> ArrayVec<A> {
        unsafe {
            ArrayVec { xs: Flag::Alive(Array::new()), len: 0 }
        }
    }

    #[inline]
    fn array(&self) -> &A {
        match self.xs {
            Flag::Alive(ref xs) => xs,
            _ => unreachable!(),
            //_ => std::intrinsics::unreachable(),
        }
    }

    #[inline]
    fn array_mut(&mut self) -> &mut A {
        // FIXME: Optimize this, we know it's always Some.
        match self.xs {
            Flag::Alive(ref mut xs) => xs,
            _ => unreachable!(),
            //_ => std::intrinsics::unreachable(),
        }
    }

    /// Return the length of the **ArrayVec**.
    ///
    /// ## Examples
    /// ```
    /// use arrayvec::ArrayVec;
    ///
    /// let mut array = ArrayVec::from([1, 2, 3]);
    /// array.pop();
    /// assert_eq!(array.len(), 2);
    /// ```
    #[inline]
    pub fn len(&self) -> usize { self.len as usize }

    /// Return the capacity of the **ArrayVec**.
    ///
    /// ## Examples
    /// ```
    /// use arrayvec::ArrayVec;
    ///
    /// let array = ArrayVec::from([1, 2, 3]);
    /// assert_eq!(array.capacity(), 3);
    /// ```
    #[inline]
    pub fn capacity(&self) -> usize { A::capacity() }

    /// Push **elt** to the end of the vector.
    ///
    /// Return **None** if the push succeeds, or and return **Some(** *elt* **)**
    /// if the vector is full.
    ///
    /// ## Examples
    /// ```
    /// use arrayvec::ArrayVec;
    ///
    /// let mut array = ArrayVec::<[_; 2]>::new();
    ///
    /// array.push(1);
    /// array.push(2);
    /// let overflow = array.push(3);
    ///
    /// assert_eq!(&array[..], &[1, 2]);
    /// assert_eq!(overflow, Some(3));
    /// ```
    pub fn push(&mut self, elt: A::Item) -> Option<A::Item> {
        if self.len() < A::capacity() {
            unsafe {
                let len = self.len();
                ptr::write(self.get_unchecked_mut(len), elt);
            }
            self.len += 1;
            None
        } else {
            Some(elt)
        }
    }

    /// Remove the last element in the vector.
    ///
    /// Return **Some(** *element* **)** if the vector is non-empty, else **None**.
    ///
    /// ## Examples
    /// ```
    /// use arrayvec::ArrayVec;
    ///
    /// let mut array = ArrayVec::<[_; 2]>::new();
    ///
    /// array.push(1);
    ///
    /// assert_eq!(array.pop(), Some(1));
    /// assert_eq!(array.pop(), None);
    /// ```
    pub fn pop(&mut self) -> Option<A::Item> {
        if self.len == 0 {
            return None
        }
        unsafe {
            self.len -= 1;
            let len = self.len();
            Some(ptr::read(self.get_unchecked_mut(len)))
        }
    }
}

impl<A: Array> Deref for ArrayVec<A> {
    type Target = [A::Item];
    #[inline]
    fn deref(&self) -> &[A::Item] {
        unsafe {
            slice::from_raw_parts(self.array().as_ptr(), self.len())
        }
    }
}

impl<A: Array> DerefMut for ArrayVec<A> {
    #[inline]
    fn deref_mut(&mut self) -> &mut [A::Item] {
        let len = self.len();
        unsafe {
            slice::from_raw_parts_mut(self.array_mut().as_mut_ptr(), len)
        }
    }
}

/// Create an **ArrayVec** from an array.
///
/// ## Examples
/// ```
/// use arrayvec::ArrayVec;
///
/// let mut array = ArrayVec::from([1, 2, 3]);
/// assert_eq!(array.len(), 3);
/// assert_eq!(array.capacity(), 3);
/// ```
impl<A: Array> From<A> for ArrayVec<A> {
    fn from(array: A) -> Self {
        ArrayVec { xs: Flag::Alive(array), len: A::capacity() as u8 }
    }
}

/// Iterate the **ArrayVec** with references to each element.
///
/// ## Examples
///
/// ```
/// use arrayvec::ArrayVec;
///
/// let array = ArrayVec::from([1, 2, 3]);
///
/// for elt in &array {
///     // ...
/// }
/// ```
impl<'a, A: Array> IntoIterator for &'a ArrayVec<A> {
    type Item = &'a A::Item;
    type IntoIter = slice::Iter<'a, A::Item>;
    fn into_iter(self) -> Self::IntoIter { self.iter() }
}

/// Iterate the **ArrayVec** with each element by value.
///
/// The vector is consumed by this operation.
///
/// ## Examples
///
/// ```
/// use arrayvec::ArrayVec;
///
/// for elt in ArrayVec::from([1, 2, 3]) {
///     // ...
/// }
/// ```
impl<A: Array> IntoIterator for ArrayVec<A> {
    type Item = A::Item;
    type IntoIter = IntoIter<A>;
    fn into_iter(self) -> IntoIter<A> {
        IntoIter { index: 0, v: self, }
    }
}

/// By-value iterator for ArrayVec.
pub struct IntoIter<A: Array> {
    index: u8,
    v: ArrayVec<A>,
}

impl<A: Array> Iterator for IntoIter<A> {
    type Item = A::Item;

    fn next(&mut self) -> Option<A::Item> {
        if self.index == self.v.len {
            None
        } else {
            unsafe {
                let ptr = self.v.get_unchecked_mut(self.index as usize);
                let elt = ptr::read(ptr);
                self.index += 1;
                Some(elt)
            }
        }
    }
}

impl<A: Array> Drop for IntoIter<A> {
    fn drop(&mut self) {
        // exhaust iterator and clear the vector
        while let Some(_) = self.next() { }
        self.v.len = 0;
    }
}

#[test]
fn test1() {
    let mut vec: ArrayVec<[Vec<i32>; 3]> = ArrayVec::new();

    vec.push(vec![1,2,4,5]);
    vec.push(vec![3]);
    vec.push(vec![97,98,92]);

    for elt in vec {
        println!("{:?}", elt);
    }
}

fn main() {
    let mut v = ArrayVec::from([1, 2, 3]);
    v.push(4);
    v.push(5);
    println!("{:?}", v.pop());
    println!("{:?}", v.pop());
    println!("{:?}", &*v);
    v.pop();
    v.pop();
    v.push(8);
    println!("{:?}", &*v);

    let mut u: ArrayVec<[_; 3]> = ArrayVec::new();

    u.push(vec![1,2,4,5]);
    u.push(vec![3]);
    u.push(vec![97,98,92]);

    {
        let slc: &[_] = &u;
        println!("{:?}", slc);
    }
    println!("{:?}", u.pop());
    println!("{:?}", u.pop());
    println!("{:?}", u.len());
    println!("{:?}", u[0]);

    let mut v: ArrayVec<[Dud; 2]> = ArrayVec::new();
    v.push(Dud(1));
    v.push(Dud(2));
    v.pop();
    v.pop();
    v.pop();
    v.push(Dud(3));
    v.pop();
    v.push(Dud(4));
    v.push(Dud(5));
    v.push(Dud(6));
    //v.pop();

    println!("v: {:?}", &*v);

    for elt in &v { // slice iter
        println!("Slice Iter: {:?}", elt);
    }

    for elt in v {
        println!("Iter: {:?}", elt);
        //break;
    }

    for elt in ArrayVec::from(["a".to_string(), "b".to_string()]).into_iter() {
        println!("Iter: {:?}", elt);
    }
}
<commit_msg>Tests<commit_after>use std::mem;
use std::ptr;
use std::ops::{
    Deref,
    DerefMut,
};
use std::slice;
use std::convert::From;

/// Make sure the non-nullable pointer optimization does not occur!
enum Flag<T> {
    Alive(T),
    Dropped,
    _Unused,
}

/// Trait for fixed size arrays.
pub unsafe trait Array {
    #[doc(hidden)]
    type Item;
    #[doc(hidden)]
    unsafe fn new() -> Self;
    #[doc(hidden)]
    fn as_ptr(&self) -> *const Self::Item;
    #[doc(hidden)]
    fn as_mut_ptr(&mut self) -> *mut Self::Item;
    #[doc(hidden)]
    fn capacity() -> usize;
}

macro_rules! fix_array_impl {
    ($len:expr ) => (
        unsafe impl<T> Array for [T; $len] {
            type Item = T;
            unsafe fn new() -> [T; $len] { mem::uninitialized() }
            #[inline]
            fn as_ptr(&self) -> *const T { self as *const _ as *const _ }
            fn as_mut_ptr(&mut self) -> *mut T { self as *mut _ as *mut _}
            #[inline]
            fn capacity() -> usize { $len }
        }
    )
}

macro_rules! fix_array_impl_recursive {
    () => ();
    ($len:expr, $($more:expr,)*) => (
        fix_array_impl!($len);
        fix_array_impl_recursive!($($more,)*);
    );
}

fix_array_impl_recursive!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
                          16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
                          32, 40, 48, 56, 64, 72, 96, 128, 160, 192, 224,);

/// A vector with a fixed capacity.
///
/// The **ArrayVec** is a vector backed by a fixed size array and keeps track of
/// the number of initialized elements.
///
/// The vector is a contiguous value that you can store directly on the stack
/// if needed.
///
/// It offers a simple API of *.push()* and *.pop()* but also dereferences to a slice, so
/// that the full slice API is available.
///
/// The vector also implements a by value iterator.
pub struct ArrayVec<A: Array> {
    len: u8,
    xs: Flag<A>,
}

impl<A: Array> Drop for ArrayVec<A> {
    fn drop(&mut self) {
        // clear all elements, then inhibit drop of inner array
        while let Some(_) = self.pop() { }
        unsafe {
            ptr::write(&mut self.xs, Flag::Dropped);
        }
    }
}

impl<A: Array> ArrayVec<A> {
    /// Create a new empty **ArrayVec**.
    ///
    /// Capacity is inferred from the type parameter.
    ///
    /// ## Examples
    ///
    /// ```
    /// use arrayvec::ArrayVec;
    ///
    /// let mut array = ArrayVec::<[_; 16]>::new();
    /// array.push(1);
    /// array.push(2);
    /// assert_eq!(&array[..], &[1, 2]);
    /// assert_eq!(array.capacity(), 16);
    /// ```
    pub fn new() -> ArrayVec<A> {
        unsafe {
            ArrayVec { xs: Flag::Alive(Array::new()), len: 0 }
        }
    }

    #[inline]
    fn array(&self) -> &A {
        match self.xs {
            Flag::Alive(ref xs) => xs,
            _ => unreachable!(),
            //_ => std::intrinsics::unreachable(),
        }
    }

    #[inline]
    fn array_mut(&mut self) -> &mut A {
        // FIXME: Optimize this, we know it's always Some.
        match self.xs {
            Flag::Alive(ref mut xs) => xs,
            _ => unreachable!(),
            //_ => std::intrinsics::unreachable(),
        }
    }

    /// Return the length of the **ArrayVec**.
    ///
    /// ## Examples
    /// ```
    /// use arrayvec::ArrayVec;
    ///
    /// let mut array = ArrayVec::from([1, 2, 3]);
    /// array.pop();
    /// assert_eq!(array.len(), 2);
    /// ```
    #[inline]
    pub fn len(&self) -> usize { self.len as usize }

    /// Return the capacity of the **ArrayVec**.
    ///
    /// ## Examples
    /// ```
    /// use arrayvec::ArrayVec;
    ///
    /// let array = ArrayVec::from([1, 2, 3]);
    /// assert_eq!(array.capacity(), 3);
    /// ```
    #[inline]
    pub fn capacity(&self) -> usize { A::capacity() }

    /// Push **elt** to the end of the vector.
    ///
    /// Return **None** if the push succeeds, or and return **Some(** *elt* **)**
    /// if the vector is full.
    ///
    /// ## Examples
    /// ```
    /// use arrayvec::ArrayVec;
    ///
    /// let mut array = ArrayVec::<[_; 2]>::new();
    ///
    /// array.push(1);
    /// array.push(2);
    /// let overflow = array.push(3);
    ///
    /// assert_eq!(&array[..], &[1, 2]);
    /// assert_eq!(overflow, Some(3));
    /// ```
    pub fn push(&mut self, elt: A::Item) -> Option<A::Item> {
        if self.len() < A::capacity() {
            unsafe {
                let len = self.len();
                ptr::write(self.get_unchecked_mut(len), elt);
            }
            self.len += 1;
            None
        } else {
            Some(elt)
        }
    }

    /// Remove the last element in the vector.
    ///
    /// Return **Some(** *element* **)** if the vector is non-empty, else **None**.
    ///
    /// ## Examples
    /// ```
    /// use arrayvec::ArrayVec;
    ///
    /// let mut array = ArrayVec::<[_; 2]>::new();
    ///
    /// array.push(1);
    ///
    /// assert_eq!(array.pop(), Some(1));
    /// assert_eq!(array.pop(), None);
    /// ```
    pub fn pop(&mut self) -> Option<A::Item> {
        if self.len == 0 {
            return None
        }
        unsafe {
            self.len -= 1;
            let len = self.len();
            Some(ptr::read(self.get_unchecked_mut(len)))
        }
    }
}

impl<A: Array> Deref for ArrayVec<A> {
    type Target = [A::Item];
    #[inline]
    fn deref(&self) -> &[A::Item] {
        unsafe {
            slice::from_raw_parts(self.array().as_ptr(), self.len())
        }
    }
}

impl<A: Array> DerefMut for ArrayVec<A> {
    #[inline]
    fn deref_mut(&mut self) -> &mut [A::Item] {
        let len = self.len();
        unsafe {
            slice::from_raw_parts_mut(self.array_mut().as_mut_ptr(), len)
        }
    }
}

/// Create an **ArrayVec** from an array.
///
/// ## Examples
/// ```
/// use arrayvec::ArrayVec;
///
/// let mut array = ArrayVec::from([1, 2, 3]);
/// assert_eq!(array.len(), 3);
/// assert_eq!(array.capacity(), 3);
/// ```
impl<A: Array> From<A> for ArrayVec<A> {
    fn from(array: A) -> Self {
        ArrayVec { xs: Flag::Alive(array), len: A::capacity() as u8 }
    }
}

/// Iterate the **ArrayVec** with references to each element.
///
/// ## Examples
///
/// ```
/// use arrayvec::ArrayVec;
///
/// let array = ArrayVec::from([1, 2, 3]);
///
/// for elt in &array {
///     // ...
/// }
/// ```
impl<'a, A: Array> IntoIterator for &'a ArrayVec<A> {
    type Item = &'a A::Item;
    type IntoIter = slice::Iter<'a, A::Item>;
    fn into_iter(self) -> Self::IntoIter { self.iter() }
}

/// Iterate the **ArrayVec** with each element by value.
///
/// The vector is consumed by this operation.
///
/// ## Examples
///
/// ```
/// use arrayvec::ArrayVec;
///
/// for elt in ArrayVec::from([1, 2, 3]) {
///     // ...
/// }
/// ```
impl<A: Array> IntoIterator for ArrayVec<A> {
    type Item = A::Item;
    type IntoIter = IntoIter<A>;
    fn into_iter(self) -> IntoIter<A> {
        IntoIter { index: 0, v: self, }
    }
}

/// By-value iterator for ArrayVec.
pub struct IntoIter<A: Array> {
    index: u8,
    v: ArrayVec<A>,
}

impl<A: Array> Iterator for IntoIter<A> {
    type Item = A::Item;

    fn next(&mut self) -> Option<A::Item> {
        if self.index == self.v.len {
            None
        } else {
            unsafe {
                let ptr = self.v.get_unchecked_mut(self.index as usize);
                let elt = ptr::read(ptr);
                self.index += 1;
                Some(elt)
            }
        }
    }
}

impl<A: Array> Drop for IntoIter<A> {
    fn drop(&mut self) {
        // exhaust iterator and clear the vector
        while let Some(_) = self.next() { }
        self.v.len = 0;
    }
}

#[test]
fn test1() {
    use std::ops::Add;

    let mut vec: ArrayVec<[Vec<i32>; 3]> = ArrayVec::new();

    vec.push(vec![1,2,3,4]);
    vec.push(vec![3]);
    vec.push(vec![-1, 90, -2]);

    for elt in &vec {
        println!("{:?}", elt);
    }

    let sum = vec.iter().map(|x| x.iter().fold(0, Add::add)).fold(0, Add::add);
    assert_eq!(sum, 13 + 87);
    let sum_len = vec.into_iter().map(|x| x.len()).fold(0, Add::add);
    assert_eq!(sum_len, 8);
}

fn main() {
    let mut v = ArrayVec::from([1, 2, 3]);
    v.push(4);
    v.push(5);
    println!("{:?}", v.pop());
    println!("{:?}", v.pop());
    println!("{:?}", &*v);
    v.pop();
    v.pop();
    v.push(8);
    println!("{:?}", &*v);

    let mut u: ArrayVec<[_; 3]> = ArrayVec::new();

    u.push(vec![1,2,4,5]);
    u.push(vec![3]);
    u.push(vec![97,98,92]);

    {
        let slc: &[_] = &u;
        println!("{:?}", slc);
    }
    println!("{:?}", u.pop());
    println!("{:?}", u.pop());
    println!("{:?}", u.len());
    println!("{:?}", u[0]);

    println!("v: {:?}", &*v);

    for elt in &v { // slice iter
        println!("Slice Iter: {:?}", elt);
    }

    for elt in v {
        println!("Iter: {:?}", elt);
        //break;
    }

    for elt in ArrayVec::from(["a".to_string(), "b".to_string()]).into_iter() {
        println!("Iter: {:?}", elt);
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;

use byteorder::{WriteBytesExt, BigEndian};
use std::io::{Result, Read, Write};
use std::fs::{File};

struct Header {
    magic: [u8; 4],
    orig_length: u32, // for some reasons the decrucnher asm checks if the first byte is a 0
                    // maybe it is a real u24?
    unknown: u32, // probably a checksum... again...checking explicitly for 0 in the asm :S
}

enum Chunk {
    Unique {
        data: Vec<u8>,
    },
    Repeated {
        byte: u8,
        num: usize,
    },
}

fn write_chunk<T: WriteBytesExt>(chunk: Chunk, target: &mut T) -> Result<()> {
    match chunk {
        Chunk::Unique { data } => {
            // argh...negating without the compiler being a dingens
            try!(target.write_i8((data.len() as i32 * -1) as i8));
            for c in data.iter() {
                try!(target.write_u8(*c));
            }
        },
        Chunk::Repeated { byte, num } => {
            try!(target.write_u8(num as u8 - 1));
            try!(target.write_u8(byte));
        }
    }
    Ok(())
}

fn write_header<T: WriteBytesExt>(length: u64, mut target: T) -> Result<usize> {
    let header = Header { magic: *b"RPck", orig_length: length as u32, unknown: 0};
    for c in header.magic.iter() {
        try!(target.write_u8(*c));
    }

    try!(target.write_u32::<BigEndian>(header.orig_length));
    try!(target.write_u32::<BigEndian>(header.unknown));
    Ok(1)
}

pub fn archive<T: Read>(rfile: T, size: u64, mut wfile: File) -> Result<()> {
    try!(write_header(size, &wfile));
    write_data(rfile, &mut wfile)
}

fn write_data<TR: Read, TW: Write>(readable: TR, mut writeable: &mut TW) -> Result<()> {
    let mut current: Option<Chunk> = None;
    for byte in readable.bytes() {
        // this is all looking super fuzzy :S n00bish code is n00bish :D
        let b = byte.unwrap();
        current = match current {
            None => Some(Chunk::Unique { data: [b].to_vec()}),
            Some(current) => {
                let (chunk, len) = match current {
                    Chunk::Unique { mut data } => {
                        let len = data.len();
                        if len > 1 && data.ends_with(&[b, b]) {
                            if len > 2 {
                                data.split_off(len - 2);
                                try!(write_chunk(Chunk::Unique {
                                    data: data,
                                }, &mut writeable));
                            }
                            (Chunk::Repeated {
                                byte: b,
                                num: 3,
                            }, 3)
                        } else {
                            data.push(b);
                            (Chunk::Unique {
                                data: data,
                            }, len + 1)
                        }
                    },
                    Chunk::Repeated { byte, mut num } => {
                        if b == byte {
                            num += 1;
                            (Chunk::Repeated {
                                byte: b,
                                num: num,
                            }, num)
                        } else {
                            try!(write_chunk(current, &mut writeable));
                            (Chunk::Unique { data: [b].to_vec()}, 1)
                        }
                    }
                };

                if len == 128 {
                    try!(write_chunk(chunk, &mut writeable));
                    None
                } else {
                    Some(chunk)
                }
            }
        };
    }
    if current.is_some() {
        try!(write_chunk(current.unwrap(), &mut writeable));
    }
    Ok(())
}

#[cfg(test)]
mod test;<commit_msg>Finally the missing number is understood<commit_after>extern crate byteorder;

use byteorder::{WriteBytesExt, BigEndian};
use std::io::{Result, Read, Write, Seek, SeekFrom};
use std::fs::{File};

struct Header {
    magic: [u8; 4],
    orig_length: u32, // for some reasons the decrucnher asm checks if the first byte is a 0
                    // maybe it is a real u24?
    offset: u32, // unpacked_size-packed_data+1
}

enum Chunk {
    Unique {
        data: Vec<u8>,
    },
    Repeated {
        byte: u8,
        num: usize,
    },
}

fn write_chunk<T: WriteBytesExt>(chunk: Chunk, target: &mut T) -> Result<usize> {
    let written = match chunk {
        Chunk::Unique { data } => {
            // argh...negating without the compiler being a dingens
            try!(target.write_i8((data.len() as i32 * -1) as i8));
            for c in data.iter() {
                try!(target.write_u8(*c));
            }
            1 + data.len()
        },
        Chunk::Repeated { byte, num } => {
            try!(target.write_u8(num as u8 - 1));
            try!(target.write_u8(byte));
            2
        }
    };
    Ok(written)
}

fn write_header<T: WriteBytesExt>(length: u64, mut target: T) -> Result<usize> {
    let header = Header { magic: *b"RPck", orig_length: length as u32, offset: 0};
    for c in header.magic.iter() {
        try!(target.write_u8(*c));
    }

    try!(target.write_u32::<BigEndian>(header.orig_length));
    try!(target.write_u32::<BigEndian>(header.offset));
    Ok(1)
}

pub fn archive<T: Read>(rfile: T, size: u64, mut wfile: File) -> Result<()> {
    try!(write_header(size, &wfile));
    let packed_size = try!(write_data(rfile, &mut wfile));
    try!(wfile.seek(SeekFrom::Start(8)));
    try!(wfile.write_u32::<BigEndian>((size - packed_size as u64 + 1) as u32));
    Ok(())
}

fn write_data<TR: Read, TW: Write>(readable: TR, mut writeable: &mut TW) -> Result<usize> {
    let mut written:usize = 0;
    let mut current: Option<Chunk> = None;
    for byte in readable.bytes() {
        // this is all looking super fuzzy :S n00bish code is n00bish :D
        let b = byte.unwrap();
        current = match current {
            None => Some(Chunk::Unique { data: [b].to_vec()}),
            Some(current) => {
                let (chunk, len) = match current {
                    Chunk::Unique { mut data } => {
                        let len = data.len();
                        if len > 1 && data.ends_with(&[b, b]) {
                            if len > 2 {
                                data.split_off(len - 2);
                                written = written + try!(write_chunk(Chunk::Unique {
                                    data: data,
                                }, &mut writeable));
                            }
                            (Chunk::Repeated {
                                byte: b,
                                num: 3,
                            }, 3)
                        } else {
                            data.push(b);
                            (Chunk::Unique {
                                data: data,
                            }, len + 1)
                        }
                    },
                    Chunk::Repeated { byte, mut num } => {
                        if b == byte {
                            num += 1;
                            (Chunk::Repeated {
                                byte: b,
                                num: num,
                            }, num)
                        } else {
                            written = written + try!(write_chunk(current, &mut writeable));
                            (Chunk::Unique { data: [b].to_vec()}, 1)
                        }
                    }
                };

                if len == 128 {
                    written = written + try!(write_chunk(chunk, &mut writeable));
                    None
                } else {
                    Some(chunk)
                }
            }
        };
    }
    if current.is_some() {
        written = written + try!(write_chunk(current.unwrap(), &mut writeable));
    }
    Ok(written)
}

#[cfg(test)]
mod test;<|endoftext|>


<commit_before>extern crate mio;
extern crate nix;
extern crate libc;

mod ffi;

use std::io::{Read, Write, Result};
use std::ffi::CString;
use std::mem;

use std::os::unix::prelude::AsRawFd;

#[repr(C, packed)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct BtAddr(pub [u8; 6]);

impl BtAddr {
    pub fn any () -> BtAddr {
        BtAddr ([0, 0, 0, 0, 0, 0])
    }

    pub fn from_string(addr : &str) -> Option<BtAddr> {
        let mut parsed_address : BtAddr = Self::any();
        match CString::new(addr) {
            Ok(a) => {
                if unsafe { ffi::str2ba(a.as_ptr(), &mut parsed_address) } >= 0 {
                    Some(parsed_address)
                }
                else {
                    None
                }
            }
            Err(_) => None
        }
    }

    pub fn to_string(&self) -> String {
        unsafe {
            let ffi_buffer = CString::from_vec_unchecked(vec![0u8; 17]);
            ffi::ba2str(&self, ffi_buffer.as_ptr());
            String::from(ffi_buffer.to_str().unwrap())
        }
    }
}

#[repr(C)]
#[derive(Copy, Debug, Clone)]
struct sockaddr_rc {
    rc_family : libc::sa_family_t,
    rc_bdaddr : BtAddr,
    rc_channel : u8
}

pub enum BluetoothProtocol {
    L2CAP = BTPROTO_L2CAP,
    HCI = BTPROTO_HCI,
    SCO = BTPROTO_SCO,
    RFCOMM = BTPROTO_RFCOMM,
    BNEP = BTPROTO_BNEP,
    CMTP = BTPROTO_CMTP,
    HIDP = BTPROTO_HIDP,
    AVDTP = BTPROTO_AVDTP
}

pub struct BluetoothSocket {
    io : mio::Io
}

const AF_BLUETOOTH : i32 = 31;

const BTPROTO_L2CAP : isize = 0;
const BTPROTO_HCI : isize = 1;
const BTPROTO_SCO : isize = 2;
const BTPROTO_RFCOMM : isize = 3;
const BTPROTO_BNEP : isize = 4;
const BTPROTO_CMTP : isize = 5;
const BTPROTO_HIDP : isize = 6;
const BTPROTO_AVDTP : isize = 7;

impl BluetoothSocket {
    pub fn new(proto : BluetoothProtocol) -> nix::Result<BluetoothSocket> {
        let fd = unsafe { libc::socket(AF_BLUETOOTH, libc::SOCK_STREAM, proto as i32) };

        if fd < 0 {
            Err(nix::Error::last())
        } else {
            Ok(From::from(mio::Io::from_raw_fd(fd)))
        }
    }

    pub fn connect(&mut self, addr: &BtAddr) -> nix::Result<()> {
        let full_address : sockaddr_rc = sockaddr_rc { rc_family : AF_BLUETOOTH as u16,
            rc_bdaddr : *addr,
            rc_channel : 0
        };

        if unsafe { libc::connect(self.io.as_raw_fd(), &full_address as *const _ as *const libc::sockaddr, mem::size_of::<sockaddr_rc>() as u32) } < 0 {
            Err(nix::Error::last())
        } else {
            Ok(())
        }
    }
}

impl From<mio::Io> for BluetoothSocket {
    fn from(io : mio::Io) -> BluetoothSocket {
        BluetoothSocket { io : io }
    }
}

impl mio::Evented for BluetoothSocket {
    fn register(&self, selector: &mut mio::Selector, token: mio::Token, interest: mio::EventSet, opts: mio::PollOpt) -> Result<()> {
        self.io.register(selector, token, interest, opts)
    }

    fn reregister(&self, selector: &mut mio::Selector, token: mio::Token, interest: mio::EventSet, opts: mio::PollOpt) -> Result<()> {
        self.io.reregister(selector, token, interest, opts)
    }

    fn deregister(&self, selector: &mut mio::Selector) -> Result<()> {
        self.io.deregister(selector)
    }
}

impl Read for BluetoothSocket {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.io.read(buf)
    }
}

impl Write for BluetoothSocket {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.io.write(buf)
    }

    fn flush(&mut self) -> Result<()> {
        self.io.flush()
    }
}

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

    #[test()]
    fn btaddr_from_string() {
        match BtAddr::from_string("addr : String") {
            Some(_) => panic!("Somehow managed to parse \"addr : String\" as an address?!"),
            None => ()
        }

        match BtAddr::from_string("00:00:00:00:00:00") {
            Some(addr) => assert_eq!(addr, BtAddr([0u8; 6])),
            None => panic!("")
        }
    }

    #[test()]
    fn btaddr_to_string() {
        assert_eq!(BtAddr::any().to_string(), "00:00:00:00:00:00");
        assert_eq!(BtAddr([1, 2, 3, 4, 5, 6]).to_string(), "06:05:04:03:02:01");
    }

    #[test()]
    fn btaddr_roundtrips_to_from_string() {
        let addr = BtAddr([0, 22, 4, 1, 33, 192]);
        let addr_string = "00:ff:ee:ee:dd:12";

        assert_eq!(addr, BtAddr::from_string(&addr.to_string()).unwrap());
        assert!(addr_string.eq_ignore_ascii_case(&BtAddr::from_string(addr_string).unwrap().to_string()));
    }

    #[cfg(not(feature = "test_without_hardware"))]
    #[test()]
    fn creates_rfcomm_socket() {
        BluetoothSocket::new(BluetoothProtocol::RFCOMM).unwrap();
    }
}
<commit_msg>Fix build on stable.<commit_after>extern crate mio;
extern crate nix;
extern crate libc;

mod ffi;

use std::io::{Read, Write, Result};
use std::ffi::CString;
use std::mem;
use std::str;

use std::os::unix::prelude::AsRawFd;

#[repr(C, packed)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct BtAddr(pub [u8; 6]);

impl BtAddr {
    pub fn any () -> BtAddr {
        BtAddr ([0, 0, 0, 0, 0, 0])
    }

    pub fn from_string(addr : &str) -> Option<BtAddr> {
        let mut parsed_address : BtAddr = Self::any();
        match CString::new(addr) {
            Ok(a) => {
                if unsafe { ffi::str2ba(a.as_ptr(), &mut parsed_address) } >= 0 {
                    Some(parsed_address)
                }
                else {
                    None
                }
            }
            Err(_) => None
        }
    }

    pub fn to_string(&self) -> String {
        unsafe {
            let ffi_buffer = CString::from_vec_unchecked(vec![0u8; 17]);
            ffi::ba2str(&self, ffi_buffer.as_ptr());
            String::from(str::from_utf8(ffi_buffer.as_bytes()).unwrap())
        }
    }
}

#[repr(C)]
#[derive(Copy, Debug, Clone)]
struct sockaddr_rc {
    rc_family : libc::sa_family_t,
    rc_bdaddr : BtAddr,
    rc_channel : u8
}

pub enum BluetoothProtocol {
    L2CAP = BTPROTO_L2CAP,
    HCI = BTPROTO_HCI,
    SCO = BTPROTO_SCO,
    RFCOMM = BTPROTO_RFCOMM,
    BNEP = BTPROTO_BNEP,
    CMTP = BTPROTO_CMTP,
    HIDP = BTPROTO_HIDP,
    AVDTP = BTPROTO_AVDTP
}

pub struct BluetoothSocket {
    io : mio::Io
}

const AF_BLUETOOTH : i32 = 31;

const BTPROTO_L2CAP : isize = 0;
const BTPROTO_HCI : isize = 1;
const BTPROTO_SCO : isize = 2;
const BTPROTO_RFCOMM : isize = 3;
const BTPROTO_BNEP : isize = 4;
const BTPROTO_CMTP : isize = 5;
const BTPROTO_HIDP : isize = 6;
const BTPROTO_AVDTP : isize = 7;

impl BluetoothSocket {
    pub fn new(proto : BluetoothProtocol) -> nix::Result<BluetoothSocket> {
        let fd = unsafe { libc::socket(AF_BLUETOOTH, libc::SOCK_STREAM, proto as i32) };

        if fd < 0 {
            Err(nix::Error::last())
        } else {
            Ok(From::from(mio::Io::from_raw_fd(fd)))
        }
    }

    pub fn connect(&mut self, addr: &BtAddr) -> nix::Result<()> {
        let full_address : sockaddr_rc = sockaddr_rc { rc_family : AF_BLUETOOTH as u16,
            rc_bdaddr : *addr,
            rc_channel : 0
        };

        if unsafe { libc::connect(self.io.as_raw_fd(), &full_address as *const _ as *const libc::sockaddr, mem::size_of::<sockaddr_rc>() as u32) } < 0 {
            Err(nix::Error::last())
        } else {
            Ok(())
        }
    }
}

impl From<mio::Io> for BluetoothSocket {
    fn from(io : mio::Io) -> BluetoothSocket {
        BluetoothSocket { io : io }
    }
}

impl mio::Evented for BluetoothSocket {
    fn register(&self, selector: &mut mio::Selector, token: mio::Token, interest: mio::EventSet, opts: mio::PollOpt) -> Result<()> {
        self.io.register(selector, token, interest, opts)
    }

    fn reregister(&self, selector: &mut mio::Selector, token: mio::Token, interest: mio::EventSet, opts: mio::PollOpt) -> Result<()> {
        self.io.reregister(selector, token, interest, opts)
    }

    fn deregister(&self, selector: &mut mio::Selector) -> Result<()> {
        self.io.deregister(selector)
    }
}

impl Read for BluetoothSocket {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.io.read(buf)
    }
}

impl Write for BluetoothSocket {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        self.io.write(buf)
    }

    fn flush(&mut self) -> Result<()> {
        self.io.flush()
    }
}

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

    #[test()]
    fn btaddr_from_string() {
        match BtAddr::from_string("addr : String") {
            Some(_) => panic!("Somehow managed to parse \"addr : String\" as an address?!"),
            None => ()
        }

        match BtAddr::from_string("00:00:00:00:00:00") {
            Some(addr) => assert_eq!(addr, BtAddr([0u8; 6])),
            None => panic!("")
        }
    }

    #[test()]
    fn btaddr_to_string() {
        assert_eq!(BtAddr::any().to_string(), "00:00:00:00:00:00");
        assert_eq!(BtAddr([1, 2, 3, 4, 5, 6]).to_string(), "06:05:04:03:02:01");
    }

    #[test()]
    fn btaddr_roundtrips_to_from_string() {
        let addr = BtAddr([0, 22, 4, 1, 33, 192]);
        let addr_string = "00:ff:ee:ee:dd:12";

        assert_eq!(addr, BtAddr::from_string(&addr.to_string()).unwrap());
        assert!(addr_string.eq_ignore_ascii_case(&BtAddr::from_string(addr_string).unwrap().to_string()));
    }

    #[cfg(not(feature = "test_without_hardware"))]
    #[test()]
    fn creates_rfcomm_socket() {
        BluetoothSocket::new(BluetoothProtocol::RFCOMM).unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#![recursion_limit="128"]

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate lazy_static;

extern crate rusqlite;

pub extern crate edn;
extern crate mentat_core;
extern crate mentat_db;
extern crate mentat_query;
extern crate mentat_query_algebrizer;
extern crate mentat_query_parser;
extern crate mentat_query_projector;
extern crate mentat_query_translator;
extern crate mentat_sql;
extern crate mentat_tx;
extern crate mentat_tx_parser;

pub use mentat_core::{
    Attribute,
    Entid,
    HasSchema,
    NamespacedKeyword,
    TypedValue,
    Uuid,
    ValueType,
};

pub use mentat_query::{
    FindSpec,
};

pub use mentat_db::{
    CORE_SCHEMA_VERSION,
    DB_SCHEMA_CORE,
    TxReport,
    new_connection,
};

/// Produce the appropriate `NamespacedKeyword` for the provided namespace and name.
/// This lives here because we can't re-export macros:
/// https://github.com/rust-lang/rust/issues/29638.
#[macro_export]
macro_rules! kw {
    ( : $ns:ident / $n:ident ) => {
        // We don't need to go through `new` -- `ident` is strict enough.
        $crate::NamespacedKeyword {
            namespace: stringify!($ns).into(),
            name: stringify!($n).into(),
        }
    };

    ( : $ns:ident$(. $nss:ident)+ / $n:ident ) => {
        // We don't need to go through `new` -- `ident` is strict enough.
        $crate::NamespacedKeyword {
            namespace: concat!(stringify!($ns) $(, ".", stringify!($nss))+).into(),
            name: stringify!($n).into(),
        }
    };
}

pub mod cache;
pub mod errors;
pub mod ident;
pub mod vocabulary;
pub mod conn;
pub mod query;
pub mod entity_builder;

pub fn get_name() -> String {
    return String::from("mentat");
}

pub use query::{
    IntoResult,
    PlainSymbol,
    QueryExecutionResult,
    QueryExplanation,
    QueryInputs,
    QueryOutput,
    QueryPlanStep,
    QueryResults,
    Variable,
    q_once,
};

pub use conn::{
    Conn,
    InProgress,
    Metadata,
    Queryable,
    Store,
};

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

    #[test]
    fn can_import_edn() {
        assert_eq!("foo", Keyword::new("foo").0);
    }

    #[test]
    fn test_kw() {
        assert_eq!(kw!(:foo/bar), NamespacedKeyword::new("foo", "bar"));
        assert_eq!(kw!(:org.mozilla.foo/bar_baz), NamespacedKeyword::new("org.mozilla.foo", "bar_baz"));
    }
}
<commit_msg>Add a var! macro. (#548)(#550) r=emily <commit_after>// Copyright 2016 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#![recursion_limit="128"]

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate lazy_static;

extern crate rusqlite;

pub extern crate edn;
extern crate mentat_core;
extern crate mentat_db;
extern crate mentat_query;
extern crate mentat_query_algebrizer;
extern crate mentat_query_parser;
extern crate mentat_query_projector;
extern crate mentat_query_translator;
extern crate mentat_sql;
extern crate mentat_tx;
extern crate mentat_tx_parser;

pub use mentat_core::{
    Attribute,
    Entid,
    HasSchema,
    NamespacedKeyword,
    TypedValue,
    Uuid,
    ValueType,
};

pub use mentat_query::{
    FindSpec,
};

pub use mentat_db::{
    CORE_SCHEMA_VERSION,
    DB_SCHEMA_CORE,
    TxReport,
    new_connection,
};

/// Produce the appropriate `Variable` for the provided valid ?-prefixed name.
/// This lives here because we can't re-export macros:
/// https://github.com/rust-lang/rust/issues/29638.
#[macro_export]
macro_rules! var {
    ( ? $var:ident ) => {
        $crate::Variable::from_valid_name(concat!("?", stringify!($var)))
    };
}

/// Produce the appropriate `NamespacedKeyword` for the provided namespace and name.
/// This lives here because we can't re-export macros:
/// https://github.com/rust-lang/rust/issues/29638.
#[macro_export]
macro_rules! kw {
    ( : $ns:ident / $n:ident ) => {
        // We don't need to go through `new` -- `ident` is strict enough.
        $crate::NamespacedKeyword {
            namespace: stringify!($ns).into(),
            name: stringify!($n).into(),
        }
    };

    ( : $ns:ident$(. $nss:ident)+ / $n:ident ) => {
        // We don't need to go through `new` -- `ident` is strict enough.
        $crate::NamespacedKeyword {
            namespace: concat!(stringify!($ns) $(, ".", stringify!($nss))+).into(),
            name: stringify!($n).into(),
        }
    };
}

pub mod cache;
pub mod errors;
pub mod ident;
pub mod vocabulary;
pub mod conn;
pub mod query;
pub mod entity_builder;

pub fn get_name() -> String {
    return String::from("mentat");
}

pub use query::{
    IntoResult,
    PlainSymbol,
    QueryExecutionResult,
    QueryExplanation,
    QueryInputs,
    QueryOutput,
    QueryPlanStep,
    QueryResults,
    Variable,
    q_once,
};

pub use conn::{
    Conn,
    InProgress,
    Metadata,
    Queryable,
    Store,
};

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

    #[test]
    fn can_import_edn() {
        assert_eq!("foo", Keyword::new("foo").0);
    }

    #[test]
    fn test_kw() {
        assert_eq!(kw!(:foo/bar), NamespacedKeyword::new("foo", "bar"));
        assert_eq!(kw!(:org.mozilla.foo/bar_baz), NamespacedKeyword::new("org.mozilla.foo", "bar_baz"));
    }

    #[test]
    fn test_var() {
        let foo_baz = var!(?foo_baz);
        let vu = var!(?vü);
        assert_eq!(foo_baz, Variable::from_valid_name("?foo_baz"));
        assert_eq!(vu, Variable::from_valid_name("?vü"));
        assert_eq!(foo_baz.as_str(), "?foo_baz");
    }
}
<|endoftext|>