<commit_before>extern crate base64;
extern crate hyper;
extern crate libc;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use base64::{encode, decode};
use hyper::Client;
use hyper::Error;
use hyper::client::response::Response;
use hyper::header::{Headers, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::status::StatusCode;
use libc::{uint8_t, size_t};
use log::LogLevelFilter;
use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Config, Logger, Root};
use log4rs::encode::pattern::PatternEncoder;
use serde::Serialize;
use std::collections::HashMap;
use std::env::var;
use std::io::Read;
use std::slice;
use std::sync::{Once, ONCE_INIT, Mutex};

const BASE_URL: &'static str = "http://localhost:8080/k2/ctapi/";

static OK: i8 = 0;
static ERR_INVALID: i8 = -1;
static ERR_HOST: i8 = -127;
static ERR_HTSI: i8 = -128;

static INIT: Once = ONCE_INIT;

lazy_static! {
    static ref MAP: Mutex<HashMap<u16, u16>> = Mutex::new(HashMap::new());
}

#[derive(Serialize)]
struct Empty();

#[derive(Serialize)]
struct RequestData {
    dad: u8,
    sad: u8,
    lenc: usize,
    command: String,
    lenr: usize,
}

#[allow(non_snake_case)]
#[derive(Deserialize)]
struct ResponseData {
    dad: u8,
    sad: u8,
    lenr: usize,
    response: String,
    responseCode: i8,
}

macro_rules! post_request {
    ($path:expr) => (post_request($path, &Empty{}));
    ($path:expr, $data:expr) => (post_request($path, $data));
}

#[no_mangle]
#[allow(non_snake_case, unused_must_use)]
pub extern "C" fn CT_init(ctn: u16, pn: u16) -> i8 {
    init_logging();

    debug!("CT_init: Called (ctn {}, pn {})", ctn, pn);

    // Do we know this CTN?
    if MAP.lock().unwrap().contains_key(&ctn) {
        debug!("CT_init: Card terminal has already been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    // Build the request URL
    let endpoint = "ct_init".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    // Perform the request
    match post_request!(&path) {
        Ok(mut response) => {
            debug!("{:?}", response); // TODO enrich output

            match response.status {
                StatusCode::Ok => {
                    // Cast server response
                    let mut body = String::new();
                    response.read_to_string(&mut body).unwrap();

                    let status = body.parse::<i8>().unwrap();
                    if status == OK {
                        // Store CTN
                        MAP.lock().unwrap().insert(ctn, pn);
                        debug!("CT_init: Card terminal opened.");
                    }

                    debug!("CT_init: Returning {}", status);
                    status
                }
                _ => {
                    error!("CT_init: Response not OK! Returning {}", ERR_HOST);
                    ERR_HOST
                }
            }
        }
        Err(error) => {
            debug!("Error: {:?}", error);
            error!("CT_data: Request failed! Returning {}", ERR_HTSI);
            ERR_HTSI
        }
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CT_data(ctn: u16,
                          dad: *mut uint8_t,
                          sad: *mut uint8_t,
                          lenc: size_t,
                          command: *const uint8_t,
                          lenr: *mut size_t,
                          response: *mut uint8_t)
                          -> i8 {
    init_logging();

    debug!("CT_data: Called");
    debug!(" ctn: {}", ctn);

    let _dad: &mut u8 = unsafe { &mut *dad };
    debug!(" dad: {}", _dad);

    let _sad: &mut u8 = unsafe { &mut *sad };
    debug!(" sad: {}", _sad);
    debug!(" lenc: {}", lenc);

    let _command = unsafe { slice::from_raw_parts(command, lenc as usize) };
    debug!(" command: {:?}", _command);

    let _lenr: &mut size_t = unsafe { &mut *lenr };
    debug!(" lenr: {}", _lenr);

    let _response = unsafe { slice::from_raw_parts_mut(response, *_lenr) };
    debug!(" response.len(): {}", _response.len());

    if !MAP.lock().unwrap().contains_key(&ctn) {
        debug!("CT_data: Card terminal has not been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    let requestData = RequestData {
        dad: *_dad,
        sad: *_sad,
        lenc: lenc,
        command: encode(_command),
        lenr: *_lenr,
    };

    let pn = MAP.lock().unwrap();
    let pn = pn.get(&ctn).unwrap();
    let endpoint = "ct_data".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    match post_request(&path, &requestData) {
        Ok(mut http_response) => {
            debug!("{:?}", http_response); // TODO enrich output

            match http_response.status {
                StatusCode::Ok => {
                    // decode server response
                    let mut body = String::new();
                    http_response.read_to_string(&mut body).unwrap();
                    debug!("CT_data: Response body: {}", body);

                    let responseData: ResponseData = serde_json::from_str(&body).unwrap();

                    if responseData.responseCode == OK {
                        *_dad = responseData.dad;
                        *_sad = responseData.sad;
                        *_lenr = responseData.lenr;

                        let decoded = decode(&responseData.response).unwrap();
                        debug!("CT_data: Decoded response field {:?}", decoded);

                        for (place, element) in _response.iter_mut().zip(decoded.iter()) {
                            *place = *element;
                        }
                    }
                    debug!("CT_data: Returning {}", responseData.responseCode);
                    return responseData.responseCode;
                }
                _ => {
                    error!("CT_data: Response not OK! Returning {}", ERR_HOST);
                    ERR_HOST
                }
            }
        }
        Err(error) => {
            debug!("Error: {:?}", error);
            error!("CT_data: Request failed! Returning {}", ERR_HTSI);
            ERR_HTSI
        }
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CT_close(ctn: u16) -> i8 {
    init_logging();

    debug!("CT_close: Called (ctn {})", ctn);

    // Do we know this CTN?
    if !MAP.lock().unwrap().contains_key(&ctn) {
        debug!("CT_close: Card terminal has not been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    // Build the request URL
    let pn = MAP.lock().unwrap().get(&ctn).unwrap().clone();
    let endpoint = "ct_close".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    // Perform the request
    match post_request!(&path) {
        Ok(mut response) => {
            debug!("{:?}", response); // TODO enrich output

            match response.status {
                StatusCode::Ok => {
                    // Cast server response
                    let mut body = String::new();
                    response.read_to_string(&mut body).unwrap();

                    let status = body.parse::<i8>().unwrap();
                    if status == OK {
                        // Remove CTN
                        MAP.lock().unwrap().remove(&ctn);
                        debug!("CT_close: Card terminal has been closed.");
                    }

                    debug!("CT_close: Returning {}", status);
                    status
                }
                _ => {
                    error!("CT_close: Response not OK! Returning {}", ERR_HOST);
                    ERR_HOST
                }
            }
        }
        Err(error) => {
            debug!("Error: {}", error);
            error!("CT_close: Request failed! Returning {}", ERR_HTSI);
            ERR_HTSI
        }
    }
}

fn init_logging() {
    match var("K2_LOG_PATH") {
        Ok(path) => {
            INIT.call_once(|| {
                let file = FileAppender::builder()
                    .encoder(Box::new(PatternEncoder::new("{d} {l} {M}: {m}{n}")))
                    .build(path + &"/ctehxk2.log".to_string())
                    .unwrap();

                let config = Config::builder()
                    .appender(Appender::builder().build("file", Box::new(file)))
                    .logger(Logger::builder()
                                .appender("file")
                                .additive(false)
                                .build("ctehxk2", LogLevelFilter::Debug))
                    .build(Root::builder()
                               .appender("file")
                               .build(LogLevelFilter::Error))
                    .unwrap();

                log4rs::init_config(config).unwrap();
            })
        }
        _ => (),
    }
}

fn post_request<T>(path: &str, payload: &T) -> Result<Response, Error>
    where T: Serialize
{
    let base_url = var("K2_BASE_URL").unwrap_or(BASE_URL.to_string());
    let url = base_url + path;

    let client = Client::new();

    let mut headers = Headers::new();
    headers.set(ContentType(Mime(TopLevel::Application, SubLevel::Json, vec![])));

    let body = serde_json::to_string(&payload).unwrap();

    debug!("HTTP POST URL: {}", url);
    debug!("HTTP POST body: {:?}", body);

    let mut builder = client.post(&url);
    builder = builder.headers(headers);
    builder = builder.body(&body[..]);
    builder.send()
}
<commit_msg>flatten match calls<commit_after>extern crate base64;
extern crate hyper;
extern crate libc;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use base64::{encode, decode};
use hyper::Client;
use hyper::Error;
use hyper::client::response::Response;
use hyper::header::{Headers, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::status::StatusCode;
use libc::{uint8_t, size_t};
use log::LogLevelFilter;
use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Config, Logger, Root};
use log4rs::encode::pattern::PatternEncoder;
use serde::Serialize;
use std::collections::HashMap;
use std::env::var;
use std::io::Read;
use std::slice;
use std::sync::{Once, ONCE_INIT, Mutex};

const BASE_URL: &'static str = "http://localhost:8080/k2/ctapi/";

static OK: i8 = 0;
static ERR_INVALID: i8 = -1;
static ERR_HOST: i8 = -127;
static ERR_HTSI: i8 = -128;

static INIT: Once = ONCE_INIT;

lazy_static! {
    static ref MAP: Mutex<HashMap<u16, u16>> = Mutex::new(HashMap::new());
}

#[derive(Serialize)]
struct Empty();

#[derive(Serialize)]
struct RequestData {
    dad: u8,
    sad: u8,
    lenc: usize,
    command: String,
    lenr: usize,
}

#[allow(non_snake_case)]
#[derive(Deserialize)]
struct ResponseData {
    dad: u8,
    sad: u8,
    lenr: usize,
    response: String,
    responseCode: i8,
}

macro_rules! post_request {
    ($path:expr) => (post_request($path, &Empty{}));
    ($path:expr, $data:expr) => (post_request($path, $data));
}

#[no_mangle]
#[allow(non_snake_case, unused_must_use)]
pub extern "C" fn CT_init(ctn: u16, pn: u16) -> i8 {
    init_logging();

    debug!("CT_init: Called (ctn {}, pn {})", ctn, pn);

    // Do we know this CTN?
    if MAP.lock().unwrap().contains_key(&ctn) {
        debug!("CT_init: Card terminal has already been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    // Build the request URL
    let endpoint = "ct_init".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    // Perform the request
    let mut response = match post_request!(&path) {
        Ok(response) => response,
        Err(error) => {
            debug!("Error: {:?}", error);
            error!("CT_data: Request failed! Returning {}", ERR_HTSI);
            return ERR_HTSI;
        }
    };

    debug!("{:?}", response); // TODO enrich output

    match response.status {
        StatusCode::Ok => {
            // Cast server response
            let mut body = String::new();
            response.read_to_string(&mut body).unwrap();

            let status = body.parse::<i8>().unwrap();
            if status == OK {
                // Store CTN
                MAP.lock().unwrap().insert(ctn, pn);
                debug!("CT_init: Card terminal opened.");
            }

            debug!("CT_init: Returning {}", status);
            status
        }
        _ => {
            error!("CT_init: Response not OK! Returning {}", ERR_HOST);
            ERR_HOST
        }
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CT_data(ctn: u16,
                          dad: *mut uint8_t,
                          sad: *mut uint8_t,
                          lenc: size_t,
                          command: *const uint8_t,
                          lenr: *mut size_t,
                          response: *mut uint8_t)
                          -> i8 {
    init_logging();

    debug!("CT_data: Called");
    debug!(" ctn: {}", ctn);

    let _dad: &mut u8 = unsafe { &mut *dad };
    debug!(" dad: {}", _dad);

    let _sad: &mut u8 = unsafe { &mut *sad };
    debug!(" sad: {}", _sad);
    debug!(" lenc: {}", lenc);

    let _command = unsafe { slice::from_raw_parts(command, lenc as usize) };
    debug!(" command: {:?}", _command);

    let _lenr: &mut size_t = unsafe { &mut *lenr };
    debug!(" lenr: {}", _lenr);

    let _response = unsafe { slice::from_raw_parts_mut(response, *_lenr) };
    debug!(" response.len(): {}", _response.len());

    if !MAP.lock().unwrap().contains_key(&ctn) {
        debug!("CT_data: Card terminal has not been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    let requestData = RequestData {
        dad: *_dad,
        sad: *_sad,
        lenc: lenc,
        command: encode(_command),
        lenr: *_lenr,
    };

    let pn = MAP.lock().unwrap();
    let pn = pn.get(&ctn).unwrap();
    let endpoint = "ct_data".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    let mut http_response = match post_request(&path, &requestData) {
        Ok(http_response) => http_response,
        Err(error) => {
            debug!("Error: {:?}", error);
            error!("CT_data: Request failed! Returning {}", ERR_HTSI);
            return ERR_HTSI;
        }
    };

    debug!("{:?}", http_response); // TODO enrich output

    match http_response.status {
        StatusCode::Ok => {
            // decode server response
            let mut body = String::new();
            http_response.read_to_string(&mut body).unwrap();
            debug!("CT_data: Response body: {}", body);

            let responseData: ResponseData = serde_json::from_str(&body).unwrap();

            if responseData.responseCode == OK {
                *_dad = responseData.dad;
                *_sad = responseData.sad;
                *_lenr = responseData.lenr;

                let decoded = decode(&responseData.response).unwrap();
                debug!("CT_data: Decoded response field {:?}", decoded);

                for (place, element) in _response.iter_mut().zip(decoded.iter()) {
                    *place = *element;
                }
            }
            debug!("CT_data: Returning {}", responseData.responseCode);
            return responseData.responseCode;
        }
        _ => {
            error!("CT_data: Response not OK! Returning {}", ERR_HOST);
            ERR_HOST
        }
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CT_close(ctn: u16) -> i8 {
    init_logging();

    debug!("CT_close: Called (ctn {})", ctn);

    // Do we know this CTN?
    if !MAP.lock().unwrap().contains_key(&ctn) {
        debug!("CT_close: Card terminal has not been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    // Build the request URL
    let pn = MAP.lock().unwrap().get(&ctn).unwrap().clone();
    let endpoint = "ct_close".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    // Perform the request
    let mut response = match post_request!(&path) {
        Ok(response) => response,
        Err(error) => {
            debug!("Error: {:?}", error);
            error!("CT_close: Request failed! Returning {}", ERR_HTSI);
            return ERR_HTSI;
        }
    };

    debug!("{:?}", response); // TODO enrich output

    match response.status {
        StatusCode::Ok => {
            // Cast server response
            let mut body = String::new();
            response.read_to_string(&mut body).unwrap();

            let status = body.parse::<i8>().unwrap();
            if status == OK {
                // Remove CTN
                MAP.lock().unwrap().remove(&ctn);
                debug!("CT_close: Card terminal has been closed.");
            }

            debug!("CT_close: Returning {}", status);
            status
        }
        _ => {
            error!("CT_close: Response not OK! Returning {}", ERR_HOST);
            ERR_HOST
        }
    }
}

fn init_logging() {
    match var("K2_LOG_PATH") {
        Ok(path) => {
            INIT.call_once(|| {
                let file = FileAppender::builder()
                    .encoder(Box::new(PatternEncoder::new("{d} {l} {M}: {m}{n}")))
                    .build(path + &"/ctehxk2.log".to_string())
                    .unwrap();

                let config = Config::builder()
                    .appender(Appender::builder().build("file", Box::new(file)))
                    .logger(Logger::builder()
                                .appender("file")
                                .additive(false)
                                .build("ctehxk2", LogLevelFilter::Debug))
                    .build(Root::builder()
                               .appender("file")
                               .build(LogLevelFilter::Error))
                    .unwrap();

                log4rs::init_config(config).unwrap();
            })
        }
        _ => (),
    }
}

fn post_request<T>(path: &str, payload: &T) -> Result<Response, Error>
    where T: Serialize
{
    let base_url = var("K2_BASE_URL").unwrap_or(BASE_URL.to_string());
    let url = base_url + path;

    let client = Client::new();

    let mut headers = Headers::new();
    headers.set(ContentType(Mime(TopLevel::Application, SubLevel::Json, vec![])));

    let body = serde_json::to_string(&payload).unwrap();

    debug!("HTTP POST URL: {}", url);
    debug!("HTTP POST body: {:?}", body);

    let mut builder = client.post(&url);
    builder = builder.headers(headers);
    builder = builder.body(&body[..]);
    builder.send()
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate uuid;
#[cfg(feature = "slog")]
#[macro_use]
extern crate slog;

use test::Bencher;
use uuid::Uuid;
#[cfg(feature = "slog")]
use slog::Drain;

#[bench]
fn bench_parse(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("");
        let _ = Uuid::parse_str("!");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4");
        let _ = Uuid::parse_str("01020304-1112-2122-3132-41424344");
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c88");
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0cg8");
        let _ = Uuid::parse_str("67e5504410b1426%9247bb680e5fe0c8");

        // Valid
        let _ = Uuid::parse_str("00000000000000000000000000000000");
        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4");
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8");
        let _ = Uuid::parse_str("01020304-1112-2122-3132-414243444546");
        let _ = Uuid::parse_str("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8");

        // Nil
        let _ = Uuid::parse_str("00000000000000000000000000000000");
        let _ = Uuid::parse_str("00000000-0000-0000-0000-000000000000");

        // Test error reporting
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c");
        let _ = Uuid::parse_str("67e550X410b1426f9247bb680e5fe0cd");
        let _ = Uuid::parse_str("67e550-4105b1426f9247bb680e5fe0c");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4");
    });
}

#[bench]
fn bench_parse_invalid_len(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4");
    })
}

#[bench]
fn bench_parse_invalid_character(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4");
    })
}

#[bench]
fn bench_parse_invalid_group_len(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("01020304-1112-2122-3132-41424344");
    });
}

#[bench]
fn bench_parse_invalid_groups(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4");
    });
}

#[bench]
fn bench_valid_hyphenated(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
    });
}

#[bench]
fn bench_valid_short(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8");
    });
}

#[cfg(feature = "slog")]
#[bench]
fn bench_log_discard_kv(b: &mut Bencher) {
    let root = slog::Logger::root(slog::Discard.fuse(), o!());
    let u1 = Uuid::parse_str("F9168C5E-CEB2-4FAB-B6BF-329BF39FA1E4").unwrap();
    b.iter(|| {
        crit!(root, "test"; "u1" => u1);
    });
}
<commit_msg>Update parse_str.rs<commit_after>#![feature(test)]
extern crate test;
extern crate uuid;
#[cfg(feature = "slog")]
#[macro_use]
extern crate slog;
use test::Bencher;
use uuid::Uuid;
#[cfg(feature = "slog")]
use slog::Drain;

#[bench]
fn bench_parse(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("");
        let _ = Uuid::parse_str("!");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E45");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faaXB6BFF329BF39FA1E4");
        let _ = Uuid::parse_str("F9168C5E-CEB-24fa-eB6BFF32-BF39FA1E4");
        let _ = Uuid::parse_str("01020304-1112-2122-3132-41424344");
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c88");
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0cg8");
        let _ = Uuid::parse_str("67e5504410b1426%9247bb680e5fe0c8");

        // Valid
        let _ = Uuid::parse_str("00000000000000000000000000000000");
        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4");
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8");
        let _ = Uuid::parse_str("01020304-1112-2122-3132-414243444546");
        let _ = Uuid::parse_str("urn:uuid:67e55044-10b1-426f-9247-bb680e5fe0c8");

        // Nil
        let _ = Uuid::parse_str("00000000000000000000000000000000");
        let _ = Uuid::parse_str("00000000-0000-0000-0000-000000000000");

        // Test error reporting
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c");
        let _ = Uuid::parse_str("67e550X410b1426f9247bb680e5fe0cd");
        let _ = Uuid::parse_str("67e550-4105b1426f9247bb680e5fe0c");
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BF1-02BF39FA1E4");
    });
}

#[bench]
fn bench_parse_invalid_len(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BBF-329BF39FA1E4");
    })
}

#[bench]
fn bench_parse_invalid_character(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-BGBF-329BF39FA1E4");
    })
}

#[bench]
fn bench_parse_invalid_group_len(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("01020304-1112-2122-3132-41424344");
    });
}

#[bench]
fn bench_parse_invalid_groups(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("F9168C5E-CEB2-4faa-B6BFF329BF39FA1E4");
    });
}

#[bench]
fn bench_valid_hyphenated(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8");
    });
}

#[bench]
fn bench_valid_short(b: &mut Bencher) {
    b.iter(|| {
        let _ = Uuid::parse_str("67e5504410b1426f9247bb680e5fe0c8");
    });
}

#[cfg(feature = "slog")]
#[bench]
fn bench_log_discard_kv(b: &mut Bencher) {
    let root = slog::Logger::root(slog::Discard.fuse(), o!());
    let u1 = Uuid::parse_str("F9168C5E-CEB2-4FAB-B6BF-329BF39FA1E4").unwrap();
    b.iter(|| {
        crit!(root, "test"; "u1" => u1);
    });
}
<|endoftext|>


<commit_before>//! Simple crate that parses athenahealth Watertown's Nourish menu, and posts it to a slack channel
//! of choice.

#![warn(missing_docs)]

#[macro_use]
extern crate lazy_static;

extern crate chrono;
extern crate hyper;
extern crate inflector;
extern crate linked_hash_map;
extern crate regex;
extern crate select;
extern crate url;

use std::cmp;
use std::fmt::Write;

use chrono::{Datelike, Duration, NaiveDate};
use inflector::Inflector;
use linked_hash_map::LinkedHashMap;
use regex::Regex;
use select::document::Document;
use select::predicate::{Attr, Name};
use url::Url;

lazy_static! {
    /// This Regex matches nutritional information, to filter it out from the menu output.
    static ref NUTRITION_RE: Regex = Regex::new(r"Cal.*Fat.*Sat.*Sod.*Carbs.*Fib.*Pro").unwrap();

    /// This Regex matches the price information, to filter it out from the menu output.
    static ref PRICE_RE: Regex = Regex::new(r"^\d+\.\d+( / \d+\.\d+)?$").unwrap();
}

/// The Nourish menu for a given date.
#[derive(Debug, Clone, Default)]
pub struct Menu(LinkedHashMap<String, Vec<String>>);

impl Menu {
    /// Renders the menu as a Markdown string.
    pub fn to_markdown(&self) -> String {
        let mut output = String::default();

        for (ref category, ref items) in &self.0 {
            writeln!(output, "*{}*\n", category).unwrap();

            for item in items.iter() {
                writeln!(output, "• {}", item).unwrap();
            }

            writeln!(output, "").unwrap();
        }

        writeln!(output,
                 "> Made with :cnr: by @anrussell. Source available at \
                  https://github.com/euclio/nourishbot.")
            .unwrap();

        output
    }
}

/// Returns the URL pointing to the Nourish menu for a given day. On the weekends, returns Friday's
/// menu.
pub fn url_for_date(date: &NaiveDate) -> Url {
    let days_from_monday = cmp::min(date.weekday().num_days_from_monday(), 4);
    let monday = *date - Duration::days(date.weekday().num_days_from_monday() as i64);

    Url::parse(&format!("http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                       nsf/weeklyMenuLaunch/8DURSE~{}/$file/day{}.htm",
                        monday.format("%m-%d-%Y"),
                        days_from_monday + 1))
        .unwrap()
}

/// Parses the menu information out of HTML.
pub fn parse_menu(html: &str) -> Menu {
    let document = Document::from(html);

    let mut menu: LinkedHashMap<String, Vec<String>> = LinkedHashMap::new();

    let mut last_category = None;

    let menu_node = document.find(Attr("id", "center_text")).first().unwrap();
    for node in menu_node.find(Name("div")).iter() {
        let text = node.text().trim().to_owned();

        if NUTRITION_RE.is_match(&text) || PRICE_RE.is_match(&text) {
            continue;
        }

        if let Some("font-weight:bold;") = node.attr("style") {
            let category = text.to_lower_case().to_title_case();

            // Filter out breakfast.
            if category != "Breakfast Special" {
                last_category = Some(text.to_lower_case().to_title_case());
            }
        } else {
            if let Some(ref category) = last_category {
                if menu.contains_key(category) {
                    let mut entries = menu.get_mut(category).unwrap();
                    entries.push(text);
                } else {
                    menu.insert(category.to_owned(), vec![text]);
                }

            }
        }
    }

    Menu(menu)
}

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

    use chrono::NaiveDate;

    #[test]
    fn monday() {
        let expected_url = "http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                            nsf/weeklyMenuLaunch/8DURSE~04-18-2016/$file/day1.htm";

        assert_eq!(expected_url,
                   &url_for_date(&NaiveDate::from_ymd(2016, 4, 18)).serialize());
    }

    #[test]
    fn saturday() {
        let expected_url = "http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                            nsf/weeklyMenuLaunch/8DURSE~04-11-2016/$file/day5.htm";

        assert_eq!(expected_url,
                   &url_for_date(&NaiveDate::from_ymd(2016, 4, 16)).serialize());

    }
}
<commit_msg>Display a message when there is no menu<commit_after>//! Simple crate that parses athenahealth Watertown's Nourish menu, and posts it to a slack channel
//! of choice.

#![warn(missing_docs)]

#[macro_use]
extern crate lazy_static;

extern crate chrono;
extern crate hyper;
extern crate inflector;
extern crate linked_hash_map;
extern crate regex;
extern crate select;
extern crate url;

use std::cmp;
use std::fmt::Write;

use chrono::{Datelike, Duration, NaiveDate};
use inflector::Inflector;
use linked_hash_map::LinkedHashMap;
use regex::Regex;
use select::document::Document;
use select::predicate::{Attr, Name};
use url::Url;

lazy_static! {
    /// This Regex matches nutritional information, to filter it out from the menu output.
    static ref NUTRITION_RE: Regex = Regex::new(r"Cal.*Fat.*Sat.*Sod.*Carbs.*Fib.*Pro").unwrap();

    /// This Regex matches the price information, to filter it out from the menu output.
    static ref PRICE_RE: Regex = Regex::new(r"^\d+\.\d+( / \d+\.\d+)?$").unwrap();
}

/// The Nourish menu for a given date.
#[derive(Debug, Clone, Default)]
pub struct Menu(LinkedHashMap<String, Vec<String>>);

impl Menu {
    /// Renders the menu as a Markdown string.
    pub fn to_markdown(&self) -> String {
        let mut output = String::default();

        for (ref category, ref items) in &self.0 {
            writeln!(output, "*{}*\n", category).unwrap();

            for item in items.iter() {
                writeln!(output, "• {}", item).unwrap();
            }

            writeln!(output, "").unwrap();
        }

        if (output.is_empty()) {
            writeln!(output,
                     "There is no menu today ¯\_(ツ)_/¯");
        }

        writeln!(output,
                 "> Made with :cnr: by @anrussell. Source available at \
                  https://github.com/euclio/nourishbot.")
            .unwrap();

        output
    }
}

/// Returns the URL pointing to the Nourish menu for a given day. On the weekends, returns Friday's
/// menu.
pub fn url_for_date(date: &NaiveDate) -> Url {
    let days_from_monday = cmp::min(date.weekday().num_days_from_monday(), 4);
    let monday = *date - Duration::days(date.weekday().num_days_from_monday() as i64);

    Url::parse(&format!("http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                       nsf/weeklyMenuLaunch/8DURSE~{}/$file/day{}.htm",
                        monday.format("%m-%d-%Y"),
                        days_from_monday + 1))
        .unwrap()
}

/// Parses the menu information out of HTML.
pub fn parse_menu(html: &str) -> Menu {
    let document = Document::from(html);

    let mut menu: LinkedHashMap<String, Vec<String>> = LinkedHashMap::new();

    let mut last_category = None;

    let menu_node = document.find(Attr("id", "center_text")).first().unwrap();
    for node in menu_node.find(Name("div")).iter() {
        let text = node.text().trim().to_owned();

        if NUTRITION_RE.is_match(&text) || PRICE_RE.is_match(&text) {
            continue;
        }

        if let Some("font-weight:bold;") = node.attr("style") {
            let category = text.to_lower_case().to_title_case();

            // Filter out breakfast.
            if category != "Breakfast Special" {
                last_category = Some(text.to_lower_case().to_title_case());
            }
        } else {
            if let Some(ref category) = last_category {
                if menu.contains_key(category) {
                    let mut entries = menu.get_mut(category).unwrap();
                    entries.push(text);
                } else {
                    menu.insert(category.to_owned(), vec![text]);
                }

            }
        }
    }

    Menu(menu)
}

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

    use chrono::NaiveDate;

    #[test]
    fn monday() {
        let expected_url = "http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                            nsf/weeklyMenuLaunch/8DURSE~04-18-2016/$file/day1.htm";

        assert_eq!(expected_url,
                   &url_for_date(&NaiveDate::from_ymd(2016, 4, 18)).serialize());
    }

    #[test]
    fn saturday() {
        let expected_url = "http://dining.guckenheimer.com/clients/athenahealth/fss/fss.\
                            nsf/weeklyMenuLaunch/8DURSE~04-11-2016/$file/day5.htm";

        assert_eq!(expected_url,
                   &url_for_date(&NaiveDate::from_ymd(2016, 4, 16)).serialize());

    }
}
<|endoftext|>


<commit_before>extern crate libc;
#[cfg(feature = "v5-20")]
use libc::c_void;
use libc::{c_char, c_int, size_t};

// `libmagic` API as in "magic.h"

// https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
#[repr(C)]
pub struct Magic {
    _data: [u8; 0],
    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}

pub const MAGIC_NONE: c_int = 0x000_0000;
pub const MAGIC_DEBUG: c_int = 0x000_0001;
pub const MAGIC_SYMLINK: c_int = 0x000_0002;
pub const MAGIC_COMPRESS: c_int = 0x000_0004;
pub const MAGIC_DEVICES: c_int = 0x000_0008;
pub const MAGIC_MIME_TYPE: c_int = 0x000_0010;
pub const MAGIC_CONTINUE: c_int = 0x000_0020;
pub const MAGIC_CHECK: c_int = 0x000_0040;
pub const MAGIC_PRESERVE_ATIME: c_int = 0x000_0080;
pub const MAGIC_RAW: c_int = 0x000_0100;
pub const MAGIC_ERROR: c_int = 0x000_0200;
pub const MAGIC_MIME_ENCODING: c_int = 0x000_0400;
pub const MAGIC_MIME: c_int = MAGIC_MIME_TYPE | MAGIC_MIME_ENCODING;
pub const MAGIC_APPLE: c_int = 0x00_0800;
#[cfg(feature = "v5-23")]
pub const MAGIC_EXTENSION: c_int = 0x100_0000;
#[cfg(feature = "v5-23")]
pub const MAGIC_COMPRESS_TRANSP: c_int = 0x200_0000;
#[cfg(feature = "v5-23")]
pub const MAGIC_NODESC: c_int = MAGIC_EXTENSION | MAGIC_MIME | MAGIC_APPLE;

pub const MAGIC_NO_CHECK_COMPRESS: c_int = 0x000_1000;
pub const MAGIC_NO_CHECK_TAR: c_int = 0x000_2000;
pub const MAGIC_NO_CHECK_SOFT: c_int = 0x000_4000;
pub const MAGIC_NO_CHECK_APPTYPE: c_int = 0x000_8000;
pub const MAGIC_NO_CHECK_ELF: c_int = 0x001_0000;
pub const MAGIC_NO_CHECK_TEXT: c_int = 0x002_0000;
pub const MAGIC_NO_CHECK_CDF: c_int = 0x004_0000;
#[cfg(feature = "v5-38")]
pub const MAGIC_NO_CHECK_CSV: c_int = 0x008_0000;
pub const MAGIC_NO_CHECK_TOKENS: c_int = 0x010_0000;
pub const MAGIC_NO_CHECK_ENCODING: c_int = 0x020_0000;
#[cfg(feature = "v5-35")]
pub const MAGIC_NO_CHECK_JSON: c_int = 0x040_0000;

#[cfg(all(feature = "v5-05", not(feature = "v5-10")))]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = 0x3f_b000;
#[cfg(all(feature = "v5-10", not(feature = "v5-35")))]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
MAGIC_NO_CHECK_TAR      |
// MAGIC_NO_CHECK_SOFT  |
MAGIC_NO_CHECK_APPTYPE  |
MAGIC_NO_CHECK_ELF      |
MAGIC_NO_CHECK_TEXT     |
MAGIC_NO_CHECK_CDF      |
MAGIC_NO_CHECK_TOKENS   |
MAGIC_NO_CHECK_ENCODING;
#[cfg(all(feature = "v5-35", not(feature = "v5-38")))]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
MAGIC_NO_CHECK_TAR      |
// MAGIC_NO_CHECK_SOFT  |
MAGIC_NO_CHECK_APPTYPE  |
MAGIC_NO_CHECK_ELF      |
MAGIC_NO_CHECK_TEXT     |
MAGIC_NO_CHECK_CDF      |
MAGIC_NO_CHECK_TOKENS   |
MAGIC_NO_CHECK_ENCODING |
MAGIC_NO_CHECK_JSON;
#[cfg(feature = "v5-38")]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
MAGIC_NO_CHECK_TAR      |
// MAGIC_NO_CHECK_SOFT  |
MAGIC_NO_CHECK_APPTYPE  |
MAGIC_NO_CHECK_ELF      |
MAGIC_NO_CHECK_TEXT     |
MAGIC_NO_CHECK_CSV      |
MAGIC_NO_CHECK_CDF      |
MAGIC_NO_CHECK_TOKENS   |
MAGIC_NO_CHECK_ENCODING |
MAGIC_NO_CHECK_JSON;

#[deprecated]
pub const MAGIC_NO_CHECK_ASCII: c_int = MAGIC_NO_CHECK_TEXT;

#[deprecated]
pub const MAGIC_NO_CHECK_FORTRAN: c_int = 0x00_0000;
#[deprecated]
pub const MAGIC_NO_CHECK_TROFF: c_int = 0x00_0000;

// TODO: MAGIC_VERSION string

// TODO: MAGIC_SNPRINTB bytes

#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_INDIR_MAX: c_int = 0;
#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_NAME_MAX: c_int = 1;
#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_ELF_PHNUM_MAX: c_int = 2;
#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_ELF_SHNUM_MAX: c_int = 3;
#[cfg(feature = "v5-22")]
pub const MAGIC_PARAM_ELF_NOTES_MAX: c_int = 4;
#[cfg(feature = "v5-25")]
pub const MAGIC_PARAM_REGEX_MAX: c_int = 5;
#[cfg(feature = "v5-27")]
pub const MAGIC_PARAM_BYTES_MAX: c_int = 6;
#[cfg(feature = "v5-40")]
pub const MAGIC_PARAM_ENCODING_MAX: c_int = 7;

// NOTE: the following are from `file.h`, but part of `magic.h` API
#[cfg(feature = "v5-04")]
pub const FILE_LOAD: c_int = 0;
#[cfg(feature = "v5-04")]
pub const FILE_CHECK: c_int = 1;
#[cfg(feature = "v5-04")]
pub const FILE_COMPILE: c_int = 2;
#[cfg(feature = "v5-05")]
pub const FILE_LIST: c_int = 3;

extern "C" {
    pub fn magic_open(flags: c_int) -> *const Magic;
    pub fn magic_close(cookie: *const Magic);

    #[cfg(feature = "v5-04")]
    pub fn magic_getpath(magicfile: *const c_char, action: c_int) -> *const c_char;
    pub fn magic_file(cookie: *const Magic, filename: *const c_char) -> *const c_char;
    pub fn magic_descriptor(cookie: *const Magic, fd: c_int) -> *const c_char;
    pub fn magic_buffer(cookie: *const Magic, buffer: *const u8, length: size_t) -> *const c_char;

    pub fn magic_error(cookie: *const Magic) -> *const c_char;
    #[cfg(feature = "v5-32")]
    pub fn magic_getflags(cookie: *const Magic) -> c_int;
    #[must_use]
    pub fn magic_setflags(cookie: *const Magic, flags: c_int) -> c_int;

    #[cfg(feature = "v5-13")]
    pub fn magic_version() -> c_int;
    #[must_use]
    pub fn magic_load(cookie: *const Magic, filename: *const c_char) -> c_int;
    #[cfg(feature = "v5-20")]
    #[must_use]
    pub fn magic_load_buffers(
        cookie: *const Magic,
        buffers: *const *const c_void,
        sizes: *const size_t,
        nbuffers: size_t,
    ) -> c_int;

    #[must_use]
    pub fn magic_compile(cookie: *const Magic, filename: *const c_char) -> c_int;
    #[must_use]
    pub fn magic_check(cookie: *const Magic, filename: *const c_char) -> c_int;
    #[cfg(feature = "v5-05")]
    #[must_use]
    pub fn magic_list(cookie: *const Magic, filename: *const c_char) -> c_int;
    pub fn magic_errno(cookie: *const Magic) -> *const c_int;

    #[cfg(feature = "v5-21")]
    #[must_use]
    pub fn magic_setparam(cookie: *const Magic, param: c_int, value: *const c_void) -> c_int;
    #[cfg(feature = "v5-21")]
    #[must_use]
    pub fn magic_getparam(cookie: *const Magic, param: c_int, value: *mut c_void) -> c_int;
}

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

    // Those tests are mostly just sanity checks to see if linkage works,
    // they are NOT testing `libmagic` API/implementation

    #[test]
    fn test_magic_open() {
        unsafe {
            magic_open(MAGIC_NONE);
        }
    }

    #[test]
    fn test_magic_close() {
        unsafe {
            magic_close(std::ptr::null());
        }
    }

    #[cfg(feature = "v5-04")]
    #[test]
    fn test_magic_getpath() {
        unsafe {
            magic_getpath(std::ptr::null(), FILE_CHECK);
        }
    }

    #[test]
    fn test_magic_file() {
        unsafe {
            magic_file(std::ptr::null(), std::ptr::null());
        }
    }

    #[test]
    fn test_magic_descriptor() {
        unsafe {
            magic_descriptor(std::ptr::null(), -1);
        }
    }

    #[test]
    fn test_magic_buffer() {
        unsafe {
            magic_buffer(std::ptr::null(), std::ptr::null(), 0);
        }
    }

    #[test]
    fn test_magic_error() {
        unsafe {
            magic_error(std::ptr::null());
        }
    }

    #[cfg(feature = "v5-32")]
    #[test]
    fn test_magic_getflags() {
        unsafe {
            magic_getflags(std::ptr::null());
        }
    }

    #[test]
    fn test_magic_setflags() {
        unsafe {
            let _ = magic_setflags(std::ptr::null(), MAGIC_NONE);
        }
    }

    #[cfg(feature = "v5-13")]
    #[test]
    fn test_magic_version() {
        unsafe {
            magic_version();
        }
    }

    #[test]
    fn test_magic_load() {
        unsafe {
            let _ = magic_load(std::ptr::null(), std::ptr::null());
        }
    }

    #[cfg(feature = "v5-20")]
    #[test]
    fn test_magic_load_buffers() {
        unsafe {
            let _ = magic_load_buffers(std::ptr::null(), std::ptr::null(), std::ptr::null(), 0);
        }
    }

    #[test]
    fn test_magic_compile() {
        unsafe {
            let _ = magic_compile(std::ptr::null(), std::ptr::null());
        }
    }

    #[test]
    fn test_magic_check() {
        unsafe {
            let _ = magic_check(std::ptr::null(), std::ptr::null());
        }
    }

    #[cfg(feature = "v5-05")]
    #[test]
    fn test_magic_list() {
        unsafe {
            let _ = magic_list(std::ptr::null(), std::ptr::null());
        }
    }

    #[test]
    fn test_magic_errno() {
        unsafe {
            magic_errno(std::ptr::null());
        }
    }

    #[cfg(feature = "v5-21")]
    #[test]
    fn test_magic_setparam() {
        unsafe {
            let _ = magic_setparam(std::ptr::null(), MAGIC_PARAM_INDIR_MAX, std::ptr::null());
        }
    }

    #[cfg(feature = "v5-21")]
    #[test]
    fn test_magic_getparam() {
        unsafe {
            let _ = magic_getparam(
                std::ptr::null(),
                MAGIC_PARAM_INDIR_MAX,
                std::ptr::null_mut(),
            );
        }
    }
}
<commit_msg>Fix mutable pointers<commit_after>extern crate libc;
#[cfg(feature = "v5-20")]
use libc::c_void;
use libc::{c_char, c_int, size_t};

// `libmagic` API as in "magic.h"

#[allow(non_camel_case_types)]
// https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
#[repr(C)]
pub struct magic_set {
    _data: [u8; 0],
    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}

#[allow(non_camel_case_types)]
pub type magic_t = *mut magic_set;

pub const MAGIC_NONE: c_int = 0x000_0000;
pub const MAGIC_DEBUG: c_int = 0x000_0001;
pub const MAGIC_SYMLINK: c_int = 0x000_0002;
pub const MAGIC_COMPRESS: c_int = 0x000_0004;
pub const MAGIC_DEVICES: c_int = 0x000_0008;
pub const MAGIC_MIME_TYPE: c_int = 0x000_0010;
pub const MAGIC_CONTINUE: c_int = 0x000_0020;
pub const MAGIC_CHECK: c_int = 0x000_0040;
pub const MAGIC_PRESERVE_ATIME: c_int = 0x000_0080;
pub const MAGIC_RAW: c_int = 0x000_0100;
pub const MAGIC_ERROR: c_int = 0x000_0200;
pub const MAGIC_MIME_ENCODING: c_int = 0x000_0400;
pub const MAGIC_MIME: c_int = MAGIC_MIME_TYPE | MAGIC_MIME_ENCODING;
pub const MAGIC_APPLE: c_int = 0x00_0800;
#[cfg(feature = "v5-23")]
pub const MAGIC_EXTENSION: c_int = 0x100_0000;
#[cfg(feature = "v5-23")]
pub const MAGIC_COMPRESS_TRANSP: c_int = 0x200_0000;
#[cfg(feature = "v5-23")]
pub const MAGIC_NODESC: c_int = MAGIC_EXTENSION | MAGIC_MIME | MAGIC_APPLE;

pub const MAGIC_NO_CHECK_COMPRESS: c_int = 0x000_1000;
pub const MAGIC_NO_CHECK_TAR: c_int = 0x000_2000;
pub const MAGIC_NO_CHECK_SOFT: c_int = 0x000_4000;
pub const MAGIC_NO_CHECK_APPTYPE: c_int = 0x000_8000;
pub const MAGIC_NO_CHECK_ELF: c_int = 0x001_0000;
pub const MAGIC_NO_CHECK_TEXT: c_int = 0x002_0000;
pub const MAGIC_NO_CHECK_CDF: c_int = 0x004_0000;
#[cfg(feature = "v5-38")]
pub const MAGIC_NO_CHECK_CSV: c_int = 0x008_0000;
pub const MAGIC_NO_CHECK_TOKENS: c_int = 0x010_0000;
pub const MAGIC_NO_CHECK_ENCODING: c_int = 0x020_0000;
#[cfg(feature = "v5-35")]
pub const MAGIC_NO_CHECK_JSON: c_int = 0x040_0000;

#[cfg(all(feature = "v5-05", not(feature = "v5-10")))]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = 0x3f_b000;
#[cfg(all(feature = "v5-10", not(feature = "v5-35")))]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
MAGIC_NO_CHECK_TAR      |
// MAGIC_NO_CHECK_SOFT  |
MAGIC_NO_CHECK_APPTYPE  |
MAGIC_NO_CHECK_ELF      |
MAGIC_NO_CHECK_TEXT     |
MAGIC_NO_CHECK_CDF      |
MAGIC_NO_CHECK_TOKENS   |
MAGIC_NO_CHECK_ENCODING;
#[cfg(all(feature = "v5-35", not(feature = "v5-38")))]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
MAGIC_NO_CHECK_TAR      |
// MAGIC_NO_CHECK_SOFT  |
MAGIC_NO_CHECK_APPTYPE  |
MAGIC_NO_CHECK_ELF      |
MAGIC_NO_CHECK_TEXT     |
MAGIC_NO_CHECK_CDF      |
MAGIC_NO_CHECK_TOKENS   |
MAGIC_NO_CHECK_ENCODING |
MAGIC_NO_CHECK_JSON;
#[cfg(feature = "v5-38")]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
MAGIC_NO_CHECK_TAR      |
// MAGIC_NO_CHECK_SOFT  |
MAGIC_NO_CHECK_APPTYPE  |
MAGIC_NO_CHECK_ELF      |
MAGIC_NO_CHECK_TEXT     |
MAGIC_NO_CHECK_CSV      |
MAGIC_NO_CHECK_CDF      |
MAGIC_NO_CHECK_TOKENS   |
MAGIC_NO_CHECK_ENCODING |
MAGIC_NO_CHECK_JSON;

#[deprecated]
pub const MAGIC_NO_CHECK_ASCII: c_int = MAGIC_NO_CHECK_TEXT;

#[deprecated]
pub const MAGIC_NO_CHECK_FORTRAN: c_int = 0x00_0000;
#[deprecated]
pub const MAGIC_NO_CHECK_TROFF: c_int = 0x00_0000;

// TODO: MAGIC_VERSION string

// TODO: MAGIC_SNPRINTB bytes

#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_INDIR_MAX: c_int = 0;
#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_NAME_MAX: c_int = 1;
#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_ELF_PHNUM_MAX: c_int = 2;
#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_ELF_SHNUM_MAX: c_int = 3;
#[cfg(feature = "v5-22")]
pub const MAGIC_PARAM_ELF_NOTES_MAX: c_int = 4;
#[cfg(feature = "v5-25")]
pub const MAGIC_PARAM_REGEX_MAX: c_int = 5;
#[cfg(feature = "v5-27")]
pub const MAGIC_PARAM_BYTES_MAX: c_int = 6;
#[cfg(feature = "v5-40")]
pub const MAGIC_PARAM_ENCODING_MAX: c_int = 7;

// NOTE: the following are from `file.h`, but part of `magic.h` API
#[cfg(feature = "v5-04")]
pub const FILE_LOAD: c_int = 0;
#[cfg(feature = "v5-04")]
pub const FILE_CHECK: c_int = 1;
#[cfg(feature = "v5-04")]
pub const FILE_COMPILE: c_int = 2;
#[cfg(feature = "v5-05")]
pub const FILE_LIST: c_int = 3;

extern "C" {
    pub fn magic_open(flags: c_int) -> magic_t;
    pub fn magic_close(cookie: magic_t);

    #[cfg(feature = "v5-04")]
    pub fn magic_getpath(magicfile: *const c_char, action: c_int) -> *const c_char;
    pub fn magic_file(cookie: magic_t, filename: *const c_char) -> *const c_char;
    pub fn magic_descriptor(cookie: magic_t, fd: c_int) -> *const c_char;
    pub fn magic_buffer(cookie: magic_t, buffer: *const u8, length: size_t) -> *const c_char;

    pub fn magic_error(cookie: magic_t) -> *const c_char;
    #[cfg(feature = "v5-32")]
    pub fn magic_getflags(cookie: magic_t) -> c_int;
    #[must_use]
    pub fn magic_setflags(cookie: magic_t, flags: c_int) -> c_int;

    #[cfg(feature = "v5-13")]
    pub fn magic_version() -> c_int;
    #[must_use]
    pub fn magic_load(cookie: magic_t, filename: *const c_char) -> c_int;
    #[cfg(feature = "v5-20")]
    #[must_use]
    pub fn magic_load_buffers(
        cookie: magic_t,
        buffers: *mut *mut c_void,
        sizes: *mut size_t,
        nbuffers: size_t,
    ) -> c_int;

    #[must_use]
    pub fn magic_compile(cookie: magic_t, filename: *const c_char) -> c_int;
    #[must_use]
    pub fn magic_check(cookie: magic_t, filename: *const c_char) -> c_int;
    #[cfg(feature = "v5-05")]
    #[must_use]
    pub fn magic_list(cookie: magic_t, filename: *const c_char) -> c_int;
    pub fn magic_errno(cookie: magic_t) -> *const c_int;

    #[cfg(feature = "v5-21")]
    #[must_use]
    pub fn magic_setparam(cookie: magic_t, param: c_int, value: *const c_void) -> c_int;
    #[cfg(feature = "v5-21")]
    #[must_use]
    pub fn magic_getparam(cookie: magic_t, param: c_int, value: *mut c_void) -> c_int;
}

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

    // Those tests are mostly just sanity checks to see if linkage works,
    // they are NOT testing `libmagic` API/implementation

    #[test]
    fn test_magic_open() {
        unsafe {
            magic_open(MAGIC_NONE);
        }
    }

    #[test]
    fn test_magic_close() {
        unsafe {
            magic_close(std::ptr::null_mut());
        }
    }

    #[cfg(feature = "v5-04")]
    #[test]
    fn test_magic_getpath() {
        unsafe {
            magic_getpath(std::ptr::null(), FILE_CHECK);
        }
    }

    #[test]
    fn test_magic_file() {
        unsafe {
            magic_file(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[test]
    fn test_magic_descriptor() {
        unsafe {
            magic_descriptor(std::ptr::null_mut(), -1);
        }
    }

    #[test]
    fn test_magic_buffer() {
        unsafe {
            magic_buffer(std::ptr::null_mut(), std::ptr::null(), 0);
        }
    }

    #[test]
    fn test_magic_error() {
        unsafe {
            magic_error(std::ptr::null_mut());
        }
    }

    #[cfg(feature = "v5-32")]
    #[test]
    fn test_magic_getflags() {
        unsafe {
            magic_getflags(std::ptr::null_mut());
        }
    }

    #[test]
    fn test_magic_setflags() {
        unsafe {
            let _ = magic_setflags(std::ptr::null_mut(), MAGIC_NONE);
        }
    }

    #[cfg(feature = "v5-13")]
    #[test]
    fn test_magic_version() {
        unsafe {
            magic_version();
        }
    }

    #[test]
    fn test_magic_load() {
        unsafe {
            let _ = magic_load(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[cfg(feature = "v5-20")]
    #[test]
    fn test_magic_load_buffers() {
        unsafe {
            let _ = magic_load_buffers(
                std::ptr::null_mut(),
                std::ptr::null_mut(),
                std::ptr::null_mut(),
                0,
            );
        }
    }

    #[test]
    fn test_magic_compile() {
        unsafe {
            let _ = magic_compile(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[test]
    fn test_magic_check() {
        unsafe {
            let _ = magic_check(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[cfg(feature = "v5-05")]
    #[test]
    fn test_magic_list() {
        unsafe {
            let _ = magic_list(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[test]
    fn test_magic_errno() {
        unsafe {
            magic_errno(std::ptr::null_mut());
        }
    }

    #[cfg(feature = "v5-21")]
    #[test]
    fn test_magic_setparam() {
        unsafe {
            let _ = magic_setparam(
                std::ptr::null_mut(),
                MAGIC_PARAM_INDIR_MAX,
                std::ptr::null(),
            );
        }
    }

    #[cfg(feature = "v5-21")]
    #[test]
    fn test_magic_getparam() {
        unsafe {
            let _ = magic_getparam(
                std::ptr::null_mut(),
                MAGIC_PARAM_INDIR_MAX,
                std::ptr::null_mut(),
            );
        }
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! A simple and type agnostic quaternion math library designed for reexporting

extern crate vecmath;

use vecmath::Vector3;
use vecmath::traits::Float;

/// Quaternion type alias.
pub type Quaternion<T> = (T, [T; 3]);

/// Constructs identity quaternion.
#[inline(always)]
pub fn id<T>() -> Quaternion<T>
    where T: Float
{
    let one = T::one();
    let zero = T::zero();
    (one, [zero, zero, zero])
}

/// Adds two quaternions.
#[inline(always)]
pub fn add<T>(
    a: Quaternion<T>,
    b: Quaternion<T>
) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_add as add;
    (a.0 + b.0, add(a.1, b.1))
}

/// Multiplies two quaternions.
#[inline(always)]
pub fn mul<T>(
    a: Quaternion<T>,
    b: Quaternion<T>
) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_cross as cross;
    use vecmath::vec3_add as add;
    use vecmath::vec3_dot as dot;
    use vecmath::vec3_scale as scale;

    (
        a.0 * b.0 - dot(a.1, b.1),
        add(
            add(scale(b.1, a.0), scale(a.1, b.0)),
            cross(a.1, b.1)
        )
    )
}

/// Takes the quaternion conjugate.
#[inline(always)]
pub fn conj<T>(a: Quaternion<T>) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_neg as neg;

    (a.0, neg(a.1))
}

/// Computes the square length of a quaternion.
#[inline(always)]
pub fn square_len<T>(q: Quaternion<T>) -> T
    where T: Float
{
    use vecmath::vec3_square_len as square_len;
    q.0 * q.0 + square_len(q.1)
}

/// Computes the length of a quaternion.
#[inline(always)]
pub fn len<T>(q: Quaternion<T>) -> T
    where T: Float
{
    square_len(q).sqrt()
}

/// Rotate the given vector using the given quaternion
#[inline(always)]
pub fn rotate_vector<T>(q: Quaternion<T>, v: Vector3<T>) -> Vector3<T>
    where T: Float
{
    let zero = T::zero();
    let v_as_q : Quaternion<T> = (zero, v);
    let q_conj = conj(q);
    mul(mul(q, v_as_q), q_conj).1
}

/// Construct a quaternion representing the given euler angle rotations (in radians)
#[inline(always)]
pub fn euler_angles<T>(x: T, y: T, z: T) -> Quaternion<T>
    where T: Float
{
    let two: T = T::one() + T::one();

    let half_x = x / two;
    let half_y = y / two;
    let half_z = z / two;

    let cos_x_2 = half_x.cos();
    let cos_y_2 = half_y.cos();
    let cos_z_2 = half_z.cos();

    let sin_x_2 = half_x.sin();
    let sin_y_2 = half_y.sin();
    let sin_z_2 = half_z.sin();

    (
        cos_x_2 * cos_y_2 * cos_z_2 + sin_x_2 * sin_y_2 * sin_z_2,
        [
            sin_x_2 * cos_y_2 * cos_z_2 + cos_x_2 * sin_y_2 * sin_z_2,
            cos_x_2 * sin_y_2 * cos_z_2 + sin_x_2 * cos_y_2 * sin_z_2,
            cos_x_2 * cos_y_2 * sin_z_2 + sin_x_2 * sin_y_2 * cos_z_2
        ]
    )
}

/// Construct a quaternion for the given angle (in radians)
/// about the given axis.
/// Axis must be a unit vector.
#[inline(always)]
pub fn axis_angle<T>(axis: Vector3<T>, angle: T) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_scale as scale;
    let two: T = T::one() + T::one();
    let half_angle = angle / two;
    (half_angle.cos(), scale(axis, half_angle.sin()))
}

/// Tests
#[cfg(test)]
mod test {
    use super::*;
    use vecmath::Vector3;
    use std::f32::consts::PI;

    /// Fudge factor for float equality checks
    static EPSILON: f32 = 0.000001;

    #[test]
    fn test_axis_angle() {
        use vecmath::vec3_normalized as normalized;
        let axis: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = axis_angle(
            normalized(axis),
            PI
        );

        // Should be a unit quaternion
        assert!((square_len(q) - 1.0).abs() < EPSILON);
    }

    #[test]
    fn test_euler_angle() {
        let q: Quaternion<f32> = euler_angles(PI, PI, PI);
        // Should be a unit quaternion
        assert!((square_len(q) - 1.0).abs() < EPSILON);
    }

    #[test]
    fn test_rotate_vector_axis_angle() {
        let v: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = axis_angle([0.0, 1.0, 0.0], PI);
        let rotated = rotate_vector(q, v);
        assert!((rotated[0] - -1.0).abs() < EPSILON);
        assert!((rotated[1] - 1.0).abs() < EPSILON);
        assert!((rotated[2] - -1.0).abs() < EPSILON);
    }

    #[test]
    fn test_rotate_vector_euler_angle() {
        let v: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = euler_angles(0.0, PI, 0.0);
        let rotated = rotate_vector(q, v);
        assert!((rotated[0] - -1.0).abs() < EPSILON);
        assert!((rotated[1] - 1.0).abs() < EPSILON);
        assert!((rotated[2] - -1.0).abs() < EPSILON);
    }

    /// Rotation on axis parallel to vector direction should have no effect
    #[test]
    fn test_rotate_vector_axis_angle_same_axis() {
        use vecmath::vec3_normalized as normalized;

        let v: Vector3<f32> = [1.0, 1.0, 1.0];
        let arbitrary_angle = 32.12f32;
        let axis: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = axis_angle(
            normalized(axis),
            arbitrary_angle
        );
        let rotated = rotate_vector(q, v);

        assert!((rotated[0] - 1.0).abs() < EPSILON);
        assert!((rotated[1] - 1.0).abs() < EPSILON);
        assert!((rotated[2] - 1.0).abs() < EPSILON);
    }
}
<commit_msg>Added 'scale' to scale a quaternion by a float<commit_after>#![deny(missing_docs)]

//! A simple and type agnostic quaternion math library designed for reexporting

extern crate vecmath;

use vecmath::Vector3;
use vecmath::traits::Float;

/// Quaternion type alias.
pub type Quaternion<T> = (T, [T; 3]);

/// Constructs identity quaternion.
#[inline(always)]
pub fn id<T>() -> Quaternion<T>
    where T: Float
{
    let one = T::one();
    let zero = T::zero();
    (one, [zero, zero, zero])
}

/// Adds two quaternions.
#[inline(always)]
pub fn add<T>(
    a: Quaternion<T>,
    b: Quaternion<T>
) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_add as add;
    (a.0 + b.0, add(a.1, b.1))
}

/// Scales a quaternion (element-wise) by a scalar
#[inline(always)]
pub fn scale<T>(
    q: Quaternion<T>,
    t: T
) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_scale as scale;
    (q.0 * t, scale(q.1, t))
}

/// Multiplies two quaternions.
#[inline(always)]
pub fn mul<T>(
    a: Quaternion<T>,
    b: Quaternion<T>
) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_cross as cross;
    use vecmath::vec3_add as add;
    use vecmath::vec3_dot as dot;
    use vecmath::vec3_scale as scale;

    (
        a.0 * b.0 - dot(a.1, b.1),
        add(
            add(scale(b.1, a.0), scale(a.1, b.0)),
            cross(a.1, b.1)
        )
    )
}

/// Takes the quaternion conjugate.
#[inline(always)]
pub fn conj<T>(a: Quaternion<T>) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_neg as neg;

    (a.0, neg(a.1))
}

/// Computes the square length of a quaternion.
#[inline(always)]
pub fn square_len<T>(q: Quaternion<T>) -> T
    where T: Float
{
    use vecmath::vec3_square_len as square_len;
    q.0 * q.0 + square_len(q.1)
}

/// Computes the length of a quaternion.
#[inline(always)]
pub fn len<T>(q: Quaternion<T>) -> T
    where T: Float
{
    square_len(q).sqrt()
}

/// Rotate the given vector using the given quaternion
#[inline(always)]
pub fn rotate_vector<T>(q: Quaternion<T>, v: Vector3<T>) -> Vector3<T>
    where T: Float
{
    let zero = T::zero();
    let v_as_q : Quaternion<T> = (zero, v);
    let q_conj = conj(q);
    mul(mul(q, v_as_q), q_conj).1
}

/// Construct a quaternion representing the given euler angle rotations (in radians)
#[inline(always)]
pub fn euler_angles<T>(x: T, y: T, z: T) -> Quaternion<T>
    where T: Float
{
    let two: T = T::one() + T::one();

    let half_x = x / two;
    let half_y = y / two;
    let half_z = z / two;

    let cos_x_2 = half_x.cos();
    let cos_y_2 = half_y.cos();
    let cos_z_2 = half_z.cos();

    let sin_x_2 = half_x.sin();
    let sin_y_2 = half_y.sin();
    let sin_z_2 = half_z.sin();

    (
        cos_x_2 * cos_y_2 * cos_z_2 + sin_x_2 * sin_y_2 * sin_z_2,
        [
            sin_x_2 * cos_y_2 * cos_z_2 + cos_x_2 * sin_y_2 * sin_z_2,
            cos_x_2 * sin_y_2 * cos_z_2 + sin_x_2 * cos_y_2 * sin_z_2,
            cos_x_2 * cos_y_2 * sin_z_2 + sin_x_2 * sin_y_2 * cos_z_2
        ]
    )
}

/// Construct a quaternion for the given angle (in radians)
/// about the given axis.
/// Axis must be a unit vector.
#[inline(always)]
pub fn axis_angle<T>(axis: Vector3<T>, angle: T) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_scale as scale;
    let two: T = T::one() + T::one();
    let half_angle = angle / two;
    (half_angle.cos(), scale(axis, half_angle.sin()))
}

/// Tests
#[cfg(test)]
mod test {
    use super::*;
    use vecmath::Vector3;
    use std::f32::consts::PI;

    /// Fudge factor for float equality checks
    static EPSILON: f32 = 0.000001;

    #[test]
    fn test_axis_angle() {
        use vecmath::vec3_normalized as normalized;
        let axis: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = axis_angle(
            normalized(axis),
            PI
        );

        // Should be a unit quaternion
        assert!((square_len(q) - 1.0).abs() < EPSILON);
    }

    #[test]
    fn test_euler_angle() {
        let q: Quaternion<f32> = euler_angles(PI, PI, PI);
        // Should be a unit quaternion
        assert!((square_len(q) - 1.0).abs() < EPSILON);
    }

    #[test]
    fn test_rotate_vector_axis_angle() {
        let v: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = axis_angle([0.0, 1.0, 0.0], PI);
        let rotated = rotate_vector(q, v);
        assert!((rotated[0] - -1.0).abs() < EPSILON);
        assert!((rotated[1] - 1.0).abs() < EPSILON);
        assert!((rotated[2] - -1.0).abs() < EPSILON);
    }

    #[test]
    fn test_rotate_vector_euler_angle() {
        let v: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = euler_angles(0.0, PI, 0.0);
        let rotated = rotate_vector(q, v);
        assert!((rotated[0] - -1.0).abs() < EPSILON);
        assert!((rotated[1] - 1.0).abs() < EPSILON);
        assert!((rotated[2] - -1.0).abs() < EPSILON);
    }

    /// Rotation on axis parallel to vector direction should have no effect
    #[test]
    fn test_rotate_vector_axis_angle_same_axis() {
        use vecmath::vec3_normalized as normalized;

        let v: Vector3<f32> = [1.0, 1.0, 1.0];
        let arbitrary_angle = 32.12f32;
        let axis: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = axis_angle(
            normalized(axis),
            arbitrary_angle
        );
        let rotated = rotate_vector(q, v);

        assert!((rotated[0] - 1.0).abs() < EPSILON);
        assert!((rotated[1] - 1.0).abs() < EPSILON);
        assert!((rotated[2] - 1.0).abs() < EPSILON);
    }
}
<|endoftext|>


<commit_before>//! lzf-rs is a small wrapper around [LibLZF](http://software.schmorp.de/pkg/liblzf.html),
//! a very small data compression library.
//!
//! The compression algorithm is very, very fast, yet still written in portable C.
//!
//! This Rust library is a wrapper around the library from Marc Lehmann.
//!
//! # Basic Operation
//!
//! ```rust,no_run
//! # use lzf;
//! let data = "foobar";
//!
//! let compressed = lzf::compress(data.as_bytes()).unwrap();
//!
//! let decompressed = lzf::decompress(compressed.as_slice(), data.len()).unwrap();
//! ```

#![experimental]

extern crate libc;

use libc::{c_uint,c_void};

extern {
    fn lzf_compress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
    fn lzf_decompress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
}

#[derive(PartialEq, Eq, Clone, Show, Copy)]
pub enum LzfError {
    BufferTooSmall,
    DataCorrupted,
    NoCompressionPossible,
    UnknownError(usize)
}
pub type LzfResult<T> = Result<T, LzfError>;

/// Compress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The buffer is always set to the same size as the input buffer.
/// If that is not enough to hold the lzf-compressed data,
/// an error will be returned.
///
/// Example:
///
/// ```rust
/// let data = "foobar";
/// let compressed = lzf::compress(data.as_bytes());
/// ```
pub fn compress(data: &[u8]) -> LzfResult<Vec<u8>> {
    let data_len = data.len();
    let mut out : Vec<u8> = Vec::with_capacity(data_len);

    let result = unsafe { lzf_compress(data.as_ptr() as *const c_void, data_len as c_uint,
                                       out.as_ptr() as *const c_void, data_len as c_uint) };

    match result {
        0 => Err(LzfError::NoCompressionPossible),
        _ => {
            unsafe { out.set_len(result as usize) };
            Ok(out)
        }
    }
}

/// Decompress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The length of the output buffer can be specified.
/// If the output buffer is not large enough to hold the decompressed data,
/// BufferTooSmall is returned.
/// Otherwise the number of decompressed bytes
/// (i.e. the original length of the data) is returned.
///
/// If an error in the compressed data is detected, DataCorrupted is returned.
///
/// Example:
///
/// ```rust,no_run
/// let data = "[your-compressed-data]";
/// let decompressed = lzf::decompress(data.as_bytes(), 10);
/// ```
pub fn decompress(data: &[u8], out_len: usize) -> LzfResult<Vec<u8>> {
    let mut out : Vec<u8> = Vec::with_capacity(out_len);

    let result = unsafe { lzf_decompress(data.as_ptr() as *const c_void, data.len() as c_uint,
                                         out.as_ptr() as *const c_void, out_len as c_uint) };
    match result {
        0 => {
            match std::os::errno() {
                7  => Err(LzfError::BufferTooSmall),
                22 => Err(LzfError::DataCorrupted),
                e  => Err(LzfError::UnknownError(e))
            }
        },
        _ => {
            unsafe { out.set_len(result as usize) };
            Ok(out)
        }
    }
}

#[test]
fn test_compress_skips_short() {
    match compress("foo".as_bytes()) {
        Ok(_) => panic!("Compression did _something_, with is wrong for 'foo'"),
        Err(err) => assert_eq!(LzfError::NoCompressionPossible, err)
    }
}

#[test]
fn test_compress_lorem() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    match compress(lorem.as_bytes()) {
        Ok(compressed) => {
            assert_eq!(272, compressed.len())
        }
        Err(err) => panic!("Compression failed with error {}", err)
    }
}

#[test]
fn test_compress_decompress_lorem_round() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {}", err)
    };

    match decompress(compressed.as_slice(), lorem.len()) {
        Ok(decompressed) => {
            assert_eq!(lorem.len(), decompressed.len());
            assert_eq!(lorem.as_bytes(), decompressed.as_slice());
        },
        Err(err) => panic!("Decompression failed with error {}", err)
    };
}

#[test]
fn test_decompress_fails_with_short_buffer() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {}", err)
    };

    match decompress(compressed.as_slice(), 10) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::BufferTooSmall, err)
    }
}

#[test]
fn test_decompress_fails_for_corrupted_data() {
    let lorem = "Lorem ipsum dolor sit amet";

    match decompress(lorem.as_bytes(), lorem.len()) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::DataCorrupted, err)
    }
}
<commit_msg>Use Show for displaying the error<commit_after>//! lzf-rs is a small wrapper around [LibLZF](http://software.schmorp.de/pkg/liblzf.html),
//! a very small data compression library.
//!
//! The compression algorithm is very, very fast, yet still written in portable C.
//!
//! This Rust library is a wrapper around the library from Marc Lehmann.
//!
//! # Basic Operation
//!
//! ```rust,no_run
//! # use lzf;
//! let data = "foobar";
//!
//! let compressed = lzf::compress(data.as_bytes()).unwrap();
//!
//! let decompressed = lzf::decompress(compressed.as_slice(), data.len()).unwrap();
//! ```

#![experimental]

extern crate libc;

use libc::{c_uint,c_void};

extern {
    fn lzf_compress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
    fn lzf_decompress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
}

#[derive(PartialEq, Eq, Clone, Show, Copy)]
pub enum LzfError {
    BufferTooSmall,
    DataCorrupted,
    NoCompressionPossible,
    UnknownError(usize)
}
pub type LzfResult<T> = Result<T, LzfError>;

/// Compress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The buffer is always set to the same size as the input buffer.
/// If that is not enough to hold the lzf-compressed data,
/// an error will be returned.
///
/// Example:
///
/// ```rust
/// let data = "foobar";
/// let compressed = lzf::compress(data.as_bytes());
/// ```
pub fn compress(data: &[u8]) -> LzfResult<Vec<u8>> {
    let data_len = data.len();
    let mut out : Vec<u8> = Vec::with_capacity(data_len);

    let result = unsafe { lzf_compress(data.as_ptr() as *const c_void, data_len as c_uint,
                                       out.as_ptr() as *const c_void, data_len as c_uint) };

    match result {
        0 => Err(LzfError::NoCompressionPossible),
        _ => {
            unsafe { out.set_len(result as usize) };
            Ok(out)
        }
    }
}

/// Decompress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The length of the output buffer can be specified.
/// If the output buffer is not large enough to hold the decompressed data,
/// BufferTooSmall is returned.
/// Otherwise the number of decompressed bytes
/// (i.e. the original length of the data) is returned.
///
/// If an error in the compressed data is detected, DataCorrupted is returned.
///
/// Example:
///
/// ```rust,no_run
/// let data = "[your-compressed-data]";
/// let decompressed = lzf::decompress(data.as_bytes(), 10);
/// ```
pub fn decompress(data: &[u8], out_len: usize) -> LzfResult<Vec<u8>> {
    let mut out : Vec<u8> = Vec::with_capacity(out_len);

    let result = unsafe { lzf_decompress(data.as_ptr() as *const c_void, data.len() as c_uint,
                                         out.as_ptr() as *const c_void, out_len as c_uint) };
    match result {
        0 => {
            match std::os::errno() {
                7  => Err(LzfError::BufferTooSmall),
                22 => Err(LzfError::DataCorrupted),
                e  => Err(LzfError::UnknownError(e))
            }
        },
        _ => {
            unsafe { out.set_len(result as usize) };
            Ok(out)
        }
    }
}

#[test]
fn test_compress_skips_short() {
    match compress("foo".as_bytes()) {
        Ok(_) => panic!("Compression did _something_, with is wrong for 'foo'"),
        Err(err) => assert_eq!(LzfError::NoCompressionPossible, err)
    }
}

#[test]
fn test_compress_lorem() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    match compress(lorem.as_bytes()) {
        Ok(compressed) => {
            assert_eq!(272, compressed.len())
        }
        Err(err) => panic!("Compression failed with error {:?}", err)
    }
}

#[test]
fn test_compress_decompress_lorem_round() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {:?}", err)
    };

    match decompress(compressed.as_slice(), lorem.len()) {
        Ok(decompressed) => {
            assert_eq!(lorem.len(), decompressed.len());
            assert_eq!(lorem.as_bytes(), decompressed.as_slice());
        },
        Err(err) => panic!("Decompression failed with error {:?}", err)
    };
}

#[test]
fn test_decompress_fails_with_short_buffer() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {:?}", err)
    };

    match decompress(compressed.as_slice(), 10) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::BufferTooSmall, err)
    }
}

#[test]
fn test_decompress_fails_for_corrupted_data() {
    let lorem = "Lorem ipsum dolor sit amet";

    match decompress(lorem.as_bytes(), lorem.len()) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::DataCorrupted, err)
    }
}
<|endoftext|>


<commit_before>#![feature(core, libc)]
#![deny(missing_docs)]

//! A simple task queue with dependency tracking.

#[macro_use]
extern crate log;
extern crate pulse;
extern crate atom;
extern crate deque;
extern crate rand;
extern crate libc;
extern crate num_cpus;
extern crate bran;
extern crate future_pulse;

mod back;
mod front;
mod task;
mod worker;

pub use self::front::{Frontend, Schedule};
pub use self::task::{task, TaskBuilder};

/// Wait mode for the front-end termination.
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum Wait {
    /// Wait for nothing - terminate immediately.
    None,
    /// Wait for active tasks only, drop the pending.
    Active,
    /// Wait for the whole queue to flush.
    Pending,
}

<commit_msg>core -> fnbox<commit_after>#![feature(libc, fnbox)]
#![deny(missing_docs)]

//! A simple task queue with dependency tracking.

#[macro_use]
extern crate log;
extern crate pulse;
extern crate atom;
extern crate deque;
extern crate rand;
extern crate libc;
extern crate num_cpus;
extern crate bran;
extern crate future_pulse;

mod back;
mod front;
mod task;
mod worker;

pub use self::front::{Frontend, Schedule};
pub use self::task::{task, TaskBuilder};

/// Wait mode for the front-end termination.
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum Wait {
    /// Wait for nothing - terminate immediately.
    None,
    /// Wait for active tasks only, drop the pending.
    Active,
    /// Wait for the whole queue to flush.
    Pending,
}

<|endoftext|>


<commit_before>//! The API Documentation below will help you learn about the various things you can do with this
//! crate.
//!
//! **If this is your first time using Rust or using this crate, read the Guide on
//! [turtle.rs](http://turtle.rs) to learn how to start.**
//!
//! The documentation for the [`Turtle` struct](struct.Turtle.html) contains a listing of all of the
//! various drawing commands that you can use on the Turtles that you create. The [`color`
//! module](color/index.html) and its submodules contain hundreds of predefined color names that you
//! can use to set the pen, background and fill color of a turtle. That module also explains how to
//! use any arbitrary color, including ones that may not be defined in this crate.
//!
//! Note: Call [`turtle::start()`](fn.start.html) if you do not create a turtle with
//! [`Turtle::new()`](struct.Turtle.html#method.new) right at the beginning of your program. Most
//! programs will never need to call this function as it is called for you in
//! [`Turtle::new()`](struct.Turtle.html#method.new).
//!
//! # Random Values
//!
//! See the [`rand` module](rand/index.html) for information about generating random colors, speeds,
//! angles, and more which can be used in your programs to produce some interesting results!
//!
//! # Event Handling
//!
//! The [`Event` enum](event/enum.Event.html) documentation provides information about how you can
//! create an event loop. This allows you to draw things in response to certain events like the
//! mouse moving, keys being pressed, and more.
//!
//! The `Turtle` struct contains a few convenience methods so you can do some common event-related
//! things without creating the entire event loop. For example, use
//! [`wait_for_click()`](struct.Turtle.html#method.wait_for_click) to wait for the user to click
//! anywhere on the screen before proceeding.

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

extern crate piston_window;
extern crate interpolation;
extern crate rand as rand_crate;

mod turtle_window;

mod app;
mod turtle;
mod speed;
mod radians;
mod animation;
mod extensions;
mod renderer;
mod state;
mod query;
mod server;
mod renderer_process;
mod messenger;

pub mod color;
pub mod event;
pub mod rand;

pub use server::start;
pub use turtle::{Turtle, Point, Distance, Angle};
pub use speed::{Speed};
pub use color::{Color};
pub use event::Event;
pub use rand::{random, random_range};
<commit_msg>Making `cargo test` result in a compile error if you don't use it with --features test<commit_after>//! The API Documentation below will help you learn about the various things you can do with this
//! crate.
//!
//! **If this is your first time using Rust or using this crate, read the Guide on
//! [turtle.rs](http://turtle.rs) to learn how to start.**
//!
//! The documentation for the [`Turtle` struct](struct.Turtle.html) contains a listing of all of the
//! various drawing commands that you can use on the Turtles that you create. The [`color`
//! module](color/index.html) and its submodules contain hundreds of predefined color names that you
//! can use to set the pen, background and fill color of a turtle. That module also explains how to
//! use any arbitrary color, including ones that may not be defined in this crate.
//!
//! Note: Call [`turtle::start()`](fn.start.html) if you do not create a turtle with
//! [`Turtle::new()`](struct.Turtle.html#method.new) right at the beginning of your program. Most
//! programs will never need to call this function as it is called for you in
//! [`Turtle::new()`](struct.Turtle.html#method.new).
//!
//! # Random Values
//!
//! See the [`rand` module](rand/index.html) for information about generating random colors, speeds,
//! angles, and more which can be used in your programs to produce some interesting results!
//!
//! # Event Handling
//!
//! The [`Event` enum](event/enum.Event.html) documentation provides information about how you can
//! create an event loop. This allows you to draw things in response to certain events like the
//! mouse moving, keys being pressed, and more.
//!
//! The `Turtle` struct contains a few convenience methods so you can do some common event-related
//! things without creating the entire event loop. For example, use
//! [`wait_for_click()`](struct.Turtle.html#method.wait_for_click) to wait for the user to click
//! anywhere on the screen before proceeding.

#[cfg(all(test, not(feature = "test")))]
compile_error!("Make sure you run tests with `cargo test --features test`");

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

extern crate piston_window;
extern crate interpolation;
extern crate rand as rand_crate;

mod turtle_window;

mod app;
mod turtle;
mod speed;
mod radians;
mod animation;
mod extensions;
mod renderer;
mod state;
mod query;
mod server;
mod renderer_process;
mod messenger;

pub mod color;
pub mod event;
pub mod rand;

pub use server::start;
pub use turtle::{Turtle, Point, Distance, Angle};
pub use speed::{Speed};
pub use color::{Color};
pub use event::Event;
pub use rand::{random, random_range};
<|endoftext|>


<commit_before>#![feature(core)]
extern crate biterator;
extern crate itertools;

mod crockford_base32;
<commit_msg>Make public<commit_after>#![feature(core)]
extern crate biterator;
extern crate itertools;

pub mod crockford_base32;
<|endoftext|>


<commit_before>#![allow(dead_code, unused_variables)]

extern crate mpack;

use std::env;
use std::fmt;
use std::io;
use std::process::Command;

pub use self::metadata::Metadata;
pub use self::session::Session;

mod metadata;
mod session;

/// A function as parsed from `get_api_info()`.
pub struct Function {
    pub name: String,
    pub parameters: Vec<(String, String)>,
    pub return_type: String,
    pub async: bool,
    pub can_fail: bool,
}

impl fmt::Display for Function {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{name}({params}) -> {return_type} {can_fail}{async}",
            return_type=self.return_type,
            async=if self.async { "async" } else { "" },
            name=self.name,
            params=self.parameters.iter().map(|p| format!("{} {}", p.0, p.1)).collect::<Vec<String>>().join(", "),
            can_fail=if self.can_fail { "[can fail]" } else { "" },
        )
    }
}

/// The result of `get_api_info()`.
pub struct ApiInfo {
    pub functions: Vec<Function>,
}

/// Get API information from Vim by running `nvim --api-info` and parsing the output.
pub fn get_api_info() -> Result<ApiInfo, mpack::ReadError> {
    let cmd = env::var("NVIM_BIN").unwrap_or(String::from("nvim"));
    let output = try!(Command::new(cmd).arg("--api-info").output());
    if !output.status.success() {
        return Err(mpack::ReadError::Io(match output.status.code() {
            Some(code) => io::Error::from_raw_os_error(code),
            None => io::Error::new(io::ErrorKind::Other, "killed by signal"),
        }))
    }

    let mut r = mpack::Reader::new(&output.stdout[..]);
    let dict = try!(r.read_value()).map().unwrap();
    let dict_functions = dict.get_array("functions").unwrap();

    let mut functions = Vec::with_capacity(dict_functions.len());

    for f in dict_functions {
        let f = f.map().unwrap();
        let name = f.get_string("name").unwrap();
        let parameters = f.get_array("parameters").unwrap().into_iter().map(|p| {
            let p = p.array().unwrap();
            (p[0].clone().string().unwrap(), p[1].clone().string().unwrap())
        }).collect();
        let return_type = f.get_string("return_type").unwrap();
        let async = f.get_bool("async").unwrap();
        let can_fail = f.get_bool("can_fail").unwrap_or(false);
        functions.push(Function{
            name: name,
            parameters: parameters,
            return_type: return_type,
            async: async,
            can_fail: can_fail,
        });
    }

    Ok(ApiInfo{
        functions: functions,
    })
}
<commit_msg>Add crate blurb<commit_after>#![allow(dead_code, unused_variables)]
//! `neovim` is a crate that enables building Neovim plugins with Rust.
//!
//! Neovim is a fork of Vim that enables fully asynchronous communication
//! with plugins that run as external programs, communicating via Msgpack-RPC.
//! This crate provides facilities for connecting to a Neovim instance
//! and making API calls to take actions within the editor.

extern crate mpack;

use std::env;
use std::fmt;
use std::io;
use std::process::Command;

pub use self::metadata::Metadata;
pub use self::session::Session;

mod metadata;
mod session;

/// A function as parsed from `get_api_info()`.
pub struct Function {
    pub name: String,
    pub parameters: Vec<(String, String)>,
    pub return_type: String,
    pub async: bool,
    pub can_fail: bool,
}

impl fmt::Display for Function {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{name}({params}) -> {return_type} {can_fail}{async}",
            return_type=self.return_type,
            async=if self.async { "async" } else { "" },
            name=self.name,
            params=self.parameters.iter().map(|p| format!("{} {}", p.0, p.1)).collect::<Vec<String>>().join(", "),
            can_fail=if self.can_fail { "[can fail]" } else { "" },
        )
    }
}

/// The result of `get_api_info()`.
pub struct ApiInfo {
    pub functions: Vec<Function>,
}

/// Get API information from Vim by running `nvim --api-info` and parsing the output.
pub fn get_api_info() -> Result<ApiInfo, mpack::ReadError> {
    let cmd = env::var("NVIM_BIN").unwrap_or(String::from("nvim"));
    let output = try!(Command::new(cmd).arg("--api-info").output());
    if !output.status.success() {
        return Err(mpack::ReadError::Io(match output.status.code() {
            Some(code) => io::Error::from_raw_os_error(code),
            None => io::Error::new(io::ErrorKind::Other, "killed by signal"),
        }))
    }

    let mut r = mpack::Reader::new(&output.stdout[..]);
    let dict = try!(r.read_value()).map().unwrap();
    let dict_functions = dict.get_array("functions").unwrap();

    let mut functions = Vec::with_capacity(dict_functions.len());

    for f in dict_functions {
        let f = f.map().unwrap();
        let name = f.get_string("name").unwrap();
        let parameters = f.get_array("parameters").unwrap().into_iter().map(|p| {
            let p = p.array().unwrap();
            (p[0].clone().string().unwrap(), p[1].clone().string().unwrap())
        }).collect();
        let return_type = f.get_string("return_type").unwrap();
        let async = f.get_bool("async").unwrap();
        let can_fail = f.get_bool("can_fail").unwrap_or(false);
        functions.push(Function{
            name: name,
            parameters: parameters,
            return_type: return_type,
            async: async,
            can_fail: can_fail,
        });
    }

    Ok(ApiInfo{
        functions: functions,
    })
}
<|endoftext|>