<commit_before>extern crate conduit;
extern crate libc;
extern crate semver;
extern crate civet_sys as ffi;

use std::collections::HashMap;
use std::io::prelude::*;
use std::io::{self, BufWriter};
use std::net::{SocketAddr, Ipv4Addr, SocketAddrV4};

use conduit::{Handler, Extensions, TypeMap, Method, Scheme, Host};

use raw::{RequestInfo,Header};
use raw::{get_header,get_headers,get_request_info};
use status::{ToStatusCode};

pub use config::Config;

mod raw;
mod config;
pub mod status;

pub struct Connection<'a> {
    request: CivetRequest<'a>,
    written: bool,
}

pub struct CivetRequest<'a> {
    conn: &'a raw::Connection,
    request_info: RequestInfo<'a>,
    headers: Headers<'a>,
    extensions: Extensions
}

fn ver(major: u64, minor: u64) -> semver::Version {
    semver::Version {
        major: major,
        minor: minor,
        patch: 0,
        pre: vec!(),
        build: vec!()
    }
}

impl<'a> conduit::Request for CivetRequest<'a> {
    fn http_version(&self) -> semver::Version {
        let version = self.request_info.http_version().unwrap();
        match version {
            "1.0" => ver(1, 0),
            "1.1" => ver(1, 1),
            _ => ver(1, 1)
        }
    }

    fn conduit_version(&self) -> semver::Version {
        ver(0, 1)
    }

    fn method(&self) -> Method {
        match self.request_info.method().unwrap() {
            "HEAD" => Method::Head,
            "GET" => Method::Get,
            "POST" => Method::Post,
            "PUT" => Method::Put,
            "DELETE" => Method::Delete,
            "PATCH" => Method::Patch,
            "PURGE" => Method::Purge,
            "CONNECT" => Method::Connect,
            "OPTIONS" => Method::Options,
            "TRACE" => Method::Trace,
            other @ _ => panic!("Civet does not support {} requests", other)
        }
    }

    fn scheme(&self) -> Scheme {
        if self.request_info.is_ssl() {
            Scheme::Https
        } else {
            Scheme::Http
        }
    }

    fn host(&self) -> Host {
        Host::Name(get_header(self.conn, "Host").unwrap())
    }

    fn virtual_root(&self) -> Option<&str> {
        None
    }

    fn path(&self) -> &str {
        self.request_info.url().unwrap()
    }

    fn query_string(&self) -> Option<&str> {
        self.request_info.query_string()
    }

    fn remote_addr(&self) -> SocketAddr {
        let ip = self.request_info.remote_ip();
        let ip = Ipv4Addr::new((ip >> 24) as u8,
                               (ip >> 16) as u8,
                               (ip >>  8) as u8,
                               (ip >>  0) as u8);
        SocketAddr::V4(SocketAddrV4::new(ip, self.request_info.remote_port()))
    }

    fn content_length(&self) -> Option<u64> {
        get_header(self.conn, "Content-Length").and_then(|s| s.parse().ok())
    }

    fn headers(&self) -> &conduit::Headers { &self.headers }

    fn body(&mut self) -> &mut Read { self }

    fn extensions(&self) -> &Extensions { &self.extensions }

    fn mut_extensions(&mut self) -> &mut Extensions {
        &mut self.extensions
    }
}

pub fn response<S: ToStatusCode, R: Read + Send + 'static>(status: S,
    headers: HashMap<String, Vec<String>>, body: R) -> conduit::Response
{
    conduit::Response {
        status: status.to_status().ok().unwrap().to_code(),
        headers: headers,
        body: Box::new(body),
    }
}

impl<'a> Connection<'a> {
    fn new(conn: &raw::Connection) -> Result<Connection, String> {
        match request_info(conn) {
            Ok(info) => {
                let request = CivetRequest {
                    conn: conn,
                    request_info: info,
                    headers: Headers { conn: conn },
                    extensions: TypeMap::new()
                };

                Ok(Connection {
                    request: request,
                    written: false,
                })
            },
            Err(err) => Err(err)
        }
    }

}

impl<'a> Write for Connection<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.written = true;
        match raw::write(self.request.conn, buf) {
            n if n < 0 => Err(io::Error::new(io::ErrorKind::Other,
                                             &format!("write error ({})", n)[..])),
            n => Ok(n as usize)
        }
    }
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

impl<'a> Read for CivetRequest<'a> {
    fn read(&mut self, buf: &mut[u8]) -> io::Result<usize> {
        match raw::read(self.conn, buf) {
            n if n < 0 => Err(io::Error::new(io::ErrorKind::Other,
                                             &format!("read error ({})", n)[..])),
            n => Ok(n as usize)
        }
    }
}

impl<'a> Drop for Connection<'a> {
    fn drop(&mut self) {
        if !self.written {
            let _ = writeln!(self, "HTTP/1.1 500 Internal Server Error");
        }
    }
}

pub struct Headers<'a> {
    conn: &'a raw::Connection
}

impl<'a> conduit::Headers for Headers<'a> {
    fn find(&self, string: &str) -> Option<Vec<&str>> {
        get_header(self.conn, string).map(|s| vec!(s))
    }

    fn has(&self, string: &str) -> bool {
        get_header(self.conn, string).is_some()
    }

    fn all(&self) -> Vec<(&str, Vec<&str>)> {
        HeaderIterator::new(self.conn).collect()
    }
}

pub struct HeaderIterator<'a> {
    headers: Vec<Header<'a>>,
    position: usize
}

impl<'a> HeaderIterator<'a> {
    fn new<'b>(conn: &'b raw::Connection) -> HeaderIterator<'b> {
        HeaderIterator { headers: get_headers(conn), position: 0 }
    }
}

impl<'a> Iterator for HeaderIterator<'a> {
    type Item = (&'a str, Vec<&'a str>);
    fn next(&mut self) -> Option<(&'a str, Vec<&'a str>)> {
        let pos = self.position;
        let headers = &self.headers;

        if self.headers.len() <= pos {
            None
        } else {
            let header = &headers[pos];
            self.position += 1;
            header.name().map(|name| (name, vec!(header.value().unwrap())))
        }
    }
}

pub struct Server(raw::Server<Box<Handler + 'static + Sync>>);

impl Server {
    pub fn start<H: Handler + 'static + Sync>(options: Config, handler: H)
        -> io::Result<Server>
    {
        fn internal_handler(conn: &mut raw::Connection,
                            handler: &Box<Handler + 'static + Sync>)
                            -> Result<(), ()> {
            let mut connection = Connection::new(conn).unwrap();
            let response = handler.call(&mut connection.request);
            let mut writer = BufWriter::new(connection);

            fn err<W: Write>(writer: &mut W) {
                let _ = writeln!(writer, "HTTP/1.1 500 Internal Server Error");
            }

            let conduit::Response { status, headers, mut body } = match response {
                Ok(r) => r,
                Err(_) => return Err(err(&mut writer)),
            };
            let (code, string) = status;
            try!(write!(&mut writer, "HTTP/1.1 {} {}\r\n", code, string).map_err(|_| ()));

            for (key, value) in headers.iter() {
                for header in value.iter() {
                    try!(write!(&mut writer, "{}: {}\r\n", *key, *header).map_err(|_| ()));
                }
            }

            try!(write!(&mut writer, "\r\n").map_err(|_| ()));
            let mut body: &mut Read = &mut *body;
            try!(io::copy(&mut body, &mut writer).map_err(|_| ()));

            Ok(())
        }

        let handler = Box::new(handler);
        let raw_callback = raw::ServerCallback::new(internal_handler, handler);
        Ok(Server(try!(raw::Server::start(options, raw_callback))))
    }
}

fn request_info<'a>(connection: &'a raw::Connection)
    -> Result<RequestInfo<'a>, String>
{
    match get_request_info(connection) {
        Some(info) => Ok(info),
        None => Err("Couldn't get request info for connection".to_string())
    }
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use std::error::Error;
    use std::io::prelude::*;
    use std::io::{self, Cursor};
    use std::net::{SocketAddr, TcpStream, SocketAddrV4, Ipv4Addr};
    use std::sync::Mutex;
    use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
    use std::sync::mpsc::{channel, Sender};
    use super::{Server, Config, response};
    use conduit::{Request, Response, Handler};

    fn noop(_: &mut Request) -> Result<Response, io::Error> { unreachable!() }

    fn request(addr: SocketAddr, req: &str) -> String {
        let mut s = TcpStream::connect(&addr).unwrap();
        s.write_all(req.trim_left().as_bytes()).unwrap();
        let mut ret = String::new();
        s.read_to_string(&mut ret).unwrap();
        ret
    }

    fn port() -> u16 {
        static CNT: AtomicUsize = ATOMIC_USIZE_INIT;
        CNT.fetch_add(1, Ordering::SeqCst) as u16 + 13038
    }

    fn cfg(port: u16) -> Config {
        let mut cfg = Config::new();
        cfg.port(port).threads(1);
        return cfg
    }

    #[test]
    fn smoke() {
        Server::start(cfg(port()), noop).unwrap();
    }

    #[test]
    fn dupe_port() {
        let port = port();
        let s1 = Server::start(cfg(port), noop);
        assert!(s1.is_ok());
        let s2 = Server::start(cfg(port), noop);
        assert!(s2.is_err());
    }

    #[test]
    fn drops_handler() {
        static mut DROPPED: bool = false;
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Error+Send>> {
                panic!()
            }
        }
        impl Drop for Foo {
            fn drop(&mut self) { unsafe { DROPPED = true; } }
        }

        drop(Server::start(cfg(port()), Foo));
        unsafe { assert!(DROPPED); }
    }

    #[test]
    fn invokes() {
        struct Foo(Mutex<Sender<()>>);
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Error+Send>> {
                let Foo(ref tx) = *self;
                tx.lock().unwrap().send(()).unwrap();
                Ok(response(200, HashMap::new(), Cursor::new(vec![])))
            }
        }

        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let port = port();
        let ip = Ipv4Addr::new(127, 0, 0, 1);
        let addr = SocketAddr::V4(SocketAddrV4::new(ip, port));
        let _s = Server::start(cfg(port), handler);
        request(addr, r"
GET / HTTP/1.1

");
        rx.recv().unwrap();
    }

    #[test]
    fn header_sent() {
        struct Foo(Mutex<Sender<String>>);
        impl Handler for Foo {
            fn call(&self, req: &mut Request) -> Result<Response, Box<Error+Send>> {
                let Foo(ref tx) = *self;
                tx.lock().unwrap()
                  .send(req.headers().find("Foo").unwrap().join("")).unwrap();
                Ok(response(200, HashMap::new(), Cursor::new(vec![])))
            }
        }

        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let port = port();
        let ip = Ipv4Addr::new(127, 0, 0, 1);
        let addr = SocketAddr::V4(SocketAddrV4::new(ip, port));
        let _s = Server::start(cfg(port), handler);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert_eq!(rx.recv().unwrap(), "bar");
    }

    #[test]
    fn failing_handler() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Error+Send>> {
                panic!()
            }
        }

        let port = port();
        let ip = Ipv4Addr::new(127, 0, 0, 1);
        let addr = SocketAddr::V4(SocketAddrV4::new(ip, port));
        let _s = Server::start(cfg(port), Foo);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
    }

    #[test]
    fn failing_handler_is_500() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Error+Send>> {
                panic!()
            }
        }

        let port = port();
        let ip = Ipv4Addr::new(127, 0, 0, 1);
        let addr = SocketAddr::V4(SocketAddrV4::new(ip, port));
        let _s = Server::start(cfg(port), Foo);
        let response = request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert!(response.contains("500 Internal"),
                "not a failing response: {}", response);
    }
}
<commit_msg>Update with master<commit_after>extern crate conduit;
extern crate libc;
extern crate semver;
extern crate civet_sys as ffi;

use std::collections::HashMap;
use std::io::prelude::*;
use std::io::{self, BufWriter};
use std::net::{SocketAddr, Ipv4Addr, SocketAddrV4};

use conduit::{Handler, Extensions, TypeMap, Method, Scheme, Host};

use raw::{RequestInfo,Header};
use raw::{get_header,get_headers,get_request_info};
use status::{ToStatusCode};

pub use config::Config;

mod raw;
mod config;
pub mod status;

pub struct Connection<'a> {
    request: CivetRequest<'a>,
    written: bool,
}

pub struct CivetRequest<'a> {
    conn: &'a raw::Connection,
    request_info: RequestInfo<'a>,
    headers: Headers<'a>,
    extensions: Extensions
}

fn ver(major: u64, minor: u64) -> semver::Version {
    semver::Version {
        major: major,
        minor: minor,
        patch: 0,
        pre: vec!(),
        build: vec!()
    }
}

impl<'a> conduit::Request for CivetRequest<'a> {
    fn http_version(&self) -> semver::Version {
        let version = self.request_info.http_version().unwrap();
        match version {
            "1.0" => ver(1, 0),
            "1.1" => ver(1, 1),
            _ => ver(1, 1)
        }
    }

    fn conduit_version(&self) -> semver::Version {
        ver(0, 1)
    }

    fn method(&self) -> Method {
        match self.request_info.method().unwrap() {
            "HEAD" => Method::Head,
            "GET" => Method::Get,
            "POST" => Method::Post,
            "PUT" => Method::Put,
            "DELETE" => Method::Delete,
            "PATCH" => Method::Patch,
            "PURGE" => Method::Purge,
            "CONNECT" => Method::Connect,
            "OPTIONS" => Method::Options,
            "TRACE" => Method::Trace,
            other @ _ => panic!("Civet does not support {} requests", other)
        }
    }

    fn scheme(&self) -> Scheme {
        if self.request_info.is_ssl() {
            Scheme::Https
        } else {
            Scheme::Http
        }
    }

    fn host(&self) -> Host {
        Host::Name(get_header(self.conn, "Host").unwrap())
    }

    fn virtual_root(&self) -> Option<&str> {
        None
    }

    fn path(&self) -> &str {
        self.request_info.url().unwrap()
    }

    fn query_string(&self) -> Option<&str> {
        self.request_info.query_string()
    }

    fn remote_addr(&self) -> SocketAddr {
        let ip = self.request_info.remote_ip();
        let ip = Ipv4Addr::new((ip >> 24) as u8,
                               (ip >> 16) as u8,
                               (ip >>  8) as u8,
                               (ip >>  0) as u8);
        SocketAddr::V4(SocketAddrV4::new(ip, self.request_info.remote_port()))
    }

    fn content_length(&self) -> Option<u64> {
        get_header(self.conn, "Content-Length").and_then(|s| s.parse().ok())
    }

    fn headers(&self) -> &conduit::Headers { &self.headers }

    fn body(&mut self) -> &mut Read { self }

    fn extensions(&self) -> &Extensions { &self.extensions }

    fn mut_extensions(&mut self) -> &mut Extensions {
        &mut self.extensions
    }
}

pub fn response<S: ToStatusCode, R: Read + Send + 'static>(status: S,
    headers: HashMap<String, Vec<String>>, body: R) -> conduit::Response
{
    conduit::Response {
        status: status.to_status().ok().unwrap().to_code(),
        headers: headers,
        body: Box::new(body),
    }
}

impl<'a> Connection<'a> {
    fn new(conn: &raw::Connection) -> Result<Connection, String> {
        match request_info(conn) {
            Ok(info) => {
                let request = CivetRequest {
                    conn: conn,
                    request_info: info,
                    headers: Headers { conn: conn },
                    extensions: TypeMap::new()
                };

                Ok(Connection {
                    request: request,
                    written: false,
                })
            },
            Err(err) => Err(err)
        }
    }

}

impl<'a> Write for Connection<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.written = true;
        match raw::write(self.request.conn, buf) {
            n if n < 0 => Err(io::Error::new(io::ErrorKind::Other,
                                             &format!("write error ({})", n)[..])),
            n => Ok(n as usize)
        }
    }
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

impl<'a> Read for CivetRequest<'a> {
    fn read(&mut self, buf: &mut[u8]) -> io::Result<usize> {
        match raw::read(self.conn, buf) {
            n if n < 0 => Err(io::Error::new(io::ErrorKind::Other,
                                             &format!("read error ({})", n)[..])),
            n => Ok(n as usize)
        }
    }
}

impl<'a> Drop for Connection<'a> {
    fn drop(&mut self) {
        if !self.written {
            let _ = writeln!(self, "HTTP/1.1 500 Internal Server Error");
        }
    }
}

pub struct Headers<'a> {
    conn: &'a raw::Connection
}

impl<'a> conduit::Headers for Headers<'a> {
    fn find(&self, string: &str) -> Option<Vec<&str>> {
        get_header(self.conn, string).map(|s| vec!(s))
    }

    fn has(&self, string: &str) -> bool {
        get_header(self.conn, string).is_some()
    }

    fn all(&self) -> Vec<(&str, Vec<&str>)> {
        HeaderIterator::new(self.conn).collect()
    }
}

pub struct HeaderIterator<'a> {
    headers: Vec<Header<'a>>,
    position: usize
}

impl<'a> HeaderIterator<'a> {
    fn new<'b>(conn: &'b raw::Connection) -> HeaderIterator<'b> {
        HeaderIterator { headers: get_headers(conn), position: 0 }
    }
}

impl<'a> Iterator for HeaderIterator<'a> {
    type Item = (&'a str, Vec<&'a str>);
    fn next(&mut self) -> Option<(&'a str, Vec<&'a str>)> {
        let pos = self.position;
        let headers = &self.headers;

        if self.headers.len() <= pos {
            None
        } else {
            let header = &headers[pos];
            self.position += 1;
            header.name().map(|name| (name, vec!(header.value().unwrap())))
        }
    }
}

pub struct Server(raw::Server<Box<Handler + 'static + Sync>>);

impl Server {
    pub fn start<H: Handler + 'static + Sync>(options: Config, handler: H)
        -> io::Result<Server>
    {
        fn internal_handler(conn: &mut raw::Connection,
                            handler: &Box<Handler + 'static + Sync>)
                            -> Result<(), ()> {
            let mut connection = Connection::new(conn).unwrap();
            let response = handler.call(&mut connection.request);
            let mut writer = BufWriter::new(connection);

            fn err<W: Write>(writer: &mut W) {
                let _ = writeln!(writer, "HTTP/1.1 500 Internal Server Error");
            }

            let conduit::Response { status, headers, mut body } = match response {
                Ok(r) => r,
                Err(_) => return Err(err(&mut writer)),
            };
            let (code, string) = status;
            try!(write!(&mut writer, "HTTP/1.1 {} {}\r\n", code, string).map_err(|_| ()));

            for (key, value) in headers.iter() {
                for header in value.iter() {
                    try!(write!(&mut writer, "{}: {}\r\n", *key, *header).map_err(|_| ()));
                }
            }

            try!(write!(&mut writer, "\r\n").map_err(|_| ()));
            try!(body.write_body(&mut writer).map_err(|_| ()));

            Ok(())
        }

        let handler = Box::new(handler);
        let raw_callback = raw::ServerCallback::new(internal_handler, handler);
        Ok(Server(try!(raw::Server::start(options, raw_callback))))
    }
}

fn request_info<'a>(connection: &'a raw::Connection)
    -> Result<RequestInfo<'a>, String>
{
    match get_request_info(connection) {
        Some(info) => Ok(info),
        None => Err("Couldn't get request info for connection".to_string())
    }
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use std::error::Error;
    use std::io::prelude::*;
    use std::io::{self, Cursor};
    use std::net::{SocketAddr, TcpStream, SocketAddrV4, Ipv4Addr};
    use std::sync::Mutex;
    use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
    use std::sync::mpsc::{channel, Sender};
    use super::{Server, Config, response};
    use conduit::{Request, Response, Handler};

    fn noop(_: &mut Request) -> Result<Response, io::Error> { unreachable!() }

    fn request(addr: SocketAddr, req: &str) -> String {
        let mut s = TcpStream::connect(&addr).unwrap();
        s.write_all(req.trim_left().as_bytes()).unwrap();
        let mut ret = String::new();
        s.read_to_string(&mut ret).unwrap();
        ret
    }

    fn port() -> u16 {
        static CNT: AtomicUsize = ATOMIC_USIZE_INIT;
        CNT.fetch_add(1, Ordering::SeqCst) as u16 + 13038
    }

    fn cfg(port: u16) -> Config {
        let mut cfg = Config::new();
        cfg.port(port).threads(1);
        return cfg
    }

    #[test]
    fn smoke() {
        Server::start(cfg(port()), noop).unwrap();
    }

    #[test]
    fn dupe_port() {
        let port = port();
        let s1 = Server::start(cfg(port), noop);
        assert!(s1.is_ok());
        let s2 = Server::start(cfg(port), noop);
        assert!(s2.is_err());
    }

    #[test]
    fn drops_handler() {
        static mut DROPPED: bool = false;
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Error+Send>> {
                panic!()
            }
        }
        impl Drop for Foo {
            fn drop(&mut self) { unsafe { DROPPED = true; } }
        }

        drop(Server::start(cfg(port()), Foo));
        unsafe { assert!(DROPPED); }
    }

    #[test]
    fn invokes() {
        struct Foo(Mutex<Sender<()>>);
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Error+Send>> {
                let Foo(ref tx) = *self;
                tx.lock().unwrap().send(()).unwrap();
                Ok(response(200, HashMap::new(), Cursor::new(vec![])))
            }
        }

        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let port = port();
        let ip = Ipv4Addr::new(127, 0, 0, 1);
        let addr = SocketAddr::V4(SocketAddrV4::new(ip, port));
        let _s = Server::start(cfg(port), handler);
        request(addr, r"
GET / HTTP/1.1

");
        rx.recv().unwrap();
    }

    #[test]
    fn header_sent() {
        struct Foo(Mutex<Sender<String>>);
        impl Handler for Foo {
            fn call(&self, req: &mut Request) -> Result<Response, Box<Error+Send>> {
                let Foo(ref tx) = *self;
                tx.lock().unwrap()
                  .send(req.headers().find("Foo").unwrap().join("")).unwrap();
                Ok(response(200, HashMap::new(), Cursor::new(vec![])))
            }
        }

        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let port = port();
        let ip = Ipv4Addr::new(127, 0, 0, 1);
        let addr = SocketAddr::V4(SocketAddrV4::new(ip, port));
        let _s = Server::start(cfg(port), handler);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert_eq!(rx.recv().unwrap(), "bar");
    }

    #[test]
    fn failing_handler() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Error+Send>> {
                panic!()
            }
        }

        let port = port();
        let ip = Ipv4Addr::new(127, 0, 0, 1);
        let addr = SocketAddr::V4(SocketAddrV4::new(ip, port));
        let _s = Server::start(cfg(port), Foo);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
    }

    #[test]
    fn failing_handler_is_500() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Error+Send>> {
                panic!()
            }
        }

        let port = port();
        let ip = Ipv4Addr::new(127, 0, 0, 1);
        let addr = SocketAddr::V4(SocketAddrV4::new(ip, port));
        let _s = Server::start(cfg(port), Foo);
        let response = request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert!(response.contains("500 Internal"),
                "not a failing response: {}", response);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "binstat"]
#![deny(missing_doc)]

//! A library for modelling and reasoning about multidimensional
//! binary states.

use std::collections::Bitv;

/// Models a multidimensional binary state.
pub struct BinGraph<TAction> {
    /// The states and the bits that can be flipped.
    pub data: Vec<(Bitv, Bitv)>,
    /// A description the action that takes when flipping bits.
    pub actions: Vec<TAction>,
}

<commit_msg>Made it easier to add new information<commit_after>#![crate_name = "binstat"]
#![deny(missing_doc)]

//! A library for modelling and reasoning about multidimensional
//! binary states.

use std::collections::Bitv;

/// Contains a binary state and the choices.
pub struct BinStateChoices {
    /// The state composed of bits.
    pub state: Bitv,
    /// The choices represented as bits that can be flipped.
    pub choices: Bitv
}

impl BinStateChoices {
    /// Gets pairs from pair of booleans.
    pub fn from_pairs(pairs: &[(bool, bool)]) -> BinStateChoices {
        BinStateChoices {
            state: pairs.iter().map(|&(a, _)| a).collect(),
            choices: pairs.iter().map(|&(_, b)| b).collect()
        }
    }
}

/// Models a multidimensional binary state.
pub struct BinGraph<TAction> {
    /// The states and the bits that can be flipped.
    pub data: Vec<BinStateChoices>,
    /// A description the action that takes when flipping bits.
    pub actions: Vec<TAction>,
}

impl<TAction> BinGraph<TAction> {
    /// Creates a new BinGraph.
    pub fn new() -> BinGraph<TAction> {
        BinGraph {
            data: Vec::new(),
            actions: Vec::new()
        }
    }

    /// Adds new information about state and choices.
    ///
    /// The first bool indicate state, the second whether it can change.
    pub fn push_pairs(&mut self, pairs: &[(bool, bool)]) {
        self.data.push(BinStateChoices::from_pairs(pairs));
    }
}

#[test]
fn test_exclusive() {
    let mut g: BinGraph<&'static str> = BinGraph::new();
    g.actions.push("Go swiming");
    g.actions.push("Read a book");

    g.push_pairs([
        (false, true), // go swimming
        (false, true), // read a book
    ]);
    g.push_pairs([
        (true, true), // is swimming, can stop.
        (false, false), // is not reading book, can't read book.
    ]);
}

<|endoftext|>


<commit_before>#![doc(html_root_url = "https://acmcarther.github.io/cucumber-rs/")]

#![cfg_attr(nightly, feature(custom_derive, plugin))]
#![cfg_attr(nightly, plugin(serde_macros))]

extern crate regex;
extern crate itertools;
extern crate serde;
extern crate serde_json;

/// Low level location of step functions and matcher logic
pub mod state;

/// External facing interface to other Gherkin implementations
pub mod server;

/// Coordinator logic between [server](server/index.html) and
/// [state](state/index.html)
pub mod runner;

/// Business logic for step registration and invoke argument destructuring
pub mod definitions;

/// External facing interface for events
pub mod event;

/// Helpers for regular expressions
pub mod cucumber_regex;

mod launcher;

pub use launcher::{ruby_command, create_config};

pub use runner::{CommandRunner, WorldRunner};
pub use definitions::registration::CucumberRegistrar;
pub use state::{Cucumber, SendableStep};
pub use server::Server;
pub use event::request::InvokeArgument;

/// Destructure a vector of
/// [InvokeArgument](event/request/enum.InvokeArgument.html) into a tuple of
/// values, or a bad [InvokeResponse](event/response/enum.InvokeResponse.html),
/// similar to normal try!
///
/// Will either short circult return an InvokeArgument::Fail, describing either
/// improper arg count
/// or improper arg type, or will yield the tuple of values
///
/// Reminder: Tuple of one value is represented as `(t,): (Type,)`
///
/// # Example
///
/// ```
/// #[macro_use]
/// extern crate cucumber;
///
/// use cucumber::{
///   InvokeArgument,
/// };
///
/// fn main() {
///   fn do_work() {
///     let args = vec![
///       InvokeArgument::from_str("1"),
///       InvokeArgument::from_str("2"),
///       InvokeArgument::None
///     ];
///     let (x, y, z): (u32, u32, bool) = try_destructure!(args);
///
///     assert_eq!(x, 1);
///     assert_eq!(y, 2);
///     assert_eq!(z, false);
///   }
/// }
/// ```
#[macro_export]
macro_rules! try_destructure {
  ($r: ident) => ({
    use $crate::definitions::destructuring::{DestructurableSet, InvokeArgSetError};

    match $r.destructure_set() {
      Ok(e) => e,
      Err(error) => {
        match error {
          InvokeArgSetError::TypeMismatch {arg_idx} => {
            panic!("Argument in position [{}] did not have the correct type or was unparseable", arg_idx)
          },
          InvokeArgSetError::ArgCountMismatch {expected, actual} => {
            panic!("Expected [{}] arguments, but found [{}] in step definition", expected, actual)
          }
        }
      }
    }
  })
}

/// Add a Given step to a
/// [CucumberRegistrar](definitions/registration/trait.CucumberRegistrar.html)
///
/// # Example
/// ```
/// #[macro_use]
/// extern crate cucumber;
///
/// use cucumber::{
///   CucumberRegistrar,
///   Cucumber
/// };
///
/// pub fn main () {
///   let mut cucumber: Cucumber<u32> = Cucumber::new();
///
/// Given!(cucumber, "^I have (\\d+) coins$", |_, world: &mut u32,
/// (coin_count,): (u32,)| {
///     *world = coin_count;
///   });
/// }
/// ```
///
#[macro_export]
macro_rules! Given {
  ($cuke:expr, $regex:expr, $body:expr) => {{
    use $crate::cucumber_regex;
    $cuke.given(file!(), line!(), cucumber_regex::build($regex), Box::new(move |cuke, world, args| {
      ($body)(cuke, world, try_destructure!(args))
    }))
  }}
}

/// Add a When step to a
/// [CucumberRegistrar](definitions/registration/trait.CucumberRegistrar.html)
///
/// # Example
/// ```
/// #[macro_use]
/// extern crate cucumber;
///
/// use cucumber::{
///   CucumberRegistrar,
///   Cucumber
/// };
///
/// pub fn main () {
///   let mut cucumber: Cucumber<u32> = Cucumber::new();
///
/// When!(cucumber, "^I spend (\\d+) coins$", |_, world: &mut u32,
/// (coin_count,): (u32,)| {
///     if *world - coin_count < 0 {
///       panic!("Tried to spend more coins than were owned")
///     } else {
///       *world = *world - coin_count;
///     }
///   });
/// }
/// ```
///
#[macro_export]
macro_rules! When {
  ($cuke:expr, $regex:expr, $body:expr) => {{
    use $crate::cucumber_regex;
    $cuke.when(file!(), line!(), cucumber_regex::build($regex), Box::new(move |cuke, world, args| {
      ($body)(cuke, world, try_destructure!(args))
    }))
  }}
}

/// Add a Then step to a
/// [CucumberRegistrar](definitions/registration/trait.CucumberRegistrar.html)
///
/// # Example
/// ```
/// #[macro_use]
/// extern crate cucumber;
///
/// use cucumber::{
///   CucumberRegistrar,
///   Cucumber
/// };
///
/// pub fn main () {
///   let mut cucumber: Cucumber<u32> = Cucumber::new();
///
/// Then!(cucumber, "^I have (\\d+) coins left$", |_, world: &mut u32,
/// (coin_count,): (u32,)| {
///     assert_eq!(*world, coin_count)
///   });
/// }
/// ```
///
#[macro_export]
macro_rules! Then {
  ($cuke:expr, $regex:expr, $body:expr) => {{
    use $crate::cucumber_regex;
    $cuke.then(file!(), line!(), cucumber_regex::build($regex), Box::new(move |cuke, world, args| {
      ($body)(cuke, world, try_destructure!(args))
    }))
  }}
}
<commit_msg>Reexported CucumberConfig (#49)<commit_after>#![doc(html_root_url = "https://acmcarther.github.io/cucumber-rs/")]

#![cfg_attr(nightly, feature(custom_derive, plugin))]
#![cfg_attr(nightly, plugin(serde_macros))]

extern crate regex;
extern crate itertools;
extern crate serde;
extern crate serde_json;

/// Low level location of step functions and matcher logic
pub mod state;

/// External facing interface to other Gherkin implementations
pub mod server;

/// Coordinator logic between [server](server/index.html) and
/// [state](state/index.html)
pub mod runner;

/// Business logic for step registration and invoke argument destructuring
pub mod definitions;

/// External facing interface for events
pub mod event;

/// Helpers for regular expressions
pub mod cucumber_regex;

mod launcher;

pub use launcher::{ruby_command, create_config, CucumberConfig};

pub use runner::{CommandRunner, WorldRunner};
pub use definitions::registration::CucumberRegistrar;
pub use state::{Cucumber, SendableStep};
pub use server::Server;
pub use event::request::InvokeArgument;

/// Destructure a vector of
/// [InvokeArgument](event/request/enum.InvokeArgument.html) into a tuple of
/// values, or a bad [InvokeResponse](event/response/enum.InvokeResponse.html),
/// similar to normal try!
///
/// Will either short circult return an InvokeArgument::Fail, describing either
/// improper arg count
/// or improper arg type, or will yield the tuple of values
///
/// Reminder: Tuple of one value is represented as `(t,): (Type,)`
///
/// # Example
///
/// ```
/// #[macro_use]
/// extern crate cucumber;
///
/// use cucumber::{
///   InvokeArgument,
/// };
///
/// fn main() {
///   fn do_work() {
///     let args = vec![
///       InvokeArgument::from_str("1"),
///       InvokeArgument::from_str("2"),
///       InvokeArgument::None
///     ];
///     let (x, y, z): (u32, u32, bool) = try_destructure!(args);
///
///     assert_eq!(x, 1);
///     assert_eq!(y, 2);
///     assert_eq!(z, false);
///   }
/// }
/// ```
#[macro_export]
macro_rules! try_destructure {
  ($r: ident) => ({
    use $crate::definitions::destructuring::{DestructurableSet, InvokeArgSetError};

    match $r.destructure_set() {
      Ok(e) => e,
      Err(error) => {
        match error {
          InvokeArgSetError::TypeMismatch {arg_idx} => {
            panic!("Argument in position [{}] did not have the correct type or was unparseable", arg_idx)
          },
          InvokeArgSetError::ArgCountMismatch {expected, actual} => {
            panic!("Expected [{}] arguments, but found [{}] in step definition", expected, actual)
          }
        }
      }
    }
  })
}

/// Add a Given step to a
/// [CucumberRegistrar](definitions/registration/trait.CucumberRegistrar.html)
///
/// # Example
/// ```
/// #[macro_use]
/// extern crate cucumber;
///
/// use cucumber::{
///   CucumberRegistrar,
///   Cucumber
/// };
///
/// pub fn main () {
///   let mut cucumber: Cucumber<u32> = Cucumber::new();
///
/// Given!(cucumber, "^I have (\\d+) coins$", |_, world: &mut u32,
/// (coin_count,): (u32,)| {
///     *world = coin_count;
///   });
/// }
/// ```
///
#[macro_export]
macro_rules! Given {
  ($cuke:expr, $regex:expr, $body:expr) => {{
    use $crate::cucumber_regex;
    $cuke.given(file!(), line!(), cucumber_regex::build($regex), Box::new(move |cuke, world, args| {
      ($body)(cuke, world, try_destructure!(args))
    }))
  }}
}

/// Add a When step to a
/// [CucumberRegistrar](definitions/registration/trait.CucumberRegistrar.html)
///
/// # Example
/// ```
/// #[macro_use]
/// extern crate cucumber;
///
/// use cucumber::{
///   CucumberRegistrar,
///   Cucumber
/// };
///
/// pub fn main () {
///   let mut cucumber: Cucumber<u32> = Cucumber::new();
///
/// When!(cucumber, "^I spend (\\d+) coins$", |_, world: &mut u32,
/// (coin_count,): (u32,)| {
///     if *world - coin_count < 0 {
///       panic!("Tried to spend more coins than were owned")
///     } else {
///       *world = *world - coin_count;
///     }
///   });
/// }
/// ```
///
#[macro_export]
macro_rules! When {
  ($cuke:expr, $regex:expr, $body:expr) => {{
    use $crate::cucumber_regex;
    $cuke.when(file!(), line!(), cucumber_regex::build($regex), Box::new(move |cuke, world, args| {
      ($body)(cuke, world, try_destructure!(args))
    }))
  }}
}

/// Add a Then step to a
/// [CucumberRegistrar](definitions/registration/trait.CucumberRegistrar.html)
///
/// # Example
/// ```
/// #[macro_use]
/// extern crate cucumber;
///
/// use cucumber::{
///   CucumberRegistrar,
///   Cucumber
/// };
///
/// pub fn main () {
///   let mut cucumber: Cucumber<u32> = Cucumber::new();
///
/// Then!(cucumber, "^I have (\\d+) coins left$", |_, world: &mut u32,
/// (coin_count,): (u32,)| {
///     assert_eq!(*world, coin_count)
///   });
/// }
/// ```
///
#[macro_export]
macro_rules! Then {
  ($cuke:expr, $regex:expr, $body:expr) => {{
    use $crate::cucumber_regex;
    $cuke.then(file!(), line!(), cucumber_regex::build($regex), Box::new(move |cuke, world, args| {
      ($body)(cuke, world, try_destructure!(args))
    }))
  }}
}
<|endoftext|>


<commit_before>// Filebuffer -- Fast and simple file reading
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! Filebuffer, a library for fast and simple file reading.
//!
//! # Examples
//!
//! Map a file into memory and access it as a slice of bytes. This is simple and will generally
//! outperform `Read::read_to_end()`.
//!
//! ```
//! use filebuffer::FileBuffer;
//! let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
//! assert_eq!(&fbuffer[3..45], &b"Filebuffer -- Fast and simple file reading"[..]);
//! ```

#![warn(missing_docs)]

use std::cmp;
use std::io;
use std::fs;
use std::ops::Deref;
use std::path::Path;
use std::ptr;
use std::slice;

#[cfg(unix)]
mod unix;

#[cfg(windows)]
mod windows;

#[cfg(unix)]
use unix::{PlatformData, get_resident, get_page_size, map_file, unmap_file, prefetch};

#[cfg(windows)]
use windows::{PlatformData, get_resident, get_page_size, map_file, unmap_file, prefetch};

/// A memory-mapped file.
///
/// # Safety
///
/// **On Unix-ish platforms, external modifications to the file made after the file buffer was
/// opened can show up in this file buffer.** In particular, if a file is truncated after opening,
/// accessing the removed part causes undefined behavior. On Windows it is possible to prevent this
/// by opening the file in exclusive mode, but that functionality is not available in stable Rust
/// currently. (Filestream will be updated after stabilization.)
///
/// It is recommended to ensure that other applications do not write to the file when it is mapped,
/// possibly by marking the file read-only. (Though even this is no guarantee.)
pub struct FileBuffer {
    page_size: usize,
    buffer: *const u8,
    length: usize,

    #[allow(dead_code)] // This field is not dead, it might have an effectful destructor.
    platform_data: PlatformData,
}

/// Rounds `size` up to the nearest multiple of `power_of_two`.
fn round_up_to(size: usize, power_of_two: usize) -> usize {
    (size + (power_of_two - 1)) & !(power_of_two - 1)
}

#[test]
fn verify_round_up_to() {
    assert_eq!(1024, round_up_to(23, 1024));
    assert_eq!(1024, round_up_to(1024, 1024));
    assert_eq!(2048, round_up_to(1025, 1024));
}

/// Rounds `size` down to the nearest multiple of `power_of_two`.
fn round_down_to(size: usize, power_of_two: usize) -> usize {
    size & !(power_of_two - 1)
}

#[test]
fn verify_round_down_to() {
    assert_eq!(0, round_down_to(23, 1024));
    assert_eq!(1024, round_down_to(1024, 1024));
    assert_eq!(1024, round_down_to(1025, 1024));
}

impl FileBuffer {
    /// Maps the file at `path` into memory.
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<FileBuffer> {
        // Open the `fs::File` so we get all of std's error handling for free, then use it to
        // extract the file descriptor. The file is closed again when `map_file` returns on
        // Unix-ish platforms, but `mmap` only requires the descriptor to be open for the `mmap`
        // call, so this is fine. On Windows, the file must be kept open for the lifetime of the
        // mapping, so `map_file` moves the file into the platform data.
        let mut open_opts = fs::OpenOptions::new();
        open_opts.read(true);

        // TODO: On Windows, set `share_mode()` to read-only. This requires the `open_options_ext`
        // feature that is currently unstable, but it is required to ensure that a different
        // process does not suddenly modify the contents of the file.

        let file = try!(open_opts.open(path));
        let (buffer, length, platform_data) = try!(map_file(file));
        let fbuffer = FileBuffer {
            page_size: get_page_size(),
            buffer: buffer,
            length: length,
            platform_data: platform_data
        };
        Ok(fbuffer)
    }

    /// Returns the number of bytes resident in physical memory, starting from `offset`.
    ///
    /// The slice `[offset..offset + resident_len]` can be accessed without causing page faults or
    /// disk access. Note that this is only a snapshot, and the kernel might decide to evict pages
    /// or make them resident at any time.
    ///
    /// The returned resident length is at most `length`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    ///
    /// # Remarks
    ///
    /// Windows does not expose a mechanism to query which pages are resident in physical
    /// memory. Therefore this function optimistically claims that the entire range is resident
    /// on Windows.
    pub fn resident_len(&self, offset: usize, length: usize) -> usize {
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        // This is a no-op for empty files.
        if self.buffer == ptr::null() { return 0; }

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);
        let num_pages = aligned_length / self.page_size;

        // There is a tradeoff here: to store residency information, we need an array of booleans.
        // The requested range can potentially be very large and it is only known at runtime. We
        // could allocate a vector here, but that requires a heap allocation just to get residency
        // information (which might in turn cause a page fault). Instead, check at most 32 pages at
        // once. This means more syscalls for large ranges, but it saves us the heap allocation,
        // and for ranges up to 32 pages (128 KiB typically) there is only one syscall.
        let mut residency = [false; 32];
        let mut pages_checked = 0;
        let mut pages_resident = 0;

        while pages_checked < num_pages {
            let pages_to_check = cmp::min(32, num_pages - pages_checked);
            let check_offset = (aligned_offset + pages_checked * self.page_size) as isize;
            let check_buffer = unsafe { self.buffer.offset(check_offset) };
            let check_length = pages_to_check * self.page_size;
            get_resident(check_buffer, check_length, &mut residency);

            // Count the number of resident pages.
            match residency[..pages_to_check].iter().position(|resident| !resident) {
                Some(non_resident) => {
                    // The index of the non-resident page is the number of resident pages.
                    pages_resident += non_resident;
                    break;
                }
                None => {
                    pages_resident += pages_to_check;
                    pages_checked += pages_to_check;
                }
            }
        }

        let resident_length = pages_resident * self.page_size + aligned_offset - offset;

        // Never return more than the requested length. The resident length might be larger than
        // the length of the buffer, because it is rounded up to the page size.
        cmp::min(length, resident_length)
    }

    /// Returns the system page size.
    ///
    /// When the kernel makes the file resident in physical memory, it does so with page
    /// granularity. (In practice this happens in larger chunks, but still in multiples of
    /// the page size.) Therefore, when processing the file in chunks, this is a good chunk
    /// length.
    pub fn chunk_len_hint(&self) -> usize {
        self.page_size
    }

    /// Advises the kernel to make a slice of the file resident in physical memory.
    ///
    /// This method does not block, meaning that when the function returns, the slice is not
    /// necessarily resident. After this function returns, the kernel may read the requested slice
    /// from disk and make it resident. Note that this is only an advice, the kernel need not honor
    /// it.
    ///
    /// To check whether the slice is resident at a later time, use `resident_len()`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    pub fn prefetch(&self, offset: usize, length: usize) {
        // TODO: This function should use `collections::range::RangeArgument` once stabilized.
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        // This is a no-op for empty files.
        if self.buffer == ptr::null() { return; }

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);

        let buffer = unsafe { self.buffer.offset(aligned_offset as isize) };
        prefetch(buffer, aligned_length);
    }

    /// Leaks the file buffer as a byte slice.
    ///
    /// This prevents the buffer from being unmapped, keeping the file mapped until the program
    /// ends. This is not as bad as it sounds, because the kernel is free to evict pages from
    /// physical memory in case of memory pressure. Because the file is mapped read-only, it can
    /// always be read from disk again.
    ///
    /// If the file buffer is going to be open for the entire duration of the program anyway, this
    /// method can avoid some lifetime issues. Still, it is good practice to close the file buffer
    /// if possible. This method should be a last resort.
    pub fn leak(mut self) -> &'static [u8] {
        let buffer = unsafe { slice::from_raw_parts(self.buffer, self.length) };

        // Prevent `drop()` from freeing the buffer.
        self.buffer = ptr::null();
        self.length = 0;

        buffer
    }
}

// There is no possibility of data races when passing `&FileBuffer` across threads,
// because the buffer is read-only. `&FileBuffer` has no interior mutability.
unsafe impl Sync for FileBuffer {}

// It is safe to move a `FileBuffer` into a different thread.
unsafe impl Send for FileBuffer {}

impl Drop for FileBuffer {
    fn drop(&mut self) {
        if self.buffer != ptr::null() { unmap_file(self.buffer, self.length); }
    }
}

impl Deref for FileBuffer {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe { slice::from_raw_parts(self.buffer, self.length) }
    }
}

#[test]
fn open_file() {
    let fbuffer = FileBuffer::open("src/lib.rs");
    assert!(fbuffer.is_ok());
}

#[test]
fn make_resident() {
    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();

    // Touch the first page to make it resident.
    assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);

    // Now at least that part should be resident.
    assert_eq!(fbuffer.resident_len(3, 10), 10);
}

#[test]
fn prefetch_is_not_harmful() {
    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();

    // It is impossible to test that this actually works without root access to instruct the kernel
    // to drop its caches, but at least we can verify that calling `prefetch` is not harmful.
    fbuffer.prefetch(0, fbuffer.len());

    // Reading from the file should still work as normal.
    assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);
}

#[test]
fn drop_after_leak() {
    let mut bytes = &[0u8][..];
    assert_eq!(bytes[0], 0);
    {
        let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
        bytes = fbuffer.leak();
    }
    assert_eq!(&bytes[3..13], &b"Filebuffer"[..]);
}

#[test]
fn fbuffer_can_be_moved_into_thread() {
    use std::thread;

    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
    thread::spawn(move || {
        assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);
    });
}

#[test]
fn fbuffer_can_be_shared_among_threads() {
    use std::sync;
    use std::thread;

    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
    let buffer1 = sync::Arc::new(fbuffer);
    let buffer2 = buffer1.clone();
    thread::spawn(move || {
        assert_eq!(&buffer2[3..13], &b"Filebuffer"[..]);
    });
    assert_eq!(&buffer1[17..45], &b"Fast and simple file reading"[..]);
}

#[test]
fn open_empty_file_is_fine() {
    FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
}

#[test]
fn empty_file_prefetch_is_fine() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    fbuffer.prefetch(0, 0);
}

#[test]
fn empty_file_deref_is_fine() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    assert_eq!(fbuffer.iter().any(|_| true), false);
}

#[test]
fn empty_file_has_zero_resident_len() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    assert_eq!(fbuffer.resident_len(0, 0), 0);
}

#[test]
fn page_size_at_least_4096() {
    // There is no reason why the page size cannot be smaller, it is just that in practice there
    // is no platform with a smaller page size, so this tests that `get_page_size()` returns
    // a plausible value.
    assert!(get_page_size() >= 4096);
}
<commit_msg>Fix typo<commit_after>// Filebuffer -- Fast and simple file reading
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! Filebuffer, a library for fast and simple file reading.
//!
//! # Examples
//!
//! Map a file into memory and access it as a slice of bytes. This is simple and will generally
//! outperform `Read::read_to_end()`.
//!
//! ```
//! use filebuffer::FileBuffer;
//! let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
//! assert_eq!(&fbuffer[3..45], &b"Filebuffer -- Fast and simple file reading"[..]);
//! ```

#![warn(missing_docs)]

use std::cmp;
use std::io;
use std::fs;
use std::ops::Deref;
use std::path::Path;
use std::ptr;
use std::slice;

#[cfg(unix)]
mod unix;

#[cfg(windows)]
mod windows;

#[cfg(unix)]
use unix::{PlatformData, get_resident, get_page_size, map_file, unmap_file, prefetch};

#[cfg(windows)]
use windows::{PlatformData, get_resident, get_page_size, map_file, unmap_file, prefetch};

/// A memory-mapped file.
///
/// # Safety
///
/// **On Unix-ish platforms, external modifications to the file made after the file buffer was
/// opened can show up in this file buffer.** In particular, if a file is truncated after opening,
/// accessing the removed part causes undefined behavior. On Windows it is possible to prevent this
/// by opening the file in exclusive mode, but that functionality is not available in stable Rust
/// currently. (Filebuffer will be updated after stabilization.)
///
/// It is recommended to ensure that other applications do not write to the file when it is mapped,
/// possibly by marking the file read-only. (Though even this is no guarantee.)
pub struct FileBuffer {
    page_size: usize,
    buffer: *const u8,
    length: usize,

    #[allow(dead_code)] // This field is not dead, it might have an effectful destructor.
    platform_data: PlatformData,
}

/// Rounds `size` up to the nearest multiple of `power_of_two`.
fn round_up_to(size: usize, power_of_two: usize) -> usize {
    (size + (power_of_two - 1)) & !(power_of_two - 1)
}

#[test]
fn verify_round_up_to() {
    assert_eq!(1024, round_up_to(23, 1024));
    assert_eq!(1024, round_up_to(1024, 1024));
    assert_eq!(2048, round_up_to(1025, 1024));
}

/// Rounds `size` down to the nearest multiple of `power_of_two`.
fn round_down_to(size: usize, power_of_two: usize) -> usize {
    size & !(power_of_two - 1)
}

#[test]
fn verify_round_down_to() {
    assert_eq!(0, round_down_to(23, 1024));
    assert_eq!(1024, round_down_to(1024, 1024));
    assert_eq!(1024, round_down_to(1025, 1024));
}

impl FileBuffer {
    /// Maps the file at `path` into memory.
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<FileBuffer> {
        // Open the `fs::File` so we get all of std's error handling for free, then use it to
        // extract the file descriptor. The file is closed again when `map_file` returns on
        // Unix-ish platforms, but `mmap` only requires the descriptor to be open for the `mmap`
        // call, so this is fine. On Windows, the file must be kept open for the lifetime of the
        // mapping, so `map_file` moves the file into the platform data.
        let mut open_opts = fs::OpenOptions::new();
        open_opts.read(true);

        // TODO: On Windows, set `share_mode()` to read-only. This requires the `open_options_ext`
        // feature that is currently unstable, but it is required to ensure that a different
        // process does not suddenly modify the contents of the file.

        let file = try!(open_opts.open(path));
        let (buffer, length, platform_data) = try!(map_file(file));
        let fbuffer = FileBuffer {
            page_size: get_page_size(),
            buffer: buffer,
            length: length,
            platform_data: platform_data
        };
        Ok(fbuffer)
    }

    /// Returns the number of bytes resident in physical memory, starting from `offset`.
    ///
    /// The slice `[offset..offset + resident_len]` can be accessed without causing page faults or
    /// disk access. Note that this is only a snapshot, and the kernel might decide to evict pages
    /// or make them resident at any time.
    ///
    /// The returned resident length is at most `length`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    ///
    /// # Remarks
    ///
    /// Windows does not expose a mechanism to query which pages are resident in physical
    /// memory. Therefore this function optimistically claims that the entire range is resident
    /// on Windows.
    pub fn resident_len(&self, offset: usize, length: usize) -> usize {
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        // This is a no-op for empty files.
        if self.buffer == ptr::null() { return 0; }

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);
        let num_pages = aligned_length / self.page_size;

        // There is a tradeoff here: to store residency information, we need an array of booleans.
        // The requested range can potentially be very large and it is only known at runtime. We
        // could allocate a vector here, but that requires a heap allocation just to get residency
        // information (which might in turn cause a page fault). Instead, check at most 32 pages at
        // once. This means more syscalls for large ranges, but it saves us the heap allocation,
        // and for ranges up to 32 pages (128 KiB typically) there is only one syscall.
        let mut residency = [false; 32];
        let mut pages_checked = 0;
        let mut pages_resident = 0;

        while pages_checked < num_pages {
            let pages_to_check = cmp::min(32, num_pages - pages_checked);
            let check_offset = (aligned_offset + pages_checked * self.page_size) as isize;
            let check_buffer = unsafe { self.buffer.offset(check_offset) };
            let check_length = pages_to_check * self.page_size;
            get_resident(check_buffer, check_length, &mut residency);

            // Count the number of resident pages.
            match residency[..pages_to_check].iter().position(|resident| !resident) {
                Some(non_resident) => {
                    // The index of the non-resident page is the number of resident pages.
                    pages_resident += non_resident;
                    break;
                }
                None => {
                    pages_resident += pages_to_check;
                    pages_checked += pages_to_check;
                }
            }
        }

        let resident_length = pages_resident * self.page_size + aligned_offset - offset;

        // Never return more than the requested length. The resident length might be larger than
        // the length of the buffer, because it is rounded up to the page size.
        cmp::min(length, resident_length)
    }

    /// Returns the system page size.
    ///
    /// When the kernel makes the file resident in physical memory, it does so with page
    /// granularity. (In practice this happens in larger chunks, but still in multiples of
    /// the page size.) Therefore, when processing the file in chunks, this is a good chunk
    /// length.
    pub fn chunk_len_hint(&self) -> usize {
        self.page_size
    }

    /// Advises the kernel to make a slice of the file resident in physical memory.
    ///
    /// This method does not block, meaning that when the function returns, the slice is not
    /// necessarily resident. After this function returns, the kernel may read the requested slice
    /// from disk and make it resident. Note that this is only an advice, the kernel need not honor
    /// it.
    ///
    /// To check whether the slice is resident at a later time, use `resident_len()`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    pub fn prefetch(&self, offset: usize, length: usize) {
        // TODO: This function should use `collections::range::RangeArgument` once stabilized.
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        // This is a no-op for empty files.
        if self.buffer == ptr::null() { return; }

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);

        let buffer = unsafe { self.buffer.offset(aligned_offset as isize) };
        prefetch(buffer, aligned_length);
    }

    /// Leaks the file buffer as a byte slice.
    ///
    /// This prevents the buffer from being unmapped, keeping the file mapped until the program
    /// ends. This is not as bad as it sounds, because the kernel is free to evict pages from
    /// physical memory in case of memory pressure. Because the file is mapped read-only, it can
    /// always be read from disk again.
    ///
    /// If the file buffer is going to be open for the entire duration of the program anyway, this
    /// method can avoid some lifetime issues. Still, it is good practice to close the file buffer
    /// if possible. This method should be a last resort.
    pub fn leak(mut self) -> &'static [u8] {
        let buffer = unsafe { slice::from_raw_parts(self.buffer, self.length) };

        // Prevent `drop()` from freeing the buffer.
        self.buffer = ptr::null();
        self.length = 0;

        buffer
    }
}

// There is no possibility of data races when passing `&FileBuffer` across threads,
// because the buffer is read-only. `&FileBuffer` has no interior mutability.
unsafe impl Sync for FileBuffer {}

// It is safe to move a `FileBuffer` into a different thread.
unsafe impl Send for FileBuffer {}

impl Drop for FileBuffer {
    fn drop(&mut self) {
        if self.buffer != ptr::null() { unmap_file(self.buffer, self.length); }
    }
}

impl Deref for FileBuffer {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe { slice::from_raw_parts(self.buffer, self.length) }
    }
}

#[test]
fn open_file() {
    let fbuffer = FileBuffer::open("src/lib.rs");
    assert!(fbuffer.is_ok());
}

#[test]
fn make_resident() {
    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();

    // Touch the first page to make it resident.
    assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);

    // Now at least that part should be resident.
    assert_eq!(fbuffer.resident_len(3, 10), 10);
}

#[test]
fn prefetch_is_not_harmful() {
    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();

    // It is impossible to test that this actually works without root access to instruct the kernel
    // to drop its caches, but at least we can verify that calling `prefetch` is not harmful.
    fbuffer.prefetch(0, fbuffer.len());

    // Reading from the file should still work as normal.
    assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);
}

#[test]
fn drop_after_leak() {
    let mut bytes = &[0u8][..];
    assert_eq!(bytes[0], 0);
    {
        let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
        bytes = fbuffer.leak();
    }
    assert_eq!(&bytes[3..13], &b"Filebuffer"[..]);
}

#[test]
fn fbuffer_can_be_moved_into_thread() {
    use std::thread;

    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
    thread::spawn(move || {
        assert_eq!(&fbuffer[3..13], &b"Filebuffer"[..]);
    });
}

#[test]
fn fbuffer_can_be_shared_among_threads() {
    use std::sync;
    use std::thread;

    let fbuffer = FileBuffer::open("src/lib.rs").unwrap();
    let buffer1 = sync::Arc::new(fbuffer);
    let buffer2 = buffer1.clone();
    thread::spawn(move || {
        assert_eq!(&buffer2[3..13], &b"Filebuffer"[..]);
    });
    assert_eq!(&buffer1[17..45], &b"Fast and simple file reading"[..]);
}

#[test]
fn open_empty_file_is_fine() {
    FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
}

#[test]
fn empty_file_prefetch_is_fine() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    fbuffer.prefetch(0, 0);
}

#[test]
fn empty_file_deref_is_fine() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    assert_eq!(fbuffer.iter().any(|_| true), false);
}

#[test]
fn empty_file_has_zero_resident_len() {
    let fbuffer = FileBuffer::open("src/empty_file_for_testing.rs").unwrap();
    assert_eq!(fbuffer.resident_len(0, 0), 0);
}

#[test]
fn page_size_at_least_4096() {
    // There is no reason why the page size cannot be smaller, it is just that in practice there
    // is no platform with a smaller page size, so this tests that `get_page_size()` returns
    // a plausible value.
    assert!(get_page_size() >= 4096);
}
<|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 itertools::Itertools;
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 + Eq + Hash + Ord + PartialEq + PartialOrd { }

/// 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) -> Self::IntoIter {
        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;
        let key_vec = self.keymap.values()
                                 .flat_map(|bt| bt.into_iter().filter_map(|x| x))
                                 .collect::<Vec<_>>();

        input_translator.keymap.reserve(key_vec.len());
        for &k in &key_vec {
            for (&a, bt) in self.keymap.iter() {
                if bt.contains(k) {
                    input_translator.keymap.insert(k, a);
                }
            }
        }

        input_translator
    }
}

impl<A: Action> Into<InputRebind<A>> for InputTranslator<A> {
    fn into(self) -> InputRebind<A> {
        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>Remove unnecessary PartialCmp traits on Action<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 itertools::Itertools;
use window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::cmp::{PartialEq, Eq, 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 + Eq + Hash + 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) -> Self::IntoIter {
        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;
        let key_vec = self.keymap.values()
                                 .flat_map(|bt| bt.into_iter().filter_map(|x| x))
                                 .collect::<Vec<_>>();

        input_translator.keymap.reserve(key_vec.len());
        for &k in &key_vec {
            for (&a, bt) in self.keymap.iter() {
                if bt.contains(k) {
                    input_translator.keymap.insert(k, a);
                }
            }
        }

        input_translator
    }
}

impl<A: Action> Into<InputRebind<A>> for InputTranslator<A> {
    fn into(self) -> InputRebind<A> {
        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>#![feature(pub_restricted)]
#![feature(inclusive_range_syntax, inclusive_range)]
#![feature(type_ascription)]
#![feature(slice_patterns)]

/// (Macro imports need to appear at the crate root.)
#[macro_use] extern crate lazy_static;

#[macro_use]
extern crate log;

/// Literate programming stuff goes in `mod lit`.
#[path="lit/src/mod.rs"]
mod lit;

use lit::{attrs};
pub use lit::{directions, find_text, find_path, format};
pub use lit::{grid, path};
pub use lit::{render, svg, text, test_data};

#[cfg(test)]
use lit::{env_logger};
use lit::{regex, treexml};

pub use lit::Scene;

/// LalrPop grammar and its generated goes in `mod grammar`.
mod grammar;
<commit_msg>workaround unreachable pattern issue by turning off the error.<commit_after>#![feature(pub_restricted)]
#![feature(inclusive_range_syntax, inclusive_range)]
#![feature(type_ascription)]
#![feature(slice_patterns)]

#![allow(unreachable_patterns)]

/// (Macro imports need to appear at the crate root.)
#[macro_use] extern crate lazy_static;

#[macro_use]
extern crate log;

/// Literate programming stuff goes in `mod lit`.
#[path="lit/src/mod.rs"]
mod lit;

use lit::{attrs};
pub use lit::{directions, find_text, find_path, format};
pub use lit::{grid, path};
pub use lit::{render, svg, text, test_data};

#[cfg(test)]
use lit::{env_logger};
use lit::{regex, treexml};

pub use lit::Scene;

/// LalrPop grammar and its generated goes in `mod grammar`.
mod grammar;
<|endoftext|>