<commit_before>#![feature(libc)]

extern crate libc;
use std::ffi::CString;
use std::slice;
use std::ptr;

mod ffi;

#[derive(Debug, Copy, Clone)]
pub struct Env {
    env: ffi::Voidptr
}

#[derive(Debug, Copy, Clone)]
pub struct Db {
    db: ffi::Voidptr
}

// XXX: Use Arc
unsafe impl Sync for Db {}
unsafe impl Send for Db {}
unsafe impl Sync for Env {}
unsafe impl Send for Env {}

impl Env {
    pub fn new() -> Env {
        Env {env: unsafe{ffi::sp_env()}}
    }

    pub fn destroy(self) {
        unsafe{ffi::sp_destroy(self.env)};
    }

    pub fn db(&mut self, dbname: &str) {
        // XXX: is dbname copied?
        let dbname = CString::new(dbname).unwrap();
        unsafe {ffi::setstring(self.env, "db\0".as_bytes(), dbname.as_bytes(), 0) };
    }

    pub fn open(&mut self) {
        unsafe {ffi::sp_open(self.env)};
    }

    /*
    fn get_object(&mut self, attr: &str) -> Voidptr {
        let attr = CString::new(attr).unwrap();
        unsafe {ffi::sp_getobject(self.env, attr.as_ptr() as *const u8)}
    }
    */

    pub fn get_db(&self, dbname: &str) -> Option<Db> {
        let dbstr = "db.".to_string() + dbname;
        let attr = CString::new(&dbstr[..]).unwrap();
        unsafe {
            let obj = ffi::sp_getobject(self.env, attr.as_ptr() as *const u8);
            if obj.is_null() {
                None
            }
            else {
                Some(Db {db: obj})
            }
        }
    }

    pub fn setattr(&mut self, key: &str, val: &str) {
        let key = CString::new(key).unwrap();
        let val = CString::new(val).unwrap();
        unsafe {ffi::setstring(self.env, key.as_bytes(), val.as_bytes(), 0) };
    }

    pub fn setintattr(&mut self, key: &str, val: i64) {
        let key = CString::new(key).unwrap();
        unsafe {ffi::sp_setint(self.env, key.as_ptr(), val) };
    }
}

pub struct Object<'a> {
    obj: ffi::Voidptr,
    key: &'a [u8]
}

impl<'a> Object<'a> {
    pub fn get_value<'b>(&'b mut self) -> Option<&'b[u8]> {
        unsafe {
            let mut sz = 0;
            let valptr = ffi::sp_getstring(self.obj, "value\0".as_ptr(), &mut sz);

            // XXX: what if we stored an empty value?
            if valptr.is_null() {
                return None;
            }

            let s = slice::from_raw_parts(valptr as *const u8, sz as usize);
            return Some(s);
        }
    }
}

impl<'a> Drop for Object<'a> {
    fn drop(&mut self) {
        unsafe {ffi::sp_destroy(self.obj);}
    }
}

pub struct Cursor {
    obj: ffi::Voidptr,
}

pub struct CursorObject<'a> {
    obj: ffi::Voidptr,
    cur: &'a Cursor
}

impl<'a> CursorObject<'a> {
    pub fn get_key<'b>(&'b mut self) -> Option<&'b[u8]> {
        unsafe {
            let mut sz = 0;
            let keyptr = ffi::sp_getstring(self.obj, "key\0".as_ptr(), &mut sz);

            if keyptr.is_null() {
                return None;
            }

            let s = slice::from_raw_parts(keyptr as *const u8, sz as usize);
            return Some(s);
        }
    }

    pub fn get_value<'b>(&'b mut self) -> Option<&'b[u8]> {
        unsafe {
            let mut sz = 0;
            let valptr = ffi::sp_getstring(self.obj, "value\0".as_ptr(), &mut sz);

            // XXX: what if we stored an empty value?
            if valptr.is_null() {
                return None;
            }

            let s = slice::from_raw_parts(valptr as *const u8, sz as usize);
            return Some(s);
        }
    }
}

impl<'a> Drop for CursorObject<'a> {
    fn drop(&mut self) {
        unsafe {ffi::sp_destroy(self.obj);}
    }
}

impl Drop for Cursor {
    fn drop(&mut self) {
        unsafe {ffi::sp_destroy(self.obj);}
    }
}

impl Cursor {
    pub fn next<'a>(&'a self) -> Option<CursorObject<'a>> {
        let res = unsafe { ffi::sp_get(self.obj, ptr::null_mut()) };
        if res.is_null() {
            None
        }
        else {
            Some(CursorObject{obj: res, cur: &self})
        }
    }
}

impl Db {
    pub fn set(&mut self, key: &[u8], value: &[u8]) {
        unsafe {
            //ffi::sp_set_kv(self.db, key.as_ptr(), key.len() as i32, value.as_ptr(), value.len() as i32);
            let obj = ffi::sp_object(self.db);
            assert!(!obj.is_null());
            ffi::setkey(obj, key);
            ffi::setvalue(obj, value);
            ffi::sp_set(self.db, obj);
            ffi::sp_destroy(obj);
        }
    }

    pub fn iter_all(&mut self) -> Cursor {
        unsafe {
            let obj = ffi::sp_object(self.db);
            assert!(!obj.is_null());
            ffi::setstring(obj, "order\0".as_bytes(), ">=\0".as_bytes(), 0);
            let cursor = ffi::sp_cursor(self.db, obj);
            assert!(!cursor.is_null());
            Cursor {obj: cursor}
        }
    }

    pub fn get<'a>(&self, key: &'a [u8]) -> Option<Object<'a>> {
        assert!(key.len() > 0);
        unsafe {
            let pattern = ffi::sp_object(self.db);
            if pattern.is_null() {
                // XXX: Return Err
                return None;
            }
            ffi::setkey(pattern, key);
            let res = ffi::sp_get(self.db, pattern);
            if res.is_null() {
                ffi::sp_destroy(pattern);
                return None;
            }
            return Some(Object{obj: res, key: key});
        }
    }
}
<commit_msg>Add helper function get_value()<commit_after>#![feature(libc)]

extern crate libc;
use std::ffi::CString;
use std::slice;
use std::ptr;

mod ffi;

#[derive(Debug, Copy, Clone)]
pub struct Env {
    env: ffi::Voidptr
}

#[derive(Debug, Copy, Clone)]
pub struct Db {
    db: ffi::Voidptr
}

// XXX: Use Arc
unsafe impl Sync for Db {}
unsafe impl Send for Db {}
unsafe impl Sync for Env {}
unsafe impl Send for Env {}

impl Env {
    pub fn new() -> Env {
        Env {env: unsafe{ffi::sp_env()}}
    }

    pub fn destroy(self) {
        unsafe{ffi::sp_destroy(self.env)};
    }

    pub fn db(&mut self, dbname: &str) {
        // XXX: is dbname copied?
        let dbname = CString::new(dbname).unwrap();
        unsafe {ffi::setstring(self.env, "db\0".as_bytes(), dbname.as_bytes(), 0) };
    }

    pub fn open(&mut self) {
        unsafe {ffi::sp_open(self.env)};
    }

    /*
    fn get_object(&mut self, attr: &str) -> Voidptr {
        let attr = CString::new(attr).unwrap();
        unsafe {ffi::sp_getobject(self.env, attr.as_ptr() as *const u8)}
    }
    */

    pub fn get_db(&self, dbname: &str) -> Option<Db> {
        let dbstr = "db.".to_string() + dbname;
        let attr = CString::new(&dbstr[..]).unwrap();
        unsafe {
            let obj = ffi::sp_getobject(self.env, attr.as_ptr() as *const u8);
            if obj.is_null() {
                None
            }
            else {
                Some(Db {db: obj})
            }
        }
    }

    pub fn setattr(&mut self, key: &str, val: &str) {
        let key = CString::new(key).unwrap();
        let val = CString::new(val).unwrap();
        unsafe {ffi::setstring(self.env, key.as_bytes(), val.as_bytes(), 0) };
    }

    pub fn setintattr(&mut self, key: &str, val: i64) {
        let key = CString::new(key).unwrap();
        unsafe {ffi::sp_setint(self.env, key.as_ptr(), val) };
    }
}

pub struct Object<'a> {
    obj: ffi::Voidptr,
    key: &'a [u8]
}

impl<'a> Object<'a> {
    pub fn get_value<'b>(&'b mut self) -> Option<&'b[u8]> {
        unsafe {
            let mut sz = 0;
            let valptr = ffi::sp_getstring(self.obj, "value\0".as_ptr(), &mut sz);

            // XXX: what if we stored an empty value?
            if valptr.is_null() {
                return None;
            }

            let s = slice::from_raw_parts(valptr as *const u8, sz as usize);
            return Some(s);
        }
    }
}

impl<'a> Drop for Object<'a> {
    fn drop(&mut self) {
        unsafe {ffi::sp_destroy(self.obj);}
    }
}

pub struct Cursor {
    obj: ffi::Voidptr,
}

pub struct CursorObject<'a> {
    obj: ffi::Voidptr,
    cur: &'a Cursor
}

impl<'a> CursorObject<'a> {
    pub fn get_key<'b>(&'b mut self) -> Option<&'b[u8]> {
        unsafe {
            let mut sz = 0;
            let keyptr = ffi::sp_getstring(self.obj, "key\0".as_ptr(), &mut sz);

            if keyptr.is_null() {
                return None;
            }

            let s = slice::from_raw_parts(keyptr as *const u8, sz as usize);
            return Some(s);
        }
    }

    pub fn get_value<'b>(&'b mut self) -> Option<&'b[u8]> {
        unsafe {
            let mut sz = 0;
            let valptr = ffi::sp_getstring(self.obj, "value\0".as_ptr(), &mut sz);

            // XXX: what if we stored an empty value?
            if valptr.is_null() {
                return None;
            }

            let s = slice::from_raw_parts(valptr as *const u8, sz as usize);
            return Some(s);
        }
    }
}

impl<'a> Drop for CursorObject<'a> {
    fn drop(&mut self) {
        unsafe {ffi::sp_destroy(self.obj);}
    }
}

impl Drop for Cursor {
    fn drop(&mut self) {
        unsafe {ffi::sp_destroy(self.obj);}
    }
}

impl Cursor {
    pub fn next<'a>(&'a self) -> Option<CursorObject<'a>> {
        let res = unsafe { ffi::sp_get(self.obj, ptr::null_mut()) };
        if res.is_null() {
            None
        }
        else {
            Some(CursorObject{obj: res, cur: &self})
        }
    }
}

impl Db {
    pub fn set(&mut self, key: &[u8], value: &[u8]) {
        unsafe {
            //ffi::sp_set_kv(self.db, key.as_ptr(), key.len() as i32, value.as_ptr(), value.len() as i32);
            let obj = ffi::sp_object(self.db);
            assert!(!obj.is_null());
            ffi::setkey(obj, key);
            ffi::setvalue(obj, value);
            ffi::sp_set(self.db, obj);
            ffi::sp_destroy(obj);
        }
    }

    pub fn iter_all(&mut self) -> Cursor {
        unsafe {
            let obj = ffi::sp_object(self.db);
            assert!(!obj.is_null());
            ffi::setstring(obj, "order\0".as_bytes(), ">=\0".as_bytes(), 0);
            let cursor = ffi::sp_cursor(self.db, obj);
            assert!(!cursor.is_null());
            Cursor {obj: cursor}
        }
    }

    pub fn get<'a>(&self, key: &'a [u8]) -> Option<Object<'a>> {
        assert!(key.len() > 0);
        unsafe {
            let pattern = ffi::sp_object(self.db);
            if pattern.is_null() {
                // XXX: Return Err
                return None;
            }
            ffi::setkey(pattern, key);
            let res = ffi::sp_get(self.db, pattern);
            if res.is_null() {
                ffi::sp_destroy(pattern);
                return None;
            }
            return Some(Object{obj: res, key: key});
        }
    }

    // XXX: Cannot distinguish between key not found and no value.
    pub fn get_value(&self, key: &[u8]) -> Option<Vec<u8>> {
        match self.get(key) {
            None => None,
            Some(mut valobj) => {
                match valobj.get_value() {
                    Some(val) => Some(val.to_vec()),
                    None => None
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/7853871?s=128", html_favicon_url = "https://avatars0.githubusercontent.com/u/7853871?s=256", html_root_url = "http://ironframework.io/core/iron")]
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]

//! The main crate for Iron.
//!
//! ## Overview
//!
//! Iron is a high level web framework built in and for Rust, built on
//! [hyper](https://github.com/hyperium/hyper). Iron is designed to take advantage
//! of Rust's greatest features - its excellent type system and principled
//! approach to ownership in both single threaded and multi threaded contexts.
//!
//! Iron is highly concurrent and can scale horizontally on more machines behind a
//! load balancer or by running more threads on a more powerful machine. Iron
//! avoids the bottlenecks encountered in highly concurrent code by avoiding shared
//! writes and locking in the core framework.
//!
//! ## Hello World
//!
//! ```no_run
//! extern crate iron;
//!
//! use iron::prelude::*;
//! use iron::status;
//!
//! fn main() {
//!     Iron::new(|_: &mut Request| {
//!         Ok(Response::with((status::Ok, "Hello World!")))
//!     }).http("localhost:3000").unwrap();
//! }
//! ```
//!
//! ## Design Philosophy
//!
//! Iron is meant to be as extensible and pluggable as possible; Iron's core is
//! concentrated and avoids unnecessary features by leaving them to middleware,
//! plugins, and modifiers.
//!
//! Middleware, Plugins, and Modifiers are the main ways to extend Iron with new
//! functionality. Most extensions that would be provided by middleware in other
//! web frameworks are instead addressed by the much simpler Modifier and Plugin
//! systems.
//!
//! Modifiers allow external code to manipulate Requests and Response in an ergonomic
//! fashion, allowing third-party extensions to get the same treatment as modifiers
//! defined in Iron itself. Plugins allow for lazily-evaluated, automatically cached
//! extensions to Requests and Responses, perfect for parsing, accessing, and
//! otherwise lazily manipulating an http connection.
//!
//! Middleware are only used when it is necessary to modify the control flow of a
//! Request flow, hijack the entire handling of a Request, check an incoming
//! Request, or to do final post-processing. This covers areas such as routing,
//! mounting, static asset serving, final template rendering, authentication, and
//! logging.
//!
//! Iron comes with only basic modifiers for setting the status, body, and various
//! headers, and the infrastructure for creating modifiers, plugins, and
//! middleware. No plugins or middleware are bundled with Iron.
//!

// Stdlib dependencies
#[macro_use] extern crate log;

// Third party packages
extern crate hyper;
extern crate typemap as tmap;
extern crate plugin;
extern crate error as err;
extern crate url;
extern crate num_cpus;
extern crate conduit_mime_types as mime_types;
#[macro_use]
extern crate lazy_static;

// Request + Response
pub use request::{Request, Url};
pub use response::Response;

// Middleware system
pub use middleware::{BeforeMiddleware, AfterMiddleware, AroundMiddleware,
                     Handler, Chain};

// Server
pub use iron::{Iron, Protocol, Timeouts};

// Extensions
pub use typemap::TypeMap;

// Headers
pub use hyper::header as headers;
pub use hyper::header::Headers;

// Expose `Pluggable` as `Plugin` so users can do `use iron::Plugin`.
pub use plugin::Pluggable as Plugin;

// Expose modifiers.
pub use modifier::Set;

// Errors
pub use error::Error;
pub use error::IronError;

// Mime types
pub use hyper::mime;

/// Iron's error type and associated utilities.
pub mod error;

/// The Result alias used throughout Iron and in clients of Iron.
pub type IronResult<T> = Result<T, IronError>;

/// A module meant to be glob imported when using Iron.
///
/// For instance:
///
/// ```
/// use iron::prelude::*;
/// ```
///
/// This module contains several important traits that provide many
/// of the convenience methods in Iron, as well as `Request`, `Response`
/// `IronResult`, `IronError` and `Iron`.
pub mod prelude {
    pub use {Set, Plugin, Chain, Request, Response,
             IronResult, IronError, Iron};
}

/// Re-exports from the TypeMap crate.
pub mod typemap {
    pub use tmap::{TypeMap, Key};
}

/// Re-exports from the Modifier crate.
pub mod modifier {
    extern crate modifier as modfier;
    pub use self::modfier::*;
}

/// Status Codes
pub mod status {
    pub use hyper::status::StatusCode as Status;
    pub use hyper::status::StatusCode::*;
    pub use hyper::status::StatusClass;
}

/// HTTP Methods
pub mod method {
    pub use hyper::method::Method;
    pub use hyper::method::Method::*;
}

// Publicized to show the documentation
pub mod middleware;

// Response utilities
pub mod response;

// Request utilities
pub mod request;

// Request and Response Modifiers
pub mod modifiers;

// Helper macros for error handling
mod macros;

mod iron;
<commit_msg>(fix) Re-export all of the iron module at the root.<commit_after>#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/7853871?s=128", html_favicon_url = "https://avatars0.githubusercontent.com/u/7853871?s=256", html_root_url = "http://ironframework.io/core/iron")]
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]

//! The main crate for Iron.
//!
//! ## Overview
//!
//! Iron is a high level web framework built in and for Rust, built on
//! [hyper](https://github.com/hyperium/hyper). Iron is designed to take advantage
//! of Rust's greatest features - its excellent type system and principled
//! approach to ownership in both single threaded and multi threaded contexts.
//!
//! Iron is highly concurrent and can scale horizontally on more machines behind a
//! load balancer or by running more threads on a more powerful machine. Iron
//! avoids the bottlenecks encountered in highly concurrent code by avoiding shared
//! writes and locking in the core framework.
//!
//! ## Hello World
//!
//! ```no_run
//! extern crate iron;
//!
//! use iron::prelude::*;
//! use iron::status;
//!
//! fn main() {
//!     Iron::new(|_: &mut Request| {
//!         Ok(Response::with((status::Ok, "Hello World!")))
//!     }).http("localhost:3000").unwrap();
//! }
//! ```
//!
//! ## Design Philosophy
//!
//! Iron is meant to be as extensible and pluggable as possible; Iron's core is
//! concentrated and avoids unnecessary features by leaving them to middleware,
//! plugins, and modifiers.
//!
//! Middleware, Plugins, and Modifiers are the main ways to extend Iron with new
//! functionality. Most extensions that would be provided by middleware in other
//! web frameworks are instead addressed by the much simpler Modifier and Plugin
//! systems.
//!
//! Modifiers allow external code to manipulate Requests and Response in an ergonomic
//! fashion, allowing third-party extensions to get the same treatment as modifiers
//! defined in Iron itself. Plugins allow for lazily-evaluated, automatically cached
//! extensions to Requests and Responses, perfect for parsing, accessing, and
//! otherwise lazily manipulating an http connection.
//!
//! Middleware are only used when it is necessary to modify the control flow of a
//! Request flow, hijack the entire handling of a Request, check an incoming
//! Request, or to do final post-processing. This covers areas such as routing,
//! mounting, static asset serving, final template rendering, authentication, and
//! logging.
//!
//! Iron comes with only basic modifiers for setting the status, body, and various
//! headers, and the infrastructure for creating modifiers, plugins, and
//! middleware. No plugins or middleware are bundled with Iron.
//!

// Stdlib dependencies
#[macro_use] extern crate log;

// Third party packages
extern crate hyper;
extern crate typemap as tmap;
extern crate plugin;
extern crate error as err;
extern crate url;
extern crate num_cpus;
extern crate conduit_mime_types as mime_types;
#[macro_use]
extern crate lazy_static;

// Request + Response
pub use request::{Request, Url};
pub use response::Response;

// Middleware system
pub use middleware::{BeforeMiddleware, AfterMiddleware, AroundMiddleware,
                     Handler, Chain};

// Server
pub use iron::*;

// Extensions
pub use typemap::TypeMap;

// Headers
pub use hyper::header as headers;
pub use hyper::header::Headers;

// Expose `Pluggable` as `Plugin` so users can do `use iron::Plugin`.
pub use plugin::Pluggable as Plugin;

// Expose modifiers.
pub use modifier::Set;

// Errors
pub use error::Error;
pub use error::IronError;

// Mime types
pub use hyper::mime;

/// Iron's error type and associated utilities.
pub mod error;

/// The Result alias used throughout Iron and in clients of Iron.
pub type IronResult<T> = Result<T, IronError>;

/// A module meant to be glob imported when using Iron.
///
/// For instance:
///
/// ```
/// use iron::prelude::*;
/// ```
///
/// This module contains several important traits that provide many
/// of the convenience methods in Iron, as well as `Request`, `Response`
/// `IronResult`, `IronError` and `Iron`.
pub mod prelude {
    pub use {Set, Plugin, Chain, Request, Response,
             IronResult, IronError, Iron};
}

/// Re-exports from the TypeMap crate.
pub mod typemap {
    pub use tmap::{TypeMap, Key};
}

/// Re-exports from the Modifier crate.
pub mod modifier {
    extern crate modifier as modfier;
    pub use self::modfier::*;
}

/// Status Codes
pub mod status {
    pub use hyper::status::StatusCode as Status;
    pub use hyper::status::StatusCode::*;
    pub use hyper::status::StatusClass;
}

/// HTTP Methods
pub mod method {
    pub use hyper::method::Method;
    pub use hyper::method::Method::*;
}

// Publicized to show the documentation
pub mod middleware;

// Response utilities
pub mod response;

// Request utilities
pub mod request;

// Request and Response Modifiers
pub mod modifiers;

// Helper macros for error handling
mod macros;

mod iron;
<|endoftext|>


<commit_before>#![warn(missing_docs)]
#![feature(slice_patterns)]

//! rebind
//! =========
//!
//! A library for binding input keys to actions, and modifying mouse behaviour. Keys can be
//! bound to actions, and then translated during runtime. `Keys` are mapped to `Actions` using
//! a `HashMap`, so lookup time is constant.

extern crate input;
extern crate itertools;
extern crate window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;

#[cfg(test)]
mod test;

use input::{Input, Button, Motion};
use window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::cmp::{PartialEq, Eq, PartialOrd, Ord};
use std::fmt::{Debug, Formatter, Result};
use std::hash::Hash;
use viewport::Viewport;

pub use builder::RebindBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward. Needs to be hashable, as it is used as a
/// lookup key when rebinding an action to a different button.
pub trait Action: Copy + PartialEq + Eq + Hash + PartialOrd + Ord { }

/// A translated action.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// A three-element tuple of Option<Button>. For simplicity, a maximum number of 3
/// buttons can be bound to each action, and this is exposed through the `InputRebind`
/// struct.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    /// Creates a new tuple with no buttons in it (equivalent to `Default::default()`).
    pub fn new() -> Self { Default::default() }

    /// Check if the button is in the tuple.
    pub fn contains(&self, button: Button) -> bool {
        let sbtn = Some(button);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    /// Insert a button into the tuple if there is room, searching from left to right.
    /// If the button is inserted, returns true. Otherwise, if the button is not inserted,
    /// this function returns false.
    pub fn insert_inplace(&mut self, button: Button) -> bool {
        let sbtn = Some(button);
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(sbtn, b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, sbtn, c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, sbtn); true}
            _ => false
        }
    }

    /// Returns an iterator over this tuple.
    pub fn iter(&self) -> ButtonTupleIter { (*self).into_iter() }
}

impl Default for ButtonTuple {
    /// Creates a new tuple with no buttons in it.
    fn default() -> Self { ButtonTuple(None, None, None) }
}

impl IntoIterator for ButtonTuple {
    type Item = Option<Button>;
    type IntoIter = ButtonTupleIter;

    fn into_iter(self) -> ButtonTupleIter {
        ButtonTupleIter {
            button_tuple: self,
            i: 0
        }
    }
}

/// An iterator over a ButtonTuple.
pub struct ButtonTupleIter {
    button_tuple: ButtonTuple,
    i: usize
}

impl Iterator for ButtonTupleIter {
    type Item = Option<Button>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        self.i += 1;
        match i {
            0 => Some(self.button_tuple.0),
            1 => Some(self.button_tuple.1),
            2 => Some(self.button_tuple.2),
            _ => None
        }
    }
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone, Debug, PartialEq)]
pub struct InputTranslator<A: Action> {
    keymap: HashMap<Button, A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {
    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: HashMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event. Returns `None` if there is no
    /// action associated with the `Input` variant.
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.get(&$but_var).map(|x| *x) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    _sensitivity: f64,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            _sensitivity: 0.0,
            viewport_size: size
        }
    }
}

impl Debug for MouseTranslationData {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}, {}, {}, {}, {}, ({}, {})",
               self.x_axis_motion_inverted,
               self.y_axis_motion_inverted,
               self.x_axis_scroll_inverted,
               self.y_axis_scroll_inverted,
               self._sensitivity,
               self.viewport_size.width,
               self.viewport_size.height)
    }
}

impl PartialEq for MouseTranslationData {
    fn eq(&self, other: &Self) -> bool {
        self.x_axis_motion_inverted == other.x_axis_motion_inverted &&
        self.y_axis_motion_inverted == other.y_axis_motion_inverted &&
        self.x_axis_scroll_inverted == other.x_axis_scroll_inverted &&
        self.y_axis_scroll_inverted == other.y_axis_scroll_inverted &&
        self._sensitivity == other._sensitivity &&
        self.viewport_size.width    == other.viewport_size.width &&
        self.viewport_size.height   == other.viewport_size.height
    }
}

#[derive(Clone, Debug, PartialEq)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

/// An interface for rebinding keys to actions. This is freely convertable to and
/// from an InputTranslator.
#[derive(Clone, Debug, PartialEq)]
pub struct InputRebind<A: Action> {
    keymap: HashMap<A, ButtonTuple>,
    mouse_data: MouseTranslationData
}

impl<A: Action> InputRebind<A> {
    /// Creates a new InputRebind with no stored Action/ButtonTuple pairs.
    pub fn new(size: Size) -> Self {
        InputRebind {
            keymap: HashMap::new(),
            mouse_data: MouseTranslationData::new(size)
        }
    }

    /// Insert an Action into this InputRebind. If the Action is already in the
    /// InputRebind, then its ButtonTuple will be reset to (None, None, None), and
    /// the old ButtonTuple will be returned.
    pub fn insert_action(&mut self, action: A) -> Option<ButtonTuple> {
        self.keymap.insert(action, ButtonTuple::new())
    }

    /// Insert an Action into this InputRebind, and assign it to the ButtonTuple.
    /// If the Action is already in the InputRebind, the old ButtonTuple will be
    /// returned.
    pub fn insert_action_with_buttons(&mut self, action: A, buttons: ButtonTuple) -> Option<ButtonTuple> {
        self.keymap.insert(action, buttons)
    }

    /// Return a reference to the current ButtonTuple stored for an action. If the action
    /// is not stored in this InputRebind, then `None` will be returned.
    pub fn get_bindings(&self, action: &A) -> Option<&ButtonTuple> {
        self.keymap.get(action)
    }

    /// Returns a mutable reference to the current ButtonTuple stored for an action. If the
    /// action is not stored in this InputRebind, then `None` will be returned.
    pub fn get_bindings_mut(&mut self, action: &mut A) -> Option<&mut ButtonTuple> {
        self.keymap.get_mut(action)
    }

    /// Returns a reference to the boolean which represents whether x axis scrolling is inverted.
    pub fn get_x_scroll_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_scroll_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether x axis scrolling is inverted.
    pub fn get_x_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_scroll_inverted
    }

    /// Returns a reference to the boolean which represents whether y axis scrolling is inverted.
    pub fn get_y_scroll_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_scroll_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether y axis scrolling is inverted.
    pub fn get_y_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_scroll_inverted
    }

    /// Returns a reference to the boolean which represents whether mouse movement along the x axis is
    /// inverted.
    pub fn get_x_motion_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_motion_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether mouse movement along the
    /// x axis is inverted.
    pub fn get_x_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_motion_inverted
    }

    /// Returns a reference to the boolean which represents whether mouse movement along the y axis is
    /// inverted.
    pub fn get_y_motion_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_motion_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether mouse movement along the
    /// y axis is inverted.
    pub fn get_y_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_motion_inverted
    }

    /// Returns a reference to the currently stored viewport size used for calculating the imaginary mouse
    /// position.
    pub fn get_viewport_size(&self) -> &Size {
        &self.mouse_data.viewport_size
    }

    /// Returns a mutable reference to the currently stored viewport size used for calculating the imaginary
    /// mouse position.
    pub fn get_viewport_size_mut(&mut self) -> &mut Size {
        &mut self.mouse_data.viewport_size
    }
}

impl<A: Action> Default for InputRebind<A> {
    /// Creates an `InputRebind` with no pairs. In addition, the viewport size is set to [800, 600].
    fn default() -> Self {
        InputRebind::new((800, 600).into())
    }
}

impl<A: Action> Into<InputTranslator<A>> for InputRebind<A> {
    fn into(self) -> InputTranslator<A> {
        let mut input_translator = InputTranslator::new(self.mouse_data.viewport_size);
        input_translator.mouse_translator.data = self.mouse_data;
        input_translator.keymap = self.keymap.values()
                                             .flat_map(|&bt| bt.into_iter())
                                             .filter_map(|x| x)
                                             .zip(self.keymap.keys().cloned())
                                             .collect();

        input_translator
    }
}

impl<A: Action> Into<InputRebind<A>> for InputTranslator<A> {
    fn into(self) -> InputRebind<A> {
        use itertools::Itertools;

        let mut input_rebind = InputRebind::new(self.mouse_translator.data.viewport_size);
        input_rebind.mouse_data = self.mouse_translator.data;
        input_rebind.keymap = self.keymap.iter()
                                         .map(|(k, v)| (*v, vec![Some(*k)]))
                                         .sorted_by(|&(v0, _), &(v1, _)| Ord::cmp(&v0, &v1))
                                         .into_iter()
                                         .coalesce(|(k0, v0), (k1, v1)| if k0 == k1 {
                                                 Ok((k0, v0.into_iter().chain(v1).collect()))
                                             } else {
                                                 Err(((k0, v0), (k1, v1)))
                                             })
                                         .map(|(k, v)| if let [b0, b1, b2] = &v.iter()
                                                                               .cloned()
                                                                               .pad_using(3, |_| None)
                                                                               .take(3)
                                                                               .collect::<Vec<_>>()[..] {
                                                  (k, ButtonTuple(b0, b1, b2))
                                             } else {
                                                 unreachable!();
                                             })
                                         .collect();

        input_rebind
    }
}
<commit_msg>Use Option::cloned instead of map deref in InputTranslator::translate<commit_after>#![warn(missing_docs)]
#![feature(slice_patterns)]

//! rebind
//! =========
//!
//! A library for binding input keys to actions, and modifying mouse behaviour. Keys can be
//! bound to actions, and then translated during runtime. `Keys` are mapped to `Actions` using
//! a `HashMap`, so lookup time is constant.

extern crate input;
extern crate itertools;
extern crate window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;

#[cfg(test)]
mod test;

use input::{Input, Button, Motion};
use window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::cmp::{PartialEq, Eq, PartialOrd, Ord};
use std::fmt::{Debug, Formatter, Result};
use std::hash::Hash;
use viewport::Viewport;

pub use builder::RebindBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward. Needs to be hashable, as it is used as a
/// lookup key when rebinding an action to a different button.
pub trait Action: Copy + PartialEq + Eq + Hash + PartialOrd + Ord { }

/// A translated action.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// A three-element tuple of Option<Button>. For simplicity, a maximum number of 3
/// buttons can be bound to each action, and this is exposed through the `InputRebind`
/// struct.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    /// Creates a new tuple with no buttons in it (equivalent to `Default::default()`).
    pub fn new() -> Self { Default::default() }

    /// Check if the button is in the tuple.
    pub fn contains(&self, button: Button) -> bool {
        let sbtn = Some(button);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    /// Insert a button into the tuple if there is room, searching from left to right.
    /// If the button is inserted, returns true. Otherwise, if the button is not inserted,
    /// this function returns false.
    pub fn insert_inplace(&mut self, button: Button) -> bool {
        let sbtn = Some(button);
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(sbtn, b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, sbtn, c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, sbtn); true}
            _ => false
        }
    }

    /// Returns an iterator over this tuple.
    pub fn iter(&self) -> ButtonTupleIter { (*self).into_iter() }
}

impl Default for ButtonTuple {
    /// Creates a new tuple with no buttons in it.
    fn default() -> Self { ButtonTuple(None, None, None) }
}

impl IntoIterator for ButtonTuple {
    type Item = Option<Button>;
    type IntoIter = ButtonTupleIter;

    fn into_iter(self) -> ButtonTupleIter {
        ButtonTupleIter {
            button_tuple: self,
            i: 0
        }
    }
}

/// An iterator over a ButtonTuple.
pub struct ButtonTupleIter {
    button_tuple: ButtonTuple,
    i: usize
}

impl Iterator for ButtonTupleIter {
    type Item = Option<Button>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        self.i += 1;
        match i {
            0 => Some(self.button_tuple.0),
            1 => Some(self.button_tuple.1),
            2 => Some(self.button_tuple.2),
            _ => None
        }
    }
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone, Debug, PartialEq)]
pub struct InputTranslator<A: Action> {
    keymap: HashMap<Button, A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {
    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: HashMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event. Returns `None` if there is no
    /// action associated with the `Input` variant.
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.get(&$but_var).cloned() {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    _sensitivity: f64,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            _sensitivity: 0.0,
            viewport_size: size
        }
    }
}

impl Debug for MouseTranslationData {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}, {}, {}, {}, {}, ({}, {})",
               self.x_axis_motion_inverted,
               self.y_axis_motion_inverted,
               self.x_axis_scroll_inverted,
               self.y_axis_scroll_inverted,
               self._sensitivity,
               self.viewport_size.width,
               self.viewport_size.height)
    }
}

impl PartialEq for MouseTranslationData {
    fn eq(&self, other: &Self) -> bool {
        self.x_axis_motion_inverted == other.x_axis_motion_inverted &&
        self.y_axis_motion_inverted == other.y_axis_motion_inverted &&
        self.x_axis_scroll_inverted == other.x_axis_scroll_inverted &&
        self.y_axis_scroll_inverted == other.y_axis_scroll_inverted &&
        self._sensitivity == other._sensitivity &&
        self.viewport_size.width    == other.viewport_size.width &&
        self.viewport_size.height   == other.viewport_size.height
    }
}

#[derive(Clone, Debug, PartialEq)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

/// An interface for rebinding keys to actions. This is freely convertable to and
/// from an InputTranslator.
#[derive(Clone, Debug, PartialEq)]
pub struct InputRebind<A: Action> {
    keymap: HashMap<A, ButtonTuple>,
    mouse_data: MouseTranslationData
}

impl<A: Action> InputRebind<A> {
    /// Creates a new InputRebind with no stored Action/ButtonTuple pairs.
    pub fn new(size: Size) -> Self {
        InputRebind {
            keymap: HashMap::new(),
            mouse_data: MouseTranslationData::new(size)
        }
    }

    /// Insert an Action into this InputRebind. If the Action is already in the
    /// InputRebind, then its ButtonTuple will be reset to (None, None, None), and
    /// the old ButtonTuple will be returned.
    pub fn insert_action(&mut self, action: A) -> Option<ButtonTuple> {
        self.keymap.insert(action, ButtonTuple::new())
    }

    /// Insert an Action into this InputRebind, and assign it to the ButtonTuple.
    /// If the Action is already in the InputRebind, the old ButtonTuple will be
    /// returned.
    pub fn insert_action_with_buttons(&mut self, action: A, buttons: ButtonTuple) -> Option<ButtonTuple> {
        self.keymap.insert(action, buttons)
    }

    /// Return a reference to the current ButtonTuple stored for an action. If the action
    /// is not stored in this InputRebind, then `None` will be returned.
    pub fn get_bindings(&self, action: &A) -> Option<&ButtonTuple> {
        self.keymap.get(action)
    }

    /// Returns a mutable reference to the current ButtonTuple stored for an action. If the
    /// action is not stored in this InputRebind, then `None` will be returned.
    pub fn get_bindings_mut(&mut self, action: &mut A) -> Option<&mut ButtonTuple> {
        self.keymap.get_mut(action)
    }

    /// Returns a reference to the boolean which represents whether x axis scrolling is inverted.
    pub fn get_x_scroll_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_scroll_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether x axis scrolling is inverted.
    pub fn get_x_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_scroll_inverted
    }

    /// Returns a reference to the boolean which represents whether y axis scrolling is inverted.
    pub fn get_y_scroll_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_scroll_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether y axis scrolling is inverted.
    pub fn get_y_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_scroll_inverted
    }

    /// Returns a reference to the boolean which represents whether mouse movement along the x axis is
    /// inverted.
    pub fn get_x_motion_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_motion_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether mouse movement along the
    /// x axis is inverted.
    pub fn get_x_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_motion_inverted
    }

    /// Returns a reference to the boolean which represents whether mouse movement along the y axis is
    /// inverted.
    pub fn get_y_motion_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_motion_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether mouse movement along the
    /// y axis is inverted.
    pub fn get_y_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_motion_inverted
    }

    /// Returns a reference to the currently stored viewport size used for calculating the imaginary mouse
    /// position.
    pub fn get_viewport_size(&self) -> &Size {
        &self.mouse_data.viewport_size
    }

    /// Returns a mutable reference to the currently stored viewport size used for calculating the imaginary
    /// mouse position.
    pub fn get_viewport_size_mut(&mut self) -> &mut Size {
        &mut self.mouse_data.viewport_size
    }
}

impl<A: Action> Default for InputRebind<A> {
    /// Creates an `InputRebind` with no pairs. In addition, the viewport size is set to [800, 600].
    fn default() -> Self {
        InputRebind::new((800, 600).into())
    }
}

impl<A: Action> Into<InputTranslator<A>> for InputRebind<A> {
    fn into(self) -> InputTranslator<A> {
        let mut input_translator = InputTranslator::new(self.mouse_data.viewport_size);
        input_translator.mouse_translator.data = self.mouse_data;
        input_translator.keymap = self.keymap.values()
                                             .flat_map(|&bt| bt.into_iter())
                                             .filter_map(|x| x)
                                             .zip(self.keymap.keys().cloned())
                                             .collect();

        input_translator
    }
}

impl<A: Action> Into<InputRebind<A>> for InputTranslator<A> {
    fn into(self) -> InputRebind<A> {
        use itertools::Itertools;

        let mut input_rebind = InputRebind::new(self.mouse_translator.data.viewport_size);
        input_rebind.mouse_data = self.mouse_translator.data;
        input_rebind.keymap = self.keymap.iter()
                                         .map(|(k, v)| (*v, vec![Some(*k)]))
                                         .sorted_by(|&(v0, _), &(v1, _)| Ord::cmp(&v0, &v1))
                                         .into_iter()
                                         .coalesce(|(k0, v0), (k1, v1)| if k0 == k1 {
                                                 Ok((k0, v0.into_iter().chain(v1).collect()))
                                             } else {
                                                 Err(((k0, v0), (k1, v1)))
                                             })
                                         .map(|(k, v)| if let [b0, b1, b2] = &v.iter()
                                                                               .cloned()
                                                                               .pad_using(3, |_| None)
                                                                               .take(3)
                                                                               .collect::<Vec<_>>()[..] {
                                                  (k, ButtonTuple(b0, b1, b2))
                                             } else {
                                                 unreachable!();
                                             })
                                         .collect();

        input_rebind
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, PartialEq, Eq)]
pub struct GitStatus {
    oid: String,
    branch: String,
    upstream: Option<String>,
    ahead: bool,
    behind: bool,
    staged: bool,
    unstaged: bool,
    untracked: bool,
    ignored: bool,
}

impl GitStatus {
    pub fn new(status_txt: &str) -> Result<GitStatus, &'static str> {
        let mut s = GitStatus {
            oid: String::new(),
            branch: String::new(),
            upstream: None,
            ahead: false,
            behind: false,
            staged: false,
            unstaged: false,
            untracked: false,
            ignored: false,
        };
        let err = "Bad input";
        for line in status_txt.lines() {
            let mut words = line.split(' ');
            match words.next() {
                Some("#") => {
                    match words.next() {
                        Some("branch.oid") => {
                            s.oid = String::from(words.next().ok_or(err)?);
                        },
                        Some("branch.head") => {
                            s.branch = String::from(words.next().ok_or(err)?);
                        }
                        Some("branch.upstream") => {
                            s.upstream = Some(String::from(words.next().ok_or(err)?));
                        },
                        Some("branch.ab") => {
                            if words.next().ok_or(err)? != "+0" {
                                s.ahead = true;
                            }
                            if words.next().ok_or(err)? != "-0" {
                                s.behind = true;
                            }
                        },
                        _ => return Err(err),
                    }
                },
                Some("1") | Some("2") => {
                    let changes = words.next().ok_or(err)?;
                    let mut changes = changes.chars();
                    if changes.next().ok_or(err)? != '.' {
                        s.staged = true;
                    }
                    if changes.next().ok_or(err)? != '.' {
                        s.unstaged = true;
                    }
                },
                Some("?") => s.untracked = true,
                Some("!") => s.ignored = true,
                Some("") | None => {},
                _ => return Err(err),
            }
        }
        Ok(s)
    }

    pub fn to_line(&self) -> String {
        let mut symbols = String::new();
        if self.ahead {
            symbols.push('A');
        }
        if self.behind {
            symbols.push('B');
        }
        if self.staged {
            symbols.push('+');
        }
        if self.unstaged {
            symbols.push('*');
        }
        if self.untracked {
            symbols.push('?');
        }
        if self.ignored {
            symbols.push('!');
        }
        let short_oid = if self.oid == "(initial)" {
            &self.oid
        } else {
            &self.oid[..7]
        };
        if symbols.is_empty() {
            format!("[{} {}]", self.branch, short_oid)
        } else {
            format!("[{} {} {}]", self.branch, short_oid, symbols)
        }
    }
}

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

    #[test]
    fn parse_clean() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: None,
                ahead: false,
                behind: false,
                staged: false,
                unstaged: false,
                untracked: false,
                ignored: false,
            }
        );
    }

    #[test]
    fn parse_clean_upstream() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
# branch.upstream origin/master
# branch.ab +1 -1
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: Some(String::from("origin/master")),
                ahead: true,
                behind: true,
                staged: false,
                unstaged: false,
                untracked: false,
                ignored: false,
            }
        );
    }

    #[test]
    fn parse_staged_only() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 M. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_unstaged_only() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 .M N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(!s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_both_staged_and_unstaged() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 MM N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_deleted() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 D. N... 100644 000000 000000 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 0000000000000000000000000000000000000000 README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_renamed() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
2 R. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 R100 README	README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_untracked() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
? foo.txt
";
        assert!(GitStatus::new(test_status).unwrap().untracked);
    }

    #[test]
    fn parse_ignored() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
! node_modules/
";
        assert!(GitStatus::new(test_status).unwrap().ignored);
    }

    #[test]
    fn parse_very_dirty() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
# branch.upstream origin/master
# branch.ab +1 -1
1 D. N... 100644 000000 000000 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 0000000000000000000000000000000000000000 README.md
1 .M N... 100644 100644 100644 5e8a8090976077ddf16252a560460a20dbbdd6a5 5e8a8090976077ddf16252a560460a20dbbdd6a5 gh-pages.sh
? foo.txt
! ignored.txt
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: Some(String::from("origin/master")),
                ahead: true,
                behind: true,
                staged: true,
                unstaged: true,
                untracked: true,
                ignored: true,
            }
        );
    }

    #[test]
    fn parse_bad_input() {
        assert_eq!(GitStatus::new("foo"), Err("Bad input"));
    }

    #[test]
    fn test_to_line_clean() {
        let s = GitStatus {
            oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
            branch: String::from("master"),
            upstream: None,
            ahead: false,
            behind: false,
            staged: false,
            unstaged: false,
            untracked: false,
            ignored: false,
        };
        assert_eq!(s.to_line(), String::from("[master 3845e7a]"));
    }

    #[test]
    fn test_to_line_dirty() {
        let s = GitStatus {
            oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
            branch: String::from("master"),
            upstream: Some(String::from("origin/master")),
            ahead: true,
            behind: true,
            staged: true,
            unstaged: true,
            untracked: true,
            ignored: true,
        };
        assert_eq!(s.to_line(), String::from("[master 3845e7a AB+*?!]"));
    }

    #[test]
    fn test_to_line_initial_commit() {
        let s = GitStatus {
            oid: String::from("(initial)"),
            branch: String::from("master"),
            upstream: None,
            ahead: false,
            behind: false,
            staged: false,
            unstaged: false,
            untracked: false,
            ignored: false,
        };
        assert_eq!(s.to_line(), String::from("[master (initial)]"));
    }
}
<commit_msg>Refactor branch info parsing<commit_after>#[derive(Debug, PartialEq, Eq)]
pub struct GitStatus {
    oid: String,
    branch: String,
    upstream: Option<String>,
    ahead: bool,
    behind: bool,
    staged: bool,
    unstaged: bool,
    untracked: bool,
    ignored: bool,
}

impl GitStatus {
    pub fn new(status_txt: &str) -> Result<GitStatus, &'static str> {
        let mut s = GitStatus {
            oid: String::new(),
            branch: String::new(),
            upstream: None,
            ahead: false,
            behind: false,
            staged: false,
            unstaged: false,
            untracked: false,
            ignored: false,
        };
        let err = "Bad input";
        for line in status_txt.lines() {
            let mut words = line.split(' ');
            match words.next() {
                Some("#") => {
                    let key = words.next().ok_or(err)?;
                    let value = words.next().ok_or(err)?;
                    match key {
                        "branch.oid" => s.oid = String::from(value),
                        "branch.head" => s.branch = String::from(value),
                        "branch.upstream" => s.upstream = Some(String::from(value)),
                        "branch.ab" => {
                            if value != "+0" {
                                s.ahead = true;
                            }
                            if words.next().ok_or(err)? != "-0" {
                                s.behind = true;
                            }
                        },
                        _ => return Err(err),
                    }
                },
                Some("1") | Some("2") => {
                    let changes = words.next().ok_or(err)?;
                    let mut changes = changes.chars();
                    if changes.next().ok_or(err)? != '.' {
                        s.staged = true;
                    }
                    if changes.next().ok_or(err)? != '.' {
                        s.unstaged = true;
                    }
                },
                Some("?") => s.untracked = true,
                Some("!") => s.ignored = true,
                Some("") | None => {},
                _ => return Err(err),
            }
        }
        Ok(s)
    }

    pub fn to_line(&self) -> String {
        let mut symbols = String::new();
        if self.ahead {
            symbols.push('A');
        }
        if self.behind {
            symbols.push('B');
        }
        if self.staged {
            symbols.push('+');
        }
        if self.unstaged {
            symbols.push('*');
        }
        if self.untracked {
            symbols.push('?');
        }
        if self.ignored {
            symbols.push('!');
        }
        let short_oid = if self.oid == "(initial)" {
            &self.oid
        } else {
            &self.oid[..7]
        };
        if symbols.is_empty() {
            format!("[{} {}]", self.branch, short_oid)
        } else {
            format!("[{} {} {}]", self.branch, short_oid, symbols)
        }
    }
}

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

    #[test]
    fn parse_clean() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: None,
                ahead: false,
                behind: false,
                staged: false,
                unstaged: false,
                untracked: false,
                ignored: false,
            }
        );
    }

    #[test]
    fn parse_clean_upstream() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
# branch.upstream origin/master
# branch.ab +1 -1
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: Some(String::from("origin/master")),
                ahead: true,
                behind: true,
                staged: false,
                unstaged: false,
                untracked: false,
                ignored: false,
            }
        );
    }

    #[test]
    fn parse_staged_only() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 M. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_unstaged_only() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 .M N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(!s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_both_staged_and_unstaged() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 MM N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_deleted() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 D. N... 100644 000000 000000 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 0000000000000000000000000000000000000000 README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_renamed() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
2 R. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 R100 README	README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_untracked() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
? foo.txt
";
        assert!(GitStatus::new(test_status).unwrap().untracked);
    }

    #[test]
    fn parse_ignored() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
! node_modules/
";
        assert!(GitStatus::new(test_status).unwrap().ignored);
    }

    #[test]
    fn parse_very_dirty() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
# branch.upstream origin/master
# branch.ab +1 -1
1 D. N... 100644 000000 000000 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 0000000000000000000000000000000000000000 README.md
1 .M N... 100644 100644 100644 5e8a8090976077ddf16252a560460a20dbbdd6a5 5e8a8090976077ddf16252a560460a20dbbdd6a5 gh-pages.sh
? foo.txt
! ignored.txt
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: Some(String::from("origin/master")),
                ahead: true,
                behind: true,
                staged: true,
                unstaged: true,
                untracked: true,
                ignored: true,
            }
        );
    }

    #[test]
    fn parse_bad_input() {
        assert_eq!(GitStatus::new("foo"), Err("Bad input"));
    }

    #[test]
    fn test_to_line_clean() {
        let s = GitStatus {
            oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
            branch: String::from("master"),
            upstream: None,
            ahead: false,
            behind: false,
            staged: false,
            unstaged: false,
            untracked: false,
            ignored: false,
        };
        assert_eq!(s.to_line(), String::from("[master 3845e7a]"));
    }

    #[test]
    fn test_to_line_dirty() {
        let s = GitStatus {
            oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
            branch: String::from("master"),
            upstream: Some(String::from("origin/master")),
            ahead: true,
            behind: true,
            staged: true,
            unstaged: true,
            untracked: true,
            ignored: true,
        };
        assert_eq!(s.to_line(), String::from("[master 3845e7a AB+*?!]"));
    }

    #[test]
    fn test_to_line_initial_commit() {
        let s = GitStatus {
            oid: String::from("(initial)"),
            branch: String::from("master"),
            upstream: None,
            ahead: false,
            behind: false,
            staged: false,
            unstaged: false,
            untracked: false,
            ignored: false,
        };
        assert_eq!(s.to_line(), String::from("[master (initial)]"));
    }
}
<|endoftext|>


<commit_before>#![feature(io, core)]

use std::io;
use std::io::prelude::*;

pub enum LittleEndian {}
pub enum BigEndian {}

pub trait Endianness : std::marker::MarkerTrait {
    fn int_to_target<T: std::num::Int>(val: T) -> T;
    fn int_from_target<T: std::num::Int>(val: T) -> T;
}

impl Endianness for LittleEndian {
    fn int_to_target<T: std::num::Int>(val: T) -> T {
        val.to_le()
    }
    fn int_from_target<T: std::num::Int>(val: T) -> T {
        <T as std::num::Int>::from_le(val)
    }
}

impl Endianness for BigEndian {
    fn int_to_target<T: std::num::Int>(val: T) -> T {
        val.to_be()
    }
    fn int_from_target<T: std::num::Int>(val: T) -> T {
        <T as std::num::Int>::from_be(val)
    }
}

/// Additional integer write methods for a io::Read
pub trait WritePodExt {
    /// Write a usize
    fn write_usize<T: Endianness>(&mut self, usize) -> io::Result<()>;
    /// Write a u64
    fn write_u64<T: Endianness>(&mut self, u64) -> io::Result<()>;
    /// Write a u32
    fn write_u32<T: Endianness>(&mut self, u32) -> io::Result<()>;
    /// Write a u16
    fn write_u16<T: Endianness>(&mut self, u16) -> io::Result<()>;
    /// Write a u8
    fn write_u8<T: Endianness>(&mut self, u8) -> io::Result<()>;
}

macro_rules! val_to_buf {
    ($val:ident, $buf:ident) => {
        {
            for i in 0..$buf.len() {
                $buf[i] = ($val >> (i * 8)) as u8;
            }
        }
    };
}

impl<W: Write> WritePodExt for W {
    fn write_usize<T: Endianness>(&mut self, val: usize) -> io::Result<()> {
        let mut buf = [0u8; ::std::usize::BYTES as usize];
        let tval = <T as Endianness>::int_to_target(val);
        val_to_buf!(tval, buf);
        self.write_all(&buf)
    }

    fn write_u64<T: Endianness>(&mut self, val: u64) -> io::Result<()> {
        let mut buf = [0u8; 8];
        let tval = <T as Endianness>::int_to_target(val);
        val_to_buf!(tval, buf);
        self.write_all(&buf)
    }

    fn write_u32<T: Endianness>(&mut self, val: u32) -> io::Result<()> {
        let mut buf = [0u8; 4];
        let tval = <T as Endianness>::int_to_target(val);
        val_to_buf!(tval, buf);
        self.write_all(&buf)
    }

    fn write_u16<T: Endianness>(&mut self, val: u16) -> io::Result<()> {
        let mut buf = [0u8; 2];
        let tval = <T as Endianness>::int_to_target(val);
        val_to_buf!(tval, buf);
        self.write_all(&buf)
    }

    fn write_u8<T: Endianness>(&mut self, val: u8) -> io::Result<()> {
        self.write_all(&[val])
    }
}

#[cfg(test)]
mod test {
    use std::io;
    use super::{LittleEndian, BigEndian};
    use super::WritePodExt;

    #[test]
    fn write_be() {
        let buf: &mut [u8] = &mut [0u8; 8];
        let mut writer = io::Cursor::new(buf);

        writer.set_position(0);
        writer.write_usize::<BigEndian>(0x01_23_45_67_89_ab_cd_ef_u64 as usize).unwrap();
        assert_eq!(&writer.get_ref()[0..::std::usize::BYTES as usize], &[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef][..::std::usize::BYTES as usize]);

        writer.set_position(0);
        writer.write_u64::<BigEndian>(0x01_23_45_67_89_ab_cd_ef).unwrap();
        assert_eq!(&writer.get_ref()[0..8], &[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);

        writer.set_position(0);
        writer.write_u32::<BigEndian>(0x01_23_45_67).unwrap();
        assert_eq!(&writer.get_ref()[0..4], &[0x01, 0x23, 0x45, 0x67]);

        writer.set_position(0);
        writer.write_u16::<BigEndian>(0x01_23).unwrap();
        assert_eq!(&writer.get_ref()[0..2], &[0x01, 0x23]);

        writer.set_position(0);
        writer.write_u8::<BigEndian>(0x01).unwrap();
        assert_eq!(&writer.get_ref()[0..1], &[0x01]);
    }

    #[test]
    fn write_le() {
        let buf: &mut [u8] = &mut [0u8; 8];
        let mut writer = io::Cursor::new(buf);

        writer.set_position(0);
        writer.write_usize::<LittleEndian>(0x01_23_45_67_89_ab_cd_ef_u64 as usize).unwrap();
        assert_eq!(&writer.get_ref()[0..::std::usize::BYTES as usize], &[0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01][8-::std::usize::BYTES as usize..]);

        writer.set_position(0);
        writer.write_u64::<LittleEndian>(0x01_23_45_67_89_ab_cd_ef).unwrap();
        assert_eq!(&writer.get_ref()[0..8], &[0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01]);

        writer.set_position(0);
        writer.write_u32::<LittleEndian>(0x01_23_45_67).unwrap();
        assert_eq!(&writer.get_ref()[0..4], &[0x67, 0x45, 0x23, 0x01]);

        writer.set_position(0);
        writer.write_u16::<LittleEndian>(0x01_23).unwrap();
        assert_eq!(&writer.get_ref()[0..2], &[0x23, 0x01]);

        writer.set_position(0);
        writer.write_u8::<LittleEndian>(0x01).unwrap();
        assert_eq!(&writer.get_ref()[0..1], &[0x01]);
    }
}
<commit_msg>Actually fix tests on 32 bit<commit_after>#![feature(io, core)]

use std::io;
use std::io::prelude::*;

pub enum LittleEndian {}
pub enum BigEndian {}

pub trait Endianness : std::marker::MarkerTrait {
    fn int_to_target<T: std::num::Int>(val: T) -> T;
    fn int_from_target<T: std::num::Int>(val: T) -> T;
}

impl Endianness for LittleEndian {
    fn int_to_target<T: std::num::Int>(val: T) -> T {
        val.to_le()
    }
    fn int_from_target<T: std::num::Int>(val: T) -> T {
        <T as std::num::Int>::from_le(val)
    }
}

impl Endianness for BigEndian {
    fn int_to_target<T: std::num::Int>(val: T) -> T {
        val.to_be()
    }
    fn int_from_target<T: std::num::Int>(val: T) -> T {
        <T as std::num::Int>::from_be(val)
    }
}

/// Additional integer write methods for a io::Read
pub trait WritePodExt {
    /// Write a usize
    fn write_usize<T: Endianness>(&mut self, usize) -> io::Result<()>;
    /// Write a u64
    fn write_u64<T: Endianness>(&mut self, u64) -> io::Result<()>;
    /// Write a u32
    fn write_u32<T: Endianness>(&mut self, u32) -> io::Result<()>;
    /// Write a u16
    fn write_u16<T: Endianness>(&mut self, u16) -> io::Result<()>;
    /// Write a u8
    fn write_u8<T: Endianness>(&mut self, u8) -> io::Result<()>;
}

macro_rules! val_to_buf {
    ($val:ident, $buf:ident) => {
        {
            for i in 0..$buf.len() {
                $buf[i] = ($val >> (i * 8)) as u8;
            }
        }
    };
}

impl<W: Write> WritePodExt for W {
    fn write_usize<T: Endianness>(&mut self, val: usize) -> io::Result<()> {
        let mut buf = [0u8; ::std::usize::BYTES as usize];
        let tval = <T as Endianness>::int_to_target(val);
        val_to_buf!(tval, buf);
        self.write_all(&buf)
    }

    fn write_u64<T: Endianness>(&mut self, val: u64) -> io::Result<()> {
        let mut buf = [0u8; 8];
        let tval = <T as Endianness>::int_to_target(val);
        val_to_buf!(tval, buf);
        self.write_all(&buf)
    }

    fn write_u32<T: Endianness>(&mut self, val: u32) -> io::Result<()> {
        let mut buf = [0u8; 4];
        let tval = <T as Endianness>::int_to_target(val);
        val_to_buf!(tval, buf);
        self.write_all(&buf)
    }

    fn write_u16<T: Endianness>(&mut self, val: u16) -> io::Result<()> {
        let mut buf = [0u8; 2];
        let tval = <T as Endianness>::int_to_target(val);
        val_to_buf!(tval, buf);
        self.write_all(&buf)
    }

    fn write_u8<T: Endianness>(&mut self, val: u8) -> io::Result<()> {
        self.write_all(&[val])
    }
}

#[cfg(test)]
mod test {
    use std::io;
    use super::{LittleEndian, BigEndian};
    use super::WritePodExt;

    #[test]
    fn write_be() {
        let buf: &mut [u8] = &mut [0u8; 8];
        let mut writer = io::Cursor::new(buf);

        writer.set_position(0);
        writer.write_usize::<BigEndian>(0x01_23_45_67_89_ab_cd_ef_u64 as usize).unwrap();
        assert_eq!(&writer.get_ref()[0..::std::usize::BYTES as usize], &[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef][8-::std::usize::BYTES as usize..]);

        writer.set_position(0);
        writer.write_u64::<BigEndian>(0x01_23_45_67_89_ab_cd_ef).unwrap();
        assert_eq!(&writer.get_ref()[0..8], &[0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);

        writer.set_position(0);
        writer.write_u32::<BigEndian>(0x01_23_45_67).unwrap();
        assert_eq!(&writer.get_ref()[0..4], &[0x01, 0x23, 0x45, 0x67]);

        writer.set_position(0);
        writer.write_u16::<BigEndian>(0x01_23).unwrap();
        assert_eq!(&writer.get_ref()[0..2], &[0x01, 0x23]);

        writer.set_position(0);
        writer.write_u8::<BigEndian>(0x01).unwrap();
        assert_eq!(&writer.get_ref()[0..1], &[0x01]);
    }

    #[test]
    fn write_le() {
        let buf: &mut [u8] = &mut [0u8; 8];
        let mut writer = io::Cursor::new(buf);

        writer.set_position(0);
        writer.write_usize::<LittleEndian>(0x01_23_45_67_89_ab_cd_ef_u64 as usize).unwrap();
        assert_eq!(&writer.get_ref()[0..::std::usize::BYTES as usize], &[0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01][..::std::usize::BYTES as usize]);

        writer.set_position(0);
        writer.write_u64::<LittleEndian>(0x01_23_45_67_89_ab_cd_ef).unwrap();
        assert_eq!(&writer.get_ref()[0..8], &[0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01]);

        writer.set_position(0);
        writer.write_u32::<LittleEndian>(0x01_23_45_67).unwrap();
        assert_eq!(&writer.get_ref()[0..4], &[0x67, 0x45, 0x23, 0x01]);

        writer.set_position(0);
        writer.write_u16::<LittleEndian>(0x01_23).unwrap();
        assert_eq!(&writer.get_ref()[0..2], &[0x23, 0x01]);

        writer.set_position(0);
        writer.write_u8::<LittleEndian>(0x01).unwrap();
        assert_eq!(&writer.get_ref()[0..1], &[0x01]);
    }
}
<|endoftext|>


<commit_before>//! Virtual machine for the CHIP-8 programming language
//!
//! This crate implements a virtual machine for the CHIP-8
//! programming language.
//! It can be used as a backend for CHIP-8 emulators, debuggers
//! and so on.
//!
//!
//! The code is split into the `instructions` module, which provides
//! the translation from raw bits (`RawInstruction`) into valid
//! instructions (`Instruction`).
//!
//! The `vm` module contains the actual virtual machine implementation
//! (`Vm`).
//!
//! The `error` module contains the `Chip8Error` implementation of
//! `std:error::Error` for any kinds of errors that might occur using
//! the `chip8_vm` crate.

// Silence 'core' feature warnings
// for `error:Error` and such
#![feature(core)]
// Silence 'io' feature warnings
// for `BufWriter` and such
#![feature(io)]

extern crate rand;

#[macro_use]
extern crate log;

pub mod error;
pub mod instructions;
pub mod vm;

pub use instructions::*;

/// Returns the version of this crate in the format `MAJOR.MINOR.PATCH`.
pub fn version() -> &'static str {
    // TODO: There's also an optional _PRE part
    concat!(
        env!("CARGO_PKG_VERSION_MAJOR"), ".",
        env!("CARGO_PKG_VERSION_MINOR"), ".",
        env!("CARGO_PKG_VERSION_PATCH"),
    )
}
<commit_msg>Update feature gates<commit_after>//! Virtual machine for the CHIP-8 programming language
//!
//! This crate implements a virtual machine for the CHIP-8
//! programming language.
//! It can be used as a backend for CHIP-8 emulators, debuggers
//! and so on.
//!
//!
//! The code is split into the `instructions` module, which provides
//! the translation from raw bits (`RawInstruction`) into valid
//! instructions (`Instruction`).
//!
//! The `vm` module contains the actual virtual machine implementation
//! (`Vm`).
//!
//! The `error` module contains the `Chip8Error` implementation of
//! `std:error::Error` for any kinds of errors that might occur using
//! the `chip8_vm` crate.

// Silence 'core' feature warnings
// for `error:Error` and such
#![feature(core)]

extern crate rand;

#[macro_use]
extern crate log;

pub mod error;
pub mod instructions;
pub mod vm;

pub use instructions::*;

/// Returns the version of this crate in the format `MAJOR.MINOR.PATCH`.
pub fn version() -> &'static str {
    // TODO: There's also an optional _PRE part
    concat!(
        env!("CARGO_PKG_VERSION_MAJOR"), ".",
        env!("CARGO_PKG_VERSION_MINOR"), ".",
        env!("CARGO_PKG_VERSION_PATCH"),
    )
}
<|endoftext|>


<commit_before>#![warn(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;
mod rebind;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use rebind::InputRebind;
pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    /// Creates a new tuple with no buttons in it (equivalent to
    /// ```Default::default()```)
    pub fn new() -> Self { Default::default() }

    /// Check if the button is in the tuple.
    pub fn contains(&self, button: Button) -> bool {
        let sbtn = Some(button);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    #[allow(missing_docs)]
    pub fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    #[allow(missing_docs)]
    pub fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    #[allow(missing_docs)]
    pub fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    /// Creates a new tuple with no buttons in it
    fn default() -> Self { ButtonTuple(None, None, None) }
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: HashMap<Button, A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: HashMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.get(&$but_var).map(|x| *x) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

#[derive(Clone)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}
<commit_msg>Format doc comment<commit_after>#![warn(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;
mod rebind;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use rebind::InputRebind;
pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    /// Creates a new tuple with no buttons in it (equivalent to `Default::default()`)
    pub fn new() -> Self { Default::default() }

    /// Check if the button is in the tuple.
    pub fn contains(&self, button: Button) -> bool {
        let sbtn = Some(button);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    #[allow(missing_docs)]
    pub fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    #[allow(missing_docs)]
    pub fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    #[allow(missing_docs)]
    pub fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    /// Creates a new tuple with no buttons in it
    fn default() -> Self { ButtonTuple(None, None, None) }
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: HashMap<Button, A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: HashMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.get(&$but_var).map(|x| *x) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

#[derive(Clone)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}
<|endoftext|>