<commit_before>//! Neon is a safe Rust abstraction layer for writing native Node.js modules.

extern crate neon_sys;

mod internal;
pub mod mem;
pub mod vm;
pub mod scope;
pub mod value;
pub mod error;
pub mod buffer;

/// The module version for Node.js 4.x is 46.
// TODO detect this based on what we're compiling for.
pub const NODE_MODULE_VERSION: i32 = 46;

#[macro_export]
macro_rules! neon_module {
    ($name:ident($module:ident) $init:block) => {
        // Mark this function as a global constructor (like C++).
        // TODO Support more OSes here.
        #[cfg_attr(target_os = "linux", link_section = ".ctors")]
        #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
        #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
        pub static __LOAD_NEON_MODULE: extern "C" fn() = {
            fn $name(mut $module: $crate::vm::Module) -> $crate::vm::Result<()> $init

            extern "C" fn __load_neon_module() {
                // Put everything else in the ctor fn so the user fn can't see it.
                #[repr(C)]
                struct __NodeModule {
                    version: i32,
                    flags: u32,
                    dso_handle: *mut u8,
                    filename: *const u8,
                    register_func: Option<extern "C" fn(
                        $crate::mem::Handle<$crate::value::SomeObject>, *mut u8, *mut u8)>,
                    context_register_func: Option<extern "C" fn(
                        $crate::mem::Handle<$crate::value::SomeObject>, *mut u8, *mut u8, *mut u8)>,
                    modname: *const u8,
                    priv_data: *mut u8,
                    link: *mut __NodeModule
                }

                static mut __NODE_MODULE: __NodeModule = __NodeModule {
                    version: $crate::NODE_MODULE_VERSION,
                    flags: 0,
                    dso_handle: 0 as *mut _,
                    filename: b"neon_source.rs\0" as *const u8,
                    register_func: Some(__register_neon_module),
                    context_register_func: None,
                    modname: b"neon_module\0" as *const u8,
                    priv_data: 0 as *mut _,
                    link: 0 as *mut _
                };

                extern "C" fn __register_neon_module(
                        m: $crate::mem::Handle<$crate::value::SomeObject>, _: *mut u8, _: *mut u8) {
                    $crate::vm::Module::initialize(m, $name);
                }

                extern "C" {
                    fn node_module_register(module: *mut __NodeModule);
                }

                unsafe {
                    node_module_register(&mut __NODE_MODULE);
                }
            }

            __load_neon_module
        };
    }
}
<commit_msg>tweaking the macro UI<commit_after>//! Neon is a safe Rust abstraction layer for writing native Node.js modules.

extern crate neon_sys;

mod internal;
pub mod mem;
pub mod vm;
pub mod scope;
pub mod value;
pub mod error;
pub mod buffer;

// The module version for Node.js 4.x is 46.
// FIXME: detect this based on what we're compiling for.
pub const NODE_MODULE_VERSION: i32 = 46;

#[macro_export]
macro_rules! onload {
    ($module:ident, $init:block) => {
        // Mark this function as a global constructor (like C++).
        // FIXME: Support more OSes here.
        #[cfg_attr(target_os = "linux", link_section = ".ctors")]
        #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
        #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
        pub static __LOAD_NEON_MODULE: extern "C" fn() = {
            fn __init_neon_module(mut $module: $crate::vm::Module) -> $crate::vm::Result<()> $init

            extern "C" fn __load_neon_module() {
                // Put everything else in the ctor fn so the user fn can't see it.
                #[repr(C)]
                struct __NodeModule {
                    version: i32,
                    flags: u32,
                    dso_handle: *mut u8,
                    filename: *const u8,
                    register_func: Option<extern "C" fn(
                        $crate::mem::Handle<$crate::value::SomeObject>, *mut u8, *mut u8)>,
                    context_register_func: Option<extern "C" fn(
                        $crate::mem::Handle<$crate::value::SomeObject>, *mut u8, *mut u8, *mut u8)>,
                    modname: *const u8,
                    priv_data: *mut u8,
                    link: *mut __NodeModule
                }

                static mut __NODE_MODULE: __NodeModule = __NodeModule {
                    version: $crate::NODE_MODULE_VERSION,
                    flags: 0,
                    dso_handle: 0 as *mut _,
                    filename: b"neon_source.rs\0" as *const u8,
                    register_func: Some(__register_neon_module),
                    context_register_func: None,
                    modname: b"neon_module\0" as *const u8,
                    priv_data: 0 as *mut _,
                    link: 0 as *mut _
                };

                extern "C" fn __register_neon_module(
                        m: $crate::mem::Handle<$crate::value::SomeObject>, _: *mut u8, _: *mut u8) {
                    $crate::vm::Module::initialize(m, __init_neon_module);
                }

                extern "C" {
                    fn node_module_register(module: *mut __NodeModule);
                }

                unsafe {
                    node_module_register(&mut __NODE_MODULE);
                }
            }

            __load_neon_module
        };
    }
}
<|endoftext|>


<commit_before>extern crate glob;
extern crate nix;
extern crate reqwest;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;

#[macro_use]
extern crate lazy_static;

use std::ffi::CStr;
use std::io::{BufRead, Write};
extern crate libc;

mod structs;
use structs::Config;
mod buffer;
mod ghclient;
use buffer::Buffer;
mod cstructs;
use cstructs::{Group, Passwd, Spwd};
mod runfiles;
mod statics;
use statics::{CLIENT, CONFIG};

#[allow(dead_code)]
enum NssStatus {
    TryAgain,
    Unavail,
    NotFound,
    Success,
}

impl From<NssStatus> for libc::c_int {
    fn from(status: NssStatus) -> libc::c_int {
        match status {
            NssStatus::TryAgain => -2,
            NssStatus::Unavail => -1,
            NssStatus::NotFound => 0,
            NssStatus::Success => 1,
        }
    }
}

fn string_from(cstrptr: *const libc::c_char) -> String {
    let cstr: &CStr = unsafe { CStr::from_ptr(cstrptr) };
    String::from(cstr.to_str().unwrap_or(""))
}

macro_rules! succeed {
    () => {{
        return libc::c_int::from(NssStatus::Success);
    }};
    ($finalize:expr) => {{
        $finalize;
        return libc::c_int::from(NssStatus::Success);
    }};
}

macro_rules! fail {
    ($err_no_p:ident, $err_no:expr, $return_val:expr) => {{
        unsafe { *$err_no_p = $err_no as libc::c_int };
        return libc::c_int::from($return_val);
    }};
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwnam_r(cnameptr: *const libc::c_char, pwptr: *mut Passwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                if let Some(member) = sector.members.get(&name) {
                    match unsafe {
                              (*pwptr).pack_args(&mut buffer, &member.login, member.id, sector.get_gid(), &CONFIG)
                          } {
                        Ok(_) => succeed!(),
                        Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                    }
                }
            }
        }
        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwuid_r(uid: libc::uid_t, pwptr: *mut Passwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                for member in sector.members.values() {
                    if uid == member.id as libc::uid_t {
                        match unsafe {
                                  (*pwptr).pack_args(&mut buffer, &member.login, member.id, sector.get_gid(), &CONFIG)
                              } {
                            Ok(_) => succeed!(),
                            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                        }
                    }
                }
            }
        }
        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setpwent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    };
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                for member in sector.members.values() {
                    list_file.write(format!("{}\t{}\t{}\n", member.login, member.id, sector.get_gid()).as_bytes())
                             .unwrap();
                }
            }
        }
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwent_r(pwptr: *mut Passwd, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        let id = words[1].parse::<u64>().unwrap();
        let gid = words[2].parse::<u64>().unwrap();
        match unsafe { (*pwptr).pack_args(&mut buffer, words[0], id, gid, &CONFIG) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endpwent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getspnam_r(cnameptr: *const libc::c_char, spptr: *mut Spwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                if let Some(member) = sector.members.get(&name) {
                    match unsafe { (*spptr).pack_args(&mut buffer, &member.login, &CONFIG) } {
                        Ok(_) => succeed!(),
                        Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                    }
                }
            }
        }

        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setspent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    };
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                for member in sector.members.values() {
                    list_file.write(format!("{}\t{}\n", member.login, member.id).as_bytes())
                             .unwrap();
                }
            }
        }
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getspent_r(spptr: *mut Spwd, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        match unsafe { (*spptr).pack_args(&mut buffer, words[0], &CONFIG) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endspent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrgid_r(gid: libc::gid_t, grptr: *mut Group, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                let members: Vec<&str> = sector.members.values().map(|m| m.login.as_str()).collect();
                if gid as u64 == sector.get_gid() {
                    match unsafe { (*grptr).pack_args(&mut buffer, &sector.get_group(), gid as u64, &members) } {
                        Ok(_) => succeed!(),
                        Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                    }
                }
            }
        }

        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrnam_r(cnameptr: *const libc::c_char, grptr: *mut Group, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                let members: Vec<&str> = sector.members.values().map(|m| m.login.as_str()).collect();
                if name == sector.get_group() {
                    match unsafe { (*grptr).pack_args(&mut buffer, &sector.get_group(), sector.get_gid(), &members) } {
                        Ok(_) => succeed!(),
                        Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                    }
                }
            }
        }
        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setgrent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    };

    match CLIENT.get_sectors() {
        Ok(sectors) => {
            for sector in sectors {
                let member_names = sector.members
                                         .values()
                                         .map(|x| x.login.as_str())
                                         .collect::<Vec<&str>>()
                                         .join(" ");
                list_file.write(format!("{}\t{}\t{}\n", sector.get_group(), sector.get_gid(), member_names).as_bytes())
                         .unwrap();
            }
        }

        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrent_r(grptr: *mut Group, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        let member_names: Vec<&str> = words[2].split(" ").collect();
        let gid = words[1].parse::<u64>().unwrap();
        match unsafe { (*grptr).pack_args(&mut buffer, words[0], gid, &member_names) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endgrent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}
<commit_msg>Use variable for sectors to unnest loop<commit_after>extern crate glob;
extern crate nix;
extern crate reqwest;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;

#[macro_use]
extern crate lazy_static;

use std::ffi::CStr;
use std::io::{BufRead, Write};
extern crate libc;

mod structs;
use structs::Config;
mod buffer;
mod ghclient;
use buffer::Buffer;
mod cstructs;
use cstructs::{Group, Passwd, Spwd};
mod runfiles;
mod statics;
use statics::{CLIENT, CONFIG};

#[allow(dead_code)]
enum NssStatus {
    TryAgain,
    Unavail,
    NotFound,
    Success,
}

impl From<NssStatus> for libc::c_int {
    fn from(status: NssStatus) -> libc::c_int {
        match status {
            NssStatus::TryAgain => -2,
            NssStatus::Unavail => -1,
            NssStatus::NotFound => 0,
            NssStatus::Success => 1,
        }
    }
}

fn string_from(cstrptr: *const libc::c_char) -> String {
    let cstr: &CStr = unsafe { CStr::from_ptr(cstrptr) };
    String::from(cstr.to_str().unwrap_or(""))
}

macro_rules! succeed {
    () => {{
        return libc::c_int::from(NssStatus::Success);
    }};
    ($finalize:expr) => {{
        $finalize;
        return libc::c_int::from(NssStatus::Success);
    }};
}

macro_rules! fail {
    ($err_no_p:ident, $err_no:expr, $return_val:expr) => {{
        unsafe { *$err_no_p = $err_no as libc::c_int };
        return libc::c_int::from($return_val);
    }};
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwnam_r(cnameptr: *const libc::c_char, pwptr: *mut Passwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let sectors = match CLIENT.get_sectors() {
        Ok(sectors) => sectors,
        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    };
    for sector in sectors {
        if let Some(member) = sector.members.get(&name) {
            match unsafe { (*pwptr).pack_args(&mut buffer, &member.login, member.id, sector.get_gid(), &CONFIG) } {
                Ok(_) => succeed!(),
                Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
            }
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwuid_r(uid: libc::uid_t, pwptr: *mut Passwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let sectors = match CLIENT.get_sectors() {
        Ok(sectors) => sectors,
        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    };
    for sector in sectors {
        for member in sector.members.values() {
            if uid == member.id as libc::uid_t {
                match unsafe { (*pwptr).pack_args(&mut buffer, &member.login, member.id, sector.get_gid(), &CONFIG) } {
                    Ok(_) => succeed!(),
                    Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
                }
            }
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setpwent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    };
    let sectors = match CLIENT.get_sectors() {
        Ok(sectors) => sectors,
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    };
    for sector in sectors {
        for member in sector.members.values() {
            list_file.write(format!("{}\t{}\t{}\n", member.login, member.id, sector.get_gid()).as_bytes())
                     .unwrap();
        }
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwent_r(pwptr: *mut Passwd, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        let id = words[1].parse::<u64>().unwrap();
        let gid = words[2].parse::<u64>().unwrap();
        match unsafe { (*pwptr).pack_args(&mut buffer, words[0], id, gid, &CONFIG) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endpwent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getspnam_r(cnameptr: *const libc::c_char, spptr: *mut Spwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let sectors = match CLIENT.get_sectors() {
        Ok(sectors) => sectors,
        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    };
    for sector in sectors {
        if let Some(member) = sector.members.get(&name) {
            match unsafe { (*spptr).pack_args(&mut buffer, &member.login, &CONFIG) } {
                Ok(_) => succeed!(),
                Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
            }
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setspent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    };
    let sectors = match CLIENT.get_sectors() {
        Ok(sectors) => sectors,
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    };
    for sector in sectors {
        for member in sector.members.values() {
            list_file.write(format!("{}\t{}\n", member.login, member.id).as_bytes())
                     .unwrap();
        }
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getspent_r(spptr: *mut Spwd, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        match unsafe { (*spptr).pack_args(&mut buffer, words[0], &CONFIG) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endspent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrgid_r(gid: libc::gid_t, grptr: *mut Group, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let sectors = match CLIENT.get_sectors() {
        Ok(sectors) => sectors,
        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    };
    for sector in sectors {
        let members: Vec<&str> = sector.members.values().map(|m| m.login.as_str()).collect();
        if gid as u64 == sector.get_gid() {
            match unsafe { (*grptr).pack_args(&mut buffer, &sector.get_group(), gid as u64, &members) } {
                Ok(_) => succeed!(),
                Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
            }
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrnam_r(cnameptr: *const libc::c_char, grptr: *mut Group, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let sectors = match CLIENT.get_sectors() {
        Ok(sectors) => sectors,
        Err(_) => fail!(errnop, nix::Errno::EAGAIN, NssStatus::TryAgain),
    };
    for sector in sectors {
        let members: Vec<&str> = sector.members.values().map(|m| m.login.as_str()).collect();
        if name == sector.get_group() {
            match unsafe { (*grptr).pack_args(&mut buffer, &sector.get_group(), sector.get_gid(), &members) } {
                Ok(_) => succeed!(),
                Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
            }
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setgrent() -> libc::c_int {
    let mut list_file = match runfiles::create() {
        Ok(ret) => ret,
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    };
    let sectors = match CLIENT.get_sectors() {
        Ok(sectors) => sectors,
        Err(_) => return libc::c_int::from(NssStatus::TryAgain),
    };
    for sector in sectors {
        let member_names = sector.members
                                 .values()
                                 .map(|x| x.login.as_str())
                                 .collect::<Vec<&str>>()
                                 .join(" ");
        list_file.write(format!("{}\t{}\t{}\n", sector.get_group(), sector.get_gid(), member_names).as_bytes())
                 .unwrap();
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrent_r(grptr: *mut Group, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = match runfiles::open() {
        Ok(ret) => ret,
        Err(_) => fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound),
    };
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let words: Vec<&str> = line.split("\t").collect();
        let member_names: Vec<&str> = words[2].split(" ").collect();
        let gid = words[1].parse::<u64>().unwrap();
        match unsafe { (*grptr).pack_args(&mut buffer, words[0], gid, &member_names) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, nix::Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, nix::Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endgrent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod test {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Provide a basic wrapper around std::env<commit_after>//! Access secure credentials at runtime with multiple backends.
//!
//! ```
//! use credentials;
//! use std::env;
//!
//! env::set_var("PASSWORD", "secret");
//! assert_eq!("secret", credentials::get("PASSWORD").unwrap());
//! ```

use std::convert::AsRef;
use std::env;

/// An error occurred accessing credentials.
#[derive(Clone, Copy, Debug)]
pub struct CredentialError;

/// Fetch the value of a credential.
pub fn get<K: AsRef<str>>(key: K) -> Result<String, CredentialError> {
    env::var(key.as_ref()).map_err(|_| {
        CredentialError
    })
}
<|endoftext|>


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

extern crate num_traits;

pub mod checkers;
pub mod types;
mod float_impl;

use std::marker::PhantomData;
use num_traits::Float;

//FIXME add doc comments
//FIXME proofread rustdocs, make sure the impls from float_impl are included
//FIXME implement Debug and Display for appropriate F types...

pub trait FloatChecker<F> {
    fn assert(value: F);
    fn check(value: F) -> bool;
}

pub struct NoisyFloat<F: Float, C: FloatChecker<F>> {
    value: F,
    checker: PhantomData<C>
}

//note: not implementing From<F>, because From conversion is never supposed to fail, according to the docs
impl<F: Float, C: FloatChecker<F>> NoisyFloat<F, C> {
    #[inline]
    pub fn new(value: F) -> NoisyFloat<F, C> {
        C::assert(value);
        Self::unchecked_new(value)
    }

    #[inline]
    fn unchecked_new(value: F) -> NoisyFloat<F, C> {
        NoisyFloat {
            value: value,
            checker: PhantomData
        }
    }

    #[inline]
    pub fn try_new(value: F) -> Option<NoisyFloat<F, C>> {
        if C::check(value) {
            Some(NoisyFloat {
                value: value,
                checker: PhantomData
            })
        } else {
            None
        }
    }

    #[inline]
    pub fn raw(self) -> F {
        self.value
    }
}

impl<C: FloatChecker<f32>> Into<f32> for NoisyFloat<f32, C> {
    #[inline]
    fn into(self) -> f32 {
        self.value
    }
}

impl<C: FloatChecker<f64>> Into<f64> for NoisyFloat<f64, C> {
    #[inline]
    fn into(self) -> f64 {
        self.value
    }
}

//TODO add tests
#[cfg(test)]
mod tests {
    use types::*;

    #[test]
    fn it_works() {
        n64(1.0) + n64(2.0);
    }
}
<commit_msg>added formatter implementations<commit_after>// Copyright 2016 Matthew D. Michelotti
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate num_traits;

pub mod checkers;
pub mod types;
mod float_impl;

use std::marker::PhantomData;
use std::fmt;
use num_traits::Float;

//FIXME add doc comments
//FIXME proofread rustdocs, make sure the impls from float_impl are included

pub trait FloatChecker<F> {
    fn assert(value: F);
    fn check(value: F) -> bool;
}

pub struct NoisyFloat<F: Float, C: FloatChecker<F>> {
    value: F,
    checker: PhantomData<C>
}

//note: not implementing From<F>, because From conversion is never supposed to fail, according to the docs
impl<F: Float, C: FloatChecker<F>> NoisyFloat<F, C> {
    #[inline]
    pub fn new(value: F) -> NoisyFloat<F, C> {
        C::assert(value);
        Self::unchecked_new(value)
    }

    #[inline]
    fn unchecked_new(value: F) -> NoisyFloat<F, C> {
        NoisyFloat {
            value: value,
            checker: PhantomData
        }
    }

    #[inline]
    pub fn try_new(value: F) -> Option<NoisyFloat<F, C>> {
        if C::check(value) {
            Some(NoisyFloat {
                value: value,
                checker: PhantomData
            })
        } else {
            None
        }
    }

    #[inline]
    pub fn raw(self) -> F {
        self.value
    }
}

impl<C: FloatChecker<f32>> Into<f32> for NoisyFloat<f32, C> {
    #[inline]
    fn into(self) -> f32 {
        self.value
    }
}

impl<C: FloatChecker<f64>> Into<f64> for NoisyFloat<f64, C> {
    #[inline]
    fn into(self) -> f64 {
        self.value
    }
}

impl<F: Float + fmt::Debug, C: FloatChecker<F>> fmt::Debug for NoisyFloat<F, C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::Debug::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::Display, C: FloatChecker<F>> fmt::Display for NoisyFloat<F, C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::Display::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::LowerExp, C: FloatChecker<F>> fmt::LowerExp for NoisyFloat<F, C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::LowerExp::fmt(&self.value, f)
    }
}

impl<F: Float + fmt::UpperExp, C: FloatChecker<F>> fmt::UpperExp for NoisyFloat<F, C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt::UpperExp::fmt(&self.value, f)
    }
}

//TODO add tests
#[cfg(test)]
mod tests {
    use types::*;

    #[test]
    fn it_works() {
        println!("1 + 2 = {}", n64(1.0) + n64(2.0));
    }
}
<|endoftext|>


<commit_before>#![feature(proc_macro)]

#[macro_use]
extern crate log;
extern crate hayaku_http;
#[macro_use(quick_error)]
extern crate quick_error;
extern crate regex;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

mod error;
mod trie;

use hayaku_http::{Handler, Method, Request, RequestHandler, Response, Status};

use std::collections::HashMap;

pub use error::Error;

use trie::TrieNode;

type Tree<T> = HashMap<Method, TrieNode<RequestHandler<T>>>;

#[derive(Clone)]
pub struct Router<T: Clone> {
    trees: Tree<T>,
    /// Enables automatic redirection if the current route can't be matched but
    /// a handler for the path with (without) the trailing slash exists.
    /// For example if /foo/ is requested but a route only exists for /foo, the
    /// client is redirected to /foo with http status code 301 for GET requests
    /// and 307 for all other request methods.
    pub redirect_trailing_slash: bool,
    /// If enabled, the router tries to fix the current request path, if no
    /// handle is registered for it.
    /// First superfluous path elements like ../ or // are removed.
    /// Afterwards the router does a case-insensitive lookup of the cleaned path.
    /// If a handle can be found for this route, the router makes a redirection
    /// to the corrected path with status code 301 for GET requests and 307 for
    /// all other request methods.
    /// For example /FOO and /..//Foo could be redirected to /foo.
    /// `redirect_trailing_slash` is independent of this option.
    pub redirect_fixed_path: bool,
    /// If enabled, the router checks if another method is allowed for the
    /// current route, if the current request can not be routed.
    /// If this is the case, the request is answered with `Method Not Allowed`
    /// and HTTP status code 405.
    /// If no other Method is allowed, the request is delegated to the NotFound
    /// handler.
    pub handle_method_not_allowed: bool,
    /// If enabled, the router automatically replies to OPTIONS requests.
    /// Custom OPTIONS handlers take priority over automatic replies.
    pub handle_options: bool,
    /// Configurable handler which is called when no matching route is
    /// found. If it is `None`, the default 404 handler is used.
    not_found: Option<RequestHandler<T>>,
}

impl<T: Clone> Router<T> {
    pub fn new() -> Self {
        Router {
            trees: HashMap::new(),
            redirect_trailing_slash: true,
            redirect_fixed_path: true,
            handle_method_not_allowed: true,
            handle_options: true,
            not_found: None,
        }
    }

    pub fn set_not_found_handler(&mut self, handler: RequestHandler<T>) {
        self.not_found = Some(handler);
    }

    /// `get` is a shortcut for `Self::handle(Method::Get, path, handle)`.
    pub fn get<S: Into<String>>(&mut self,
                                path: S,
                                handle: RequestHandler<T>)
                                -> Result<(), Error> {
        self.handle(Method::Get, path, handle)
    }

    /// `head` is a shortcut for `Self::handle(Method::Head, path, handle)`.
    pub fn head<S: Into<String>>(&mut self,
                                 path: S,
                                 handle: RequestHandler<T>)
                                 -> Result<(), Error> {
        self.handle(Method::Head, path, handle)
    }

    /// `options` is a shortcut for `Self::handle(Method::Options, path, handle)`.
    pub fn options<S: Into<String>>(&mut self,
                                    path: S,
                                    handle: RequestHandler<T>)
                                    -> Result<(), Error> {
        self.handle(Method::Options, path, handle)
    }

    /// `post` is a shortcut for `Self::handle(Method::Post, path, handle)`.
    pub fn post<S: Into<String>>(&mut self,
                                 path: S,
                                 handle: RequestHandler<T>)
                                 -> Result<(), Error> {
        self.handle(Method::Post, path, handle)
    }

    /// `put` is a shortcut for `Self::handle(Method::Put, path, handle)`.
    pub fn put<S: Into<String>>(&mut self,
                                path: S,
                                handle: RequestHandler<T>)
                                -> Result<(), Error> {
        self.handle(Method::Put, path, handle)
    }

    /// `patch` is a shortcut for `Self::handle(Method::Patch, path, handle)`.
    pub fn patch<S: Into<String>>(&mut self,
                                  path: S,
                                  handle: RequestHandler<T>)
                                  -> Result<(), Error> {
        self.handle(Method::Patch, path, handle)
    }

    /// `delete` is a shortcut for `Self::handle(Method::Delete, path, handle)`.
    pub fn delete<S: Into<String>>(&mut self,
                                   path: S,
                                   handle: RequestHandler<T>)
                                   -> Result<(), Error> {
        self.handle(Method::Delete, path, handle)
    }

    /// Registers a new request handle with the given path and method.
    ///
    /// For GET, POST, PUT, PATCH, and DELETE requests the respective
    /// shortcut functions can be used.
    ///
    /// This function is intended for bulk loading and to allow the usage
    /// of less frequently used, non-standardized or custom methods
    /// (e.g. for internal communication with a proxy).
    pub fn handle<S: Into<String>>(&mut self,
                                   method: Method,
                                   path: S,
                                   handle: RequestHandler<T>)
                                   -> Result<(), Error> {
        let path = path.into();
        if !path.starts_with('/') {
            return Err(Error::StartWithSlash(path.to_string()));
        }

        if self.trees.get(&method).is_none() {
            let root = TrieNode::new();
            self.trees.insert(method.clone(), root);
        }

        // TODO(nokaa): we should probably not unwrap here.
        // It may be possible for the retrieval to fail, even
        // though we check just before this.
        let mut root = self.trees.get_mut(&method).unwrap();
        root.insert(path, handle);

        Ok(())
    }
}

impl<T: Clone> Handler<T> for Router<T> {
    // Handler makes the router implement the fasthttp.ListenAndServe interface.
    fn handler(&self, req: &Request, res: &mut Response, ctx: &T) {
        let path = req.path().unwrap();
        debug!("path: {}", path);
        let method = req.method();
        debug!("method: {:?}", method);
        if let Some(root) = self.trees.get(method) {
            match root.get(path) {
                Some((val, map)) => {
                    let serialized = serde_json::to_vec(&map).unwrap();
                    *req.user_data.borrow_mut() = serialized;
                    val.unwrap()(req, res, ctx);
                }
                None => {
                    if self.not_found.is_none() {
                        // Default handler
                        res.status(Status::NotFound);
                        let msg = String::from("404, path \"") + path + "\" not found :(";
                        res.body(msg.into_bytes())
                    } else {
                        // We have already checked that self.not_found is not
                        // `None`, so unwrapping should be okay.
                        let handle = self.not_found.clone().unwrap();
                        handle(req, res, ctx);
                    }
                }
            }
        } else {
            // TODO(nokaa): We want to send a different error than 404
            // for this case. In this case we have an incorrect method being
            // used.
            if self.not_found.is_none() {
                // Default handler
                res.status(Status::NotFound);
                let msg = String::from("404, path \"") + path + "\" not found :(";
                res.body(msg.into_bytes());
            } else {
                // We have already checked that self.not_found is not
                // `None`, so unwrapping should be okay.
                let handle = self.not_found.clone().unwrap();
                handle(req, res, ctx);
            }
        }
    }
}
<commit_msg>Update for new handler interface<commit_after>#![feature(proc_macro)]

#[macro_use]
extern crate log;
extern crate hayaku_http;
#[macro_use(quick_error)]
extern crate quick_error;
extern crate regex;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

mod error;
mod trie;

use hayaku_http::{Handler, Method, Request, RequestHandler, Response, Status};

use std::collections::HashMap;

pub use error::Error;

use trie::TrieNode;

type Tree<T> = HashMap<Method, TrieNode<RequestHandler<T>>>;

#[derive(Clone)]
pub struct Router<T: Clone> {
    trees: Tree<T>,
    /// Enables automatic redirection if the current route can't be matched but
    /// a handler for the path with (without) the trailing slash exists.
    /// For example if /foo/ is requested but a route only exists for /foo, the
    /// client is redirected to /foo with http status code 301 for GET requests
    /// and 307 for all other request methods.
    pub redirect_trailing_slash: bool,
    /// If enabled, the router tries to fix the current request path, if no
    /// handle is registered for it.
    /// First superfluous path elements like ../ or // are removed.
    /// Afterwards the router does a case-insensitive lookup of the cleaned path.
    /// If a handle can be found for this route, the router makes a redirection
    /// to the corrected path with status code 301 for GET requests and 307 for
    /// all other request methods.
    /// For example /FOO and /..//Foo could be redirected to /foo.
    /// `redirect_trailing_slash` is independent of this option.
    pub redirect_fixed_path: bool,
    /// If enabled, the router checks if another method is allowed for the
    /// current route, if the current request can not be routed.
    /// If this is the case, the request is answered with `Method Not Allowed`
    /// and HTTP status code 405.
    /// If no other Method is allowed, the request is delegated to the NotFound
    /// handler.
    pub handle_method_not_allowed: bool,
    /// If enabled, the router automatically replies to OPTIONS requests.
    /// Custom OPTIONS handlers take priority over automatic replies.
    pub handle_options: bool,
    /// Configurable handler which is called when no matching route is
    /// found. If it is `None`, the default 404 handler is used.
    not_found: Option<RequestHandler<T>>,
}

impl<T: Clone> Router<T> {
    pub fn new() -> Self {
        Router {
            trees: HashMap::new(),
            redirect_trailing_slash: true,
            redirect_fixed_path: true,
            handle_method_not_allowed: true,
            handle_options: true,
            not_found: None,
        }
    }

    pub fn set_not_found_handler(&mut self, handler: RequestHandler<T>) {
        self.not_found = Some(handler);
    }

    /// `get` is a shortcut for `Self::handle(Method::Get, path, handle)`.
    pub fn get<S: Into<String>>(&mut self,
                                path: S,
                                handle: RequestHandler<T>)
                                -> Result<(), Error> {
        self.handle(Method::Get, path, handle)
    }

    /// `head` is a shortcut for `Self::handle(Method::Head, path, handle)`.
    pub fn head<S: Into<String>>(&mut self,
                                 path: S,
                                 handle: RequestHandler<T>)
                                 -> Result<(), Error> {
        self.handle(Method::Head, path, handle)
    }

    /// `options` is a shortcut for `Self::handle(Method::Options, path, handle)`.
    pub fn options<S: Into<String>>(&mut self,
                                    path: S,
                                    handle: RequestHandler<T>)
                                    -> Result<(), Error> {
        self.handle(Method::Options, path, handle)
    }

    /// `post` is a shortcut for `Self::handle(Method::Post, path, handle)`.
    pub fn post<S: Into<String>>(&mut self,
                                 path: S,
                                 handle: RequestHandler<T>)
                                 -> Result<(), Error> {
        self.handle(Method::Post, path, handle)
    }

    /// `put` is a shortcut for `Self::handle(Method::Put, path, handle)`.
    pub fn put<S: Into<String>>(&mut self,
                                path: S,
                                handle: RequestHandler<T>)
                                -> Result<(), Error> {
        self.handle(Method::Put, path, handle)
    }

    /// `patch` is a shortcut for `Self::handle(Method::Patch, path, handle)`.
    pub fn patch<S: Into<String>>(&mut self,
                                  path: S,
                                  handle: RequestHandler<T>)
                                  -> Result<(), Error> {
        self.handle(Method::Patch, path, handle)
    }

    /// `delete` is a shortcut for `Self::handle(Method::Delete, path, handle)`.
    pub fn delete<S: Into<String>>(&mut self,
                                   path: S,
                                   handle: RequestHandler<T>)
                                   -> Result<(), Error> {
        self.handle(Method::Delete, path, handle)
    }

    /// Registers a new request handle with the given path and method.
    ///
    /// For GET, POST, PUT, PATCH, and DELETE requests the respective
    /// shortcut functions can be used.
    ///
    /// This function is intended for bulk loading and to allow the usage
    /// of less frequently used, non-standardized or custom methods
    /// (e.g. for internal communication with a proxy).
    pub fn handle<S: Into<String>>(&mut self,
                                   method: Method,
                                   path: S,
                                   handle: RequestHandler<T>)
                                   -> Result<(), Error> {
        let path = path.into();
        if !path.starts_with('/') {
            return Err(Error::StartWithSlash(path.to_string()));
        }

        if self.trees.get(&method).is_none() {
            let root = TrieNode::new();
            self.trees.insert(method.clone(), root);
        }

        // TODO(nokaa): we should probably not unwrap here.
        // It may be possible for the retrieval to fail, even
        // though we check just before this.
        let mut root = self.trees.get_mut(&method).unwrap();
        root.insert(path, handle);

        Ok(())
    }
}

impl<T: Clone> Handler<T> for Router<T> {
    // Handler makes the router implement the fasthttp.ListenAndServe interface.
    fn handler(&self, req: Request, res: &mut Response, ctx: &T) {
        let path = req.path().unwrap();
        debug!("path: {}", path);
        let method = req.method().clone();
        debug!("method: {:?}", method);
        if let Some(root) = self.trees.get(&method) {
            match root.get(&path) {
                Some((val, map)) => {
                    let serialized = serde_json::to_vec(&map).unwrap();
                    *req.user_data.borrow_mut() = serialized;
                    val.unwrap()(req, res, ctx);
                }
                None => {
                    if self.not_found.is_none() {
                        // Default handler
                        res.status(Status::NotFound);
                        let msg = String::from("404, path \"") + &path + "\" not found :(";
                        res.body(msg.into_bytes())
                    } else {
                        // We have already checked that self.not_found is not
                        // `None`, so unwrapping should be okay.
                        let handle = self.not_found.clone().unwrap();
                        handle(req, res, ctx);
                    }
                }
            }
        } else {
            // TODO(nokaa): We want to send a different error than 404
            // for this case. In this case we have an incorrect method being
            // used.
            if self.not_found.is_none() {
                // Default handler
                res.status(Status::NotFound);
                let msg = String::from("404, path \"") + &path + "\" not found :(";
                res.body(msg.into_bytes());
            } else {
                // We have already checked that self.not_found is not
                // `None`, so unwrapping should be okay.
                let handle = self.not_found.clone().unwrap();
                handle(req, res, ctx);
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;

use clap::{Parser, ValueEnum};

pub type Piece = Vec<[i32; 3]>;
pub type Puzzle = Vec<Piece>;

/// Program to display the 3x3 cube solution(s).
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
    /// What puzzle to solve.
    #[arg(value_enum, default_value_t = PuzzleOption::Minotaur)]
    puzzle: PuzzleOption,
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
enum PuzzleOption {
    /// blue
    Blue,
    /// green
    Green,
    /// minotaur
    Minotaur,
    /// orange
    Orange,
}

pub fn choose_puzzle() -> Puzzle {
    let cli = Cli::parse();

    match cli.puzzle {
        PuzzleOption::Blue => blue(),
        PuzzleOption::Green => green(),
        PuzzleOption::Minotaur => minotaur(),
        PuzzleOption::Orange => orange(),
    }
}

pub fn blue() -> Puzzle {
    let mut blue = Vec::new();

    blue.push(vec![[2, 0, 2], [2, 1, 2], [2, 2, 2]]);

    let piece_2 = vec![[1, 0, 2], [1, 1, 1], [1, 1, 2], [2, 0, 2]];
    for _ in 0..3 {
        blue.push(piece_2.clone());
    }

    let piece_3 = vec![[1, 0, 2], [1, 1, 2], [2, 0, 1], [2, 0, 2]];
    for _ in 0..3 {
        blue.push(piece_3.clone());
    }

    blue
}

// Is wrong, has a volume of 28.
pub fn green() -> Puzzle {
    let mut green = Vec::new();
    green.push(vec![[2, 1, 3], [2, 2, 3], [2, 3, 3], [3, 1, 3]]);
    for _ in 0..2 {
        green.push(vec![[2, 2, 3], [3, 1, 2], [3, 1, 3], [3, 2, 3]]);
    }
    green.push(vec![[1, 1, 3], [2, 1, 3], [2, 2, 2], [2, 2, 3], [3, 2, 2]]);
    green.push(vec![[2, 1, 3], [3, 1, 3], [3, 2, 1], [3, 2, 2], [3, 2, 3]]);
    green.push(vec![[2, 1, 1], [2, 1, 2], [2, 1, 3], [2, 2, 3], [2, 3, 3], [3, 1, 1]]);
    green
}

pub fn minotaur() -> Puzzle {
    let mut minotaur = Vec::new();
    minotaur.push(vec![[1, 2, 1], [2, 2, 1], [2, 1, 1], [2, 1, 2]]);
    minotaur.push(vec![[1, 2, 1], [2, 2, 1], [2, 2, 2], [2, 1, 2]]);
    minotaur.push(vec![[1, 1, 1], [2, 1, 1], [3, 1, 1], [2, 2, 1]]);
    minotaur.push(vec![[1, 1, 2], [1, 2, 2], [1, 2, 1], [1, 3, 1], [2, 2, 1]]);
    minotaur.push(vec![[1, 3, 1], [2, 1, 2], [2, 2, 2], [2, 2, 1], [2, 3, 1]]);
    minotaur.push(vec![[1, 1, 1], [1, 2, 1], [1, 3, 1], [2, 1, 1], [1, 2, 2]]);
    minotaur
}

pub fn orange() -> Puzzle {
    let mut orange = Vec::new();
    orange.push(vec![[2, 1, 2], [2, 2, 2], [2, 2, 3], [3, 1, 2]]);
    for _ in 0..2 {
        orange.push(vec![[1, 1, 3], [2, 1, 3], [3, 1, 3], [3, 2, 3]]);
    }
    orange.push(vec![[1, 1, 3], [2, 1, 3], [3, 1, 2], [3, 1, 3], [3, 2, 3]]);
    for _ in 0..2 {
        orange.push(vec![[1, 1, 3], [2, 1, 3], [3, 1, 3], [3, 2, 2], [3, 2, 3]]);
    }
    orange
}<commit_msg>Solve the harder pieces first.<commit_after>extern crate clap;

use clap::{Parser, ValueEnum};

pub type Piece = Vec<[i32; 3]>;
pub type Puzzle = Vec<Piece>;

/// Program to display the 3x3 cube solution(s).
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
    /// What puzzle to solve.
    #[arg(value_enum, default_value_t = PuzzleOption::Minotaur)]
    puzzle: PuzzleOption,
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
enum PuzzleOption {
    /// blue
    Blue,
    /// green
    Green,
    /// minotaur
    Minotaur,
    /// orange
    Orange,
}

pub fn choose_puzzle() -> Puzzle {
    let cli = Cli::parse();

    match cli.puzzle {
        PuzzleOption::Blue => blue(),
        PuzzleOption::Green => green(),
        PuzzleOption::Minotaur => minotaur(),
        PuzzleOption::Orange => orange(),
    }
}

pub fn blue() -> Puzzle {
    let mut blue = Vec::new();

    let piece_2 = vec![[1, 0, 2], [1, 1, 1], [1, 1, 2], [2, 0, 2]];
    for _ in 0..3 {
        blue.push(piece_2.clone());
    }

    let piece_3 = vec![[1, 0, 2], [1, 1, 2], [2, 0, 1], [2, 0, 2]];
    for _ in 0..3 {
        blue.push(piece_3.clone());
    }

    blue.push(vec![[2, 0, 2], [2, 1, 2], [2, 2, 2]]);
    blue
}

// Is wrong, has a volume of 28.
pub fn green() -> Puzzle {
    let mut green = Vec::new();
    green.push(vec![[2, 1, 3], [2, 2, 3], [2, 3, 3], [3, 1, 3]]);
    for _ in 0..2 {
        green.push(vec![[2, 2, 3], [3, 1, 2], [3, 1, 3], [3, 2, 3]]);
    }
    green.push(vec![[1, 1, 3], [2, 1, 3], [2, 2, 2], [2, 2, 3], [3, 2, 2]]);
    green.push(vec![[2, 1, 3], [3, 1, 3], [3, 2, 1], [3, 2, 2], [3, 2, 3]]);
    green.push(vec![[2, 1, 1], [2, 1, 2], [2, 1, 3], [2, 2, 3], [2, 3, 3], [3, 1, 1]]);
    green
}

pub fn minotaur() -> Puzzle {
    let mut minotaur = Vec::new();
    minotaur.push(vec![[1, 1, 2], [1, 2, 2], [1, 2, 1], [1, 3, 1], [2, 2, 1]]);
    minotaur.push(vec![[1, 3, 1], [2, 1, 2], [2, 2, 2], [2, 2, 1], [2, 3, 1]]);
    minotaur.push(vec![[1, 1, 1], [1, 2, 1], [1, 3, 1], [2, 1, 1], [1, 2, 2]]);
    minotaur.push(vec![[1, 2, 1], [2, 2, 1], [2, 1, 1], [2, 1, 2]]);
    minotaur.push(vec![[1, 2, 1], [2, 2, 1], [2, 2, 2], [2, 1, 2]]);
    minotaur.push(vec![[1, 1, 1], [2, 1, 1], [3, 1, 1], [2, 2, 1]]);
    minotaur
}

pub fn orange() -> Puzzle {
    let mut orange = Vec::new();
    orange.push(vec![[1, 1, 3], [2, 1, 3], [3, 1, 2], [3, 1, 3], [3, 2, 3]]);
    for _ in 0..2 {
        orange.push(vec![[1, 1, 3], [2, 1, 3], [3, 1, 3], [3, 2, 2], [3, 2, 3]]);
    }
    orange.push(vec![[2, 1, 2], [2, 2, 2], [2, 2, 3], [3, 1, 2]]);
    for _ in 0..2 {
        orange.push(vec![[1, 1, 3], [2, 1, 3], [3, 1, 3], [3, 2, 3]]);
    }
    orange
}<|endoftext|>


<commit_before>//! A generic [Markov chain](https://en.wikipedia.org/wiki/Markov_chain) for almost any type. This
//! uses HashMaps internally, and so Eq and Hash are both required.
//!
//! # Examples
//!
//! ```
//! use markov::Chain;
//!
//! let mut chain = Chain::for_strings();
//! chain.feed_str("I like cats and I like dogs.");
//! println!("{}", chain.generate_str());
//! ```
//!
//! ```
//! use markov::Chain;
//!
//! let mut chain = Chain::new(0u8, 255);
//! chain.feed(vec![1u8, 2, 3, 5]).feed(vec![3u8, 9, 2]);
//! println!("{:?}", chain.generate());
//! ```
#![warn(missing_docs)]

extern crate rand;

use std::borrow::ToOwned;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::fmt::Debug;
use std::fs::File;
use std::hash::Hash;
use std::io::{BufReader, Error, ErrorKind, Result};
use std::io::prelude::*;
use std::iter::Map;
use std::path::Path;
use std::rc::Rc;
use rand::{Rng, thread_rng};

/// The definition of all types that can be used in a Chain.
pub trait Chainable: Eq + Hash {}
impl<T> Chainable for T where T: Eq + Hash {}

/// A generic [Markov chain](https://en.wikipedia.org/wiki/Markov_chain) for almost any type. This
/// uses HashMaps internally, and so Eq and Hash are both required.
#[derive(PartialEq, Debug)]
pub struct Chain<T> where T: Chainable {
    map: HashMap<Vec<Option<Rc<T>>>, HashMap<Option<Rc<T>>, usize>>,
    order: usize,
}

impl<T> Chain<T> where T: Chainable {
    /// Constructs a new Markov chain.
    pub fn new() -> Chain<T> {
        Chain {
            map: {
                let mut map = HashMap::new();
                map.insert(vec!(None; 1), HashMap::new());
                map
            },
            order: 1,
        }
    }

    /// Choose a specific Markov chain order. The order is the number of previous tokens to use
    /// as the index into the map.
    pub fn order(&mut self, order: usize) -> &mut Chain<T> {
        assert!(order > 0);
        self.order = order;
        self.map.insert(vec!(None; self.order), HashMap::new());
        self
    }

    /// Determines whether or not the chain is empty. A chain is considered empty if nothing has
    /// been fed into it.
    pub fn is_empty(&self) -> bool {
        self.map[&vec!(None; self.order)].is_empty()
    }

    /// Feeds the chain a collection of tokens. This operation is O(n) where n is the number of
    /// tokens to be fed into the chain.
    pub fn feed(&mut self, tokens: Vec<T>) -> &mut Chain<T> {
        if tokens.len() == 0 { return self }
        let mut toks = vec!(None; self.order);
        toks.extend(tokens.into_iter().map(|token| {
            Some(Rc::new(token))
        }));
        toks.push(None);
        for p in toks.windows(self.order + 1) {
            if !self.map.contains_key(&p[0..self.order].to_vec()) {
                self.map.insert(p[0..self.order].to_vec(), HashMap::new());
            }
            self.map.get_mut(&p[0..self.order].to_vec()).unwrap().add(p[self.order].clone());
        }
        self
    }

    /// Generates a collection of tokens from the chain. This operation is O(mn) where m is the
    /// length of the generated collection, and n is the number of possible states from a given
    /// state.
    pub fn generate(&self) -> Vec<Rc<T>> {
        let mut ret = Vec::new();
        let mut curs = vec!(None; self.order);
        loop {
            let next = self.map[&curs].next();
            curs = curs[1..self.order].to_vec();
            curs.push(next.clone());
            if let Some(next) = next { ret.push(next) };
            if curs[self.order - 1].is_none() { break }
        }
        ret
    }

    /// Generates a collection of tokens from the chain, starting with the given token. This
    /// operation is O(mn) where m is the length of the generated collection, and n is the number
    /// of possible states from a given state. This returns an empty vector if the token is not
    /// found.
    pub fn generate_from_token(&self, token: T) -> Vec<Rc<T>> {
        let token = Rc::new(token);
        if !self.map.contains_key(&vec!(Some(token.clone()); self.order)) { return Vec::new() }
        let mut ret = vec![token.clone()];
        let mut curs = vec!(Some(token.clone()); self.order);
        loop {
            let next = self.map[&curs].next();
            curs = curs[1..self.order].to_vec();
            curs.push(next.clone());
            if let Some(next) = next { ret.push(next) };
            if curs[self.order - 1].is_none() { break }
        }
        ret
    }

    /// Produces an infinite iterator of generated token collections.
    pub fn iter(&self) -> InfiniteChainIterator<T> {
        InfiniteChainIterator { chain: self }
    }

    /// Produces an iterator for the specified number of generated token collections.
    pub fn iter_for(&self, size: usize) -> SizedChainIterator<T> {
        SizedChainIterator { chain: self, size: size }
    }
}

impl Chain<String> {
    /// Feeds a string of text into the chain.
    pub fn feed_str(&mut self, string: &str) -> &mut Chain<String> {
        self.feed(string.split(" ").map(|s| s.to_owned()).collect())
    }

    /// Feeds a properly formatted file into the chain. This file should be formatted such that
    /// each line is a new sentence. Punctuation may be included if it is desired.
    pub fn feed_file(&mut self, path: &Path) -> &mut Chain<String> {
        let reader = BufReader::new(File::open(path).unwrap());
        for line in reader.lines() {
            let line = line.unwrap();
            let words: Vec<_> = line.split(&[' ', '\t', '\n', '\r'][..])
                                    .filter(|word| !word.is_empty())
                                    .collect();
            self.feed(words.iter().map(|&s| s.to_owned()).collect());
        }
        self
    }

    /// Converts the output of generate(...) on a String chain to a single String.
    fn vec_to_string(vec: Vec<Rc<String>>) -> String {
        let mut ret = String::new();
        for s in vec.iter() {
            ret.push_str(&s);
            ret.push_str(" ");
        }
        let len = ret.len();
        if len > 0 {
            ret.truncate(len - 1);
        }
        ret
    }

    /// Generates a random string of text.
    pub fn generate_str(&self) -> String {
        Chain::vec_to_string(self.generate())
    }

    /// Generates a random string of text starting with the desired token. This returns an empty
    /// string if the token is not found.
    pub fn generate_str_from_token(&self, string: &str) -> String {
        Chain::vec_to_string(self.generate_from_token(string.to_owned()))
    }

    /// Produces an infinite iterator of generated strings.
    pub fn str_iter(&self) -> InfiniteChainStringIterator {
        let vec_to_string: fn(Vec<Rc<String>>) -> String = Chain::vec_to_string;
        self.iter().map(vec_to_string)
    }

    /// Produces a sized iterator of generated strings.
    pub fn str_iter_for(&self, size: usize) -> SizedChainStringIterator {
        let vec_to_string: fn(Vec<Rc<String>>) -> String = Chain::vec_to_string;
        self.iter_for(size).map(vec_to_string)
    }
}

/// A sized iterator over a Markov chain of strings.
pub type SizedChainStringIterator<'a> =
Map<SizedChainIterator<'a, String>, fn(Vec<Rc<String>>) -> String>;

/// A sized iterator over a Markov chain.
pub struct SizedChainIterator<'a, T: Chainable + 'a> {
    chain: &'a Chain<T>,
    size: usize,
}

impl<'a, T> Iterator for SizedChainIterator<'a, T> where T: Chainable + 'a {
    type Item = Vec<Rc<T>>;
    fn next(&mut self) -> Option<Vec<Rc<T>>> {
        if self.size > 0 {
            self.size -= 1;
            Some(self.chain.generate())
        } else {
            None
        }
    }

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

/// An infinite iterator over a Markov chain of strings.
pub type InfiniteChainStringIterator<'a> =
Map<InfiniteChainIterator<'a, String>, fn(Vec<Rc<String>>) -> String>;

/// An infinite iterator over a Markov chain.
pub struct InfiniteChainIterator<'a, T: Chainable + 'a> {
    chain: &'a Chain<T>
}

impl<'a, T> Iterator for InfiniteChainIterator<'a, T> where T: Chainable + 'a {
    type Item = Vec<Rc<T>>;
    fn next(&mut self) -> Option<Vec<Rc<T>>> {
        Some(self.chain.generate())
    }
}

/// A collection of states for the Markov chain.
trait States<T: PartialEq> {
    /// Adds a state to this states collection.
    fn add(&mut self, token: Option<Rc<T>>);
    /// Gets the next state from this collection of states.
    fn next(&self) -> Option<Rc<T>>;
}

impl<T> States<T> for HashMap<Option<Rc<T>>, usize> where T: Chainable {
    fn add(&mut self, token: Option<Rc<T>>) {
        match self.entry(token) {
            Occupied(mut e) => *e.get_mut() += 1,
            Vacant(e) => { e.insert(1); },
        }
    }

    fn next(&self) -> Option<Rc<T>> {
        let mut sum = 0;
        for &value in self.values() {
            sum += value;
        }
        let mut rng = thread_rng();
        let cap = rng.gen_range(0, sum);
        sum = 0;
        for (key, &value) in self.iter() {
            sum += value;
            if sum > cap {
                return key.clone()
            }
        }
        unreachable!("The random number generator failed.")
    }
}

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

    #[test]
    fn new() {
        Chain::<u8>::new();
        Chain::<String>::new();
    }

    #[test]
    fn is_empty() {
        let mut chain = Chain::new();
        assert!(chain.is_empty());
        chain.feed(vec![1u8, 2, 3]);
        assert!(!chain.is_empty());
    }

    #[test]
    fn feed() {
        let mut chain = Chain::new();
        chain.feed(vec![3, 5, 10]).feed(vec![5, 12]);
    }

    #[test]
    fn generate() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        let v = chain.generate().into_iter().map(|v| *v).collect();
        assert!([vec![3, 5, 10], vec![3, 5, 12], vec![5, 10], vec![5, 12]].contains(&v));
    }

    #[test]
    fn generate_for_higher_order() {
        let mut chain = Chain::new();
        chain.order(2);
        chain.feed(vec![3u8, 5, 10]).feed(vec![2, 3, 5, 12]);
        let v = chain.generate().into_iter().map(|v| *v).collect();
        assert!([vec![3, 5, 10], vec![3, 5, 12], vec![2, 3, 5, 10], vec![2, 3, 5, 12]].contains(&v));
    }

    #[test]
    fn generate_from_token() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        let v = chain.generate_from_token(5).into_iter().map(|v| *v).collect();
        assert!([vec![5, 10], vec![5, 12]].contains(&v));
    }

    #[test]
    fn generate_from_unfound_token() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        let v: Vec<_> = chain.generate_from_token(9).into_iter().map(|v| *v).collect();
        assert_eq!(v, vec![]);
    }

    #[test]
    fn iter() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        assert_eq!(chain.iter().size_hint().1, None);
    }

    #[test]
    fn iter_for() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        assert_eq!(chain.iter_for(5).collect::<Vec<_>>().len(), 5);
    }

    #[test]
    fn feed_str() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats and dogs");
    }

    #[test]
    fn generate_str() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats").feed_str("I hate cats");
        assert!(["I like cats", "I hate cats"].contains(&&chain.generate_str()[..]));
    }

    #[test]
    fn generate_str_from_token() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats").feed_str("cats are cute");
        assert!(["cats", "cats are cute"].contains(&&chain.generate_str_from_token("cats")[..]));
    }

    #[test]
    fn generate_str_from_unfound_token() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats").feed_str("cats are cute");
        assert_eq!(chain.generate_str_from_token("test"), "");
    }

    #[test]
    fn str_iter() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats and I like dogs");
        assert_eq!(chain.str_iter().size_hint().1, None);
    }

    #[test]
    fn str_iter_for() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats and I like dogs");
        assert_eq!(chain.str_iter_for(5).collect::<Vec<_>>().len(), 5);
    }
}
<commit_msg>Fixed compilation of docs.<commit_after>//! A generic [Markov chain](https://en.wikipedia.org/wiki/Markov_chain) for almost any type. This
//! uses HashMaps internally, and so Eq and Hash are both required.
//!
//! # Examples
//!
//! ```
//! use markov::Chain;
//!
//! let mut chain = Chain::new();
//! chain.feed_str("I like cats and I like dogs.");
//! println!("{}", chain.generate_str());
//! ```
//!
//! ```
//! use markov::Chain;
//!
//! let mut chain = Chain::new();
//! chain.feed(vec![1u8, 2, 3, 5]).feed(vec![3u8, 9, 2]);
//! println!("{:?}", chain.generate());
//! ```
#![warn(missing_docs)]

extern crate rand;

use std::borrow::ToOwned;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::fmt::Debug;
use std::fs::File;
use std::hash::Hash;
use std::io::{BufReader, Error, ErrorKind, Result};
use std::io::prelude::*;
use std::iter::Map;
use std::path::Path;
use std::rc::Rc;
use rand::{Rng, thread_rng};

/// The definition of all types that can be used in a Chain.
pub trait Chainable: Eq + Hash {}
impl<T> Chainable for T where T: Eq + Hash {}

/// A generic [Markov chain](https://en.wikipedia.org/wiki/Markov_chain) for almost any type. This
/// uses HashMaps internally, and so Eq and Hash are both required.
#[derive(PartialEq, Debug)]
pub struct Chain<T> where T: Chainable {
    map: HashMap<Vec<Option<Rc<T>>>, HashMap<Option<Rc<T>>, usize>>,
    order: usize,
}

impl<T> Chain<T> where T: Chainable {
    /// Constructs a new Markov chain.
    pub fn new() -> Chain<T> {
        Chain {
            map: {
                let mut map = HashMap::new();
                map.insert(vec!(None; 1), HashMap::new());
                map
            },
            order: 1,
        }
    }

    /// Choose a specific Markov chain order. The order is the number of previous tokens to use
    /// as the index into the map.
    pub fn order(&mut self, order: usize) -> &mut Chain<T> {
        assert!(order > 0);
        self.order = order;
        self.map.insert(vec!(None; self.order), HashMap::new());
        self
    }

    /// Determines whether or not the chain is empty. A chain is considered empty if nothing has
    /// been fed into it.
    pub fn is_empty(&self) -> bool {
        self.map[&vec!(None; self.order)].is_empty()
    }

    /// Feeds the chain a collection of tokens. This operation is O(n) where n is the number of
    /// tokens to be fed into the chain.
    pub fn feed(&mut self, tokens: Vec<T>) -> &mut Chain<T> {
        if tokens.len() == 0 { return self }
        let mut toks = vec!(None; self.order);
        toks.extend(tokens.into_iter().map(|token| {
            Some(Rc::new(token))
        }));
        toks.push(None);
        for p in toks.windows(self.order + 1) {
            if !self.map.contains_key(&p[0..self.order].to_vec()) {
                self.map.insert(p[0..self.order].to_vec(), HashMap::new());
            }
            self.map.get_mut(&p[0..self.order].to_vec()).unwrap().add(p[self.order].clone());
        }
        self
    }

    /// Generates a collection of tokens from the chain. This operation is O(mn) where m is the
    /// length of the generated collection, and n is the number of possible states from a given
    /// state.
    pub fn generate(&self) -> Vec<Rc<T>> {
        let mut ret = Vec::new();
        let mut curs = vec!(None; self.order);
        loop {
            let next = self.map[&curs].next();
            curs = curs[1..self.order].to_vec();
            curs.push(next.clone());
            if let Some(next) = next { ret.push(next) };
            if curs[self.order - 1].is_none() { break }
        }
        ret
    }

    /// Generates a collection of tokens from the chain, starting with the given token. This
    /// operation is O(mn) where m is the length of the generated collection, and n is the number
    /// of possible states from a given state. This returns an empty vector if the token is not
    /// found.
    pub fn generate_from_token(&self, token: T) -> Vec<Rc<T>> {
        let token = Rc::new(token);
        if !self.map.contains_key(&vec!(Some(token.clone()); self.order)) { return Vec::new() }
        let mut ret = vec![token.clone()];
        let mut curs = vec!(Some(token.clone()); self.order);
        loop {
            let next = self.map[&curs].next();
            curs = curs[1..self.order].to_vec();
            curs.push(next.clone());
            if let Some(next) = next { ret.push(next) };
            if curs[self.order - 1].is_none() { break }
        }
        ret
    }

    /// Produces an infinite iterator of generated token collections.
    pub fn iter(&self) -> InfiniteChainIterator<T> {
        InfiniteChainIterator { chain: self }
    }

    /// Produces an iterator for the specified number of generated token collections.
    pub fn iter_for(&self, size: usize) -> SizedChainIterator<T> {
        SizedChainIterator { chain: self, size: size }
    }
}

impl Chain<String> {
    /// Feeds a string of text into the chain.
    pub fn feed_str(&mut self, string: &str) -> &mut Chain<String> {
        self.feed(string.split(" ").map(|s| s.to_owned()).collect())
    }

    /// Feeds a properly formatted file into the chain. This file should be formatted such that
    /// each line is a new sentence. Punctuation may be included if it is desired.
    pub fn feed_file(&mut self, path: &Path) -> &mut Chain<String> {
        let reader = BufReader::new(File::open(path).unwrap());
        for line in reader.lines() {
            let line = line.unwrap();
            let words: Vec<_> = line.split(&[' ', '\t', '\n', '\r'][..])
                                    .filter(|word| !word.is_empty())
                                    .collect();
            self.feed(words.iter().map(|&s| s.to_owned()).collect());
        }
        self
    }

    /// Converts the output of generate(...) on a String chain to a single String.
    fn vec_to_string(vec: Vec<Rc<String>>) -> String {
        let mut ret = String::new();
        for s in vec.iter() {
            ret.push_str(&s);
            ret.push_str(" ");
        }
        let len = ret.len();
        if len > 0 {
            ret.truncate(len - 1);
        }
        ret
    }

    /// Generates a random string of text.
    pub fn generate_str(&self) -> String {
        Chain::vec_to_string(self.generate())
    }

    /// Generates a random string of text starting with the desired token. This returns an empty
    /// string if the token is not found.
    pub fn generate_str_from_token(&self, string: &str) -> String {
        Chain::vec_to_string(self.generate_from_token(string.to_owned()))
    }

    /// Produces an infinite iterator of generated strings.
    pub fn str_iter(&self) -> InfiniteChainStringIterator {
        let vec_to_string: fn(Vec<Rc<String>>) -> String = Chain::vec_to_string;
        self.iter().map(vec_to_string)
    }

    /// Produces a sized iterator of generated strings.
    pub fn str_iter_for(&self, size: usize) -> SizedChainStringIterator {
        let vec_to_string: fn(Vec<Rc<String>>) -> String = Chain::vec_to_string;
        self.iter_for(size).map(vec_to_string)
    }
}

/// A sized iterator over a Markov chain of strings.
pub type SizedChainStringIterator<'a> =
Map<SizedChainIterator<'a, String>, fn(Vec<Rc<String>>) -> String>;

/// A sized iterator over a Markov chain.
pub struct SizedChainIterator<'a, T: Chainable + 'a> {
    chain: &'a Chain<T>,
    size: usize,
}

impl<'a, T> Iterator for SizedChainIterator<'a, T> where T: Chainable + 'a {
    type Item = Vec<Rc<T>>;
    fn next(&mut self) -> Option<Vec<Rc<T>>> {
        if self.size > 0 {
            self.size -= 1;
            Some(self.chain.generate())
        } else {
            None
        }
    }

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

/// An infinite iterator over a Markov chain of strings.
pub type InfiniteChainStringIterator<'a> =
Map<InfiniteChainIterator<'a, String>, fn(Vec<Rc<String>>) -> String>;

/// An infinite iterator over a Markov chain.
pub struct InfiniteChainIterator<'a, T: Chainable + 'a> {
    chain: &'a Chain<T>
}

impl<'a, T> Iterator for InfiniteChainIterator<'a, T> where T: Chainable + 'a {
    type Item = Vec<Rc<T>>;
    fn next(&mut self) -> Option<Vec<Rc<T>>> {
        Some(self.chain.generate())
    }
}

/// A collection of states for the Markov chain.
trait States<T: PartialEq> {
    /// Adds a state to this states collection.
    fn add(&mut self, token: Option<Rc<T>>);
    /// Gets the next state from this collection of states.
    fn next(&self) -> Option<Rc<T>>;
}

impl<T> States<T> for HashMap<Option<Rc<T>>, usize> where T: Chainable {
    fn add(&mut self, token: Option<Rc<T>>) {
        match self.entry(token) {
            Occupied(mut e) => *e.get_mut() += 1,
            Vacant(e) => { e.insert(1); },
        }
    }

    fn next(&self) -> Option<Rc<T>> {
        let mut sum = 0;
        for &value in self.values() {
            sum += value;
        }
        let mut rng = thread_rng();
        let cap = rng.gen_range(0, sum);
        sum = 0;
        for (key, &value) in self.iter() {
            sum += value;
            if sum > cap {
                return key.clone()
            }
        }
        unreachable!("The random number generator failed.")
    }
}

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

    #[test]
    fn new() {
        Chain::<u8>::new();
        Chain::<String>::new();
    }

    #[test]
    fn is_empty() {
        let mut chain = Chain::new();
        assert!(chain.is_empty());
        chain.feed(vec![1u8, 2, 3]);
        assert!(!chain.is_empty());
    }

    #[test]
    fn feed() {
        let mut chain = Chain::new();
        chain.feed(vec![3, 5, 10]).feed(vec![5, 12]);
    }

    #[test]
    fn generate() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        let v = chain.generate().into_iter().map(|v| *v).collect();
        assert!([vec![3, 5, 10], vec![3, 5, 12], vec![5, 10], vec![5, 12]].contains(&v));
    }

    #[test]
    fn generate_for_higher_order() {
        let mut chain = Chain::new();
        chain.order(2);
        chain.feed(vec![3u8, 5, 10]).feed(vec![2, 3, 5, 12]);
        let v = chain.generate().into_iter().map(|v| *v).collect();
        assert!([vec![3, 5, 10], vec![3, 5, 12], vec![2, 3, 5, 10], vec![2, 3, 5, 12]].contains(&v));
    }

    #[test]
    fn generate_from_token() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        let v = chain.generate_from_token(5).into_iter().map(|v| *v).collect();
        assert!([vec![5, 10], vec![5, 12]].contains(&v));
    }

    #[test]
    fn generate_from_unfound_token() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        let v: Vec<_> = chain.generate_from_token(9).into_iter().map(|v| *v).collect();
        assert_eq!(v, vec![]);
    }

    #[test]
    fn iter() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        assert_eq!(chain.iter().size_hint().1, None);
    }

    #[test]
    fn iter_for() {
        let mut chain = Chain::new();
        chain.feed(vec![3u8, 5, 10]).feed(vec![5, 12]);
        assert_eq!(chain.iter_for(5).collect::<Vec<_>>().len(), 5);
    }

    #[test]
    fn feed_str() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats and dogs");
    }

    #[test]
    fn generate_str() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats").feed_str("I hate cats");
        assert!(["I like cats", "I hate cats"].contains(&&chain.generate_str()[..]));
    }

    #[test]
    fn generate_str_from_token() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats").feed_str("cats are cute");
        assert!(["cats", "cats are cute"].contains(&&chain.generate_str_from_token("cats")[..]));
    }

    #[test]
    fn generate_str_from_unfound_token() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats").feed_str("cats are cute");
        assert_eq!(chain.generate_str_from_token("test"), "");
    }

    #[test]
    fn str_iter() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats and I like dogs");
        assert_eq!(chain.str_iter().size_hint().1, None);
    }

    #[test]
    fn str_iter_for() {
        let mut chain = Chain::new();
        chain.feed_str("I like cats and I like dogs");
        assert_eq!(chain.str_iter_for(5).collect::<Vec<_>>().len(), 5);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg_attr(not(test), no_std)]

//! A collection of strongly typed math tools for computer graphics with an inclination
//! towards 2d graphics and layout.
//!
//! All types are generic over the scalar type of their component (`f32`, `i32`, etc.),
//! and tagged with a generic Unit parameter which is useful to prevent mixing
//! values from different spaces. For example it should not be legal to translate
//! a screen-space position by a world-space vector and this can be expressed using
//! the generic Unit parameter.
//!
//! This unit system is not mandatory and all structures have an alias
//! with the default unit: `UnknownUnit`.
//! for example ```default::Point2D<T>``` is equivalent to ```Point2D<T, UnknownUnit>```.
//! Client code typically creates a set of aliases for each type and doesn't need
//! to deal with the specifics of typed units further. For example:
//!
//! ```rust
//! use euclid::*;
//! pub struct ScreenSpace;
//! pub type ScreenPoint = Point2D<f32, ScreenSpace>;
//! pub type ScreenSize = Size2D<f32, ScreenSpace>;
//! pub struct WorldSpace;
//! pub type WorldPoint = Point3D<f32, WorldSpace>;
//! pub type ProjectionMatrix = Transform3D<f32, WorldSpace, ScreenSpace>;
//! // etc...
//! ```
//!
//! All euclid types are marked `#[repr(C)]` in order to facilitate exposing them to
//! foreign function interfaces (provided the underlying scalar type is also `repr(C)`).
//!

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

#[cfg(feature = "mint")]
pub extern crate mint;
extern crate num_traits;
#[cfg(test)]
use std as core;

pub use angle::Angle;
pub use box2d::Box2D;
pub use length::Length;
pub use scale::Scale;
pub use transform2d::Transform2D;
pub use transform3d::Transform3D;
pub use point::{Point2D, Point3D, point2, point3};
pub use vector::{Vector2D, Vector3D, vec2, vec3};
pub use vector::{BoolVector2D, BoolVector3D, bvec2, bvec3};
pub use homogen::HomogeneousVector;
pub use nonempty::NonEmpty;

pub use rect::{rect, Rect};
pub use rigid::{RigidTransform3D};
pub use box3d::{box3d, Box3D};
pub use translation::{Translation2D, Translation3D};
pub use rotation::{Rotation2D, Rotation3D};
pub use side_offsets::SideOffsets2D;
pub use size::{Size2D, Size3D, size2, size3};
pub use trig::Trig;

#[macro_use]
mod macros;

mod angle;
pub mod approxeq;
pub mod approxord;
mod box2d;
mod homogen;
pub mod num;
mod length;
mod point;
mod rect;
mod rigid;
mod rotation;
mod scale;
mod side_offsets;
mod size;
mod transform2d;
mod transform3d;
mod translation;
mod trig;
mod vector;
mod box3d;
mod nonempty;

/// The default unit.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UnknownUnit;

pub mod default {
    //! A set of aliases for all types, tagged with the default unknown unit.

    use super::UnknownUnit;
    pub type Point2D<T> = super::Point2D<T, UnknownUnit>;
    pub type Point3D<T> = super::Point3D<T, UnknownUnit>;
    pub type Vector2D<T> = super::Vector2D<T, UnknownUnit>;
    pub type Vector3D<T> = super::Vector3D<T, UnknownUnit>;
    pub type HomogeneousVector<T> = super::HomogeneousVector<T, UnknownUnit>;
    pub type Size2D<T> = super::Size2D<T, UnknownUnit>;
    pub type Size3D<T> = super::Size3D<T, UnknownUnit>;
    pub type Rect<T> = super::Rect<T, UnknownUnit>;
    pub type Box2D<T> = super::Box2D<T, UnknownUnit>;
    pub type Box3D<T> = super::Box3D<T, UnknownUnit>;
    pub type SideOffsets2D<T> = super::SideOffsets2D<T, UnknownUnit>;
    pub type Transform2D<T> = super::Transform2D<T, UnknownUnit, UnknownUnit>;
    pub type Transform3D<T> = super::Transform3D<T, UnknownUnit, UnknownUnit>;
    pub type Rotation2D<T> = super::Rotation2D<T, UnknownUnit, UnknownUnit>;
    pub type Rotation3D<T> = super::Rotation3D<T, UnknownUnit, UnknownUnit>;
    pub type Translation3D<T> = super::Translation3D<T, UnknownUnit, UnknownUnit>;
    pub type Scale<T> = super::Scale<T, UnknownUnit, UnknownUnit>;
    pub type RigidTransform3D<T> = super::RigidTransform3D<T, UnknownUnit, UnknownUnit>;
}
<commit_msg>Auto merge of #397 - psincf:translation2D, r=nical<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg_attr(not(test), no_std)]

//! A collection of strongly typed math tools for computer graphics with an inclination
//! towards 2d graphics and layout.
//!
//! All types are generic over the scalar type of their component (`f32`, `i32`, etc.),
//! and tagged with a generic Unit parameter which is useful to prevent mixing
//! values from different spaces. For example it should not be legal to translate
//! a screen-space position by a world-space vector and this can be expressed using
//! the generic Unit parameter.
//!
//! This unit system is not mandatory and all structures have an alias
//! with the default unit: `UnknownUnit`.
//! for example ```default::Point2D<T>``` is equivalent to ```Point2D<T, UnknownUnit>```.
//! Client code typically creates a set of aliases for each type and doesn't need
//! to deal with the specifics of typed units further. For example:
//!
//! ```rust
//! use euclid::*;
//! pub struct ScreenSpace;
//! pub type ScreenPoint = Point2D<f32, ScreenSpace>;
//! pub type ScreenSize = Size2D<f32, ScreenSpace>;
//! pub struct WorldSpace;
//! pub type WorldPoint = Point3D<f32, WorldSpace>;
//! pub type ProjectionMatrix = Transform3D<f32, WorldSpace, ScreenSpace>;
//! // etc...
//! ```
//!
//! All euclid types are marked `#[repr(C)]` in order to facilitate exposing them to
//! foreign function interfaces (provided the underlying scalar type is also `repr(C)`).
//!

#[cfg(feature = "serde")]
#[macro_use]
extern crate serde;

#[cfg(feature = "mint")]
pub extern crate mint;
extern crate num_traits;
#[cfg(test)]
use std as core;

pub use angle::Angle;
pub use box2d::Box2D;
pub use length::Length;
pub use scale::Scale;
pub use transform2d::Transform2D;
pub use transform3d::Transform3D;
pub use point::{Point2D, Point3D, point2, point3};
pub use vector::{Vector2D, Vector3D, vec2, vec3};
pub use vector::{BoolVector2D, BoolVector3D, bvec2, bvec3};
pub use homogen::HomogeneousVector;
pub use nonempty::NonEmpty;

pub use rect::{rect, Rect};
pub use rigid::{RigidTransform3D};
pub use box3d::{box3d, Box3D};
pub use translation::{Translation2D, Translation3D};
pub use rotation::{Rotation2D, Rotation3D};
pub use side_offsets::SideOffsets2D;
pub use size::{Size2D, Size3D, size2, size3};
pub use trig::Trig;

#[macro_use]
mod macros;

mod angle;
pub mod approxeq;
pub mod approxord;
mod box2d;
mod homogen;
pub mod num;
mod length;
mod point;
mod rect;
mod rigid;
mod rotation;
mod scale;
mod side_offsets;
mod size;
mod transform2d;
mod transform3d;
mod translation;
mod trig;
mod vector;
mod box3d;
mod nonempty;

/// The default unit.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UnknownUnit;

pub mod default {
    //! A set of aliases for all types, tagged with the default unknown unit.

    use super::UnknownUnit;
    pub type Point2D<T> = super::Point2D<T, UnknownUnit>;
    pub type Point3D<T> = super::Point3D<T, UnknownUnit>;
    pub type Vector2D<T> = super::Vector2D<T, UnknownUnit>;
    pub type Vector3D<T> = super::Vector3D<T, UnknownUnit>;
    pub type HomogeneousVector<T> = super::HomogeneousVector<T, UnknownUnit>;
    pub type Size2D<T> = super::Size2D<T, UnknownUnit>;
    pub type Size3D<T> = super::Size3D<T, UnknownUnit>;
    pub type Rect<T> = super::Rect<T, UnknownUnit>;
    pub type Box2D<T> = super::Box2D<T, UnknownUnit>;
    pub type Box3D<T> = super::Box3D<T, UnknownUnit>;
    pub type SideOffsets2D<T> = super::SideOffsets2D<T, UnknownUnit>;
    pub type Transform2D<T> = super::Transform2D<T, UnknownUnit, UnknownUnit>;
    pub type Transform3D<T> = super::Transform3D<T, UnknownUnit, UnknownUnit>;
    pub type Rotation2D<T> = super::Rotation2D<T, UnknownUnit, UnknownUnit>;
    pub type Rotation3D<T> = super::Rotation3D<T, UnknownUnit, UnknownUnit>;
    pub type Translation2D<T> = super::Translation2D<T, UnknownUnit, UnknownUnit>;
    pub type Translation3D<T> = super::Translation3D<T, UnknownUnit, UnknownUnit>;
    pub type Scale<T> = super::Scale<T, UnknownUnit, UnknownUnit>;
    pub type RigidTransform3D<T> = super::RigidTransform3D<T, UnknownUnit, UnknownUnit>;
}
<|endoftext|>