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

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

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

enum DispatchMessage<U: WebDriverExtensionRoute> {
    HandleWebDriver(WebDriverMessage<U>, 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<U: WebDriverExtensionRoute=VoidWebDriverExtensionRoute> : Send {
    fn handle_command(&mut self, session: &Option<Session>, msg: WebDriverMessage<U>) -> WebDriverResult<WebDriverResponse>;
    fn delete_session(&mut self, session: &Option<Session>);
}

struct Dispatcher<T: WebDriverHandler<U>,
                  U: WebDriverExtensionRoute> {
    handler: T,
    session: Option<Session>,
    extension_type: PhantomData<U>,
}

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

    fn run(&mut self, msg_chan: Receiver<DispatchMessage<U>>) {
        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) => {
                            self.delete_session();
                        },
                        Err(ref x) if x.delete_session() => {
                            self.delete_session();
                        }
                        _ => {}
                    }

                    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 delete_session(&mut self) {
        debug!("Deleting session");
        self.handler.delete_session(&self.session);
        self.session = None;
    }

    fn check_session(&self, msg: &WebDriverMessage<U>) -> 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::Status => Ok(()),
                            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(()),
                            WebDriverCommand::Status => Ok(()),
                            _ => Err(WebDriverError::new(
                                ErrorStatus::InvalidSessionId,
                                "Tried to run a command before creating a session"))
                        }
                    }
                }
            }
        }
    }
}

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

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

impl <U: WebDriverExtensionRoute> Handler for HttpHandler<U> {
    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())
                    }
                };
                debug!("Returning status {:?}", status);
                debug!("Returning body {}", resp_body);
                {
                    let resp_status = res.status_mut();
                    *resp_status = status;
                }
                res.headers_mut().set(ContentType::json());
                res.send(&resp_body.as_bytes()).unwrap();
            },
            _ => {}
        }
    }
}

pub fn start<T, U>(address: SocketAddr,
                   handler: T,
                   extension_routes: &[(Method, &str, U)])
                   -> Result<Listening>
    where T: 'static + WebDriverHandler<U>,
          U: 'static + WebDriverExtensionRoute
{
    let (msg_send, msg_recv) = channel();

    let api = WebDriverHttpApi::new(extension_routes);
    let http_handler = HttpHandler::new(api, msg_send);
    let mut server = try!(Server::http(address));
    server.keep_alive(None);

    let builder = thread::Builder::new().name("webdriver dispatcher".to_string());
    try!(builder.spawn(move || {
        let mut dispatcher = Dispatcher::new(handler);
        dispatcher.run(msg_recv);
    }));

    server.handle(http_handler)
}
<commit_msg>Correct response headers<commit_after>use std::io::Read;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::Mutex;
use std::thread;

use hyper::header::{ContentType, CacheControl, CacheDirective};
use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use hyper::method::Method;
use hyper::Result;
use hyper::server::{Handler, Listening, Request, Response, Server};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;

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

enum DispatchMessage<U: WebDriverExtensionRoute> {
    HandleWebDriver(WebDriverMessage<U>, 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<U: WebDriverExtensionRoute=VoidWebDriverExtensionRoute> : Send {
    fn handle_command(&mut self, session: &Option<Session>, msg: WebDriverMessage<U>) -> WebDriverResult<WebDriverResponse>;
    fn delete_session(&mut self, session: &Option<Session>);
}

struct Dispatcher<T: WebDriverHandler<U>,
                  U: WebDriverExtensionRoute> {
    handler: T,
    session: Option<Session>,
    extension_type: PhantomData<U>,
}

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

    fn run(&mut self, msg_chan: Receiver<DispatchMessage<U>>) {
        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) => {
                            self.delete_session();
                        },
                        Err(ref x) if x.delete_session() => {
                            self.delete_session();
                        }
                        _ => {}
                    }

                    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 delete_session(&mut self) {
        debug!("Deleting session");
        self.handler.delete_session(&self.session);
        self.session = None;
    }

    fn check_session(&self, msg: &WebDriverMessage<U>) -> 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::Status => Ok(()),
                            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(()),
                            WebDriverCommand::Status => Ok(()),
                            _ => Err(WebDriverError::new(
                                ErrorStatus::InvalidSessionId,
                                "Tried to run a command before creating a session"))
                        }
                    }
                }
            }
        }
    }
}

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

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

impl <U: WebDriverExtensionRoute> Handler for HttpHandler<U> {
    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())
                    }
                };
                debug!("Returning status {:?}", status);
                debug!("Returning body {}", resp_body);
                {
                    let resp_status = res.status_mut();
                    *resp_status = status;
                }
                res.headers_mut().set(
                    ContentType(Mime(TopLevel::Application, SubLevel::Json,
                                     vec![(Attr::Charset, Value::Utf8)])));
                res.headers_mut().set(CacheControl(vec![CacheDirective::NoCache]));
                res.send(&resp_body.as_bytes()).unwrap();
            },
            _ => {}
        }
    }
}

pub fn start<T, U>(address: SocketAddr,
                   handler: T,
                   extension_routes: &[(Method, &str, U)])
                   -> Result<Listening>
    where T: 'static + WebDriverHandler<U>,
          U: 'static + WebDriverExtensionRoute
{
    let (msg_send, msg_recv) = channel();

    let api = WebDriverHttpApi::new(extension_routes);
    let http_handler = HttpHandler::new(api, msg_send);
    let mut server = try!(Server::http(address));
    server.keep_alive(None);

    let builder = thread::Builder::new().name("webdriver dispatcher".to_string());
    try!(builder.spawn(move || {
        let mut dispatcher = Dispatcher::new(handler);
        dispatcher.run(msg_recv);
    }));

    server.handle(http_handler)
}
<|endoftext|>


<commit_before>//! `Server` listens for HTTP requests.
//!
//!```rust
//!# use rustful::server::Server;
//!# use rustful::router::Router;
//!# let routes = [];
//!let server = Server {
//!	router: ~Router::from_routes(routes),
//!	port: 8080
//!};
//!
//!server.run();
//!```

use router::Router;
use request::Request;
use response::Response;
use response::status::NotFound;

use http;
use http::server::{ResponseWriter, Config};
use http::server::request::{AbsoluteUri, AbsolutePath};
use http::headers::content_type::MediaType;
use http::method::Post;

use std::io::net::ip::{SocketAddr, Ipv4Addr, Port};
use std::hashmap::HashMap;
use std::str::from_utf8;
use std::uint;
use std::io::BufReader;

use extra::time;

use HTTP = http::server::Server;

///A handler function for routing.
pub type HandlerFn = fn(&Request, &mut Response);

#[deriving(Clone)]
pub struct Server {
	///A routing tree with response handlers
	router: ~Router<HandlerFn>,

	///The port where the server will listen for requests
	port: Port
}

impl Server {
	///Start the server and run forever.
	///This will only return if the initial connection fails.
	pub fn run(&self) {
		self.clone().serve_forever();
	}
}

impl HTTP for Server {
	fn get_config(&self) -> Config {
		Config {
			bind_address: SocketAddr {
				ip: Ipv4Addr(0, 0, 0, 0),
				port: self.port
			}
		}
	}

	fn handle_request(&self, request: &http::server::request::Request, writer: &mut ResponseWriter) {
		let mut response = Response::new(writer);
		response.headers.date = Some(time::now_utc());
		response.headers.content_type = Some(MediaType {
			type_: ~"text",
			subtype: ~"plain",
			parameters: ~[(~"charset", ~"UTF-8")]
		});
		response.headers.server = Some(~"rustful");

		let found = match build_request(request) {
			Some(mut request) => match self.router.find(request.method.clone(), request.path) {
				Some((&handler, variables)) => {
					request.variables = variables;
					handler(&request, response);
					true
				},
				None => false
			},
			None => false
		};

		if !found {
			let content = bytes!("File not found");
			response.headers.content_length = Some(content.len());
			response.status = NotFound;
			match response.write(content.to_owned()) {
				Err(e) => println!("error while writing 404: {}", e),
				_ => {}
			}
		}
	}
}

fn build_request(request: &http::server::request::Request) -> Option<Request> {
	let path = match request.request_uri {
		AbsoluteUri(ref url) => {
			let query = ~url.query.iter().map(|&(ref a, ref b)| {
				(a.to_str(), b.to_str())
			}).collect();
			Some((url.path.to_str(), query, url.fragment.to_str()))
		},
		AbsolutePath(ref path) => Some(parse_path(path.to_str())),
		_ => None
	};

	match path {
		Some((path, query, fragment)) => {
			let post = if request.method == Post {
				parse_parameters(request.body)
			} else {
				~HashMap::new()
			};

			Some(Request {
				headers: request.headers.clone(),
				method: request.method.clone(),
				path: path.to_owned(),
				variables: ~HashMap::new(),
				post: post,
				query: query,
				fragment: fragment,
				body: request.body.to_str()
			})
		}
		None => None
	}
}

fn parse_parameters(source: &str) -> ~HashMap<~str, ~str> {
	let mut parameters = ~HashMap::new();
	for parameter in source.split('&') {
		let parts = parameter.split('=').collect::<~[&str]>();
		match parts {
			[name, value] => {
				parameters.insert(url_decode(name), url_decode(value));
			},
			[name] => {
				parameters.insert(url_decode(name), ~"");
			},
			[name, value, ..] => {
				parameters.insert(url_decode(name), url_decode(value));
			},
			[] => {}
		}
	}

	parameters
}

fn parse_path(path: &str) -> (~str, ~HashMap<~str, ~str>, ~str) {
	match path.find('?') {
		Some(index) => {
			let (query, fragment) = parse_fragment(path.slice(index+1, path.len()));
			(path.slice(0, index).to_str(), parse_parameters(query), fragment)
		},
		None => {
			let (path, fragment) = parse_fragment(path);
			(path, ~HashMap::new(), fragment)
		}
	}
}

fn parse_fragment(path: &str) -> (~str, ~str) {
	match path.find('#') {
		Some(index) => (path.slice(0, index).to_str(), path.slice(index+1, path.len()).to_str()),
		None => (path.to_str(), ~"")
	}
}

fn url_decode(string: &str) -> ~str {
	let mut rdr = BufReader::new(string.as_bytes());
	let mut out = ~[];

	loop {
		let mut buf = [0];
		let ch = match rdr.read(buf) {
			Err(..) => break,
			Ok(..) => buf[0] as char
		};
		match ch {
			'%' => {
				let mut bytes = [0, 0];
				match rdr.read(bytes) {
					Ok(2) => {}
					_ => fail!()
				}
				let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8;
				out.push(ch);
			}
			ch => out.push(ch as u8)
		}
	}

	match from_utf8(out) {
		Some(result) => result.to_str(),
		None => string.to_str()
	}
}

#[test]
fn parsing_parameters() {
	let parameters = parse_parameters("a=1&aa=2&ab=202");
	let a = ~"1";
	let aa = ~"2";
	let ab = ~"202";
	assert_eq!(parameters.find(&~"a"), Some(&a));
	assert_eq!(parameters.find(&~"aa"), Some(&aa));
	assert_eq!(parameters.find(&~"ab"), Some(&ab));
}

#[test]
fn parsing_strange_parameters() {
	let parameters = parse_parameters("a=1=2&=2&ab=");
	let a = ~"1";
	let aa = ~"2";
	let ab = ~"";
	assert_eq!(parameters.find(&~"a"), Some(&a));
	assert_eq!(parameters.find(&~""), Some(&aa));
	assert_eq!(parameters.find(&~"ab"), Some(&ab));
}

#[test]
fn parse_path_parts() {
	let (path, query, fragment) = parse_path("/path/to/something?whith=this&and=that#lol");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query, ~"whith=this&and=that");
	assert_eq!(fragment, ~"lol");
}

#[test]
fn parse_strange_path() {
	let (path, query, fragment) = parse_path("/path/to/something?whith=this&and=what?#");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query, ~"whith=this&and=what?");
	assert_eq!(fragment, ~"");
}

#[test]
fn parse_missing_path_parts() {
	let (path, query, fragment) = parse_path("/path/to/something?whith=this&and=that");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query, ~"whith=this&and=that");
	assert_eq!(fragment, ~"");

	let (path, query, fragment) = parse_path("/path/to/something#lol");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query, ~"");
	assert_eq!(fragment, ~"lol");

	let (path, query, fragment) = parse_path("?whith=this&and=that#lol");
	assert_eq!(path, ~"");
	assert_eq!(query, ~"whith=this&and=that");
	assert_eq!(fragment, ~"lol");
}<commit_msg>Unique vector patterns are going away. Let's see how long this works<commit_after>//! `Server` listens for HTTP requests.
//!
//!```rust
//!# use rustful::server::Server;
//!# use rustful::router::Router;
//!# let routes = [];
//!let server = Server {
//!	router: ~Router::from_routes(routes),
//!	port: 8080
//!};
//!
//!server.run();
//!```

use router::Router;
use request::Request;
use response::Response;
use response::status::NotFound;

use http;
use http::server::{ResponseWriter, Config};
use http::server::request::{AbsoluteUri, AbsolutePath};
use http::headers::content_type::MediaType;
use http::method::Post;

use std::io::net::ip::{SocketAddr, Ipv4Addr, Port};
use std::hashmap::HashMap;
use std::str::from_utf8;
use std::uint;
use std::io::BufReader;

use extra::time;

use HTTP = http::server::Server;

///A handler function for routing.
pub type HandlerFn = fn(&Request, &mut Response);

#[deriving(Clone)]
pub struct Server {
	///A routing tree with response handlers
	router: ~Router<HandlerFn>,

	///The port where the server will listen for requests
	port: Port
}

impl Server {
	///Start the server and run forever.
	///This will only return if the initial connection fails.
	pub fn run(&self) {
		self.clone().serve_forever();
	}
}

impl HTTP for Server {
	fn get_config(&self) -> Config {
		Config {
			bind_address: SocketAddr {
				ip: Ipv4Addr(0, 0, 0, 0),
				port: self.port
			}
		}
	}

	fn handle_request(&self, request: &http::server::request::Request, writer: &mut ResponseWriter) {
		let mut response = Response::new(writer);
		response.headers.date = Some(time::now_utc());
		response.headers.content_type = Some(MediaType {
			type_: ~"text",
			subtype: ~"plain",
			parameters: ~[(~"charset", ~"UTF-8")]
		});
		response.headers.server = Some(~"rustful");

		let found = match build_request(request) {
			Some(mut request) => match self.router.find(request.method.clone(), request.path) {
				Some((&handler, variables)) => {
					request.variables = variables;
					handler(&request, response);
					true
				},
				None => false
			},
			None => false
		};

		if !found {
			let content = bytes!("File not found");
			response.headers.content_length = Some(content.len());
			response.status = NotFound;
			match response.write(content.to_owned()) {
				Err(e) => println!("error while writing 404: {}", e),
				_ => {}
			}
		}
	}
}

fn build_request(request: &http::server::request::Request) -> Option<Request> {
	let path = match request.request_uri {
		AbsoluteUri(ref url) => {
			let query = ~url.query.iter().map(|&(ref a, ref b)| {
				(a.to_str(), b.to_str())
			}).collect();
			Some((url.path.to_str(), query, url.fragment.to_str()))
		},
		AbsolutePath(ref path) => Some(parse_path(path.to_str())),
		_ => None
	};

	match path {
		Some((path, query, fragment)) => {
			let post = if request.method == Post {
				parse_parameters(request.body)
			} else {
				~HashMap::new()
			};

			Some(Request {
				headers: request.headers.clone(),
				method: request.method.clone(),
				path: path.to_owned(),
				variables: ~HashMap::new(),
				post: post,
				query: query,
				fragment: fragment,
				body: request.body.to_str()
			})
		}
		None => None
	}
}

fn parse_parameters(source: &str) -> ~HashMap<~str, ~str> {
	let mut parameters = ~HashMap::new();
	for parameter in source.split('&') {
		let parts = parameter.split('=').collect::<~[&str]>();
		match parts.as_slice() {
			[name, value] => {
				parameters.insert(url_decode(name), url_decode(value));
			},
			[name] => {
				parameters.insert(url_decode(name), ~"");
			},
			[name, value, ..] => {
				parameters.insert(url_decode(name), url_decode(value));
			},
			[] => {}
		}
	}

	parameters
}

fn parse_path(path: &str) -> (~str, ~HashMap<~str, ~str>, ~str) {
	match path.find('?') {
		Some(index) => {
			let (query, fragment) = parse_fragment(path.slice(index+1, path.len()));
			(path.slice(0, index).to_str(), parse_parameters(query), fragment)
		},
		None => {
			let (path, fragment) = parse_fragment(path);
			(path, ~HashMap::new(), fragment)
		}
	}
}

fn parse_fragment(path: &str) -> (~str, ~str) {
	match path.find('#') {
		Some(index) => (path.slice(0, index).to_str(), path.slice(index+1, path.len()).to_str()),
		None => (path.to_str(), ~"")
	}
}

fn url_decode(string: &str) -> ~str {
	let mut rdr = BufReader::new(string.as_bytes());
	let mut out = ~[];

	loop {
		let mut buf = [0];
		let ch = match rdr.read(buf) {
			Err(..) => break,
			Ok(..) => buf[0] as char
		};
		match ch {
			'%' => {
				let mut bytes = [0, 0];
				match rdr.read(bytes) {
					Ok(2) => {}
					_ => fail!()
				}
				let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8;
				out.push(ch);
			}
			ch => out.push(ch as u8)
		}
	}

	match from_utf8(out) {
		Some(result) => result.to_str(),
		None => string.to_str()
	}
}

#[test]
fn parsing_parameters() {
	let parameters = parse_parameters("a=1&aa=2&ab=202");
	let a = ~"1";
	let aa = ~"2";
	let ab = ~"202";
	assert_eq!(parameters.find(&~"a"), Some(&a));
	assert_eq!(parameters.find(&~"aa"), Some(&aa));
	assert_eq!(parameters.find(&~"ab"), Some(&ab));
}

#[test]
fn parsing_strange_parameters() {
	let parameters = parse_parameters("a=1=2&=2&ab=");
	let a = ~"1";
	let aa = ~"2";
	let ab = ~"";
	assert_eq!(parameters.find(&~"a"), Some(&a));
	assert_eq!(parameters.find(&~""), Some(&aa));
	assert_eq!(parameters.find(&~"ab"), Some(&ab));
}

#[test]
fn parse_path_parts() {
	let (path, query, fragment) = parse_path("/path/to/something?whith=this&and=that#lol");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query, ~"whith=this&and=that");
	assert_eq!(fragment, ~"lol");
}

#[test]
fn parse_strange_path() {
	let (path, query, fragment) = parse_path("/path/to/something?whith=this&and=what?#");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query, ~"whith=this&and=what?");
	assert_eq!(fragment, ~"");
}

#[test]
fn parse_missing_path_parts() {
	let (path, query, fragment) = parse_path("/path/to/something?whith=this&and=that");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query, ~"whith=this&and=that");
	assert_eq!(fragment, ~"");

	let (path, query, fragment) = parse_path("/path/to/something#lol");
	assert_eq!(path, ~"/path/to/something");
	assert_eq!(query, ~"");
	assert_eq!(fragment, ~"lol");

	let (path, query, fragment) = parse_path("?whith=this&and=that#lol");
	assert_eq!(path, ~"");
	assert_eq!(query, ~"whith=this&and=that");
	assert_eq!(fragment, ~"lol");
}<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

use {REMOTE, net2};
use bincode::serde::DeserializeError;
use errors::WireError;
use framed::Proto;
use futures::{self, Async, Future, Stream};
use serde::{Deserialize, Serialize};
use std::io;
use std::net::SocketAddr;
use tokio_core::net::TcpListener;
use tokio_core::reactor::Handle;
use tokio_proto::BindServer;
use tokio_service::NewService;

/// A message from server to client.
pub type Response<T, E> = Result<T, WireError<E>>;

/// Spawns a service that binds to the given address and runs on the default reactor core.
pub fn listen<S, Req, Resp, E>(addr: SocketAddr, new_service: S) -> ListenFuture
    where S: NewService<Request = Result<Req, DeserializeError>,
                        Response = Response<Resp, E>,
                        Error = io::Error> + Send + 'static,
          Req: Deserialize + 'static,
          Resp: Serialize + 'static,
          E: Serialize + 'static
{
    let (tx, rx) = futures::oneshot();
    REMOTE.spawn(move |handle| Ok(tx.complete(listen_with(addr, new_service, handle.clone()))));
    ListenFuture { inner: rx }
}

/// Spawns a service that binds to the given address using the given handle.
pub fn listen_with<S, Req, Resp, E>(addr: SocketAddr,
                                    new_service: S,
                                    handle: Handle)
                                    -> io::Result<SocketAddr>
    where S: NewService<Request = Result<Req, DeserializeError>,
                        Response = Response<Resp, E>,
                        Error = io::Error> + Send + 'static,
          Req: Deserialize + 'static,
          Resp: Serialize + 'static,
          E: Serialize + 'static
{
    let listener = listener(&addr, &handle)?;
    let addr = listener.local_addr()?;

    let handle2 = handle.clone();
    let server = listener.incoming().for_each(move |(socket, _)| {
        Proto::new().bind_server(&handle2, socket, new_service.new_service()?);

        Ok(())
    }).map_err(|e| error!("While processing incoming connections: {}", e));
    handle.spawn(server);
    Ok(addr)
}

fn listener(addr: &SocketAddr,
            handle: &Handle) -> io::Result<TcpListener> {
    match *addr {
        SocketAddr::V4(_) => net2::TcpBuilder::new_v4(),
        SocketAddr::V6(_) => net2::TcpBuilder::new_v6()
    }?
    .reuse_address(true)?
    .bind(addr)?
    .listen(1024)
    .and_then(|l| {
        TcpListener::from_listener(l, addr, handle)
    })
}

/// A future that resolves to a `ServerHandle`.
pub struct ListenFuture {
    inner: futures::Oneshot<io::Result<SocketAddr>>,
}

impl ListenFuture {
    #[doc(hidden)]
    pub fn from_oneshot(rx: futures::Oneshot<io::Result<SocketAddr>>) -> Self {
        ListenFuture { inner: rx }
    }
}

impl Future for ListenFuture {
    type Item = SocketAddr;
    type Error = io::Error;

    fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
        // Can't panic the oneshot is always completed.
        match self.inner.poll().unwrap() {
            Async::Ready(result) => result.map(Async::Ready),
            Async::NotReady => Ok(Async::NotReady),
        }
    }
}
<commit_msg>Make connection backlog arg to listen a const<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

use {REMOTE, net2};
use bincode::serde::DeserializeError;
use errors::WireError;
use framed::Proto;
use futures::{self, Async, Future, Stream};
use serde::{Deserialize, Serialize};
use std::io;
use std::net::SocketAddr;
use tokio_core::net::TcpListener;
use tokio_core::reactor::Handle;
use tokio_proto::BindServer;
use tokio_service::NewService;

/// A message from server to client.
pub type Response<T, E> = Result<T, WireError<E>>;

/// Spawns a service that binds to the given address and runs on the default reactor core.
pub fn listen<S, Req, Resp, E>(addr: SocketAddr, new_service: S) -> ListenFuture
    where S: NewService<Request = Result<Req, DeserializeError>,
                        Response = Response<Resp, E>,
                        Error = io::Error> + Send + 'static,
          Req: Deserialize + 'static,
          Resp: Serialize + 'static,
          E: Serialize + 'static
{
    let (tx, rx) = futures::oneshot();
    REMOTE.spawn(move |handle| Ok(tx.complete(listen_with(addr, new_service, handle.clone()))));
    ListenFuture { inner: rx }
}

/// Spawns a service that binds to the given address using the given handle.
pub fn listen_with<S, Req, Resp, E>(addr: SocketAddr,
                                    new_service: S,
                                    handle: Handle)
                                    -> io::Result<SocketAddr>
    where S: NewService<Request = Result<Req, DeserializeError>,
                        Response = Response<Resp, E>,
                        Error = io::Error> + Send + 'static,
          Req: Deserialize + 'static,
          Resp: Serialize + 'static,
          E: Serialize + 'static
{
    let listener = listener(&addr, &handle)?;
    let addr = listener.local_addr()?;

    let handle2 = handle.clone();
    let server = listener.incoming().for_each(move |(socket, _)| {
        Proto::new().bind_server(&handle2, socket, new_service.new_service()?);

        Ok(())
    }).map_err(|e| error!("While processing incoming connections: {}", e));
    handle.spawn(server);
    Ok(addr)
}

fn listener(addr: &SocketAddr,
            handle: &Handle) -> io::Result<TcpListener> {
    const PENDING_CONNECTION_BACKLOG = 1024;

    match *addr {
        SocketAddr::V4(_) => net2::TcpBuilder::new_v4(),
        SocketAddr::V6(_) => net2::TcpBuilder::new_v6()
    }?
    .reuse_address(true)?
    .bind(addr)?
    .listen(PENDING_CONNECTION_BACKLOG)
    .and_then(|l| {
        TcpListener::from_listener(l, addr, handle)
    })
}

/// A future that resolves to a `ServerHandle`.
pub struct ListenFuture {
    inner: futures::Oneshot<io::Result<SocketAddr>>,
}

impl ListenFuture {
    #[doc(hidden)]
    pub fn from_oneshot(rx: futures::Oneshot<io::Result<SocketAddr>>) -> Self {
        ListenFuture { inner: rx }
    }
}

impl Future for ListenFuture {
    type Item = SocketAddr;
    type Error = io::Error;

    fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
        // Can't panic the oneshot is always completed.
        match self.inner.poll().unwrap() {
            Async::Ready(result) => result.map(Async::Ready),
            Async::NotReady => Ok(Async::NotReady),
        }
    }
}
<|endoftext|>


<commit_before>use num::{ Float, ToPrimitive, FromPrimitive };
use callback::Callable;
use frame::Frameable;
use color::{ Color, Colorable };
use dimensions::Dimensions;
use label;
use mouse::Mouse;
use graphics::Graphics;
use graphics::character::CharacterCache;
use point::Point;
use rectangle;
use ui_context::{ UIID, UiContext };
use utils::{
    clamp,
    percentage,
    value_from_perc,
};
use widget::Widget;
use vecmath::vec2_add;

/// Represents the state of the Button widget.
#[derive(PartialEq, Clone, Copy)]
pub enum State {
    Normal,
    Highlighted,
    Clicked,
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State::Normal => rectangle::State::Normal,
            &State::Highlighted => rectangle::State::Highlighted,
            &State::Clicked => rectangle::State::Clicked,
        }
    }
}

widget_fns!(Slider, State, Widget::Slider(State::Normal));

/// Check the current state of the slider.
fn get_new_state(is_over: bool,
                 prev: State,
                 mouse: Mouse) -> State {
    use mouse::ButtonState::{Down, Up};
    use self::State::{Normal, Highlighted, Clicked};
    match (is_over, prev, mouse.left) {
        (true,  Normal,  Down) => Normal,
        (true,  _,       Down) => Clicked,
        (true,  _,       Up)   => Highlighted,
        (false, Clicked, Down) => Clicked,
        _ => Normal,
    }
}

/// A context on which the builder pattern can be implemented.
pub struct Slider<'a, T, F> {
    ui_id: UIID,
    value: T,
    min: T,
    max: T,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_label: Option<&'a str>,
    maybe_label_color: Option<Color>,
    maybe_label_font_size: Option<u32>,
}

impl<'a, T, F> Slider<'a, T, F> {
    /// A button builder method to be implemented by the UiContext.
    pub fn new(ui_id: UIID, value: T, min: T, max: T) -> Slider<'a, T, F> {
        Slider {
            ui_id: ui_id,
            value: value,
            min: min,
            max: max,
            pos: [0.0, 0.0],
            dim: [192.0, 48.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_label: None,
            maybe_label_color: None,
            maybe_label_font_size: None,
        }
    }
}

impl<'a, T, F> Colorable for Slider<'a, T, F> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

impl<'a, T, F> Frameable for Slider<'a, T, F> {
    fn frame(mut self, width: f64) -> Self {
        self.maybe_frame = Some(width);
        self
    }
    fn frame_color(mut self, color: Color) -> Self {
        self.maybe_frame_color = Some(color);
        self
    }
}

impl<'a, T, F> Callable<F> for Slider<'a, T, F> {
    fn callback(mut self, cb: F) -> Self {
        self.maybe_callback = Some(cb);
        self
    }
}

/*
quack! {
    slider: Slider['a, T, F]
    get:
        fn () -> Size [] { Size(slider.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(Widget::Slider(State::Normal))
        }
        fn () -> Id [] { Id(slider.ui_id) }
    set:
        fn (val: LabelText<'a>) [] { slider.maybe_label = Some(val.0) }
        fn (val: LabelColor) [] { slider.maybe_label_color = Some(val.0) }
        fn (val: LabelFontSize) [] { slider.maybe_label_font_size = Some(val.0) }
        fn (val: Position) [] { slider.pos = val.0 }
        fn (val: Size) [] { slider.dim = val.0 }
    action:
}
*/

impl<'a, T, F> ::draw::Drawable for Slider<'a, T, F>
    where
        T: Float + FromPrimitive + ToPrimitive,
        F: FnMut(T) + 'a
{

    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {

        let state = *get_state(uic, self.ui_id);
        let mouse = uic.get_mouse_state();
        let is_over = rectangle::is_over(self.pos, mouse.pos, self.dim);
        let new_state = get_new_state(is_over, state, mouse);

        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let frame_w2 = frame_w * 2.0;
        let frame_color = self.maybe_frame_color.unwrap_or(uic.theme.frame_color);

        let is_horizontal = self.dim[0] > self.dim[1];
        let (new_value, pad_pos, pad_dim) = if is_horizontal {
            // Horizontal.
            let p = vec2_add(self.pos, [frame_w, frame_w]);
            let max_w = self.dim[0] - frame_w2;
            let w = match (is_over, state, new_state) {
                (true, State::Highlighted, State::Clicked) | (_, State::Clicked, State::Clicked)  =>
                     clamp(mouse.pos[0] - p[0], 0f64, max_w),
                _ => clamp(percentage(self.value, self.min, self.max) as f64 * max_w, 0f64, max_w),
            };
            let h = self.dim[1] - frame_w2;
            let new_value = value_from_perc((w / max_w) as f32, self.min, self.max);
            (new_value, p, [w, h])
        } else {
            // Vertical.
            let max_h = self.dim[1] - frame_w2;
            let corner = vec2_add(self.pos, [frame_w, frame_w]);
            let y_max = corner[1] + max_h;
            let (h, p) = match (is_over, state, new_state) {
                (true, State::Highlighted, State::Clicked) | (_, State::Clicked, State::Clicked) => {
                    let p = [corner[0], clamp(mouse.pos[1], corner[1], y_max)];
                    let h = clamp(max_h - (p[1] - corner[1]), 0.0, max_h);
                    (h, p)
                },
                _ => {
                    let h = clamp(percentage(self.value, self.min, self.max) as f64 * max_h, 0.0, max_h);
                    let p = [corner[0], corner[1] + max_h - h];
                    (h, p)
                },
            };
            let w = self.dim[0] - frame_w2;
            let new_value = value_from_perc((h / max_h) as f32, self.min, self.max);
            (new_value, p, [w, h])
        };

        // Callback.
        match self.maybe_callback {
            Some(ref mut callback) => {
                if self.value != new_value || match (state, new_state) {
                    (State::Highlighted, State::Clicked) | (State::Clicked, State::Highlighted) => true,
                    _ => false,
                } { (*callback)(new_value) }
            }, None => (),
        }

        // Draw.
        let rect_state = new_state.as_rectangle_state();
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);

        // Rectangle frame / backdrop.
        rectangle::draw(uic.win_w, uic.win_h, graphics, rect_state,
                        self.pos, self.dim, None, frame_color);
        // Slider rectangle.
        rectangle::draw(uic.win_w, uic.win_h, graphics, rect_state,
                        pad_pos, pad_dim, None, color);

        // If there's a label, draw it.
        if let Some(text) = self.maybe_label {
            let text_color = self.maybe_label_color.unwrap_or(uic.theme.label_color);
            let size = self.maybe_label_font_size.unwrap_or(uic.theme.font_size_medium);
            let is_horizontal = self.dim[0] > self.dim[1];
            let l_pos = if is_horizontal {
                let x = pad_pos[0] + (pad_dim[1] - size as f64) / 2.0;
                let y = pad_pos[1] + (pad_dim[1] - size as f64) / 2.0;
                [x, y]
            } else {
                let label_w = label::width(uic, size, &text);
                let x = pad_pos[0] + (pad_dim[0] - label_w) / 2.0;
                let y = pad_pos[1] + pad_dim[1] - pad_dim[0] - frame_w;
                [x, y]
            };
            // Draw the label.
            uic.draw_text(graphics, l_pos, size, text_color, &text);
        }

        set_state(uic, self.ui_id, Widget::Slider(new_state), self.pos, self.dim);

    }
}
<commit_msg>Implement `Labelable` for `Slider`<commit_after>use num::{ Float, ToPrimitive, FromPrimitive };
use callback::Callable;
use frame::Frameable;
use color::{ Color, Colorable };
use label::{ FontSize, Labelable };
use dimensions::Dimensions;
use label;
use mouse::Mouse;
use graphics::Graphics;
use graphics::character::CharacterCache;
use point::Point;
use rectangle;
use ui_context::{ UIID, UiContext };
use utils::{
    clamp,
    percentage,
    value_from_perc,
};
use widget::Widget;
use vecmath::vec2_add;

/// Represents the state of the Button widget.
#[derive(PartialEq, Clone, Copy)]
pub enum State {
    Normal,
    Highlighted,
    Clicked,
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State::Normal => rectangle::State::Normal,
            &State::Highlighted => rectangle::State::Highlighted,
            &State::Clicked => rectangle::State::Clicked,
        }
    }
}

widget_fns!(Slider, State, Widget::Slider(State::Normal));

/// Check the current state of the slider.
fn get_new_state(is_over: bool,
                 prev: State,
                 mouse: Mouse) -> State {
    use mouse::ButtonState::{Down, Up};
    use self::State::{Normal, Highlighted, Clicked};
    match (is_over, prev, mouse.left) {
        (true,  Normal,  Down) => Normal,
        (true,  _,       Down) => Clicked,
        (true,  _,       Up)   => Highlighted,
        (false, Clicked, Down) => Clicked,
        _ => Normal,
    }
}

/// A context on which the builder pattern can be implemented.
pub struct Slider<'a, T, F> {
    ui_id: UIID,
    value: T,
    min: T,
    max: T,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_label: Option<&'a str>,
    maybe_label_color: Option<Color>,
    maybe_label_font_size: Option<u32>,
}

impl<'a, T, F> Slider<'a, T, F> {
    /// A button builder method to be implemented by the UiContext.
    pub fn new(ui_id: UIID, value: T, min: T, max: T) -> Slider<'a, T, F> {
        Slider {
            ui_id: ui_id,
            value: value,
            min: min,
            max: max,
            pos: [0.0, 0.0],
            dim: [192.0, 48.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_label: None,
            maybe_label_color: None,
            maybe_label_font_size: None,
        }
    }
}

impl<'a, T, F> Colorable for Slider<'a, T, F> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

impl<'a, T, F> Frameable for Slider<'a, T, F> {
    fn frame(mut self, width: f64) -> Self {
        self.maybe_frame = Some(width);
        self
    }
    fn frame_color(mut self, color: Color) -> Self {
        self.maybe_frame_color = Some(color);
        self
    }
}

impl<'a, T, F> Callable<F> for Slider<'a, T, F> {
    fn callback(mut self, cb: F) -> Self {
        self.maybe_callback = Some(cb);
        self
    }
}

impl<'a, T, F> Labelable<'a> for Slider<'a, T, F>
{
    fn label(mut self, text: &'a str) -> Self {
        self.maybe_label = Some(text);
        self
    }

    fn label_color(mut self, color: Color) -> Self {
        self.maybe_label_color = Some(color);
        self
    }

    fn label_font_size(mut self, size: FontSize) -> Self {
        self.maybe_label_font_size = Some(size);
        self
    }
}

/*
quack! {
    slider: Slider['a, T, F]
    get:
        fn () -> Size [] { Size(slider.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(Widget::Slider(State::Normal))
        }
        fn () -> Id [] { Id(slider.ui_id) }
    set:
        fn (val: Position) [] { slider.pos = val.0 }
        fn (val: Size) [] { slider.dim = val.0 }
    action:
}
*/

impl<'a, T, F> ::draw::Drawable for Slider<'a, T, F>
    where
        T: Float + FromPrimitive + ToPrimitive,
        F: FnMut(T) + 'a
{

    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {

        let state = *get_state(uic, self.ui_id);
        let mouse = uic.get_mouse_state();
        let is_over = rectangle::is_over(self.pos, mouse.pos, self.dim);
        let new_state = get_new_state(is_over, state, mouse);

        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let frame_w2 = frame_w * 2.0;
        let frame_color = self.maybe_frame_color.unwrap_or(uic.theme.frame_color);

        let is_horizontal = self.dim[0] > self.dim[1];
        let (new_value, pad_pos, pad_dim) = if is_horizontal {
            // Horizontal.
            let p = vec2_add(self.pos, [frame_w, frame_w]);
            let max_w = self.dim[0] - frame_w2;
            let w = match (is_over, state, new_state) {
                (true, State::Highlighted, State::Clicked) | (_, State::Clicked, State::Clicked)  =>
                     clamp(mouse.pos[0] - p[0], 0f64, max_w),
                _ => clamp(percentage(self.value, self.min, self.max) as f64 * max_w, 0f64, max_w),
            };
            let h = self.dim[1] - frame_w2;
            let new_value = value_from_perc((w / max_w) as f32, self.min, self.max);
            (new_value, p, [w, h])
        } else {
            // Vertical.
            let max_h = self.dim[1] - frame_w2;
            let corner = vec2_add(self.pos, [frame_w, frame_w]);
            let y_max = corner[1] + max_h;
            let (h, p) = match (is_over, state, new_state) {
                (true, State::Highlighted, State::Clicked) | (_, State::Clicked, State::Clicked) => {
                    let p = [corner[0], clamp(mouse.pos[1], corner[1], y_max)];
                    let h = clamp(max_h - (p[1] - corner[1]), 0.0, max_h);
                    (h, p)
                },
                _ => {
                    let h = clamp(percentage(self.value, self.min, self.max) as f64 * max_h, 0.0, max_h);
                    let p = [corner[0], corner[1] + max_h - h];
                    (h, p)
                },
            };
            let w = self.dim[0] - frame_w2;
            let new_value = value_from_perc((h / max_h) as f32, self.min, self.max);
            (new_value, p, [w, h])
        };

        // Callback.
        match self.maybe_callback {
            Some(ref mut callback) => {
                if self.value != new_value || match (state, new_state) {
                    (State::Highlighted, State::Clicked) | (State::Clicked, State::Highlighted) => true,
                    _ => false,
                } { (*callback)(new_value) }
            }, None => (),
        }

        // Draw.
        let rect_state = new_state.as_rectangle_state();
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);

        // Rectangle frame / backdrop.
        rectangle::draw(uic.win_w, uic.win_h, graphics, rect_state,
                        self.pos, self.dim, None, frame_color);
        // Slider rectangle.
        rectangle::draw(uic.win_w, uic.win_h, graphics, rect_state,
                        pad_pos, pad_dim, None, color);

        // If there's a label, draw it.
        if let Some(text) = self.maybe_label {
            let text_color = self.maybe_label_color.unwrap_or(uic.theme.label_color);
            let size = self.maybe_label_font_size.unwrap_or(uic.theme.font_size_medium);
            let is_horizontal = self.dim[0] > self.dim[1];
            let l_pos = if is_horizontal {
                let x = pad_pos[0] + (pad_dim[1] - size as f64) / 2.0;
                let y = pad_pos[1] + (pad_dim[1] - size as f64) / 2.0;
                [x, y]
            } else {
                let label_w = label::width(uic, size, &text);
                let x = pad_pos[0] + (pad_dim[0] - label_w) / 2.0;
                let y = pad_pos[1] + pad_dim[1] - pad_dim[0] - frame_w;
                [x, y]
            };
            // Draw the label.
            uic.draw_text(graphics, l_pos, size, text_color, &text);
        }

        set_state(uic, self.ui_id, Widget::Slider(new_state), self.pos, self.dim);

    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Maciej Dziardziel <fiedzia@gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.

// spell-checker:ignore (vars/api) fcntl setrlimit setitimer
// spell-checker:ignore (vars/signals) ABRT ALRM CHLD SEGV SIGABRT SIGALRM SIGBUS SIGCHLD SIGCONT SIGEMT SIGFPE SIGHUP SIGILL SIGINFO SIGINT SIGIO SIGIOT SIGKILL SIGPIPE SIGPROF SIGQUIT SIGSEGV SIGSTOP SIGSYS SIGTERM SIGTRAP SIGTSTP SIGTTIN SIGTTOU SIGURG SIGUSR SIGVTALRM SIGWINCH SIGXCPU SIGXFSZ STKFLT TSTP TTIN TTOU VTALRM XCPU XFSZ

pub static DEFAULT_SIGNAL: usize = 15;

pub struct Signal<'a> {
    pub name: &'a str,
    pub value: usize,
}

/*

Linux Programmer's Manual

 1 HUP      2 INT      3 QUIT     4 ILL      5 TRAP     6 ABRT     7 BUS
 8 FPE      9 KILL    10 USR1    11 SEGV    12 USR2    13 PIPE    14 ALRM
15 TERM    16 STKFLT  17 CHLD    18 CONT    19 STOP    20 TSTP    21 TTIN
22 TTOU    23 URG     24 XCPU    25 XFSZ    26 VTALRM  27 PROF    28 WINCH
29 POLL    30 PWR     31 SYS

*/

#[cfg(target_os = "linux")]
pub static ALL_SIGNALS: [Signal<'static>; 31] = [
    Signal {
        name: "HUP",
        value: 1,
    },
    Signal {
        name: "INT",
        value: 2,
    },
    Signal {
        name: "QUIT",
        value: 3,
    },
    Signal {
        name: "ILL",
        value: 4,
    },
    Signal {
        name: "TRAP",
        value: 5,
    },
    Signal {
        name: "ABRT",
        value: 6,
    },
    Signal {
        name: "BUS",
        value: 7,
    },
    Signal {
        name: "FPE",
        value: 8,
    },
    Signal {
        name: "KILL",
        value: 9,
    },
    Signal {
        name: "USR1",
        value: 10,
    },
    Signal {
        name: "SEGV",
        value: 11,
    },
    Signal {
        name: "USR2",
        value: 12,
    },
    Signal {
        name: "PIPE",
        value: 13,
    },
    Signal {
        name: "ALRM",
        value: 14,
    },
    Signal {
        name: "TERM",
        value: 15,
    },
    Signal {
        name: "STKFLT",
        value: 16,
    },
    Signal {
        name: "CHLD",
        value: 17,
    },
    Signal {
        name: "CONT",
        value: 18,
    },
    Signal {
        name: "STOP",
        value: 19,
    },
    Signal {
        name: "TSTP",
        value: 20,
    },
    Signal {
        name: "TTIN",
        value: 21,
    },
    Signal {
        name: "TTOU",
        value: 22,
    },
    Signal {
        name: "URG",
        value: 23,
    },
    Signal {
        name: "XCPU",
        value: 24,
    },
    Signal {
        name: "XFSZ",
        value: 25,
    },
    Signal {
        name: "VTALRM",
        value: 26,
    },
    Signal {
        name: "PROF",
        value: 27,
    },
    Signal {
        name: "WINCH",
        value: 28,
    },
    Signal {
        name: "POLL",
        value: 29,
    },
    Signal {
        name: "PWR",
        value: 30,
    },
    Signal {
        name: "SYS",
        value: 31,
    },
];

/*

https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/signal.3.html

No    Name         Default Action       Description
1     SIGHUP       terminate process    terminal line hangup
2     SIGINT       terminate process    interrupt program
3     SIGQUIT      create core image    quit program
4     SIGILL       create core image    illegal instruction
5     SIGTRAP      create core image    trace trap
6     SIGABRT      create core image    abort program (formerly SIGIOT)
7     SIGEMT       create core image    emulate instruction executed
8     SIGFPE       create core image    floating-point exception
9     SIGKILL      terminate process    kill program
10    SIGBUS       create core image    bus error
11    SIGSEGV      create core image    segmentation violation
12    SIGSYS       create core image    non-existent system call invoked
13    SIGPIPE      terminate process    write on a pipe with no reader
14    SIGALRM      terminate process    real-time timer expired
15    SIGTERM      terminate process    software termination signal
16    SIGURG       discard signal       urgent condition present on socket
17    SIGSTOP      stop process         stop (cannot be caught or ignored)
18    SIGTSTP      stop process         stop signal generated from keyboard
19    SIGCONT      discard signal       continue after stop
20    SIGCHLD      discard signal       child status has changed
21    SIGTTIN      stop process         background read attempted from control terminal
22    SIGTTOU      stop process         background write attempted to control terminal
23    SIGIO        discard signal       I/O is possible on a descriptor (see fcntl(2))
24    SIGXCPU      terminate process    cpu time limit exceeded (see setrlimit(2))
25    SIGXFSZ      terminate process    file size limit exceeded (see setrlimit(2))
26    SIGVTALRM    terminate process    virtual time alarm (see setitimer(2))
27    SIGPROF      terminate process    profiling timer alarm (see setitimer(2))
28    SIGWINCH     discard signal       Window size change
29    SIGINFO      discard signal       status request from keyboard
30    SIGUSR1      terminate process    User defined signal 1
31    SIGUSR2      terminate process    User defined signal 2

*/

#[cfg(any(target_vendor = "apple", target_os = "freebsd"))]
pub static ALL_SIGNALS: [Signal<'static>; 31] = [
    Signal {
        name: "HUP",
        value: 1,
    },
    Signal {
        name: "INT",
        value: 2,
    },
    Signal {
        name: "QUIT",
        value: 3,
    },
    Signal {
        name: "ILL",
        value: 4,
    },
    Signal {
        name: "TRAP",
        value: 5,
    },
    Signal {
        name: "ABRT",
        value: 6,
    },
    Signal {
        name: "EMT",
        value: 7,
    },
    Signal {
        name: "FPE",
        value: 8,
    },
    Signal {
        name: "KILL",
        value: 9,
    },
    Signal {
        name: "BUS",
        value: 10,
    },
    Signal {
        name: "SEGV",
        value: 11,
    },
    Signal {
        name: "SYS",
        value: 12,
    },
    Signal {
        name: "PIPE",
        value: 13,
    },
    Signal {
        name: "ALRM",
        value: 14,
    },
    Signal {
        name: "TERM",
        value: 15,
    },
    Signal {
        name: "URG",
        value: 16,
    },
    Signal {
        name: "STOP",
        value: 17,
    },
    Signal {
        name: "TSTP",
        value: 18,
    },
    Signal {
        name: "CONT",
        value: 19,
    },
    Signal {
        name: "CHLD",
        value: 20,
    },
    Signal {
        name: "TTIN",
        value: 21,
    },
    Signal {
        name: "TTOU",
        value: 22,
    },
    Signal {
        name: "IO",
        value: 23,
    },
    Signal {
        name: "XCPU",
        value: 24,
    },
    Signal {
        name: "XFSZ",
        value: 25,
    },
    Signal {
        name: "VTALRM",
        value: 26,
    },
    Signal {
        name: "PROF",
        value: 27,
    },
    Signal {
        name: "WINCH",
        value: 28,
    },
    Signal {
        name: "INFO",
        value: 29,
    },
    Signal {
        name: "USR1",
        value: 30,
    },
    Signal {
        name: "USR2",
        value: 31,
    },
];

pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option<usize> {
    if let Ok(value) = signal_name_or_value.parse() {
        if is_signal(value) {
            return Some(value);
        } else {
            return None;
        }
    }
    let signal_name = signal_name_or_value.trim_start_matches("SIG");

    ALL_SIGNALS
        .iter()
        .find(|s| s.name == signal_name)
        .map(|s| s.value)
}

#[inline(always)]
pub fn is_signal(num: usize) -> bool {
    // Named signals start at 1
    num <= ALL_SIGNALS.len()
}

#[test]
fn signals_all_contiguous() {
    for (i, signal) in ALL_SIGNALS.iter().enumerate() {
        assert_eq!(signal.value, i + 1);
    }
}

#[test]
fn signals_all_are_signal() {
    for signal in &ALL_SIGNALS {
        assert!(is_signal(signal.value));
    }
}

#[test]
fn signal_by_value() {
    assert_eq!(signal_by_name_or_value("0"), Some(0));
    for signal in &ALL_SIGNALS {
        assert_eq!(
            signal_by_name_or_value(&signal.value.to_string()),
            Some(signal.value)
        );
    }
}

#[test]
fn signal_by_short_name() {
    for signal in &ALL_SIGNALS {
        assert_eq!(signal_by_name_or_value(signal.name), Some(signal.value));
    }
}

#[test]
fn signal_by_long_name() {
    for signal in &ALL_SIGNALS {
        assert_eq!(
            signal_by_name_or_value(&format!("SIG{}", signal.name)),
            Some(signal.value)
        );
    }
}
<commit_msg>core: add EXIT signal<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Maciej Dziardziel <fiedzia@gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.

// spell-checker:ignore (vars/api) fcntl setrlimit setitimer
// spell-checker:ignore (vars/signals) ABRT ALRM CHLD SEGV SIGABRT SIGALRM SIGBUS SIGCHLD SIGCONT SIGEMT SIGFPE SIGHUP SIGILL SIGINFO SIGINT SIGIO SIGIOT SIGKILL SIGPIPE SIGPROF SIGQUIT SIGSEGV SIGSTOP SIGSYS SIGTERM SIGTRAP SIGTSTP SIGTTIN SIGTTOU SIGURG SIGUSR SIGVTALRM SIGWINCH SIGXCPU SIGXFSZ STKFLT TSTP TTIN TTOU VTALRM XCPU XFSZ

pub static DEFAULT_SIGNAL: usize = 15;

pub struct Signal<'a> {
    pub name: &'a str,
    pub value: usize,
}

/*

Linux Programmer's Manual

 1 HUP      2 INT      3 QUIT     4 ILL      5 TRAP     6 ABRT     7 BUS
 8 FPE      9 KILL    10 USR1    11 SEGV    12 USR2    13 PIPE    14 ALRM
15 TERM    16 STKFLT  17 CHLD    18 CONT    19 STOP    20 TSTP    21 TTIN
22 TTOU    23 URG     24 XCPU    25 XFSZ    26 VTALRM  27 PROF    28 WINCH
29 POLL    30 PWR     31 SYS

*/

#[cfg(target_os = "linux")]
pub static ALL_SIGNALS: [Signal<'static>; 32] = [
    Signal {
        name: "EXIT",
        value: 0,
    },
    Signal {
        name: "HUP",
        value: 1,
    },
    Signal {
        name: "INT",
        value: 2,
    },
    Signal {
        name: "QUIT",
        value: 3,
    },
    Signal {
        name: "ILL",
        value: 4,
    },
    Signal {
        name: "TRAP",
        value: 5,
    },
    Signal {
        name: "ABRT",
        value: 6,
    },
    Signal {
        name: "BUS",
        value: 7,
    },
    Signal {
        name: "FPE",
        value: 8,
    },
    Signal {
        name: "KILL",
        value: 9,
    },
    Signal {
        name: "USR1",
        value: 10,
    },
    Signal {
        name: "SEGV",
        value: 11,
    },
    Signal {
        name: "USR2",
        value: 12,
    },
    Signal {
        name: "PIPE",
        value: 13,
    },
    Signal {
        name: "ALRM",
        value: 14,
    },
    Signal {
        name: "TERM",
        value: 15,
    },
    Signal {
        name: "STKFLT",
        value: 16,
    },
    Signal {
        name: "CHLD",
        value: 17,
    },
    Signal {
        name: "CONT",
        value: 18,
    },
    Signal {
        name: "STOP",
        value: 19,
    },
    Signal {
        name: "TSTP",
        value: 20,
    },
    Signal {
        name: "TTIN",
        value: 21,
    },
    Signal {
        name: "TTOU",
        value: 22,
    },
    Signal {
        name: "URG",
        value: 23,
    },
    Signal {
        name: "XCPU",
        value: 24,
    },
    Signal {
        name: "XFSZ",
        value: 25,
    },
    Signal {
        name: "VTALRM",
        value: 26,
    },
    Signal {
        name: "PROF",
        value: 27,
    },
    Signal {
        name: "WINCH",
        value: 28,
    },
    Signal {
        name: "POLL",
        value: 29,
    },
    Signal {
        name: "PWR",
        value: 30,
    },
    Signal {
        name: "SYS",
        value: 31,
    },
];

/*

https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/signal.3.html

No    Name         Default Action       Description
1     SIGHUP       terminate process    terminal line hangup
2     SIGINT       terminate process    interrupt program
3     SIGQUIT      create core image    quit program
4     SIGILL       create core image    illegal instruction
5     SIGTRAP      create core image    trace trap
6     SIGABRT      create core image    abort program (formerly SIGIOT)
7     SIGEMT       create core image    emulate instruction executed
8     SIGFPE       create core image    floating-point exception
9     SIGKILL      terminate process    kill program
10    SIGBUS       create core image    bus error
11    SIGSEGV      create core image    segmentation violation
12    SIGSYS       create core image    non-existent system call invoked
13    SIGPIPE      terminate process    write on a pipe with no reader
14    SIGALRM      terminate process    real-time timer expired
15    SIGTERM      terminate process    software termination signal
16    SIGURG       discard signal       urgent condition present on socket
17    SIGSTOP      stop process         stop (cannot be caught or ignored)
18    SIGTSTP      stop process         stop signal generated from keyboard
19    SIGCONT      discard signal       continue after stop
20    SIGCHLD      discard signal       child status has changed
21    SIGTTIN      stop process         background read attempted from control terminal
22    SIGTTOU      stop process         background write attempted to control terminal
23    SIGIO        discard signal       I/O is possible on a descriptor (see fcntl(2))
24    SIGXCPU      terminate process    cpu time limit exceeded (see setrlimit(2))
25    SIGXFSZ      terminate process    file size limit exceeded (see setrlimit(2))
26    SIGVTALRM    terminate process    virtual time alarm (see setitimer(2))
27    SIGPROF      terminate process    profiling timer alarm (see setitimer(2))
28    SIGWINCH     discard signal       Window size change
29    SIGINFO      discard signal       status request from keyboard
30    SIGUSR1      terminate process    User defined signal 1
31    SIGUSR2      terminate process    User defined signal 2

*/

#[cfg(any(target_vendor = "apple", target_os = "freebsd"))]
pub static ALL_SIGNALS: [Signal<'static>; 32] = [
    Signal {
        name: "EXIT",
        value: 0,
    },
    Signal {
        name: "HUP",
        value: 1,
    },
    Signal {
        name: "INT",
        value: 2,
    },
    Signal {
        name: "QUIT",
        value: 3,
    },
    Signal {
        name: "ILL",
        value: 4,
    },
    Signal {
        name: "TRAP",
        value: 5,
    },
    Signal {
        name: "ABRT",
        value: 6,
    },
    Signal {
        name: "EMT",
        value: 7,
    },
    Signal {
        name: "FPE",
        value: 8,
    },
    Signal {
        name: "KILL",
        value: 9,
    },
    Signal {
        name: "BUS",
        value: 10,
    },
    Signal {
        name: "SEGV",
        value: 11,
    },
    Signal {
        name: "SYS",
        value: 12,
    },
    Signal {
        name: "PIPE",
        value: 13,
    },
    Signal {
        name: "ALRM",
        value: 14,
    },
    Signal {
        name: "TERM",
        value: 15,
    },
    Signal {
        name: "URG",
        value: 16,
    },
    Signal {
        name: "STOP",
        value: 17,
    },
    Signal {
        name: "TSTP",
        value: 18,
    },
    Signal {
        name: "CONT",
        value: 19,
    },
    Signal {
        name: "CHLD",
        value: 20,
    },
    Signal {
        name: "TTIN",
        value: 21,
    },
    Signal {
        name: "TTOU",
        value: 22,
    },
    Signal {
        name: "IO",
        value: 23,
    },
    Signal {
        name: "XCPU",
        value: 24,
    },
    Signal {
        name: "XFSZ",
        value: 25,
    },
    Signal {
        name: "VTALRM",
        value: 26,
    },
    Signal {
        name: "PROF",
        value: 27,
    },
    Signal {
        name: "WINCH",
        value: 28,
    },
    Signal {
        name: "INFO",
        value: 29,
    },
    Signal {
        name: "USR1",
        value: 30,
    },
    Signal {
        name: "USR2",
        value: 31,
    },
];

pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option<usize> {
    if let Ok(value) = signal_name_or_value.parse() {
        if is_signal(value) {
            return Some(value);
        } else {
            return None;
        }
    }
    let signal_name = signal_name_or_value.trim_start_matches("SIG");

    ALL_SIGNALS
        .iter()
        .find(|s| s.name == signal_name)
        .map(|s| s.value)
}

#[inline(always)]
pub fn is_signal(num: usize) -> bool {
    // Named signals start at 1
    num <= ALL_SIGNALS.len()
}

#[test]
fn signals_all_contiguous() {
    for (i, signal) in ALL_SIGNALS.iter().enumerate() {
        assert_eq!(signal.value, i + 1);
    }
}

#[test]
fn signals_all_are_signal() {
    for signal in &ALL_SIGNALS {
        assert!(is_signal(signal.value));
    }
}

#[test]
fn signal_by_value() {
    assert_eq!(signal_by_name_or_value("0"), Some(0));
    for signal in &ALL_SIGNALS {
        assert_eq!(
            signal_by_name_or_value(&signal.value.to_string()),
            Some(signal.value)
        );
    }
}

#[test]
fn signal_by_short_name() {
    for signal in &ALL_SIGNALS {
        assert_eq!(signal_by_name_or_value(signal.name), Some(signal.value));
    }
}

#[test]
fn signal_by_long_name() {
    for signal in &ALL_SIGNALS {
        assert_eq!(
            signal_by_name_or_value(&format!("SIG{}", signal.name)),
            Some(signal.value)
        );
    }
}
<|endoftext|>


<commit_before>//
//    Stachanov
//    Copyright (C) 2017 Stachanov Developer Collective
//
//    This file is part of Stachanov.
//
//    This program is free software: you can redistribute it and/or
//    modify it under the terms of the GNU Affero General Public
//    License, version 3, as published by the Free Software Foundation.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU Affero General Public License for more details.
//
//    You should have received a copy of the
//               GNU Affero General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

use std::collections::HashMap;
use blockchain::traits::Hashable;
use blockchain::block::BlockId;

// NOTE: This module currently only consists of
// a dummy implementation

#[derive(Clone)]
pub enum Transaction{
    Dummy
}

impl Hashable for Transaction{

    fn to_sha3_hash(&self) -> [u8; 32]{
        [0; 32]
    }

}

/// TxId denotes a registered transaction in the chain.
/// It is composed of the BlockId pointing to a block
/// in the chain and a u16 index pointing to a position
/// in the list of transactions in that block.

// NOTE: since we can address only 2**16 transactions,
// the maximum number of transactions per block is
// limited to 65536 transactions. I chose an u16 over
// a u32, so systems with smaller memory are not
// overburdend.

#[derive(Clone)]
pub struct TxId{
    block_id: BlockId,
    tx_index: u16,
}

/// TxRel denotes the relationship between two transactions.
/// Transactions can relate in various ways to each other.
/// For example workloads can be transformed into coupons,
/// coupons can be redeemed in a relation to a dispatcher
/// collective, etc

#[derive(Hash)]
#[derive(Clone)]
pub enum TxRel{
    Dummy
}

/// TxLinkState denotes the state of a (possible) link
/// between transactions
///
/// * `Unlinked`: The link points to no future target so far
/// * `SingleLinked(TxId)': The link points to a single target
///         in the future and is seen as 'spent', which means,
///         no other target transaction can be linked to the
///         source transaction in the same relationship.
/// * `MultiLinked(Vec<TxId>)`: The link points to a set of
///         transactions in the future. This is utilized by
///         transactions such as Order, that can have links
///         to multiple workloads. If a transaction is multi-
///         linked, it is the responsibility of the link
///         verification mechanism to check if possible
///         quotas are exceeded.

#[derive(Clone)]
enum TxLinkState{
    Unlinked,
    SingleLinked(TxId),
    MultiLinked(Vec<TxId>)
}

/// TxLinkMapState denotes the general link state of a
/// transaction. Depending on its value it can overwrite
/// the single link states. It can take the values:
///
/// * `Linkable`: The transaction can _generally_ be linked
///         to other transactions. This means that the linking
///         permit depends on the TxLinkState of the
///         relationship that should be established
/// * `Unlinkable`: The transaction can not be linked to any
///         other transaction (anymore). This state should
///         be used when a transaction type is deprecated
///         by a later system version or if the list of
///         (possible) links / relationships is empty
/// * `Finalized`: The transaction was finalized by another
///         transaction and can not link to a future target
///         transaction anymore.

#[derive(Clone)]
enum TxLinkMapState{
    Linkable,
    Unlinkable,
    Finalized(TxId),
}

/// TxLinkMap defines existing and possible links of a transaction
/// to future transactions. It maps transaction relationships to
/// TxLinkStates and holds a TxLinkMapState to denote the general
/// link state of the transaction.

#[derive(Clone)]
pub struct TxLinkMap{
    state: TxLinkMapState,
    links: HashMap<TxRel, TxLinkState>
}
<commit_msg>REFACTOR typewrapped tx_index + pub'd TxId fields<commit_after>//
//    Stachanov
//    Copyright (C) 2017 Stachanov Developer Collective
//
//    This file is part of Stachanov.
//
//    This program is free software: you can redistribute it and/or
//    modify it under the terms of the GNU Affero General Public
//    License, version 3, as published by the Free Software Foundation.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU Affero General Public License for more details.
//
//    You should have received a copy of the
//               GNU Affero General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

use std::collections::HashMap;
use blockchain::traits::Hashable;
use blockchain::block::BlockId;

// NOTE: This module currently only consists of
// a dummy implementation

#[derive(Clone)]
pub enum Transaction{
    Dummy
}

impl Hashable for Transaction{

    fn to_sha3_hash(&self) -> [u8; 32]{
        [0; 32]
    }

}

/// TxIndex typewraps an u16 int. It denotes the index
/// in the transaction vector of a single block

// NOTE: since we can address only 2**16 transactions,
// the maximum number of transactions per block is
// limited to 65536 transactions. I chose an u16 over
// a u32, so systems with smaller memory are not
// overburdend.

#[derive(Clone)]
pub struct TxIndex(pub u16);

/// TxId denotes a registered transaction in the chain.
/// It is composed of the BlockId pointing to a block
/// in the chain and a u16 index pointing to a position
/// in the list of transactions in that block.

#[derive(Clone)]
pub struct TxId{
    pub block_id: BlockId,
    pub tx_index: TxIndex,
}

/// TxRel denotes the relationship between two transactions.
/// Transactions can relate in various ways to each other.
/// For example workloads can be transformed into coupons,
/// coupons can be redeemed in a relation to a dispatcher
/// collective, etc

#[derive(Hash)]
#[derive(Clone)]
pub enum TxRel{
    Dummy
}

/// TxLinkState denotes the state of a (possible) link
/// between transactions
///
/// * `Unlinked`: The link points to no future target so far
/// * `SingleLinked(TxId)': The link points to a single target
///         in the future and is seen as 'spent', which means,
///         no other target transaction can be linked to the
///         source transaction in the same relationship.
/// * `MultiLinked(Vec<TxId>)`: The link points to a set of
///         transactions in the future. This is utilized by
///         transactions such as Order, that can have links
///         to multiple workloads. If a transaction is multi-
///         linked, it is the responsibility of the link
///         verification mechanism to check if possible
///         quotas are exceeded.

#[derive(Clone)]
enum TxLinkState{
    Unlinked,
    SingleLinked(TxId),
    MultiLinked(Vec<TxId>)
}

/// TxLinkMapState denotes the general link state of a
/// transaction. Depending on its value it can overwrite
/// the single link states. It can take the values:
///
/// * `Linkable`: The transaction can _generally_ be linked
///         to other transactions. This means that the linking
///         permit depends on the TxLinkState of the
///         relationship that should be established
/// * `Unlinkable`: The transaction can not be linked to any
///         other transaction (anymore). This state should
///         be used when a transaction type is deprecated
///         by a later system version or if the list of
///         (possible) links / relationships is empty
/// * `Finalized`: The transaction was finalized by another
///         transaction and can not link to a future target
///         transaction anymore.

#[derive(Clone)]
enum TxLinkMapState{
    Linkable,
    Unlinkable,
    Finalized(TxId),
}

/// TxLinkMap defines existing and possible links of a transaction
/// to future transactions. It maps transaction relationships to
/// TxLinkStates and holds a TxLinkMapState to denote the general
/// link state of the transaction.

#[derive(Clone)]
pub struct TxLinkMap{
    state: TxLinkMapState,
    links: HashMap<TxRel, TxLinkState>
}
<|endoftext|>


<commit_before><commit_msg>bench: update spawn benchmarks (#3927)<commit_after><|endoftext|>


<commit_before>use std::io;

use error::Error;
use token::Sentence;

/// A trait for objects that can write CoNLL-X `Sentence`s.
pub trait WriteSentence {
    /// Write a `Sentence` into this object.
    ///
    /// # Errors
    ///
    /// A call to `write_sentence` may generate an error to indicate that
    /// the operation could not be completed.
    fn write_sentence(&mut self, sentence: &Sentence) -> Result<(), Error>;
}

/// A writer for CoNLL-X sentences.
///
/// This writer will write sentences to the embedded writer in CoNLL-X
/// tabular format.
pub struct Writer<W> {
    write: W,
    first: bool,
}

impl<W: io::Write> Writer<W> {
    /// Construct a new writer from an object that implements the `io::Write`
    /// trait.
    pub fn new(write: W) -> Writer<W> {
        Writer {
            write: write,
            first: true,
        }
    }

    /// Borrow the embedded writer. Getting the underlying writer is often
    /// useful when the writer writes to a memory object.
    ///
    /// # Examples
    ///
    /// ```
    /// use conllx::{Sentence, Token, WriteSentence, Writer};
    /// use std::str;
    ///
    /// let output = Vec::new();
    /// let mut writer = Writer::new(output);
    /// let sent = Sentence::new(vec![
    ///   Token::new(),
    ///   Token::new(),
    /// ]);
    ///
    /// writer.write_sentence(&sent).unwrap();
    ///
    /// println!("Output:\n{}", str::from_utf8(writer.get_ref()).unwrap());
    /// ```
    pub fn get_ref(&self) -> &W {
        &self.write
    }
}

impl<W: io::Write> WriteSentence for Writer<W> {
    fn write_sentence(&mut self, sentence: &Sentence) -> Result<(), Error> {
        if self.first {
            self.first = false;
            try!(write!(self.write, "{}", sentence))
        } else {
            try!(write!(self.write, "\n\n{}", sentence))
        }

        Ok(())
    }
}

/// A writer for CoNLL-X sentences that partitions incoming objects
/// among multiple writers.
///
/// For example, suppose that a `PartitioningWriter` is wraps writers
/// *w1*, *w2*, and sentences s_[1-5]$ are written. The sentences are then
/// written as follows:
///
/// * s1 -> w1
/// * s2 -> w2
/// * s3 -> w1
/// * s4 -> w2
/// * s5 -> w1
pub struct PartitioningWriter<W>
    where W: WriteSentence
{
    writers: Vec<W>,
    fold: usize,
}

impl<W> PartitioningWriter<W>
    where W: WriteSentence
{
    pub fn new(writers: Vec<W>) -> PartitioningWriter<W> {
        PartitioningWriter {
            writers: writers,
            fold: 0,
        }
    }
}

impl<W> WriteSentence for PartitioningWriter<W>
    where W: WriteSentence
{
    fn write_sentence(&mut self, sentence: &Sentence) -> Result<(), Error> {
        if self.fold == self.writers.len() {
            self.fold = 0
        }

        try!(self.writers[self.fold].write_sentence(sentence));
        self.fold += 1;

        Ok(())
    }
}
<commit_msg>Small documentation markup fix.<commit_after>use std::io;

use error::Error;
use token::Sentence;

/// A trait for objects that can write CoNLL-X `Sentence`s.
pub trait WriteSentence {
    /// Write a `Sentence` into this object.
    ///
    /// # Errors
    ///
    /// A call to `write_sentence` may generate an error to indicate that
    /// the operation could not be completed.
    fn write_sentence(&mut self, sentence: &Sentence) -> Result<(), Error>;
}

/// A writer for CoNLL-X sentences.
///
/// This writer will write sentences to the embedded writer in CoNLL-X
/// tabular format.
pub struct Writer<W> {
    write: W,
    first: bool,
}

impl<W: io::Write> Writer<W> {
    /// Construct a new writer from an object that implements the `io::Write`
    /// trait.
    pub fn new(write: W) -> Writer<W> {
        Writer {
            write: write,
            first: true,
        }
    }

    /// Borrow the embedded writer. Getting the underlying writer is often
    /// useful when the writer writes to a memory object.
    ///
    /// # Examples
    ///
    /// ```
    /// use conllx::{Sentence, Token, WriteSentence, Writer};
    /// use std::str;
    ///
    /// let output = Vec::new();
    /// let mut writer = Writer::new(output);
    /// let sent = Sentence::new(vec![
    ///   Token::new(),
    ///   Token::new(),
    /// ]);
    ///
    /// writer.write_sentence(&sent).unwrap();
    ///
    /// println!("Output:\n{}", str::from_utf8(writer.get_ref()).unwrap());
    /// ```
    pub fn get_ref(&self) -> &W {
        &self.write
    }
}

impl<W: io::Write> WriteSentence for Writer<W> {
    fn write_sentence(&mut self, sentence: &Sentence) -> Result<(), Error> {
        if self.first {
            self.first = false;
            try!(write!(self.write, "{}", sentence))
        } else {
            try!(write!(self.write, "\n\n{}", sentence))
        }

        Ok(())
    }
}

/// A writer for CoNLL-X sentences that partitions incoming objects
/// among multiple writers.
///
/// For example, suppose that a `PartitioningWriter` is wraps writers
/// *w1*, *w2*, and sentences *s[1-5]* are written. The sentences are then
/// written as follows:
///
/// * s1 -> w1
/// * s2 -> w2
/// * s3 -> w1
/// * s4 -> w2
/// * s5 -> w1
pub struct PartitioningWriter<W>
    where W: WriteSentence
{
    writers: Vec<W>,
    fold: usize,
}

impl<W> PartitioningWriter<W>
    where W: WriteSentence
{
    pub fn new(writers: Vec<W>) -> PartitioningWriter<W> {
        PartitioningWriter {
            writers: writers,
            fold: 0,
        }
    }
}

impl<W> WriteSentence for PartitioningWriter<W>
    where W: WriteSentence
{
    fn write_sentence(&mut self, sentence: &Sentence) -> Result<(), Error> {
        if self.fold == self.writers.len() {
            self.fold = 0
        }

        try!(self.writers[self.fold].write_sentence(sentence));
        self.fold += 1;

        Ok(())
    }
}
<|endoftext|>


<commit_before>// Options
// Space before /
// Quote style
// Ordering of attributes

#[cfg(test)]
mod test {
    use std::io::{IoResult,MemWriter};

    use super::super::{Document,Element,Text,Comment,ProcessingInstruction};
    use super::super::{ElementElementChild,TextElementChild,CommentElementChild,PIElementChild};

    macro_rules! assert_str_eq(
        ($l:expr, $r:expr) => (assert_eq!($l.as_slice(), $r.as_slice()));
    )

    enum Content {
        WElement(Element),
        WElementEnd(String),
        WText(Text),
        WComment(Comment),
        WProcessingInstruction(ProcessingInstruction),
    }

    fn format_element<W : Writer>(element: Element, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
        try!(write!(writer, "<{}", element.name()));

        for attr in element.attributes().iter() {
            try!(write!(writer, " {}='{}'", attr.name(), attr.value()));
        }

        let mut children = element.children();
        if children.is_empty() {
            writer.write_str("/>")
        } else {
            try!(writer.write_str(">"));

            todo.push(WElementEnd(element.name()));
            children.reverse();
            let x = children.move_iter().map(|c| match c {
                ElementElementChild(element) => WElement(element),
                TextElementChild(t) => WText(t),
                CommentElementChild(c) => WComment(c),
                PIElementChild(p) => WProcessingInstruction(p),
            }).collect();
            todo.push_all_move(x);

            Ok(())
        }
    }

    fn format_processing_instruction<W : Writer>(pi: ProcessingInstruction, writer: &mut W) -> IoResult<()> {
        match pi.value() {
            None    => write!(writer, "<?{}?>", pi.target()),
            Some(v) => write!(writer, "<?{} {}?>", pi.target(), v),
        }
    }

    fn format_document<W : Writer>(doc: &Document, writer: &mut W) -> IoResult<()> {
        let mut todo = Vec::new();

        try!(writer.write_str("<?xml version='1.0'?>"));
        let e = doc.root().children()[0].element().expect("not an element?");

        todo.push(WElement(e));

        while ! todo.is_empty() {
            match todo.pop().unwrap() {
                WElement(e) => try!(format_element(e, &mut todo, writer)),
                WElementEnd(name) => try!(write!(writer, "</{}>", name)),
                WText(t) => try!(writer.write_str(t.text().as_slice())),
                WComment(c) => try!(write!(writer, "<!--{}-->", c.text())),
                WProcessingInstruction(p) => try!(format_processing_instruction(p, writer)),
            }
        }

        Ok(())
    }

    fn format_xml(doc: &Document) -> String {
        let mut w = MemWriter::new();
        format_document(doc, &mut w).ok().expect("Not formatted");
        String::from_utf8(w.unwrap()).ok().expect("Not a string")
    }

    #[test]
    fn top_element() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello/>");
    }

    #[test]
    fn element_with_attributes() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        e.set_attribute("a".to_string(), "b".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello a='b'/>");
    }

    #[test]
    fn nested_element() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let world = d.new_element("world".to_string());
        hello.append_child(world);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><world/></hello>");
    }

    #[test]
    fn nested_text() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let text = d.new_text("A fine day to you!".to_string());
        hello.append_child(text);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello>A fine day to you!</hello>");
    }

    #[test]
    fn nested_comment() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let comment = d.new_comment(" Fill this in ".to_string());
        hello.append_child(comment);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><!-- Fill this in --></hello>");
    }

    #[test]
    fn nested_processing_instruction_without_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), None);
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display?></hello>");
    }

    #[test]
    fn nested_processing_instruction_with_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), Some("screen".to_string()));
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display screen?></hello>");
    }
}
<commit_msg>Refactoring<commit_after>// Options
// Space before /
// Quote style
// Ordering of attributes

#[cfg(test)]
mod test {
    use std::io::{IoResult,MemWriter};

    use super::super::{Document,Element,Text,Comment,ProcessingInstruction};
    use super::super::{ElementElementChild,TextElementChild,CommentElementChild,PIElementChild};

    macro_rules! assert_str_eq(
        ($l:expr, $r:expr) => (assert_eq!($l.as_slice(), $r.as_slice()));
    )

    enum Content {
        WElement(Element),
        WElementEnd(String),
        WText(Text),
        WComment(Comment),
        WProcessingInstruction(ProcessingInstruction),
    }

    fn format_element<W : Writer>(element: Element, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
        try!(write!(writer, "<{}", element.name()));

        for attr in element.attributes().iter() {
            try!(write!(writer, " {}='{}'", attr.name(), attr.value()));
        }

        let mut children = element.children();
        if children.is_empty() {
            writer.write_str("/>")
        } else {
            try!(writer.write_str(">"));

            todo.push(WElementEnd(element.name()));
            children.reverse();
            let x = children.move_iter().map(|c| match c {
                ElementElementChild(element) => WElement(element),
                TextElementChild(t) => WText(t),
                CommentElementChild(c) => WComment(c),
                PIElementChild(p) => WProcessingInstruction(p),
            }).collect();
            todo.push_all_move(x);

            Ok(())
        }
    }

    fn format_processing_instruction<W : Writer>(pi: ProcessingInstruction, writer: &mut W) -> IoResult<()> {
        match pi.value() {
            None    => write!(writer, "<?{}?>", pi.target()),
            Some(v) => write!(writer, "<?{} {}?>", pi.target(), v),
        }
    }

    fn format_one<W : Writer>(content: Content, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
        match content {
            WElement(e)               => format_element(e, todo, writer),
            WElementEnd(name)         => write!(writer, "</{}>", name),
            WText(t)                  => writer.write_str(t.text().as_slice()),
            WComment(c)               => write!(writer, "<!--{}-->", c.text()),
            WProcessingInstruction(p) => format_processing_instruction(p, writer),
        }
    }

    fn format_document<W : Writer>(doc: &Document, writer: &mut W) -> IoResult<()> {
        let mut todo = Vec::new();

        try!(writer.write_str("<?xml version='1.0'?>"));
        let e = doc.root().children()[0].element().expect("not an element?");

        todo.push(WElement(e));

        while ! todo.is_empty() {
            try!(format_one(todo.pop().unwrap(), &mut todo, writer));
        }

        Ok(())
    }

    fn format_xml(doc: &Document) -> String {
        let mut w = MemWriter::new();
        format_document(doc, &mut w).ok().expect("Not formatted");
        String::from_utf8(w.unwrap()).ok().expect("Not a string")
    }

    #[test]
    fn top_element() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello/>");
    }

    #[test]
    fn element_with_attributes() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        e.set_attribute("a".to_string(), "b".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello a='b'/>");
    }

    #[test]
    fn nested_element() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let world = d.new_element("world".to_string());
        hello.append_child(world);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><world/></hello>");
    }

    #[test]
    fn nested_text() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let text = d.new_text("A fine day to you!".to_string());
        hello.append_child(text);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello>A fine day to you!</hello>");
    }

    #[test]
    fn nested_comment() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let comment = d.new_comment(" Fill this in ".to_string());
        hello.append_child(comment);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><!-- Fill this in --></hello>");
    }

    #[test]
    fn nested_processing_instruction_without_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), None);
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display?></hello>");
    }

    #[test]
    fn nested_processing_instruction_with_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), Some("screen".to_string()));
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display screen?></hello>");
    }
}
<|endoftext|>