<commit_before>
#![feature(phase)]

extern crate crypto;
extern crate libc;
#[phase(plugin, link)] extern crate log;

use crypto::sha2::Sha512;
use crypto::digest::Digest;
use libc::{getgid, getuid};
use std::os;
use std::io::{OTHER_EXECUTE, OTHER_READ, OTHER_RWX,
              GROUP_EXECUTE, GROUP_READ, GROUP_RWX,
              USER_RWX, ALL_PERMISSIONS};
use std::io::fs::{File, PathExtensions, mkdir, mkdir_recursive, chmod};
use std::io::process::{Command, InheritFd, ExitStatus};

const CACHE_SUBPATH: &'static str = "pexe-runner-cache";
// TODO: support overriding cache location.
const CACHE_BASE: &'static str = "/tmp";

const RUST_PNACL_TRANS: &'static str = "rust-pnacl-trans";

pub fn main() {
    let args = os::args();
    if args.len() != 2 { return; }
    let pexe_path = Path::new(args[1].as_slice());
    let pexe_filename = Path::new(pexe_path.filename().unwrap());

    let cache = Path::new(CACHE_BASE).join(CACHE_SUBPATH);
    if !cache.exists() {
        mkdir_recursive(&cache, ALL_PERMISSIONS).unwrap();
    }

    // if the binary is rx by the world, don't use a user prefix when caching.

    let mut pexe = File::open(&pexe_path).unwrap();

    let pexe_stat = pexe.stat().unwrap();
    let (cache_dir, perms) = if pexe_stat.perm.contains(OTHER_EXECUTE | OTHER_READ) {
        let c = cache.join("other");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        (c, OTHER_RWX)
    } else if pexe_stat.perm.contains(GROUP_EXECUTE | GROUP_READ) {
        let c = cache.join("group");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let gid = unsafe { getgid() };
        let c = c.join(format!("{}", gid));
        if !c.exists() {
            mkdir(&c, GROUP_RWX).unwrap();
        }
        (c, GROUP_RWX)
    } else {
        let c = cache.join("user");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let uid = unsafe { getuid() };
        let c = c.join(format!("{}", uid));
        if !c.exists() {
            mkdir(&c, USER_RWX).unwrap();
        }
        (c, USER_RWX)
    };

    let pexe_bin = pexe.read_to_end().unwrap();

    let mut hasher = Sha512::new();
    hasher.input(pexe_bin.as_slice());
    let cache_dir = cache_dir.join(hasher.result_str());
    if !cache_dir.exists() {
        mkdir(&cache_dir, perms).unwrap();
    }
    let nexe_path = cache_dir
        .join(pexe_filename.with_extension("nexe"));

    let nacl_sdk_root = env!("NACL_SDK_ROOT");

    if !nexe_path.exists() {
        let mut cmd = Command::new(RUST_PNACL_TRANS);
        cmd.arg("--cross-path");
        cmd.arg(nacl_sdk_root);
        cmd.arg(pexe_path.display().to_string());
        cmd.arg("-o");
        cmd.arg(nexe_path.display().to_string());
        cmd.arg("--opt-level=2");
        println!("trans cmd line: `{}`", cmd);
        let mut trans = cmd.spawn().unwrap();

        let status = trans.wait().unwrap();
        match status {
            ExitStatus(0) => {
                chmod(&nexe_path, perms).unwrap();
            }
            _ => {
                panic!("trans failed!");
            }
        }
    }

    let nacl_sdk_root = Path::new(nacl_sdk_root);
    let tools = nacl_sdk_root.join("tools");
    let nacl_helper_bootstrap = tools.join("nacl_helper_bootstrap_x86_64");
    let sel_ldr_bin = tools.join("sel_ldr_x86_64");
    let irt_core = tools.join("irt_core_x86_64.nexe");

    let mut sel_ldr_args = vec!(sel_ldr_bin.display().to_string(),
                                "--r_debug=0xXXXXXXXXXXXXXXXX".to_string(),
                                "--reserved_at_zero=0xXXXXXXXXXXXXXXXX".to_string(),
                                //"-a".to_string(),
                                "-B".to_string(),
                                irt_core.display().to_string(),
                                "-l".to_string(), "/dev/null".to_string());
    sel_ldr_args.push("--".to_string());
    sel_ldr_args.push(nexe_path.display().to_string());
    sel_ldr_args.extend(args.slice_from(2).to_vec().into_iter());

    let mut cmd = Command::new(nacl_helper_bootstrap);
    cmd.args(sel_ldr_args.as_slice());
    cmd.stdout(InheritFd(libc::STDOUT_FILENO));
    cmd.stderr(InheritFd(libc::STDERR_FILENO));
    debug!("sel_ldr cmd line: `{}`", cmd);
    match cmd.spawn() {
        Ok(mut process) => {
            match process.wait() {
                Ok(ExitStatus(status)) => {
                    os::set_exit_status(status);
                }
                Ok(_) => {
                    os::set_exit_status(1);
                }
                Err(e) => {
                    panic!("couldn't wait on sel_ldr: {}", e);
                }
            }
        }
        Err(e) => {
            panic!("couldn't spawn sel_ldr: {}", e);
        }
    }
}
<commit_msg>Fix accidentally committed debug code.<commit_after>
#![feature(phase)]

extern crate crypto;
extern crate libc;
#[phase(plugin, link)] extern crate log;

use crypto::sha2::Sha512;
use crypto::digest::Digest;
use libc::{getgid, getuid};
use std::os;
use std::io::{OTHER_EXECUTE, OTHER_READ, OTHER_RWX,
              GROUP_EXECUTE, GROUP_READ, GROUP_RWX,
              USER_RWX, ALL_PERMISSIONS};
use std::io::fs::{File, PathExtensions, mkdir, mkdir_recursive, chmod};
use std::io::process::{Command, InheritFd, ExitStatus};

const CACHE_SUBPATH: &'static str = "pexe-runner-cache";
// TODO: support overriding cache location.
const CACHE_BASE: &'static str = "/tmp";

const RUST_PNACL_TRANS: &'static str = "rust-pnacl-trans";

pub fn main() {
    let args = os::args();
    if args.len() != 2 { return; }
    let pexe_path = Path::new(args[1].as_slice());
    let pexe_filename = Path::new(pexe_path.filename().unwrap());

    let cache = Path::new(CACHE_BASE).join(CACHE_SUBPATH);
    if !cache.exists() {
        mkdir_recursive(&cache, ALL_PERMISSIONS).unwrap();
    }

    // if the binary is rx by the world, don't use a user prefix when caching.

    let mut pexe = File::open(&pexe_path).unwrap();

    let pexe_stat = pexe.stat().unwrap();
    let (cache_dir, perms) = if pexe_stat.perm.contains(OTHER_EXECUTE | OTHER_READ) {
        let c = cache.join("other");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        (c, OTHER_RWX)
    } else if pexe_stat.perm.contains(GROUP_EXECUTE | GROUP_READ) {
        let c = cache.join("group");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let gid = unsafe { getgid() };
        let c = c.join(format!("{}", gid));
        if !c.exists() {
            mkdir(&c, GROUP_RWX).unwrap();
        }
        (c, GROUP_RWX)
    } else {
        let c = cache.join("user");
        if !c.exists() {
            mkdir(&c, ALL_PERMISSIONS).unwrap();
        }
        let uid = unsafe { getuid() };
        let c = c.join(format!("{}", uid));
        if !c.exists() {
            mkdir(&c, USER_RWX).unwrap();
        }
        (c, USER_RWX)
    };

    let pexe_bin = pexe.read_to_end().unwrap();

    let mut hasher = Sha512::new();
    hasher.input(pexe_bin.as_slice());
    let cache_dir = cache_dir.join(hasher.result_str());
    if !cache_dir.exists() {
        mkdir(&cache_dir, perms).unwrap();
    }
    let nexe_path = cache_dir
        .join(pexe_filename.with_extension("nexe"));

    let nacl_sdk_root = env!("NACL_SDK_ROOT");

    if !nexe_path.exists() {
        let mut cmd = Command::new(RUST_PNACL_TRANS);
        cmd.arg("--cross-path");
        cmd.arg(nacl_sdk_root);
        cmd.arg(pexe_path.display().to_string());
        cmd.arg("-o");
        cmd.arg(nexe_path.display().to_string());
        cmd.arg("--opt-level=2");
        debug!("trans cmd line: `{}`", cmd);
        let mut trans = cmd.spawn().unwrap();

        let status = trans.wait().unwrap();
        match status {
            ExitStatus(0) => {
                chmod(&nexe_path, perms).unwrap();
            }
            _ => {
                panic!("trans failed!");
            }
        }
    }

    let nacl_sdk_root = Path::new(nacl_sdk_root);
    let tools = nacl_sdk_root.join("tools");
    let nacl_helper_bootstrap = tools.join("nacl_helper_bootstrap_x86_64");
    let sel_ldr_bin = tools.join("sel_ldr_x86_64");
    let irt_core = tools.join("irt_core_x86_64.nexe");

    let mut sel_ldr_args = vec!(sel_ldr_bin.display().to_string(),
                                "--r_debug=0xXXXXXXXXXXXXXXXX".to_string(),
                                "--reserved_at_zero=0xXXXXXXXXXXXXXXXX".to_string(),
                                //"-a".to_string(),
                                "-B".to_string(),
                                irt_core.display().to_string(),
                                "-l".to_string(), "/dev/null".to_string());
    sel_ldr_args.push("--".to_string());
    sel_ldr_args.push(nexe_path.display().to_string());
    sel_ldr_args.extend(args.slice_from(2).to_vec().into_iter());

    let mut cmd = Command::new(nacl_helper_bootstrap);
    cmd.args(sel_ldr_args.as_slice());
    cmd.stdout(InheritFd(libc::STDOUT_FILENO));
    cmd.stderr(InheritFd(libc::STDERR_FILENO));
    debug!("sel_ldr cmd line: `{}`", cmd);
    match cmd.spawn() {
        Ok(mut process) => {
            match process.wait() {
                Ok(ExitStatus(status)) => {
                    os::set_exit_status(status);
                }
                Ok(_) => {
                    os::set_exit_status(1);
                }
                Err(e) => {
                    panic!("couldn't wait on sel_ldr: {}", e);
                }
            }
        }
        Err(e) => {
            panic!("couldn't spawn sel_ldr: {}", e);
        }
    }
}
<|endoftext|>


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

struct Coordinates {
    x: Cell<i32>,
    y: Cell<i32>,
}

fn main() {
    let bike = Coordinates { x: Cell::new(0), y: Cell::new(0) };
    let mut previous_positions = vec![];
    // borrow the value so that it can change (using the '&' symbol borrows the var)
    move_up(&bike.y);
    add_positions(&mut previous_positions, &bike.y);
    move_down(&bike.y);
    add_positions(&mut previous_positions, &bike.y);
    move_right(&bike.x);
    add_positions(&mut previous_positions, &bike.y);
    move_left(&bike.x);
    add_positions(&mut previous_positions, &bike.y);

    println!("X is {:?}, Y is {:?}", bike.x, bike.y);
    println!("{:?}", previous_positions)

}

fn add_positions<'a>(vector: &'a mut Vec<i32>, y_cc: &Cell<i32>) -> &'a mut Vec<i32> {
    let c_x = y_cc;
    vector.push(c_x.get());
    vector
}

fn move_up(y_cord: &Cell<i32>) -> &Cell<i32> {
    let new_val = y_cord.get(); // get the value and store it
    y_cord.set(new_val + 1); // modify the stored value and set the incoming param
    y_cord // no semicolon here because it is the return value
}

fn move_down(y_cord: &Cell<i32>) -> &Cell<i32> {
    let new_val = y_cord.get(); // get the value and store it
    y_cord.set(new_val - 1); // modify the stored value and set the incoming param
    y_cord // no semicolon here because it is the return value
}

fn move_right(x_cord: &Cell<i32>) -> &Cell<i32> {
    let new_val = x_cord.get(); // get the value and store it
    x_cord.set(new_val + 1); // modify the stored value and set the incoming param
    x_cord // no semicolon here because it is the return value
}

fn move_left(x_cord: &Cell<i32>) -> &Cell<i32> {
    let new_val = x_cord.get(); // get the value and store it
    x_cord.set(new_val - 1); // modify the stored value and set the incoming param
    x_cord // no semicolon here because it is the return value
}

#[test]
fn it_can_move() {
    let bike = Coordinates { x: Cell::new(0), y: Cell::new(0) };

    // test it starts at 0

    assert_eq!(0, bike.y.get());

    // test it can move up one

    move_up(&bike.y);

    assert_eq!(1, bike.y.get());

    // test it can continue to move up and theat move logic is valid

    move_up(&bike.y);
    move_up(&bike.y);
    move_up(&bike.y);

    assert_eq!(4, bike.y.get());

    for _ in 0..19 { // _ instead of x so that rust does not complain about x not being used
        move_up(&bike.y); // moves up 19 times
    }

    assert_eq!(23, bike.y.get());

    // test it can move down

    for _ in 0..19 {
        move_down(&bike.y);
    }

    assert_eq!(4, bike.y.get());

    // test it can move right

    for _ in 0..19 {
        move_right(&bike.x);
    }

    assert_eq!(19, bike.x.get());

    // test it can move left

    for _ in 0..10 {
        move_left(&bike.x);
    }

    assert_eq!(9, bike.x.get());
}
<commit_msg>can push all coords to vec<commit_after>use std::cell::Cell;

struct Coordinates {
    x: Cell<i32>,
    y: Cell<i32>,
}

fn main() {
    let bike = Coordinates { x: Cell::new(0), y: Cell::new(0) };
    let mut previous_positions = vec![];
    // borrow the value so that it can change (using the '&' symbol borrows the var)
    move_up(&bike.y);
    add_positions(&mut previous_positions, &bike.y, &bike.x);
    move_down(&bike.y);
    add_positions(&mut previous_positions, &bike.y, &bike.x);
    move_right(&bike.x);
    add_positions(&mut previous_positions, &bike.y, &bike.x);
    move_left(&bike.x);
    add_positions(&mut previous_positions, &bike.y, &bike.x);

    println!("X is {:?}, Y is {:?}", bike.x, bike.y);
    println!("{:?}", previous_positions)

}

fn add_positions<'a>(v_cc: &'a mut Vec<i32>, y: &Cell<i32>, x: &Cell<i32>) -> &'a mut Vec<i32> {
    let c_y = y;
    let c_x = x;
    v_cc.push(c_x.get());
    v_cc.push(c_y.get());
    v_cc
}

fn move_up(y_cord: &Cell<i32>) -> &Cell<i32> {
    let new_val = y_cord.get(); // get the value and store it
    y_cord.set(new_val + 1); // modify the stored value and set the incoming param
    y_cord // no semicolon here because it is the return value
}

fn move_down(y_cord: &Cell<i32>) -> &Cell<i32> {
    let new_val = y_cord.get(); // get the value and store it
    y_cord.set(new_val - 1); // modify the stored value and set the incoming param
    y_cord // no semicolon here because it is the return value
}

fn move_right(x_cord: &Cell<i32>) -> &Cell<i32> {
    let new_val = x_cord.get(); // get the value and store it
    x_cord.set(new_val + 1); // modify the stored value and set the incoming param
    x_cord // no semicolon here because it is the return value
}

fn move_left(x_cord: &Cell<i32>) -> &Cell<i32> {
    let new_val = x_cord.get(); // get the value and store it
    x_cord.set(new_val - 1); // modify the stored value and set the incoming param
    x_cord // no semicolon here because it is the return value
}

#[test]
fn it_can_move() {
    let bike = Coordinates { x: Cell::new(0), y: Cell::new(0) };

    // test it starts at 0

    assert_eq!(0, bike.y.get());

    // test it can move up one

    move_up(&bike.y);

    assert_eq!(1, bike.y.get());

    // test it can continue to move up and theat move logic is valid

    move_up(&bike.y);
    move_up(&bike.y);
    move_up(&bike.y);

    assert_eq!(4, bike.y.get());

    for _ in 0..19 { // _ instead of x so that rust does not complain about x not being used
        move_up(&bike.y); // moves up 19 times
    }

    assert_eq!(23, bike.y.get());

    // test it can move down

    for _ in 0..19 {
        move_down(&bike.y);
    }

    assert_eq!(4, bike.y.get());

    // test it can move right

    for _ in 0..19 {
        move_right(&bike.x);
    }

    assert_eq!(19, bike.x.get());

    // test it can move left

    for _ in 0..10 {
        move_left(&bike.x);
    }

    assert_eq!(9, bike.x.get());
}
<|endoftext|>


<commit_before>
fn to_pig_latin(string: String) -> String {
    let vowels: Vec<char> = vec!['a', 'e', 'i', 'o', 'u'];
    let strings = string.split_whitespace();
    let mut string_out = String::new();

    for string in strings {
        let mut prefix = String::new();

        for chr in string.chars() {
            if vowels.contains(&chr) {
                break;
            }
            prefix.push(chr);
        }

        let prefix_count = prefix.chars().count();
        let body: String = string.chars().skip(prefix_count).collect();

        string_out.push_str(&body);
        string_out.push_str(&prefix);
        string_out.push_str("ay ");
    }

    return string_out;
}

fn main() {
    use std::env;
    use std::io;

    if env::args().len() > 1 {
        if env::args().nth(1) == Some("-h".to_string()) {
            println!("Usage: {} [-h] <string1, string2, ...>", env::args().nth(0).unwrap());
            println!("\nIf no strings are passed as parameters, the input will be read from stdin");
            println!("\n\th\tdisplay this help dialog");
        }
        else {
            for arg in env::args() {
                println!("{}", to_pig_latin(arg));
            }
        }
    }
    else {
        let mut input = String::new();
        match io::stdin().read_line(&mut input) {
            Ok(_) => println!("{}", to_pig_latin(input)),
            _ => println!("There was an error reading from the console!"),
        }
    }
}
<commit_msg>Added tests for to_pig_latin<commit_after>
fn to_pig_latin(string: String) -> String {
    let vowels: Vec<char> = vec!['a', 'e', 'i', 'o', 'u'];
    let strings = string.split_whitespace();
    let mut string_out = String::new();

    for string in strings {
        let mut prefix = String::new();

        for chr in string.chars() {
            if vowels.contains(&chr) {
                break;
            }
            prefix.push(chr);
        }

        let prefix_count = prefix.chars().count();
        let body: String = string.chars().skip(prefix_count).collect();

        string_out.push_str(&body);
        string_out.push_str(&prefix);
        string_out.push_str("ay ");
    }

    // remove additional space
    return String::from(string_out.trim());
}

fn main() {
    use std::env;
    use std::io;

    if env::args().len() > 1 {
        if env::args().nth(1) == Some("-h".to_string()) {
            println!("Usage: {} [-h] <string1, string2, ...>", env::args().nth(0).unwrap());
            println!("\nIf no strings are passed as parameters, the input will be read from stdin");
            println!("\n\th\tdisplay this help dialog");
        }
        else {
            for arg in env::args() {
                println!("{}", to_pig_latin(arg));
            }
        }
    }
    else {
        let mut input = String::new();
        match io::stdin().read_line(&mut input) {
            Ok(_) => println!("{}", to_pig_latin(input)),
            _ => println!("There was an error reading from the console!"),
        }
    }
}

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

    #[test]
    fn test_to_pig_latin() {
        assert_eq!("ellohay", &to_pig_latin("hello".to_string()));
        assert_eq!("orldway", &to_pig_latin("world".to_string()));

        assert_eq!("ellohay orldway", &to_pig_latin("hello world".to_string()));
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::env;
use std::fs;
use std::io::{BufReader, BufRead};

extern crate git2;
extern crate glob;
extern crate rustc_serialize;
extern crate tiny_http;

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";
static INDEX_LOCAL_PATH: &'static str = "crates.io-index";

#[derive(RustcDecodable)]
#[allow(dead_code)]
struct CrateInfo {
    name: String,
    vers: String,
    deps: Vec<DepInfo>,
    cksum: String,
    features: HashMap<String, Vec<String>>,
    yanked: bool,
}

#[derive(RustcDecodable)]
#[allow(dead_code)]
struct DepInfo {
    name: String,
    req: String,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<String>,
    kind: Option<String>
}

fn build_dependency_map() -> HashMap<String, Vec<String>> {
    let mut match_options = glob::MatchOptions::new();
    match_options.require_literal_leading_dot = true;

    let index_paths1 = glob::glob_with("crates.io-index/*/*/*", &match_options).unwrap();
    let index_paths2 = glob::glob_with("crates.io-index/[12]/*", &match_options).unwrap();

    let index_paths = index_paths1.chain(index_paths2);

    let mut map = HashMap::new();

    for glob_result in index_paths {
        let index_path = glob_result.unwrap();
        let file = fs::File::open(&index_path).unwrap();
        let last_line = BufReader::new(file).lines().last().unwrap().unwrap();
        let crate_info: CrateInfo = rustc_serialize::json::decode(&last_line).unwrap();
        let deps_names = crate_info.deps.iter().map(|d| d.name.clone()).collect();
        map.insert(crate_info.name, deps_names);
    }

    map
}

fn main() {
    if fs::metadata(INDEX_LOCAL_PATH).is_err() {
        println!("Cloning crates.io-index");
        git2::Repository::clone(INDEX_GIT_URL, INDEX_LOCAL_PATH).unwrap();
    }

    let dep_map = build_dependency_map();

    let port = match env::var("PORT") {
        Ok(p) => p.parse::<u16>().unwrap(),
        Err(..) => 8000,
    };

    let server = tiny_http::ServerBuilder::new().with_port(port).build().unwrap();

    println!("Server listening on port {}", port);
    for request in server.incoming_requests() {
        println!("received request! method: {:?}, url: {:?}, headers: {:?}",
            request.get_method(),
            request.get_url(),
            request.get_headers()
        );

        let response = tiny_http::Response::from_string("hello world".to_string());
        request.respond(response);
    }
}
<commit_msg>Respond with dependency if given a crate name<commit_after>use std::collections::HashMap;
use std::env;
use std::fs;
use std::io::{BufReader, BufRead};

extern crate git2;
extern crate glob;
extern crate rustc_serialize;
extern crate tiny_http;

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";
static INDEX_LOCAL_PATH: &'static str = "crates.io-index";

#[derive(RustcDecodable)]
#[allow(dead_code)]
struct CrateInfo {
    name: String,
    vers: String,
    deps: Vec<DepInfo>,
    cksum: String,
    features: HashMap<String, Vec<String>>,
    yanked: bool,
}

#[derive(RustcDecodable)]
#[allow(dead_code)]
struct DepInfo {
    name: String,
    req: String,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<String>,
    kind: Option<String>
}

fn build_dependency_map() -> HashMap<String, Vec<String>> {
    let mut match_options = glob::MatchOptions::new();
    match_options.require_literal_leading_dot = true;

    let index_paths1 = glob::glob_with("crates.io-index/*/*/*", &match_options).unwrap();
    let index_paths2 = glob::glob_with("crates.io-index/[12]/*", &match_options).unwrap();

    let index_paths = index_paths1.chain(index_paths2);

    let mut map = HashMap::new();

    for glob_result in index_paths {
        let index_path = glob_result.unwrap();
        let file = fs::File::open(&index_path).unwrap();
        let last_line = BufReader::new(file).lines().last().unwrap().unwrap();
        let crate_info: CrateInfo = rustc_serialize::json::decode(&last_line).unwrap();
        let deps_names = crate_info.deps.iter().map(|d| d.name.clone()).collect();
        map.insert(crate_info.name, deps_names);
    }

    map
}

fn main() {
    if fs::metadata(INDEX_LOCAL_PATH).is_err() {
        println!("Cloning crates.io-index");
        git2::Repository::clone(INDEX_GIT_URL, INDEX_LOCAL_PATH).unwrap();
    }

    let dep_map = build_dependency_map();

    let port = match env::var("PORT") {
        Ok(p) => p.parse::<u16>().unwrap(),
        Err(..) => 8000,
    };

    let server = tiny_http::ServerBuilder::new().with_port(port).build().unwrap();

    println!("Server listening on port {}", port);
    for req in server.incoming_requests() {
        { println!("{}", req.get_url().trim_left_matches("/")) }
        let response = match dep_map.get(req.get_url().trim_left_matches("/")) {
            Some(d) => d.iter().fold(String::new(), |acc, item| acc + ", " + &item),
            None => String::from("could not find crate"),
        };

        let response = tiny_http::Response::from_string(response);
        req.respond(response);
    }
}
<|endoftext|>


<commit_before>extern crate getopts;
use getopts::{optopt,optflag,getopts,OptGroup,short_usage,Matches};
use std::os;

fn print_usage(program: &str, opts: &[OptGroup]) {
    let brief = format!("{}", program);
    print!("{}", short_usage(brief.as_slice(), opts));
}

fn main() {
    let args: Vec<String> = os::args();
    let program = args[0].clone();

    let opts = &[
        optflag("b", "", ""),
        optflag("e", "", ""),
        optflag("n", "", ""),
        optflag("t", "", ""),
    ];

    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => {
            print!("{}: {}\n\n", program, f.to_string());
            print_usage(program.as_slice(), opts); return;
        }
    };

    if matches.free.is_empty() {
        print_usage(program.as_slice(), opts);
    };

    scanfiles(matches);
}

fn scanfiles(matches: Matches) {

    let files = if !matches.free.is_empty() {
        matches.free.clone()
    } else {
        print!("Nada");
        return;
    };

    for file in files.iter() {
        print!("{}\n", file);
    }
}
<commit_msg>Working version without all of the bsd crap<commit_after>extern crate getopts;
use getopts::{optopt,optflag,getopts,OptGroup,short_usage,Matches};
use std::os;
use std::io::{File, stdout};

fn print_usage(program: &str, opts: &[OptGroup]) {
    let brief = format!("{}", program);
    print!("{}", short_usage(brief.as_slice(), opts));
}

fn main() {
    let args: Vec<String> = os::args();
    let program = args[0].clone();

    let opts = &[
        optflag("u", "", ""),
    ];

    let matches = match getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => {
            print!("{}: {}\n\n", program, f.to_string());
            print_usage(program.as_slice(), opts); return;
        }
    };

    if matches.free.is_empty() {
        print_usage(program.as_slice(), opts);
    };

    cat(matches);
}

fn cat(matches: Matches) {

    let files = if !matches.free.is_empty() {
        matches.free.clone()
    } else {
        return;
    };

    for file in files.iter() {
        let contents = File::open(&Path::new(file)).read_to_end();
        for line in contents.iter() {
            stdout().write(line.as_slice());
        }
    }
}
<|endoftext|>


<commit_before>/// Divide `n` by `divisor`, and round up to the nearest integer
/// if not evenly divisable.
#[inline]
pub fn div_round_up(n: usize, divisor: usize) -> usize {
    if n == 0 {
        0
    } else {
        (n - 1) / divisor + 1
    }
}

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

    #[test]
    fn check_div_round_up() {
        assert_eq!(0, div_round_up(0, 5));
        assert_eq!(1, div_round_up(5, 5));
        assert_eq!(1, div_round_up(1, 5));
        assert_eq!(2, div_round_up(3, 2));
        assert_eq!(usize::max_value() / 2 + 1, div_round_up(usize::max_value(), 2));
    }
}
<commit_msg>Add assertion that divisor isn't 0 in div_round_up<commit_after>/// Divide `n` by `divisor`, and round up to the nearest integer
/// if not evenly divisable.
#[inline]
pub fn div_round_up(n: usize, divisor: usize) -> usize {
    debug_assert!(divisor != 0, "Division by zero!");
    if n == 0 {
        0
    } else {
        (n - 1) / divisor + 1
    }
}

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

    #[test]
    fn check_div_round_up() {
        assert_eq!(0, div_round_up(0, 5));
        assert_eq!(1, div_round_up(5, 5));
        assert_eq!(1, div_round_up(1, 5));
        assert_eq!(2, div_round_up(3, 2));
        assert_eq!(usize::max_value() / 2 + 1, div_round_up(usize::max_value(), 2));
    }
}
<|endoftext|>


<commit_before>use std::f32::{NEG_INFINITY, INFINITY};
use std::cmp::Ordering;
use std::collections::HashMap;

use time;

use identity::{Team, JobDescription, Agent};
use life::{Commit, WorldState};
use motion::CENTER_OF_THE_WORLD;
use space::Pinfield;

pub fn orientation(team: Team) -> f32 {
    match team {
        Team::Orange => 1.0,
        Team::Blue => -1.0,
    }
}

pub fn figurine_valuation(agent: Agent) -> f32 {
    let value = match agent.job_description {
        // en.wikipedia.org/wiki/
        // Chess_piece_relative_value#Hans_Berliner.27s_system
        JobDescription::Servant => 1.0,
        JobDescription::Pony => 3.2,
        JobDescription::Scholar => 3.3,
        JobDescription::Cop => 5.1,
        JobDescription::Princess => 8.8,
        JobDescription::Figurehead => 20000.0,
    };
    orientation(agent.team) * value
}

pub fn score(world: WorldState) -> f32 {
    let mut valuation = 0.0;

    for team in Team::league().into_iter() {
        for agent in Agent::dramatis_personæ(team).into_iter() {
            valuation += world.agent_to_pinfield_ref(
                agent).pincount() as f32 * figurine_valuation(agent);
        }
        // breadth of scholarship bonus
        if world.agent_to_pinfield_ref(Agent {
                    team: team,
                    job_description: JobDescription::Scholar,
                })
                .to_locales()
                .len() >= 2 {
            valuation += orientation(team) * 0.5
        }
    }

    // ponies and servants want to be in the center of the world's
    // action, maybe??
    let center = Pinfield(CENTER_OF_THE_WORLD);
    // cast to signed to avoid overflow
    let orange_centerism: i8 = world.orange_servants.union(
        world.orange_ponies).intersection(center).pincount() as i8;
    let blue_centerism: i8 = world.blue_servants.union(
        world.blue_ponies).intersection(center).pincount() as i8;
    valuation += (orange_centerism - blue_centerism) as f32 * 0.1;

    valuation
}

fn mmv_lva_heuristic(commit: &Commit) -> f32 {
    // https://chessprogramming.wikispaces.com/MVV-LVA
    match commit.hospitalization {
        Some(patient) => (
            figurine_valuation(patient) - figurine_valuation(commit.patch.star)),
        None => 0.0,
    }
}

fn order_moves(commits: &mut Vec<Commit>) {
    commits.sort_by(|a, b| {
        mmv_lva_heuristic(&b)
            .partial_cmp(&mmv_lva_heuristic(&a))
            .unwrap_or(Ordering::Equal)
    });
}

pub fn α_β_negamax_search(world: WorldState,
                          depth: u8,
                          α: f32,
                          β: f32,
                          déjà_vu_table: &mut HashMap<WorldState, f32>)
                          -> (Option<Commit>, f32) {
    let mut experienced_α = α;
    let team = world.to_move;
    let potential_score = orientation(team) * score(world);
    let mut premonitions = world.reckless_lookahead();
    order_moves(&mut premonitions);
    if depth == 0 || premonitions.is_empty() {
        return (None, potential_score)
    };
    let mut optimum = NEG_INFINITY;
    let mut optimand = None;
    for premonition in premonitions.into_iter() {
        let mut value: f32;
        let cached: bool;
        {
            let cached_value_maybe = déjà_vu_table.get(&premonition.tree);
            match cached_value_maybe {
                Some(&cached_value) => {
                    cached = true;
                    value = cached_value;
                }
                None => {
                    cached = false;
                    // XXX fake assignment to work around the compiler's
                    // "possibly uninitialized value" rules
                    value = NEG_INFINITY;
                }
            };
        }

        if !cached {
            let (_, acquired_value) = α_β_negamax_search(premonition.tree,
                                                         depth - 1,
                                                         -β,
                                                         -experienced_α,
                                                         déjà_vu_table);
            value = -acquired_value;
            déjà_vu_table.insert(premonition.tree, value);
        }

        if value > optimum {
            optimum = value;
            optimand = Some(premonition);
        }
        if value > experienced_α {
            experienced_α = value;
        }
        if experienced_α >= β {
            break;
        }
        if (20000.0 - experienced_α.abs()).abs() < 30.0 {
            break;
        };
    }

    (optimand, optimum)
}

pub fn potentially_timebound_kickoff(world: &WorldState, depth: u8,
                                     nihilistically: bool,
                                     deadline_maybe: Option<time::Timespec>)
                                     -> Option<Vec<(Commit, f32)>> {
    let mut déjà_vu_table: HashMap<WorldState, f32> = HashMap::new();
    let mut premonitions;
    if nihilistically {
        premonitions = world.reckless_lookahead();
    } else {
        premonitions = world.lookahead();
    }
    order_moves(&mut premonitions);
    let mut forecasts = Vec::new();
    for premonition in premonitions.into_iter() {
        if let Some(deadline) = deadline_maybe {
            if time::get_time() > deadline {
                return None;
            }
        }
        let (_grandchild, mut value) = α_β_negamax_search(premonition.tree,
                                                          depth - 1,
                                                          NEG_INFINITY,
                                                          INFINITY,
                                                          &mut déjà_vu_table);
        value = -value;
        forecasts.push((premonition, value));
    }
    forecasts.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
    Some(forecasts)
}

pub fn kickoff(world: &WorldState, depth: u8,
               nihilistically: bool) -> Vec<(Commit, f32)> {
    potentially_timebound_kickoff(world, depth, nihilistically, None).unwrap()
}

pub fn iterative_deepening_kickoff(world: &WorldState, timeout: time::Duration,
                                   nihilistically: bool)
                                   -> (Vec<(Commit, f32)>, u8) {
    let deadline = time::get_time() + timeout;
    let mut depth = 1;
    let mut forecasts = potentially_timebound_kickoff(
        world, depth, nihilistically, None).unwrap();
    while let Some(prophecy) = potentially_timebound_kickoff(
            world, depth, nihilistically, Some(deadline)) {
        forecasts = prophecy;
        depth += 1;
    }
    (forecasts, depth)
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    use time;
    use super::{kickoff, score};
    use space::Locale;
    use life::WorldState;
    use identity::Team;

    impl WorldState {
        fn no_castling_at_all(&mut self) {
            self.orange_east_service_eligibility = false;
            self.orange_west_service_eligibility = false;
            self.blue_east_service_eligibility = false;
            self.blue_west_service_eligibility = false;
        }
    }

    #[bench]
    fn benchmark_scoring(b: &mut Bencher) {
        b.iter(|| score(WorldState::new()));
    }

    #[bench]
    fn benchmark_kickoff_depth_1(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 1, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_arbys(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_carefully(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, false));
    }

    #[ignore]
    #[bench]
    fn benchmark_kickoff_depth_3(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 3, true));
    }

    #[test]
    fn concerning_short_circuiting_upon_finding_mate() {
        let ws = WorldState::reconstruct("7K/r7/1r6/8/8/8/8/7k b -".to_owned());
        let start = time::get_time();
        kickoff(&ws, 30, true);
        let duration = time::get_time() - start;
        assert!(duration.num_seconds() < 20);
    }

    #[test]
    #[allow(float_cmp)]
    fn concerning_fairness_of_the_initial_position() {
        // It's okay to assume this is really 0.0. Floats may be imprecise,
        // but they do have well-defined behavior.
        assert_eq!(0.0, score(WorldState::new()));
    }

    #[test]
    fn concerning_servant_ascension_choices() {
        let ws = WorldState::reconstruct("8/q1P1k/8/8/8/8/6PP/7K w -".to_owned());
        // looking ahead 3 moves allows the Leafline AI to catch the
        // split, whereby transforming into a pony (rather than
        // transitioning into a princess, as would usually be
        // expected) endangers both the blue princess and figurehead
        let (ref best_move, score) = kickoff(&ws, 3, true)[0];
        println!("{:?}", best_move);
        assert!(score > 0.0);
        assert_eq!(best_move.tree.preserve(), "2N5/q3k3/8/8/8/8/6PP/7K b -");
    }

    #[test]
    fn experimentally_about_kickoff() {
        let mut world = WorldState::new_except_empty();
        // SCENARIO: let's imagine Orange (to move) has separate attacks against
        // Blue's pony and servant, against which Blue has no defense but
        // to run away. We predict that Orange will take the pony, and
        // then Blue will move the servant out of the way.

        // scholar endangers pony
        world.blue_ponies = world.blue_ponies.alight(
            Locale { rank: 0, file: 0 });
        world.orange_scholars = world.orange_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 7, file: 1 });
        world.orange_ponies = world.orange_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Blue has another servant sitting nowhere interesting
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 3, file: 6 });
        world.no_castling_at_all();

        let depth = 2;
        let advisory = kickoff(&world, depth, true);

        // taking the pony is the right thing to do
        assert_eq!(Locale { rank: 0, file: 0 }, advisory[0].0.patch.whither);

        // And, furthermore, the answer should be the same if we face the
        // same situation with the colors reversed
        //
        // XXX this would be tidier and less copy-pastey if I had more
        // general figurine-placing functions that were three rather than
        // two levels of abstraction above twiddling bits on an unsigned
        // int ... oh, well
        let mut negaworld = WorldState::new_except_empty();
        negaworld.to_move = Team::Blue;

        // scholar endangers pony
        negaworld.orange_ponies = negaworld.orange_ponies.alight(
            Locale { rank: 0, file: 0 });
        negaworld.blue_scholars = negaworld.blue_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 7, file: 1 });
        negaworld.blue_ponies = negaworld.blue_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Orange has another servant sitting nowhere interesting
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 3, file: 6 });
        negaworld.to_move = Team::Blue;

        negaworld.no_castling_at_all();

        let negadvisory = kickoff(&negaworld, depth, true);

        // taking the pony is still the right thing to do, even in the
        // negaworld
        assert_eq!(Locale { rank: 0, file: 0 },
                   negadvisory[0].0.patch.whither);
    }

}
<commit_msg>30 points is NOTHING<commit_after>use std::f32::{NEG_INFINITY, INFINITY};
use std::cmp::Ordering;
use std::collections::HashMap;

use time;

use identity::{Team, JobDescription, Agent};
use life::{Commit, WorldState};
use motion::CENTER_OF_THE_WORLD;
use space::Pinfield;

pub fn orientation(team: Team) -> f32 {
    match team {
        Team::Orange => 1.0,
        Team::Blue => -1.0,
    }
}

pub fn figurine_valuation(agent: Agent) -> f32 {
    let value = match agent.job_description {
        // en.wikipedia.org/wiki/
        // Chess_piece_relative_value#Hans_Berliner.27s_system
        JobDescription::Servant => 1.0,
        JobDescription::Pony => 3.2,
        JobDescription::Scholar => 3.3,
        JobDescription::Cop => 5.1,
        JobDescription::Princess => 8.8,
        JobDescription::Figurehead => 20000.0,
    };
    orientation(agent.team) * value
}

pub fn score(world: WorldState) -> f32 {
    let mut valuation = 0.0;

    for team in Team::league().into_iter() {
        for agent in Agent::dramatis_personæ(team).into_iter() {
            valuation += world.agent_to_pinfield_ref(
                agent).pincount() as f32 * figurine_valuation(agent);
        }
        // breadth of scholarship bonus
        if world.agent_to_pinfield_ref(Agent {
                    team: team,
                    job_description: JobDescription::Scholar,
                })
                .to_locales()
                .len() >= 2 {
            valuation += orientation(team) * 0.5
        }
    }

    // ponies and servants want to be in the center of the world's
    // action, maybe??
    let center = Pinfield(CENTER_OF_THE_WORLD);
    // cast to signed to avoid overflow
    let orange_centerism: i8 = world.orange_servants.union(
        world.orange_ponies).intersection(center).pincount() as i8;
    let blue_centerism: i8 = world.blue_servants.union(
        world.blue_ponies).intersection(center).pincount() as i8;
    valuation += (orange_centerism - blue_centerism) as f32 * 0.1;

    valuation
}

fn mmv_lva_heuristic(commit: &Commit) -> f32 {
    // https://chessprogramming.wikispaces.com/MVV-LVA
    match commit.hospitalization {
        Some(patient) => (
            figurine_valuation(patient) - figurine_valuation(commit.patch.star)),
        None => 0.0,
    }
}

fn order_moves(commits: &mut Vec<Commit>) {
    commits.sort_by(|a, b| {
        mmv_lva_heuristic(&b)
            .partial_cmp(&mmv_lva_heuristic(&a))
            .unwrap_or(Ordering::Equal)
    });
}

pub fn α_β_negamax_search(world: WorldState,
                          depth: u8,
                          α: f32,
                          β: f32,
                          déjà_vu_table: &mut HashMap<WorldState, f32>)
                          -> (Option<Commit>, f32) {
    let mut experienced_α = α;
    let team = world.to_move;
    let potential_score = orientation(team) * score(world);
    let mut premonitions = world.reckless_lookahead();
    order_moves(&mut premonitions);
    if depth == 0 || premonitions.is_empty() {
        return (None, potential_score)
    };
    let mut optimum = NEG_INFINITY;
    let mut optimand = None;
    for premonition in premonitions.into_iter() {
        let mut value: f32;
        let cached: bool;
        {
            let cached_value_maybe = déjà_vu_table.get(&premonition.tree);
            match cached_value_maybe {
                Some(&cached_value) => {
                    cached = true;
                    value = cached_value;
                }
                None => {
                    cached = false;
                    // XXX fake assignment to work around the compiler's
                    // "possibly uninitialized value" rules
                    value = NEG_INFINITY;
                }
            };
        }

        if !cached {
            let (_, acquired_value) = α_β_negamax_search(premonition.tree,
                                                         depth - 1,
                                                         -β,
                                                         -experienced_α,
                                                         déjà_vu_table);
            value = -acquired_value;
            déjà_vu_table.insert(premonition.tree, value);
        }

        if value > optimum {
            optimum = value;
            optimand = Some(premonition);
        }
        if value > experienced_α {
            experienced_α = value;
        }
        if experienced_α >= β {
            break;
        }
        if (20000.0 - experienced_α.abs()).abs() < 1000.0 {
            break;
        };
    }

    (optimand, optimum)
}

pub fn potentially_timebound_kickoff(world: &WorldState, depth: u8,
                                     nihilistically: bool,
                                     deadline_maybe: Option<time::Timespec>)
                                     -> Option<Vec<(Commit, f32)>> {
    let mut déjà_vu_table: HashMap<WorldState, f32> = HashMap::new();
    let mut premonitions;
    if nihilistically {
        premonitions = world.reckless_lookahead();
    } else {
        premonitions = world.lookahead();
    }
    order_moves(&mut premonitions);
    let mut forecasts = Vec::new();
    for premonition in premonitions.into_iter() {
        if let Some(deadline) = deadline_maybe {
            if time::get_time() > deadline {
                return None;
            }
        }
        let (_grandchild, mut value) = α_β_negamax_search(premonition.tree,
                                                          depth - 1,
                                                          NEG_INFINITY,
                                                          INFINITY,
                                                          &mut déjà_vu_table);
        value = -value;
        forecasts.push((premonition, value));
    }
    forecasts.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
    Some(forecasts)
}

pub fn kickoff(world: &WorldState, depth: u8,
               nihilistically: bool) -> Vec<(Commit, f32)> {
    potentially_timebound_kickoff(world, depth, nihilistically, None).unwrap()
}

pub fn iterative_deepening_kickoff(world: &WorldState, timeout: time::Duration,
                                   nihilistically: bool)
                                   -> (Vec<(Commit, f32)>, u8) {
    let deadline = time::get_time() + timeout;
    let mut depth = 1;
    let mut forecasts = potentially_timebound_kickoff(
        world, depth, nihilistically, None).unwrap();
    while let Some(prophecy) = potentially_timebound_kickoff(
            world, depth, nihilistically, Some(deadline)) {
        forecasts = prophecy;
        depth += 1;
    }
    (forecasts, depth)
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;

    use time;
    use super::{kickoff, score};
    use space::Locale;
    use life::WorldState;
    use identity::Team;

    impl WorldState {
        fn no_castling_at_all(&mut self) {
            self.orange_east_service_eligibility = false;
            self.orange_west_service_eligibility = false;
            self.blue_east_service_eligibility = false;
            self.blue_west_service_eligibility = false;
        }
    }

    #[bench]
    fn benchmark_scoring(b: &mut Bencher) {
        b.iter(|| score(WorldState::new()));
    }

    #[bench]
    fn benchmark_kickoff_depth_1(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 1, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_arbys(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, true));
    }

    #[bench]
    fn benchmark_kickoff_depth_2_carefully(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 2, false));
    }

    #[ignore]
    #[bench]
    fn benchmark_kickoff_depth_3(b: &mut Bencher) {
        let ws = WorldState::new();
        b.iter(|| kickoff(&ws, 3, true));
    }

    #[test]
    fn concerning_short_circuiting_upon_finding_mate() {
        let ws = WorldState::reconstruct("7K/r7/1r6/8/8/8/8/7k b -".to_owned());
        let start = time::get_time();
        kickoff(&ws, 30, true);
        let duration = time::get_time() - start;
        assert!(duration.num_seconds() < 20);
    }

    #[test]
    #[allow(float_cmp)]
    fn concerning_fairness_of_the_initial_position() {
        // It's okay to assume this is really 0.0. Floats may be imprecise,
        // but they do have well-defined behavior.
        assert_eq!(0.0, score(WorldState::new()));
    }

    #[test]
    fn concerning_servant_ascension_choices() {
        let ws = WorldState::reconstruct("8/q1P1k/8/8/8/8/6PP/7K w -".to_owned());
        // looking ahead 3 moves allows the Leafline AI to catch the
        // split, whereby transforming into a pony (rather than
        // transitioning into a princess, as would usually be
        // expected) endangers both the blue princess and figurehead
        let (ref best_move, score) = kickoff(&ws, 3, true)[0];
        println!("{:?}", best_move);
        assert!(score > 0.0);
        assert_eq!(best_move.tree.preserve(), "2N5/q3k3/8/8/8/8/6PP/7K b -");
    }

    #[test]
    fn experimentally_about_kickoff() {
        let mut world = WorldState::new_except_empty();
        // SCENARIO: let's imagine Orange (to move) has separate attacks against
        // Blue's pony and servant, against which Blue has no defense but
        // to run away. We predict that Orange will take the pony, and
        // then Blue will move the servant out of the way.

        // scholar endangers pony
        world.blue_ponies = world.blue_ponies.alight(
            Locale { rank: 0, file: 0 });
        world.orange_scholars = world.orange_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 7, file: 1 });
        world.orange_ponies = world.orange_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Blue has another servant sitting nowhere interesting
        world.blue_servants = world.blue_servants.alight(
            Locale { rank: 3, file: 6 });
        world.no_castling_at_all();

        let depth = 2;
        let advisory = kickoff(&world, depth, true);

        // taking the pony is the right thing to do
        assert_eq!(Locale { rank: 0, file: 0 }, advisory[0].0.patch.whither);

        // And, furthermore, the answer should be the same if we face the
        // same situation with the colors reversed
        //
        // XXX this would be tidier and less copy-pastey if I had more
        // general figurine-placing functions that were three rather than
        // two levels of abstraction above twiddling bits on an unsigned
        // int ... oh, well
        let mut negaworld = WorldState::new_except_empty();
        negaworld.to_move = Team::Blue;

        // scholar endangers pony
        negaworld.orange_ponies = negaworld.orange_ponies.alight(
            Locale { rank: 0, file: 0 });
        negaworld.blue_scholars = negaworld.blue_scholars.alight(
            Locale { rank: 2, file: 2 });

        // pony endangers servant
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 7, file: 1 });
        negaworld.blue_ponies = negaworld.blue_ponies.alight(
            Locale { rank: 5, file: 2 });

        // Orange has another servant sitting nowhere interesting
        negaworld.orange_servants = negaworld.orange_servants.alight(
            Locale { rank: 3, file: 6 });
        negaworld.to_move = Team::Blue;

        negaworld.no_castling_at_all();

        let negadvisory = kickoff(&negaworld, depth, true);

        // taking the pony is still the right thing to do, even in the
        // negaworld
        assert_eq!(Locale { rank: 0, file: 0 },
                   negadvisory[0].0.patch.whither);
    }

}
<|endoftext|>


<commit_before>//! A module of helper traits and iterators that are not intended to be used
//! directly.

use std::ops::{
    RangeFull,
    Range,
    RangeTo,
    RangeFrom
};

use std::mem;
use std::slice;

/// Apply **IntoIterator** on each element of a tuple.
pub trait IntoIteratorTuple
{
    /// Tuple of values that implement **Iterator**.
    type Output;

    /// Return a tuple of iterators.
    fn into_iterator_tuple(self) -> Self::Output;
}

/// A helper trait for (x, y, z) ++ w => (x, y, z, w),
/// used for implementing `iproduct!`.
pub trait AppendTuple<X> {
    /// Resulting tuple type
    type Result;
    /// “Append” value **x** to a tuple.
    fn append(self, x: X) -> Self::Result;
}

macro_rules! impl_append_tuple(
    () => (
        impl<T> AppendTuple<T> for () {
            type Result = (T, );
            fn append(self, x: T) -> (T, ) {
                (x, )
            }
        }
    );

    ($A:ident, $($B:ident,)*) => (
        impl_append_tuple!($($B,)*);
        #[allow(non_snake_case)]
        impl<$A, $($B,)* T> AppendTuple<T> for ($A, $($B),*) {
            type Result = ($A, $($B, )* T);
            fn append(self, x: T) -> ($A, $($B,)* T) {
                let ($A, $($B),*) = self;
                ($A, $($B,)* x)
            }
        }
    );
);

impl_append_tuple!(A, B, C, D, E, F, G, H, I, J, K, L,);

/// A helper iterator that maps an iterator of tuples like
/// `((A, B), C)` to an iterator of `(A, B, C)`.
///
/// Used by the `iproduct!()` macro.
#[derive(Clone)]
pub struct FlatTuples<I> {
    iter: I,
}

impl<I> FlatTuples<I>
{
    /// Create a new **FlatTuples**.
    pub fn new(iter: I) -> Self
    {
        FlatTuples{iter: iter}
    }
}

impl<X, T, I> Iterator for FlatTuples<I> where
    I: Iterator<Item=(T, X)>,
    T: AppendTuple<X>,
{
    type Item = T::Result;
    #[inline]
    fn next(&mut self) -> Option<Self::Item>
    {
        self.iter.next().map(|(t, x)| t.append(x))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl<X, T, I> DoubleEndedIterator for FlatTuples<I> where
    I: DoubleEndedIterator<Item=(T, X)>,
    T: AppendTuple<X>,
{
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item>
    {
        self.iter.next_back().map(|(t, x)| t.append(x))
    }
}

/// **GenericRange** is implemented by Rust's built-in range types, produced
/// by range syntax like `a..`, `..b` or `c..d`.
pub trait GenericRange {
    /// Start index (inclusive)
    fn start(&self) -> Option<usize> { None }
    /// End index (exclusive)
    fn end(&self) -> Option<usize> { None }
}

impl GenericRange for RangeFull {}

impl GenericRange for RangeFrom<usize> {
    fn start(&self) -> Option<usize> { Some(self.start) }
}

impl GenericRange for RangeTo<usize> {
    fn end(&self) -> Option<usize> { Some(self.end) }
}

impl GenericRange for Range<usize> {
    fn start(&self) -> Option<usize> { Some(self.start) }
    fn end(&self) -> Option<usize> { Some(self.end) }
}

/// Helper trait to convert usize to floating point type.
pub trait ToFloat<F> : Copy {
    /// Convert usize to float.
    fn to_float(self) -> F;
}

impl ToFloat<f32> for usize {
    fn to_float(self) -> f32 { self as f32 }
}

impl ToFloat<f64> for usize {
    fn to_float(self) -> f64 { self as f64 }
}

/// A trait for items that can *maybe* be joined together.
pub trait MendSlice : Copy
{
    /// If the slices are contiguous, return them joined into one.
    fn mend(Self, Self) -> Option<Self>;
}

impl<'a, T> MendSlice for &'a [T]
{
    fn mend(a: &'a [T], b: &'a [T]) -> Option<&'a [T]>
    {
        unsafe {
            let a_end = a.as_ptr().offset(a.len() as isize);
            if a_end == b.as_ptr() {
                Some(slice::from_raw_parts(a.as_ptr(), a.len() + b.len()))
            } else {
                None
            }
        }
    }
}

impl<'a> MendSlice for &'a str
{
    fn mend(a: &'a str, b: &'a str) -> Option<&'a str>
    {
        unsafe {
            mem::transmute(MendSlice::mend(a.as_bytes(), b.as_bytes()))
        }
    }
}
<commit_msg>Use doc(hidden) in misc to discourage use<commit_after>//! A module of helper traits and iterators that are not intended to be used
//! directly.

use std::ops::{
    RangeFull,
    Range,
    RangeTo,
    RangeFrom
};

use std::mem;
use std::slice;

/// Apply **IntoIterator** on each element of a tuple.
pub trait IntoIteratorTuple
{
    /// Tuple of values that implement **Iterator**.
    type Output;

    /// Return a tuple of iterators.
    fn into_iterator_tuple(self) -> Self::Output;
}

/// A helper trait for (x, y, z) ++ w => (x, y, z, w),
/// used for implementing `iproduct!`.
pub trait AppendTuple<X> {
    /// Resulting tuple type
    type Result;
    /// “Append” value **x** to a tuple.
    fn append(self, x: X) -> Self::Result;
}

macro_rules! impl_append_tuple(
    () => (
        impl<T> AppendTuple<T> for () {
            type Result = (T, );
            fn append(self, x: T) -> (T, ) {
                (x, )
            }
        }
    );

    ($A:ident, $($B:ident,)*) => (
        impl_append_tuple!($($B,)*);
        #[allow(non_snake_case)]
        impl<$A, $($B,)* T> AppendTuple<T> for ($A, $($B),*) {
            type Result = ($A, $($B, )* T);
            fn append(self, x: T) -> ($A, $($B,)* T) {
                let ($A, $($B),*) = self;
                ($A, $($B,)* x)
            }
        }
    );
);

impl_append_tuple!(A, B, C, D, E, F, G, H, I, J, K, L,);

/// A helper iterator that maps an iterator of tuples like
/// `((A, B), C)` to an iterator of `(A, B, C)`.
///
/// Used by the `iproduct!()` macro.
#[derive(Clone)]
pub struct FlatTuples<I> {
    iter: I,
}

impl<I> FlatTuples<I>
{
    /// Create a new **FlatTuples**.
    #[doc(hidden)]
    pub fn new(iter: I) -> Self
    {
        FlatTuples{iter: iter}
    }
}

impl<X, T, I> Iterator for FlatTuples<I> where
    I: Iterator<Item=(T, X)>,
    T: AppendTuple<X>,
{
    type Item = T::Result;
    #[inline]
    fn next(&mut self) -> Option<Self::Item>
    {
        self.iter.next().map(|(t, x)| t.append(x))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

impl<X, T, I> DoubleEndedIterator for FlatTuples<I> where
    I: DoubleEndedIterator<Item=(T, X)>,
    T: AppendTuple<X>,
{
    #[inline]
    fn next_back(&mut self) -> Option<Self::Item>
    {
        self.iter.next_back().map(|(t, x)| t.append(x))
    }
}

/// **GenericRange** is implemented by Rust's built-in range types, produced
/// by range syntax like `a..`, `..b` or `c..d`.
pub trait GenericRange {
    #[doc(hidden)]
    /// Start index (inclusive)
    fn start(&self) -> Option<usize> { None }
    #[doc(hidden)]
    /// End index (exclusive)
    fn end(&self) -> Option<usize> { None }
}

impl GenericRange for RangeFull {}

impl GenericRange for RangeFrom<usize> {
    fn start(&self) -> Option<usize> { Some(self.start) }
}

impl GenericRange for RangeTo<usize> {
    fn end(&self) -> Option<usize> { Some(self.end) }
}

impl GenericRange for Range<usize> {
    fn start(&self) -> Option<usize> { Some(self.start) }
    fn end(&self) -> Option<usize> { Some(self.end) }
}

/// Helper trait to convert usize to floating point type.
pub trait ToFloat<F> : Copy {
    #[doc(hidden)]
    /// Convert usize to float.
    fn to_float(self) -> F;
}

impl ToFloat<f32> for usize {
    fn to_float(self) -> f32 { self as f32 }
}

impl ToFloat<f64> for usize {
    fn to_float(self) -> f64 { self as f64 }
}

/// A trait for items that can *maybe* be joined together.
pub trait MendSlice : Copy
{
    #[doc(hidden)]
    /// If the slices are contiguous, return them joined into one.
    fn mend(Self, Self) -> Option<Self>;
}

impl<'a, T> MendSlice for &'a [T]
{
    fn mend(a: &'a [T], b: &'a [T]) -> Option<&'a [T]>
    {
        unsafe {
            let a_end = a.as_ptr().offset(a.len() as isize);
            if a_end == b.as_ptr() {
                Some(slice::from_raw_parts(a.as_ptr(), a.len() + b.len()))
            } else {
                None
            }
        }
    }
}

impl<'a> MendSlice for &'a str
{
    fn mend(a: &'a str, b: &'a str) -> Option<&'a str>
    {
        unsafe {
            mem::transmute(MendSlice::mend(a.as_bytes(), b.as_bytes()))
        }
    }
}
<|endoftext|>


<commit_before>//! Norms for the computation of anisotropic distance functions.
//!
//! For the fast sweeping algorithm, it is necessary to know the dual norm (convex polar) of the
//! desired norm, not the norm itself. This is captured by the trait `DualNorm`.
//!
//! The correctness of the implementation can be tested using `test_inv_dual_norm_2d` and
//! `test_inv_dual_norm_3d` functions.
use super::{max, min};

/// Trait for setting up anisotropic distance function computation.
///
/// Represents the __dual norm__ of the desired anisotropic norm.
///
/// `V` is the vector type, either `[S; 2]` or `[S; 3]` and `S` is the scalar type, usually `f64`.
///
pub trait DualNorm<V, S> {
    /// `dual_norm` returns the __dual__ norm. It must be a positively one-homogeneous function.
    fn dual_norm(&self, p: V) -> S;
    /// Solves the "inverse problem" for the norm: Given values `v_i` at points `-s_i e_i` (`e_i`
    /// is the canonical basis), find the largest value `t ≤ d` at the origin such that `||p|| ≤
    /// 1`, where `p_i = s_i (t - v_i)_+` and `||p||` is the __dual__ anisotropic norm.
    fn inv_dual_norm(&self, d: S, v: V, s: V) -> S;
}

/// Euclidean (l^2) norm
pub struct EuclideanNorm;

/// Dual norm for the max (l^∞) norm is the l^1 norm.
impl DualNorm<[f64; 2], f64> for EuclideanNorm {
    #[inline(always)]
    fn dual_norm(&self, p: [f64; 2]) -> f64 {
        (p[0] * p[0] + p[1] * p[1]).sqrt()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 2], _: [f64; 2]) -> f64 {
        let a = v[0];
        let b = v[1];

        let x = if (a - b).abs() >= 1. {
            min(a, b) + 1.
        } else {
            0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt())
        };

        min(d, x)
    }
}

/// Dual norm for the max (l^∞) norm is the l^1 norm.
impl DualNorm<[f64; 3], f64> for EuclideanNorm {
    #[inline(always)]
    fn dual_norm(&self, p: [f64; 3]) -> f64 {
        (p[0] * p[0] + p[1] * p[1] + p[2] * p[2]).sqrt()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 3], _: [f64; 3]) -> f64 {
        let (a, b, c) = {
            use std::mem::swap;
            let mut a = v[0];
            let mut b = v[1];
            let mut c = v[2];

            if a > b {
                swap(&mut a, &mut b);
            }
            if b > c {
                swap(&mut b, &mut c);
            }
            if a > b {
                swap(&mut a, &mut b);
            }

            (a, b, c)
        };

        let x = if b >= a + 1. {
            a + 1.
        } else {
            let x = 0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt());
            if x <= c {
                x
            } else {
                let v = (1. / 3.)
                    * (a + b
                        + c
                        + (3. + (a + b + c).powi(2) - 3. * (a * a + b * b + c * c)).sqrt());
                v
            }
        };

        min(d, x)
    }
}

/// l^1 (taxicab, Manhattan) norm
pub struct L1Norm;

/// Dual norm for the l^1 norm is the l^∞ norm.
impl DualNorm<[f64; 2], f64> for L1Norm {
    fn dual_norm(&self, p: [f64; 2]) -> f64 {
        max(p[0].abs(), p[1].abs())
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 2], _: [f64; 2]) -> f64 {
        min(d, min(v[0], v[1]) + 1.)
    }
}

/// Maximum (l^∞) norm
pub struct MaxNorm;

/// Dual norm for the max (l^∞) norm is the l^1 norm.
impl DualNorm<[f64; 2], f64> for MaxNorm {
    fn dual_norm(&self, p: [f64; 2]) -> f64 {
        p[0].abs() + p[1].abs()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 2], _: [f64; 2]) -> f64 {
        min(min(d, v[0] + 1.), min(v[1] + 1., 0.5 * (v[0] + v[1] + 1.)))
    }
}

/// Dual norm for the max (l^∞) norm is the l^1 norm.
impl DualNorm<[f64; 3], f64> for MaxNorm {
    fn dual_norm(&self, p: [f64; 3]) -> f64 {
        p[0].abs() + p[1].abs() + p[2].abs()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 3], _: [f64; 3]) -> f64 {
        let (a, b, c) = {
            use std::mem::swap;
            let mut a = v[0];
            let mut b = v[1];
            let mut c = v[2];

            if a > b {
                swap(&mut a, &mut b);
            }
            if b > c {
                swap(&mut b, &mut c);
            }
            if a > b {
                swap(&mut a, &mut b);
            }

            (a, b, c)
        };
        min(
            min(d, a + 1.),
            min(0.5 * (a + b + 1.), (1. / 3.) * (a + b + c + 1.)),
        )
    }
}

/// Convenience function to test the consistency of the `inv_dual_norm` implementation with
/// `dual_norm` by generating vectors on a `(n + 1)^3` grid with values in the interval [-m, m].
pub fn test_inv_dual_norm_2d<N>(norm: N, m: f64, n: u32)
where
    N: DualNorm<[f64; 2], f64>,
{
    let h = 2. * m / n as f64;

    for i in 0..(n + 1) {
        for j in 0..(n + 1) {
            let v = [i as f64 * h - m, j as f64 * h - m];
            let s = [-v[0].signum(), -v[1].signum()];
            let t = norm.inv_dual_norm(0., v, s);
            assert!(t <= 0., "returned t > d");

            let x = norm.dual_norm([s[0] * (t - v[0]).max(0.), s[1] * (t - v[1]).max(0.)]);
            if t < 0. {
                assert!((x - 1.).abs() < 1e-7, "t = {}, v = {:?}, s = {:?}", t, v, s);
            } else {
                assert!(t < 1. + 1e-7, "t = {}, v = {:?}, s = {:?}", t, v, s);
            }
        }
    }
}

/// Convenience function to test the consistency of the `inv_dual_norm` implementation with
/// `dual_norm` by generating vectors on a `(n + 1)^3` grid with values in the interval [-m, m].
pub fn test_inv_dual_norm_3d<N>(norm: N, m: f64, n: u32)
where
    N: DualNorm<[f64; 3], f64>,
{
    let h = 2. * m / n as f64;

    for i in 0..(n + 1) {
        for j in 0..(n + 1) {
            for k in 0..(n + 1) {
                let v = [i as f64 * h - m, j as f64 * h - m, k as f64 * h - m];
                let s = [-v[0].signum(), -v[1].signum(), -v[2].signum()];
                let t = norm.inv_dual_norm(0., v, s);
                assert!(t <= 0.);

                let x = norm.dual_norm([
                    s[0] * (t - v[0]).max(0.),
                    s[1] * (t - v[1]).max(0.),
                    s[2] * (t - v[2]).max(0.),
                ]);
                if t < 0. {
                    assert!(
                        (x - 1.).abs() < 1e-7,
                        "dual_norm = {}, t = {}, v = {:?}, s = {:?}",
                        x,
                        t,
                        v,
                        s
                    );
                } else {
                    assert!(
                        t < 1. + 1e-7,
                        "dual_norm = {}, t = {}, v = {:?}, s = {:?}",
                        x,
                        t,
                        v,
                        s
                    );
                }
            }
        }
    }
}

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

    #[test]
    fn dual_norm_max_norm() {
        test_inv_dual_norm_2d(MaxNorm, 2., 5);
        test_inv_dual_norm_3d(MaxNorm, 2., 5);
    }

    #[test]
    fn dual_norm_euclidean_norm() {
        test_inv_dual_norm_2d(EuclideanNorm, 2., 5);
        test_inv_dual_norm_3d(EuclideanNorm, 2., 5);
    }

    #[test]
    fn dual_norm_l1_norm() {
        test_inv_dual_norm_2d(L1Norm, 2., 5);
    }
}
<commit_msg>doc tweaks<commit_after>//! Norms for the computation of anisotropic distance functions.
//!
//! For the fast sweeping algorithm, it is necessary to know the dual norm (convex polar) of the
//! desired norm, not the norm itself. This is captured by the trait `DualNorm`.
//!
//! The correctness of the implementation can be tested using `test_inv_dual_norm_2d` and
//! `test_inv_dual_norm_3d` functions.
use super::{max, min};

/// Trait for setting up anisotropic distance function computation.
///
/// Represents the __dual norm__ of the desired anisotropic norm.
///
/// `V` is the vector type, either `[S; 2]` or `[S; 3]` and `S` is the scalar type, usually `f64`.
///
pub trait DualNorm<V, S> {
    /// `dual_norm` returns the __dual__ norm. It must be a positively one-homogeneous function.
    fn dual_norm(&self, p: V) -> S;
    /// Solves the "inverse problem" for the norm: Given values `v_i` at points `-s_i e_i` (`e_i`
    /// is the canonical basis), find the largest value `t ≤ d` at the origin such that `||p|| ≤
    /// 1`, where `p_i = s_i (t - v_i)_+` and `||p||` is the __dual__ anisotropic norm.
    fn inv_dual_norm(&self, d: S, v: V, s: V) -> S;
}

/// Euclidean (l²) norm
pub struct EuclideanNorm;

/// Dual norm for the max (l∞) norm is the l¹ norm.
impl DualNorm<[f64; 2], f64> for EuclideanNorm {
    #[inline(always)]
    fn dual_norm(&self, p: [f64; 2]) -> f64 {
        (p[0] * p[0] + p[1] * p[1]).sqrt()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 2], _: [f64; 2]) -> f64 {
        let a = v[0];
        let b = v[1];

        let x = if (a - b).abs() >= 1. {
            min(a, b) + 1.
        } else {
            0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt())
        };

        min(d, x)
    }
}

/// Dual norm for the max (l∞) norm is the l¹ norm.
impl DualNorm<[f64; 3], f64> for EuclideanNorm {
    #[inline(always)]
    fn dual_norm(&self, p: [f64; 3]) -> f64 {
        (p[0] * p[0] + p[1] * p[1] + p[2] * p[2]).sqrt()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 3], _: [f64; 3]) -> f64 {
        let (a, b, c) = {
            use std::mem::swap;
            let mut a = v[0];
            let mut b = v[1];
            let mut c = v[2];

            if a > b {
                swap(&mut a, &mut b);
            }
            if b > c {
                swap(&mut b, &mut c);
            }
            if a > b {
                swap(&mut a, &mut b);
            }

            (a, b, c)
        };

        let x = if b >= a + 1. {
            a + 1.
        } else {
            let x = 0.5 * (a + b + (2. - (a - b) * (a - b)).sqrt());
            if x <= c {
                x
            } else {
                let v = (1. / 3.)
                    * (a + b
                        + c
                        + (3. + (a + b + c).powi(2) - 3. * (a * a + b * b + c * c)).sqrt());
                v
            }
        };

        min(d, x)
    }
}

/// l¹ (taxicab, Manhattan) norm
pub struct L1Norm;

/// Dual norm for the l¹ norm is the l∞ norm.
impl DualNorm<[f64; 2], f64> for L1Norm {
    fn dual_norm(&self, p: [f64; 2]) -> f64 {
        max(p[0].abs(), p[1].abs())
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 2], _: [f64; 2]) -> f64 {
        min(d, min(v[0], v[1]) + 1.)
    }
}

/// Maximum (l∞) norm
pub struct MaxNorm;

/// Dual norm for the max (l∞) norm is the l¹ norm.
impl DualNorm<[f64; 2], f64> for MaxNorm {
    fn dual_norm(&self, p: [f64; 2]) -> f64 {
        p[0].abs() + p[1].abs()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 2], _: [f64; 2]) -> f64 {
        min(min(d, v[0] + 1.), min(v[1] + 1., 0.5 * (v[0] + v[1] + 1.)))
    }
}

/// Dual norm for the max (l∞) norm is the l¹ norm.
impl DualNorm<[f64; 3], f64> for MaxNorm {
    fn dual_norm(&self, p: [f64; 3]) -> f64 {
        p[0].abs() + p[1].abs() + p[2].abs()
    }

    fn inv_dual_norm(&self, d: f64, v: [f64; 3], _: [f64; 3]) -> f64 {
        let (a, b, c) = {
            use std::mem::swap;
            let mut a = v[0];
            let mut b = v[1];
            let mut c = v[2];

            if a > b {
                swap(&mut a, &mut b);
            }
            if b > c {
                swap(&mut b, &mut c);
            }
            if a > b {
                swap(&mut a, &mut b);
            }

            (a, b, c)
        };
        min(
            min(d, a + 1.),
            min(0.5 * (a + b + 1.), (1. / 3.) * (a + b + c + 1.)),
        )
    }
}

/// Convenience function to test the consistency of the `inv_dual_norm` implementation with
/// `dual_norm` by generating vectors on a `(n + 1)^3` grid with values in the interval [-m, m].
pub fn test_inv_dual_norm_2d<N>(norm: N, m: f64, n: u32)
where
    N: DualNorm<[f64; 2], f64>,
{
    let h = 2. * m / n as f64;

    for i in 0..(n + 1) {
        for j in 0..(n + 1) {
            let v = [i as f64 * h - m, j as f64 * h - m];
            let s = [-v[0].signum(), -v[1].signum()];
            let t = norm.inv_dual_norm(0., v, s);
            assert!(t <= 0., "returned t > d");

            let x = norm.dual_norm([s[0] * (t - v[0]).max(0.), s[1] * (t - v[1]).max(0.)]);
            if t < 0. {
                assert!((x - 1.).abs() < 1e-7, "t = {}, v = {:?}, s = {:?}", t, v, s);
            } else {
                assert!(t < 1. + 1e-7, "t = {}, v = {:?}, s = {:?}", t, v, s);
            }
        }
    }
}

/// Convenience function to test the consistency of the `inv_dual_norm` implementation with
/// `dual_norm` by generating vectors on a `(n + 1)^3` grid with values in the interval [-m, m].
pub fn test_inv_dual_norm_3d<N>(norm: N, m: f64, n: u32)
where
    N: DualNorm<[f64; 3], f64>,
{
    let h = 2. * m / n as f64;

    for i in 0..(n + 1) {
        for j in 0..(n + 1) {
            for k in 0..(n + 1) {
                let v = [i as f64 * h - m, j as f64 * h - m, k as f64 * h - m];
                let s = [-v[0].signum(), -v[1].signum(), -v[2].signum()];
                let t = norm.inv_dual_norm(0., v, s);
                assert!(t <= 0.);

                let x = norm.dual_norm([
                    s[0] * (t - v[0]).max(0.),
                    s[1] * (t - v[1]).max(0.),
                    s[2] * (t - v[2]).max(0.),
                ]);
                if t < 0. {
                    assert!(
                        (x - 1.).abs() < 1e-7,
                        "dual_norm = {}, t = {}, v = {:?}, s = {:?}",
                        x,
                        t,
                        v,
                        s
                    );
                } else {
                    assert!(
                        t < 1. + 1e-7,
                        "dual_norm = {}, t = {}, v = {:?}, s = {:?}",
                        x,
                        t,
                        v,
                        s
                    );
                }
            }
        }
    }
}

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

    #[test]
    fn dual_norm_max_norm() {
        test_inv_dual_norm_2d(MaxNorm, 2., 5);
        test_inv_dual_norm_3d(MaxNorm, 2., 5);
    }

    #[test]
    fn dual_norm_euclidean_norm() {
        test_inv_dual_norm_2d(EuclideanNorm, 2., 5);
        test_inv_dual_norm_3d(EuclideanNorm, 2., 5);
    }

    #[test]
    fn dual_norm_l1_norm() {
        test_inv_dual_norm_2d(L1Norm, 2., 5);
    }
}
<|endoftext|>


<commit_before>use std::iter::Peekable;
use std::str::CharIndices;

use {Error, Result};

/// The data attribute of a path.
///
/// http://www.w3.org/TR/SVG/paths.html#PathData
pub struct Data {
    commands: Vec<Command>,
}

/// A command used to draw a path.
#[derive(Debug)]
pub enum Command {
    /// [Establish][1] a new current point.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataMovetoCommands
    MoveTo(Positioning, Vec<f64>),

    /// [End][1] the current subpath.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand
    ClosePath,

    /// [Draw][1] straight lines.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands
    LineTo(Positioning, Vec<f64>),

    /// [Draw][1] horizontal lines.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands
    HorizontalLineTo(Positioning, Vec<f64>),

    /// [Draw][1] vertical lines.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands
    VerticalLineTo(Positioning, Vec<f64>),

    /// [Draw][1] a cubic Bézier curve.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands
    CurveTo(Positioning, Vec<f64>),

    /// [Draw][1] a cubic Bézier curve assuming the first control point to be
    /// the reflection of the second control point on the previous command
    /// relative to the current point.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands
    SmoothCurveTo(Positioning, Vec<f64>),

    /// [Draw][1] a quadratic Bézier curve.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands
    QuadraticBezierCurveTo(Positioning, Vec<f64>),

    /// [Draw][1] a quadratic Bézier curve assuming the control point to be the
    /// reflection of the control point on the previous command relative to the
    /// current point.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands
    SmoothQuadraticBezierCurveTo(Positioning, Vec<f64>),

    /// [Draw][1] an elliptical arc.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
    EllipticalArc(Positioning, Vec<f64>),
}

/// An attribute of a command indicating whether the coordinates of the command
/// are absolute or relative to the current position.
#[derive(Debug)]
pub enum Positioning {
    Absolute,
    Relative,
}

impl Data {
    /// Parse the data attribute of a path.
    #[inline]
    pub fn parse(line: &str) -> Result<Data> {
        DataParser::new(line).process()
    }

    #[inline]
    pub fn iter(&self) -> ::std::slice::Iter<Command> {
        self.commands.iter()
    }
}

struct DataParser<'s> {
    line: &'s str,
    position: usize,
    cursor: Peekable<CharIndices<'s>>,
}

macro_rules! ok(
    ($result:expr) => (
        match $result {
            Ok(result) => result,
            Err(error) => return Err(error),
        }
    )
);

macro_rules! raise(
    ($parser:expr, $($arg:tt)*) => (
        return Err(Error {
            line: 1,
            column: $parser.position,
            message: format!($($arg)*),
        })
    );
);

impl<'s> DataParser<'s> {
    fn new(line: &'s str) -> DataParser<'s> {
        DataParser {
            line: line,
            position: 0,
            cursor: line.char_indices().peekable(),
        }
    }

    fn process(&mut self) -> Result<Data> {
        let mut commands = Vec::new();

        loop {
            self.skip_whitespace();

            match ok!(self.read_command()) {
                Some(command) => commands.push(command),
                _ => break,
            }
        }

        Ok(Data {
            commands: commands,
        })
    }

    fn read_command(&mut self) -> Result<Option<Command>> {
        use self::Command::*;
        use self::Positioning::*;

        let name = match self.next() {
            Some(name) => match name {
                'A'...'Z' | 'a'...'z' => name,
                _ => raise!(self, "expected a path command"),
            },
            _ => return Ok(None),
        };

        self.skip_whitespace();

        let params = ok!(self.read_parameters());

        Ok(Some(match name {
            'M' => MoveTo(Absolute, params),
            'm' => MoveTo(Relative, params),

            'Z' | 'z' => ClosePath,

            'L' => LineTo(Absolute, params),
            'l' => LineTo(Relative, params),

            'H' => HorizontalLineTo(Absolute, params),
            'h' => HorizontalLineTo(Relative, params),

            'V' => VerticalLineTo(Absolute, params),
            'v' => VerticalLineTo(Relative, params),

            'C' => CurveTo(Absolute, params),
            'c' => CurveTo(Relative, params),

            'S' => SmoothCurveTo(Absolute, params),
            's' => SmoothCurveTo(Relative, params),

            'Q' => QuadraticBezierCurveTo(Absolute, params),
            'q' => QuadraticBezierCurveTo(Relative, params),

            'T' => SmoothQuadraticBezierCurveTo(Absolute, params),
            't' => SmoothQuadraticBezierCurveTo(Relative, params),

            'A' => EllipticalArc(Absolute, params),
            'a' => EllipticalArc(Relative, params),

            _ => raise!(self, "found an unknown path command '{}'", name),
        }))
    }

    fn read_parameters(&mut self) -> Result<Vec<f64>> {
        let mut params = Vec::new();

        loop {
            match ok!(self.read_number()) {
                Some(number) => params.push(number),
                _ => break,
            }

            self.skip_whitespace();
            self.skip(",");
        }

        Ok(params)
    }

    fn read_number(&mut self) -> Result<Option<f64>> {
        self.skip_whitespace();

        let start = self.position;

        self.skip("-");
        self.skip_digits();
        self.skip(".");
        self.skip_digits();

        let end = self.position;

        if start == end {
            return Ok(None)
        }

        let number = &self.line[start..end];

        match number.parse() {
            Ok(number) => Ok(Some(number)),
            Err(_) => raise!(self, "failed to parse a number '{}'", number),
        }
    }

    #[inline]
    fn skip_whitespace(&mut self) {
        self.skip(" \t")
    }

    #[inline]
    fn skip_digits(&mut self) {
        self.skip("0123456789")
    }

    fn skip(&mut self, chars: &str) {
        loop {
            match self.peek() {
                Some(c) => {
                    if chars.contains_char(c) {
                        self.next();
                    } else {
                        break;
                    }
                },
                _ => break,
            }
        }
    }

    #[inline]
    fn next(&mut self) -> Option<char> {
        match self.cursor.next() {
            Some((_, c)) => {
                self.position += 1;
                Some(c)
            },
            _ => None,
        }
    }

    #[inline]
    fn peek(&mut self) -> Option<char> {
        match self.cursor.peek() {
            Some(&(_, c)) => Some(c),
            _ => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{Data, DataParser};
    use super::Command::*;
    use super::Positioning::*;

    #[test]
    fn data_parser() {
        let data = Data::parse("M1,2 l3,4").ok().unwrap();

        assert_eq!(data.commands.len(), 2);

        match data.commands[0] {
            MoveTo(Absolute, ref params) => assert_eq!(*params, vec![1.0, 2.0]),
            _ => assert!(false),
        }

        match data.commands[1] {
            LineTo(Relative, ref params) => assert_eq!(*params, vec![3.0, 4.0]),
            _ => assert!(false),
        }
    }

    #[test]
    fn data_parser_read_command() {
        macro_rules! run(
            ($line:expr) => ({
                let mut parser = DataParser::new($line);
                parser.read_command().ok().unwrap().unwrap()
            });
        );

        macro_rules! test(
            ($line:expr, $command:ident, $positioning:ident, $params:expr) => (
                match run!($line) {
                    $command($positioning, params) => assert_eq!(params, $params),
                    _ => assert!(false),
                }
            );
            ($line:expr, $command:ident) => (
                match run!($line) {
                    $command => {},
                    _ => assert!(false),
                }
            );
        );

        test!("M4,2", MoveTo, Absolute, vec![4.0, 2.0]);
        test!("m4,2", MoveTo, Relative, vec![4.0, 2.0]);

        test!("Z", ClosePath);
        test!("z", ClosePath);

        test!("L7, 8  9", LineTo, Absolute, vec![7.0, 8.0, 9.0]);
        test!("l 7,8 9", LineTo, Relative, vec![7.0, 8.0, 9.0]);

        test!("H\t6,9", HorizontalLineTo, Absolute, vec![6.0, 9.0]);
        test!("h6,  \t9", HorizontalLineTo, Relative, vec![6.0, 9.0]);

        test!("V2.1,-3", VerticalLineTo, Absolute, vec![2.1, -3.0]);
        test!("v2.1 -3", VerticalLineTo, Relative, vec![2.1, -3.0]);

        test!("C0,1 0,2", CurveTo, Absolute, vec![0.0, 1.0, 0.0, 2.0]);
        test!("c0 ,1 0,  2", CurveTo, Relative, vec![0.0, 1.0, 0.0, 2.0]);

        test!("S42,0", SmoothCurveTo, Absolute, vec![42.0, 0.0]);
        test!("s \t 42,0", SmoothCurveTo, Relative, vec![42.0, 0.0]);

        test!("Q90.5 0", QuadraticBezierCurveTo, Absolute, vec![90.5, 0.0]);
        test!("q90.5, 0", QuadraticBezierCurveTo, Relative, vec![90.5, 0.0]);

        test!("T-1", SmoothQuadraticBezierCurveTo, Absolute, vec![-1.0]);
        test!("t -1", SmoothQuadraticBezierCurveTo, Relative, vec![-1.0]);

        test!("A2.6,0 -7", EllipticalArc, Absolute, vec![2.6, 0.0, -7.0]);
        test!("a 2.6 ,0 -7", EllipticalArc, Relative, vec![2.6, 0.0, -7.0]);
    }

    #[test]
    fn data_parser_read_parameters() {
        let mut parser = DataParser::new("1,2 3,4 5 6.7");
        let params = parser.read_parameters().ok().unwrap();
        assert_eq!(params, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.7]);
    }

    #[test]
    fn data_parser_read_number() {
        let lines = vec!["-1", "3", "3.14"];
        let numbers = vec![-1.0, 3.0, 3.14];

        for (line, &number) in lines.iter().zip(numbers.iter()) {
            let mut parser = DataParser::new(line);
            assert_eq!(parser.read_number().ok().unwrap().unwrap(), number);
        }
    }

    #[test]
    fn data_parser_skip_whitespace() {
        let mut parser = DataParser::new(" \t    m ");
        parser.skip_whitespace();
        assert_eq!(parser.position, 6);
    }
}
<commit_msg>Use chars instead of char_indices<commit_after>use std::iter::Peekable;
use std::str::Chars;

use {Error, Result};

/// The data attribute of a path.
///
/// http://www.w3.org/TR/SVG/paths.html#PathData
pub struct Data {
    commands: Vec<Command>,
}

/// A command used to draw a path.
#[derive(Debug)]
pub enum Command {
    /// [Establish][1] a new current point.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataMovetoCommands
    MoveTo(Positioning, Vec<f64>),

    /// [End][1] the current subpath.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand
    ClosePath,

    /// [Draw][1] straight lines.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands
    LineTo(Positioning, Vec<f64>),

    /// [Draw][1] horizontal lines.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands
    HorizontalLineTo(Positioning, Vec<f64>),

    /// [Draw][1] vertical lines.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands
    VerticalLineTo(Positioning, Vec<f64>),

    /// [Draw][1] a cubic Bézier curve.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands
    CurveTo(Positioning, Vec<f64>),

    /// [Draw][1] a cubic Bézier curve assuming the first control point to be
    /// the reflection of the second control point on the previous command
    /// relative to the current point.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands
    SmoothCurveTo(Positioning, Vec<f64>),

    /// [Draw][1] a quadratic Bézier curve.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands
    QuadraticBezierCurveTo(Positioning, Vec<f64>),

    /// [Draw][1] a quadratic Bézier curve assuming the control point to be the
    /// reflection of the control point on the previous command relative to the
    /// current point.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands
    SmoothQuadraticBezierCurveTo(Positioning, Vec<f64>),

    /// [Draw][1] an elliptical arc.
    ///
    /// [1]: http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
    EllipticalArc(Positioning, Vec<f64>),
}

/// An attribute of a command indicating whether the coordinates of the command
/// are absolute or relative to the current position.
#[derive(Debug)]
pub enum Positioning {
    Absolute,
    Relative,
}

impl Data {
    /// Parse the data attribute of a path.
    #[inline]
    pub fn parse(line: &str) -> Result<Data> {
        DataParser::new(line).process()
    }

    #[inline]
    pub fn iter(&self) -> ::std::slice::Iter<Command> {
        self.commands.iter()
    }
}

struct DataParser<'s> {
    line: &'s str,
    position: usize,
    cursor: Peekable<Chars<'s>>,
}

macro_rules! ok(
    ($result:expr) => (
        match $result {
            Ok(result) => result,
            Err(error) => return Err(error),
        }
    )
);

macro_rules! raise(
    ($parser:expr, $($arg:tt)*) => (
        return Err(Error {
            line: 1,
            column: $parser.position,
            message: format!($($arg)*),
        })
    );
);

impl<'s> DataParser<'s> {
    fn new(line: &'s str) -> DataParser<'s> {
        DataParser {
            line: line,
            position: 0,
            cursor: line.chars().peekable(),
        }
    }

    fn process(&mut self) -> Result<Data> {
        let mut commands = Vec::new();

        loop {
            self.skip_whitespace();

            match ok!(self.read_command()) {
                Some(command) => commands.push(command),
                _ => break,
            }
        }

        Ok(Data {
            commands: commands,
        })
    }

    fn read_command(&mut self) -> Result<Option<Command>> {
        use self::Command::*;
        use self::Positioning::*;

        let name = match self.next() {
            Some(name) => match name {
                'A'...'Z' | 'a'...'z' => name,
                _ => raise!(self, "expected a path command"),
            },
            _ => return Ok(None),
        };

        self.skip_whitespace();

        let params = ok!(self.read_parameters());

        Ok(Some(match name {
            'M' => MoveTo(Absolute, params),
            'm' => MoveTo(Relative, params),

            'Z' | 'z' => ClosePath,

            'L' => LineTo(Absolute, params),
            'l' => LineTo(Relative, params),

            'H' => HorizontalLineTo(Absolute, params),
            'h' => HorizontalLineTo(Relative, params),

            'V' => VerticalLineTo(Absolute, params),
            'v' => VerticalLineTo(Relative, params),

            'C' => CurveTo(Absolute, params),
            'c' => CurveTo(Relative, params),

            'S' => SmoothCurveTo(Absolute, params),
            's' => SmoothCurveTo(Relative, params),

            'Q' => QuadraticBezierCurveTo(Absolute, params),
            'q' => QuadraticBezierCurveTo(Relative, params),

            'T' => SmoothQuadraticBezierCurveTo(Absolute, params),
            't' => SmoothQuadraticBezierCurveTo(Relative, params),

            'A' => EllipticalArc(Absolute, params),
            'a' => EllipticalArc(Relative, params),

            _ => raise!(self, "found an unknown path command '{}'", name),
        }))
    }

    fn read_parameters(&mut self) -> Result<Vec<f64>> {
        let mut params = Vec::new();

        loop {
            match ok!(self.read_number()) {
                Some(number) => params.push(number),
                _ => break,
            }

            self.skip_whitespace();
            self.skip(",");
        }

        Ok(params)
    }

    fn read_number(&mut self) -> Result<Option<f64>> {
        self.skip_whitespace();

        let start = self.position;

        self.skip("-");
        self.skip_digits();
        self.skip(".");
        self.skip_digits();

        let end = self.position;

        if start == end {
            return Ok(None)
        }

        let number = &self.line[start..end];

        match number.parse() {
            Ok(number) => Ok(Some(number)),
            Err(_) => raise!(self, "failed to parse a number '{}'", number),
        }
    }

    #[inline]
    fn skip_whitespace(&mut self) {
        self.skip(" \t")
    }

    #[inline]
    fn skip_digits(&mut self) {
        self.skip("0123456789")
    }

    fn skip(&mut self, chars: &str) {
        loop {
            match self.peek() {
                Some(c) => {
                    if chars.contains_char(c) {
                        self.next();
                    } else {
                        break;
                    }
                },
                _ => break,
            }
        }
    }

    #[inline]
    fn next(&mut self) -> Option<char> {
        match self.cursor.next() {
            Some(c) => {
                self.position += 1;
                Some(c)
            },
            _ => None,
        }
    }

    #[inline]
    fn peek(&mut self) -> Option<char> {
        self.cursor.peek().and_then(|&c| Some(c))
    }
}

#[cfg(test)]
mod tests {
    use super::{Data, DataParser};
    use super::Command::*;
    use super::Positioning::*;

    #[test]
    fn data_parser() {
        let data = Data::parse("M1,2 l3,4").ok().unwrap();

        assert_eq!(data.commands.len(), 2);

        match data.commands[0] {
            MoveTo(Absolute, ref params) => assert_eq!(*params, vec![1.0, 2.0]),
            _ => assert!(false),
        }

        match data.commands[1] {
            LineTo(Relative, ref params) => assert_eq!(*params, vec![3.0, 4.0]),
            _ => assert!(false),
        }
    }

    #[test]
    fn data_parser_read_command() {
        macro_rules! run(
            ($line:expr) => ({
                let mut parser = DataParser::new($line);
                parser.read_command().ok().unwrap().unwrap()
            });
        );

        macro_rules! test(
            ($line:expr, $command:ident, $positioning:ident, $params:expr) => (
                match run!($line) {
                    $command($positioning, params) => assert_eq!(params, $params),
                    _ => assert!(false),
                }
            );
            ($line:expr, $command:ident) => (
                match run!($line) {
                    $command => {},
                    _ => assert!(false),
                }
            );
        );

        test!("M4,2", MoveTo, Absolute, vec![4.0, 2.0]);
        test!("m4,2", MoveTo, Relative, vec![4.0, 2.0]);

        test!("Z", ClosePath);
        test!("z", ClosePath);

        test!("L7, 8  9", LineTo, Absolute, vec![7.0, 8.0, 9.0]);
        test!("l 7,8 9", LineTo, Relative, vec![7.0, 8.0, 9.0]);

        test!("H\t6,9", HorizontalLineTo, Absolute, vec![6.0, 9.0]);
        test!("h6,  \t9", HorizontalLineTo, Relative, vec![6.0, 9.0]);

        test!("V2.1,-3", VerticalLineTo, Absolute, vec![2.1, -3.0]);
        test!("v2.1 -3", VerticalLineTo, Relative, vec![2.1, -3.0]);

        test!("C0,1 0,2", CurveTo, Absolute, vec![0.0, 1.0, 0.0, 2.0]);
        test!("c0 ,1 0,  2", CurveTo, Relative, vec![0.0, 1.0, 0.0, 2.0]);

        test!("S42,0", SmoothCurveTo, Absolute, vec![42.0, 0.0]);
        test!("s \t 42,0", SmoothCurveTo, Relative, vec![42.0, 0.0]);

        test!("Q90.5 0", QuadraticBezierCurveTo, Absolute, vec![90.5, 0.0]);
        test!("q90.5, 0", QuadraticBezierCurveTo, Relative, vec![90.5, 0.0]);

        test!("T-1", SmoothQuadraticBezierCurveTo, Absolute, vec![-1.0]);
        test!("t -1", SmoothQuadraticBezierCurveTo, Relative, vec![-1.0]);

        test!("A2.6,0 -7", EllipticalArc, Absolute, vec![2.6, 0.0, -7.0]);
        test!("a 2.6 ,0 -7", EllipticalArc, Relative, vec![2.6, 0.0, -7.0]);
    }

    #[test]
    fn data_parser_read_parameters() {
        let mut parser = DataParser::new("1,2 3,4 5 6.7");
        let params = parser.read_parameters().ok().unwrap();
        assert_eq!(params, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.7]);
    }

    #[test]
    fn data_parser_read_number() {
        let lines = vec!["-1", "3", "3.14"];
        let numbers = vec![-1.0, 3.0, 3.14];

        for (line, &number) in lines.iter().zip(numbers.iter()) {
            let mut parser = DataParser::new(line);
            assert_eq!(parser.read_number().ok().unwrap().unwrap(), number);
        }
    }

    #[test]
    fn data_parser_skip_whitespace() {
        let mut parser = DataParser::new(" \t    m ");
        parser.skip_whitespace();
        assert_eq!(parser.position, 6);
    }
}
<|endoftext|>