<commit_before>use std::sync::Arc;

use wayland_backend::server::{
    ClientData, ClientId, GlobalHandler, GlobalId, Handle, ObjectData, ObjectId,
};

use crate::{
    dispatch::{DelegateDispatch, DelegateDispatchBase},
    Client, DataInit, Dispatch, DisplayHandle, New, Resource,
};

pub(crate) struct GlobalData<I: Resource, D: GlobalDispatch<I>> {
    pub(crate) data: <D as GlobalDispatch<I>>::GlobalData,
}

impl<I: Resource + 'static, D: GlobalDispatch<I> + 'static> GlobalHandler<D> for GlobalData<I, D> {
    fn can_view(&self, id: ClientId, data: &Arc<dyn ClientData<D>>, _: GlobalId) -> bool {
        let client = Client { id, data: data.clone().into_any_arc() };
        <D as GlobalDispatch<I>>::can_view(client, &self.data)
    }

    fn bind(
        self: Arc<Self>,
        handle: &mut Handle<D>,
        data: &mut D,
        client_id: ClientId,
        _: GlobalId,
        object_id: ObjectId,
    ) -> Arc<dyn ObjectData<D>> {
        let mut handle = DisplayHandle::from_handle(handle);
        let client = Client::from_id(&mut handle, client_id).expect("Dead client in bind ?!");
        let resource = <I as Resource>::from_id(&mut handle, object_id)
            .expect("Wrong object_id in GlobalHandler ?!");

        let mut new_data = None;

        data.bind(
            &mut handle,
            &client,
            New::wrap(resource),
            &self.data,
            &mut DataInit { store: &mut new_data },
        );

        match new_data {
            Some(data) => data,
            None => panic!(
                "Bind callback for interface {} did not init new instance.",
                I::interface().name
            ),
        }
    }
}

/// A trait which provides an implementation for handling advertisement of a global to clients with some type
/// of associated user data.
pub trait GlobalDispatch<I: Resource>: Dispatch<I> {
    /// Data associated with the global.
    type GlobalData: Send + Sync + 'static;

    /// Called when a client has bound this global.
    ///
    /// The return value of this function should contain user data to associate the object created by the
    /// client.
    fn bind(
        &mut self,
        handle: &mut DisplayHandle<'_, Self>,
        client: &Client,
        resource: New<I>,
        global_data: &Self::GlobalData,
        data_init: &mut DataInit<'_, Self>,
    );

    /// Checks if the global should be advertised to some client.
    ///
    /// The implementation of this function determines whether a client may see and bind some global. If this
    /// function returns false, the client will not be told the global exists and attempts to bind the global
    /// will raise a protocol error.
    ///
    /// One use of this function is implementing privileged protocols such as XWayland keyboard grabbing
    /// which must only be used by XWayland.
    ///
    /// The default implementation allows all clients to see the global.
    fn can_view(_client: Client, _global_data: &Self::GlobalData) -> bool {
        true
    }
}

/*
 * Dispatch delegation helpers
 */

/// The base trait used to define a delegate type to handle some global.
pub trait DelegateGlobalDispatchBase<I: Resource>: DelegateDispatchBase<I> {
    /// Data associated with the global.
    type GlobalData: Send + Sync + 'static;
}

/// A trait which defines a delegate type to handle some type of global.
///
/// This trait is useful for building modular handlers for globals.
pub trait DelegateGlobalDispatch<
    I: Resource,
    D: GlobalDispatch<I, GlobalData = <Self as DelegateGlobalDispatchBase<I>>::GlobalData>
        + Dispatch<I, UserData = Self::UserData>,
>: Sized + DelegateGlobalDispatchBase<I> + DelegateDispatch<I, D>
{
    /// Called when a client has bound this global.
    ///
    /// The return value of this function should contain user data to associate the object created by the
    /// client.
    fn bind(
        state: &mut D,
        handle: &mut DisplayHandle<'_, D>,
        client: &Client,
        resource: New<I>,
        global_data: &Self::GlobalData,
        data_init: &mut DataInit<'_, Self>,
    ) -> D::UserData;

    /// Checks if the global should be advertised to some client.
    ///
    /// The implementation of this function determines whether a client may see and bind some global. If this
    /// function returns false, the client will not be told the global exists and attempts to bind the global
    /// will raise a protocol error.
    ///
    /// One use of this function is implementing privileged protocols such as XWayland keyboard grabbing
    /// which must only be used by XWayland.
    ///
    /// The default implementation allows all clients to see the global.
    fn can_view(_client: Client, _global_data: &Self::GlobalData) -> bool {
        true
    }
}

#[macro_export]
macro_rules! delegate_global_dispatch {
    ($dispatch_from: ty: [$($interface: ty),*] => $dispatch_to: ty) => {
        $(
            impl $crate::GlobalDispatch<$interface> for $dispatch_from {
                type GlobalData = <$dispatch_to as $crate::DelegateGlobalDispatchBase<$interface>>::GlobalData;

                fn bind(
                    &mut self,
                    dhandle: &mut $crate::DisplayHandle<'_, Self>,
                    client: &$crate::Client,
                    resource: $crate::New<&$interface>,
                    global_data: &Self::GlobalData,
                    data_init: &mut $crate::DataInit<'_, Self>,
                ) {
                    <$dispatch_to as $crate::DelegateGlobalDispatch<$interface, Self>>::bind(self, dhandle, client, resource, global_data, data_init)
                }

                fn can_view(client: Client, global_data: &Self::GlobalData) -> bool {
                    <$dispatch_to as $crate::DelegateGlobalDispatch<$interface, Self>>::can_view(client, global_data)
                }
            }
        )*
    };
}
<commit_msg>Fix type param in delegate global<commit_after>use std::sync::Arc;

use wayland_backend::server::{
    ClientData, ClientId, GlobalHandler, GlobalId, Handle, ObjectData, ObjectId,
};

use crate::{
    dispatch::{DelegateDispatch, DelegateDispatchBase},
    Client, DataInit, Dispatch, DisplayHandle, New, Resource,
};

pub(crate) struct GlobalData<I: Resource, D: GlobalDispatch<I>> {
    pub(crate) data: <D as GlobalDispatch<I>>::GlobalData,
}

impl<I: Resource + 'static, D: GlobalDispatch<I> + 'static> GlobalHandler<D> for GlobalData<I, D> {
    fn can_view(&self, id: ClientId, data: &Arc<dyn ClientData<D>>, _: GlobalId) -> bool {
        let client = Client { id, data: data.clone().into_any_arc() };
        <D as GlobalDispatch<I>>::can_view(client, &self.data)
    }

    fn bind(
        self: Arc<Self>,
        handle: &mut Handle<D>,
        data: &mut D,
        client_id: ClientId,
        _: GlobalId,
        object_id: ObjectId,
    ) -> Arc<dyn ObjectData<D>> {
        let mut handle = DisplayHandle::from_handle(handle);
        let client = Client::from_id(&mut handle, client_id).expect("Dead client in bind ?!");
        let resource = <I as Resource>::from_id(&mut handle, object_id)
            .expect("Wrong object_id in GlobalHandler ?!");

        let mut new_data = None;

        data.bind(
            &mut handle,
            &client,
            New::wrap(resource),
            &self.data,
            &mut DataInit { store: &mut new_data },
        );

        match new_data {
            Some(data) => data,
            None => panic!(
                "Bind callback for interface {} did not init new instance.",
                I::interface().name
            ),
        }
    }
}

/// A trait which provides an implementation for handling advertisement of a global to clients with some type
/// of associated user data.
pub trait GlobalDispatch<I: Resource>: Dispatch<I> {
    /// Data associated with the global.
    type GlobalData: Send + Sync + 'static;

    /// Called when a client has bound this global.
    ///
    /// The return value of this function should contain user data to associate the object created by the
    /// client.
    fn bind(
        &mut self,
        handle: &mut DisplayHandle<'_, Self>,
        client: &Client,
        resource: New<I>,
        global_data: &Self::GlobalData,
        data_init: &mut DataInit<'_, Self>,
    );

    /// Checks if the global should be advertised to some client.
    ///
    /// The implementation of this function determines whether a client may see and bind some global. If this
    /// function returns false, the client will not be told the global exists and attempts to bind the global
    /// will raise a protocol error.
    ///
    /// One use of this function is implementing privileged protocols such as XWayland keyboard grabbing
    /// which must only be used by XWayland.
    ///
    /// The default implementation allows all clients to see the global.
    fn can_view(_client: Client, _global_data: &Self::GlobalData) -> bool {
        true
    }
}

/*
 * Dispatch delegation helpers
 */

/// The base trait used to define a delegate type to handle some global.
pub trait DelegateGlobalDispatchBase<I: Resource>: DelegateDispatchBase<I> {
    /// Data associated with the global.
    type GlobalData: Send + Sync + 'static;
}

/// A trait which defines a delegate type to handle some type of global.
///
/// This trait is useful for building modular handlers for globals.
pub trait DelegateGlobalDispatch<
    I: Resource,
    D: GlobalDispatch<I, GlobalData = <Self as DelegateGlobalDispatchBase<I>>::GlobalData>
        + Dispatch<I, UserData = Self::UserData>,
>: Sized + DelegateGlobalDispatchBase<I> + DelegateDispatch<I, D>
{
    /// Called when a client has bound this global.
    ///
    /// The return value of this function should contain user data to associate the object created by the
    /// client.
    fn bind(
        state: &mut D,
        handle: &mut DisplayHandle<'_, D>,
        client: &Client,
        resource: New<I>,
        global_data: &Self::GlobalData,
        data_init: &mut DataInit<'_, D>,
    );

    /// Checks if the global should be advertised to some client.
    ///
    /// The implementation of this function determines whether a client may see and bind some global. If this
    /// function returns false, the client will not be told the global exists and attempts to bind the global
    /// will raise a protocol error.
    ///
    /// One use of this function is implementing privileged protocols such as XWayland keyboard grabbing
    /// which must only be used by XWayland.
    ///
    /// The default implementation allows all clients to see the global.
    fn can_view(_client: Client, _global_data: &Self::GlobalData) -> bool {
        true
    }
}

#[macro_export]
macro_rules! delegate_global_dispatch {
    ($dispatch_from: ty: [$($interface: ty),*] => $dispatch_to: ty) => {
        $(
            impl $crate::GlobalDispatch<$interface> for $dispatch_from {
                type GlobalData = <$dispatch_to as $crate::DelegateGlobalDispatchBase<$interface>>::GlobalData;

                fn bind(
                    &mut self,
                    dhandle: &mut $crate::DisplayHandle<'_, Self>,
                    client: &$crate::Client,
                    resource: $crate::New<$interface>,
                    global_data: &Self::GlobalData,
                    data_init: &mut $crate::DataInit<'_, Self>,
                ) {
                    <$dispatch_to as $crate::DelegateGlobalDispatch<$interface, Self>>::bind(self, dhandle, client, resource, global_data, data_init)
                }

                fn can_view(client: $crate::Client, global_data: &Self::GlobalData) -> bool {
                    <$dispatch_to as $crate::DelegateGlobalDispatch<$interface, Self>>::can_view(client, global_data)
                }
            }
        )*
    };
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

// LDAPString ::= OCTET STRING -- UTF-8 encoded,
//                             -- [ISO10646] characters

#[derive(Debug)]
struct Asn1Type {
  name: String,
  assign: String
}

named!(type_name <&[u8], String>, chain!(
  s: take_while!(nom::is_alphanumeric),
  || String::from_utf8(Vec::from(s)).unwrap()
));

named!(type_assignment <&[u8], Asn1Type>, chain!(
  opt!(nom::multispace) ~
  name: type_name ~
  take_until_and_consume!("::=") ~
  opt!(nom::multispace) ~
  assign: type_name,
  || Asn1Type {
    name: name,
    assign: assign,
  }
));

fn main() {
  println!("{:#?}", type_assignment("test ::= hi".as_bytes()));
}
<commit_msg>Expand types<commit_after>#[macro_use]
extern crate nom;

// LDAPString ::= OCTET STRING -- UTF-8 encoded,
//                             -- [ISO10646] characters

#[derive(Debug)]
enum Asn1Type {
  Type(String),
  Seq(Asn1Seq),
}

#[derive(Debug)]
struct Asn1Def {
  name: String,
  assign: Asn1Type,
}

#[derive(Debug)]
struct Asn1Seq {
  fields: Vec<Asn1Def>,
}

named!(type_name <&[u8], String>, chain!(
  s: take_while!(nom::is_alphanumeric),
  || String::from_utf8(Vec::from(s)).unwrap()
));

named!(type_assignment <&[u8], Asn1Def>, chain!(
  opt!(nom::multispace) ~
  name: type_name ~
  take_until_and_consume!("::=") ~
  opt!(nom::multispace) ~
  assign: type_name,
  || Asn1Def {
    name: name,
    assign: Asn1Type::Type(assign),
  }
));

named!(type_sequence <&[u8], Asn1Seq>, chain!(
  tag!("SEQUNECE"),
  || Asn1Seq {
    fields: Vec::new(),
  }
));

fn main() {
  println!("{:#?}", type_assignment("test ::= hi".as_bytes()));
}
<|endoftext|>


<commit_before>use std::os::getenv;

struct HttpContext{
    request: Request,
    response: Response
}

impl HttpContext{
    fn create() -> HttpContext{
        HttpContext{
            request: Request::populate(),
            response: Response::new()
        }
    }
}

struct Request {
    path: ~str,
    querystring: ~str
}

impl Request {
    fn populate() -> Request {
        Request{
            path: getenv("PATH_INFO").unwrap_or(~""),
            querystring: getenv("QUERY_STRING").unwrap_or(~"")
        }
    }
}

struct Response{
    contenttype: ~str,
    body: ~str
}

impl Response{
    fn new() -> Response{
        Response{contenttype: ~"text/plain", body: ~""}
    }
}

struct Route {
    path: ~str,
    handler: ~fn(&mut HttpContext)
}

struct Router{
    routes: ~[Route],
}

impl Router{
    fn new() -> Router{
        Router{routes: ~[]}
    }
    fn add(&mut self, r: Route){
        self.routes.push(r);
    }
    fn execute(&self, c: &mut HttpContext) {
        for route in self.routes.iter(){
            if(route.path == c.request.path){
                (route.handler)(c);
            }
        }
    }
    fn controller<T>(~self, creator: ~fn(&HttpContext) -> T) -> ControllerBox<T>
    {
        ControllerBox{
            router: self,
            route: ~Route{path: ~"", handler: default_handler},
            creator: Some(creator)
        }
    }
}

trait HttpController{

}

struct ControllerBox<T>{
    router: ~Router,
    route: ~Route,
    creator: Option<~fn(&HttpContext) -> T>
}

impl<T> ControllerBox<T>{
    fn handles(@mut self, path: ~str) -> @mut ControllerBox<T>{
        self.route.path=path;
        self
    }
    fn with<'r>(&'r mut self, invoker: ~fn(&T)) -> &'r mut ControllerBox<T>{
        let tmp=self.creator.take();

        self.route.handler = |c| {
            match tmp {
                None => (),
                Some(ref t) => {
                    let ctrl=(*t)(c);
                    invoker(&ctrl);
                }
            };
        };
        self
    }
}
/*
struct Meh{
    biz: ~fn(int) -> int
}

impl Meh{
    fn foo(@mut self
}
*/

fn default_handler(context: &mut HttpContext){
    context.response.body.push_str("404 not found");
}

fn index(context: &mut HttpContext){
    context.response.body.push_str("yay index");
}

fn foo(context: &mut HttpContext){
    context.response.body.push_str("yay foo");
}

fn main() {
    let mut context=HttpContext::create();
    let mut router=Router::new();
    router.add(Route{path: ~"", handler: index});
    router.add(Route{path: ~"/foo", handler: foo});
    router.execute(&mut context);
    println(context.response.contenttype);
    println("");
    println(context.response.body);
}<commit_msg>still doesn't work because who knows. Apparently router doesn't implement controller.. wtf<commit_after>use std::os::getenv;

struct HttpContext{
    request: Request,
    response: Response
}

impl HttpContext{
    fn create() -> HttpContext{
        HttpContext{
            request: Request::populate(),
            response: Response::new()
        }
    }
}

struct Request {
    path: ~str,
    querystring: ~str
}

impl Request {
    fn populate() -> Request {
        Request{
            path: getenv("PATH_INFO").unwrap_or(~""),
            querystring: getenv("QUERY_STRING").unwrap_or(~"")
        }
    }
}

struct Response{
    contenttype: ~str,
    body: ~str
}

impl Response{
    fn new() -> Response{
        Response{contenttype: ~"text/plain", body: ~""}
    }
}

struct Route {
    path: ~str,
    handler: ~fn(&mut HttpContext)
}

struct Router{
    routes: ~[Route],
}

impl Router{
    fn new() -> Router{
        Router{routes: ~[]}
    }
    fn add(&mut self, r: Route){
        self.routes.push(r);
    }
    fn execute(&self, c: &mut HttpContext) {
        for route in self.routes.iter(){
            if(route.path == c.request.path){
                (route.handler)(c);
            }
        }
    }
    fn controller<T>(~self, creator: ~fn(&HttpContext) -> T) -> ControllerBox<T>
    {
        ControllerBox{
            router: self,
            route: ~Route{path: ~"", handler: default_handler},
            creator: Some(creator)
        }
    }
}

trait HttpController{

}

struct ControllerBox<T>{
    router: ~Router,
    route: ~Route,
    creator: Option<~fn(&HttpContext) -> T>
}

impl<T> ControllerBox<T>{
    fn handles(@mut self, path: ~str) -> @mut ControllerBox<T>{
        self.route.path=path;
        self
    }
    fn with<'r>(&'r mut self, invoker: ~fn(&mut T)) -> &'r mut ControllerBox<T>{
        let tmp=self.creator.take();

        self.route.handler = |c| {
            match tmp {
                None => (),
                Some(ref t) => {
                    let mut ctrl=(*t)(c);
                    invoker(&mut ctrl);
                }
            };
        };
        self
    }
}
/*
struct Meh{
    biz: ~fn(int) -> int
}

impl Meh{
    fn foo(@mut self
}
*/

struct TestController{
    context: ~HttpContext
}

impl TestController{
    fn new(c: ~HttpContext) -> TestController{
        TestController{ context: c}
    }
    fn index(&mut self) {
        self.context.response.body.push_str("test index");
    }
}

fn default_handler(context: &mut HttpContext){
    context.response.body.push_str("404 not found");
}

fn index(context: &mut HttpContext){
    context.response.body.push_str("yay index");
}

fn foo(context: &mut HttpContext){
    context.response.body.push_str("yay foo");
}

fn main() {
    let mut context=HttpContext::create();
    let mut router=Router::new();
    router.add(Route{path: ~"", handler: index});
    router.add(Route{path: ~"/foo", handler: foo});

    let mut test = router.controller(|c| TestController::new(c));
    test.handles(~"/test").with(|c| c.index());

    router.execute(&mut context);

    println(context.response.contenttype);
    println("");
    println(context.response.body);
}<|endoftext|>


<commit_before>#[cfg(feature = "bindgen")]
extern crate bindgen;

extern crate gcc;
extern crate glob;

#[cfg(feature = "bindgen")]
fn generate_bindings() {
    use std::env;
    use std::path::PathBuf;

    let bindings = bindgen::Builder::default()
        .header("zstd.h")
        .blacklist_type("max_align_t")
        .use_core()
        .ctypes_prefix("::libc")
        .clang_arg("-Izstd/lib")
        .clang_arg("-DZSTD_STATIC_LINKING_ONLY")
        .generate()
        .expect("Unable to generate bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Could not write bindings");

}

#[cfg(not(feature = "bindgen"))]
fn generate_bindings() {}

#[cfg(not(feature = "legacy"))]
fn set_legacy(_config: &mut gcc::Build) {}

#[cfg(feature = "legacy")]
fn set_legacy(config: &mut gcc::Build) {
    config.define("ZSTD_LEGACY_SUPPORT", Some("1"));
}

#[cfg(feature = "zstdmt")]
fn set_pthread(config: &mut gcc::Build) {
    config.flag("-pthread");
}

#[cfg(not(feature = "zstdmt"))]
fn set_pthread(_config: &mut gcc::Build) {}

fn compile_zstd() {
    let mut config = gcc::Build::new();

    let globs = &[
        "zstd/lib/common/*.c",
        "zstd/lib/compress/*.c",
        "zstd/lib/decompress/*.c",
        "zstd/lib/legacy/*.c",
        "zstd/lib/deprecated/*.c",
        "zstd/lib/dictBuilder/*.c",
    ];

    for pattern in globs {
        for path in glob::glob(pattern).unwrap() {
            let path = path.unwrap();
            config.file(path);
        }
    }

    // Some extra parameters
    config.opt_level(3);
    config.include("zstd/lib/");
    config.include("zstd/lib/common");
    config.include("zstd/lib/legacy");
    config.warnings(false);

    set_pthread(&mut config);
    set_legacy(&mut config);

    // Compile!
    config.compile("libzstd.a");
}

fn main() {
    // println!("cargo:rustc-link-lib=zstd");

    compile_zstd();
    generate_bindings();
}
<commit_msg>adjust build<commit_after>#[cfg(feature = "bindgen")]
extern crate bindgen;

extern crate gcc;
extern crate glob;

use std::{env, fs};
use std::path::PathBuf;

#[cfg(feature = "bindgen")]
fn generate_bindings() {
    use std::env;
    use std::path::PathBuf;

    let bindings = bindgen::Builder::default()
        .header("zstd.h")
        .blacklist_type("max_align_t")
        .use_core()
        .ctypes_prefix("::libc")
        .clang_arg("-Izstd/lib")
        .clang_arg("-DZSTD_STATIC_LINKING_ONLY")
        .generate()
        .expect("Unable to generate bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Could not write bindings");

}

#[cfg(not(feature = "bindgen"))]
fn generate_bindings() {}

#[cfg(not(feature = "legacy"))]
fn set_legacy(_config: &mut gcc::Build) {}

#[cfg(feature = "legacy")]
fn set_legacy(config: &mut gcc::Build) {
    config.define("ZSTD_LEGACY_SUPPORT", Some("1"));
}

#[cfg(feature = "zstdmt")]
fn set_pthread(config: &mut gcc::Build) {
    config.flag("-pthread");
}

#[cfg(not(feature = "zstdmt"))]
fn set_pthread(_config: &mut gcc::Build) {}

fn compile_zstd() {
    let mut config = gcc::Build::new();

    let globs = &[
        "zstd/lib/common/*.c",
        "zstd/lib/compress/*.c",
        "zstd/lib/decompress/*.c",
        "zstd/lib/legacy/*.c",
        "zstd/lib/deprecated/*.c",
        "zstd/lib/dictBuilder/*.c",
    ];

    for pattern in globs {
        for path in glob::glob(pattern).unwrap() {
            let path = path.unwrap();
            config.file(path);
        }
    }

    // Some extra parameters
    config.opt_level(3);
    config.include("zstd/lib/");
    config.include("zstd/lib/common");
    config.include("zstd/lib/legacy");
    config.warnings(false);

    set_pthread(&mut config);
    set_legacy(&mut config);

    // Compile!
    config.compile("libzstd.a");

    let src = env::current_dir().unwrap().join("zstd").join("lib");
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let include = dst.join("include");
    fs::create_dir_all(&include).unwrap();
    fs::copy(src.join("zstd.h"), include.join("zstd.h")).unwrap();
    println!("cargo:root={}", dst.display());
}

fn main() {
    // println!("cargo:rustc-link-lib=zstd");

    compile_zstd();
    generate_bindings();
}
<|endoftext|>


<commit_before>use std::{fs, cmp};
use std::path::Path;
use std::io::{self, Read};

use websocket::client::sync::Client as WClient;
use websocket::stream::Stream;
use websocket::message::OwnedMessage as WSMessage;
use reqwest::{Client as HClient, header};
use serde_json;
use prettytable::Table;

use rpc::message::{CMessage, SMessage};
use rpc::criterion::{Criterion, Value, Operation};
use rpc::resource::{Resource, ResourceKind, SResourceUpdate};

error_chain! {
    errors {
        FileIO {
            description("Failed to perform file IO")
                display("Failed to perform file IO")
        }
        Serialization {
            description("Failed to serialize structure")
                display("Failed to serialize structure")
        }
        Deserialization {
            description("Failed to deserialize structure")
                display("Failed to deserialize structure")
        }
        Websocket {
            description("Failed to handle websocket client")
                display("Failed to handle websocket client")
        }
        HTTP {
            description("HTTP transfer failed")
                display("HTTP transfer failed")
        }
    }
}

struct Serial(u64);
impl Serial {
    fn next(&mut self) -> u64 {
        self.0 += 1;
        self.0 - 1
    }
}

pub fn add<S: Stream>(
    mut c: WClient<S>,
    url: &str,
    files: Vec<&str>,
    dir: Option<&str>,
) -> Result<()> {
    let mut serial = Serial(0);
    for file in files {
        add_file(&mut c, &mut serial, url, file, dir)?;
    }
    Ok(())
}

fn add_file<S: Stream>(
    c: &mut WClient<S>,
    serial: &mut Serial,
    url: &str,
    file: &str,
    dir: Option<&str>,
) -> Result<()> {
    let mut torrent = Vec::new();
    let mut f = fs::File::open(file).chain_err(|| ErrorKind::FileIO)?;
    f.read_to_end(&mut torrent).chain_err(|| ErrorKind::FileIO)?;

    let msg = CMessage::UploadTorrent {
        serial: serial.next(),
        size: torrent.len() as u64,
        path: dir.as_ref().map(|d| format!("{}", d)),
    };
    let msg_data = serde_json::to_string(&msg).chain_err(
        || ErrorKind::Serialization,
    )?;
    let wsmsg = WSMessage::Text(msg_data);
    c.send_message(&wsmsg).chain_err(|| ErrorKind::Websocket)?;
    let mut smsg = match c.recv_message().chain_err(|| ErrorKind::Websocket)? {
        WSMessage::Text(s) => {
            serde_json::from_str(&s).chain_err(
                || ErrorKind::Deserialization,
            )?
        }
        // TODO: Handle Ping here
        _ => unimplemented!(),
    };
    let token = if let SMessage::TransferOffer { token, .. } = smsg {
        token
    } else {
        bail!("Failed to receieve transfer offer from synapse!");
    };
    let client = HClient::new().chain_err(|| ErrorKind::HTTP)?;
    client
        .post(url)
        .chain_err(|| ErrorKind::HTTP)?
        .header(header::Authorization(header::Bearer { token }))
        .body(torrent)
        .send()
        .chain_err(|| ErrorKind::HTTP)?;

    smsg = match c.recv_message().chain_err(|| ErrorKind::Websocket)? {
        WSMessage::Text(s) => {
            serde_json::from_str(&s).chain_err(
                || ErrorKind::Deserialization,
            )?
        }
        _ => unimplemented!(),
    };
    if let SMessage::OResourcesExtant { .. } = smsg {
    } else {
        bail!("Failed to receieve upload acknowledgement from synapse!");
    };

    Ok(())
}

pub fn del<S: Stream>(mut c: WClient<S>, torrents: Vec<&str>) -> Result<()> {
    let mut serial = Serial(0);
    for torrent in torrents {
        del_torrent(&mut c, &mut serial, torrent)?;
    }
    Ok(())
}

fn del_torrent<S: Stream>(c: &mut WClient<S>, serial: &mut Serial, torrent: &str) -> Result<()> {
    let resources = search_torrent_name(c, serial, torrent)?;
    if resources.len() == 1 {
        let msg = CMessage::RemoveResource {
            serial: serial.next(),
            id: resources[0].id().to_owned(),
        };
        let msg_data = serde_json::to_string(&msg).chain_err(
            || ErrorKind::Serialization,
        )?;
        c.send_message(&WSMessage::Text(msg_data)).chain_err(|| {
            ErrorKind::Websocket
        })?;
    } else if resources.is_empty() {
        eprintln!("Could not find any matching torrents for {}", torrent);
    } else {
        eprintln!(
            "Ambiguous results searching for {}. Potential alternatives include: ",
            torrent
        );
        for res in resources.into_iter().take(3) {
            if let Resource::Torrent(t) = res {
                eprintln!("{}", t.name);
            }
        }
    }
    Ok(())
}

pub fn dl<S: Stream>(mut c: WClient<S>, url: &str, name: &str) -> Result<()> {
    let mut serial = Serial(0);
    let resources = search_torrent_name(&mut c, &mut serial, name)?;
    let files = if resources.len() == 1 {
        let msg = CMessage::FilterSubscribe {
            serial: serial.next(),
            kind: ResourceKind::File,
            criteria: vec![
                Criterion {
                    field: "torrent_id".to_owned(),
                    op: Operation::Eq,
                    value: Value::S(resources[0].id().to_owned()),
                },
            ],
        };
        let msg_data = serde_json::to_string(&msg).chain_err(
            || ErrorKind::Serialization,
        )?;
        c.send_message(&WSMessage::Text(msg_data)).chain_err(|| {
            ErrorKind::Websocket
        })?;

        let smsg = match c.recv_message().chain_err(|| ErrorKind::Websocket)? {
            WSMessage::Text(s) => {
                serde_json::from_str(&s).chain_err(
                    || ErrorKind::Deserialization,
                )?
            }
            _ => unimplemented!(),
        };
        if let SMessage::OResourcesExtant { ids, .. } = smsg {
            get_resources(&mut c, &mut serial, ids)?
        } else {
            bail!("Could not get files for torrent!");
        }
    } else if resources.is_empty() {
        eprintln!("Could not find any matching torrents for {}", name);
        return Ok(());
    } else {
        eprintln!(
            "Ambiguous results searching for {}. Potential alternatives include: ",
            name
        );
        for res in resources.into_iter().take(3) {
            if let Resource::Torrent(t) = res {
                eprintln!("{}", t.name);
            }
        }
        return Ok(());
    };

    for file in files {
        let msg = CMessage::DownloadFile {
            serial: serial.next(),
            id: file.id().to_owned(),
        };
        let msg_data = serde_json::to_string(&msg).chain_err(
            || ErrorKind::Serialization,
        )?;
        c.send_message(&WSMessage::Text(msg_data)).chain_err(|| {
            ErrorKind::Websocket
        })?;

        let smsg = match c.recv_message().chain_err(|| ErrorKind::Websocket)? {
            WSMessage::Text(s) => {
                serde_json::from_str(&s).chain_err(
                    || ErrorKind::Deserialization,
                )?
            }
            _ => unimplemented!(),
        };
        if let SMessage::TransferOffer { token, .. } = smsg {
            let client = HClient::new().chain_err(|| ErrorKind::HTTP)?;
            let mut resp = client
                .get(url)
                .chain_err(|| ErrorKind::HTTP)?
                .header(header::Authorization(header::Bearer { token }))
                .send()
                .chain_err(|| ErrorKind::HTTP)?;
            if let Resource::File(f) = file {
                let p = Path::new(&f.path);
                if let Some(par) = p.parent() {
                    fs::create_dir_all(par).chain_err(|| ErrorKind::FileIO)?;
                }
                let mut f = fs::File::create(p).chain_err(|| ErrorKind::FileIO)?;
                io::copy(&mut resp, &mut f).chain_err(|| ErrorKind::FileIO)?;
            } else {
                bail!("Expected a file resource");
            }
        }
    }
    Ok(())
}

pub fn list<S: Stream>(
    mut c: WClient<S>,
    kind: &str,
    crit: Vec<Criterion>,
    output: &str,
) -> Result<()> {
    let k = match kind {
        "torrent" => ResourceKind::Torrent,
        "tracker" => ResourceKind::Tracker,
        "peer" => ResourceKind::Peer,
        "piece" => ResourceKind::Piece,
        "file" => ResourceKind::File,
        "server" => ResourceKind::Server,
        _ => bail!("Unexpected resource kind {}", kind),
    };
    let mut serial = Serial(0);
    let results = search(&mut c, &mut serial, k, crit)?;
    if output == "text" {
        let mut table = Table::new();
        match k {
            ResourceKind::Torrent => {
                table.add_row(row!["Name", "Done", "DL", "UL", "DL RT", "UL RT", "Peers"]);
            }
            ResourceKind::Tracker => {
                table.add_row(row!["URL", "Torrent", "Error"]);
            }
            ResourceKind::Peer => {
                table.add_row(row!["IP", "Torrent", "DL RT", "UL RT"]);
            }
            ResourceKind::Piece => {
                table.add_row(row!["Torrent", "DLd", "Avail"]);
            }
            ResourceKind::File => {
                table.add_row(row!["Path", "Torrent", "Done", "Prio", "Avail"]);
            }
            ResourceKind::Server => {
                table.add_row(row!["DL RT", "UL RT"]);
            }
        }

        #[cfg_attr(rustfmt, rustfmt_skip)]
        for res in results {
            match k {
                ResourceKind::Torrent => {
                    let t = res.as_torrent();
                    table.add_row(row![
                        t.name,
                        format!("{:.2}%", t.progress * 100.),
                        fmt_bytes(t.transferred_down as f64),
                        fmt_bytes(t.transferred_up as f64),
                        fmt_bytes(t.rate_down as f64) + "/s",
                        fmt_bytes(t.rate_up as f64) + "/s",
                        t.peers
                    ]);
                }
                ResourceKind::Tracker => {
                    let t = res.as_tracker();
                    table.add_row(row![
                        t.url,
                        t.torrent_id,
                        t.error.as_ref().map(|s| s.as_str()).unwrap_or("")
                    ]);
                }
                ResourceKind::Peer => {
                    let p = res.as_peer();
                    let rd = fmt_bytes(p.rate_down as f64) + "/s";
                    let ru = fmt_bytes(p.rate_up as f64) + "/s";
                    table.add_row(row![p.ip, p.torrent_id, rd, ru]);
                }
                ResourceKind::Piece => {
                    let p = res.as_piece();
                    table.add_row(row![p.torrent_id, p.downloaded, p.available]);
                }
                ResourceKind::File => {
                    let f = res.as_file();
                    table.add_row(row![
                        f.path,
                        f.torrent_id,
                        format!("{:.2}%", f.progress as f64 * 100.),
                        f.priority,
                        format!("{:.2}%", f.availability as f64 * 100.)
                    ]);
                }
                ResourceKind::Server => {
                    let s = res.as_server();
                    let rd = fmt_bytes(s.rate_down as f64) + "/s";
                    let ru = fmt_bytes(s.rate_up as f64) + "/s";
                    table.add_row(row![rd, ru]);
                }
            }
        }
        table.printstd();
    } else {
    }
    Ok(())
}

pub fn rate<S: Stream>(c: WClient<S>) {}

pub fn start<S: Stream>(c: WClient<S>) {}

pub fn stop<S: Stream>(c: WClient<S>) {}

fn search_torrent_name<S: Stream>(
    c: &mut WClient<S>,
    serial: &mut Serial,
    name: &str,
) -> Result<Vec<Resource>> {
    search(
        c,
        serial,
        ResourceKind::Torrent,
        vec![
            Criterion {
                field: "name".to_owned(),
                op: Operation::ILike,
                value: Value::S(format!("%{}%", name)),
            },
        ],
    )
}

fn search<S: Stream>(
    c: &mut WClient<S>,
    serial: &mut Serial,
    kind: ResourceKind,
    criteria: Vec<Criterion>,
) -> Result<Vec<Resource>> {
    let s = serial.next();
    let msg = CMessage::FilterSubscribe {
        serial: s,
        kind,
        criteria,
    };
    let msg_data = serde_json::to_string(&msg).chain_err(
        || ErrorKind::Serialization,
    )?;
    c.send_message(&WSMessage::Text(msg_data)).chain_err(|| {
        ErrorKind::Websocket
    })?;
    let smsg = match c.recv_message().chain_err(|| ErrorKind::Websocket)? {
        WSMessage::Text(s) => {
            serde_json::from_str(&s).chain_err(
                || ErrorKind::Deserialization,
            )?
        }
        _ => unimplemented!(),
    };
    if let SMessage::OResourcesExtant { ids, .. } = smsg {
        get_resources(c, serial, ids)
    } else {
        bail!("Failed to receive extant resource list!");
    }
}

fn get_resources<S: Stream>(
    c: &mut WClient<S>,
    serial: &mut Serial,
    ids: Vec<String>,
) -> Result<Vec<Resource>> {
    let msg_data = serde_json::to_string(&CMessage::Subscribe {
        serial: serial.next(),
        ids,
    }).chain_err(|| ErrorKind::Serialization)?;
    c.send_message(&WSMessage::Text(msg_data)).chain_err(|| {
        ErrorKind::Websocket
    })?;
    let smsg = match c.recv_message().chain_err(|| ErrorKind::Websocket)? {
        WSMessage::Text(s) => {
            serde_json::from_str(&s).chain_err(
                || ErrorKind::Deserialization,
            )?
        }
        _ => unimplemented!(),
    };
    let resources = if let SMessage::UpdateResources { resources } = smsg {
        resources
    } else {
        bail!("Failed to received torrent resource list!");
    };

    let mut results = Vec::new();
    for r in resources {
        if let SResourceUpdate::OResource(res) = r {
            results.push(res);
        } else {
            bail!("Failed to received full resource!");
        }
    }
    Ok(results)
}

fn fmt_bytes(num: f64) -> String {
    let num = num.abs();
    let units = ["B", "kiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
    if num < 1_f64 {
        return format!("{} {}", num, "B");
    }
    let delimiter = 1024_f64;
    let exponent = cmp::min(
        (num.ln() / delimiter.ln()).floor() as i32,
        (units.len() - 1) as i32,
    );
    let pretty_bytes = format!("{:.2}", num / delimiter.powi(exponent))
        .parse::<f64>()
        .unwrap() * 1_f64;
    let unit = units[exponent as usize];
    format!("{} {}", pretty_bytes, unit)
}
<commit_msg>Support JSON output in list command<commit_after>use std::{fs, cmp};
use std::path::Path;
use std::io::{self, Read};

use websocket::client::sync::Client as WClient;
use websocket::stream::Stream;
use websocket::message::OwnedMessage as WSMessage;
use reqwest::{Client as HClient, header};
use serde_json;
use prettytable::Table;

use rpc::message::{CMessage, SMessage};
use rpc::criterion::{Criterion, Value, Operation};
use rpc::resource::{Resource, ResourceKind, SResourceUpdate};

error_chain! {
    errors {
        FileIO {
            description("Failed to perform file IO")
                display("Failed to perform file IO")
        }
        Serialization {
            description("Failed to serialize structure")
                display("Failed to serialize structure")
        }
        Deserialization {
            description("Failed to deserialize structure")
                display("Failed to deserialize structure")
        }
        Websocket {
            description("Failed to handle websocket client")
                display("Failed to handle websocket client")
        }
        HTTP {
            description("HTTP transfer failed")
                display("HTTP transfer failed")
        }
    }
}

struct Serial(u64);
impl Serial {
    fn next(&mut self) -> u64 {
        self.0 += 1;
        self.0 - 1
    }
}

pub fn add<S: Stream>(
    mut c: WClient<S>,
    url: &str,
    files: Vec<&str>,
    dir: Option<&str>,
) -> Result<()> {
    let mut serial = Serial(0);
    for file in files {
        add_file(&mut c, &mut serial, url, file, dir)?;
    }
    Ok(())
}

fn add_file<S: Stream>(
    c: &mut WClient<S>,
    serial: &mut Serial,
    url: &str,
    file: &str,
    dir: Option<&str>,
) -> Result<()> {
    let mut torrent = Vec::new();
    let mut f = fs::File::open(file).chain_err(|| ErrorKind::FileIO)?;
    f.read_to_end(&mut torrent).chain_err(|| ErrorKind::FileIO)?;

    let msg = CMessage::UploadTorrent {
        serial: serial.next(),
        size: torrent.len() as u64,
        path: dir.as_ref().map(|d| format!("{}", d)),
    };
    let msg_data = serde_json::to_string(&msg).chain_err(
        || ErrorKind::Serialization,
    )?;
    let wsmsg = WSMessage::Text(msg_data);
    c.send_message(&wsmsg).chain_err(|| ErrorKind::Websocket)?;
    let mut smsg = match c.recv_message().chain_err(|| ErrorKind::Websocket)? {
        WSMessage::Text(s) => {
            serde_json::from_str(&s).chain_err(
                || ErrorKind::Deserialization,
            )?
        }
        // TODO: Handle Ping here
        _ => unimplemented!(),
    };
    let token = if let SMessage::TransferOffer { token, .. } = smsg {
        token
    } else {
        bail!("Failed to receieve transfer offer from synapse!");
    };
    let client = HClient::new().chain_err(|| ErrorKind::HTTP)?;
    client
        .post(url)
        .chain_err(|| ErrorKind::HTTP)?
        .header(header::Authorization(header::Bearer { token }))
        .body(torrent)
        .send()
        .chain_err(|| ErrorKind::HTTP)?;

    smsg = match c.recv_message().chain_err(|| ErrorKind::Websocket)? {
        WSMessage::Text(s) => {
            serde_json::from_str(&s).chain_err(
                || ErrorKind::Deserialization,
            )?
        }
        _ => unimplemented!(),
    };
    if let SMessage::OResourcesExtant { .. } = smsg {
    } else {
        bail!("Failed to receieve upload acknowledgement from synapse!");
    };

    Ok(())
}

pub fn del<S: Stream>(mut c: WClient<S>, torrents: Vec<&str>) -> Result<()> {
    let mut serial = Serial(0);
    for torrent in torrents {
        del_torrent(&mut c, &mut serial, torrent)?;
    }
    Ok(())
}

fn del_torrent<S: Stream>(c: &mut WClient<S>, serial: &mut Serial, torrent: &str) -> Result<()> {
    let resources = search_torrent_name(c, serial, torrent)?;
    if resources.len() == 1 {
        let msg = CMessage::RemoveResource {
            serial: serial.next(),
            id: resources[0].id().to_owned(),
        };
        let msg_data = serde_json::to_string(&msg).chain_err(
            || ErrorKind::Serialization,
        )?;
        c.send_message(&WSMessage::Text(msg_data)).chain_err(|| {
            ErrorKind::Websocket
        })?;
    } else if resources.is_empty() {
        eprintln!("Could not find any matching torrents for {}", torrent);
    } else {
        eprintln!(
            "Ambiguous results searching for {}. Potential alternatives include: ",
            torrent
        );
        for res in resources.into_iter().take(3) {
            if let Resource::Torrent(t) = res {
                eprintln!("{}", t.name);
            }
        }
    }
    Ok(())
}

pub fn dl<S: Stream>(mut c: WClient<S>, url: &str, name: &str) -> Result<()> {
    let mut serial = Serial(0);
    let resources = search_torrent_name(&mut c, &mut serial, name)?;
    let files = if resources.len() == 1 {
        let msg = CMessage::FilterSubscribe {
            serial: serial.next(),
            kind: ResourceKind::File,
            criteria: vec![
                Criterion {
                    field: "torrent_id".to_owned(),
                    op: Operation::Eq,
                    value: Value::S(resources[0].id().to_owned()),
                },
            ],
        };
        let msg_data = serde_json::to_string(&msg).chain_err(
            || ErrorKind::Serialization,
        )?;
        c.send_message(&WSMessage::Text(msg_data)).chain_err(|| {
            ErrorKind::Websocket
        })?;

        let smsg = match c.recv_message().chain_err(|| ErrorKind::Websocket)? {
            WSMessage::Text(s) => {
                serde_json::from_str(&s).chain_err(
                    || ErrorKind::Deserialization,
                )?
            }
            _ => unimplemented!(),
        };
        if let SMessage::OResourcesExtant { ids, .. } = smsg {
            get_resources(&mut c, &mut serial, ids)?
        } else {
            bail!("Could not get files for torrent!");
        }
    } else if resources.is_empty() {
        eprintln!("Could not find any matching torrents for {}", name);
        return Ok(());
    } else {
        eprintln!(
            "Ambiguous results searching for {}. Potential alternatives include: ",
            name
        );
        for res in resources.into_iter().take(3) {
            if let Resource::Torrent(t) = res {
                eprintln!("{}", t.name);
            }
        }
        return Ok(());
    };

    for file in files {
        let msg = CMessage::DownloadFile {
            serial: serial.next(),
            id: file.id().to_owned(),
        };
        let msg_data = serde_json::to_string(&msg).chain_err(
            || ErrorKind::Serialization,
        )?;
        c.send_message(&WSMessage::Text(msg_data)).chain_err(|| {
            ErrorKind::Websocket
        })?;

        let smsg = match c.recv_message().chain_err(|| ErrorKind::Websocket)? {
            WSMessage::Text(s) => {
                serde_json::from_str(&s).chain_err(
                    || ErrorKind::Deserialization,
                )?
            }
            _ => unimplemented!(),
        };
        if let SMessage::TransferOffer { token, .. } = smsg {
            let client = HClient::new().chain_err(|| ErrorKind::HTTP)?;
            let mut resp = client
                .get(url)
                .chain_err(|| ErrorKind::HTTP)?
                .header(header::Authorization(header::Bearer { token }))
                .send()
                .chain_err(|| ErrorKind::HTTP)?;
            if let Resource::File(f) = file {
                let p = Path::new(&f.path);
                if let Some(par) = p.parent() {
                    fs::create_dir_all(par).chain_err(|| ErrorKind::FileIO)?;
                }
                let mut f = fs::File::create(p).chain_err(|| ErrorKind::FileIO)?;
                io::copy(&mut resp, &mut f).chain_err(|| ErrorKind::FileIO)?;
            } else {
                bail!("Expected a file resource");
            }
        }
    }
    Ok(())
}

pub fn list<S: Stream>(
    mut c: WClient<S>,
    kind: &str,
    crit: Vec<Criterion>,
    output: &str,
) -> Result<()> {
    let k = match kind {
        "torrent" => ResourceKind::Torrent,
        "tracker" => ResourceKind::Tracker,
        "peer" => ResourceKind::Peer,
        "piece" => ResourceKind::Piece,
        "file" => ResourceKind::File,
        "server" => ResourceKind::Server,
        _ => bail!("Unexpected resource kind {}", kind),
    };
    let mut serial = Serial(0);
    let results = search(&mut c, &mut serial, k, crit)?;
    if output == "text" {
        let mut table = Table::new();
        match k {
            ResourceKind::Torrent => {
                table.add_row(row!["Name", "Done", "DL", "UL", "DL RT", "UL RT", "Peers"]);
            }
            ResourceKind::Tracker => {
                table.add_row(row!["URL", "Torrent", "Error"]);
            }
            ResourceKind::Peer => {
                table.add_row(row!["IP", "Torrent", "DL RT", "UL RT"]);
            }
            ResourceKind::Piece => {
                table.add_row(row!["Torrent", "DLd", "Avail"]);
            }
            ResourceKind::File => {
                table.add_row(row!["Path", "Torrent", "Done", "Prio", "Avail"]);
            }
            ResourceKind::Server => {
                table.add_row(row!["DL RT", "UL RT"]);
            }
        }

        #[cfg_attr(rustfmt, rustfmt_skip)]
        for res in results {
            match k {
                ResourceKind::Torrent => {
                    let t = res.as_torrent();
                    table.add_row(row![
                        t.name,
                        format!("{:.2}%", t.progress * 100.),
                        fmt_bytes(t.transferred_down as f64),
                        fmt_bytes(t.transferred_up as f64),
                        fmt_bytes(t.rate_down as f64) + "/s",
                        fmt_bytes(t.rate_up as f64) + "/s",
                        t.peers
                    ]);
                }
                ResourceKind::Tracker => {
                    let t = res.as_tracker();
                    table.add_row(row![
                        t.url,
                        t.torrent_id,
                        t.error.as_ref().map(|s| s.as_str()).unwrap_or("")
                    ]);
                }
                ResourceKind::Peer => {
                    let p = res.as_peer();
                    let rd = fmt_bytes(p.rate_down as f64) + "/s";
                    let ru = fmt_bytes(p.rate_up as f64) + "/s";
                    table.add_row(row![p.ip, p.torrent_id, rd, ru]);
                }
                ResourceKind::Piece => {
                    let p = res.as_piece();
                    table.add_row(row![p.torrent_id, p.downloaded, p.available]);
                }
                ResourceKind::File => {
                    let f = res.as_file();
                    table.add_row(row![
                        f.path,
                        f.torrent_id,
                        format!("{:.2}%", f.progress as f64 * 100.),
                        f.priority,
                        format!("{:.2}%", f.availability as f64 * 100.)
                    ]);
                }
                ResourceKind::Server => {
                    let s = res.as_server();
                    let rd = fmt_bytes(s.rate_down as f64) + "/s";
                    let ru = fmt_bytes(s.rate_up as f64) + "/s";
                    table.add_row(row![rd, ru]);
                }
            }
        }
        table.printstd();
    } else {
        println!("{}", serde_json::to_string_pretty(&results).chain_err(|| ErrorKind::Serialization)?);
    }
    Ok(())
}

pub fn rate<S: Stream>(c: WClient<S>) {}

pub fn start<S: Stream>(c: WClient<S>) {}

pub fn stop<S: Stream>(c: WClient<S>) {}

fn search_torrent_name<S: Stream>(
    c: &mut WClient<S>,
    serial: &mut Serial,
    name: &str,
) -> Result<Vec<Resource>> {
    search(
        c,
        serial,
        ResourceKind::Torrent,
        vec![
            Criterion {
                field: "name".to_owned(),
                op: Operation::ILike,
                value: Value::S(format!("%{}%", name)),
            },
        ],
    )
}

fn search<S: Stream>(
    c: &mut WClient<S>,
    serial: &mut Serial,
    kind: ResourceKind,
    criteria: Vec<Criterion>,
) -> Result<Vec<Resource>> {
    let s = serial.next();
    let msg = CMessage::FilterSubscribe {
        serial: s,
        kind,
        criteria,
    };
    let msg_data = serde_json::to_string(&msg).chain_err(
        || ErrorKind::Serialization,
    )?;
    c.send_message(&WSMessage::Text(msg_data)).chain_err(|| {
        ErrorKind::Websocket
    })?;
    let smsg = match c.recv_message().chain_err(|| ErrorKind::Websocket)? {
        WSMessage::Text(s) => {
            serde_json::from_str(&s).chain_err(
                || ErrorKind::Deserialization,
            )?
        }
        _ => unimplemented!(),
    };
    if let SMessage::OResourcesExtant { ids, .. } = smsg {
        get_resources(c, serial, ids)
    } else {
        bail!("Failed to receive extant resource list!");
    }
}

fn get_resources<S: Stream>(
    c: &mut WClient<S>,
    serial: &mut Serial,
    ids: Vec<String>,
) -> Result<Vec<Resource>> {
    let msg_data = serde_json::to_string(&CMessage::Subscribe {
        serial: serial.next(),
        ids,
    }).chain_err(|| ErrorKind::Serialization)?;
    c.send_message(&WSMessage::Text(msg_data)).chain_err(|| {
        ErrorKind::Websocket
    })?;
    let smsg = match c.recv_message().chain_err(|| ErrorKind::Websocket)? {
        WSMessage::Text(s) => {
            serde_json::from_str(&s).chain_err(
                || ErrorKind::Deserialization,
            )?
        }
        _ => unimplemented!(),
    };
    let resources = if let SMessage::UpdateResources { resources } = smsg {
        resources
    } else {
        bail!("Failed to received torrent resource list!");
    };

    let mut results = Vec::new();
    for r in resources {
        if let SResourceUpdate::OResource(res) = r {
            results.push(res);
        } else {
            bail!("Failed to received full resource!");
        }
    }
    Ok(results)
}

fn fmt_bytes(num: f64) -> String {
    let num = num.abs();
    let units = ["B", "kiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
    if num < 1_f64 {
        return format!("{} {}", num, "B");
    }
    let delimiter = 1024_f64;
    let exponent = cmp::min(
        (num.ln() / delimiter.ln()).floor() as i32,
        (units.len() - 1) as i32,
    );
    let pretty_bytes = format!("{:.2}", num / delimiter.powi(exponent))
        .parse::<f64>()
        .unwrap() * 1_f64;
    let unit = units[exponent as usize];
    format!("{} {}", pretty_bytes, unit)
}
<|endoftext|>


<commit_before>use mio::*;
use std::cell::RefCell;
use std::fmt::Debug;
use std::io;
use std::rc::Rc;
use std::time::Duration;
use slab::Slab;

pub trait EventHandler {
    fn on_ready(&mut self, selector: &mut Selector, event: Event);
}

impl<F> EventHandler for F where F: FnMut(&mut Selector, Event) {
    fn on_ready(&mut self, selector: &mut Selector, event: Event) {
        self(selector, event);
    }
}

// for convenience
impl<T: EventHandler> EventHandler for Rc<RefCell<T>> {
    fn on_ready(&mut self, selector: &mut Selector, event: Event) {
        self.borrow_mut().on_ready(selector, event);
    }
}

pub struct Selector {
    poll: Poll,
    handlers: Slab<Box<EventHandler>, Token>,
    running_state: RunningState,
}

struct RunningState {
    token: Option<Token>,
    removed: bool,
}

impl RunningState {
    fn new() -> Self {
        Self {
            token: None,
            removed: false,
        }
    }

    fn running(&mut self, token: Token) {
        self.token = Some(token);
    }

    fn stopping(&mut self) {
        self.token = None;
    }

    fn is_running(&self, token: Token) -> bool {
        self.token.map_or(false, |current_token| current_token == token)
    }

    fn set_removed(&mut self, removed: bool) {
        self.removed = removed;
    }

    fn is_removed(&self) -> bool {
        self.removed
    }
}

impl Selector {
    pub fn new() -> io::Result<Self> {
        Ok(Self {
            poll: Poll::new()?,
            handlers: Slab::with_capacity(1024),
            running_state: RunningState::new(),
        })
    }

    pub fn register<E>(&mut self, handle: &E, handler: Box<EventHandler>,
                   interest: Ready, opts: PollOpt) -> io::Result<Token>
            where E: Evented + ?Sized {
        let token = self.handlers.insert(handler)
                        .map_err(|_| io::Error::new(io::ErrorKind::Other, "Cannot allocate slab slot"))?;
        self.poll.register(handle, token, interest, opts)?;
        Ok(token)
    }

    pub fn reregister<E>(&mut self, handle: &E, token: Token,
                   interest: Ready, opts: PollOpt) -> io::Result<()>
            where E: Evented + ?Sized {
        if self.running_state.is_running(token) {
            self.running_state.set_removed(false);
        }
        self.poll.reregister(handle, token, interest, opts)
    }

    pub fn deregister<E>(&mut self, handle: &E, token: Token) -> io::Result<()>
            where E: Evented + ?Sized {
        if self.running_state.is_running(token) {
            // only mark as removed to not reinsert it after its execution
            self.running_state.set_removed(true);
        } else {
            self.handlers.remove(token).expect("Unknown token removed");
        }
        self.poll.deregister(handle)
    }

    pub fn poll(&mut self, events: &mut Events, timeout: Option<Duration>) -> io::Result<usize> {
        self.poll.poll(events, timeout)
    }

    pub fn run_handler(&mut self, event: Event) {
        let mut handler = self.handlers.remove(event.token()).expect("Token not found");

        self.running_state.running(event.token());

        handler.on_ready(self, event);

        if !self.running_state.is_removed() {
            if let Err(_) = self.handlers.insert(handler) {
                panic!("Cannot allocate slab slot");
            }
        }

        self.running_state.stopping();
    }
}
<commit_msg>Rc/RefCell for EventHandlers in Slab<commit_after>use mio::*;
use std::cell::RefCell;
use std::fmt::Debug;
use std::io;
use std::rc::Rc;
use std::time::Duration;
use slab::Slab;

pub trait EventHandler {
    fn on_ready(&mut self, selector: &mut Selector, event: Event);
}

impl<F> EventHandler for F where F: FnMut(&mut Selector, Event) {
    fn on_ready(&mut self, selector: &mut Selector, event: Event) {
        self(selector, event);
    }
}

// for convenience
impl<T: EventHandler> EventHandler for Rc<RefCell<T>> {
    fn on_ready(&mut self, selector: &mut Selector, event: Event) {
        self.borrow_mut().on_ready(selector, event);
    }
}

pub struct Selector {
    poll: Poll,
    handlers: Slab<Rc<RefCell<Box<EventHandler>>>, Token>,
}

struct RunningState {
    token: Option<Token>,
    removed: bool,
}

impl Selector {
    pub fn new() -> io::Result<Self> {
        Ok(Self {
            poll: Poll::new()?,
            handlers: Slab::with_capacity(1024),
        })
    }

    pub fn register<E>(&mut self, handle: &E, handler: Box<EventHandler>,
                   interest: Ready, opts: PollOpt) -> io::Result<Token>
            where E: Evented + ?Sized {
        let token = self.handlers.insert(Rc::new(RefCell::new(handler)))
                        .map_err(|_| io::Error::new(io::ErrorKind::Other, "Cannot allocate slab slot"))?;
        self.poll.register(handle, token, interest, opts)?;
        Ok(token)
    }

    pub fn reregister<E>(&mut self, handle: &E, token: Token,
                   interest: Ready, opts: PollOpt) -> io::Result<()>
            where E: Evented + ?Sized {
        self.poll.reregister(handle, token, interest, opts)
    }

    pub fn deregister<E>(&mut self, handle: &E, token: Token) -> io::Result<()>
            where E: Evented + ?Sized {
        self.handlers.remove(token).expect("Unknown token removed");
        self.poll.deregister(handle)
    }

    pub fn poll(&mut self, events: &mut Events, timeout: Option<Duration>) -> io::Result<usize> {
        self.poll.poll(events, timeout)
    }

    pub fn run_handler(&mut self, event: Event) {
        let mut handler = self.handlers.get_mut(event.token()).expect("Token not found").clone();
        handler.borrow_mut().on_ready(self, event);
    }
}
<|endoftext|>


<commit_before>extern crate time;

use std::ascii::AsciiExt;

use time::get_time;

#[must_use]
fn match_char(e1: &u8, e2: &u8, ignore_case: bool) -> bool {
    if ignore_case {
        // FIXME: redis uses tolower() which is locale aware
        return e1.to_ascii_lowercase() == e2.to_ascii_lowercase();
    } else {
        return e1 == e2;
    }
}

pub fn glob_match(pattern: &Vec<u8>, element: &Vec<u8>, ignore_case: bool) -> bool {
    let mut patternpos = 0;
    let mut elementpos = 0;
    let star = 42u8; /* '*' */
    let question_mark = 63u8; /* '?' */
    let backslash = 92u8; /* '\\' */
    let open_bracket = 91u8; /* '[' */
    let close_bracket = 93u8; /* '[' */
    while patternpos < pattern.len() {
        match pattern[patternpos] {
            x if x == star => {
                while patternpos + 1 < pattern.len() && pattern[patternpos + 1] == star {
                    patternpos += 1;
                }
                if patternpos == pattern.len() {
                    return true;
                }
                for i in elementpos..(element.len() + 1) {
                    if glob_match(&pattern[patternpos + 1..].to_vec(), &element[i..].to_vec(), ignore_case) {
                        return true;
                    }
                }
                return false;
            },
            x if x == question_mark => {
                if elementpos >= element.len() {
                    return false;
                }
                elementpos += 1;
            },
            x if x == backslash => {
                patternpos += 1;
                if elementpos >= element.len(){
                    return false;
                }
                if !match_char(&pattern[patternpos], &element[elementpos], ignore_case) {
                    return false;
                }
                elementpos += 1;
            },
            x if x == open_bracket => {
                patternpos += 1;
                let not = pattern[patternpos] == ('^' as u8);
                if not {
                    patternpos += 1;
                }
                let mut matched = false;
                loop {
                    if pattern[patternpos] == backslash {
                        patternpos += 1;
                        if pattern[patternpos] == element[elementpos] {
                            matched = true;
                        }
                    } else if pattern[patternpos] == close_bracket {
                        break;
                    } else if patternpos >= pattern.len() {
                        patternpos += 1;
                        break;
                    } else if pattern.len() >= patternpos + 3 && pattern[patternpos + 1] == ('-' as u8) {
                        let mut start = pattern[patternpos];
                        let mut end = pattern[patternpos + 2];
                        let mut c = element[elementpos];
                        if start > end {
                            let t = start;
                            start = end;
                            end = t;
                        }
                        if ignore_case {
                            start = start.to_ascii_lowercase();
                            end = end.to_ascii_lowercase();
                            c = c.to_ascii_lowercase();
                        }
                        patternpos += 2;
                        if c >= start && c <= end {
                            matched = true;
                        }
                    } else {
                        if match_char(&pattern[patternpos], &element[elementpos], ignore_case) {
                            matched = true;
                        }
                    }
                    patternpos += 1;
                }
                if not {
                    matched = !matched;
                }
                if !matched {
                    return false;
                }
                elementpos += 1;
            },
            _ => {
                if elementpos >= element.len(){
                    return false;
                }
                if !match_char(&pattern[patternpos], &element[elementpos], ignore_case) {
                    return false;
                }
                elementpos += 1;
            },
        }
        patternpos += 1;
        if elementpos == element.len() {
            for p in patternpos..pattern.len() {
                if pattern[p] != star {
                    break;
                }
            }
            break;
        }
    }

    if patternpos == pattern.len() && elementpos == element.len() {
        return true;
    }
    return false;
}

pub fn ustime() -> i64 {
    let tv = get_time();
    tv.sec * 1000000 + (tv.nsec / 1000) as i64
}

pub fn mstime() -> i64 {
    ustime() / 1000
}

pub fn splitargs(args: &[u8]) -> Result<Vec<Vec<u8>>, ()> {
    let mut i = 0;
    let mut result = Vec::new();
    for _ in args {
        while i < args.len() && (args[i] == 0 || (args[i] as char).is_whitespace()) { i += 1; }
        if i >=  args.len() { break; }
        let mut inq = false;
        let mut insq = false;
        let mut done = false;
        let mut current = Vec::new();
        while !done && i < args.len() {
            let p = args[i] as char;
            if inq {
                if p == '\\' && (args[i + 1] as char) == 'x' {
                    if let Some(c1) = (args[i + 2] as char).to_digit(16) {
                        if let Some(c2) = (args[i + 3] as char).to_digit(16) {
                            current.push((c1 * 16 + c2) as u8);
                            i += 3;
                        }
                    }
                } else if p == '"'{
                    // closing quote must be followed by a space or nothing at all
                    i += 1;
                    if i != args.len() && !(args[i] as char).is_whitespace() { return Err(()); }
                    inq = false;
                    done = true;
                } else if p == '\\' && i + 1 < args.len() {
                    i += 1;
                    let c = match args[i] as char {
                        'n' => '\n',
                        'r' => '\r',
                        't' => '\t',
                        // FIXME: Rust does not recognize '\a' and '\b'?
                        'b' => 'b',
                        'a' => 'a',
                        c => c as char,
                    } as u8;
                    current.push(c);
                } else {
                    current.push(args[i]);
                }
            } else if insq {
                if p == '\'' {
                    // closing quote must be followed by a space or nothing at all
                    i += 1;
                    if i != args.len() && !(args[i] as char).is_whitespace() { return Err(()); }
                    insq = false;
                    done = true;
                } else if p == '\\' && i + 1 < args.len() && (args[i + 1] as char == '\'') {
                    current.push(args[i + 1]);
                    i += 1;
                } else {
                    current.push(args[i]);
                }
            } else {
                match p as char {
                    ' ' => done = true,
                    '\t' => done = true,
                    '\n' => done = true,
                    '\r' => done = true,
                    '\0' => done = true,
                    '"' => inq = true,
                    '\'' => insq = true,
                    _ => current.push(args[i]),
                }
            }
            i += 1;
        }
        result.push(current);
        if i >=  args.len() {
            if inq || insq {
                return Err(());
            }
            break;
        }
    }
    Ok(result)
}

pub fn htonl(v: u32) -> [u8; 4] {
    // maybe it should use C api instead?
    [
        ((v >> 24) & 0xFF) as u8,
        ((v >> 16) & 0xFF) as u8,
        ((v >> 8) & 0xFF) as u8,
        ((v >> 0) & 0xFF) as u8,
    ]
}

#[cfg(test)]
mod test_util {
    use std::{u8, u32};
    use std::thread::sleep_ms;

    use super::{mstime, splitargs, glob_match, htonl};

    #[test]
    fn mstime_sleep() {
        let start = mstime();
        sleep_ms(100);
        let end = mstime();
        assert!(start < end && start + 100 <= end && start + 500 > end);
    }

    #[test]
    fn glob_match_empty() {
        assert!(glob_match(&b"".to_vec(), &b"".to_vec(), true));
    }

    #[test]
    fn glob_match_star() {
        assert!(glob_match(&b"*".to_vec(), &b"".to_vec(), true));
        assert!(glob_match(&b"*".to_vec(), &b"hello world".to_vec(), true));
        assert!(glob_match(&b"**".to_vec(), &b"hello world".to_vec(), true));
        assert!(glob_match(&b"hello*".to_vec(), &b"hello world".to_vec(), true));
        assert!(glob_match(&b"*world".to_vec(), &b"hello world".to_vec(), true));
        assert!(!glob_match(&b"foo*".to_vec(), &b"hello world".to_vec(), true));
        assert!(!glob_match(&b"*bar".to_vec(), &b"hello world".to_vec(), true));
        assert!(!glob_match(&b"*bar".to_vec(), &b"".to_vec(), true));
    }

    #[test]
    fn glob_match_question_mark() {
        assert!(!glob_match(&b"?".to_vec(), &b"".to_vec(), true));
        assert!(glob_match(&b"?".to_vec(), &b"a".to_vec(), true));
        assert!(!glob_match(&b"?".to_vec(), &b"aa".to_vec(), true));
        assert!(glob_match(&b"a?".to_vec(), &b"aa".to_vec(), true));
    }

    #[test]
    fn glob_match_backslash() {
        assert!(glob_match(&b"\\*asd".to_vec(), &b"*asd".to_vec(), true));
        assert!(!glob_match(&b"\\*d".to_vec(), &b"*asd".to_vec(), true));
        assert!(glob_match(&b"\\?a".to_vec(), &b"?a".to_vec(), true));
        assert!(!glob_match(&b"\\?a".to_vec(), &b"ba".to_vec(), true));
    }

    #[test]
    fn glob_match_brackets() {
        assert!(glob_match(&b"[abc]".to_vec(), &b"a".to_vec(), true));
        assert!(!glob_match(&b"[^abc]".to_vec(), &b"a".to_vec(), true));
        assert!(glob_match(&b"[abc]b".to_vec(), &b"ab".to_vec(), true));
        assert!(!glob_match(&b"[abc]".to_vec(), &b"ab".to_vec(), true));
        assert!(glob_match(&b"[\\]*]".to_vec(), &b"]".to_vec(), true));
        assert!(!glob_match(&b"[\\]*]".to_vec(), &b"a".to_vec(), true));
    }

    #[test]
    fn splitargs_quotes() {
        assert_eq!(splitargs(&b"\"\\x9f\"".to_vec()).unwrap(), vec![vec![159u8]]);
        assert_eq!(splitargs(&b"\"\"".to_vec()).unwrap(), vec![vec![]]);
        assert_eq!(splitargs(&b"\"\\thello\\n\"".to_vec()).unwrap(), vec![b"\thello\n".to_vec()]);
        assert!(splitargs(&b"\"a".to_vec()).is_err());
    }

    #[test]
    fn splitargs_singlequotes() {
        assert_eq!(splitargs(&b"\'\\x9f\'".to_vec()).unwrap(), vec![b"\\x9f".to_vec()]);
        assert_eq!(splitargs(&b"\'\'".to_vec()).unwrap(), vec![vec![]]);
        assert_eq!(splitargs(&b"\'\\\'\'".to_vec()).unwrap(), vec![b"'".to_vec()]);
        assert_eq!(splitargs(&b"\'\\thello\\n\'".to_vec()).unwrap(), vec![b"\\thello\\n".to_vec()]);
        assert!(splitargs(&b"\'a".to_vec()).is_err());
    }

    #[test]
    fn splitargs_misc() {
        assert_eq!(splitargs(&b"hello world".to_vec()).unwrap(), vec![b"hello".to_vec(), b"world".to_vec()]);
        assert_eq!(splitargs(&b"\'hello\' world".to_vec()).unwrap(), vec![b"hello".to_vec(), b"world".to_vec()]);
        assert_eq!(splitargs(&b"\"hello\" world".to_vec()).unwrap(), vec![b"hello".to_vec(), b"world".to_vec()]);
        assert!(splitargs(&b"\"hello\"world".to_vec()).is_err());
        assert!(splitargs(&b"\'hello\'world".to_vec()).is_err());
    }

    #[test]
    fn htonl_basic() {
        assert_eq!(htonl(1), [0, 0, 0, 1]);
        assert_eq!(htonl(256), [0, 0, 1, 0]);
        assert_eq!(htonl(u32::MAX), [u8::MAX, u8::MAX, u8::MAX, u8::MAX]);
    }
}
<commit_msg>Document util functions<commit_after>extern crate time;

use std::ascii::AsciiExt;

use time::get_time;

/// Are two chars the same? Optionally ignoring the case.
///
/// # Examples
///
/// ```
/// use util::match_char;
/// assert!( match_char(&('a' as u8), &('a' as u8), false));
/// assert!( match_char(&('a' as u8), &('a' as u8), true));
/// assert!(!match_char(&('a' as u8), &('A' as u8), false));
/// assert!( match_char(&('a' as u8), &('A' as u8), true));
/// ```
#[must_use]
pub fn match_char(e1: &u8, e2: &u8, ignore_case: bool) -> bool {
    if ignore_case {
        // FIXME: redis uses tolower() which is locale aware
        return e1.to_ascii_lowercase() == e2.to_ascii_lowercase();
    } else {
        return e1 == e2;
    }
}

/// Whether an element matches a glob-like pattern. Optionally ignores case.
///
/// # Examples
///
/// ```
/// use util::glob_match;
/// assert!(glob_match(&b"".to_vec(), &b"".to_vec(), false));
/// assert!(glob_match(&b"foo*baz".to_vec(), &b"foobarbaz".to_vec(), false));
/// assert!(!glob_match(&b"foo*baz".to_vec(), &b"foobazbar".to_vec(), false));
/// assert!(glob_match(&b"fooba?".to_vec(), &b"foobar".to_vec(), false));
/// assert!(glob_match(&b"fooba?".to_vec(), &b"foobaz".to_vec(), false));
/// assert!(!glob_match(&b"fooba?".to_vec(), &b"foofoo".to_vec(), false));
/// ```
#[must_use]
pub fn glob_match(pattern: &Vec<u8>, element: &Vec<u8>, ignore_case: bool) -> bool {
    let mut patternpos = 0;
    let mut elementpos = 0;
    let star = 42u8; /* '*' */
    let question_mark = 63u8; /* '?' */
    let backslash = 92u8; /* '\\' */
    let open_bracket = 91u8; /* '[' */
    let close_bracket = 93u8; /* '[' */
    while patternpos < pattern.len() {
        match pattern[patternpos] {
            x if x == star => {
                while patternpos + 1 < pattern.len() && pattern[patternpos + 1] == star {
                    patternpos += 1;
                }
                if patternpos == pattern.len() {
                    return true;
                }
                for i in elementpos..(element.len() + 1) {
                    if glob_match(&pattern[patternpos + 1..].to_vec(), &element[i..].to_vec(), ignore_case) {
                        return true;
                    }
                }
                return false;
            },
            x if x == question_mark => {
                if elementpos >= element.len() {
                    return false;
                }
                elementpos += 1;
            },
            x if x == backslash => {
                patternpos += 1;
                if elementpos >= element.len(){
                    return false;
                }
                if !match_char(&pattern[patternpos], &element[elementpos], ignore_case) {
                    return false;
                }
                elementpos += 1;
            },
            x if x == open_bracket => {
                patternpos += 1;
                let not = pattern[patternpos] == ('^' as u8);
                if not {
                    patternpos += 1;
                }
                let mut matched = false;
                loop {
                    if pattern[patternpos] == backslash {
                        patternpos += 1;
                        if pattern[patternpos] == element[elementpos] {
                            matched = true;
                        }
                    } else if pattern[patternpos] == close_bracket {
                        break;
                    } else if patternpos >= pattern.len() {
                        patternpos += 1;
                        break;
                    } else if pattern.len() >= patternpos + 3 && pattern[patternpos + 1] == ('-' as u8) {
                        let mut start = pattern[patternpos];
                        let mut end = pattern[patternpos + 2];
                        let mut c = element[elementpos];
                        if start > end {
                            let t = start;
                            start = end;
                            end = t;
                        }
                        if ignore_case {
                            start = start.to_ascii_lowercase();
                            end = end.to_ascii_lowercase();
                            c = c.to_ascii_lowercase();
                        }
                        patternpos += 2;
                        if c >= start && c <= end {
                            matched = true;
                        }
                    } else {
                        if match_char(&pattern[patternpos], &element[elementpos], ignore_case) {
                            matched = true;
                        }
                    }
                    patternpos += 1;
                }
                if not {
                    matched = !matched;
                }
                if !matched {
                    return false;
                }
                elementpos += 1;
            },
            _ => {
                if elementpos >= element.len(){
                    return false;
                }
                if !match_char(&pattern[patternpos], &element[elementpos], ignore_case) {
                    return false;
                }
                elementpos += 1;
            },
        }
        patternpos += 1;
        if elementpos == element.len() {
            for p in patternpos..pattern.len() {
                if pattern[p] != star {
                    break;
                }
            }
            break;
        }
    }

    if patternpos == pattern.len() && elementpos == element.len() {
        return true;
    }
    return false;
}

/// Current timestamp in microseconds
pub fn ustime() -> i64 {
    let tv = get_time();
    tv.sec * 1000000 + (tv.nsec / 1000) as i64
}

/// Current timestamp in milliseconds
pub fn mstime() -> i64 {
    ustime() / 1000
}

/// Parses a config line string.
///
/// # Examples
/// ```
/// # use util::splitargs;
/// #
/// let res = splitargs(b"hello world").unwrap();
/// assert_eq!(res, vec![b"hello".to_vec(), b"world".to_vec()]);
/// ```
///
/// ```
/// # use util::splitargs;
/// #
/// let res = splitargs(b"foo \"bar baz\"").unwrap();
/// assert_eq!(res, vec![b"foo".to_vec(), b"bar baz".to_vec()]);
/// ```
pub fn splitargs(args: &[u8]) -> Result<Vec<Vec<u8>>, ()> {
    let mut i = 0;
    let mut result = Vec::new();
    for _ in args {
        while i < args.len() && (args[i] == 0 || (args[i] as char).is_whitespace()) { i += 1; }
        if i >=  args.len() { break; }
        let mut inq = false;
        let mut insq = false;
        let mut done = false;
        let mut current = Vec::new();
        while !done && i < args.len() {
            let p = args[i] as char;
            if inq {
                if p == '\\' && (args[i + 1] as char) == 'x' {
                    if let Some(c1) = (args[i + 2] as char).to_digit(16) {
                        if let Some(c2) = (args[i + 3] as char).to_digit(16) {
                            current.push((c1 * 16 + c2) as u8);
                            i += 3;
                        }
                    }
                } else if p == '"'{
                    // closing quote must be followed by a space or nothing at all
                    i += 1;
                    if i != args.len() && !(args[i] as char).is_whitespace() { return Err(()); }
                    inq = false;
                    done = true;
                } else if p == '\\' && i + 1 < args.len() {
                    i += 1;
                    let c = match args[i] as char {
                        'n' => '\n',
                        'r' => '\r',
                        't' => '\t',
                        // FIXME: Rust does not recognize '\a' and '\b'?
                        'b' => 'b',
                        'a' => 'a',
                        c => c as char,
                    } as u8;
                    current.push(c);
                } else {
                    current.push(args[i]);
                }
            } else if insq {
                if p == '\'' {
                    // closing quote must be followed by a space or nothing at all
                    i += 1;
                    if i != args.len() && !(args[i] as char).is_whitespace() { return Err(()); }
                    insq = false;
                    done = true;
                } else if p == '\\' && i + 1 < args.len() && (args[i + 1] as char == '\'') {
                    current.push(args[i + 1]);
                    i += 1;
                } else {
                    current.push(args[i]);
                }
            } else {
                match p as char {
                    ' ' => done = true,
                    '\t' => done = true,
                    '\n' => done = true,
                    '\r' => done = true,
                    '\0' => done = true,
                    '"' => inq = true,
                    '\'' => insq = true,
                    _ => current.push(args[i]),
                }
            }
            i += 1;
        }
        result.push(current);
        if i >=  args.len() {
            if inq || insq {
                return Err(());
            }
            break;
        }
    }
    Ok(result)
}

/// Creates an array of four `u8` from a `u32`.
pub fn htonl(v: u32) -> [u8; 4] {
    // maybe it should use C api instead?
    [
        ((v >> 24) & 0xFF) as u8,
        ((v >> 16) & 0xFF) as u8,
        ((v >> 8) & 0xFF) as u8,
        ((v >> 0) & 0xFF) as u8,
    ]
}

#[cfg(test)]
mod test_util {
    use std::{u8, u32};
    use std::thread::sleep_ms;

    use super::{mstime, splitargs, glob_match, htonl};

    #[test]
    fn mstime_sleep() {
        let start = mstime();
        sleep_ms(100);
        let end = mstime();
        assert!(start < end && start + 100 <= end && start + 500 > end);
    }

    #[test]
    fn glob_match_empty() {
        assert!(glob_match(&b"".to_vec(), &b"".to_vec(), true));
    }

    #[test]
    fn glob_match_star() {
        assert!(glob_match(&b"*".to_vec(), &b"".to_vec(), true));
        assert!(glob_match(&b"*".to_vec(), &b"hello world".to_vec(), true));
        assert!(glob_match(&b"**".to_vec(), &b"hello world".to_vec(), true));
        assert!(glob_match(&b"hello*".to_vec(), &b"hello world".to_vec(), true));
        assert!(glob_match(&b"*world".to_vec(), &b"hello world".to_vec(), true));
        assert!(!glob_match(&b"foo*".to_vec(), &b"hello world".to_vec(), true));
        assert!(!glob_match(&b"*bar".to_vec(), &b"hello world".to_vec(), true));
        assert!(!glob_match(&b"*bar".to_vec(), &b"".to_vec(), true));
    }

    #[test]
    fn glob_match_question_mark() {
        assert!(!glob_match(&b"?".to_vec(), &b"".to_vec(), true));
        assert!(glob_match(&b"?".to_vec(), &b"a".to_vec(), true));
        assert!(!glob_match(&b"?".to_vec(), &b"aa".to_vec(), true));
        assert!(glob_match(&b"a?".to_vec(), &b"aa".to_vec(), true));
    }

    #[test]
    fn glob_match_backslash() {
        assert!(glob_match(&b"\\*asd".to_vec(), &b"*asd".to_vec(), true));
        assert!(!glob_match(&b"\\*d".to_vec(), &b"*asd".to_vec(), true));
        assert!(glob_match(&b"\\?a".to_vec(), &b"?a".to_vec(), true));
        assert!(!glob_match(&b"\\?a".to_vec(), &b"ba".to_vec(), true));
    }

    #[test]
    fn glob_match_brackets() {
        assert!(glob_match(&b"[abc]".to_vec(), &b"a".to_vec(), true));
        assert!(!glob_match(&b"[^abc]".to_vec(), &b"a".to_vec(), true));
        assert!(glob_match(&b"[abc]b".to_vec(), &b"ab".to_vec(), true));
        assert!(!glob_match(&b"[abc]".to_vec(), &b"ab".to_vec(), true));
        assert!(glob_match(&b"[\\]*]".to_vec(), &b"]".to_vec(), true));
        assert!(!glob_match(&b"[\\]*]".to_vec(), &b"a".to_vec(), true));
    }

    #[test]
    fn splitargs_quotes() {
        assert_eq!(splitargs(&b"\"\\x9f\"".to_vec()).unwrap(), vec![vec![159u8]]);
        assert_eq!(splitargs(&b"\"\"".to_vec()).unwrap(), vec![vec![]]);
        assert_eq!(splitargs(&b"\"\\thello\\n\"".to_vec()).unwrap(), vec![b"\thello\n".to_vec()]);
        assert!(splitargs(&b"\"a".to_vec()).is_err());
    }

    #[test]
    fn splitargs_singlequotes() {
        assert_eq!(splitargs(&b"\'\\x9f\'".to_vec()).unwrap(), vec![b"\\x9f".to_vec()]);
        assert_eq!(splitargs(&b"\'\'".to_vec()).unwrap(), vec![vec![]]);
        assert_eq!(splitargs(&b"\'\\\'\'".to_vec()).unwrap(), vec![b"'".to_vec()]);
        assert_eq!(splitargs(&b"\'\\thello\\n\'".to_vec()).unwrap(), vec![b"\\thello\\n".to_vec()]);
        assert!(splitargs(&b"\'a".to_vec()).is_err());
    }

    #[test]
    fn splitargs_misc() {
        assert_eq!(splitargs(&b"hello world".to_vec()).unwrap(), vec![b"hello".to_vec(), b"world".to_vec()]);
        assert_eq!(splitargs(&b"\'hello\' world".to_vec()).unwrap(), vec![b"hello".to_vec(), b"world".to_vec()]);
        assert_eq!(splitargs(&b"\"hello\" world".to_vec()).unwrap(), vec![b"hello".to_vec(), b"world".to_vec()]);
        assert!(splitargs(&b"\"hello\"world".to_vec()).is_err());
        assert!(splitargs(&b"\'hello\'world".to_vec()).is_err());
    }

    #[test]
    fn htonl_basic() {
        assert_eq!(htonl(1), [0, 0, 0, 1]);
        assert_eq!(htonl(256), [0, 0, 1, 0]);
        assert_eq!(htonl(u32::MAX), [u8::MAX, u8::MAX, u8::MAX, u8::MAX]);
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "cargo-clippy", allow(clone_on_ref_ptr))]
#![cfg_attr(feature = "cargo-clippy", allow(not_unsafe_ptr_arg_deref))]
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]

extern crate cairo;
extern crate cairo_sys;
extern crate cssparser;
extern crate data_url;
extern crate downcast_rs;
extern crate encoding;
extern crate float_cmp;
extern crate gdk_pixbuf;
extern crate gio;
extern crate gio_sys;
extern crate glib;
extern crate glib_sys;
extern crate itertools;
extern crate language_tags;
extern crate libc;
extern crate locale_config;
extern crate nalgebra;
extern crate num_traits;
extern crate owning_ref;
extern crate pango;
extern crate pango_cairo_sys;
extern crate pango_sys;
extern crate pangocairo;
extern crate rayon;
extern crate regex;
extern crate url;
extern crate xml as xml_rs;

#[macro_use]
extern crate lazy_static;

pub use color::{rsvg_css_parse_color, ColorKind, ColorSpec};

pub use drawing_ctx::{
    rsvg_drawing_ctx_add_node_and_ancestors_to_stack,
    rsvg_drawing_ctx_draw_node_from_stack,
    rsvg_drawing_ctx_free,
    rsvg_drawing_ctx_get_geometry,
    rsvg_drawing_ctx_new,
};

pub use handle::{
    rsvg_handle_acquire_data,
    rsvg_handle_acquire_stream,
    rsvg_handle_defs_lookup,
    rsvg_handle_rust_cascade,
    rsvg_handle_rust_free,
    rsvg_handle_rust_get_base_gfile,
    rsvg_handle_rust_get_root,
    rsvg_handle_rust_new,
    rsvg_handle_rust_node_is_root,
    rsvg_handle_rust_set_base_url,
    rsvg_handle_rust_steal_result,
};

pub use io::rsvg_get_input_stream_for_loading;

pub use node::rsvg_node_unref;

pub use structure::rsvg_node_svg_get_size;

pub use xml::{
    rsvg_xml_state_error,
    rsvg_xml_state_free,
    rsvg_xml_state_new,
    rsvg_xml_state_tree_is_valid,
};

pub use xml2_load::{rsvg_create_xml_push_parser, rsvg_xml_state_parse_from_stream};

#[macro_use]
mod log;

#[macro_use]
mod coord_units;

#[macro_use]
mod float_eq_cairo;

#[macro_use]
mod property_macros;

mod allowed_url;
mod aspect_ratio;
mod attributes;
mod bbox;
mod clip_path;
mod color;
mod cond;
mod create_node;
mod croco;
mod css;
mod defs;
mod drawing_ctx;
mod error;
pub mod filters;
mod font_props;
mod gradient;
mod handle;
mod image;
mod io;
mod iri;
mod length;
mod link;
mod marker;
mod mask;
mod node;
mod paint_server;
mod parsers;
mod path_builder;
mod path_parser;
mod pattern;
mod property_bag;
mod rect;
mod shapes;
mod space;
pub mod srgb;
mod state;
mod stop;
mod structure;
mod style;
pub mod surface_utils;
mod svg;
mod text;
mod transform;
mod tree;
pub mod tree_utils;
mod unitinterval;
mod util;
mod viewbox;
mod viewport;
mod xml;
mod xml2;
mod xml2_load;
<commit_msg>Oops, export rsvg_set_error_from_xml<commit_after>#![cfg_attr(feature = "cargo-clippy", allow(clone_on_ref_ptr))]
#![cfg_attr(feature = "cargo-clippy", allow(not_unsafe_ptr_arg_deref))]
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]

extern crate cairo;
extern crate cairo_sys;
extern crate cssparser;
extern crate data_url;
extern crate downcast_rs;
extern crate encoding;
extern crate float_cmp;
extern crate gdk_pixbuf;
extern crate gio;
extern crate gio_sys;
extern crate glib;
extern crate glib_sys;
extern crate itertools;
extern crate language_tags;
extern crate libc;
extern crate locale_config;
extern crate nalgebra;
extern crate num_traits;
extern crate owning_ref;
extern crate pango;
extern crate pango_cairo_sys;
extern crate pango_sys;
extern crate pangocairo;
extern crate rayon;
extern crate regex;
extern crate url;
extern crate xml as xml_rs;

#[macro_use]
extern crate lazy_static;

pub use color::{rsvg_css_parse_color, ColorKind, ColorSpec};

pub use drawing_ctx::{
    rsvg_drawing_ctx_add_node_and_ancestors_to_stack,
    rsvg_drawing_ctx_draw_node_from_stack,
    rsvg_drawing_ctx_free,
    rsvg_drawing_ctx_get_geometry,
    rsvg_drawing_ctx_new,
};

pub use handle::{
    rsvg_handle_acquire_data,
    rsvg_handle_acquire_stream,
    rsvg_handle_defs_lookup,
    rsvg_handle_rust_cascade,
    rsvg_handle_rust_free,
    rsvg_handle_rust_get_base_gfile,
    rsvg_handle_rust_get_root,
    rsvg_handle_rust_new,
    rsvg_handle_rust_node_is_root,
    rsvg_handle_rust_set_base_url,
    rsvg_handle_rust_steal_result,
};

pub use io::rsvg_get_input_stream_for_loading;

pub use node::rsvg_node_unref;

pub use structure::rsvg_node_svg_get_size;

pub use xml::{
    rsvg_xml_state_error,
    rsvg_xml_state_free,
    rsvg_xml_state_new,
    rsvg_xml_state_tree_is_valid,
};

pub use xml2_load::{
    rsvg_create_xml_push_parser,
    rsvg_set_error_from_xml,
    rsvg_xml_state_parse_from_stream,
};

#[macro_use]
mod log;

#[macro_use]
mod coord_units;

#[macro_use]
mod float_eq_cairo;

#[macro_use]
mod property_macros;

mod allowed_url;
mod aspect_ratio;
mod attributes;
mod bbox;
mod clip_path;
mod color;
mod cond;
mod create_node;
mod croco;
mod css;
mod defs;
mod drawing_ctx;
mod error;
pub mod filters;
mod font_props;
mod gradient;
mod handle;
mod image;
mod io;
mod iri;
mod length;
mod link;
mod marker;
mod mask;
mod node;
mod paint_server;
mod parsers;
mod path_builder;
mod path_parser;
mod pattern;
mod property_bag;
mod rect;
mod shapes;
mod space;
pub mod srgb;
mod state;
mod stop;
mod structure;
mod style;
pub mod surface_utils;
mod svg;
mod text;
mod transform;
mod tree;
pub mod tree_utils;
mod unitinterval;
mod util;
mod viewbox;
mod viewport;
mod xml;
mod xml2;
mod xml2_load;
<|endoftext|>


<commit_before>fn generate_table () {
    let pi: f32 = 3.1415926536897932384626;
    let k1: f32 = 0.6072529350088812561694; // 1/k
    let num_bits: uint = 32;
    let num_elms: uint = num_bits;
    let mul: f32 = 1073741824.000000; // 1<<(bits-2)

    println!("Cordic sin in rust");
    println!("num bits {}", num_bits);
    println!("mul {}", mul);
    println!("pi is {}", pi);
    println!("k1 is {}", k1);

    let shift: f32 = 2.0;
    for ii in range(0, num_bits) {
        let ipow: f32 = 1f32/shift.powi(ii as i32);
        let cur: f32 = ipow.atan() * mul;
        //println!("table values {:.10f}", cur);
        println!("table values 0x{}", std::f32::to_str_hex(cur));
    }
}

fn main() {
    generate_table();
}
<commit_msg>switch to f64<commit_after>fn generate_table () {
    let pi: f64 = 3.1415926536897932384626;
    let k1: f64 = 0.6072529350088812561694; // 1/k
    let num_bits: uint = 32;
    //let num_elms: uint = num_bits;
    let mul: uint = 1<<(num_bits-2);

    println!("Cordic sin in rust");
    println!("num bits {}", num_bits);
    println!("mul {}", mul);
    println!("1<<(num_bits-2) {}", ((1i << (num_bits-2)) as f64));
    println!("pi is {}", pi);
    println!("k1 is {}", k1);

    let shift: f64 = 2.0;
    for ii in range(0, num_bits) {
        let ipow: f64 = 1f64/shift.powi(ii as i32);
        let cur: f64 = ipow.atan() * (mul as f64);
        //println!("table values {:.10f}", cur);
        println!("table values 0x{}", std::f64::to_str_hex(cur));
    }
}

fn main() {
    generate_table();
}
<|endoftext|>