<commit_before>//!Router asigns handlers to paths and resolves them per request

#[cfg(test)]
use http::method;
use http::method::Method;
use regex::Regex;
use std::collections::hashmap::HashMap;
use request::Request;
use response::Response;

/// A Route is the basic data structure that stores both the path
/// and the handler that gets executed for the route.
/// The path can contain variable pattern such as `user/:userid/invoices`
struct Route {
    pub path: String,
    pub method: Method,
    pub handler: fn(request: &Request, response: &mut Response),
    pub variables: HashMap<String, uint>,
    matcher: Regex
}

impl Clone for Route {
    fn clone(&self) -> Route {
        Route {
            path: self.path.clone(),
            method: self.method.clone(),
            handler: self.handler,
            matcher: self.matcher.clone(),
            variables: self.variables.clone()
        }
    }
}

/// A RouteResult is what the router returns when `match_route` is called.
/// It contains the matched `route` and also a `params` property holding
/// a HashMap with the keys being the variable names and the value being the
/// evaluated string
struct RouteResult<'a> {
    pub route: &'a Route,
    pub params: HashMap<String, String>
}

/// The PathUtils collects some small helper methods that operate on the path
struct PathUtils;

static REGEX_VAR_SEQ: Regex                 = regex!(r":([a-zA-Z0-9_-]*)");
static VAR_SEQ:&'static str                 = "[a-zA-Z0-9_-]*";
static VAR_SEQ_WITH_SLASH:&'static str      = "[/a-zA-Z0-9_-]*";
static VAR_SEQ_WITH_CAPTURE:&'static str    = "([a-zA-Z0-9_-]*)";
static REGEX_START:&'static str             = "^";
static REGEX_END:&'static str               = "$";

impl PathUtils {
    fn create_regex (route_path: &str) -> Regex {

        let updated_path = route_path.to_string()
                                     // first mark all double wildcards for replacement. We can't directly replace them
                                     // since the replacement does contain the * symbol as well, which would get overwritten
                                     // with the next replace call
                                     .replace("**", "___DOUBLE_WILDCARD___")
                                     // then replace the regular wildcard symbols (*) with the appropriate regex
                                     .replace("*", VAR_SEQ)
                                     // now replace the previously marked double wild cards (**)
                                     .replace("___DOUBLE_WILDCARD___", VAR_SEQ_WITH_SLASH);

        // then replace the variable symbols (:variable) with the appropriate regex
        let result = REGEX_START.to_string()
                                .append(REGEX_VAR_SEQ.replace_all(updated_path.as_slice(), VAR_SEQ_WITH_CAPTURE).as_slice())
                                .append(REGEX_END);

        match Regex::new(result.as_slice()) {
            Ok(re) => re,
            Err(err) => fail!("{}", err)
        }
    }

    fn get_variable_info (route_path: &str) -> HashMap<String, uint> {
        REGEX_VAR_SEQ.captures_iter(route_path)
             .enumerate()
             .map(|(i, matched)| (matched.at(1).to_string(), i))
             .collect()
    }
}

/// The Router's job is it to hold routes and to resolve them later against
/// concrete URLs

#[deriving(Clone)]
pub struct Router{
    pub routes: Vec<Route>,
}

impl Router {
    pub fn new () -> Router {
        Router {
            routes: Vec::new()
        }
    }

    pub fn add_route (&mut self, method: Method, path: String, handler: fn(request: &Request, response: &mut Response)) -> () {
        let matcher = PathUtils::create_regex(path.as_slice());
        let variable_infos = PathUtils::get_variable_info(path.as_slice());
        let route = Route {
            path: path,
            method: method,
            matcher: matcher,
            handler: handler,
            variables: variable_infos
        };
        self.routes.push(route);
    }

    pub fn match_route(&self, method: Method, path: String) -> Option<RouteResult> {
        self.routes.iter().find(|item| item.method == method && item.matcher.is_match(path.as_slice()))
            .and_then(|route| {
                match route.matcher.captures(path.as_slice()) {
                    Some(captures) => {
                        let mut map = HashMap::new();
                        for (name, pos) in route.variables.iter() {
                            map.insert(name.to_string(), captures.at(pos + 1).to_string());
                        }
                        Some(RouteResult {
                            route: route,
                            params: map
                        })
                    },
                    None => Some(RouteResult{
                        route: route,
                        params: HashMap::new()
                    })
                }
            })
    }
}

#[test]
fn creates_map_with_var_variable_infos () {
    let map = PathUtils::get_variable_info("foo/:uid/bar/:groupid");

    assert_eq!(map.len(), 2);
    assert_eq!(map.get(&"uid".to_string()), &0);
    assert_eq!(map.get(&"groupid".to_string()), &1);
}

#[test]
fn creates_regex_with_captures () {
    let regex = PathUtils::create_regex("foo/:uid/bar/:groupid");
    let caps = regex.captures("foo/4711/bar/5490").unwrap();

    assert_eq!(caps.at(1), "4711");
    assert_eq!(caps.at(2), "5490");

    let regex = PathUtils::create_regex("foo/*/:uid/bar/:groupid");
    let caps = regex.captures("foo/test/4711/bar/5490").unwrap();

    assert_eq!(caps.at(1), "4711");
    assert_eq!(caps.at(2), "5490");

    let regex = PathUtils::create_regex("foo/**/:uid/bar/:groupid");
    let caps = regex.captures("foo/test/another/4711/bar/5490").unwrap();

    assert_eq!(caps.at(1), "4711");
    assert_eq!(caps.at(2), "5490");
}

#[test]
fn creates_valid_regex_for_routes () {
    let regex1 = PathUtils::create_regex("foo/:uid/bar/:groupid");
    let regex2 = PathUtils::create_regex("foo/*/bar");
    let regex3 = PathUtils::create_regex("foo/**/bar");

    assert_eq!(regex1.is_match("foo/4711/bar/5490"), true);
    assert_eq!(regex1.is_match("foo/4711/bar"), false);

    assert_eq!(regex2.is_match("foo/4711/bar"), true);
    assert_eq!(regex2.is_match("foo/4711/4712/bar"), false);

    assert_eq!(regex3.is_match("foo/4711/bar"), true);
    assert_eq!(regex3.is_match("foo/4711/4712/bar"), true);
}

#[test]
fn can_match_var_routes () {
    let route_store = &mut Router::new();

    fn handler (_request: &Request, response: &mut Response) -> () {
        let _ = response.origin.write("hello from foo".as_bytes());
    };

    route_store.add_route(method::Get, "/foo/:userid".to_string(), handler);
    route_store.add_route(method::Get, "/bar".to_string(), handler);

    let route_result = route_store.match_route(method::Get, "/foo/4711".to_string()).unwrap();
    let route = route_result.route;

    assert_eq!(route_result.params.get(&"userid".to_string()), &"4711".to_string());

    //assert the route has identified the variable
    assert_eq!(route.variables.len(), 1);
    assert_eq!(route.variables.get(&"userid".to_string()), &0);

    let route_result = route_store.match_route(method::Get, "/bar/4711".to_string());

    let result = match route_result {
        Some(_res) => true,
        None => false
    };

    assert_eq!(result, false);

    let route_result = route_store.match_route(method::Get, "/foo".to_string());

    let result = match route_result{
        Some(_res) => true,
        None => false
    };

    assert_eq!(result, false);
}
<commit_msg>remove warnings<commit_after>//!Router asigns handlers to paths and resolves them per request

#[cfg(test)]
use http::method;
use http::method::Method;
use regex::Regex;
use std::collections::hashmap::HashMap;
use request::Request;
use response::Response;

/// A Route is the basic data structure that stores both the path
/// and the handler that gets executed for the route.
/// The path can contain variable pattern such as `user/:userid/invoices`
pub struct Route {
    pub path: String,
    pub method: Method,
    pub handler: fn(request: &Request, response: &mut Response),
    pub variables: HashMap<String, uint>,
    matcher: Regex
}

impl Clone for Route {
    fn clone(&self) -> Route {
        Route {
            path: self.path.clone(),
            method: self.method.clone(),
            handler: self.handler,
            matcher: self.matcher.clone(),
            variables: self.variables.clone()
        }
    }
}

/// A RouteResult is what the router returns when `match_route` is called.
/// It contains the matched `route` and also a `params` property holding
/// a HashMap with the keys being the variable names and the value being the
/// evaluated string
pub struct RouteResult<'a> {
    pub route: &'a Route,
    pub params: HashMap<String, String>
}

/// The PathUtils collects some small helper methods that operate on the path
struct PathUtils;

static REGEX_VAR_SEQ: Regex                 = regex!(r":([a-zA-Z0-9_-]*)");
static VAR_SEQ:&'static str                 = "[a-zA-Z0-9_-]*";
static VAR_SEQ_WITH_SLASH:&'static str      = "[/a-zA-Z0-9_-]*";
static VAR_SEQ_WITH_CAPTURE:&'static str    = "([a-zA-Z0-9_-]*)";
static REGEX_START:&'static str             = "^";
static REGEX_END:&'static str               = "$";

impl PathUtils {
    fn create_regex (route_path: &str) -> Regex {

        let updated_path = route_path.to_string()
                                     // first mark all double wildcards for replacement. We can't directly replace them
                                     // since the replacement does contain the * symbol as well, which would get overwritten
                                     // with the next replace call
                                     .replace("**", "___DOUBLE_WILDCARD___")
                                     // then replace the regular wildcard symbols (*) with the appropriate regex
                                     .replace("*", VAR_SEQ)
                                     // now replace the previously marked double wild cards (**)
                                     .replace("___DOUBLE_WILDCARD___", VAR_SEQ_WITH_SLASH);

        // then replace the variable symbols (:variable) with the appropriate regex
        let result = REGEX_START.to_string()
                                .append(REGEX_VAR_SEQ.replace_all(updated_path.as_slice(), VAR_SEQ_WITH_CAPTURE).as_slice())
                                .append(REGEX_END);

        match Regex::new(result.as_slice()) {
            Ok(re) => re,
            Err(err) => fail!("{}", err)
        }
    }

    fn get_variable_info (route_path: &str) -> HashMap<String, uint> {
        REGEX_VAR_SEQ.captures_iter(route_path)
             .enumerate()
             .map(|(i, matched)| (matched.at(1).to_string(), i))
             .collect()
    }
}

/// The Router's job is it to hold routes and to resolve them later against
/// concrete URLs

#[deriving(Clone)]
pub struct Router{
    pub routes: Vec<Route>,
}

impl Router {
    pub fn new () -> Router {
        Router {
            routes: Vec::new()
        }
    }

    pub fn add_route (&mut self, method: Method, path: String, handler: fn(request: &Request, response: &mut Response)) -> () {
        let matcher = PathUtils::create_regex(path.as_slice());
        let variable_infos = PathUtils::get_variable_info(path.as_slice());
        let route = Route {
            path: path,
            method: method,
            matcher: matcher,
            handler: handler,
            variables: variable_infos
        };
        self.routes.push(route);
    }

    pub fn match_route(&self, method: Method, path: String) -> Option<RouteResult> {
        self.routes.iter().find(|item| item.method == method && item.matcher.is_match(path.as_slice()))
            .and_then(|route| {
                match route.matcher.captures(path.as_slice()) {
                    Some(captures) => {
                        let mut map = HashMap::new();
                        for (name, pos) in route.variables.iter() {
                            map.insert(name.to_string(), captures.at(pos + 1).to_string());
                        }
                        Some(RouteResult {
                            route: route,
                            params: map
                        })
                    },
                    None => Some(RouteResult{
                        route: route,
                        params: HashMap::new()
                    })
                }
            })
    }
}

#[test]
fn creates_map_with_var_variable_infos () {
    let map = PathUtils::get_variable_info("foo/:uid/bar/:groupid");

    assert_eq!(map.len(), 2);
    assert_eq!(map.get(&"uid".to_string()), &0);
    assert_eq!(map.get(&"groupid".to_string()), &1);
}

#[test]
fn creates_regex_with_captures () {
    let regex = PathUtils::create_regex("foo/:uid/bar/:groupid");
    let caps = regex.captures("foo/4711/bar/5490").unwrap();

    assert_eq!(caps.at(1), "4711");
    assert_eq!(caps.at(2), "5490");

    let regex = PathUtils::create_regex("foo/*/:uid/bar/:groupid");
    let caps = regex.captures("foo/test/4711/bar/5490").unwrap();

    assert_eq!(caps.at(1), "4711");
    assert_eq!(caps.at(2), "5490");

    let regex = PathUtils::create_regex("foo/**/:uid/bar/:groupid");
    let caps = regex.captures("foo/test/another/4711/bar/5490").unwrap();

    assert_eq!(caps.at(1), "4711");
    assert_eq!(caps.at(2), "5490");
}

#[test]
fn creates_valid_regex_for_routes () {
    let regex1 = PathUtils::create_regex("foo/:uid/bar/:groupid");
    let regex2 = PathUtils::create_regex("foo/*/bar");
    let regex3 = PathUtils::create_regex("foo/**/bar");

    assert_eq!(regex1.is_match("foo/4711/bar/5490"), true);
    assert_eq!(regex1.is_match("foo/4711/bar"), false);

    assert_eq!(regex2.is_match("foo/4711/bar"), true);
    assert_eq!(regex2.is_match("foo/4711/4712/bar"), false);

    assert_eq!(regex3.is_match("foo/4711/bar"), true);
    assert_eq!(regex3.is_match("foo/4711/4712/bar"), true);
}

#[test]
fn can_match_var_routes () {
    let route_store = &mut Router::new();

    fn handler (_request: &Request, response: &mut Response) -> () {
        let _ = response.origin.write("hello from foo".as_bytes());
    };

    route_store.add_route(method::Get, "/foo/:userid".to_string(), handler);
    route_store.add_route(method::Get, "/bar".to_string(), handler);

    let route_result = route_store.match_route(method::Get, "/foo/4711".to_string()).unwrap();
    let route = route_result.route;

    assert_eq!(route_result.params.get(&"userid".to_string()), &"4711".to_string());

    //assert the route has identified the variable
    assert_eq!(route.variables.len(), 1);
    assert_eq!(route.variables.get(&"userid".to_string()), &0);

    let route_result = route_store.match_route(method::Get, "/bar/4711".to_string());

    let result = match route_result {
        Some(_res) => true,
        None => false
    };

    assert_eq!(result, false);

    let route_result = route_store.match_route(method::Get, "/foo".to_string());

    let result = match route_result{
        Some(_res) => true,
        None => false
    };

    assert_eq!(result, false);
}
<|endoftext|>


<commit_before>use std::io::{Write, Read};
use std::sync::Mutex;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;
use std::net::SocketAddr;

use hyper::header::ContentLength;
use hyper::method::Method;
use hyper::server::{Server, Handler, Request, Response};
use hyper::uri::RequestUri::AbsolutePath;
use hyper::status::StatusCode;

use command::{WebDriverMessage, WebDriverCommand};
use error::{WebDriverResult, WebDriverError, ErrorStatus};
use httpapi::WebDriverHttpApi;
use response::WebDriverResponse;

enum DispatchMessage {
    HandleWebDriver(WebDriverMessage, Sender<WebDriverResult<WebDriverResponse>>),
    Quit
}

#[derive(PartialEq, Clone)]
pub struct Session {
    id: String
}

impl Session {
    fn new(id: String) -> Session {
        Session {
            id: id
        }
    }
}

pub trait WebDriverHandler : Send {
    fn handle_command(&mut self, session: &Option<Session>, msg: &WebDriverMessage) -> WebDriverResult<WebDriverResponse>;
    fn delete_session(&mut self, session: &Option<Session>);
}

struct Dispatcher<T: WebDriverHandler> {
    handler: T,
    session: Option<Session>
}

impl<T: WebDriverHandler> Dispatcher<T> {
    fn new(handler: T) -> Dispatcher<T> {
        Dispatcher {
            handler: handler,
            session: None
        }
    }

    fn run(&mut self, msg_chan: Receiver<DispatchMessage>) {
        loop {
            match msg_chan.recv() {
                Ok(DispatchMessage::HandleWebDriver(msg, resp_chan)) => {
                    let resp = match self.check_session(&msg) {
                        Ok(_) => self.handler.handle_command(&self.session, &msg),
                        Err(e) => Err(e)
                    };

                    match resp {
                        Ok(WebDriverResponse::NewSession(ref new_session)) => {
                            self.session = Some(Session::new(new_session.sessionId.clone()));
                        },
                        Ok(WebDriverResponse::DeleteSession) => {
                            debug!("Deleting session");
                            self.handler.delete_session(&self.session);
                            self.session = None;
                        },
                        _ => {}
                    }

                    if resp_chan.send(resp).is_err() {
                        error!("Sending response to the main thread failed");
                    };
                },
                Ok(DispatchMessage::Quit) => {
                    break;
                },
                Err(_) => panic!("Error receiving message in handler")
            }
        }
    }

    fn check_session(&self, msg: &WebDriverMessage) -> WebDriverResult<()> {
        match msg.session_id {
            Some(ref msg_session_id) => {
                match self.session {
                    Some(ref existing_session) => {
                        if existing_session.id != *msg_session_id {
                            Err(WebDriverError::new(
                                ErrorStatus::InvalidSessionId,
                                &format!("Got unexpected session id {} expected {}",
                                         msg_session_id,
                                         existing_session.id)[..]))
                        } else {
                            Ok(())
                        }
                    },
                    None => Ok(())
                }
            },
            None => {
                match self.session {
                    Some(_) => {
                        match msg.command {
                            WebDriverCommand::NewSession => {
                                Err(WebDriverError::new(
                                    ErrorStatus::SessionNotCreated,
                                    "Session is already started"))
                            },
                            _ => {
                                //This should be impossible
                                error!("Got a message with no session id");
                                Err(WebDriverError::new(
                                    ErrorStatus::UnknownError,
                                    "Got a command with no session?!"))
                            }
                        }
                    },
                    None => {
                        match msg.command {
                            WebDriverCommand::NewSession => Ok(()),

                            _ => Err(WebDriverError::new(
                                ErrorStatus::InvalidSessionId,
                                "Tried to run a command before creating a session"))
                        }
                    }
                }
            }
        }
    }
}

struct HttpHandler {
    chan: Mutex<Sender<DispatchMessage>>,
    api: Mutex<WebDriverHttpApi>
}

impl HttpHandler {
    fn new(api: WebDriverHttpApi, chan: Sender<DispatchMessage>) -> HttpHandler {
        HttpHandler {
            chan: Mutex::new(chan),
            api: Mutex::new(api)
        }
    }
}

impl Handler for HttpHandler {
    fn handle(&self, req: Request, res: Response) {
        let mut req = req;
        let mut res = res;

        let mut body = String::new();
        if let Method::Post = req.method {
            req.read_to_string(&mut body).unwrap();
        }
        debug!("Got request {} {:?}", req.method, req.uri);
        match req.uri {
            AbsolutePath(path) => {
                let msg_result = {
                    // The fact that this locks for basically the whole request doesn't
                    // matter as long as we are only handling one request at a time.
                    match self.api.lock() {
                        Ok(ref api) => {
                            api.decode_request(req.method, &path[..], &body[..])
                        },
                        Err(_) => return
                    }
                };
                let (status, resp_body) = match msg_result {
                    Ok(message) => {
                        let (send_res, recv_res) = channel();
                        match self.chan.lock() {
                            Ok(ref c) => {
                                let res = c.send(DispatchMessage::HandleWebDriver(message,
                                                                                send_res));
                                match res {
                                    Ok(x) => x,
                                    Err(_) => {
                                        error!("Something terrible happened");
                                        return
                                    }
                                }
                            },
                            Err(_) => {
                                error!("Something terrible happened");
                                return
                            }
                        }
                        match recv_res.recv() {
                            Ok(data) => match data {
                                Ok(response) => (StatusCode::Ok, response.to_json_string()),
                                Err(err) => (err.http_status(), err.to_json_string()),
                            },
                            Err(_) => panic!("Error reading response")
                        }
                    },
                    Err(err) => {
                        (err.http_status(), err.to_json_string())
                    }
                };
                error!("Returning status {:?}", status);
                error!("Returning body {}", resp_body);
                {
                    let resp_status = res.status_mut();
                    *resp_status = status;
                }
                res.headers_mut().set(ContentLength(resp_body.len() as u64));
                let mut stream = res.start().unwrap();
                stream.write_all(&resp_body.as_bytes()).unwrap();
                stream.end().unwrap();
            },
            _ => {}
        }
    }
}

pub fn start<T: 'static+WebDriverHandler>(address: SocketAddr, handler: T) {
    let (msg_send, msg_recv) = channel();

    let api = WebDriverHttpApi::new();
    let http_handler = HttpHandler::new(api, msg_send);
    let server = Server::http(http_handler);

    thread::spawn(move || {
        let mut dispatcher = Dispatcher::new(handler);
        dispatcher.run(msg_recv)
    });
    server.listen(&address).unwrap();
}
<commit_msg>Name http server thread for debugging.<commit_after>use std::io::{Write, Read};
use std::sync::Mutex;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;
use std::net::SocketAddr;

use hyper::header::ContentLength;
use hyper::method::Method;
use hyper::server::{Server, Handler, Request, Response};
use hyper::uri::RequestUri::AbsolutePath;
use hyper::status::StatusCode;

use command::{WebDriverMessage, WebDriverCommand};
use error::{WebDriverResult, WebDriverError, ErrorStatus};
use httpapi::WebDriverHttpApi;
use response::WebDriverResponse;

enum DispatchMessage {
    HandleWebDriver(WebDriverMessage, Sender<WebDriverResult<WebDriverResponse>>),
    Quit
}

#[derive(PartialEq, Clone)]
pub struct Session {
    id: String
}

impl Session {
    fn new(id: String) -> Session {
        Session {
            id: id
        }
    }
}

pub trait WebDriverHandler : Send {
    fn handle_command(&mut self, session: &Option<Session>, msg: &WebDriverMessage) -> WebDriverResult<WebDriverResponse>;
    fn delete_session(&mut self, session: &Option<Session>);
}

struct Dispatcher<T: WebDriverHandler> {
    handler: T,
    session: Option<Session>
}

impl<T: WebDriverHandler> Dispatcher<T> {
    fn new(handler: T) -> Dispatcher<T> {
        Dispatcher {
            handler: handler,
            session: None
        }
    }

    fn run(&mut self, msg_chan: Receiver<DispatchMessage>) {
        loop {
            match msg_chan.recv() {
                Ok(DispatchMessage::HandleWebDriver(msg, resp_chan)) => {
                    let resp = match self.check_session(&msg) {
                        Ok(_) => self.handler.handle_command(&self.session, &msg),
                        Err(e) => Err(e)
                    };

                    match resp {
                        Ok(WebDriverResponse::NewSession(ref new_session)) => {
                            self.session = Some(Session::new(new_session.sessionId.clone()));
                        },
                        Ok(WebDriverResponse::DeleteSession) => {
                            debug!("Deleting session");
                            self.handler.delete_session(&self.session);
                            self.session = None;
                        },
                        _ => {}
                    }

                    if resp_chan.send(resp).is_err() {
                        error!("Sending response to the main thread failed");
                    };
                },
                Ok(DispatchMessage::Quit) => {
                    break;
                },
                Err(_) => panic!("Error receiving message in handler")
            }
        }
    }

    fn check_session(&self, msg: &WebDriverMessage) -> WebDriverResult<()> {
        match msg.session_id {
            Some(ref msg_session_id) => {
                match self.session {
                    Some(ref existing_session) => {
                        if existing_session.id != *msg_session_id {
                            Err(WebDriverError::new(
                                ErrorStatus::InvalidSessionId,
                                &format!("Got unexpected session id {} expected {}",
                                         msg_session_id,
                                         existing_session.id)[..]))
                        } else {
                            Ok(())
                        }
                    },
                    None => Ok(())
                }
            },
            None => {
                match self.session {
                    Some(_) => {
                        match msg.command {
                            WebDriverCommand::NewSession => {
                                Err(WebDriverError::new(
                                    ErrorStatus::SessionNotCreated,
                                    "Session is already started"))
                            },
                            _ => {
                                //This should be impossible
                                error!("Got a message with no session id");
                                Err(WebDriverError::new(
                                    ErrorStatus::UnknownError,
                                    "Got a command with no session?!"))
                            }
                        }
                    },
                    None => {
                        match msg.command {
                            WebDriverCommand::NewSession => Ok(()),

                            _ => Err(WebDriverError::new(
                                ErrorStatus::InvalidSessionId,
                                "Tried to run a command before creating a session"))
                        }
                    }
                }
            }
        }
    }
}

struct HttpHandler {
    chan: Mutex<Sender<DispatchMessage>>,
    api: Mutex<WebDriverHttpApi>
}

impl HttpHandler {
    fn new(api: WebDriverHttpApi, chan: Sender<DispatchMessage>) -> HttpHandler {
        HttpHandler {
            chan: Mutex::new(chan),
            api: Mutex::new(api)
        }
    }
}

impl Handler for HttpHandler {
    fn handle(&self, req: Request, res: Response) {
        let mut req = req;
        let mut res = res;

        let mut body = String::new();
        if let Method::Post = req.method {
            req.read_to_string(&mut body).unwrap();
        }
        debug!("Got request {} {:?}", req.method, req.uri);
        match req.uri {
            AbsolutePath(path) => {
                let msg_result = {
                    // The fact that this locks for basically the whole request doesn't
                    // matter as long as we are only handling one request at a time.
                    match self.api.lock() {
                        Ok(ref api) => {
                            api.decode_request(req.method, &path[..], &body[..])
                        },
                        Err(_) => return
                    }
                };
                let (status, resp_body) = match msg_result {
                    Ok(message) => {
                        let (send_res, recv_res) = channel();
                        match self.chan.lock() {
                            Ok(ref c) => {
                                let res = c.send(DispatchMessage::HandleWebDriver(message,
                                                                                send_res));
                                match res {
                                    Ok(x) => x,
                                    Err(_) => {
                                        error!("Something terrible happened");
                                        return
                                    }
                                }
                            },
                            Err(_) => {
                                error!("Something terrible happened");
                                return
                            }
                        }
                        match recv_res.recv() {
                            Ok(data) => match data {
                                Ok(response) => (StatusCode::Ok, response.to_json_string()),
                                Err(err) => (err.http_status(), err.to_json_string()),
                            },
                            Err(e) => panic!("Error reading response: {:?}", e)
                        }
                    },
                    Err(err) => {
                        (err.http_status(), err.to_json_string())
                    }
                };
                error!("Returning status {:?}", status);
                error!("Returning body {}", resp_body);
                {
                    let resp_status = res.status_mut();
                    *resp_status = status;
                }
                res.headers_mut().set(ContentLength(resp_body.len() as u64));
                let mut stream = res.start().unwrap();
                stream.write_all(&resp_body.as_bytes()).unwrap();
                stream.end().unwrap();
            },
            _ => {}
        }
    }
}

pub fn start<T: 'static+WebDriverHandler>(address: SocketAddr, handler: T) {
    let (msg_send, msg_recv) = channel();

    let api = WebDriverHttpApi::new();
    let http_handler = HttpHandler::new(api, msg_send);
    let server = Server::http(http_handler);

    let builder = thread::Builder::new().name("webdriver dispatcher".to_string());
    builder.spawn(move || {
        let mut dispatcher = Dispatcher::new(handler);
        dispatcher.run(msg_recv)
    }).unwrap();
    server.listen(&address).unwrap();
}
<|endoftext|>


<commit_before>use nitro::App;
use nitro::component::Component;
use nitro::component::Message;
use nitro::GameObject;
use axes::AxisId;

pub struct Spinny {

}

impl Component for Spinny {
    fn receive_message(&mut self, app : &mut App, game_object : &mut GameObject, message : &Message) {
        match *message {
            Message::Update{delta_time} => {
                if let Some(horizontal) = app.get_axis_value(AxisId::Horizontal as i32) {
                    *game_object.transform.mut_x() += 100.0 * delta_time * horizontal;
                }
                if let Some(vertical) = app.get_axis_value(AxisId::Vertical as i32) {
                    *game_object.transform.mut_y() += 100.0 * delta_time * vertical;
                }
            }
            _ => {}
        }
    }
}
<commit_msg>Partial commit<commit_after>use nitro::App;
use nitro::component::Component;
use nitro::component::Message;
use nitro::GameObject;
use axes::AxisId;
use actions::ActionId;

pub struct Spinny {

}

impl Component for Spinny {
    fn receive_message(&mut self, app : &mut App, game_object : &mut GameObject, message : &Message) {
        match *message {
            Message::Update{delta_time} => {
                if let Some(horizontal) = app.get_axis_value(AxisId::Horizontal as i32) {
                    *game_object.transform.mut_x() += 100.0 * delta_time * horizontal;
                }
                if let Some(vertical) = app.get_axis_value(AxisId::Vertical as i32) {
                    *game_object.transform.mut_y() += 100.0 * delta_time * vertical;
                }
                if let Some(true) = app.action_released(ActionId::Blink as i32) {
                    *game_object.transform.mut_x() += 50.0;
                }
            }
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>use std::convert;
use std::iter::repeat;

use term_grid as grid;

use column::Cell;
use dir::Dir;
use file::File;
use output::details::{Details, Table};
use output::grid::Grid;

#[derive(PartialEq, Debug, Copy, Clone)]
pub struct GridDetails {
    pub grid: Grid,
    pub details: Details,
}

impl GridDetails {
    pub fn view(&self, dir: Option<&Dir>, files: &[File]) {

        let columns = 2;

        let make_table = || {
            let mut table = Table::with_options(self.details.colours, self.details.columns.for_dir(dir));
            if self.details.header { table.add_header() }
            table
        };

        let mut tables: Vec<_> = repeat(()).map(|_| make_table()).take(columns).collect();

        for (i, file) in files.iter().enumerate() {
            tables[i % columns].add_file(file, 0, false, false);
        }

        let direction = if self.grid.across { grid::Direction::LeftToRight }
                                       else { grid::Direction::TopToBottom };

        let mut grid = grid::Grid::new(grid::GridOptions {
            direction:        direction,
            separator_width:  2,
        });

        for table in tables {
            for cell in table.print_table(false, false).into_iter() {
                grid.add(cell.into());
            }
        }

        print!("{}", grid.fit_into_columns(columns));
    }
}

impl convert::From<Cell> for grid::Cell {
    fn from(input: Cell) -> Self {
        grid::Cell {
            contents: input.text,
            width:    input.length,
        }
    }
}
<commit_msg>Adapt the long grid view to the console width<commit_after>use std::iter::repeat;

use term_grid as grid;

use column::Cell;
use dir::Dir;
use file::File;
use output::details::{Details, Table};
use output::grid::Grid;

#[derive(PartialEq, Debug, Copy, Clone)]
pub struct GridDetails {
    pub grid: Grid,
    pub details: Details,
}

impl GridDetails {
    pub fn view(&self, dir: Option<&Dir>, files: &[File]) {
        let mut last_working_table = self.make_grid(1, dir, files);

        for column_count in 2.. {
            let grid = self.make_grid(column_count, dir, files);

            if grid.fit_into_columns(column_count).width() <= self.grid.console_width {
                last_working_table = grid;
            }
            else {
                print!("{}", last_working_table.fit_into_columns(column_count - 1));
                return;
            }
        }
    }

    pub fn make_grid(&self, column_count: usize, dir: Option<&Dir>, files: &[File]) -> grid::Grid {
        let make_table = || {
            let mut table = Table::with_options(self.details.colours, self.details.columns.for_dir(dir));
            if self.details.header { table.add_header() }
            table
        };

        let mut tables: Vec<_> = repeat(()).map(|_| make_table()).take(column_count).collect();

        for (i, file) in files.iter().enumerate() {
            tables[i % column_count].add_file(file, 0, false, false);
        }

        let direction = grid::Direction::LeftToRight;

        let mut grid = grid::Grid::new(grid::GridOptions {
            direction:        direction,
            separator_width:  4,
        });

        let columns: Vec<_> = tables.iter().map(|t| t.print_table(false, false)).collect();

        for row in 0 .. columns[0].len() {
            for column in columns.iter() {
                if row < column.len() {
                    let cell = grid::Cell {
                        contents: column[row].text.clone(),
                        width:    column[row].length,
                    };

                    grid.add(cell);
                }
            }
        }

        grid
    }
}
<|endoftext|>


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

use std::cmp::Ordering;

use super::symbol_range::*;

///
/// A symbol map maps from one set of symbol ranges to another
///
pub struct SymbolMap<Symbol: PartialOrd+Clone> {
    // Ranges in this symbol map
    ranges: Vec<SymbolRange<Symbol>>,
}

impl<Symbol: PartialOrd+Clone> SymbolMap<Symbol> {
    ///
    /// Creates a new symbol map
    ///
    pub fn new() -> SymbolMap<Symbol> {
        SymbolMap { ranges: vec![] }
    }

    ///
    /// Orders two symbols (makes unordered symbols equal)
    ///
    #[inline]
    fn order_symbols(a: &Symbol, b: &Symbol) -> Ordering {
        if let Some(order) = a.partial_cmp(b) {
            order
        } else {
            Ordering::Equal
        }
    }

    ///
    /// Orders two symbol ranges
    ///
    #[inline]
    fn order_ranges(a: &SymbolRange<Symbol>, b: &SymbolRange<Symbol>) -> Ordering {
        let ordering = SymbolMap::order_symbols(&a.lowest, &b.lowest);

        if ordering == Ordering::Equal {
            SymbolMap::order_symbols(&a.highest, &b.highest)
        } else {
            ordering
        }
    }

    ///
    /// Adds a range to those that are known about by this object
    ///
    pub fn add_range(&mut self, range: &SymbolRange<Symbol>) {
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Insert the range if it is not already in the map
        if let Err(insertion_pos) = existing {
            self.ranges.insert(insertion_pos, range.clone());
        }
    }

    ///
    /// Finds the ranges in this map that overlap the target ranges
    ///
    pub fn find_overlapping_ranges(&self, range: &SymbolRange<Symbol>) -> Vec<&SymbolRange<Symbol>> {
        let mut result = vec![];

        // Find the first range that matches (or the insertion position, which should be the first range wit a lowest value higher than the target range)
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Start returning values from here
        let mut pos = match existing {
            Ok(found_position) => found_position,
            Err(insert_position) => insert_position
        };

        // Move backwards if the previous position overlaps this one
        if pos > 0 && self.ranges[pos-1].highest >= range.lowest {
            pos -= 1;
        }

        // TODO: can we construct a set of ranges such that one is missed here? Think maybe we can
        while pos < self.ranges.len() && self.ranges[pos].lowest <= range.highest {
            result.push(&self.ranges[pos]);
            pos += 1;
        }

        result
    }

    ///
    /// Creates a non-overlapping range from an overlapping one
    ///
    pub fn to_non_overlapping_map(&self) -> SymbolMap<Symbol> {
        // Create a vector of all the range symbols
        let mut range_symbols: Vec<Symbol> = self.ranges.iter()
            .map(|r| r.lowest.clone())
            .chain(self.ranges.iter().map(|r| r.highest.clone()))
            .collect();

        // Sort and dedupe (we'll get pairs of ranges)
        range_symbols.sort_by(SymbolMap::order_symbols);
        range_symbols.dedup();

        // Generate a new symbol map with these ranges
        // They'll overlap with the last value, which should be OK if following the rules for adjacent ranges in symbol_range.rs
        let mut result = vec![];
        for index in 0..range_symbols.len()-1 {
            result.push(SymbolRange::new(range_symbols[index].clone(), range_symbols[index+1].clone()));
        }

        // We already sorted everything, so bypass the usual 'add' method (which sorts as it goes)
        SymbolMap { ranges: result }
    }
}

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

    #[test]
    fn can_lookup_overlapping_ranges() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let bottom = map.find_overlapping_ranges(&SymbolRange::new(0, 1));
        let all    = map.find_overlapping_ranges(&SymbolRange::new(1, 3));
        let top    = map.find_overlapping_ranges(&SymbolRange::new(6, 6));

        assert!(bottom == vec![&SymbolRange::new(0, 4)]);
        assert!(all == vec![&SymbolRange::new(0, 4), &SymbolRange::new(2, 5), &SymbolRange::new(3, 6)]);
        assert!(top == vec![&SymbolRange::new(3, 6)]);
    }

    #[test]
    fn can_lookup_mid_range() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(5, 10));
        map.add_range(&SymbolRange::new(11, 15));

        let mid = map.find_overlapping_ranges(&SymbolRange::new(1, 3));

        assert!(mid == vec![&SymbolRange::new(0, 4)]);
    }

    #[test]
    fn works_with_duplicate_lower_values() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 2));
        map.add_range(&SymbolRange::new(0, 3));

        let all    = map.find_overlapping_ranges(&SymbolRange::new(0, 1));

        println!("With duplicate lower values is: {:?}", all);

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(0, 3)]);
    }

    #[test]
    fn obeys_adjacency_rule() {
        let mut map = SymbolMap::new();

        // By the adjacency rule for symbol ranges (in symbol_range.rs), '4' here is only in the upper range
        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(4, 8));

        let top = map.find_overlapping_ranges(&SymbolRange::new(4, 4));

        assert!(top == vec![&SymbolRange::new(4, 8)]);
    }

    #[test]
    fn can_get_non_overlapping_map() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(2, 3), &SymbolRange::new(3, 4), &SymbolRange::new(4, 5), &SymbolRange::new(5, 6)]);
    }
}
<commit_msg>Apply the adjacency rule manually<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

use std::cmp::Ordering;

use super::symbol_range::*;

///
/// A symbol map maps from one set of symbol ranges to another
///
pub struct SymbolMap<Symbol: PartialOrd+Clone> {
    // Ranges in this symbol map
    ranges: Vec<SymbolRange<Symbol>>,
}

impl<Symbol: PartialOrd+Clone> SymbolMap<Symbol> {
    ///
    /// Creates a new symbol map
    ///
    pub fn new() -> SymbolMap<Symbol> {
        SymbolMap { ranges: vec![] }
    }

    ///
    /// Orders two symbols (makes unordered symbols equal)
    ///
    #[inline]
    fn order_symbols(a: &Symbol, b: &Symbol) -> Ordering {
        if let Some(order) = a.partial_cmp(b) {
            order
        } else {
            Ordering::Equal
        }
    }

    ///
    /// Orders two symbol ranges
    ///
    #[inline]
    fn order_ranges(a: &SymbolRange<Symbol>, b: &SymbolRange<Symbol>) -> Ordering {
        let ordering = SymbolMap::order_symbols(&a.lowest, &b.lowest);

        if ordering == Ordering::Equal {
            SymbolMap::order_symbols(&a.highest, &b.highest)
        } else {
            ordering
        }
    }

    ///
    /// Adds a range to those that are known about by this object
    ///
    pub fn add_range(&mut self, range: &SymbolRange<Symbol>) {
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Insert the range if it is not already in the map
        if let Err(insertion_pos) = existing {
            self.ranges.insert(insertion_pos, range.clone());
        }
    }

    ///
    /// Finds the ranges in this map that overlap the target ranges
    ///
    pub fn find_overlapping_ranges(&self, range: &SymbolRange<Symbol>) -> Vec<&SymbolRange<Symbol>> {
        let mut result = vec![];

        // Find the first range that matches (or the insertion position, which should be the first range wit a lowest value higher than the target range)
        let existing = self.ranges.binary_search_by(|test_range| { SymbolMap::order_ranges(test_range, range) });

        // Start returning values from here
        let mut pos = match existing {
            Ok(found_position) => found_position,
            Err(insert_position) => insert_position
        };

        // Move backwards if the previous position overlaps this one
        if pos > 0 && self.ranges[pos-1].highest >= range.lowest {
            pos -= 1;
        }

        // Apply the adjacency rule (if this range starts where the next range starts, then use the next range)
        if pos+1 < self.ranges.len() && self.ranges[pos].highest == self.ranges[pos+1].lowest && self.ranges[pos+1].lowest == range.lowest {
            pos += 1;
        }

        // TODO: can we construct a set of ranges such that one is missed here? Think maybe we can
        while pos < self.ranges.len() && self.ranges[pos].lowest <= range.highest {
            result.push(&self.ranges[pos]);
            pos += 1;
        }

        result
    }

    ///
    /// Creates a non-overlapping range from an overlapping one
    ///
    pub fn to_non_overlapping_map(&self) -> SymbolMap<Symbol> {
        // Create a vector of all the range symbols
        let mut range_symbols: Vec<Symbol> = self.ranges.iter()
            .map(|r| r.lowest.clone())
            .chain(self.ranges.iter().map(|r| r.highest.clone()))
            .collect();

        // Sort and dedupe (we'll get pairs of ranges)
        range_symbols.sort_by(SymbolMap::order_symbols);
        range_symbols.dedup();

        // Generate a new symbol map with these ranges
        // They'll overlap with the last value, which should be OK if following the rules for adjacent ranges in symbol_range.rs
        let mut result = vec![];
        for index in 0..range_symbols.len()-1 {
            result.push(SymbolRange::new(range_symbols[index].clone(), range_symbols[index+1].clone()));
        }

        // We already sorted everything, so bypass the usual 'add' method (which sorts as it goes)
        SymbolMap { ranges: result }
    }
}

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

    #[test]
    fn can_lookup_overlapping_ranges() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let bottom = map.find_overlapping_ranges(&SymbolRange::new(0, 1));
        let all    = map.find_overlapping_ranges(&SymbolRange::new(1, 3));
        let top    = map.find_overlapping_ranges(&SymbolRange::new(6, 6));

        assert!(bottom == vec![&SymbolRange::new(0, 4)]);
        assert!(all == vec![&SymbolRange::new(0, 4), &SymbolRange::new(2, 5), &SymbolRange::new(3, 6)]);
        assert!(top == vec![&SymbolRange::new(3, 6)]);
    }

    #[test]
    fn can_lookup_mid_range() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(5, 10));
        map.add_range(&SymbolRange::new(11, 15));

        let mid = map.find_overlapping_ranges(&SymbolRange::new(1, 3));

        assert!(mid == vec![&SymbolRange::new(0, 4)]);
    }

    #[test]
    fn works_with_duplicate_lower_values() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 2));
        map.add_range(&SymbolRange::new(0, 3));

        let all    = map.find_overlapping_ranges(&SymbolRange::new(0, 1));

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(0, 3)]);
    }

    #[test]
    fn obeys_adjacency_rule() {
        let mut map = SymbolMap::new();

        // By the adjacency rule for symbol ranges (in symbol_range.rs), '4' here is only in the upper range
        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(4, 8));

        let top = map.find_overlapping_ranges(&SymbolRange::new(4, 4));

        assert!(top == vec![&SymbolRange::new(4, 8)]);
    }

    #[test]
    fn can_get_non_overlapping_map() {
        let mut map = SymbolMap::new();

        map.add_range(&SymbolRange::new(0, 4));
        map.add_range(&SymbolRange::new(2, 5));
        map.add_range(&SymbolRange::new(3, 6));

        let non_overlapping = map.to_non_overlapping_map();

        let all = non_overlapping.find_overlapping_ranges(&SymbolRange::new(0, 6));

        assert!(all == vec![&SymbolRange::new(0, 2), &SymbolRange::new(2, 3), &SymbolRange::new(3, 4), &SymbolRange::new(4, 5), &SymbolRange::new(5, 6)]);
    }
}
<|endoftext|>


<commit_before>use nom;
use nom::{Err, IResult};

use metadata;

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};
use utility::{ErrorKind, ByteStream, ReadStream, StreamProducer};

use std::io;
use std::fs::File;

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

pub struct Stream {
  info: StreamInfo,
  pub metadata: Vec<Metadata>,
  pub frames: Vec<Frame>,
  state: ParserState,
}

named!(pub stream_parser <&[u8], Stream>,
  chain!(
    blocks: metadata_parser ~
    frames: many1!(apply!(frame_parser, &blocks.0)),
    move|| {
      Stream {
        info: blocks.0,
        metadata: blocks.1,
        frames: frames,
        state: ParserState::Marker,
      }
    }
  )
);

impl Stream {
  pub fn new() -> Stream {
    Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
    }
  }

  pub fn info(&self) -> StreamInfo {
    self.info
  }

  pub fn from_file(filename: &str) -> io::Result<Stream> {
    File::open(filename).and_then(|file| {
      let mut producer = ReadStream::new(file);
      let error_str    = format!("parser: couldn't parse the given file {}",
                                 filename);

      Stream::from_stream_producer(&mut producer, &error_str)
    })
  }

  fn from_stream_producer<P>(producer: &mut P, error_str: &str)
                             -> io::Result<Stream>
   where P: StreamProducer {
    let mut is_error = false;
    let mut stream   = Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
    };

    loop {
      match stream.handle(producer) {
        Ok(_)                         => break,
        Err(ErrorKind::EndOfInput)    => break,
        Err(ErrorKind::Consumed(_))   => continue,
        Err(ErrorKind::Incomplete(_)) => continue,
        Err(_)                        => {
          is_error = true;

          break;
        }
      }
    }

    if !is_error {
      Ok(stream)
    } else {
      Err(io::Error::new(io::ErrorKind::InvalidData, error_str))
    }
  }

  fn handle_marker<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(0);

    match tag!(input, "fLaC") {
      IResult::Done(i, _)    => {
        self.state = ParserState::Metadata;

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_metadata<'a>(&mut self, input: &'a [u8])
                         -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(1);

    match metadata::block(input) {
      IResult::Done(i, block) => {
        let is_last = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_frame<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(2);

    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        self.frames.push(frame);

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  pub fn handle<S: StreamProducer>(&mut self, stream: &mut S)
                                   -> Result<(), ErrorKind> {
    stream.parse(|input| {
      match self.state {
        ParserState::Marker   => self.handle_marker(input),
        ParserState::Metadata => self.handle_metadata(input),
        ParserState::Frame    => self.handle_frame(input),
      }
    })
  }
}
<commit_msg>Add `Stream::from_buffer` initializer<commit_after>use nom;
use nom::{Err, IResult};

use metadata;

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};
use utility::{ErrorKind, ByteStream, ReadStream, StreamProducer};

use std::io;
use std::fs::File;

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

pub struct Stream {
  info: StreamInfo,
  pub metadata: Vec<Metadata>,
  pub frames: Vec<Frame>,
  state: ParserState,
}

named!(pub stream_parser <&[u8], Stream>,
  chain!(
    blocks: metadata_parser ~
    frames: many1!(apply!(frame_parser, &blocks.0)),
    move|| {
      Stream {
        info: blocks.0,
        metadata: blocks.1,
        frames: frames,
        state: ParserState::Marker,
      }
    }
  )
);

impl Stream {
  pub fn new() -> Stream {
    Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
    }
  }

  pub fn info(&self) -> StreamInfo {
    self.info
  }

  pub fn from_file(filename: &str) -> io::Result<Stream> {
    File::open(filename).and_then(|file| {
      let mut producer = ReadStream::new(file);
      let error_str    = format!("parser: couldn't parse the given file {}",
                                 filename);

      Stream::from_stream_producer(&mut producer, &error_str)
    })
  }

  pub fn from_buffer(buffer: &[u8]) -> io::Result<Stream> {
    let mut producer = ByteStream::new(buffer);
    let error_str    = "parser: couldn't parse the buffer";

    Stream::from_stream_producer(&mut producer, error_str)
  }

  fn from_stream_producer<P>(producer: &mut P, error_str: &str)
                             -> io::Result<Stream>
   where P: StreamProducer {
    let mut is_error = false;
    let mut stream   = Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
    };

    loop {
      match stream.handle(producer) {
        Ok(_)                         => break,
        Err(ErrorKind::EndOfInput)    => break,
        Err(ErrorKind::Consumed(_))   => continue,
        Err(ErrorKind::Incomplete(_)) => continue,
        Err(_)                        => {
          is_error = true;

          break;
        }
      }
    }

    if !is_error {
      Ok(stream)
    } else {
      Err(io::Error::new(io::ErrorKind::InvalidData, error_str))
    }
  }

  fn handle_marker<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(0);

    match tag!(input, "fLaC") {
      IResult::Done(i, _)    => {
        self.state = ParserState::Metadata;

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_metadata<'a>(&mut self, input: &'a [u8])
                         -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(1);

    match metadata::block(input) {
      IResult::Done(i, block) => {
        let is_last = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_frame<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(2);

    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        self.frames.push(frame);

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  pub fn handle<S: StreamProducer>(&mut self, stream: &mut S)
                                   -> Result<(), ErrorKind> {
    stream.parse(|input| {
      match self.state {
        ParserState::Marker   => self.handle_marker(input),
        ParserState::Metadata => self.handle_metadata(input),
        ParserState::Frame    => self.handle_frame(input),
      }
    })
  }
}
<|endoftext|>


<commit_before>pub use font_cache::FontCache;

use au = gfx::geometry;
use au::au;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use glyph::GlyphIndex;
use libc::{ c_int, c_double, c_ulong };
use native_font::NativeFont;
use ptr::{null, addr_of};
use text::text_run::TextRun;
use vec_to_ptr = vec::raw::to_ptr;

// Used to abstract over the shaper's choice of fixed int representation.
type FractionalPixel = float;

/**
A font handle. Layout can use this to calculate glyph metrics
and the renderer can use it to render text.
*/
struct Font {
    // A back reference to keep the library alive
    lib: @FontCache,
    fontbuf: @~[u8],
    native_font: NativeFont,
    metrics: FontMetrics,
}

struct RunMetrics {
    // may be negative due to negative width
    advance_width: au,

    ascent: au, // nonzero
    descent: au, // nonzero

    // this bounding box is relative to the left origin baseline.
    // so, bounding_box.position.y = -ascent
    bounding_box: Rect<au>
}

// Public API
pub trait FontMethods {
    fn measure_text(run: &TextRun, offset: uint, length: uint) -> RunMetrics;

    fn buf(&self) -> @~[u8];
    // these are used to get glyphs and advances in the case that the
    // shaper can't figure it out.
    fn glyph_index(char) -> Option<GlyphIndex>;
    fn glyph_h_advance(GlyphIndex) -> FractionalPixel;
}

pub impl Font : FontMethods {
    fn measure_text(run: &TextRun, offset: uint, length: uint) -> RunMetrics {
        // TODO: alter advance direction for RTL
        // TODO(Issue #98): using inter-char and inter-word spacing settings  when measuring text
        let mut advance = au(0);
        do run.glyphs.iter_glyphs_for_range(offset, length) |_i, glyph| {
            advance += glyph.advance();
        }
        let mut bounds = Rect(Point2D(au(0), -self.metrics.ascent),
                          Size2D(advance, self.metrics.ascent + self.metrics.descent));

        // TODO(Issue #125): support loose and tight bounding boxes; using the
        // ascent+descent and advance is sometimes too generous and
        // looking at actual glyph extents can yield a tighter box.

        let metrics = RunMetrics { advance_width: advance,
                                  bounding_box: bounds,
                                  ascent: self.metrics.ascent,
                                  descent: self.metrics.descent,
                                 };
        debug!("Measured text range '%s' with metrics:", run.text.substr(offset, length));
        debug!("%?", metrics);

        return metrics;
    }

    fn buf(&self) -> @~[u8] {
        self.fontbuf
    }

    fn glyph_index(codepoint: char) -> Option<GlyphIndex> {
        self.native_font.glyph_index(codepoint)
    }

    fn glyph_h_advance(glyph: GlyphIndex) -> FractionalPixel {
        match self.native_font.glyph_h_advance(glyph) {
          Some(adv) => adv,
          None => /* FIXME: Need fallback strategy */ 10f as FractionalPixel
        }
    }
}

// TODO: who should own fontbuf?
fn Font(lib: @FontCache, fontbuf: @~[u8], native_font: NativeFont) -> Font {
    let metrics = native_font.get_metrics();

    Font {
        lib: lib,
        fontbuf : fontbuf,
        metrics: move metrics,
        native_font : move native_font,
    }
}

struct FontMetrics {
    underline_size:   au,
    underline_offset: au,
    leading:          au,
    x_height:         au,
    em_size:          au,
    ascent:           au,
    descent:          au,
    max_advance:      au
}

const TEST_FONT: [u8 * 33004] = #include_bin("JosefinSans-SemiBold.ttf");

fn test_font_bin() -> ~[u8] {
    return vec::from_fn(33004, |i| TEST_FONT[i]);
}

fn should_destruct_on_fail_without_leaking() {
    #[test];
    #[should_fail];

    let lib = FontCache();
    let _font = lib.get_test_font();
    fail;
}

fn should_get_glyph_indexes() {
    #[test];

    let lib = FontCache();
    let font = lib.get_test_font();
    let glyph_idx = font.glyph_index('w');
    assert glyph_idx == Some(40u as GlyphIndex);
}

fn should_get_glyph_advance() {
    #[test];
    #[ignore];

    let lib = FontCache();
    let font = lib.get_test_font();
    let x = font.glyph_h_advance(40u as GlyphIndex);
    assert x == 15f || x == 16f;
}

// Testing thread safety
fn should_get_glyph_advance_stress() {
    #[test];
    #[ignore];

    let mut ports = ~[];

    for iter::repeat(100) {
        let (chan, port) = pipes::stream();
        ports += [@move port];
        do task::spawn {
            let lib = FontCache();
            let font = lib.get_test_font();
            let x = font.glyph_h_advance(40u as GlyphIndex);
            assert x == 15f || x == 16f;
            chan.send(());
        }
    }

    for ports.each |port| {
        port.recv();
    }
}

fn should_be_able_to_create_instances_in_multiple_threads() {
    #[test];

    for iter::repeat(10u) {
        do task::spawn {
            let lib = FontCache();
            let _font = lib.get_test_font();
        }
    }
}

<commit_msg>Don't measure advance zero-length text.<commit_after>pub use font_cache::FontCache;

use au = gfx::geometry;
use au::au;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use glyph::GlyphIndex;
use libc::{ c_int, c_double, c_ulong };
use native_font::NativeFont;
use ptr::{null, addr_of};
use text::text_run::TextRun;
use vec_to_ptr = vec::raw::to_ptr;

// Used to abstract over the shaper's choice of fixed int representation.
type FractionalPixel = float;

/**
A font handle. Layout can use this to calculate glyph metrics
and the renderer can use it to render text.
*/
struct Font {
    // A back reference to keep the library alive
    lib: @FontCache,
    fontbuf: @~[u8],
    native_font: NativeFont,
    metrics: FontMetrics,
}

struct RunMetrics {
    // may be negative due to negative width
    advance_width: au,

    ascent: au, // nonzero
    descent: au, // nonzero

    // this bounding box is relative to the left origin baseline.
    // so, bounding_box.position.y = -ascent
    bounding_box: Rect<au>
}

// Public API
pub trait FontMethods {
    fn measure_text(run: &TextRun, offset: uint, length: uint) -> RunMetrics;

    fn buf(&self) -> @~[u8];
    // these are used to get glyphs and advances in the case that the
    // shaper can't figure it out.
    fn glyph_index(char) -> Option<GlyphIndex>;
    fn glyph_h_advance(GlyphIndex) -> FractionalPixel;
}

pub impl Font : FontMethods {
    fn measure_text(run: &TextRun, offset: uint, length: uint) -> RunMetrics {
        assert offset < run.text.len();
        assert offset + length <= run.text.len();

        // TODO: alter advance direction for RTL
        // TODO(Issue #98): using inter-char and inter-word spacing settings  when measuring text
        let mut advance = au(0);
        if length > 0 {
            do run.glyphs.iter_glyphs_for_range(offset, length) |_i, glyph| {
                advance += glyph.advance();
            }
        }
        let mut bounds = Rect(Point2D(au(0), -self.metrics.ascent),
                              Size2D(advance, self.metrics.ascent + self.metrics.descent));

        // TODO(Issue #125): support loose and tight bounding boxes; using the
        // ascent+descent and advance is sometimes too generous and
        // looking at actual glyph extents can yield a tighter box.

        let metrics = RunMetrics { advance_width: advance,
                                  bounding_box: bounds,
                                  ascent: self.metrics.ascent,
                                  descent: self.metrics.descent,
                                 };
        debug!("Measured text range '%s' with metrics:", run.text.substr(offset, length));
        debug!("%?", metrics);

        return metrics;
    }

    fn buf(&self) -> @~[u8] {
        self.fontbuf
    }

    fn glyph_index(codepoint: char) -> Option<GlyphIndex> {
        self.native_font.glyph_index(codepoint)
    }

    fn glyph_h_advance(glyph: GlyphIndex) -> FractionalPixel {
        match self.native_font.glyph_h_advance(glyph) {
          Some(adv) => adv,
          None => /* FIXME: Need fallback strategy */ 10f as FractionalPixel
        }
    }
}

// TODO: who should own fontbuf?
fn Font(lib: @FontCache, fontbuf: @~[u8], native_font: NativeFont) -> Font {
    let metrics = native_font.get_metrics();

    Font {
        lib: lib,
        fontbuf : fontbuf,
        metrics: move metrics,
        native_font : move native_font,
    }
}

struct FontMetrics {
    underline_size:   au,
    underline_offset: au,
    leading:          au,
    x_height:         au,
    em_size:          au,
    ascent:           au,
    descent:          au,
    max_advance:      au
}

const TEST_FONT: [u8 * 33004] = #include_bin("JosefinSans-SemiBold.ttf");

fn test_font_bin() -> ~[u8] {
    return vec::from_fn(33004, |i| TEST_FONT[i]);
}

fn should_destruct_on_fail_without_leaking() {
    #[test];
    #[should_fail];

    let lib = FontCache();
    let _font = lib.get_test_font();
    fail;
}

fn should_get_glyph_indexes() {
    #[test];

    let lib = FontCache();
    let font = lib.get_test_font();
    let glyph_idx = font.glyph_index('w');
    assert glyph_idx == Some(40u as GlyphIndex);
}

fn should_get_glyph_advance() {
    #[test];
    #[ignore];

    let lib = FontCache();
    let font = lib.get_test_font();
    let x = font.glyph_h_advance(40u as GlyphIndex);
    assert x == 15f || x == 16f;
}

// Testing thread safety
fn should_get_glyph_advance_stress() {
    #[test];
    #[ignore];

    let mut ports = ~[];

    for iter::repeat(100) {
        let (chan, port) = pipes::stream();
        ports += [@move port];
        do task::spawn {
            let lib = FontCache();
            let font = lib.get_test_font();
            let x = font.glyph_h_advance(40u as GlyphIndex);
            assert x == 15f || x == 16f;
            chan.send(());
        }
    }

    for ports.each |port| {
        port.recv();
    }
}

fn should_be_able_to_create_instances_in_multiple_threads() {
    #[test];

    for iter::repeat(10u) {
        do task::spawn {
            let lib = FontCache();
            let _font = lib.get_test_font();
        }
    }
}

<|endoftext|>


<commit_before>use crate::handler::ActiveOutput;
use std::{
    cell::{Cell, RefCell},
    rc::Rc,
};

use linked_hash_map::LinkedHashMap;
use smithay::{
    reexports::wayland_server::{
        protocol::{wl_output, wl_surface::WlSurface},
        Display,
    },
    utils::{Logical, Size},
    wayland::{
        output::{Mode, PhysicalProperties},
        seat::Seat,
    },
};

use crate::shell::{layout::Layout, output::Output, window::Kind};

pub struct Workspaces {
    display: Rc<RefCell<Display>>,
    spaces: LinkedHashMap<u8, Box<dyn Layout>>,
    outputs: Vec<Output>,
}

struct ActiveWorkspace(Cell<u8>);

impl ActiveWorkspace {
    fn new(val: u8) -> ActiveWorkspace {
        ActiveWorkspace(Cell::new(val))
    }
}

impl Workspaces {
    pub fn new(display: Rc<RefCell<Display>>) -> Workspaces {
        Workspaces {
            display,
            spaces: LinkedHashMap::new(),
            outputs: Vec::new(),
        }
    }

    fn next_available(&mut self, size: Size<i32, Logical>) -> u8 {
        for i in 1..::std::u8::MAX {
            if let Some(space) = self.spaces.get_mut(&i) {
                let mut available = true;
                for output in &self.outputs {
                    if output
                        .userdata()
                        .get::<ActiveWorkspace>()
                        .map(|x| x.0.get() as i32)
                        .unwrap()
                        == i as i32
                    {
                        available = false;
                    }
                }
                if available {
                    space.rearrange(&size);
                    return i;
                }
            } else {
                self.spaces
                    .insert(i, Box::new(super::layout::Floating::new(size)));
                return i;
            }
        }
        0
    }

    pub fn arrange(&mut self) {
        // Recalculate the outputs location
        // TODO: handle vertical stacking monitors later
        let mut output_x = 0;
        for output in self.outputs.iter_mut() {
            output.set_location((output_x, 0).into());
            output_x += output.size().w;
        }
    }

    pub fn width(&self) -> i32 {
        self.outputs.iter().map(|x| x.size().w).sum()
    }

    pub fn add_output<N>(&mut self, name: N, physical: PhysicalProperties, mode: Mode) -> &Output
    where
        N: AsRef<str>,
    {
        // Append the output to the end of the existing
        // outputs by placing it after the current overall
        // width
        let location = (self.width(), 0);

        let output = Output::new(
            name,
            location.into(),
            &mut *self.display.borrow_mut(),
            physical,
            mode,
        );
        let logical_size = output.geometry().size;
        let workspace = self.next_available(logical_size);
        slog_scope::info!("New output: {:?}", output);
        slog_scope::debug!(
            "Attaching workspace {} to output {}",
            workspace,
            output.name()
        );
        output
            .userdata()
            .insert_if_missing(|| ActiveWorkspace::new(workspace));
        self.outputs.push(output);

        // We call arrange here albeit the output is only appended and
        // this would not affect windows, but arrange could re-organize
        // outputs from a configuration.
        self.arrange();

        self.outputs.last().unwrap()
    }

    pub fn retain_outputs<F>(&mut self, f: F)
    where
        F: Fn(&Output) -> bool,
    {
        for output in self.outputs.iter().filter(|o| !f(*o)) {
            let workspace = output.userdata().get::<ActiveWorkspace>().unwrap().0.get();
            if self.spaces.get(&workspace).unwrap().is_empty() {
                slog_scope::debug!("Destroying empty workspace: {}", workspace);
                self.spaces.remove(&workspace);
            }
        }
        self.outputs.retain(f);
        self.arrange();
    }

    pub fn remove_output_by_name(&mut self, name: &str) {
        self.retain_outputs(|o| o.name() != name);
    }

    pub fn num_outputs(&self) -> usize {
        self.outputs.len()
    }

    pub fn toplevel_by_surface(&mut self, surface: &WlSurface) -> Option<Kind> {
        for (_, space) in self.spaces.iter_mut() {
            if let Some(window) = space
                .windows()
                .find(|k| k.get_surface().map(|x| x == surface).unwrap_or(false))
            {
                return Some(window);
            }
        }
        None
    }

    pub fn idx_by_output_name<N: AsRef<str>>(&self, name: N) -> Option<u8> {
        self.outputs
            .iter()
            .find(|o| o.name() == name.as_ref())
            .and_then(|x| x.userdata().get::<ActiveWorkspace>())
            .map(|x| x.0.get())
    }

    pub fn spaces<'a>(&'a mut self) -> impl Iterator<Item=&'a mut Box<dyn Layout>>
    {
        self.spaces.iter_mut().map(|(_, layout)| layout)
    }

    pub fn space_by_output_name<'a, N>(&'a mut self, name: N) -> Option<&'a mut Box<dyn Layout>>
    where
        N: AsRef<str>,
    {
        let active = self.idx_by_output_name(name);
        if let Some(a) = active {
            self.spaces.get_mut(&a)
        } else {
            None
        }
    }

    pub fn space_by_seat(&mut self, seat: &Seat) -> Option<&mut Box<dyn Layout>> {
        if let Some(name) = seat.user_data().get::<ActiveOutput>() {
            let exists = self.space_by_output_name(&*name.0.borrow()).is_some();
            if exists {
                return self.space_by_output_name(&*name.0.borrow());
            }
        }
        self.spaces.iter_mut().map(|(_, v)| v).next()
    }

    pub fn space_by_surface(&mut self, surface: &WlSurface) -> Option<&mut Box<dyn Layout>> {
        for (_, space) in self.spaces.iter_mut() {
            if space
                .windows()
                .any(|k| k.get_surface().map(|x| x == surface).unwrap_or(false))
            {
                return Some(space);
            }
        }
        None
    }

    pub fn space_by_idx(&mut self, idx: u8) -> &mut Box<dyn Layout> {
        self.spaces
            .entry(idx)
            .or_insert(Box::new(super::layout::Floating::new((0, 0))))
    }

    pub fn output<F>(&mut self, f: F) -> Option<&mut Output>
    where
        F: FnMut(&&mut Output) -> bool,
    {
        self.outputs.iter_mut().find(f)
    }

    pub fn output_by_wl(&mut self, output: &wl_output::WlOutput) -> Option<&mut Output> {
        self.output(|o| o.owns(output))
    }

    pub fn output_by_name<N>(&mut self, name: N) -> Option<&mut Output>
    where
        N: AsRef<str>,
    {
        self.output(|o| o.name() == name.as_ref())
    }

    pub fn switch_workspace(&mut self, seat: &Seat, idx: u8) {
        let output_name = &seat.user_data().get::<ActiveOutput>().unwrap().0;
        let current_idx = self.idx_by_output_name(&*output_name.borrow()).unwrap();
        if current_idx != idx {
            if let Some(output) =
                self.output(|o| o.userdata().get::<ActiveWorkspace>().unwrap().0.get() == idx)
            {
                *output_name.borrow_mut() = String::from(output.name());
            } else {
                let output = self.output_by_name(&*output_name.borrow()).unwrap();
                slog_scope::debug!("Attaching workspace {} to output {}", idx, output.name());
                output
                    .userdata()
                    .get::<ActiveWorkspace>()
                    .unwrap()
                    .0
                    .set(idx);
                let size = output.size();
                let _ = self
                    .spaces
                    .entry(idx)
                    .or_insert(Box::new(super::layout::Floating::new(size)));
            }
        }
        if self.space_by_idx(current_idx).is_empty() {
            slog_scope::debug!("Destroying empty workspace: {}", current_idx);
            self.spaces.remove(&current_idx);
        }
    }
}
<commit_msg>shell: Fixup crashes in multi-monitor setups<commit_after>use crate::handler::ActiveOutput;
use std::{
    cell::{Cell, RefCell},
    rc::Rc,
};

use linked_hash_map::LinkedHashMap;
use smithay::{
    reexports::wayland_server::{
        protocol::{wl_output, wl_surface::WlSurface},
        Display,
    },
    utils::{Logical, Size},
    wayland::{
        output::{Mode, PhysicalProperties},
        seat::Seat,
    },
};

use crate::shell::{layout::Layout, output::Output, window::Kind};

pub struct Workspaces {
    display: Rc<RefCell<Display>>,
    spaces: LinkedHashMap<u8, Box<dyn Layout>>,
    outputs: Vec<Output>,
}

struct ActiveWorkspace(Cell<u8>);

impl ActiveWorkspace {
    fn new(val: u8) -> ActiveWorkspace {
        ActiveWorkspace(Cell::new(val))
    }
}

impl Workspaces {
    pub fn new(display: Rc<RefCell<Display>>) -> Workspaces {
        Workspaces {
            display,
            spaces: LinkedHashMap::new(),
            outputs: Vec::new(),
        }
    }

    fn next_available(&mut self, size: Size<i32, Logical>) -> u8 {
        for i in 1..::std::u8::MAX {
            if let Some(space) = self.spaces.get_mut(&i) {
                let mut available = true;
                for output in &self.outputs {
                    if output
                        .userdata()
                        .get::<ActiveWorkspace>()
                        .map(|x| x.0.get() as i32)
                        .unwrap()
                        == i as i32
                    {
                        available = false;
                    }
                }
                if available {
                    space.rearrange(&size);
                    return i;
                }
            } else {
                self.spaces
                    .insert(i, Box::new(super::layout::Floating::new(size)));
                return i;
            }
        }
        0
    }

    pub fn arrange(&mut self) {
        // Recalculate the outputs location
        // TODO: handle vertical stacking monitors later
        let mut output_x = 0;
        for output in self.outputs.iter_mut() {
            output.set_location((output_x, 0).into());
            output_x += output.size().w;
        }
    }

    pub fn width(&self) -> i32 {
        self.outputs.iter().map(|x| x.size().w).sum()
    }

    pub fn add_output<N>(&mut self, name: N, physical: PhysicalProperties, mode: Mode) -> &Output
    where
        N: AsRef<str>,
    {
        // Append the output to the end of the existing
        // outputs by placing it after the current overall
        // width
        let location = (self.width(), 0);

        let output = Output::new(
            name,
            location.into(),
            &mut *self.display.borrow_mut(),
            physical,
            mode,
        );
        let logical_size = output.geometry().size;
        let workspace = self.next_available(logical_size);
        slog_scope::info!("New output: {:?}", output);
        slog_scope::debug!(
            "Attaching workspace {} to output {}",
            workspace,
            output.name()
        );
        output
            .userdata()
            .insert_if_missing(|| ActiveWorkspace::new(workspace));
        self.outputs.push(output);

        // We call arrange here albeit the output is only appended and
        // this would not affect windows, but arrange could re-organize
        // outputs from a configuration.
        self.arrange();

        self.outputs.last().unwrap()
    }

    pub fn retain_outputs<F>(&mut self, f: F)
    where
        F: Fn(&Output) -> bool,
    {
        for output in self.outputs.iter().filter(|o| !f(*o)) {
            let workspace = output.userdata().get::<ActiveWorkspace>().unwrap().0.get();
            if self.spaces.get(&workspace).unwrap().is_empty() {
                slog_scope::debug!("Destroying empty workspace: {}", workspace);
                self.spaces.remove(&workspace);
            }
        }
        self.outputs.retain(f);
        self.arrange();
    }

    pub fn remove_output_by_name(&mut self, name: &str) {
        self.retain_outputs(|o| o.name() != name);
    }

    pub fn num_outputs(&self) -> usize {
        self.outputs.len()
    }

    pub fn toplevel_by_surface(&mut self, surface: &WlSurface) -> Option<Kind> {
        for (_, space) in self.spaces.iter_mut() {
            if let Some(window) = space
                .windows()
                .find(|k| k.get_surface().map(|x| x == surface).unwrap_or(false))
            {
                return Some(window);
            }
        }
        None
    }

    pub fn idx_by_output_name<N: AsRef<str>>(&self, name: N) -> Option<u8> {
        self.outputs
            .iter()
            .find(|o| o.name() == name.as_ref())
            .and_then(|x| x.userdata().get::<ActiveWorkspace>())
            .map(|x| x.0.get())
    }

    pub fn spaces<'a>(&'a mut self) -> impl Iterator<Item=&'a mut Box<dyn Layout>>
    {
        self.spaces.iter_mut().map(|(_, layout)| layout)
    }

    pub fn space_by_output_name<'a, N>(&'a mut self, name: N) -> Option<&'a mut Box<dyn Layout>>
    where
        N: AsRef<str>,
    {
        let active = self.idx_by_output_name(name);
        if let Some(a) = active {
            self.spaces.get_mut(&a)
        } else {
            None
        }
    }

    pub fn space_by_seat(&mut self, seat: &Seat) -> Option<&mut Box<dyn Layout>> {
        if let Some(name) = seat.user_data().get::<ActiveOutput>() {
            let exists = self.space_by_output_name(&*name.0.borrow()).is_some();
            if exists {
                return self.space_by_output_name(&*name.0.borrow());
            }
        }
        self.spaces.iter_mut().map(|(_, v)| v).next()
    }

    pub fn space_by_surface(&mut self, surface: &WlSurface) -> Option<&mut Box<dyn Layout>> {
        for (_, space) in self.spaces.iter_mut() {
            if space
                .windows()
                .any(|k| k.get_surface().map(|x| x == surface).unwrap_or(false))
            {
                return Some(space);
            }
        }
        None
    }

    pub fn space_by_idx(&mut self, idx: u8) -> &mut Box<dyn Layout> {
        self.spaces
            .entry(idx)
            .or_insert(Box::new(super::layout::Floating::new((0, 0))))
    }

    pub fn output<F>(&mut self, f: F) -> Option<&mut Output>
    where
        F: FnMut(&&mut Output) -> bool,
    {
        self.outputs.iter_mut().find(f)
    }

    pub fn output_by_wl(&mut self, output: &wl_output::WlOutput) -> Option<&mut Output> {
        self.output(|o| o.owns(output))
    }

    pub fn output_by_name<N>(&mut self, name: N) -> Option<&mut Output>
    where
        N: AsRef<str>,
    {
        self.output(|o| o.name() == name.as_ref())
    }

    pub fn switch_workspace(&mut self, seat: &Seat, idx: u8) {
        let output_name = &seat.user_data().get::<ActiveOutput>().unwrap().0;
        let current_idx = self.idx_by_output_name(&*output_name.borrow()).unwrap();
        if current_idx != idx {
            if let Some(output) =
                self.output(|o| o.userdata().get::<ActiveWorkspace>().unwrap().0.get() == idx)
            {
                *output_name.borrow_mut() = String::from(output.name());
                if let Some(ptr) = seat.get_pointer() {
                    let (w, h) = output.size().into();
                    ptr.unset_grab();
                    ptr.motion((w as f64 / 2.0, h as f64 / 2.0).into(), None, 0.into(), 0);
                }
            } else {
                let output = self.output_by_name(&*output_name.borrow()).unwrap();
                slog_scope::debug!("Attaching workspace {} to output {}", idx, output.name());
                output
                    .userdata()
                    .get::<ActiveWorkspace>()
                    .unwrap()
                    .0
                    .set(idx);
                let size = output.size();
                let _ = self
                    .spaces
                    .entry(idx)
                    .or_insert(Box::new(super::layout::Floating::new(size)));
            }
        }
        if self.space_by_idx(current_idx).is_empty() && self.output(|o| o.userdata().get::<ActiveWorkspace>().unwrap().0.get() == current_idx).is_none() {
            slog_scope::debug!("Destroying empty workspace: {}", current_idx);
            self.spaces.remove(&current_idx);
        }
    }
}
<|endoftext|>


<commit_before>use std::cell::Cell;

use graphics::character::CharacterCache;

use cfg::ColorScheme;

use ui::{Px, BB};
use ui::layout::{RectBB, RectBounded, ConstrainCx, Layout};
use ui::color::Scheme;
use ui::draw::{Draw, DrawCx};
use ui::event::*;
use ui::text::{self, FontFace};

pub struct Set<T> {
    bb: RectBB,
    tabs: Vec<T>,
    current: Cell<usize>
}

const TAB_WIDTH: Px = 150.0;

impl<T> Set<T> {
    pub fn new() -> Set<T> {
        Set {
            bb: RectBB::default(),
            tabs: vec![],
            current: Cell::new(0)
        }
    }

    pub fn add(&mut self, x: T) {
        self.tabs.push(x);
    }

    pub fn remove(&mut self) -> Option<T> {
        let current = self.current.get();
        if current >= self.tabs.len() {
            None
        } else {
            if current > 0 {
                self.current.set(current - 1);
            }
            Some(self.tabs.remove(current))
        }
    }
}

impl<T: Layout> RectBounded for Set<T> {
    fn rect_bb(&self) -> &RectBB { &self.bb }
    fn name(&self) -> &'static str { "<tabset>" }
    fn constrain<'a, 'b>(&'a self, (cx, bb): ConstrainCx<'b, 'a>) {
        let current = self.current.get();
        if current >= self.tabs.len() {
            return;
        }

        let tb = self.tabs[current].collect(cx);

        let height = cx.fonts.metrics(text::Regular).height * 2.0;

        cx.equal(bb.x1, tb.x1);
        cx.equal(tb.x2, bb.x2);
        cx.distance(bb.y1, tb.y1, height);
        cx.equal(tb.y2, bb.y2);
    }
}

pub trait Tab {
    fn title(&self) -> String;
}

impl<T> Draw for Set<T> where T: Layout + Tab + Draw {
    fn draw(&self, cx: &mut DrawCx) {
        let bb = self.bb();
        let current = self.current.get();
        if current < self.tabs.len() {
            let metrics = cx.fonts.metrics(text::Regular);

            // Background for all tabs.
            cx.rect(BB {
                x1: bb.x1, x2: bb.x1 + (self.tabs.len() as Px) * TAB_WIDTH,
                y1: bb.y1, y2: bb.y1 + metrics.height * 2.0
            }, ColorScheme.inactive());

            for (i, tab) in self.tabs.iter().enumerate() {
                let size = text::Regular.size();
                let text = tab.title();
                let w = text::Regular.cache(&mut cx.fonts).width(size, &text) as Px;

                // Background for each tab.
                let x = bb.x1 + (i as Px) * TAB_WIDTH;
                cx.rect(BB {
                    x1: x + 1.0, x2: x + TAB_WIDTH - 1.0,
                    y1: bb.y1, y2: bb.y1 + metrics.height * 2.0
                }, ColorScheme.background());

                // Focus highlight.
                if i == current {
                    let y = bb.y1 + metrics.height * 2.0 - 5.0;
                    cx.rect(BB {
                        x1: x + 3.0, x2: x + TAB_WIDTH - 3.0,
                        y1: y, y2: y + 2.0
                    }, ColorScheme.focus());
                }

                cx.text(text::Regular, [(x + (TAB_WIDTH - w) / 2.0).round(),
                                        (bb.y1 + metrics.height * 0.5).round()],
                                        ColorScheme.normal(), &text);
            }

            self.tabs[current].draw(cx);
        }
    }
}

trait SetDispatch<T, E> {
    fn dispatch(&self, _tab: &T, _ev: &E) -> bool { false }
}

impl<E, T> Dispatch<E> for Set<T> where Set<T>: SetDispatch<T, E>, T: Dispatch<E> {
    fn dispatch(&self, ev: &E) -> bool {
        let current = self.current.get();
        if current < self.tabs.len() {
            let tab = &self.tabs[current];
            tab.dispatch(ev) | SetDispatch::dispatch(self, tab, ev)
        } else {
            false
        }
    }
}

impl<T> SetDispatch<T, MouseDown> for Set<T> where T: Layout {
    fn dispatch(&self, tab: &T, ev: &MouseDown) -> bool {
        let bb = self.bb();
        let pos = [ev.x, ev.y];
        if bb.contains(pos) && !tab.bb().contains(pos) {
            let current = ((ev.x - bb.x1) / TAB_WIDTH) as usize;
            if current < self.tabs.len() {
                self.current.set(current);
                return true;
            }
        }
        false
    }
}

impl<T> SetDispatch<T, MouseUp> for Set<T> {}
impl<T> SetDispatch<T, MouseMove> for Set<T> {}
impl<T> SetDispatch<T, MouseScroll> for Set<T> {}
impl<T> SetDispatch<T, Update> for Set<T> {}
impl<'a, T> SetDispatch<T, TextInput<'a>> for Set<T> {}
impl<T> SetDispatch<T, KeyDown> for Set<T> {}
impl<T> SetDispatch<T, KeyUp> for Set<T> {}
<commit_msg>ui::tab: insert new tab next to current one.<commit_after>use std::cell::Cell;

use graphics::character::CharacterCache;

use cfg::ColorScheme;

use ui::{Px, BB};
use ui::layout::{RectBB, RectBounded, ConstrainCx, Layout};
use ui::color::Scheme;
use ui::draw::{Draw, DrawCx};
use ui::event::*;
use ui::text::{self, FontFace};

pub struct Set<T> {
    bb: RectBB,
    tabs: Vec<T>,
    current: Cell<usize>
}

const TAB_WIDTH: Px = 150.0;

impl<T> Set<T> {
    pub fn new() -> Set<T> {
        Set {
            bb: RectBB::default(),
            tabs: vec![],
            current: Cell::new(0)
        }
    }

    pub fn add(&mut self, x: T) {
        let current = self.current.get();
        let current = if current + 1 >= self.tabs.len() {
            current
        } else {
            current + 1
        };
        self.tabs.insert(current, x);
        self.current.set(current);
    }

    pub fn remove(&mut self) -> Option<T> {
        let current = self.current.get();
        if current >= self.tabs.len() {
            None
        } else {
            if current > 0 {
                self.current.set(current - 1);
            }
            Some(self.tabs.remove(current))
        }
    }
}

impl<T: Layout> RectBounded for Set<T> {
    fn rect_bb(&self) -> &RectBB { &self.bb }
    fn name(&self) -> &'static str { "<tabset>" }
    fn constrain<'a, 'b>(&'a self, (cx, bb): ConstrainCx<'b, 'a>) {
        let current = self.current.get();
        if current >= self.tabs.len() {
            return;
        }

        let tb = self.tabs[current].collect(cx);

        let height = cx.fonts.metrics(text::Regular).height * 2.0;

        cx.equal(bb.x1, tb.x1);
        cx.equal(tb.x2, bb.x2);
        cx.distance(bb.y1, tb.y1, height);
        cx.equal(tb.y2, bb.y2);
    }
}

pub trait Tab {
    fn title(&self) -> String;
}

impl<T> Draw for Set<T> where T: Layout + Tab + Draw {
    fn draw(&self, cx: &mut DrawCx) {
        let bb = self.bb();
        let current = self.current.get();
        if current < self.tabs.len() {
            let metrics = cx.fonts.metrics(text::Regular);

            // Background for all tabs.
            cx.rect(BB {
                x1: bb.x1, x2: bb.x1 + (self.tabs.len() as Px) * TAB_WIDTH,
                y1: bb.y1, y2: bb.y1 + metrics.height * 2.0
            }, ColorScheme.inactive());

            for (i, tab) in self.tabs.iter().enumerate() {
                let size = text::Regular.size();
                let text = tab.title();
                let w = text::Regular.cache(&mut cx.fonts).width(size, &text) as Px;

                // Background for each tab.
                let x = bb.x1 + (i as Px) * TAB_WIDTH;
                cx.rect(BB {
                    x1: x + 1.0, x2: x + TAB_WIDTH - 1.0,
                    y1: bb.y1, y2: bb.y1 + metrics.height * 2.0
                }, ColorScheme.background());

                // Focus highlight.
                if i == current {
                    let y = bb.y1 + metrics.height * 2.0 - 5.0;
                    cx.rect(BB {
                        x1: x + 3.0, x2: x + TAB_WIDTH - 3.0,
                        y1: y, y2: y + 2.0
                    }, ColorScheme.focus());
                }

                cx.text(text::Regular, [(x + (TAB_WIDTH - w) / 2.0).round(),
                                        (bb.y1 + metrics.height * 0.5).round()],
                                        ColorScheme.normal(), &text);
            }

            self.tabs[current].draw(cx);
        }
    }
}

trait SetDispatch<T, E> {
    fn dispatch(&self, _tab: &T, _ev: &E) -> bool { false }
}

impl<E, T> Dispatch<E> for Set<T> where Set<T>: SetDispatch<T, E>, T: Dispatch<E> {
    fn dispatch(&self, ev: &E) -> bool {
        let current = self.current.get();
        if current < self.tabs.len() {
            let tab = &self.tabs[current];
            tab.dispatch(ev) | SetDispatch::dispatch(self, tab, ev)
        } else {
            false
        }
    }
}

impl<T> SetDispatch<T, MouseDown> for Set<T> where T: Layout {
    fn dispatch(&self, tab: &T, ev: &MouseDown) -> bool {
        let bb = self.bb();
        let pos = [ev.x, ev.y];
        if bb.contains(pos) && !tab.bb().contains(pos) {
            let current = ((ev.x - bb.x1) / TAB_WIDTH) as usize;
            if current < self.tabs.len() {
                self.current.set(current);
                return true;
            }
        }
        false
    }
}

impl<T> SetDispatch<T, MouseUp> for Set<T> {}
impl<T> SetDispatch<T, MouseMove> for Set<T> {}
impl<T> SetDispatch<T, MouseScroll> for Set<T> {}
impl<T> SetDispatch<T, Update> for Set<T> {}
impl<'a, T> SetDispatch<T, TextInput<'a>> for Set<T> {}
impl<T> SetDispatch<T, KeyDown> for Set<T> {}
impl<T> SetDispatch<T, KeyUp> for Set<T> {}
<|endoftext|>