<commit_before>#![cfg_attr(test, deny(warnings))]

extern crate time;
extern crate conduit;
extern crate conduit_middleware as middleware;

use conduit::{Request, Method};
use middleware::Middleware;
use std::borrow::Cow;
use std::error::Error;
use std::io;
use time::{Tm, ParseError};

pub type Response = Result<conduit::Response, Box<Error+Send>>;

#[allow(missing_copy_implementations)]
pub struct ConditionalGet;

impl Middleware for ConditionalGet {
    fn after(&self, req: &mut Request, res: Response) -> Response {
        let mut res = try!(res);

        match req.method() {
            Method::Get | Method::Head => {
                if is_ok(&res) && is_fresh(req, &res) {
                    res.status = (304, "Not Modified");
                    res.headers.remove("Content-Type");
                    res.headers.remove("Content-Length");
                    res.body = Box::new(io::empty());
                }
            },
            _ => ()
        }

        Ok(res)
    }
}

fn is_ok(response: &conduit::Response) -> bool {
    match *response {
        conduit::Response { status: (200, _), .. } => true,
        _ => false
    }
}

fn is_fresh(req: &Request, res: &conduit::Response) -> bool {
    let modified_since = req.headers().find("If-Modified-Since").map(header_val);
    let none_match     = req.headers().find("If-None-Match").map(header_val);

    if modified_since.as_ref().or_else(|| none_match.as_ref()).is_none() {
        return false;
    }

    let mut success = true;

    modified_since.and_then(|modified_since| {
        parse_http_date(&modified_since).map_err(|_| { success = false; }).ok()
    }).map(|parsed| {
        success = success && is_modified_since(parsed, res);
    });

    none_match.map(|none_match| {
        success = success && etag_matches(&none_match, res);
    });

    success
}

fn etag_matches(none_match: &str, res: &conduit::Response) -> bool {
    res.headers.get("ETag").map(|etag| {
        res_header_val(etag) == none_match
    }).unwrap_or(false)
}

fn is_modified_since(modified_since: Tm, res: &conduit::Response) -> bool {
    res.headers.get("Last-Modified").and_then(|last_modified| {
        parse_http_date(&res_header_val(last_modified)).ok()
    }).map(|last_modified| {
        modified_since.to_timespec() >= last_modified.to_timespec()
    }).unwrap_or(false)
}

fn header_val<'a>(header: Vec<&'a str>) -> Cow<'a, str> {
    if header.len() == 1 {
        Cow::Borrowed(header[0])
    } else {
        Cow::Owned(header.concat())
    }
}

fn res_header_val<'a>(header: &'a Vec<String>) -> Cow<'a, str> {
    if header.len() == 1 {
        Cow::Borrowed(&header[0])
    } else {
        Cow::Owned(header.concat())
    }
}

fn parse_http_date(string: &str) -> Result<Tm, ()> {
    parse_rfc1123(string)
        .or_else(|_| parse_rfc850(string))
        .or_else(|_| parse_asctime(string))
        .map_err(|_| ())
}

fn parse_rfc1123(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d %b %Y %T GMT")
}

fn parse_rfc850(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d-%m-%y %T GMT")
}

fn parse_asctime(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a %m%t%d %T %Y")
}

#[cfg(test)]
mod tests {
    extern crate conduit_test as test;

    use std::collections::HashMap;
    use std::error::Error;
    use std::io::Cursor;
    use time;
    use time::Tm;
    use conduit::{Request, Response, Handler, Method};
    use middleware::MiddlewareBuilder;

    use super::ConditionalGet;

    macro_rules! returning {
        ($code:expr, $($header:expr => $value:expr),+) => ({
            let mut headers = HashMap::new();
            $(headers.insert($header.to_string(), vec!($value.to_string()));)+
            let handler = SimpleHandler::new(headers, $code, "hello");
            let mut stack = MiddlewareBuilder::new(handler);
            stack.add(ConditionalGet);
            stack
        });
        ($($header:expr => $value:expr),+) => ({
            returning!((200, "OK"), $($header => $value),+)
        })
    }

    macro_rules! request {
        ($($header:expr => $value:expr),+) => ({
            let mut req = test::MockRequest::new(Method::Get, "/");
            $(req.header($header, &$value.to_string());)+
            req
        })
    }

    #[test]
    fn test_sends_304() {
        let handler = returning!("Last-Modified" => httpdate(time::now()));
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        )));
    }

    #[test]
    fn test_sends_304_if_older_than_now() {
        let handler = returning!("Last-Modified" => before_now());
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        )));
    }

    #[test]
    fn test_sends_304_with_etag() {
        let handler = returning!("ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-None-Match" => "1234"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_time_but_not_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "4321"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_etag_but_not_time() {
        let handler = returning!("Last-Modified" => now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now(),
            "If-None-Match" => "1234"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_etag() {
        let handler = returning!("ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-None-Match" => "4321"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_time() {
        let handler = returning!("Last-Modified" => now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now()
        )));
    }

    #[test]
    fn test_sends_304_with_fresh_time_and_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        )));
    }

    #[test]
    fn test_does_not_affect_non_200() {
        let code = (302, "Found");
        let handler = returning!(code, "Last-Modified" => before_now(), "ETag" => "1234");
        expect(code, handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        )));
    }

    #[test]
    fn test_does_not_affect_malformed_timestamp() {
        let bad_stamp = time::now().strftime("%Y-%m-%d %H:%M:%S %z").unwrap().to_string();
        let handler = returning!("Last-Modified" => before_now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => bad_stamp
        )));
    }

    fn expect_304(response: Result<Response, Box<Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let mut body = Vec::new();
        response.body.write_body(&mut body).ok().expect("No body");

        assert_eq!(response.status, (304, "Not Modified"));
        assert_eq!(body, b"");
    }

    fn expect_200(response: Result<Response, Box<Error+Send>>) {
        expect((200, "OK"), response);
    }

    fn expect(status: (u32, &'static str), response: Result<Response, Box<Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let mut body = Vec::new();
        response.body.write_body(&mut body).ok().expect("No body");

        assert_eq!(response.status, status);
        assert_eq!(body, b"hello");
    }

    struct SimpleHandler {
        map: HashMap<String, Vec<String>>,
        status: Status,
        body: &'static str
    }

    type Status = (u32, &'static str);

    impl SimpleHandler {
        fn new(map: HashMap<String, Vec<String>>, status: Status, body: &'static str) -> SimpleHandler {
            SimpleHandler { map: map, status: status, body: body }
        }
    }

    impl Handler for SimpleHandler {
        fn call(&self, _: &mut Request) -> Result<Response, Box<Error+Send>> {
            Ok(Response {
                status: self.status,
                headers: self.map.clone(),
                body: Box::new(Cursor::new(self.body.to_string().into_bytes())),
            })
        }
    }

    fn before_now() -> String {
        let mut now = time::now();
        now.tm_year -= 1;
        httpdate(now)
    }

    fn now() -> String {
        httpdate(time::now())
    }

    fn httpdate(time: Tm) -> String {
        time.strftime("%a, %d-%m-%y %T GMT").unwrap().to_string()
    }
}
<commit_msg>Add dyn keyword to address warnings<commit_after>#![cfg_attr(test, deny(warnings))]

extern crate time;
extern crate conduit;
extern crate conduit_middleware as middleware;

use conduit::{Request, Method};
use middleware::Middleware;
use std::borrow::Cow;
use std::error::Error;
use std::io;
use time::{Tm, ParseError};

pub type Response = Result<conduit::Response, Box<dyn Error+Send>>;

#[allow(missing_copy_implementations)]
pub struct ConditionalGet;

impl Middleware for ConditionalGet {
    fn after(&self, req: &mut dyn Request, res: Response) -> Response {
        let mut res = try!(res);

        match req.method() {
            Method::Get | Method::Head => {
                if is_ok(&res) && is_fresh(req, &res) {
                    res.status = (304, "Not Modified");
                    res.headers.remove("Content-Type");
                    res.headers.remove("Content-Length");
                    res.body = Box::new(io::empty());
                }
            },
            _ => ()
        }

        Ok(res)
    }
}

fn is_ok(response: &conduit::Response) -> bool {
    match *response {
        conduit::Response { status: (200, _), .. } => true,
        _ => false
    }
}

fn is_fresh(req: &dyn Request, res: &conduit::Response) -> bool {
    let modified_since = req.headers().find("If-Modified-Since").map(header_val);
    let none_match     = req.headers().find("If-None-Match").map(header_val);

    if modified_since.as_ref().or_else(|| none_match.as_ref()).is_none() {
        return false;
    }

    let mut success = true;

    modified_since.and_then(|modified_since| {
        parse_http_date(&modified_since).map_err(|_| { success = false; }).ok()
    }).map(|parsed| {
        success = success && is_modified_since(parsed, res);
    });

    none_match.map(|none_match| {
        success = success && etag_matches(&none_match, res);
    });

    success
}

fn etag_matches(none_match: &str, res: &conduit::Response) -> bool {
    res.headers.get("ETag").map(|etag| {
        res_header_val(etag) == none_match
    }).unwrap_or(false)
}

fn is_modified_since(modified_since: Tm, res: &conduit::Response) -> bool {
    res.headers.get("Last-Modified").and_then(|last_modified| {
        parse_http_date(&res_header_val(last_modified)).ok()
    }).map(|last_modified| {
        modified_since.to_timespec() >= last_modified.to_timespec()
    }).unwrap_or(false)
}

fn header_val<'a>(header: Vec<&'a str>) -> Cow<'a, str> {
    if header.len() == 1 {
        Cow::Borrowed(header[0])
    } else {
        Cow::Owned(header.concat())
    }
}

fn res_header_val<'a>(header: &'a Vec<String>) -> Cow<'a, str> {
    if header.len() == 1 {
        Cow::Borrowed(&header[0])
    } else {
        Cow::Owned(header.concat())
    }
}

fn parse_http_date(string: &str) -> Result<Tm, ()> {
    parse_rfc1123(string)
        .or_else(|_| parse_rfc850(string))
        .or_else(|_| parse_asctime(string))
        .map_err(|_| ())
}

fn parse_rfc1123(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d %b %Y %T GMT")
}

fn parse_rfc850(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a, %d-%m-%y %T GMT")
}

fn parse_asctime(string: &str) -> Result<Tm, ParseError> {
    time::strptime(string, "%a %m%t%d %T %Y")
}

#[cfg(test)]
mod tests {
    extern crate conduit_test as test;

    use std::collections::HashMap;
    use std::error::Error;
    use std::io::Cursor;
    use time;
    use time::Tm;
    use conduit::{Request, Response, Handler, Method};
    use middleware::MiddlewareBuilder;

    use super::ConditionalGet;

    macro_rules! returning {
        ($code:expr, $($header:expr => $value:expr),+) => ({
            let mut headers = HashMap::new();
            $(headers.insert($header.to_string(), vec!($value.to_string()));)+
            let handler = SimpleHandler::new(headers, $code, "hello");
            let mut stack = MiddlewareBuilder::new(handler);
            stack.add(ConditionalGet);
            stack
        });
        ($($header:expr => $value:expr),+) => ({
            returning!((200, "OK"), $($header => $value),+)
        })
    }

    macro_rules! request {
        ($($header:expr => $value:expr),+) => ({
            let mut req = test::MockRequest::new(Method::Get, "/");
            $(req.header($header, &$value.to_string());)+
            req
        })
    }

    #[test]
    fn test_sends_304() {
        let handler = returning!("Last-Modified" => httpdate(time::now()));
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        )));
    }

    #[test]
    fn test_sends_304_if_older_than_now() {
        let handler = returning!("Last-Modified" => before_now());
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => httpdate(time::now())
        )));
    }

    #[test]
    fn test_sends_304_with_etag() {
        let handler = returning!("ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-None-Match" => "1234"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_time_but_not_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "4321"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_etag_but_not_time() {
        let handler = returning!("Last-Modified" => now(), "ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now(),
            "If-None-Match" => "1234"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_etag() {
        let handler = returning!("ETag" => "1234");
        expect_200(handler.call(&mut request!(
            "If-None-Match" => "4321"
        )));
    }

    #[test]
    fn test_sends_200_with_fresh_time() {
        let handler = returning!("Last-Modified" => now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => before_now()
        )));
    }

    #[test]
    fn test_sends_304_with_fresh_time_and_etag() {
        let handler = returning!("Last-Modified" => before_now(), "ETag" => "1234");
        expect_304(handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        )));
    }

    #[test]
    fn test_does_not_affect_non_200() {
        let code = (302, "Found");
        let handler = returning!(code, "Last-Modified" => before_now(), "ETag" => "1234");
        expect(code, handler.call(&mut request!(
            "If-Modified-Since" => now(),
            "If-None-Match" => "1234"
        )));
    }

    #[test]
    fn test_does_not_affect_malformed_timestamp() {
        let bad_stamp = time::now().strftime("%Y-%m-%d %H:%M:%S %z").unwrap().to_string();
        let handler = returning!("Last-Modified" => before_now());
        expect_200(handler.call(&mut request!(
            "If-Modified-Since" => bad_stamp
        )));
    }

    fn expect_304(response: Result<Response, Box<dyn Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let mut body = Vec::new();
        response.body.write_body(&mut body).ok().expect("No body");

        assert_eq!(response.status, (304, "Not Modified"));
        assert_eq!(body, b"");
    }

    fn expect_200(response: Result<Response, Box<dyn Error+Send>>) {
        expect((200, "OK"), response);
    }

    fn expect(status: (u32, &'static str), response: Result<Response, Box<dyn Error+Send>>) {
        let mut response = response.ok().expect("No response");
        let mut body = Vec::new();
        response.body.write_body(&mut body).ok().expect("No body");

        assert_eq!(response.status, status);
        assert_eq!(body, b"hello");
    }

    struct SimpleHandler {
        map: HashMap<String, Vec<String>>,
        status: Status,
        body: &'static str
    }

    type Status = (u32, &'static str);

    impl SimpleHandler {
        fn new(map: HashMap<String, Vec<String>>, status: Status, body: &'static str) -> SimpleHandler {
            SimpleHandler { map: map, status: status, body: body }
        }
    }

    impl Handler for SimpleHandler {
        fn call(&self, _: &mut dyn Request) -> Result<Response, Box<dyn Error+Send>> {
            Ok(Response {
                status: self.status,
                headers: self.map.clone(),
                body: Box::new(Cursor::new(self.body.to_string().into_bytes())),
            })
        }
    }

    fn before_now() -> String {
        let mut now = time::now();
        now.tm_year -= 1;
        httpdate(now)
    }

    fn now() -> String {
        httpdate(time::now())
    }

    fn httpdate(time: Tm) -> String {
        time.strftime("%a, %d-%m-%y %T GMT").unwrap().to_string()
    }
}
<|endoftext|>


<commit_before>extern crate num_cpus;
extern crate rustc_serialize;
extern crate threadpool;
extern crate time;
extern crate tiny_http;
extern crate url;

pub use assets::match_assets;
pub use log::LogEntry;

use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::thread;
use threadpool::ThreadPool;

pub mod input;

mod assets;
mod log;
mod router;

/// An error that one of your routes can return.
///
/// This is just a convenience enum and you don't need to use it in your project
/// if you don't want to.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RouteError {
    /// Couldn't find a way to handle this request.
    NoRouteFound,

    /// The user input is wrong.
    WrongInput,

    /// The user must be logged in.
    LoginRequired,

    /// The user entered a wrong login or password.
    WrongLoginPassword,

    /// The user is logged in but shouldn't be there.
    NotAuthorized,
}

/// Starts a server and uses the given requests handler.
///
/// The request handler takes a `&Request` and must return a `Response` to send to the user.
///
/// # Common mistakes
///
/// The handler must capture its environment by value and not by reference (`'static`). If you
/// use closure, don't forget to put `move` in front of the closure.
///
/// The handler must also be thread-safe (`Send` and `Sync`).
/// For example this handler isn't thread-safe:
///
/// ```ignore
/// let mut requests_counter = 0;
///
/// rouille::start_server("localhost:80", move |request| {
///     requests_counter += 1;
///
///     // rest of the handler
/// })
/// ```
///
/// Multiple requests can be processed simultaneously, therefore you can't mutably access
/// variables from the outside.
///
/// Instead you must use a `Mutex`:
///
/// ```no_run
/// use std::sync::Mutex;
/// let requests_counter = Mutex::new(0);
///
/// rouille::start_server("localhost:80", move |request| {
///     *requests_counter.lock().unwrap() += 1;
///
///     // rest of the handler
/// # panic!()
/// })
/// ```
///
/// # Panic handling
///
/// If your request handler panicks, a 500 error will automatically be sent to the client.
///
pub fn start_server<A, F>(addr: A, handler: F) -> !
                          where A: ToSocketAddrs,
                                F: Send + Sync + 'static + Fn(&Request) -> Response
{
    // FIXME: directly pass `addr` to the `TcpListener`
    let port = addr.to_socket_addrs().unwrap().next().unwrap().port();
    let server = tiny_http::ServerBuilder::new().with_port(port).build().unwrap();

    let handler = Arc::new(handler);
    let pool = ThreadPool::new(num_cpus::get());

    loop {
        let request = server.recv().unwrap();

        let request = Request {
            url: request.url().to_owned(),
            method: request.method().as_str().to_owned(),
            request: Mutex::new(Some(request)),
            data: Mutex::new(None),
        };

        let handler = handler.clone();

        pool.execute(move || {
            let response = (*handler)(&request);
            request.request.lock().unwrap().take().unwrap().respond(response.response);
        });
    }
}

/// Represents a request made by the client.
pub struct Request {
    url: String,
    method: String,
    request: Mutex<Option<tiny_http::Request>>,     // TODO: when Mutex gets "into_inner", remove the Option
    data: Mutex<Option<Vec<u8>>>,
}

impl Request {
    /// Returns the method of the request (`GET`, `POST`, etc.).
    #[inline]
    pub fn method(&self) -> &str {
        &self.method
    }

    /// Returns the URL requested by the client. It is not decoded and thus can contain `%20` or
    /// other characters.
    #[inline]
    pub fn url(&self) -> &str {
        &self.url
    }

    /// Returns the value of a header of the request.
    #[inline]
    pub fn header(&self, key: &str) -> Option<String> {
        self.request.lock().unwrap().as_ref().unwrap().headers().iter()
                    .find(|h| h.field.as_str() == key).map(|h| h.value.as_str().to_owned())
    }

    /// Returns the data of the request.
    pub fn data(&self) -> Vec<u8> {
        let mut data = self.data.lock().unwrap();

        if let Some(ref mut data) = *data {
            return data.clone();
        }

        let mut read = Vec::new();
        let _ = self.request.lock().unwrap().as_mut().unwrap()
                            .as_reader().read_to_end(&mut read);
        let read_clone = read.clone();
        *data = Some(read);
        read_clone
    }
}

/// Contains a prototype of a response. The response is only sent when you call `Request::respond`.
pub struct Response {
    response: tiny_http::ResponseBox,
}

impl Response {
    /// UNSTABLE. Builds a default response to handle the given route error.
    ///
    /// Important: don't use this in a real website. This function is just a convenience when
    /// prototyping.
    ///
    /// For authentication-related errors, you are strongly encouraged to handle them yourself.
    #[inline]
    pub fn from_error(err: &RouteError) -> Response {
        let response = match err {
            &RouteError::NoRouteFound => tiny_http::Response::empty(404),
            &RouteError::WrongInput => tiny_http::Response::empty(400),
            &RouteError::LoginRequired => tiny_http::Response::empty(401),     // TODO: www-auth header?
            &RouteError::WrongLoginPassword => tiny_http::Response::empty(401),     // TODO: www-auth header?
            &RouteError::NotAuthorized => tiny_http::Response::empty(403),
        };

        Response { response: response.boxed() }
    }

    /// Builds a `Response` that redirects the user to another URL.
    #[inline]
    pub fn redirect(target: &str) -> Response {
        let response = tiny_http::Response::empty(303);
        // TODO: slow \|/
        let response = response.with_header(tiny_http::Header::from_str(&format!("Location: {}", target)).unwrap());

        Response { response: response.boxed() }
    }

    /// Builds a `Response` that outputs HTML.
    #[inline]
    pub fn html(content: &[u8]) -> Response {
        let response = tiny_http::Response::from_data(content);
        // TODO: slow \|/
        let response = response.with_header(tiny_http::Header::from_str("Content-Type: text/html; charset=utf8").unwrap());

        Response { response: response.boxed() }
    }

    /// Builds a `Response` that outputs JSON.
    #[inline]
    pub fn json<T>(content: &T) -> Response where T: rustc_serialize::Encodable {
        let data = rustc_serialize::json::encode(content).unwrap();
        let response = tiny_http::Response::from_string(data);
        // TODO: slow \|/
        let response = response.with_header(tiny_http::Header::from_str("Content-Type: application/json").unwrap());

        Response { response: response.boxed() }
    }

    /// Builds a `Response` that returns a `401 Not Authorized` status
    /// and a `WWW-Authenticate` header.
    #[inline]
    pub fn basic_http_auth_login_required(realm: &str) -> Response {
        // TODO: escape the realm
        let response = tiny_http::Response::empty(401);
        // TODO: slow \|/
        let response = response.with_header(tiny_http::Header::from_str(&format!("WWW-Authenticate: Basic realm=\"{}\"", realm)).unwrap());

        Response { response: response.boxed() }
    }
}
<commit_msg>Add fake requests<commit_after>extern crate num_cpus;
extern crate rustc_serialize;
extern crate threadpool;
extern crate time;
extern crate tiny_http;
extern crate url;

pub use assets::match_assets;
pub use log::LogEntry;

use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::thread;
use threadpool::ThreadPool;

pub mod input;

mod assets;
mod log;
mod router;

/// An error that one of your routes can return.
///
/// This is just a convenience enum and you don't need to use it in your project
/// if you don't want to.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RouteError {
    /// Couldn't find a way to handle this request.
    NoRouteFound,

    /// The user input is wrong.
    WrongInput,

    /// The user must be logged in.
    LoginRequired,

    /// The user entered a wrong login or password.
    WrongLoginPassword,

    /// The user is logged in but shouldn't be there.
    NotAuthorized,
}

/// Starts a server and uses the given requests handler.
///
/// The request handler takes a `&Request` and must return a `Response` to send to the user.
///
/// # Common mistakes
///
/// The handler must capture its environment by value and not by reference (`'static`). If you
/// use closure, don't forget to put `move` in front of the closure.
///
/// The handler must also be thread-safe (`Send` and `Sync`).
/// For example this handler isn't thread-safe:
///
/// ```ignore
/// let mut requests_counter = 0;
///
/// rouille::start_server("localhost:80", move |request| {
///     requests_counter += 1;
///
///     // rest of the handler
/// })
/// ```
///
/// Multiple requests can be processed simultaneously, therefore you can't mutably access
/// variables from the outside.
///
/// Instead you must use a `Mutex`:
///
/// ```no_run
/// use std::sync::Mutex;
/// let requests_counter = Mutex::new(0);
///
/// rouille::start_server("localhost:80", move |request| {
///     *requests_counter.lock().unwrap() += 1;
///
///     // rest of the handler
/// # panic!()
/// })
/// ```
///
/// # Panic handling
///
/// If your request handler panicks, a 500 error will automatically be sent to the client.
///
pub fn start_server<A, F>(addr: A, handler: F) -> !
                          where A: ToSocketAddrs,
                                F: Send + Sync + 'static + Fn(&Request) -> Response
{
    // FIXME: directly pass `addr` to the `TcpListener`
    let port = addr.to_socket_addrs().unwrap().next().unwrap().port();
    let server = tiny_http::ServerBuilder::new().with_port(port).build().unwrap();

    let handler = Arc::new(handler);
    let pool = ThreadPool::new(num_cpus::get());

    loop {
        let request = server.recv().unwrap();

        let request = Request {
            url: request.url().to_owned(),
            method: request.method().as_str().to_owned(),
            data: Mutex::new(None),
            inner: RequestImpl::Real(Mutex::new(Some(request))),
        };

        let handler = handler.clone();

        pool.execute(move || {
            let response = (*handler)(&request);
            match request.inner {
                RequestImpl::Real(rq) => rq.lock().unwrap().take().unwrap()
                                           .respond(response.response),
                RequestImpl::Fake { .. } => unreachable!()
            }
        });
    }
}

/// Represents a request made by the client.
pub struct Request {
    url: String,
    method: String,
    data: Mutex<Option<Vec<u8>>>,
    inner: RequestImpl,
}

enum RequestImpl {
    Real(Mutex<Option<tiny_http::Request>>),     // TODO: when Mutex gets "into_inner", remove the Option
    Fake { headers: Vec<(String, String)> },
}

impl Request {
    /// Builds a fake request to be used during tests.
    pub fn fake(url: String, method: String, headers: Vec<(String, String)>, data: Vec<u8>)
                -> Request
    {
        Request {
            url: url,
            method: method,
            data: Mutex::new(Some(data)),
            inner: RequestImpl::Fake { headers: headers },
        }
    }

    /// Returns the method of the request (`GET`, `POST`, etc.).
    #[inline]
    pub fn method(&self) -> &str {
        &self.method
    }

    /// Returns the URL requested by the client. It is not decoded and thus can contain `%20` or
    /// other characters.
    #[inline]
    pub fn url(&self) -> &str {
        &self.url
    }

    /// Returns the value of a header of the request.
    #[inline]
    pub fn header(&self, key: &str) -> Option<String> {
        match self.inner {
            RequestImpl::Real(ref request) => request.lock().unwrap().as_ref().unwrap().headers()
                                                     .iter().find(|h| h.field.as_str() == key)
                                                     .map(|h| h.value.as_str().to_owned()),

            RequestImpl::Fake { ref headers } => headers.iter().find(|&&(ref k, _)| k == key)
                                                        .map(|&(_, ref v)| v.clone())
        }
    }

    /// Returns the data of the request.
    pub fn data(&self) -> Vec<u8> {
        let mut data = self.data.lock().unwrap();

        if let Some(ref mut data) = *data {
            return data.clone();
        }

        let mut read = Vec::new();
        match self.inner {
            RequestImpl::Real(ref request) => {
                let _ = request.lock().unwrap().as_mut().unwrap()
                               .as_reader().read_to_end(&mut read);
            },
            RequestImpl::Fake { .. } => ()
        };
        let read_clone = read.clone();
        *data = Some(read);
        read_clone
    }
}

/// Contains a prototype of a response. The response is only sent when you call `Request::respond`.
pub struct Response {
    response: tiny_http::ResponseBox,
}

impl Response {
    /// UNSTABLE. Builds a default response to handle the given route error.
    ///
    /// Important: don't use this in a real website. This function is just a convenience when
    /// prototyping.
    ///
    /// For authentication-related errors, you are strongly encouraged to handle them yourself.
    #[inline]
    pub fn from_error(err: &RouteError) -> Response {
        let response = match err {
            &RouteError::NoRouteFound => tiny_http::Response::empty(404),
            &RouteError::WrongInput => tiny_http::Response::empty(400),
            &RouteError::LoginRequired => tiny_http::Response::empty(401),     // TODO: www-auth header?
            &RouteError::WrongLoginPassword => tiny_http::Response::empty(401),     // TODO: www-auth header?
            &RouteError::NotAuthorized => tiny_http::Response::empty(403),
        };

        Response { response: response.boxed() }
    }

    /// Builds a `Response` that redirects the user to another URL.
    #[inline]
    pub fn redirect(target: &str) -> Response {
        let response = tiny_http::Response::empty(303);
        // TODO: slow \|/
        let response = response.with_header(tiny_http::Header::from_str(&format!("Location: {}", target)).unwrap());

        Response { response: response.boxed() }
    }

    /// Builds a `Response` that outputs HTML.
    #[inline]
    pub fn html(content: &[u8]) -> Response {
        let response = tiny_http::Response::from_data(content);
        // TODO: slow \|/
        let response = response.with_header(tiny_http::Header::from_str("Content-Type: text/html; charset=utf8").unwrap());

        Response { response: response.boxed() }
    }

    /// Builds a `Response` that outputs JSON.
    #[inline]
    pub fn json<T>(content: &T) -> Response where T: rustc_serialize::Encodable {
        let data = rustc_serialize::json::encode(content).unwrap();
        let response = tiny_http::Response::from_string(data);
        // TODO: slow \|/
        let response = response.with_header(tiny_http::Header::from_str("Content-Type: application/json").unwrap());

        Response { response: response.boxed() }
    }

    /// Builds a `Response` that returns a `401 Not Authorized` status
    /// and a `WWW-Authenticate` header.
    #[inline]
    pub fn basic_http_auth_login_required(realm: &str) -> Response {
        // TODO: escape the realm
        let response = tiny_http::Response::empty(401);
        // TODO: slow \|/
        let response = response.with_header(tiny_http::Header::from_str(&format!("WWW-Authenticate: Basic realm=\"{}\"", realm)).unwrap());

        Response { response: response.boxed() }
    }
}
<|endoftext|>


<commit_before>//! A contiguous region of bytes, useful for I/O operations.
//!
//! An Iobuf consists of:
//!
//!   - a buffer
//!   - limits   (a subrange of the buffer)
//!   - a window (a subrange of the limits)
//!
//! All iobuf operations are restricted to operate within the limits. Initially,
//! the window of an Iobuf is identical to the limits. If you have an `&mut` to
//! an Iobuf, you may change the window and limits. If you only have a `&`, you
//! may not. Similarly, if you have a `RWIobuf`, you may modify the data in the
//! buffer. If you have a `ROIobuf`, you may not.
//!
//! The limits can be `narrow`ed, but never widened. The window may be set to
//! any arbitrary subrange of the limits.
//!
//! Iobufs are cheap to `clone`, since the buffers are refcounted. Use this to
//! construct multiple views into the same data.
//!
//! To keep the struct small (24 bytes!), the maximum size of an Iobuf is 2 GB.
//! Please let me know if you need more than this. I have never before seen a
//! use case for Iobufs larger than 2 GB, and it gives us a 40% smaller struct
//! compared to supporting INT64_MAX bytes. The improved size allows much better
//! register/cache usage and faster moves, both of which are critical for
//! performance.
//!
//! Although this library is designed for efficiency, and hence gives you lots
//! of ways to omit bounds checks, that does not mean it's recommended you do.
//! They merely provide a way for you to manually bounds check a whole bunch
//! of data at once (with `check_range`), and then `peek` or `poke` out the data
//! you want. See the documentation for `check_range` for an example.
//!
//! To repeat: Do not omit bounds checks unless you've checked _very_ carefully
//! that they are redundant. This can cause terrifying security issues.

#![doc(html_root_url = "http://www.rust-ci.org/cgaebel/iobuf/doc/iobuf/")]

#![feature(slicing_syntax)]
#![feature(unsafe_destructor)]
#![allow(unstable)]
#![deny(missing_docs)]

extern crate alloc;
#[cfg(test)] extern crate test;
//#[cfg(test)] extern crate quickcheck;

pub use raw::Allocator;
pub use iobuf::Iobuf;
pub use impls::{RWIobuf, ROIobuf, AROIobuf, UniqueIobuf};
pub use ringbuf::IORingbuf;
pub use bufspan::{BufSpan, ByteIter, SpanIter, SpanMoveIter};
pub use appendbuf::AppendBuf;

mod raw;
mod iobuf;
mod impls;
mod ringbuf;
mod bufspan;
mod appendbuf;
<commit_msg>rustup<commit_after>//! A contiguous region of bytes, useful for I/O operations.
//!
//! An Iobuf consists of:
//!
//!   - a buffer
//!   - limits   (a subrange of the buffer)
//!   - a window (a subrange of the limits)
//!
//! All iobuf operations are restricted to operate within the limits. Initially,
//! the window of an Iobuf is identical to the limits. If you have an `&mut` to
//! an Iobuf, you may change the window and limits. If you only have a `&`, you
//! may not. Similarly, if you have a `RWIobuf`, you may modify the data in the
//! buffer. If you have a `ROIobuf`, you may not.
//!
//! The limits can be `narrow`ed, but never widened. The window may be set to
//! any arbitrary subrange of the limits.
//!
//! Iobufs are cheap to `clone`, since the buffers are refcounted. Use this to
//! construct multiple views into the same data.
//!
//! To keep the struct small (24 bytes!), the maximum size of an Iobuf is 2 GB.
//! Please let me know if you need more than this. I have never before seen a
//! use case for Iobufs larger than 2 GB, and it gives us a 40% smaller struct
//! compared to supporting INT64_MAX bytes. The improved size allows much better
//! register/cache usage and faster moves, both of which are critical for
//! performance.
//!
//! Although this library is designed for efficiency, and hence gives you lots
//! of ways to omit bounds checks, that does not mean it's recommended you do.
//! They merely provide a way for you to manually bounds check a whole bunch
//! of data at once (with `check_range`), and then `peek` or `poke` out the data
//! you want. See the documentation for `check_range` for an example.
//!
//! To repeat: Do not omit bounds checks unless you've checked _very_ carefully
//! that they are redundant. This can cause terrifying security issues.

#![doc(html_root_url = "http://www.rust-ci.org/cgaebel/iobuf/doc/iobuf/")]

#![feature(slicing_syntax)]
#![feature(unsafe_destructor)]
#![feature(alloc)]
#![feature(core)]
#![feature(test)]

#![deny(missing_docs)]
#![allow(unused_features)]

extern crate alloc;
#[cfg(test)] extern crate test;
//#[cfg(test)] extern crate quickcheck;

pub use raw::Allocator;
pub use iobuf::Iobuf;
pub use impls::{RWIobuf, ROIobuf, AROIobuf, UniqueIobuf};
pub use ringbuf::IORingbuf;
pub use bufspan::{BufSpan, ByteIter, SpanIter, SpanMoveIter};
pub use appendbuf::AppendBuf;

mod raw;
mod iobuf;
mod impls;
mod ringbuf;
mod bufspan;
mod appendbuf;
<|endoftext|>


<commit_before>extern crate pencil;
#[macro_use] extern crate hyper;
extern crate crypto;

use std::io::Read;
use crypto::hmac::Hmac;
use crypto::sha2::Sha256;
use crypto::mac::{Mac, MacResult};
use hyper::header::Headers;
use pencil::Request;

header! { (XGitHubEvent, "X-GitHub-Event") => [String] }
header! { (XGitHubDelivery, "X-GitHub-Delivery") => [String] }
header! { (XHubSignature, "X-Hub-Signature") => [String] }

pub fn check_signature(request: &mut Request, signature: &XHubSignature, secret: &str) -> bool {
  let mut bytes: Vec<u8> = Vec::new();
  request.read_to_end(&mut bytes);
  let mut hmac = Hmac::new(Sha256::new(), secret.as_bytes());
  hmac.input(&bytes);
  let result = hmac.result();
  let check_against = MacResult::new(signature.as_bytes());
  result == check_against
}
<commit_msg>fix(hmac): make hmac checking actually work<commit_after>extern crate pencil;
#[macro_use] extern crate hyper;
extern crate crypto;

use std::io::Read;
use crypto::hmac::Hmac;
use crypto::sha1::Sha1;
use crypto::mac::{Mac, MacResult};
use hyper::header::Headers;
use pencil::Request;

header! { (XGitHubEvent, "X-GitHub-Event") => [String] }
header! { (XGitHubDelivery, "X-GitHub-Delivery") => [String] }
header! { (XHubSignature, "X-Hub-Signature") => [String] }

pub fn check_signature(request: &mut Request, signature: &XHubSignature, secret: &str) -> bool {
  let (method, hash) = {
    let mut split = signature.split('=');
    (split.next().unwrap(), split.next().unwrap())
  };
  if method != "sha1" {
    return false;
  }
  let hash = hex_string_to_bytes(hash);
  let mut bytes: Vec<u8> = Vec::new();
  request.read_to_end(&mut bytes);
  let result = build_sha1_hmac(secret, &bytes).result();
  let check_against = MacResult::new(&hash);
  result == check_against
}

fn build_sha1_hmac(secret: &str, input: &[u8]) -> Hmac<Sha1> {
  let mut hmac = Hmac::new(Sha1::new(), secret.as_bytes());
  hmac.input(input);
  hmac
}

pub fn hex_string_to_bytes(hex_string: &str) -> Vec<u8> {
  let char_vec = hex_string.chars().collect::<Vec<_>>();
  let chunks = char_vec.chunks(2);
  chunks
    .map(|x| u8::from_str_radix(
        x.into_iter().cloned().collect::<String>().as_str(),
        16
      ).unwrap()
    )
    .collect::<Vec<_>>()
}
<|endoftext|>


<commit_before>//! A library for interacting with Twitter.
//!
//! Please see [the repository][] and its enclosed examples for tips on working with this library
//! while it's still in progress.
//!
//! [the repository]: https://github.com/QuietMisdreavus/twitter-rs
//!
//! ## Getting Started
//!
//! The very first thing you'll need to do to get access to the Twitter API is to head to
//! [Twitter's Application Manager][twitter-apps] and create an app. Once you've done that, there
//! are two sets of keys immediately available to you. First are the "consumer key" and "consumer
//! secret", that are used to represent you as the application author when signing requests. These
//! keys are given to every single API call regardless of permission level. Related are an "access
//! token" and "access token secret", that can be used to skip the authentication steps if you're
//! only interacting with your own account or with no account in particular. Generally, if you want
//! to read or write to a particular user's stream, you'll need to request authorization and get an
//! access token to work on their behalf.
//!
//! [twitter-apps]: https://apps.twitter.com/
//!
//! The process to get an access token for a specific user (with this library) has three basic
//! steps:
//!
//! 1. Log your request with Twitter by getting a [request token][].
//! 2. Direct the user to grant permission to your application by sending them to an
//!    [authenticate][] or [authorize][] URL, depending on the nature of your app.
//! 3. Convert the verifier given by the permission request into an [access token][].
//!
//! [request token]: fn.request_token.html
//! [authorize]: fn.authorize_url.html
//! [authenticate]: fn.authenticate_url.html
//! [access token]: fn.access_token.html
//!
//! The process changes some smaller details depending on whether your application is web- or
//! mobile-based, as opposed to desktop-based or in another situation where redirecting users to a
//! web browser and back automatically is difficult or impossible. In the former case where URLs
//! can be used to direct the user into and out of your app, give Twitter a "callback URL" when
//! setting up your request token, and redirect the user to an [authenticate][] URL to grant your
//! app permissions. When the user accepts the request, they will be redirected back to this URL to
//! get back to your app, with the original request token and a verifier given to your app to
//! signify their acceptance.
//!
//! On the other hand, if you can't use the callback URL in this fashion, you can instead use the
//! "PIN-based Auth" version of the flow. In this version, give a "callback URL" of "oob" when
//! setting up your request token, and use an [authorize][] URL. When the user grants the
//! permissions request in this fashion, they are given a numeric PIN that can be given back to
//! your app to use as a verifier.
//!
//! Either way, when you have a "verifier" from either of these methods, you can use your Tokens
//! from earlier in the process with that verifier to request an [access token][]. This access
//! token can then be saved and cached for future use.
//!
//! ### Alternate method: Bearer tokens
//!
//! If your only use for the Twitter API is to look at public data - things like public tweet
//! searches, or viewing public user profiles - you may be interested in Application-only
//! authentication. App-only auth provides a much easier way to authenticate API calls, with the
//! restriction that the Bearer token it provides can only be used for calls that do not need a
//! user context. For example, calls like `tweet::home_timeline`, which act on behalf of the
//! authenticated user, will return an error if used with a Bearer token.
//!
//! If a Bearer token will work for your purposes, use the following steps to get a Token:
//!
//! 1. With the consumer key/secret obtained the same way as above, ask Twitter for the current
//!    [Bearer token] for your application.
//!
//! [Bearer token]: fn.bearer_token.html
//!
//! And... that's it! This Bearer token can be cached and saved for future use. It will not expire
//! until you ask Twitter to [invalidate] the token for you. Otherwise, this token can be used the
//! same way as the [access token] from earlier, but with the restrictions mentioned above.
//!
//! [invalidate]: fn.invalidate_token.html
//!
//! ## `Response<T>`
//!
//! Every method that calls Twitter and carries rate-limit information wraps its return value in a
//! [`Response`][] struct, that transmits this information to your app. From there, you can handle
//! the rate-limit information to hold off on that kind of request, or simply grab its `response`
//! field to get the output of whatever method you called.
//!
//! [`Response`]: struct.Response.html
//!
//! ## Modules
//!
//! As there are many actions available in the Twitter API, egg-mode divides them roughly into
//! several modules by their shared purpose. Here's a sort of high-level overview, in rough order
//! from "most important" to "less directly used":
//!
//! ### Primary actions
//!
//! These could be considered the "core" actions within the Twitter API that egg-mode has made
//! available.
//!
//! * `tweet`: This module lets you act on tweets. Here you can find actions to load a user's
//!   timeline, post a new tweet, or like and retweet individual posts.
//! * `user`: This module lets you act on users, be it by following or unfollowing them, loading
//!   their profile information, blocking or muting them, or showing the relationship between two
//!   users.
//! * `search`: Due to the complexity of searching for tweets, it gets its own module.
//! * `direct`: Here you can work with a user's Direct Messages, either by loading DMs they've sent
//!   or received, or by sending new ones.
//! * `text`: Text processing functions to count characters in new tweets and extract links and
//!   hashtags for highlighting and linking.
//!
//! ### Secondary actions
//!
//! These modules still contain direct actions for Twitter, but they can be considered as having
//! more of a helper role than something you might use directly.
//!
//! * `place`: Here are actions that look up physical locations that can be attached to tweets, as
//!   well at the `Place` struct that appears on tweets with locations attached.
//! * `service`: These are some miscellaneous methods that show information about the Twitter
//!   service as a whole, like loading the maximum length of t.co URLs or loading the current Terms
//!   of Service or Privacy Policy.
//!
//! ### Helper structs
//!
//! These modules contain some implementations that wrap some pattern seen in multiple "action"
//! modules.
//!
//! * `cursor`: This contains a helper trait and some helper structs that allow effective cursoring
//!   through certain collections of results from Twitter.
//! * `entities`: Whenever some text can be returned that may contain links, hashtags, media, or
//!   user mentions, its metadata is parsed into something that lives in this module.
//! * `error`: Any interaction with Twitter may result in an error condition, be it from finding a
//!   tweet or user that doesn't exist or the network connection being unavailable. All the error
//!   types are aggregated into an enum in this module.

#![warn(missing_docs)]
#![warn(unused_extern_crates)]
#![warn(unused_qualifications)]

#[macro_use] extern crate hyper;
#[macro_use] extern crate lazy_static;
extern crate url;
extern crate rand;
extern crate crypto;
extern crate rustc_serialize;
extern crate mime;
extern crate chrono;
extern crate regex;
extern crate unicode_normalization;

#[macro_use] mod common;
mod auth;
pub mod error;
pub mod user;
pub mod entities;
pub mod cursor;
pub mod tweet;
pub mod search;
pub mod place;
pub mod direct;
pub mod service;
pub mod text;
mod links;

pub use auth::{KeyPair, Token, request_token, authorize_url, authenticate_url,
               access_token, verify_tokens, bearer_token, invalidate_bearer};
pub use common::{Response, ResponseIter, ResponseIterRef, ResponseIterMut, WebResponse};
<commit_msg>fix link in docs<commit_after>//! A library for interacting with Twitter.
//!
//! Please see [the repository][] and its enclosed examples for tips on working with this library
//! while it's still in progress.
//!
//! [the repository]: https://github.com/QuietMisdreavus/twitter-rs
//!
//! ## Getting Started
//!
//! The very first thing you'll need to do to get access to the Twitter API is to head to
//! [Twitter's Application Manager][twitter-apps] and create an app. Once you've done that, there
//! are two sets of keys immediately available to you. First are the "consumer key" and "consumer
//! secret", that are used to represent you as the application author when signing requests. These
//! keys are given to every single API call regardless of permission level. Related are an "access
//! token" and "access token secret", that can be used to skip the authentication steps if you're
//! only interacting with your own account or with no account in particular. Generally, if you want
//! to read or write to a particular user's stream, you'll need to request authorization and get an
//! access token to work on their behalf.
//!
//! [twitter-apps]: https://apps.twitter.com/
//!
//! The process to get an access token for a specific user (with this library) has three basic
//! steps:
//!
//! 1. Log your request with Twitter by getting a [request token][].
//! 2. Direct the user to grant permission to your application by sending them to an
//!    [authenticate][] or [authorize][] URL, depending on the nature of your app.
//! 3. Convert the verifier given by the permission request into an [access token][].
//!
//! [request token]: fn.request_token.html
//! [authorize]: fn.authorize_url.html
//! [authenticate]: fn.authenticate_url.html
//! [access token]: fn.access_token.html
//!
//! The process changes some smaller details depending on whether your application is web- or
//! mobile-based, as opposed to desktop-based or in another situation where redirecting users to a
//! web browser and back automatically is difficult or impossible. In the former case where URLs
//! can be used to direct the user into and out of your app, give Twitter a "callback URL" when
//! setting up your request token, and redirect the user to an [authenticate][] URL to grant your
//! app permissions. When the user accepts the request, they will be redirected back to this URL to
//! get back to your app, with the original request token and a verifier given to your app to
//! signify their acceptance.
//!
//! On the other hand, if you can't use the callback URL in this fashion, you can instead use the
//! "PIN-based Auth" version of the flow. In this version, give a "callback URL" of "oob" when
//! setting up your request token, and use an [authorize][] URL. When the user grants the
//! permissions request in this fashion, they are given a numeric PIN that can be given back to
//! your app to use as a verifier.
//!
//! Either way, when you have a "verifier" from either of these methods, you can use your Tokens
//! from earlier in the process with that verifier to request an [access token][]. This access
//! token can then be saved and cached for future use.
//!
//! ### Alternate method: Bearer tokens
//!
//! If your only use for the Twitter API is to look at public data - things like public tweet
//! searches, or viewing public user profiles - you may be interested in Application-only
//! authentication. App-only auth provides a much easier way to authenticate API calls, with the
//! restriction that the Bearer token it provides can only be used for calls that do not need a
//! user context. For example, calls like `tweet::home_timeline`, which act on behalf of the
//! authenticated user, will return an error if used with a Bearer token.
//!
//! If a Bearer token will work for your purposes, use the following steps to get a Token:
//!
//! 1. With the consumer key/secret obtained the same way as above, ask Twitter for the current
//!    [Bearer token] for your application.
//!
//! [Bearer token]: fn.bearer_token.html
//!
//! And... that's it! This Bearer token can be cached and saved for future use. It will not expire
//! until you ask Twitter to [invalidate] the token for you. Otherwise, this token can be used the
//! same way as the [access token] from earlier, but with the restrictions mentioned above.
//!
//! [invalidate]: fn.invalidate_bearer.html
//!
//! ## `Response<T>`
//!
//! Every method that calls Twitter and carries rate-limit information wraps its return value in a
//! [`Response`][] struct, that transmits this information to your app. From there, you can handle
//! the rate-limit information to hold off on that kind of request, or simply grab its `response`
//! field to get the output of whatever method you called.
//!
//! [`Response`]: struct.Response.html
//!
//! ## Modules
//!
//! As there are many actions available in the Twitter API, egg-mode divides them roughly into
//! several modules by their shared purpose. Here's a sort of high-level overview, in rough order
//! from "most important" to "less directly used":
//!
//! ### Primary actions
//!
//! These could be considered the "core" actions within the Twitter API that egg-mode has made
//! available.
//!
//! * `tweet`: This module lets you act on tweets. Here you can find actions to load a user's
//!   timeline, post a new tweet, or like and retweet individual posts.
//! * `user`: This module lets you act on users, be it by following or unfollowing them, loading
//!   their profile information, blocking or muting them, or showing the relationship between two
//!   users.
//! * `search`: Due to the complexity of searching for tweets, it gets its own module.
//! * `direct`: Here you can work with a user's Direct Messages, either by loading DMs they've sent
//!   or received, or by sending new ones.
//! * `text`: Text processing functions to count characters in new tweets and extract links and
//!   hashtags for highlighting and linking.
//!
//! ### Secondary actions
//!
//! These modules still contain direct actions for Twitter, but they can be considered as having
//! more of a helper role than something you might use directly.
//!
//! * `place`: Here are actions that look up physical locations that can be attached to tweets, as
//!   well at the `Place` struct that appears on tweets with locations attached.
//! * `service`: These are some miscellaneous methods that show information about the Twitter
//!   service as a whole, like loading the maximum length of t.co URLs or loading the current Terms
//!   of Service or Privacy Policy.
//!
//! ### Helper structs
//!
//! These modules contain some implementations that wrap some pattern seen in multiple "action"
//! modules.
//!
//! * `cursor`: This contains a helper trait and some helper structs that allow effective cursoring
//!   through certain collections of results from Twitter.
//! * `entities`: Whenever some text can be returned that may contain links, hashtags, media, or
//!   user mentions, its metadata is parsed into something that lives in this module.
//! * `error`: Any interaction with Twitter may result in an error condition, be it from finding a
//!   tweet or user that doesn't exist or the network connection being unavailable. All the error
//!   types are aggregated into an enum in this module.

#![warn(missing_docs)]
#![warn(unused_extern_crates)]
#![warn(unused_qualifications)]

#[macro_use] extern crate hyper;
#[macro_use] extern crate lazy_static;
extern crate url;
extern crate rand;
extern crate crypto;
extern crate rustc_serialize;
extern crate mime;
extern crate chrono;
extern crate regex;
extern crate unicode_normalization;

#[macro_use] mod common;
mod auth;
pub mod error;
pub mod user;
pub mod entities;
pub mod cursor;
pub mod tweet;
pub mod search;
pub mod place;
pub mod direct;
pub mod service;
pub mod text;
mod links;

pub use auth::{KeyPair, Token, request_token, authorize_url, authenticate_url,
               access_token, verify_tokens, bearer_token, invalidate_bearer};
pub use common::{Response, ResponseIter, ResponseIterRef, ResponseIterMut, WebResponse};
<|endoftext|>


<commit_before>//! Library for manipulating Game Maker Studio's "data.win" (GEN8) data files.

#![feature(read_exact, associated_consts, associated_type_defaults)]
#![warn(missing_docs, trivial_casts, trivial_numeric_casts)]

#[macro_use]
extern crate quick_error;
extern crate byteorder;
#[macro_use]
extern crate log;

mod gamedata_io;

pub use gamedata_io::{ReadError, StringReadError};

use std::io::{self, Read, Write};
use std::path;

/// The data of a Game Maker Studio game.
///
/// This is the collective information acquired from "data.win".
pub struct GameData {
    metadata: MetaData,
    options: Options,
    extn: Extn,
    /// The sounds of the game.
    pub sounds: Sounds,
    audio_groups: Option<AudioGroups>,
    sprites: Sprites,
    backgrounds: Backgrounds,
    paths: Paths,
    scripts: Scripts,
    shaders: Shaders,
    /// The fonts of the game.
    pub fonts: Fonts,
    timelines: Timelines,
    objects: Objects,
    rooms: Rooms,
    dafl: Dafl,
    tpag: Tpag,
    code: Code,
    variables: Variables,
    functions: Functions,
    /// The strings of the game.
    pub strings: Strings,
    textures: Textures,
    audio: Audio,
}

/// A reader that satisfies the requirements for reading a GameData.
pub trait GameDataRead: Read + io::Seek {}
impl<T: Read + io::Seek> GameDataRead for T {}
/// A writer that satisfies the requirements for writing a GameData.
pub trait GameDataWrite: Write + io::Seek {}
impl<T: Write + io::Seek> GameDataWrite for T {}

impl GameData {
    /// Reads a GameData from a reader.
    pub fn from_reader<R: GameDataRead>(reader: &mut R) -> Result<GameData, ReadError> {
        gamedata_io::read(reader)
    }
    /// Reads a GameData from a file.
    pub fn from_file<P: AsRef<path::Path>>(path: &P) -> Result<GameData, ReadError> {
        use std::fs::File;
        use std::io::BufReader;
        let file = try!(File::open(path));
        GameData::from_reader(&mut BufReader::new(file))
    }
    /// Writes self to a writer.
    pub fn write_to_writer<W: GameDataWrite>(&self, writer: &mut W) -> io::Result<()> {
        gamedata_io::write(self, writer)
    }
    /// Writes self to a file.
    pub fn save_to_file<P: AsRef<path::Path>>(&self, path: &P) -> io::Result<()> {
        use std::fs::File;
        use std::io::BufWriter;
        let file = try!(File::create(path));
        self.write_to_writer(&mut BufWriter::new(file))
    }
    /// Returns the window width of the game.
    pub fn window_width(&self) -> u32 {
        self.metadata.window_width
    }
    /// Returns the window height of the game.
    pub fn window_height(&self) -> u32 {
        self.metadata.window_height
    }
    /// Sets the window dimensions of the game.
    pub fn set_window_dimensions(&mut self, width: u32, height: u32) {
        self.metadata.window_width = width;
        self.metadata.window_height = height;
    }
    /// Returns the window title of the game.
    pub fn window_title(&self) -> &str {
        &self.strings.strings[self.metadata.window_title_index]
    }
    /// Sets the window title of the game.
    pub fn set_window_title<S: Into<String>>(&mut self, new: S) {
        self.strings.strings[self.metadata.window_title_index] = new.into();
    }
}

/// Contains various metadata, for example, the window width/height/title.
struct MetaData {
    unk1: u32, // Purpose unknown
    game_id_1_index: usize, // Some kind of game id
    default_index: usize, // Points to "Default"
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    game_id_2_index: usize, // Some kind of game id, identical to game_id_1
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    window_width: u32,
    window_height: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    unk16: u32,
    unk17: u32,
    unk18: u32,
    unk19: u32,
    unk20: u32,
    window_title_index: usize,
    unknown: Vec<u32>,
}

/// Game Maker project Options
struct Options {
    unk1: u32, // Unknown
    unk2: u32, // Unknown
    icon_offset: u32, // Points to texture data (icon?)
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    constant1_name_index: usize, // Offset of the name of this constant in the string table
    constant2_name_index: usize, // Offset of the name of this constant in the string table
    constant3_name_index: usize, // Offset of the name of this constant in the string table
    constant4_name_index: usize, // Offset of the name of this constant in the string table
    constant5_name_index: usize, // Offset of the name of this constant in the string table
    constant6_name_index: usize, // Offset of the name of this constant in the string table
    constant7_name_index: usize, // Offset of the name of this constant in the string table
    constant8_name_index: usize, // Offset of the name of this constant in the string table
    constant9_name_index: usize, // Offset of the name of this constant in the string table
    constant10_name_index: usize, // Offset of the name of this constant in the string table
    constant11_name_index: usize, // Offset of the name of this constant in the string table
    constant12_name_index: usize, // Offset of the name of this constant in the string table
    constant13_name_index: usize, // Offset of the name of this constant in the string table
    constant14_name_index: usize, // Offset of the name of this constant in the string table
}

/// Purpose unknown.
struct Extn {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker sound.
#[derive(Clone, Copy)]
pub struct Sound {
    /// Index of the name in the string table.
    pub name_index: usize,
    unk1: u32,
    /// Index of the extension in the string table.
    pub ext_index: usize,
    /// Index of the filename in the string table.
    pub filename_index: usize,
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
}

/// A collection of sounds.
pub struct Sounds {
    /// The sounds.
    pub sounds: Vec<Sound>,
}

/// Collection of audio groups. Not present in all games.
struct AudioGroups {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker sprite.
pub struct Sprite {
    /// The index of the resource name in the string table.
    pub name_index: usize,
    /// The width of the sprite
    pub width: u32,
    /// The height of the sprite
    pub height: u32,
    unknown: Vec<u8>,
}

/// A collection of sprites.
struct Sprites {
    /// The sprites
    pub sprites: Vec<Sprite>,
}

/// A collection of backgrounds.
struct Backgrounds {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of paths.
struct Paths {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker script.
struct Script {
    /// Index of the name of the script in the string table
    pub name_index: usize,
    unknown: u32, // Unknown
}

/// A collection of scripts.
struct Scripts {
    pub scripts: Vec<Script>,
}

/// A collection of shaders.
struct Shaders {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A font.
#[derive(Clone)]
pub struct Font {
    /// Index of the font's resource name in the string table.
    pub name_index: usize,
    /// Index of the font's font name in the string table.
    pub font_name_index: usize,
    /// Point size of the font.
    pub point_size: u32,
    data: Vec<u8>,
}

/// A collection of fonts.
pub struct Fonts {
    /// The fonts.
    pub fonts: Vec<Font>,
    unknown: Vec<u8>, // Unknown trailing data
}

/// A collection of timelines.
struct Timelines {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of objects.
struct Objects {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of rooms.
struct Rooms {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
struct Dafl {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
struct Tpag {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Something to do with code. Maybe code of scripts?
struct Code {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker variable.
struct Variable {
    /// Index of the name of the variable in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section
}

/// A collection of variables.
struct Variables {
    pub variables: Vec<Variable>,
}

/// A game maker function.
struct Function {
    /// Index of the name of the function in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section.
}

/// A collection of functions.
struct Functions {
    pub functions: Vec<Function>,
}

/// A collection of strings.
///
/// All strings are assumed to be valid UTF-8.
pub struct Strings {
    /// The vector holding the strings.
    pub strings: Vec<String>,
}

struct Texture {
    unknown: u32, // Purpose unknown. Always seems to be 1.
    offset: u32, // Offset of data in the texture data
}

/// A collection of textures.
struct Textures {
    pub textures: Vec<Texture>,
    texture_data: Vec<u8>,
}

struct AudioData {
    data: Vec<u8>,
}

/// A collection of audio data.
struct Audio {
    audio: Vec<AudioData>,
    offsets: Vec<u32>, // Audio data is not contiguous, so we need to store relative offsets
    size: u32, // Fuck it
}
<commit_msg>Make sprites publicly accessible<commit_after>//! Library for manipulating Game Maker Studio's "data.win" (GEN8) data files.

#![feature(read_exact, associated_consts, associated_type_defaults)]
#![warn(missing_docs, trivial_casts, trivial_numeric_casts)]

#[macro_use]
extern crate quick_error;
extern crate byteorder;
#[macro_use]
extern crate log;

mod gamedata_io;

pub use gamedata_io::{ReadError, StringReadError};

use std::io::{self, Read, Write};
use std::path;

/// The data of a Game Maker Studio game.
///
/// This is the collective information acquired from "data.win".
pub struct GameData {
    metadata: MetaData,
    options: Options,
    extn: Extn,
    /// The sounds of the game.
    pub sounds: Sounds,
    audio_groups: Option<AudioGroups>,
    /// The sprites of the game.
    pub sprites: Sprites,
    backgrounds: Backgrounds,
    paths: Paths,
    scripts: Scripts,
    shaders: Shaders,
    /// The fonts of the game.
    pub fonts: Fonts,
    timelines: Timelines,
    objects: Objects,
    rooms: Rooms,
    dafl: Dafl,
    tpag: Tpag,
    code: Code,
    variables: Variables,
    functions: Functions,
    /// The strings of the game.
    pub strings: Strings,
    textures: Textures,
    audio: Audio,
}

/// A reader that satisfies the requirements for reading a GameData.
pub trait GameDataRead: Read + io::Seek {}
impl<T: Read + io::Seek> GameDataRead for T {}
/// A writer that satisfies the requirements for writing a GameData.
pub trait GameDataWrite: Write + io::Seek {}
impl<T: Write + io::Seek> GameDataWrite for T {}

impl GameData {
    /// Reads a GameData from a reader.
    pub fn from_reader<R: GameDataRead>(reader: &mut R) -> Result<GameData, ReadError> {
        gamedata_io::read(reader)
    }
    /// Reads a GameData from a file.
    pub fn from_file<P: AsRef<path::Path>>(path: &P) -> Result<GameData, ReadError> {
        use std::fs::File;
        use std::io::BufReader;
        let file = try!(File::open(path));
        GameData::from_reader(&mut BufReader::new(file))
    }
    /// Writes self to a writer.
    pub fn write_to_writer<W: GameDataWrite>(&self, writer: &mut W) -> io::Result<()> {
        gamedata_io::write(self, writer)
    }
    /// Writes self to a file.
    pub fn save_to_file<P: AsRef<path::Path>>(&self, path: &P) -> io::Result<()> {
        use std::fs::File;
        use std::io::BufWriter;
        let file = try!(File::create(path));
        self.write_to_writer(&mut BufWriter::new(file))
    }
    /// Returns the window width of the game.
    pub fn window_width(&self) -> u32 {
        self.metadata.window_width
    }
    /// Returns the window height of the game.
    pub fn window_height(&self) -> u32 {
        self.metadata.window_height
    }
    /// Sets the window dimensions of the game.
    pub fn set_window_dimensions(&mut self, width: u32, height: u32) {
        self.metadata.window_width = width;
        self.metadata.window_height = height;
    }
    /// Returns the window title of the game.
    pub fn window_title(&self) -> &str {
        &self.strings.strings[self.metadata.window_title_index]
    }
    /// Sets the window title of the game.
    pub fn set_window_title<S: Into<String>>(&mut self, new: S) {
        self.strings.strings[self.metadata.window_title_index] = new.into();
    }
}

/// Contains various metadata, for example, the window width/height/title.
struct MetaData {
    unk1: u32, // Purpose unknown
    game_id_1_index: usize, // Some kind of game id
    default_index: usize, // Points to "Default"
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    game_id_2_index: usize, // Some kind of game id, identical to game_id_1
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    window_width: u32,
    window_height: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    unk16: u32,
    unk17: u32,
    unk18: u32,
    unk19: u32,
    unk20: u32,
    window_title_index: usize,
    unknown: Vec<u32>,
}

/// Game Maker project Options
struct Options {
    unk1: u32, // Unknown
    unk2: u32, // Unknown
    icon_offset: u32, // Points to texture data (icon?)
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
    unk7: u32,
    unk8: u32,
    unk9: u32,
    unk10: u32,
    unk11: u32,
    unk12: u32,
    unk13: u32,
    unk14: u32,
    unk15: u32,
    constant1_name_index: usize, // Offset of the name of this constant in the string table
    constant2_name_index: usize, // Offset of the name of this constant in the string table
    constant3_name_index: usize, // Offset of the name of this constant in the string table
    constant4_name_index: usize, // Offset of the name of this constant in the string table
    constant5_name_index: usize, // Offset of the name of this constant in the string table
    constant6_name_index: usize, // Offset of the name of this constant in the string table
    constant7_name_index: usize, // Offset of the name of this constant in the string table
    constant8_name_index: usize, // Offset of the name of this constant in the string table
    constant9_name_index: usize, // Offset of the name of this constant in the string table
    constant10_name_index: usize, // Offset of the name of this constant in the string table
    constant11_name_index: usize, // Offset of the name of this constant in the string table
    constant12_name_index: usize, // Offset of the name of this constant in the string table
    constant13_name_index: usize, // Offset of the name of this constant in the string table
    constant14_name_index: usize, // Offset of the name of this constant in the string table
}

/// Purpose unknown.
struct Extn {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker sound.
#[derive(Clone, Copy)]
pub struct Sound {
    /// Index of the name in the string table.
    pub name_index: usize,
    unk1: u32,
    /// Index of the extension in the string table.
    pub ext_index: usize,
    /// Index of the filename in the string table.
    pub filename_index: usize,
    unk2: u32,
    unk3: u32,
    unk4: u32,
    unk5: u32,
    unk6: u32,
}

/// A collection of sounds.
pub struct Sounds {
    /// The sounds.
    pub sounds: Vec<Sound>,
}

/// Collection of audio groups. Not present in all games.
struct AudioGroups {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker sprite.
pub struct Sprite {
    /// The index of the resource name in the string table.
    pub name_index: usize,
    /// The width of the sprite
    pub width: u32,
    /// The height of the sprite
    pub height: u32,
    unknown: Vec<u8>,
}

/// A collection of sprites.
pub struct Sprites {
    /// The sprites
    pub sprites: Vec<Sprite>,
}

/// A collection of backgrounds.
struct Backgrounds {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of paths.
struct Paths {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker script.
struct Script {
    /// Index of the name of the script in the string table
    pub name_index: usize,
    unknown: u32, // Unknown
}

/// A collection of scripts.
struct Scripts {
    pub scripts: Vec<Script>,
}

/// A collection of shaders.
struct Shaders {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A font.
#[derive(Clone)]
pub struct Font {
    /// Index of the font's resource name in the string table.
    pub name_index: usize,
    /// Index of the font's font name in the string table.
    pub font_name_index: usize,
    /// Point size of the font.
    pub point_size: u32,
    data: Vec<u8>,
}

/// A collection of fonts.
pub struct Fonts {
    /// The fonts.
    pub fonts: Vec<Font>,
    unknown: Vec<u8>, // Unknown trailing data
}

/// A collection of timelines.
struct Timelines {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of objects.
struct Objects {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A collection of rooms.
struct Rooms {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
struct Dafl {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Purpose unknown.
struct Tpag {
    raw: Vec<u8>, // Data not analyzed yet
}

/// Something to do with code. Maybe code of scripts?
struct Code {
    raw: Vec<u8>, // Data not analyzed yet
}

/// A game maker variable.
struct Variable {
    /// Index of the name of the variable in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section
}

/// A collection of variables.
struct Variables {
    pub variables: Vec<Variable>,
}

/// A game maker function.
struct Function {
    /// Index of the name of the function in the strings section.
    pub name_index: usize,
    unknown: u32, // Purpose unknown. Ranges from 1 to a few thousand.
    code_offset: u32, // Points into the code section.
}

/// A collection of functions.
struct Functions {
    pub functions: Vec<Function>,
}

/// A collection of strings.
///
/// All strings are assumed to be valid UTF-8.
pub struct Strings {
    /// The vector holding the strings.
    pub strings: Vec<String>,
}

struct Texture {
    unknown: u32, // Purpose unknown. Always seems to be 1.
    offset: u32, // Offset of data in the texture data
}

/// A collection of textures.
struct Textures {
    pub textures: Vec<Texture>,
    texture_data: Vec<u8>,
}

struct AudioData {
    data: Vec<u8>,
}

/// A collection of audio data.
struct Audio {
    audio: Vec<AudioData>,
    offsets: Vec<u32>, // Audio data is not contiguous, so we need to store relative offsets
    size: u32, // Fuck it
}
<|endoftext|>


<commit_before>#![feature(core)]

//! A TCOD back-end for the Piston game engine.

extern crate input;
#[macro_use]
extern crate quack;
extern crate tcod;
extern crate window;

use input::{ keyboard, Button, MouseButton, Input, Motion };
use window::{
    WindowSettings,
    ShouldClose, Size, PollEvent, SwapBuffers,
    CaptureCursor, DrawSize, Title, ExitOnEsc
};
use quack::Set;
use tcod::Console;

pub struct TcodWindow {
    pub window: tcod::Console,
    title: String,
    should_close: bool,
    mouse_relative: Option<(f64, f64)>,
    mouse_state_prev: tcod::MouseState,
    exit_on_esc: bool,
}

impl TcodWindow {
    pub fn new(settings: WindowSettings) -> TcodWindow {
        let window = Console::init_root(
            settings.size[0] as i32,
            settings.size[1] as i32,
            &*settings.title,
            false
        );

        TcodWindow {
            window: window,
            title: settings.title,
            should_close: false,
            mouse_relative: None,
            // TODO: determine if there's a better way to initialize the
            // MouseState.
            mouse_state_prev: tcod::MouseState {
                x: 0is,
                y: 0is,
                dx: 0is,
                dy: 0is,
                cx: 0is,
                cy: 0is,
                dcx: 0is,
                dcy: 0is,
                lbutton: false,
                rbutton: false,
                mbutton: false,
                lbutton_pressed: false,
                rbutton_pressed: false,
                mbutton_pressed: false,
                wheel_up: false,
                wheel_down: false,
            },
            exit_on_esc: settings.exit_on_esc,
        }
    }

    fn poll_event(&mut self) -> Option<Input> {
        use tcod::KeyCode;
        use tcod::Key::Special;
        use tcod::system::Event;

        match self.mouse_relative {
            Some((x, y)) => {
                self.mouse_relative = None;
                return Some(Input::Move(Motion::MouseRelative(x, y)));
            }
            None => {}
        }
        let (flags, event) = tcod::system::check_for_event(tcod::ANY);
        match (flags, event) {
            (tcod::KEY_PRESS, Event::Key(ref key_state)) => {
                if self.exit_on_esc
                && key_state.key == Special(KeyCode::Escape) {
                    self.should_close = true;
                } else {
                    return Some(Input::Press(Button::Keyboard(tcod_map_key(key_state.key))));
                }
            },
            (tcod::KEY_RELEASE, Event::Key(ref key_state)) => {
                return Some(Input::Release(Button::Keyboard(tcod_map_key(key_state.key))));
            },
            (tcod::MOUSE_PRESS, Event::Mouse(ref mouse_state)) => {
                let button = tcod_map_mouse(self.mouse_state_prev, mouse_state);
                self.mouse_state_prev = *mouse_state.clone();
                return Some(Input::Press(Button::Mouse(button)));
            },
            (tcod::MOUSE_RELEASE, Event::Mouse(ref mouse_state)) => {
                let button = tcod_map_mouse(self.mouse_state_prev, mouse_state);
                self.mouse_state_prev = *mouse_state.clone();
                return Some(Input::Release(Button::Mouse(button)));
            },
            (tcod::MOUSE_MOVE, Event::Mouse(ref mouse_state)) => {
                // TODO: figure out why mouse_state.dx and mouse_state.dy
                // don't work.
                self.mouse_relative = Some((
                    (mouse_state.x - self.mouse_state_prev.x) as f64,
                    (mouse_state.y - self.mouse_state_prev.y) as f64
                ));
                self.mouse_state_prev = *mouse_state.clone();
                return Some(Input::Move(Motion::MouseCursor(mouse_state.x as f64, mouse_state.y as f64)));
            },
            (_, _) => {}
        }
        None
    }
}

impl Drop for TcodWindow {
    fn drop(&mut self) {
        self.set_mut(CaptureCursor(false));
    }
}

quack! {
    _obj: TcodWindow[]
    get:
        fn () -> ShouldClose { ShouldClose(_obj.should_close) }
        fn () -> Size {
            let (w, h) = (_obj.window.width(), _obj.window.height());
            Size([w as u32, h as u32])
        }
        fn () -> DrawSize {
            //let (w, h) = _obj.window.get_drawable_size();
            let (w, h) = (_obj.window.width(), _obj.window.height());
            DrawSize([w as u32, h as u32])
        }
        // TODO: Remove the .clone()
        fn () -> Title { Title(_obj.title.clone()) }
        fn () -> ExitOnEsc { ExitOnEsc(_obj.exit_on_esc) }
    set:
        fn (val: CaptureCursor) {
            //sdl2::mouse::set_relative_mouse_mode(val.0)
        }
        fn (val: ShouldClose) { _obj.should_close = val.0 }
        fn (val: Title) {
            Console::set_window_title(&*val.0);
            _obj.title = val.0
        }
        fn (val: ExitOnEsc) { _obj.exit_on_esc = val.0 }
    action:
        fn (__: SwapBuffers) -> () {
            //_obj.window.gl_swap_window()
            Console::flush()
        }
        fn (__: PollEvent) -> Option<Input> { _obj.poll_event() }
}

pub fn tcod_map_key(key: tcod::Key) -> keyboard::Key {
    use input::keyboard::Key;
    use std::num::FromPrimitive;
    match key {
        tcod::Key::Printable(keycode) => FromPrimitive::from_u64(keycode as u64).unwrap(),
        tcod::Key::Special(keycode) => {
            match keycode {
                tcod::KeyCode::NoKey => Key::Unknown,
                tcod::KeyCode::Escape => Key::Escape,
                tcod::KeyCode::Backspace => Key::Backspace,
                tcod::KeyCode::Tab => Key::Tab,
                tcod::KeyCode::Enter => Key::Return,
                tcod::KeyCode::Shift => Key::LShift, // TODO: find RShift
                tcod::KeyCode::Control => Key::LCtrl,
                tcod::KeyCode::Alt => Key::LAlt,
                tcod::KeyCode::Pause => Key::Pause,
                tcod::KeyCode::Capslock => Key::CapsLock,
                tcod::KeyCode::Pageup => Key::PageUp,
                tcod::KeyCode::Pagedown => Key::PageDown,
                tcod::KeyCode::End => Key::End,
                tcod::KeyCode::Home => Key::Home,
                tcod::KeyCode::Up => Key::Up,
                tcod::KeyCode::Left => Key::Left,
                tcod::KeyCode::Right => Key::Right,
                tcod::KeyCode::Down => Key::Down,
                tcod::KeyCode::PrintScreen => Key::PrintScreen,
                tcod::KeyCode::Insert => Key::Insert,
                tcod::KeyCode::Delete => Key::Delete,
                tcod::KeyCode::LeftWin => Key::LGui,
                tcod::KeyCode::RightWin => Key::RGui,
                tcod::KeyCode::Apps => Key::Application,
                // The numbers on the alphanum section of the keyboard
                tcod::KeyCode::Number0 => Key::D0,
                tcod::KeyCode::Number1 => Key::D1,
                tcod::KeyCode::Number2 => Key::D2,
                tcod::KeyCode::Number3 => Key::D3,
                tcod::KeyCode::Number4 => Key::D4,
                tcod::KeyCode::Number5 => Key::D5,
                tcod::KeyCode::Number6 => Key::D6,
                tcod::KeyCode::Number7 => Key::D7,
                tcod::KeyCode::Number8 => Key::D8,
                tcod::KeyCode::Number9 => Key::D9,
                // The numbers on the numeric keypad
                tcod::KeyCode::NumPad0 => Key::NumPad0,
                tcod::KeyCode::NumPad1 => Key::NumPad1,
                tcod::KeyCode::NumPad2 => Key::NumPad2,
                tcod::KeyCode::NumPad3 => Key::NumPad3,
                tcod::KeyCode::NumPad4 => Key::NumPad4,
                tcod::KeyCode::NumPad5 => Key::NumPad5,
                tcod::KeyCode::NumPad6 => Key::NumPad6,
                tcod::KeyCode::NumPad7 => Key::NumPad7,
                tcod::KeyCode::NumPad8 => Key::NumPad8,
                tcod::KeyCode::NumPad9 => Key::NumPad9,
                tcod::KeyCode::NumPadAdd => Key::NumPadPlus,
                tcod::KeyCode::NumPadSubtract => Key::NumPadMinus,
                tcod::KeyCode::NumPadDivide => Key::NumPadDivide,
                tcod::KeyCode::NumPadMultiply => Key::NumPadMultiply,
                tcod::KeyCode::NumPadDecimal => Key::NumPadDecimal,
                tcod::KeyCode::NumPadEnter => Key::NumPadEnter,
                tcod::KeyCode::F1 => Key::F1,
                tcod::KeyCode::F2 => Key::F2,
                tcod::KeyCode::F3 => Key::F3,
                tcod::KeyCode::F4 => Key::F4,
                tcod::KeyCode::F5 => Key::F5,
                tcod::KeyCode::F6 => Key::F6,
                tcod::KeyCode::F7 => Key::F7,
                tcod::KeyCode::F8 => Key::F8,
                tcod::KeyCode::F9 => Key::F9,
                tcod::KeyCode::F10 => Key::F10,
                tcod::KeyCode::F11 => Key::F11,
                tcod::KeyCode::F12 => Key::F12,
                tcod::KeyCode::NUMLOCK => Key::NumLockClear,
                tcod::KeyCode::SCROLLLOCK => Key::ScrollLock,
                tcod::KeyCode::Spacebar => Key::Space,
                // TODO: check if this is correct.
                tcod::KeyCode::Char => Key::Unknown,
            }
        }
    }
}

pub fn tcod_map_mouse(prev_state: tcod::MouseState, state: &tcod::MouseState) -> MouseButton {
    if prev_state.lbutton != state.lbutton { return MouseButton::Left }
    else if prev_state.rbutton != state.rbutton { return MouseButton::Right }
    else if prev_state.mbutton != state.mbutton { return MouseButton::Middle }
    else { return MouseButton::Unknown }
}
<commit_msg>Remove unnecessary Drop trait impl<commit_after>#![feature(core)]

//! A TCOD back-end for the Piston game engine.

extern crate input;
#[macro_use]
extern crate quack;
extern crate tcod;
extern crate window;

use input::{ keyboard, Button, MouseButton, Input, Motion };
use window::{
    WindowSettings,
    ShouldClose, Size, PollEvent, SwapBuffers,
    CaptureCursor, DrawSize, Title, ExitOnEsc
};
use quack::Set;
use tcod::Console;

pub struct TcodWindow {
    pub window: tcod::Console,
    title: String,
    should_close: bool,
    mouse_relative: Option<(f64, f64)>,
    mouse_state_prev: tcod::MouseState,
    exit_on_esc: bool,
}

impl TcodWindow {
    pub fn new(settings: WindowSettings) -> TcodWindow {
        let window = Console::init_root(
            settings.size[0] as i32,
            settings.size[1] as i32,
            &*settings.title,
            false
        );

        TcodWindow {
            window: window,
            title: settings.title,
            should_close: false,
            mouse_relative: None,
            // TODO: determine if there's a better way to initialize the
            // MouseState.
            mouse_state_prev: tcod::MouseState {
                x: 0is,
                y: 0is,
                dx: 0is,
                dy: 0is,
                cx: 0is,
                cy: 0is,
                dcx: 0is,
                dcy: 0is,
                lbutton: false,
                rbutton: false,
                mbutton: false,
                lbutton_pressed: false,
                rbutton_pressed: false,
                mbutton_pressed: false,
                wheel_up: false,
                wheel_down: false,
            },
            exit_on_esc: settings.exit_on_esc,
        }
    }

    fn poll_event(&mut self) -> Option<Input> {
        use tcod::KeyCode;
        use tcod::Key::Special;
        use tcod::system::Event;

        match self.mouse_relative {
            Some((x, y)) => {
                self.mouse_relative = None;
                return Some(Input::Move(Motion::MouseRelative(x, y)));
            }
            None => {}
        }
        let (flags, event) = tcod::system::check_for_event(tcod::ANY);
        match (flags, event) {
            (tcod::KEY_PRESS, Event::Key(ref key_state)) => {
                if self.exit_on_esc
                && key_state.key == Special(KeyCode::Escape) {
                    self.should_close = true;
                } else {
                    return Some(Input::Press(Button::Keyboard(tcod_map_key(key_state.key))));
                }
            },
            (tcod::KEY_RELEASE, Event::Key(ref key_state)) => {
                return Some(Input::Release(Button::Keyboard(tcod_map_key(key_state.key))));
            },
            (tcod::MOUSE_PRESS, Event::Mouse(ref mouse_state)) => {
                let button = tcod_map_mouse(self.mouse_state_prev, mouse_state);
                self.mouse_state_prev = *mouse_state.clone();
                return Some(Input::Press(Button::Mouse(button)));
            },
            (tcod::MOUSE_RELEASE, Event::Mouse(ref mouse_state)) => {
                let button = tcod_map_mouse(self.mouse_state_prev, mouse_state);
                self.mouse_state_prev = *mouse_state.clone();
                return Some(Input::Release(Button::Mouse(button)));
            },
            (tcod::MOUSE_MOVE, Event::Mouse(ref mouse_state)) => {
                // TODO: figure out why mouse_state.dx and mouse_state.dy
                // don't work.
                self.mouse_relative = Some((
                    (mouse_state.x - self.mouse_state_prev.x) as f64,
                    (mouse_state.y - self.mouse_state_prev.y) as f64
                ));
                self.mouse_state_prev = *mouse_state.clone();
                return Some(Input::Move(Motion::MouseCursor(mouse_state.x as f64, mouse_state.y as f64)));
            },
            (_, _) => {}
        }
        None
    }
}

quack! {
    _obj: TcodWindow[]
    get:
        fn () -> ShouldClose { ShouldClose(_obj.should_close) }
        fn () -> Size {
            let (w, h) = (_obj.window.width(), _obj.window.height());
            Size([w as u32, h as u32])
        }
        fn () -> DrawSize {
            //let (w, h) = _obj.window.get_drawable_size();
            let (w, h) = (_obj.window.width(), _obj.window.height());
            DrawSize([w as u32, h as u32])
        }
        // TODO: Remove the .clone()
        fn () -> Title { Title(_obj.title.clone()) }
        fn () -> ExitOnEsc { ExitOnEsc(_obj.exit_on_esc) }
    set:
        fn (val: CaptureCursor) {
            //sdl2::mouse::set_relative_mouse_mode(val.0)
        }
        fn (val: ShouldClose) { _obj.should_close = val.0 }
        fn (val: Title) {
            Console::set_window_title(&*val.0);
            _obj.title = val.0
        }
        fn (val: ExitOnEsc) { _obj.exit_on_esc = val.0 }
    action:
        fn (__: SwapBuffers) -> () {
            //_obj.window.gl_swap_window()
            Console::flush()
        }
        fn (__: PollEvent) -> Option<Input> { _obj.poll_event() }
}

pub fn tcod_map_key(key: tcod::Key) -> keyboard::Key {
    use input::keyboard::Key;
    use std::num::FromPrimitive;
    match key {
        tcod::Key::Printable(keycode) => FromPrimitive::from_u64(keycode as u64).unwrap(),
        tcod::Key::Special(keycode) => {
            match keycode {
                tcod::KeyCode::NoKey => Key::Unknown,
                tcod::KeyCode::Escape => Key::Escape,
                tcod::KeyCode::Backspace => Key::Backspace,
                tcod::KeyCode::Tab => Key::Tab,
                tcod::KeyCode::Enter => Key::Return,
                tcod::KeyCode::Shift => Key::LShift, // TODO: find RShift
                tcod::KeyCode::Control => Key::LCtrl,
                tcod::KeyCode::Alt => Key::LAlt,
                tcod::KeyCode::Pause => Key::Pause,
                tcod::KeyCode::Capslock => Key::CapsLock,
                tcod::KeyCode::Pageup => Key::PageUp,
                tcod::KeyCode::Pagedown => Key::PageDown,
                tcod::KeyCode::End => Key::End,
                tcod::KeyCode::Home => Key::Home,
                tcod::KeyCode::Up => Key::Up,
                tcod::KeyCode::Left => Key::Left,
                tcod::KeyCode::Right => Key::Right,
                tcod::KeyCode::Down => Key::Down,
                tcod::KeyCode::PrintScreen => Key::PrintScreen,
                tcod::KeyCode::Insert => Key::Insert,
                tcod::KeyCode::Delete => Key::Delete,
                tcod::KeyCode::LeftWin => Key::LGui,
                tcod::KeyCode::RightWin => Key::RGui,
                tcod::KeyCode::Apps => Key::Application,
                // The numbers on the alphanum section of the keyboard
                tcod::KeyCode::Number0 => Key::D0,
                tcod::KeyCode::Number1 => Key::D1,
                tcod::KeyCode::Number2 => Key::D2,
                tcod::KeyCode::Number3 => Key::D3,
                tcod::KeyCode::Number4 => Key::D4,
                tcod::KeyCode::Number5 => Key::D5,
                tcod::KeyCode::Number6 => Key::D6,
                tcod::KeyCode::Number7 => Key::D7,
                tcod::KeyCode::Number8 => Key::D8,
                tcod::KeyCode::Number9 => Key::D9,
                // The numbers on the numeric keypad
                tcod::KeyCode::NumPad0 => Key::NumPad0,
                tcod::KeyCode::NumPad1 => Key::NumPad1,
                tcod::KeyCode::NumPad2 => Key::NumPad2,
                tcod::KeyCode::NumPad3 => Key::NumPad3,
                tcod::KeyCode::NumPad4 => Key::NumPad4,
                tcod::KeyCode::NumPad5 => Key::NumPad5,
                tcod::KeyCode::NumPad6 => Key::NumPad6,
                tcod::KeyCode::NumPad7 => Key::NumPad7,
                tcod::KeyCode::NumPad8 => Key::NumPad8,
                tcod::KeyCode::NumPad9 => Key::NumPad9,
                tcod::KeyCode::NumPadAdd => Key::NumPadPlus,
                tcod::KeyCode::NumPadSubtract => Key::NumPadMinus,
                tcod::KeyCode::NumPadDivide => Key::NumPadDivide,
                tcod::KeyCode::NumPadMultiply => Key::NumPadMultiply,
                tcod::KeyCode::NumPadDecimal => Key::NumPadDecimal,
                tcod::KeyCode::NumPadEnter => Key::NumPadEnter,
                tcod::KeyCode::F1 => Key::F1,
                tcod::KeyCode::F2 => Key::F2,
                tcod::KeyCode::F3 => Key::F3,
                tcod::KeyCode::F4 => Key::F4,
                tcod::KeyCode::F5 => Key::F5,
                tcod::KeyCode::F6 => Key::F6,
                tcod::KeyCode::F7 => Key::F7,
                tcod::KeyCode::F8 => Key::F8,
                tcod::KeyCode::F9 => Key::F9,
                tcod::KeyCode::F10 => Key::F10,
                tcod::KeyCode::F11 => Key::F11,
                tcod::KeyCode::F12 => Key::F12,
                tcod::KeyCode::NUMLOCK => Key::NumLockClear,
                tcod::KeyCode::SCROLLLOCK => Key::ScrollLock,
                tcod::KeyCode::Spacebar => Key::Space,
                // TODO: check if this is correct.
                tcod::KeyCode::Char => Key::Unknown,
            }
        }
    }
}

pub fn tcod_map_mouse(prev_state: tcod::MouseState, state: &tcod::MouseState) -> MouseButton {
    if prev_state.lbutton != state.lbutton { return MouseButton::Left }
    else if prev_state.rbutton != state.rbutton { return MouseButton::Right }
    else if prev_state.mbutton != state.mbutton { return MouseButton::Middle }
    else { return MouseButton::Unknown }
}
<|endoftext|>