<commit_before>#![cfg(feature = "tools")]

extern crate octavo;
extern crate clap;
extern crate rustc_serialize;

use std::io::{self, Read};
use std::fs::File;

use clap::{App, Arg};
use rustc_serialize::hex::ToHex;

use octavo::digest::*;

const ENGINES: &'static [&'static str] = &[
    "MD4",
    "MD5",
    "RIPEMD-160",
    "SHA1",
    "SHA-224",
    "SHA-256",
    "SHA-384",
    "SHA-512",
    "SHA3-224",
    "SHA3-256",
    "SHA3-384",
    "SHA3-512",
    "Tiger"
];

fn checksum<Eng: Digest + Default>(input: &mut Read, buffer_size: usize) -> String {
    let mut eng = Eng::default();
    let mut buf = vec![0; buffer_size];

    while let Ok(len) = input.read(&mut buf[..]) {
        if len == 0 { break }

        eng.update(&buf[..len]);
    }

    let mut result = vec![0; Eng::output_bytes()];
    eng.result(&mut result[..]);

    result[..].to_hex()
}

macro_rules! digest_for {
    (match $name:ident with $size:expr, $input:ident { $($val:pat => $eng:ty,)+ }) => {
        match $name {
            $($val => checksum::<$eng>(&mut $input, $size),)*
                _ => unreachable!()
        }
    }
}

fn input(name: &str) -> io::Result<Box<Read>> {
    if name == "-" { return Ok(Box::new(io::stdin())); }

    Ok(Box::new(try!(File::open(name))))
}

fn main() {
    let matches = App::new("sum")
        .arg(Arg::with_name("digest")
             .help("Select checksum engine. Defaults to SHA1.")
             .possible_values(ENGINES)
             .short("D")
             .long("digest")
             .global(true)
             .empty_values(false)
             .takes_value(true))
        .arg(Arg::with_name("FILE")
             .help("Files to compute checksums. `-` means STDIN. Defaults to STDIN.")
             .multiple(true))
        .arg(Arg::with_name("buffer size")
             .help("Size of read buffer in bytes. Defaults to 1MiB.")
             .takes_value(true)
             .long("buffer-size"))
        .get_matches();

    let engine_name = matches.value_of("digest").unwrap_or("SHA1");
    let files = matches.values_of("FILE").unwrap_or(vec!["-"]);
    let buffer_size = matches.value_of("buffer size")
        .and_then(|val| val.parse().ok())
        .unwrap_or(1024 * 1024);

    for file in files {
        let mut input: Box<Read> = input(file).unwrap();

        let result = digest_for! {
            match engine_name with buffer_size, input {
                "MD4" => md4::Md4,
                "MD5" => md5::Md5,
                "RIPEMD-160" => ripemd::Ripemd160,
                "SHA1" => sha1::Sha1,
                "SHA-224" => sha2::Sha224,
                "SHA-256" => sha2::Sha256,
                "SHA-384" => sha2::Sha384,
                "SHA-512" => sha2::Sha512,
                "SHA3-224" => sha3::Sha3224,
                "SHA3-256" => sha3::Sha3256,
                "SHA3-384" => sha3::Sha3384,
                "SHA3-512" => sha3::Sha3512,
                "Tiger" => tiger::Tiger
            }
        };

        println!("{} {}", result, file);
    }
}
<commit_msg>fix(bin/sum): fix typo<commit_after>#![cfg(feature = "tools")]

extern crate octavo;
extern crate clap;
extern crate rustc_serialize;

use std::io::{self, Read};
use std::fs::File;

use clap::{App, Arg};
use rustc_serialize::hex::ToHex;

use octavo::digest::*;

const ENGINES: &'static [&'static str] = &[
    "MD4",
    "MD5",
    "RIPEMD-160",
    "SHA1",
    "SHA-224",
    "SHA-256",
    "SHA-384",
    "SHA-512",
    "SHA3-224",
    "SHA3-256",
    "SHA3-384",
    "SHA3-512",
    "Tiger"
];

fn checksum<Eng: Digest + Default>(input: &mut Read, buffer_size: usize) -> String {
    let mut eng = Eng::default();
    let mut buf = vec![0; buffer_size];

    while let Ok(len) = input.read(&mut buf[..]) {
        if len == 0 { break }

        eng.update(&buf[..len]);
    }

    let mut result = vec![0; Eng::output_bytes()];
    eng.result(&mut result[..]);

    result[..].to_hex()
}

macro_rules! digest_for {
    (match $name:ident with $size:expr, $input:ident { $($val:pat => $eng:ty,)+ }) => {
        match $name {
            $($val => checksum::<$eng>(&mut $input, $size),)*
                _ => unreachable!()
        }
    }
}

fn input(name: &str) -> io::Result<Box<Read>> {
    if name == "-" { return Ok(Box::new(io::stdin())); }

    Ok(Box::new(try!(File::open(name))))
}

fn main() {
    let matches = App::new("sum")
        .arg(Arg::with_name("digest")
             .help("Select checksum engine. Defaults to SHA1.")
             .possible_values(ENGINES)
             .short("D")
             .long("digest")
             .global(true)
             .empty_values(false)
             .takes_value(true))
        .arg(Arg::with_name("FILE")
             .help("Files to compute checksums. `-` means STDIN. Defaults to STDIN.")
             .multiple(true))
        .arg(Arg::with_name("buffer size")
             .help("Size of read buffer in bytes. Defaults to 1MiB.")
             .takes_value(true)
             .long("buffer-size"))
        .get_matches();

    let engine_name = matches.value_of("digest").unwrap_or("SHA1");
    let files = matches.values_of("FILE").unwrap_or(vec!["-"]);
    let buffer_size = matches.value_of("buffer size")
        .and_then(|val| val.parse().ok())
        .unwrap_or(1024 * 1024);

    for file in files {
        let mut input: Box<Read> = input(file).unwrap();

        let result = digest_for! {
            match engine_name with buffer_size, input {
                "MD4" => md4::Md4,
                "MD5" => md5::Md5,
                "RIPEMD-160" => ripemd::Ripemd160,
                "SHA1" => sha1::Sha1,
                "SHA-224" => sha2::Sha224,
                "SHA-256" => sha2::Sha256,
                "SHA-384" => sha2::Sha384,
                "SHA-512" => sha2::Sha512,
                "SHA3-224" => sha3::Sha3224,
                "SHA3-256" => sha3::Sha3256,
                "SHA3-384" => sha3::Sha3384,
                "SHA3-512" => sha3::Sha3512,
                "Tiger" => tiger::Tiger,
            }
        };

        println!("{} {}", result, file);
    }
}
<|endoftext|>


<commit_before><commit_msg>implement lsm storage rename collection<commit_after><|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

use core::prelude::*;

use boxed::Box;
use cmp;
use mem;
use ptr;
use libc::consts::os::posix01::{PTHREAD_CREATE_JOINABLE, PTHREAD_STACK_MIN};
use libc;
use thunk::Thunk;
use ffi::CString;

use sys_common::stack::RED_ZONE;
use sys_common::thread::*;

pub type rust_thread = libc::pthread_t;
pub type rust_thread_return = *mut u8;
pub type StartFn = extern "C" fn(*mut libc::c_void) -> rust_thread_return;

#[no_stack_check]
pub extern fn thread_start(main: *mut libc::c_void) -> rust_thread_return {
    return start_thread(main);
}

#[cfg(all(not(target_os = "linux"), not(target_os = "macos")))]
pub mod guard {
    pub unsafe fn current() -> uint {
        0
    }

    pub unsafe fn main() -> uint {
        0
    }

    pub unsafe fn init() {
    }
}

#[cfg(any(target_os = "linux", target_os = "macos"))]
pub mod guard {
    use super::*;
    #[cfg(any(target_os = "linux", target_os = "android"))]
    use mem;
    #[cfg(any(target_os = "linux", target_os = "android"))]
    use ptr;
    use libc;
    use libc::funcs::posix88::mman::{mmap};
    use libc::consts::os::posix88::{PROT_NONE,
                                    MAP_PRIVATE,
                                    MAP_ANON,
                                    MAP_FAILED,
                                    MAP_FIXED};

    // These are initialized in init() and only read from after
    static mut PAGE_SIZE: uint = 0;
    static mut GUARD_PAGE: uint = 0;

    #[cfg(target_os = "macos")]
    unsafe fn get_stack_start() -> *mut libc::c_void {
        current() as *mut libc::c_void
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    unsafe fn get_stack_start() -> *mut libc::c_void {
        let mut attr: libc::pthread_attr_t = mem::zeroed();
        if pthread_getattr_np(pthread_self(), &mut attr) != 0 {
            panic!("failed to get thread attributes");
        }
        let mut stackaddr = ptr::null_mut();
        let mut stacksize = 0;
        if pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize) != 0 {
            panic!("failed to get stack information");
        }
        if pthread_attr_destroy(&mut attr) != 0 {
            panic!("failed to destroy thread attributes");
        }
        stackaddr
    }

    pub unsafe fn init() {
        let psize = libc::sysconf(libc::consts::os::sysconf::_SC_PAGESIZE);
        if psize == -1 {
            panic!("failed to get page size");
        }

        PAGE_SIZE = psize as uint;

        let mut stackaddr = get_stack_start();

        // Ensure stackaddr is page aligned! A parent process might
        // have reset RLIMIT_STACK to be non-page aligned. The
        // pthread_attr_getstack() reports the usable stack area
        // stackaddr < stackaddr + stacksize, so if stackaddr is not
        // page-aligned, calculate the fix such that stackaddr <
        // new_page_aligned_stackaddr < stackaddr + stacksize
        let remainder = (stackaddr as usize) % (PAGE_SIZE as usize);
        if remainder != 0 {
            stackaddr = ((stackaddr as usize) + (PAGE_SIZE as usize) - remainder)
                as *mut libc::c_void;
        }

        // Rellocate the last page of the stack.
        // This ensures SIGBUS will be raised on
        // stack overflow.
        let result = mmap(stackaddr,
                          PAGE_SIZE as libc::size_t,
                          PROT_NONE,
                          MAP_PRIVATE | MAP_ANON | MAP_FIXED,
                          -1,
                          0);

        if result != stackaddr || result == MAP_FAILED {
            panic!("failed to allocate a guard page");
        }

        let offset = if cfg!(target_os = "linux") {
            2
        } else {
            1
        };

        GUARD_PAGE = stackaddr as uint + offset * PAGE_SIZE;
    }

    pub unsafe fn main() -> uint {
        GUARD_PAGE
    }

    #[cfg(target_os = "macos")]
    pub unsafe fn current() -> uint {
        (pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
         pthread_get_stacksize_np(pthread_self())) as uint
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    pub unsafe fn current() -> uint {
        let mut attr: libc::pthread_attr_t = mem::zeroed();
        if pthread_getattr_np(pthread_self(), &mut attr) != 0 {
            panic!("failed to get thread attributes");
        }
        let mut guardsize = 0;
        if pthread_attr_getguardsize(&attr, &mut guardsize) != 0 {
            panic!("failed to get stack guard page");
        }
        if guardsize == 0 {
            panic!("there is no guard page");
        }
        let mut stackaddr = ptr::null_mut();
        let mut stacksize = 0;
        if pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize) != 0 {
            panic!("failed to get stack information");
        }
        if pthread_attr_destroy(&mut attr) != 0 {
            panic!("failed to destroy thread attributes");
        }

        stackaddr as uint + guardsize as uint
    }
}

pub unsafe fn create(stack: uint, p: Thunk) -> rust_thread {
    let mut native: libc::pthread_t = mem::zeroed();
    let mut attr: libc::pthread_attr_t = mem::zeroed();
    assert_eq!(pthread_attr_init(&mut attr), 0);
    assert_eq!(pthread_attr_setdetachstate(&mut attr,
                                           PTHREAD_CREATE_JOINABLE), 0);

    // Reserve room for the red zone, the runtime's stack of last resort.
    let stack_size = cmp::max(stack, RED_ZONE + min_stack_size(&attr) as uint);
    match pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t) {
        0 => {
        },
        libc::EINVAL => {
            // EINVAL means |stack_size| is either too small or not a
            // multiple of the system page size.  Because it's definitely
            // >= PTHREAD_STACK_MIN, it must be an alignment issue.
            // Round up to the nearest page and try again.
            let page_size = libc::sysconf(libc::_SC_PAGESIZE) as uint;
            let stack_size = (stack_size + page_size - 1) &
                             (-(page_size as int - 1) as uint - 1);
            assert_eq!(pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t), 0);
        },
        errno => {
            // This cannot really happen.
            panic!("pthread_attr_setstacksize() error: {}", errno);
        },
    };

    let arg: *mut libc::c_void = mem::transmute(box p); // must box since sizeof(p)=2*uint
    let ret = pthread_create(&mut native, &attr, thread_start, arg);
    assert_eq!(pthread_attr_destroy(&mut attr), 0);

    if ret != 0 {
        // be sure to not leak the closure
        let _p: Box<Box<FnOnce()+Send>> = mem::transmute(arg);
        panic!("failed to spawn native thread: {}", ret);
    }
    native
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub unsafe fn set_name(name: &str) {
    // pthread_setname_np() since glibc 2.12
    // availability autodetected via weak linkage
    let cname = CString::from_slice(name.as_bytes());
    type F = unsafe extern "C" fn(libc::pthread_t, *const libc::c_char) -> libc::c_int;
    extern {
        #[linkage = "extern_weak"]
        static pthread_setname_np: *const ();
    }
    if !pthread_setname_np.is_null() {
        unsafe {
            mem::transmute::<*const (), F>(pthread_setname_np)(pthread_self(), cname.as_ptr());
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
pub unsafe fn set_name(name: &str) {
    // pthread_set_name_np() since almost forever on all BSDs
    let cname = CString::from_slice(name.as_bytes());
    pthread_set_name_np(pthread_self(), cname.as_ptr());
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub unsafe fn set_name(name: &str) {
    // pthread_setname_np() since OS X 10.6 and iOS 3.2
    let cname = CString::from_slice(name.as_bytes());
    pthread_setname_np(cname.as_ptr());
}

pub unsafe fn join(native: rust_thread) {
    assert_eq!(pthread_join(native, ptr::null_mut()), 0);
}

pub unsafe fn detach(native: rust_thread) {
    assert_eq!(pthread_detach(native), 0);
}

pub unsafe fn yield_now() { assert_eq!(sched_yield(), 0); }
// glibc >= 2.15 has a __pthread_get_minstack() function that returns
// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
// storage.  We need that information to avoid blowing up when a small stack
// is created in an application with big thread-local storage requirements.
// See #6233 for rationale and details.
//
// Link weakly to the symbol for compatibility with older versions of glibc.
// Assumes that we've been dynamically linked to libpthread but that is
// currently always the case.  Note that you need to check that the symbol
// is non-null before calling it!
#[cfg(target_os = "linux")]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> libc::size_t {
    type F = unsafe extern "C" fn(*const libc::pthread_attr_t) -> libc::size_t;
    extern {
        #[linkage = "extern_weak"]
        static __pthread_get_minstack: *const ();
    }
    if __pthread_get_minstack.is_null() {
        PTHREAD_STACK_MIN
    } else {
        unsafe { mem::transmute::<*const (), F>(__pthread_get_minstack)(attr) }
    }
}

// __pthread_get_minstack() is marked as weak but extern_weak linkage is
// not supported on OS X, hence this kludge...
#[cfg(not(target_os = "linux"))]
fn min_stack_size(_: *const libc::pthread_attr_t) -> libc::size_t {
    PTHREAD_STACK_MIN
}

#[cfg(any(target_os = "linux"))]
extern {
    pub fn pthread_self() -> libc::pthread_t;
    pub fn pthread_getattr_np(native: libc::pthread_t,
                              attr: *mut libc::pthread_attr_t) -> libc::c_int;
    pub fn pthread_attr_getguardsize(attr: *const libc::pthread_attr_t,
                                     guardsize: *mut libc::size_t) -> libc::c_int;
    pub fn pthread_attr_getstack(attr: *const libc::pthread_attr_t,
                                 stackaddr: *mut *mut libc::c_void,
                                 stacksize: *mut libc::size_t) -> libc::c_int;
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
extern {
    pub fn pthread_self() -> libc::pthread_t;
    fn pthread_set_name_np(tid: libc::pthread_t, name: *const libc::c_char);
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
extern {
    pub fn pthread_self() -> libc::pthread_t;
    pub fn pthread_get_stackaddr_np(thread: libc::pthread_t) -> *mut libc::c_void;
    pub fn pthread_get_stacksize_np(thread: libc::pthread_t) -> libc::size_t;
    fn pthread_setname_np(name: *const libc::c_char) -> libc::c_int;
}

extern {
    fn pthread_create(native: *mut libc::pthread_t,
                      attr: *const libc::pthread_attr_t,
                      f: StartFn,
                      value: *mut libc::c_void) -> libc::c_int;
    fn pthread_join(native: libc::pthread_t,
                    value: *mut *mut libc::c_void) -> libc::c_int;
    fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int;
    pub fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int;
    fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
                                 stack_size: libc::size_t) -> libc::c_int;
    fn pthread_attr_setdetachstate(attr: *mut libc::pthread_attr_t,
                                   state: libc::c_int) -> libc::c_int;
    fn pthread_detach(thread: libc::pthread_t) -> libc::c_int;
    fn sched_yield() -> libc::c_int;
}
<commit_msg>Thread native name setting, fix #10302<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

use core::prelude::*;

use boxed::Box;
use cmp;
use mem;
use ptr;
use libc::consts::os::posix01::{PTHREAD_CREATE_JOINABLE, PTHREAD_STACK_MIN};
use libc;
use thunk::Thunk;
use ffi::CString;

use sys_common::stack::RED_ZONE;
use sys_common::thread::*;

pub type rust_thread = libc::pthread_t;
pub type rust_thread_return = *mut u8;
pub type StartFn = extern "C" fn(*mut libc::c_void) -> rust_thread_return;

#[no_stack_check]
pub extern fn thread_start(main: *mut libc::c_void) -> rust_thread_return {
    return start_thread(main);
}

#[cfg(all(not(target_os = "linux"), not(target_os = "macos")))]
pub mod guard {
    pub unsafe fn current() -> uint {
        0
    }

    pub unsafe fn main() -> uint {
        0
    }

    pub unsafe fn init() {
    }
}

#[cfg(any(target_os = "linux", target_os = "macos"))]
pub mod guard {
    use super::*;
    #[cfg(any(target_os = "linux", target_os = "android"))]
    use mem;
    #[cfg(any(target_os = "linux", target_os = "android"))]
    use ptr;
    use libc;
    use libc::funcs::posix88::mman::{mmap};
    use libc::consts::os::posix88::{PROT_NONE,
                                    MAP_PRIVATE,
                                    MAP_ANON,
                                    MAP_FAILED,
                                    MAP_FIXED};

    // These are initialized in init() and only read from after
    static mut PAGE_SIZE: uint = 0;
    static mut GUARD_PAGE: uint = 0;

    #[cfg(target_os = "macos")]
    unsafe fn get_stack_start() -> *mut libc::c_void {
        current() as *mut libc::c_void
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    unsafe fn get_stack_start() -> *mut libc::c_void {
        let mut attr: libc::pthread_attr_t = mem::zeroed();
        if pthread_getattr_np(pthread_self(), &mut attr) != 0 {
            panic!("failed to get thread attributes");
        }
        let mut stackaddr = ptr::null_mut();
        let mut stacksize = 0;
        if pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize) != 0 {
            panic!("failed to get stack information");
        }
        if pthread_attr_destroy(&mut attr) != 0 {
            panic!("failed to destroy thread attributes");
        }
        stackaddr
    }

    pub unsafe fn init() {
        let psize = libc::sysconf(libc::consts::os::sysconf::_SC_PAGESIZE);
        if psize == -1 {
            panic!("failed to get page size");
        }

        PAGE_SIZE = psize as uint;

        let mut stackaddr = get_stack_start();

        // Ensure stackaddr is page aligned! A parent process might
        // have reset RLIMIT_STACK to be non-page aligned. The
        // pthread_attr_getstack() reports the usable stack area
        // stackaddr < stackaddr + stacksize, so if stackaddr is not
        // page-aligned, calculate the fix such that stackaddr <
        // new_page_aligned_stackaddr < stackaddr + stacksize
        let remainder = (stackaddr as usize) % (PAGE_SIZE as usize);
        if remainder != 0 {
            stackaddr = ((stackaddr as usize) + (PAGE_SIZE as usize) - remainder)
                as *mut libc::c_void;
        }

        // Rellocate the last page of the stack.
        // This ensures SIGBUS will be raised on
        // stack overflow.
        let result = mmap(stackaddr,
                          PAGE_SIZE as libc::size_t,
                          PROT_NONE,
                          MAP_PRIVATE | MAP_ANON | MAP_FIXED,
                          -1,
                          0);

        if result != stackaddr || result == MAP_FAILED {
            panic!("failed to allocate a guard page");
        }

        let offset = if cfg!(target_os = "linux") {
            2
        } else {
            1
        };

        GUARD_PAGE = stackaddr as uint + offset * PAGE_SIZE;
    }

    pub unsafe fn main() -> uint {
        GUARD_PAGE
    }

    #[cfg(target_os = "macos")]
    pub unsafe fn current() -> uint {
        (pthread_get_stackaddr_np(pthread_self()) as libc::size_t -
         pthread_get_stacksize_np(pthread_self())) as uint
    }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    pub unsafe fn current() -> uint {
        let mut attr: libc::pthread_attr_t = mem::zeroed();
        if pthread_getattr_np(pthread_self(), &mut attr) != 0 {
            panic!("failed to get thread attributes");
        }
        let mut guardsize = 0;
        if pthread_attr_getguardsize(&attr, &mut guardsize) != 0 {
            panic!("failed to get stack guard page");
        }
        if guardsize == 0 {
            panic!("there is no guard page");
        }
        let mut stackaddr = ptr::null_mut();
        let mut stacksize = 0;
        if pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize) != 0 {
            panic!("failed to get stack information");
        }
        if pthread_attr_destroy(&mut attr) != 0 {
            panic!("failed to destroy thread attributes");
        }

        stackaddr as uint + guardsize as uint
    }
}

pub unsafe fn create(stack: uint, p: Thunk) -> rust_thread {
    let mut native: libc::pthread_t = mem::zeroed();
    let mut attr: libc::pthread_attr_t = mem::zeroed();
    assert_eq!(pthread_attr_init(&mut attr), 0);
    assert_eq!(pthread_attr_setdetachstate(&mut attr,
                                           PTHREAD_CREATE_JOINABLE), 0);

    // Reserve room for the red zone, the runtime's stack of last resort.
    let stack_size = cmp::max(stack, RED_ZONE + min_stack_size(&attr) as uint);
    match pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t) {
        0 => {
        },
        libc::EINVAL => {
            // EINVAL means |stack_size| is either too small or not a
            // multiple of the system page size.  Because it's definitely
            // >= PTHREAD_STACK_MIN, it must be an alignment issue.
            // Round up to the nearest page and try again.
            let page_size = libc::sysconf(libc::_SC_PAGESIZE) as uint;
            let stack_size = (stack_size + page_size - 1) &
                             (-(page_size as int - 1) as uint - 1);
            assert_eq!(pthread_attr_setstacksize(&mut attr, stack_size as libc::size_t), 0);
        },
        errno => {
            // This cannot really happen.
            panic!("pthread_attr_setstacksize() error: {}", errno);
        },
    };

    let arg: *mut libc::c_void = mem::transmute(box p); // must box since sizeof(p)=2*uint
    let ret = pthread_create(&mut native, &attr, thread_start, arg);
    assert_eq!(pthread_attr_destroy(&mut attr), 0);

    if ret != 0 {
        // be sure to not leak the closure
        let _p: Box<Box<FnOnce()+Send>> = mem::transmute(arg);
        panic!("failed to spawn native thread: {}", ret);
    }
    native
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub unsafe fn set_name(name: &str) {
    // pthread_setname_np() since glibc 2.12
    // availability autodetected via weak linkage
    let cname = CString::from_slice(name.as_bytes());
    type F = unsafe extern "C" fn(libc::pthread_t, *const libc::c_char) -> libc::c_int;
    extern {
        #[linkage = "extern_weak"]
        static pthread_setname_np: *const ();
    }
    if !pthread_setname_np.is_null() {
        unsafe {
            mem::transmute::<*const (), F>(pthread_setname_np)(pthread_self(), cname.as_ptr());
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
pub unsafe fn set_name(name: &str) {
    // pthread_set_name_np() since almost forever on all BSDs
    let cname = CString::from_slice(name.as_bytes());
    pthread_set_name_np(pthread_self(), cname.as_ptr());
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub unsafe fn set_name(name: &str) {
    // pthread_setname_np() since OS X 10.6 and iOS 3.2
    let cname = CString::from_slice(name.as_bytes());
    pthread_setname_np(cname.as_ptr());
}

pub unsafe fn join(native: rust_thread) {
    assert_eq!(pthread_join(native, ptr::null_mut()), 0);
}

pub unsafe fn detach(native: rust_thread) {
    assert_eq!(pthread_detach(native), 0);
}

pub unsafe fn yield_now() { assert_eq!(sched_yield(), 0); }
// glibc >= 2.15 has a __pthread_get_minstack() function that returns
// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
// storage.  We need that information to avoid blowing up when a small stack
// is created in an application with big thread-local storage requirements.
// See #6233 for rationale and details.
//
// Link weakly to the symbol for compatibility with older versions of glibc.
// Assumes that we've been dynamically linked to libpthread but that is
// currently always the case.  Note that you need to check that the symbol
// is non-null before calling it!
#[cfg(target_os = "linux")]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> libc::size_t {
    type F = unsafe extern "C" fn(*const libc::pthread_attr_t) -> libc::size_t;
    extern {
        #[linkage = "extern_weak"]
        static __pthread_get_minstack: *const ();
    }
    if __pthread_get_minstack.is_null() {
        PTHREAD_STACK_MIN
    } else {
        unsafe { mem::transmute::<*const (), F>(__pthread_get_minstack)(attr) }
    }
}

// __pthread_get_minstack() is marked as weak but extern_weak linkage is
// not supported on OS X, hence this kludge...
#[cfg(not(target_os = "linux"))]
fn min_stack_size(_: *const libc::pthread_attr_t) -> libc::size_t {
    PTHREAD_STACK_MIN
}

#[cfg(any(target_os = "linux", target_os = "android"))]
extern {
    pub fn pthread_self() -> libc::pthread_t;
    pub fn pthread_getattr_np(native: libc::pthread_t,
                              attr: *mut libc::pthread_attr_t) -> libc::c_int;
    pub fn pthread_attr_getguardsize(attr: *const libc::pthread_attr_t,
                                     guardsize: *mut libc::size_t) -> libc::c_int;
    pub fn pthread_attr_getstack(attr: *const libc::pthread_attr_t,
                                 stackaddr: *mut *mut libc::c_void,
                                 stacksize: *mut libc::size_t) -> libc::c_int;
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
extern {
    pub fn pthread_self() -> libc::pthread_t;
    fn pthread_set_name_np(tid: libc::pthread_t, name: *const libc::c_char);
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
extern {
    pub fn pthread_self() -> libc::pthread_t;
    pub fn pthread_get_stackaddr_np(thread: libc::pthread_t) -> *mut libc::c_void;
    pub fn pthread_get_stacksize_np(thread: libc::pthread_t) -> libc::size_t;
    fn pthread_setname_np(name: *const libc::c_char) -> libc::c_int;
}

extern {
    fn pthread_create(native: *mut libc::pthread_t,
                      attr: *const libc::pthread_attr_t,
                      f: StartFn,
                      value: *mut libc::c_void) -> libc::c_int;
    fn pthread_join(native: libc::pthread_t,
                    value: *mut *mut libc::c_void) -> libc::c_int;
    fn pthread_attr_init(attr: *mut libc::pthread_attr_t) -> libc::c_int;
    pub fn pthread_attr_destroy(attr: *mut libc::pthread_attr_t) -> libc::c_int;
    fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t,
                                 stack_size: libc::size_t) -> libc::c_int;
    fn pthread_attr_setdetachstate(attr: *mut libc::pthread_attr_t,
                                   state: libc::c_int) -> libc::c_int;
    fn pthread_detach(thread: libc::pthread_t) -> libc::c_int;
    fn sched_yield() -> libc::c_int;
}
<|endoftext|>


<commit_before>
// TODO: rename module to vm

use std::mem;
use std::collections::HashMap;
use std::fmt::{self, Display, Formatter};

use byteorder::*;
use itertools::*;

use lang::{Env, Ast, BindingKey, Binding, ConstType, Result};

type Endianness = NativeEndian;
type Table<K, V> = HashMap<K, V>;

type ConstTableIdx = u16;
type FnAddrT = u32;
type FnDefIdT = u32;

pub fn compile(env: &Env, ast: &[Ast]) -> Result<Program> {

    // defs are stored in env, as are fn prototypes

    let mut code = vec![];
    let mut bcode = vec![];
    let mut callsites = vec![];
    let mut jumpsites = vec![];
    let mut fn_id_to_fn_addr = Table::new();
    let mut label_id_to_addr = Table::new();
    let mut const_table = vec![];

    let mut labels = LabelGen::new();

    // toplevel codegen
    for node in ast {
        codegen(env, &mut labels, node, &mut code);
    }

    code.push(MIns::Exit);

    // fn codegen
    for def in env.fn_defs() {
        code.push(MIns::FnDefBegin(FnDefId::from(def.id())));

        for node in def.ast() {
            codegen(env, &mut labels, node, &mut code);
        }
    }

    println!("\n===\n{}\n===",
             code.iter().map(|m| format!("{:?}", m)).join("\n"));

    // TODO: opt passes here

    for mins in code {
        if mins.is_simple() {
            mins.emit(&mut bcode);
        } else {
            match mins {
                MIns::FnDefBegin(id) => {
                    fn_id_to_fn_addr.insert(id, FnAddr::from(bcode.len() as FnAddrT));
                }
                MIns::I64(val) => {
                    let idx = const_table.len() as ConstTableIdx;
                    const_table.push(val); // TODO: Slot

                    bcode.push(Ins::LoadConst.into());
                    bcode.write_u16::<Endianness>(idx).unwrap();
                }
                MIns::CallFn(id) => {
                    bcode.push(Ins::Call.into());

                    let current_idx = bcode.len();
                    callsites.push((current_idx, id));

                    bcode.write_u32::<Endianness>(0 as FnAddrT).unwrap();
                }
                MIns::Label(id) => {
                    label_id_to_addr.insert(id, FnAddr::from(bcode.len() as FnAddrT));
                }
                MIns::Jmp(id) => {
                    bcode.push(Ins::Jmp.into());
                    jumpsites.push((id, bcode.len()));
                    bcode.write_u32::<Endianness>(0 as FnAddrT).unwrap();
                }
                MIns::JmpIfFalse(id) => {
                    bcode.push(Ins::JmpF.into());
                    jumpsites.push((id, bcode.len()));
                    bcode.write_u32::<Endianness>(0 as FnAddrT).unwrap();
                }
                _ => unreachable!(),
            }
        }
    }

    // patch jumpsites
    for (id, addr) in jumpsites {
        let target_addr = label_id_to_addr[&id].into();
        Endianness::write_u32(&mut bcode[addr..addr + mem::size_of::<FnAddrT>()],
                              target_addr);
    }

    // patch callsites
    for (i, id) in callsites {
        let addr = fn_id_to_fn_addr[&id].into();
        Endianness::write_u32(&mut bcode[i..i + mem::size_of::<FnAddrT>()], addr);
    }

    Ok(Program {
        code: bcode,
        const_pool: const_table,
    })
}

struct LabelGen(u64);

impl LabelGen {
    fn new() -> Self {
        LabelGen(0)
    }

    fn new_label(&mut self) -> LabelId {
        let id = self.0;
        self.0 += 1;
        LabelId::from(id)
    }
}

fn codegen(env: &Env, labels: &mut LabelGen, ast: &Ast, code: &mut Vec<MIns>) {
    match *ast {
        Ast::I64Literal(span, val) => {
            code.push(MIns::I64(val));
        }
        Ast::BoolLiteral(span, val) => {
            code.push(MIns::Bool(val));
        }
        Ast::Atom(span, ref binding_key) => {
            let record = match *binding_key {
                BindingKey::String(ref k) => {
                    env.lookup_by_name(k).expect("no binding found by that name")
                }
                BindingKey::Id(k) => env.lookup_by_id(k),
            };

            match *record.binding() {
                // 'x' after '(def x 10)'
                Binding::Const(ConstType::I64(val)) => {
                    code.push(MIns::I64(val));
                }
                _ => unimplemented!(),
            }
        }
        Ast::EmptyList(..) => unimplemented!(),
        Ast::Do(..) => unimplemented!(),
        Ast::Fn(..) => unimplemented!(),
        Ast::If(_, ref cond_expr, ref then_expr, ref else_expr) => {
            let label1 = labels.new_label();
            let label2 = labels.new_label();

            codegen(env, labels, &**cond_expr, code);
            code.push(MIns::JmpIfFalse(label1));

            codegen(env, labels, &**then_expr, code);
            code.push(MIns::Jmp(label2));
            code.push(MIns::Label(label1));

            codegen(env, labels, &**else_expr, code);
            code.push(MIns::Label(label2));
        }
        Ast::Inv(span, ref callee, ref args) => {
            // lookup callee
            // lookup and unify args with callee sig

            let fn_def_id = unimplemented!();

            // codegen:
            // gen each arg
            // emit fn_ptr/call

            // note the order
            for arg in args.iter() {
                codegen(env, labels, arg, code);
            }

            code.push(MIns::CallFn(fn_def_id));
        }
        Ast::Let(..) => unimplemented!(),
    }
}

// macro assembler instructions
#[derive(Clone, Debug)]
enum MIns {
    I64(i64),
    Bool(bool),

    Jmp(LabelId),
    JmpIfFalse(LabelId),
    Label(LabelId),
    // num_args
    Add(usize),
    LoadLocal(u8), // idx in local table
    SaveLocal(u8), // idx in local table
    CallFn(FnDefId),
    Ret,
    Exit,

    FnPtr(FnDefId),
    CallPtr,

    FnDefBegin(FnDefId),
    MarkStack,
    PopToMark,
}

impl MIns {
    fn is_simple(&self) -> bool {
        match *self {
            MIns::FnDefBegin(..) |
            MIns::I64(..) |
            MIns::CallFn(..) |
            MIns::Jmp(..) |
            MIns::JmpIfFalse(..) |
            MIns::Label(..) => false,
            _ => true,
        }
    }

    fn emit(&self, code: &mut Vec<u8>) {
        match *self {
            MIns::Bool(val) => {
                code.push(if val {
                              Ins::LoadTrue
                          } else {
                              Ins::LoadFalse
                          }
                          .into())
            }
            MIns::Add(num_args) => unimplemented!(),
            MIns::LoadLocal(s) => unimplemented!(),
            MIns::SaveLocal(s) => unimplemented!(),
            MIns::CallFn(id) => unimplemented!(),
            MIns::Ret => unimplemented!(),
            MIns::Exit => code.push(Ins::Exit.into()),

            MIns::FnPtr(id) => unimplemented!(),
            MIns::CallPtr => unimplemented!(),

            MIns::MarkStack => unimplemented!(),
            MIns::PopToMark => unimplemented!(),

            _ => unreachable!(),
        }
    }
}

#[derive(Copy, Clone, PartialEq, Debug)]
enum Ins {
    Fail,

    Nop,

    LoadTrue,
    LoadFalse,
    LoadConst,

    FnPtr,
    CallPtr,

    Load,
    Save,

    Pop,
    Dup,

    Add,

    Call,
    Ret,

    Jmp,
    JmpF,

    Exit,

    MarkStack,
    PopToMark,
}

#[derive(Copy, Clone)]
enum Slot {
    Bool(bool),
    I64(i64),
}

impl Display for Slot {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let s = match *self {
            Slot::Bool(val) => val.to_string(),
            Slot::I64(val) => val.to_string(),
        };
        write!(f, "{}", s)
    }
}

pub struct Program {
    code: Vec<u8>,
    const_pool: Vec<i64>,
}

impl Program {
    pub fn exec(&self) -> String {
        let code = &*self.code;
        let const_pool = &*self.const_pool;

        let mut data_stack = vec![];
        // allocate local-var buffers in same stack?
        // let mut call_stack = vec![];

        let mut ins_ptr = 0;

        loop {
            let i = ins_ptr;
            ins_ptr += 1;

            match Ins::from(code[i]) {
                Ins::Fail => unreachable!(),
                Ins::Nop => {}
                Ins::LoadTrue => {
                    data_stack.push(Slot::Bool(true));
                }
                Ins::LoadFalse => {
                    data_stack.push(Slot::Bool(false));
                }
                Ins::LoadConst => {
                    let idx = Endianness::read_u16(&code[ins_ptr..ins_ptr + 2]) as usize;
                    ins_ptr += 2;
                    data_stack.push(Slot::I64(const_pool[idx]));
                }
                Ins::FnPtr => unimplemented!(),
                Ins::CallPtr => unimplemented!(),
                Ins::Load => unimplemented!(),
                Ins::Save => unimplemented!(),
                Ins::Pop => unimplemented!(),
                Ins::Dup => unimplemented!(),
                Ins::Add => unimplemented!(),
                Ins::Call => unimplemented!(),
                Ins::Ret => unimplemented!(),
                Ins::Jmp => {
                    ins_ptr = Endianness::read_u32(&code[ins_ptr..ins_ptr + 4]) as usize;
                }
                Ins::JmpF => {
                    let addr = Endianness::read_u32(&code[ins_ptr..ins_ptr + 4]) as usize;
                    ins_ptr += 4;
                    match data_stack.pop().unwrap() {
                        Slot::Bool(val) => {
                            if !val {
                                ins_ptr = addr;
                            }
                        }
                        _ => panic!("Expected bool"),
                    }
                }
                Ins::Exit => break,
                Ins::MarkStack => unimplemented!(),
                Ins::PopToMark => unimplemented!(),
            }
        }

        format!("{}", data_stack.pop().unwrap())
    }
}

macro_rules! def_id {
    ($name:ident, $ty:ty) => {
        #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
        struct $name($ty);

        impl ::std::convert::From<$ty> for $name {
            #[inline]
            fn from(val: $ty) -> Self {
                $name(val)
            }
        }

        impl ::std::convert::From<$name> for $ty {
            #[inline]
            fn from(val: $name) -> Self {
                val.0
            }
        }
    }
}

def_id!(FnAddr, FnAddrT);
def_id!(FnDefId, FnDefIdT);
def_id!(LabelId, u64);

impl ::std::convert::From<u8> for Ins {
    #[inline]
    fn from(byte: u8) -> Self {
        unsafe { ::std::mem::transmute(byte) }
    }
}

impl ::std::convert::From<Ins> for u8 {
    #[inline]
    fn from(ins: Ins) -> Self {
        unsafe { ::std::mem::transmute(ins) }
    }
}

#[inline]
fn uninitialized_vec<T>(len: usize) -> Vec<T> {
    let mut v = Vec::with_capacity(len);
    unsafe { v.set_len(len) };
    v
}
<commit_msg>Add repr(u8) to Ins<commit_after>
// TODO: rename module to vm

use std::mem;
use std::collections::HashMap;
use std::fmt::{self, Display, Formatter};

use byteorder::*;
use itertools::*;

use lang::{Env, Ast, BindingKey, Binding, ConstType, Result};

type Endianness = NativeEndian;
type Table<K, V> = HashMap<K, V>;

type ConstTableIdx = u16;
type FnAddrT = u32;
type FnDefIdT = u32;

pub fn compile(env: &Env, ast: &[Ast]) -> Result<Program> {

    // defs are stored in env, as are fn prototypes

    let mut code = vec![];
    let mut bcode = vec![];
    let mut callsites = vec![];
    let mut jumpsites = vec![];
    let mut fn_id_to_fn_addr = Table::new();
    let mut label_id_to_addr = Table::new();
    let mut const_table = vec![];

    let mut labels = LabelGen::new();

    // toplevel codegen
    for node in ast {
        codegen(env, &mut labels, node, &mut code);
    }

    code.push(MIns::Exit);

    // fn codegen
    for def in env.fn_defs() {
        code.push(MIns::FnDefBegin(FnDefId::from(def.id())));

        for node in def.ast() {
            codegen(env, &mut labels, node, &mut code);
        }
    }

    println!("\n===\n{}\n===",
             code.iter().map(|m| format!("{:?}", m)).join("\n"));

    // TODO: opt passes here

    for mins in code {
        if mins.is_simple() {
            mins.emit(&mut bcode);
        } else {
            match mins {
                MIns::FnDefBegin(id) => {
                    fn_id_to_fn_addr.insert(id, FnAddr::from(bcode.len() as FnAddrT));
                }
                MIns::I64(val) => {
                    let idx = const_table.len() as ConstTableIdx;
                    const_table.push(val); // TODO: Slot

                    bcode.push(Ins::LoadConst.into());
                    bcode.write_u16::<Endianness>(idx).unwrap();
                }
                MIns::CallFn(id) => {
                    bcode.push(Ins::Call.into());

                    let current_idx = bcode.len();
                    callsites.push((current_idx, id));

                    bcode.write_u32::<Endianness>(0 as FnAddrT).unwrap();
                }
                MIns::Label(id) => {
                    label_id_to_addr.insert(id, FnAddr::from(bcode.len() as FnAddrT));
                }
                MIns::Jmp(id) => {
                    bcode.push(Ins::Jmp.into());
                    jumpsites.push((id, bcode.len()));
                    bcode.write_u32::<Endianness>(0 as FnAddrT).unwrap();
                }
                MIns::JmpIfFalse(id) => {
                    bcode.push(Ins::JmpF.into());
                    jumpsites.push((id, bcode.len()));
                    bcode.write_u32::<Endianness>(0 as FnAddrT).unwrap();
                }
                _ => unreachable!(),
            }
        }
    }

    // patch jumpsites
    for (id, addr) in jumpsites {
        let target_addr = label_id_to_addr[&id].into();
        Endianness::write_u32(&mut bcode[addr..addr + mem::size_of::<FnAddrT>()],
                              target_addr);
    }

    // patch callsites
    for (i, id) in callsites {
        let addr = fn_id_to_fn_addr[&id].into();
        Endianness::write_u32(&mut bcode[i..i + mem::size_of::<FnAddrT>()], addr);
    }

    Ok(Program {
        code: bcode,
        const_pool: const_table,
    })
}

struct LabelGen(u64);

impl LabelGen {
    fn new() -> Self {
        LabelGen(0)
    }

    fn new_label(&mut self) -> LabelId {
        let id = self.0;
        self.0 += 1;
        LabelId::from(id)
    }
}

fn codegen(env: &Env, labels: &mut LabelGen, ast: &Ast, code: &mut Vec<MIns>) {
    match *ast {
        Ast::I64Literal(span, val) => {
            code.push(MIns::I64(val));
        }
        Ast::BoolLiteral(span, val) => {
            code.push(MIns::Bool(val));
        }
        Ast::Atom(span, ref binding_key) => {
            let record = match *binding_key {
                BindingKey::String(ref k) => {
                    env.lookup_by_name(k).expect("no binding found by that name")
                }
                BindingKey::Id(k) => env.lookup_by_id(k),
            };

            match *record.binding() {
                // 'x' after '(def x 10)'
                Binding::Const(ConstType::I64(val)) => {
                    code.push(MIns::I64(val));
                }
                _ => unimplemented!(),
            }
        }
        Ast::EmptyList(..) => unimplemented!(),
        Ast::Do(..) => unimplemented!(),
        Ast::Fn(..) => unimplemented!(),
        Ast::If(_, ref cond_expr, ref then_expr, ref else_expr) => {
            let label1 = labels.new_label();
            let label2 = labels.new_label();

            codegen(env, labels, &**cond_expr, code);
            code.push(MIns::JmpIfFalse(label1));

            codegen(env, labels, &**then_expr, code);
            code.push(MIns::Jmp(label2));
            code.push(MIns::Label(label1));

            codegen(env, labels, &**else_expr, code);
            code.push(MIns::Label(label2));
        }
        Ast::Inv(span, ref callee, ref args) => {
            // lookup callee
            // lookup and unify args with callee sig

            let fn_def_id = unimplemented!();

            // codegen:
            // gen each arg
            // emit fn_ptr/call

            // note the order
            for arg in args.iter() {
                codegen(env, labels, arg, code);
            }

            code.push(MIns::CallFn(fn_def_id));
        }
        Ast::Let(..) => unimplemented!(),
    }
}

// macro assembler instructions
#[derive(Clone, Debug)]
enum MIns {
    I64(i64),
    Bool(bool),

    Jmp(LabelId),
    JmpIfFalse(LabelId),
    Label(LabelId),
    // num_args
    Add(usize),
    LoadLocal(u8), // idx in local table
    SaveLocal(u8), // idx in local table
    CallFn(FnDefId),
    Ret,
    Exit,

    FnPtr(FnDefId),
    CallPtr,

    FnDefBegin(FnDefId),
    MarkStack,
    PopToMark,
}

impl MIns {
    fn is_simple(&self) -> bool {
        match *self {
            MIns::FnDefBegin(..) |
            MIns::I64(..) |
            MIns::CallFn(..) |
            MIns::Jmp(..) |
            MIns::JmpIfFalse(..) |
            MIns::Label(..) => false,
            _ => true,
        }
    }

    fn emit(&self, code: &mut Vec<u8>) {
        match *self {
            MIns::Bool(val) => {
                code.push(if val {
                              Ins::LoadTrue
                          } else {
                              Ins::LoadFalse
                          }
                          .into())
            }
            MIns::Add(num_args) => unimplemented!(),
            MIns::LoadLocal(s) => unimplemented!(),
            MIns::SaveLocal(s) => unimplemented!(),
            MIns::CallFn(id) => unimplemented!(),
            MIns::Ret => unimplemented!(),
            MIns::Exit => code.push(Ins::Exit.into()),

            MIns::FnPtr(id) => unimplemented!(),
            MIns::CallPtr => unimplemented!(),

            MIns::MarkStack => unimplemented!(),
            MIns::PopToMark => unimplemented!(),

            _ => unreachable!(),
        }
    }
}

#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
enum Ins {
    Fail,

    Nop,

    LoadTrue,
    LoadFalse,
    LoadConst,

    FnPtr,
    CallPtr,

    Load,
    Save,

    Pop,
    Dup,

    Add,

    Call,
    Ret,

    Jmp,
    JmpF,

    Exit,

    MarkStack,
    PopToMark,
}

#[derive(Copy, Clone)]
enum Slot {
    Bool(bool),
    I64(i64),
}

impl Display for Slot {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let s = match *self {
            Slot::Bool(val) => val.to_string(),
            Slot::I64(val) => val.to_string(),
        };
        write!(f, "{}", s)
    }
}

pub struct Program {
    code: Vec<u8>,
    const_pool: Vec<i64>,
}

impl Program {
    pub fn exec(&self) -> String {
        let code = &*self.code;
        let const_pool = &*self.const_pool;

        let mut data_stack = vec![];
        // allocate local-var buffers in same stack?
        // let mut call_stack = vec![];

        let mut ins_ptr = 0;

        loop {
            let i = ins_ptr;
            ins_ptr += 1;

            match Ins::from(code[i]) {
                Ins::Fail => unreachable!(),
                Ins::Nop => {}
                Ins::LoadTrue => {
                    data_stack.push(Slot::Bool(true));
                }
                Ins::LoadFalse => {
                    data_stack.push(Slot::Bool(false));
                }
                Ins::LoadConst => {
                    let idx = Endianness::read_u16(&code[ins_ptr..ins_ptr + 2]) as usize;
                    ins_ptr += 2;
                    data_stack.push(Slot::I64(const_pool[idx]));
                }
                Ins::FnPtr => unimplemented!(),
                Ins::CallPtr => unimplemented!(),
                Ins::Load => unimplemented!(),
                Ins::Save => unimplemented!(),
                Ins::Pop => unimplemented!(),
                Ins::Dup => unimplemented!(),
                Ins::Add => unimplemented!(),
                Ins::Call => unimplemented!(),
                Ins::Ret => unimplemented!(),
                Ins::Jmp => {
                    ins_ptr = Endianness::read_u32(&code[ins_ptr..ins_ptr + 4]) as usize;
                }
                Ins::JmpF => {
                    let addr = Endianness::read_u32(&code[ins_ptr..ins_ptr + 4]) as usize;
                    ins_ptr += 4;
                    match data_stack.pop().unwrap() {
                        Slot::Bool(val) => {
                            if !val {
                                ins_ptr = addr;
                            }
                        }
                        _ => panic!("Expected bool"),
                    }
                }
                Ins::Exit => break,
                Ins::MarkStack => unimplemented!(),
                Ins::PopToMark => unimplemented!(),
            }
        }

        format!("{}", data_stack.pop().unwrap())
    }
}

macro_rules! def_id {
    ($name:ident, $ty:ty) => {
        #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
        struct $name($ty);

        impl ::std::convert::From<$ty> for $name {
            #[inline]
            fn from(val: $ty) -> Self {
                $name(val)
            }
        }

        impl ::std::convert::From<$name> for $ty {
            #[inline]
            fn from(val: $name) -> Self {
                val.0
            }
        }
    }
}

def_id!(FnAddr, FnAddrT);
def_id!(FnDefId, FnDefIdT);
def_id!(LabelId, u64);

impl ::std::convert::From<u8> for Ins {
    #[inline]
    fn from(byte: u8) -> Self {
        unsafe { ::std::mem::transmute(byte) }
    }
}

impl ::std::convert::From<Ins> for u8 {
    #[inline]
    fn from(ins: Ins) -> Self {
        unsafe { ::std::mem::transmute(ins) }
    }
}

#[inline]
fn uninitialized_vec<T>(len: usize) -> Vec<T> {
    let mut v = Vec::with_capacity(len);
    unsafe { v.set_len(len) };
    v
}
<|endoftext|>


<commit_before>//! The convert module.
//!
//! Contains implementations of `std::convert::From`
//! for Matrix and Vector types.

use std::convert::From;

use libnum::{Zero, ToPrimitive, NumCast};

use error::{Error, ErrorKind};

use super::matrix::{DiagOffset, Matrix, MatrixSlice, MatrixSliceMut, BaseMatrix};
use super::vector::Vector;

impl<T> From<Vec<T>> for Vector<T> {
    fn from(vec: Vec<T>) -> Self {
        Vector::new(vec)
    }
}

impl<'a, T> From<&'a [T]> for Vector<T>
    where T: Clone
{
    fn from(slice: &'a [T]) -> Self {
        Vector::new(slice.to_owned())
    }
}

impl<T> From<Vector<T>> for Matrix<T> {
    fn from(vector: Vector<T>) -> Self {
        Matrix::new(vector.size(), 1, vector.into_vec())
    }
}

macro_rules! impl_matrix_from {
    ($slice_type:ident) => {
        impl<'a, T: Copy> From<$slice_type<'a, T>> for Matrix<T> {
            fn from(slice: $slice_type<'a, T>) -> Self {
                slice.row_iter().collect::<Matrix<T>>()
            }
        }
    }
}

impl_matrix_from!(MatrixSlice);
impl_matrix_from!(MatrixSliceMut);

macro_rules! impl_diag_offset_from {
    ($signed_type:ty) => {
impl From<$signed_type> for DiagOffset {
    fn from(int: $signed_type) -> Self {
        if int.is_zero() {
            DiagOffset::Main
        } else if int.is_positive() {
            DiagOffset::Above(int as usize)
        } else {
            DiagOffset::Below((-int) as usize)
        }
    }
}
    }
}

impl_diag_offset_from!(i8);
impl_diag_offset_from!(i16);
impl_diag_offset_from!(i32);
impl_diag_offset_from!(i64);
impl_diag_offset_from!(isize);

impl<T: ToPrimitive> Matrix<T> {
    /// Attempts to convert the matrix into a new matrix of different scalar type.
    ///
    /// # Failures
    /// - One or more of the elements in the matrix cannot be converted into
    ///   the new type.
    pub fn try_into<U: NumCast>(self) -> Result<Matrix<U>, Error> {
        let (m, n) = (self.rows(), self.cols());
        let ref make_error = || {
            Error::new(ErrorKind::ScalarConversionFailure,
                       "Failed to convert between scalar types.")
        };
        let converted_data = self.into_vec()
            .into_iter()
            .map(|x| U::from(x).ok_or_else(make_error))
            .collect::<Result<Vec<_>, Error>>();

        Ok(Matrix::<U>::new(m, n, try!(converted_data)))
    }
}

#[cfg(test)]
mod tests {
    use matrix::{DiagOffset, Matrix, MatrixSlice, MatrixSliceMut, BaseMatrix};
    use vector::Vector;

    #[test]
    fn inner_product_as_matrix_multiplication() {
        let u: Vector<f32> = vector![1., 2., 3.];
        let v: Vector<f32> = vector![3., 4., 5.];
        let dot_product = u.dot(&v);

        let um: Matrix<f32> = u.into();
        let vm: Matrix<f32> = v.into();
        let matrix_product = um.transpose() * vm;

        assert_eq!(dot_product, matrix_product.data()[0]);
    }

    #[test]
    fn matrix_from_slice() {
        let mut a = Matrix::new(3, 3, vec![2.0; 9]);

        {
            let b = MatrixSlice::from_matrix(&a, [1, 1], 2, 2);
            let c = Matrix::from(b);
            assert_eq!(c.rows(), 2);
            assert_eq!(c.cols(), 2);
        }

        let d = MatrixSliceMut::from_matrix(&mut a, [1, 1], 2, 2);
        let e = Matrix::from(d);
        assert_eq!(e.rows(), 2);
        assert_eq!(e.cols(), 2);
    }

    #[test]
    fn diag_offset_from_int() {
        let a: DiagOffset = 3.into();
        assert_eq!(a, DiagOffset::Above(3));
        let a: DiagOffset = (-3).into();
        assert_eq!(a, DiagOffset::Below(3));
        let a: DiagOffset = 0.into();
        assert_eq!(a, DiagOffset::Main);
    }

    #[test]
    fn try_into_empty_matrix() {
        {
            let x: Matrix<f64> = matrix![];
            let y: Matrix<f32> = x.try_into().unwrap();
            assert_matrix_eq!(y, matrix![]);
        }

        {
            let x: Matrix<u64> = matrix![];
            let y: Matrix<u32> = x.try_into().unwrap();
            assert_matrix_eq!(y, matrix![]);
        }

        {
            let x: Matrix<f64> = matrix![];
            let y: Matrix<u64> = x.try_into().unwrap();
            assert_matrix_eq!(y, matrix![]);
        }

        {
            let x: Matrix<u8> = matrix![];
            let y: Matrix<u64> = x.try_into().unwrap();
            assert_matrix_eq!(y, matrix![]);
        }
    }

    #[test]
    fn try_into_f64_to_i64() {
        let x: Matrix<f64> = matrix![ 1.0, 2.0;
                                     -3.0, 4.0];
        let y: Matrix<i64> = x.try_into().unwrap();
        let expected = matrix![ 1, 2;
                               -3, 4];
        assert_matrix_eq!(y, expected);
    }

    #[test]
    fn try_into_f64_to_u64() {
        let x: Matrix<f64> = matrix![ 1.0, 2.0;
                                      3.0, 4.0];
        let y: Matrix<u64> = x.try_into().unwrap();
        let expected = matrix![ 1, 2;
                                3, 4];
        assert_matrix_eq!(y, expected);
    }

    #[test]
    fn try_into_i64_to_f64() {
        {
            let x: Matrix<i64> = matrix![ 1, 2;
                                         -3, 4];
            let y: Matrix<f64> = x.try_into().unwrap();

            let expected = matrix![ 1.0, 2.0;
                                   -3.0, 4.0];
            assert_matrix_eq!(y, expected);
        }

        {
            // Recall that f64 cannot exactly represent integers of sufficiently
            // large absolute value. Yet, Rust will cast and round as necessary,
            // so we only check that the result is Ok.
            {
                let x: Matrix<i64> = matrix![1, 2, i64::max_value()];
                let y_result = x.try_into::<f64>();
                assert!(y_result.is_ok());
            }

            {
                let x: Matrix<i64> = matrix![1, 2, i64::min_value()];
                let y_result = x.try_into::<f64>();
                assert!(y_result.is_ok());
            }
        }
    }

    #[test]
    fn try_into_u64_to_f64() {
        {
            let x: Matrix<u64> = matrix![ 1, 2;
                                          3, 4];
            let y: Matrix<f64> = x.try_into().unwrap();

            let expected = matrix![ 1.0, 2.0;
                                    3.0, 4.0];
            assert_matrix_eq!(y, expected);
        }

        {
            // Recall that f64 cannot exactly represent integers of sufficiently
            // large absolute value. Yet, Rust will cast and round as necessary,
            // so we only check that the result is Ok.
            {
                let x: Matrix<u64> = matrix![1, 2, u64::max_value()];
                let y_result = x.try_into::<f64>();
                assert!(y_result.is_ok());
            }
        }
    }

    #[test]
    fn try_into_signed_unsigned() {
        {
            let x: Matrix<u64> = matrix![ 1, 2;
                                          3, 4];
            let y: Matrix<i64> = x.try_into().unwrap();

            let expected = matrix![ 1, 2;
                                    3, 4];
            assert_matrix_eq!(y, expected);
        }

        {
            let x: Matrix<i64> = matrix![ 1, 2;
                                          3, 4];
            let y: Matrix<u64> = x.try_into().unwrap();

            let expected = matrix![ 1, 2;
                                    3, 4];
            assert_matrix_eq!(y, expected);
        }

        {
            // Cannot cast negative values into unsigned
            let x = matrix![ 1, -2;
                             3,  4];
            let y_result = x.try_into::<u64>();
            assert!(y_result.is_err());
        }
    }

}
<commit_msg>API: Row/Column to Vector conversion (#125)<commit_after>//! The convert module.
//!
//! Contains implementations of `std::convert::From`
//! for Matrix and Vector types.

use std::convert::From;

use libnum::{Zero, ToPrimitive, NumCast};

use error::{Error, ErrorKind};

use super::matrix::{DiagOffset, Matrix, MatrixSlice, MatrixSliceMut, BaseMatrix,
                    Row, RowMut, Column, ColumnMut};
use super::vector::Vector;

impl<T> From<Vec<T>> for Vector<T> {
    fn from(vec: Vec<T>) -> Self {
        Vector::new(vec)
    }
}

impl<'a, T> From<&'a [T]> for Vector<T>
    where T: Clone
{
    fn from(slice: &'a [T]) -> Self {
        Vector::new(slice.to_owned())
    }
}

impl<T> From<Vector<T>> for Matrix<T> {
    fn from(vector: Vector<T>) -> Self {
        Matrix::new(vector.size(), 1, vector.into_vec())
    }
}

macro_rules! impl_matrix_from {
    ($slice_type:ident) => {
        impl<'a, T: Copy> From<$slice_type<'a, T>> for Matrix<T> {
            fn from(slice: $slice_type<'a, T>) -> Self {
                slice.row_iter().collect::<Matrix<T>>()
            }
        }
    }
}

impl_matrix_from!(MatrixSlice);
impl_matrix_from!(MatrixSliceMut);

macro_rules! impl_diag_offset_from {
    ($signed_type:ty) => {
impl From<$signed_type> for DiagOffset {
    fn from(int: $signed_type) -> Self {
        if int.is_zero() {
            DiagOffset::Main
        } else if int.is_positive() {
            DiagOffset::Above(int as usize)
        } else {
            DiagOffset::Below((-int) as usize)
        }
    }
}
    }
}

impl_diag_offset_from!(i8);
impl_diag_offset_from!(i16);
impl_diag_offset_from!(i32);
impl_diag_offset_from!(i64);
impl_diag_offset_from!(isize);

impl<T: ToPrimitive> Matrix<T> {
    /// Attempts to convert the matrix into a new matrix of different scalar type.
    ///
    /// # Failures
    /// - One or more of the elements in the matrix cannot be converted into
    ///   the new type.
    pub fn try_into<U: NumCast>(self) -> Result<Matrix<U>, Error> {
        let (m, n) = (self.rows(), self.cols());
        let ref make_error = || {
            Error::new(ErrorKind::ScalarConversionFailure,
                       "Failed to convert between scalar types.")
        };
        let converted_data = self.into_vec()
            .into_iter()
            .map(|x| U::from(x).ok_or_else(make_error))
            .collect::<Result<Vec<_>, Error>>();

        Ok(Matrix::<U>::new(m, n, try!(converted_data)))
    }
}

macro_rules! impl_row_to_vector (
    ($t:ident) => (

impl<'a, T: Clone> From<$t<'a, T>> for Vector<T> {
    fn from(row: $t<'a, T>) -> Self {
        Vector::new(row.raw_slice())
    }
}

    );
);
impl_row_to_vector!(Row);
impl_row_to_vector!(RowMut);

macro_rules! impl_column_to_vector (
    ($t:ident) => (

impl<'a, T: Clone> From<$t<'a, T>> for Vector<T> {
    fn from(column: $t<'a, T>) -> Self {
        column.iter().cloned().collect::<Self>()
    }
}

    );
);
impl_column_to_vector!(Column);
impl_column_to_vector!(ColumnMut);

#[cfg(test)]
mod tests {
    use matrix::{DiagOffset, Matrix, MatrixSlice, MatrixSliceMut,
                 BaseMatrix, BaseMatrixMut};
    use vector::Vector;

    #[test]
    fn inner_product_as_matrix_multiplication() {
        let u: Vector<f32> = vector![1., 2., 3.];
        let v: Vector<f32> = vector![3., 4., 5.];
        let dot_product = u.dot(&v);

        let um: Matrix<f32> = u.into();
        let vm: Matrix<f32> = v.into();
        let matrix_product = um.transpose() * vm;

        assert_eq!(dot_product, matrix_product.data()[0]);
    }

    #[test]
    fn matrix_from_slice() {
        let mut a = Matrix::new(3, 3, vec![2.0; 9]);

        {
            let b = MatrixSlice::from_matrix(&a, [1, 1], 2, 2);
            let c = Matrix::from(b);
            assert_eq!(c.rows(), 2);
            assert_eq!(c.cols(), 2);
        }

        let d = MatrixSliceMut::from_matrix(&mut a, [1, 1], 2, 2);
        let e = Matrix::from(d);
        assert_eq!(e.rows(), 2);
        assert_eq!(e.cols(), 2);
    }

    #[test]
    fn diag_offset_from_int() {
        let a: DiagOffset = 3.into();
        assert_eq!(a, DiagOffset::Above(3));
        let a: DiagOffset = (-3).into();
        assert_eq!(a, DiagOffset::Below(3));
        let a: DiagOffset = 0.into();
        assert_eq!(a, DiagOffset::Main);
    }

    #[test]
    fn try_into_empty_matrix() {
        {
            let x: Matrix<f64> = matrix![];
            let y: Matrix<f32> = x.try_into().unwrap();
            assert_matrix_eq!(y, matrix![]);
        }

        {
            let x: Matrix<u64> = matrix![];
            let y: Matrix<u32> = x.try_into().unwrap();
            assert_matrix_eq!(y, matrix![]);
        }

        {
            let x: Matrix<f64> = matrix![];
            let y: Matrix<u64> = x.try_into().unwrap();
            assert_matrix_eq!(y, matrix![]);
        }

        {
            let x: Matrix<u8> = matrix![];
            let y: Matrix<u64> = x.try_into().unwrap();
            assert_matrix_eq!(y, matrix![]);
        }
    }

    #[test]
    fn try_into_f64_to_i64() {
        let x: Matrix<f64> = matrix![ 1.0, 2.0;
                                     -3.0, 4.0];
        let y: Matrix<i64> = x.try_into().unwrap();
        let expected = matrix![ 1, 2;
                               -3, 4];
        assert_matrix_eq!(y, expected);
    }

    #[test]
    fn try_into_f64_to_u64() {
        let x: Matrix<f64> = matrix![ 1.0, 2.0;
                                      3.0, 4.0];
        let y: Matrix<u64> = x.try_into().unwrap();
        let expected = matrix![ 1, 2;
                                3, 4];
        assert_matrix_eq!(y, expected);
    }

    #[test]
    fn try_into_i64_to_f64() {
        {
            let x: Matrix<i64> = matrix![ 1, 2;
                                         -3, 4];
            let y: Matrix<f64> = x.try_into().unwrap();

            let expected = matrix![ 1.0, 2.0;
                                   -3.0, 4.0];
            assert_matrix_eq!(y, expected);
        }

        {
            // Recall that f64 cannot exactly represent integers of sufficiently
            // large absolute value. Yet, Rust will cast and round as necessary,
            // so we only check that the result is Ok.
            {
                let x: Matrix<i64> = matrix![1, 2, i64::max_value()];
                let y_result = x.try_into::<f64>();
                assert!(y_result.is_ok());
            }

            {
                let x: Matrix<i64> = matrix![1, 2, i64::min_value()];
                let y_result = x.try_into::<f64>();
                assert!(y_result.is_ok());
            }
        }
    }

    #[test]
    fn try_into_u64_to_f64() {
        {
            let x: Matrix<u64> = matrix![ 1, 2;
                                          3, 4];
            let y: Matrix<f64> = x.try_into().unwrap();

            let expected = matrix![ 1.0, 2.0;
                                    3.0, 4.0];
            assert_matrix_eq!(y, expected);
        }

        {
            // Recall that f64 cannot exactly represent integers of sufficiently
            // large absolute value. Yet, Rust will cast and round as necessary,
            // so we only check that the result is Ok.
            {
                let x: Matrix<u64> = matrix![1, 2, u64::max_value()];
                let y_result = x.try_into::<f64>();
                assert!(y_result.is_ok());
            }
        }
    }

    #[test]
    fn try_into_signed_unsigned() {
        {
            let x: Matrix<u64> = matrix![ 1, 2;
                                          3, 4];
            let y: Matrix<i64> = x.try_into().unwrap();

            let expected = matrix![ 1, 2;
                                    3, 4];
            assert_matrix_eq!(y, expected);
        }

        {
            let x: Matrix<i64> = matrix![ 1, 2;
                                          3, 4];
            let y: Matrix<u64> = x.try_into().unwrap();

            let expected = matrix![ 1, 2;
                                    3, 4];
            assert_matrix_eq!(y, expected);
        }

        {
            // Cannot cast negative values into unsigned
            let x = matrix![ 1, -2;
                             3,  4];
            let y_result = x.try_into::<u64>();
            assert!(y_result.is_err());
        }
    }

    #[test]
    fn test_row_convert() {
        let a: Matrix<i64> = matrix![1, 2, 3, 4;
                                     5, 6, 7, 8;
                                     9, 10, 11, 12];
        let row = a.row(1);
        let v: Vector<i64> = row.into();
        assert_eq!(v, vector![5, 6, 7, 8]);

        let row = a.row(2);
        let v = Vector::from(row);
        assert_eq!(v, vector![9, 10, 11, 12]);
    }

    #[test]
    fn test_row_convert_mut() {
        let mut a: Matrix<i64> = matrix![1, 2, 3, 4;
                                         5, 6, 7, 8;
                                         9, 10, 11, 12];

        let row = a.row_mut(1);
        let v: Vector<i64> = row.into();
        assert_eq!(v, vector![5, 6, 7, 8]);

        let mut a: Matrix<i64> = matrix![1, 2, 3, 4;
                                         5, 6, 7, 8;
                                         9, 10, 11, 12];
        let row = a.row_mut(2);
        let v = Vector::from(row);
        assert_eq!(v, vector![9, 10, 11, 12]);
    }

    #[test]
    fn test_column_convert() {
        let a: Matrix<i64> = matrix![1, 2, 3, 4;
                                     5, 6, 7, 8;
                                     9, 10, 11, 12];
        let row = a.col(1);
        let v: Vector<i64> = row.into();
        assert_eq!(v, vector![2, 6, 10]);

        let row = a.col(2);
        let v = Vector::from(row);
        assert_eq!(v, vector![3, 7, 11]);
    }

    #[test]
    fn test_column_convert_mut() {
        let mut a: Matrix<i64> = matrix![1, 2, 3, 4;
                                         5, 6, 7, 8;
                                         9, 10, 11, 12];

        let row = a.col_mut(1);
        let v: Vector<i64> = row.into();
        assert_eq!(v, vector![2, 6, 10]);

        let mut a: Matrix<i64> = matrix![1, 2, 3, 4;
                                         5, 6, 7, 8;
                                         9, 10, 11, 12];
        let row = a.col_mut(2);
        let v = Vector::from(row);
        assert_eq!(v, vector![3, 7, 11]);
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2016 Marvin Böcker
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

//! This module contains a wrapper around the libsodium implementation of ed25519.
//! It reduces the size of signatures to 64 byte.

use sodiumoxide;
use sodiumoxide::crypto::sign::ed25519;

/// This is the length of a ed25519 private key.
pub const PRIVATE_KEY_LEN: usize = 64;

/// This is the length of a ed25519 public key.
pub const PUBLIC_KEY_LEN: usize = 32;

/// This is the length of a ed25519 signature.
pub const SIGNATURE_LEN: usize = 64;

static mut inited: bool = false;

/// This method generates a random ed25519 keypair from a cryptographically secure source
/// (on unix this is /dev/urandom). Returns (`public_key`, `private_key`).
pub fn generate_keypair() -> ([u8; PUBLIC_KEY_LEN], [u8; PRIVATE_KEY_LEN]) {

    unsafe {

        // we can do this simple unsafe "lazy init",
        // because it would be OK to call init() twice.

        if !inited {
            inited = true;
            sodiumoxide::init();
        }
    }

    let (pk, sk) = ed25519::gen_keypair();

    let public_key = pk.0;
    let private_key = sk.0;

    assert_eq!(PUBLIC_KEY_LEN, public_key.len());
    assert_eq!(PRIVATE_KEY_LEN, private_key.len());

    (public_key, private_key)
}

/// This method takes a data vector and a private key and computes the signature which can be
/// verified using the public key.
pub fn sign(data: &[u8], private_key: &[u8]) -> Vec<u8> {
    assert_eq!(private_key.len(), PRIVATE_KEY_LEN);

    let sk = ed25519::SecretKey::from_slice(private_key);
    let sk = sk.as_ref().unwrap();

    let s = ed25519::sign(data, &sk);

    let mut v = Vec::new();
    v.extend_from_slice(&s[0..64]);
    v
}

/// This method takes a data vector, a signature and a public key and returns true, if the
/// signature has been created using the correct private key.
pub fn verify(data: &[u8], signature: &[u8], public_key: &[u8]) -> bool {

    let pk = ed25519::PublicKey::from_slice(public_key);
    let pk = pk.as_ref().unwrap();

    // allocate buffer on heap for signature and data.
    let mut vi = Vec::with_capacity(SIGNATURE_LEN + data.len());
    vi.extend_from_slice(&signature);
    vi.extend_from_slice(data);

    let r = ed25519::verify(&vi, &pk);

    if r.is_err() {
        false
    } else {
        let bytes = r.unwrap();
        bytes == data
    }
}

#[test]
fn test_ed25519_simple() {
    let (pk, sk) = generate_keypair();

    let msg = &[0; 128][..];
    let mut sig = sign(msg, &sk);

    println!("signature: {:?}", sig);
    println!("");

    sig[0] = ((sig[0] as u16 + 1) % 256) as u8;

    assert_eq!(verify(msg, &sig, &pk), false);

    sig[0] = ((sig[0] as u16 + 255) % 256) as u8;

    assert_eq!(verify(msg, &sig, &pk), true);
}

#[test]
fn test_ed25519_shortmsg() {
    let (pk, sk) = generate_keypair();

    let msg = &[0; 32][..];
    let mut sig = sign(msg, &sk);

    println!("signature: {:?}", sig);
    println!("");

    sig[0] = ((sig[0] as u16 + 1) % 256) as u8;

    assert_eq!(verify(msg, &sig, &pk), false);

    sig[0] = ((sig[0] as u16 + 255) % 256) as u8;

    assert_eq!(verify(msg, &sig, &pk), true);
}

#[test]
fn test_testvectors() {
    use rustc_serialize::json;
    use bytescontainer::BytesContainer;

    let decode = |t| {
        let t = json::decode::<BytesContainer>(&format!("\"{}\"", t)).unwrap();
        t.get().clone()
    };

    // test vectors from
    // https://github.com/cryptosphere/rbnacl/blob/master/lib/rbnacl/test_vectors.rb

    let prv = decode("b18e1d0045995ec3d010c387ccfeb984d783af8fbb0f40fa7db126d889f6dadd77f48b59cae\
                      da77751ed138b0ec667ff50f8768c25d48309a8f386a2bad187fb");

    let pbl = decode("77f48b59caeda77751ed138b0ec667ff50f8768c25d48309a8f386a2bad187fb");

    let msg = decode("916c7d1d268fc0e77c1bef238432573c39be577bbea099893\
                      6add2b50a653171ce18a542b0b7f96c1691a3be6031522894a8\
                      634183eda38798a0c5d5d79fbd01dd04a8646d71873b77b2219\
                      98a81922d8105f892316369d5224c9983372d2313c6b1f4556e\
                      a26ba49d46e8b561e0fc76633ac9766e68e21fba7edca93c4c7\
                      460376d7f3ac22ff372c18f613f2ae2e856af40");

    let sig = decode("6bd710a368c1249923fc7a1610747403040f0cc30815a00f9ff548a896bbda0b4eb2ca19ebc\
                      f917f0f34200a9edbad3901b64ab09cc5ef7b9bcc3c40c0ff7509");

    let sig_my = sign(&msg, &prv);

    // both signatures must be equal
    assert_eq!(&sig_my, &sig);

    // the signature must be valid
    assert_eq!(true, verify(&msg, &sig_my, &pbl));
}
<commit_msg>small change<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016 Marvin Böcker
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

//! This module contains a wrapper around the libsodium implementation of ed25519.
//! It reduces the size of signatures to 64 byte.

use sodiumoxide;
use sodiumoxide::crypto::sign::ed25519;

/// This is the length of a ed25519 private key.
pub const PRIVATE_KEY_LEN: usize = 64;

/// This is the length of a ed25519 public key.
pub const PUBLIC_KEY_LEN: usize = 32;

/// This is the length of a ed25519 signature.
pub const SIGNATURE_LEN: usize = 64;

static mut inited: bool = false;

/// This method generates a random ed25519 keypair from a cryptographically secure source
/// (on unix this is /dev/urandom). Returns (`public_key`, `private_key`).
pub fn generate_keypair() -> ([u8; PUBLIC_KEY_LEN], [u8; PRIVATE_KEY_LEN]) {

    unsafe {

        // we can do this simple unsafe "lazy init",
        // because it would be OK to call init() twice.

        if !inited {
            inited = true;
            sodiumoxide::init();
        }
    }

    let (pk, sk) = ed25519::gen_keypair();

    let public_key = pk.0;
    let private_key = sk.0;

    assert_eq!(PUBLIC_KEY_LEN, public_key.len());
    assert_eq!(PRIVATE_KEY_LEN, private_key.len());

    (public_key, private_key)
}

/// This method takes a data vector and a private key and computes the signature which can be
/// verified using the public key.
pub fn sign(data: &[u8], private_key: &[u8]) -> Vec<u8> {
    assert_eq!(private_key.len(), PRIVATE_KEY_LEN);

    let sk = ed25519::SecretKey::from_slice(private_key);
    let sk = sk.as_ref().unwrap();

    let s = ed25519::sign(data, &sk);

    let mut v = Vec::new();
    v.extend_from_slice(&s[0..64]);
    v
}

/// This method takes a data vector, a signature and a public key and returns true, if the
/// signature has been created using the correct private key.
pub fn verify(data: &[u8], signature: &[u8], public_key: &[u8]) -> bool {

    let pk = ed25519::PublicKey::from_slice(public_key);
    let pk = pk.as_ref().unwrap();

    // allocate buffer on heap for signature and data.
    let mut vi = Vec::with_capacity(SIGNATURE_LEN + data.len());
    vi.extend_from_slice(&signature);
    vi.extend_from_slice(data);

    let r = ed25519::verify(&vi, &pk);

    match r {
        Err(_) => false,
        Ok(x) => x == data,
    }
}

#[test]
fn test_ed25519_simple() {
    let (pk, sk) = generate_keypair();

    let msg = &[0; 128][..];
    let mut sig = sign(msg, &sk);

    println!("signature: {:?}", sig);
    println!("");

    sig[0] = ((sig[0] as u16 + 1) % 256) as u8;

    assert_eq!(verify(msg, &sig, &pk), false);

    sig[0] = ((sig[0] as u16 + 255) % 256) as u8;

    assert_eq!(verify(msg, &sig, &pk), true);
}

#[test]
fn test_ed25519_shortmsg() {
    let (pk, sk) = generate_keypair();

    let msg = &[0; 32][..];
    let mut sig = sign(msg, &sk);

    println!("signature: {:?}", sig);
    println!("");

    sig[0] = ((sig[0] as u16 + 1) % 256) as u8;

    assert_eq!(verify(msg, &sig, &pk), false);

    sig[0] = ((sig[0] as u16 + 255) % 256) as u8;

    assert_eq!(verify(msg, &sig, &pk), true);
}

#[test]
fn test_testvectors() {
    use rustc_serialize::json;
    use bytescontainer::BytesContainer;

    let decode = |t| {
        let t = json::decode::<BytesContainer>(&format!("\"{}\"", t)).unwrap();
        t.get().clone()
    };

    // test vectors from
    // https://github.com/cryptosphere/rbnacl/blob/master/lib/rbnacl/test_vectors.rb

    let prv = decode("b18e1d0045995ec3d010c387ccfeb984d783af8fbb0f40fa7db126d889f6dadd77f48b59cae\
                      da77751ed138b0ec667ff50f8768c25d48309a8f386a2bad187fb");

    let pbl = decode("77f48b59caeda77751ed138b0ec667ff50f8768c25d48309a8f386a2bad187fb");

    let msg = decode("916c7d1d268fc0e77c1bef238432573c39be577bbea099893\
                      6add2b50a653171ce18a542b0b7f96c1691a3be6031522894a8\
                      634183eda38798a0c5d5d79fbd01dd04a8646d71873b77b2219\
                      98a81922d8105f892316369d5224c9983372d2313c6b1f4556e\
                      a26ba49d46e8b561e0fc76633ac9766e68e21fba7edca93c4c7\
                      460376d7f3ac22ff372c18f613f2ae2e856af40");

    let sig = decode("6bd710a368c1249923fc7a1610747403040f0cc30815a00f9ff548a896bbda0b4eb2ca19ebc\
                      f917f0f34200a9edbad3901b64ab09cc5ef7b9bcc3c40c0ff7509");

    let sig_my = sign(&msg, &prv);

    // both signatures must be equal
    assert_eq!(&sig_my, &sig);

    // the signature must be valid
    assert_eq!(true, verify(&msg, &sig_my, &pbl));
}
<|endoftext|>


<commit_before>use std::io::{Write, Result};
use super::representation::Representation;

pub struct Module {
    name: String,
}

impl Module {
    pub fn new<S>(name: S) -> Module where S: Into<String> {
        Module { name : name.into() }
    }
}

impl Representation for Module {
    fn write_representation(&self, writer: &mut Write) -> Result<()> {
        write!(writer, "module {} exposing (..)", self.name)
    }
}

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

    #[test]
    fn module_should_write_it_self() {
        let module = Module::new("Test");
        let mut output = Vec::new();

        module.write_representation(&mut output).unwrap();

        assert_eq!(output, b"module Test exposing (..)");
    }
}
<commit_msg>Create definitions<commit_after>use std::io::{Write, Result};
use super::representation::Representation;

pub struct Module {
    name: String,
    definitions: Vec<Definition>,
}

impl Module {
    pub fn new<S>(name: S) -> Module where S: Into<String> {
        Module { name : name.into(), definitions: Vec::new() }
    }
}

impl Representation for Module {
    fn write_representation(&self, writer: &mut Write) -> Result<()> {
        write!(writer, "module {} exposing (..)\n\n\n", self.name)?;

        for definition in &self.definitions {
            definition.write_representation(writer)?
        }

        Ok(())
    }
}

pub enum Definition {
    Struct,
    Enum,
    Function,
}

impl Representation for Definition {
    fn write_representation(&self, writer: &mut Write) -> Result<()> {
        match *self {
            Definition::Struct => {
                write!(writer, "type alias")
            },

            Definition::Enum => {
                write!(writer, "type")
            },

            Definition::Function => {
                write!(writer, "function")
            },
        }
    }
}

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

    #[test]
    fn module_should_write_it_self() {
        let module = Module::new("Test");
        let mut output = Vec::new();

        module.write_representation(&mut output).unwrap();

        assert_eq!(output[0..25], b"module Test exposing (..)"[..]);
    }
}
<|endoftext|>


<commit_before>use crate::entities::*;
use crate::enums::*;
use crate::*;

use std::fs::{create_dir_all, read_to_string, remove_dir_all};
use std::path::Path;
use std::process::Command;
use std::thread::panicking;
use std::time::SystemTime;

extern crate glob;
use glob::glob;

struct Oda {
    temp_path: String,
    input_path: String,
    output_path: String,
    oda_path: String,
}

impl Drop for Oda {
    fn drop(&mut self) {
        if panicking() {
            println!("Test drawings at '{}'", self.temp_path);
        } else {
            remove_dir_all(Path::new(&self.temp_path)).unwrap();
        }
    }
}

impl Oda {
    pub fn convert_drawing(&self, drawing: &Drawing, version: AcadVersion) -> Drawing {
        drawing
            .save_file(&format!("{}/drawing.dxf", self.input_path))
            .unwrap();
        // e.g.,
        //   ODAFileConverter.exe input_dir output_dir ACAD2000 DXF 0 1
        let mut oda_convert = Command::new(&self.oda_path)
            .arg(&self.input_path)
            .arg(&self.output_path)
            .arg(&Oda::version_string(version))
            .arg("DXF")
            .arg("0") // recurse
            .arg("1") // audit
            .spawn()
            .expect("Failed to spawn ODA converter");
        let exit_code = oda_convert
            .wait()
            .expect("Failed to wait for ODA converter");
        let mut error_messages = String::from("");
        for entry in glob(format!("{}/*.err", &self.output_path).as_str())
            .expect("failed to glob for ODA error logs")
        {
            match entry {
                Ok(path) if path.is_file() => {
                    error_messages.push_str(format!("{}:\n", path.to_str().unwrap()).as_str());
                    let error_contents = read_to_string(path).unwrap();
                    error_messages.push_str(error_contents.as_str());
                    error_messages.push_str("\n\n");
                }
                Ok(_) => (),
                Err(_) => (),
            }
        }
        if !error_messages.is_empty() {
            panic!(format!("Error converting files:\n{}", error_messages));
        }

        assert!(exit_code.success());
        Drawing::load_file(&format!("{}/drawing.dxf", self.output_path)).unwrap()
    }
    fn version_string(version: AcadVersion) -> String {
        let s = match version {
            AcadVersion::R9 => "ACAD9",
            AcadVersion::R10 => "ACAD10",
            AcadVersion::R12 => "ACAD12",
            AcadVersion::R13 => "ACAD13",
            AcadVersion::R14 => "ACAD14",
            AcadVersion::R2000 => "ACAD2000",
            AcadVersion::R2004 => "ACAD2004",
            AcadVersion::R2007 => "ACAD2007",
            AcadVersion::R2010 => "ACAD2010",
            AcadVersion::R2013 => "ACAD2013",
            AcadVersion::R2018 => "ACAD2018",
            _ => panic!("Unsupported ODA version {}", version),
        };
        String::from(s)
    }
}

macro_rules! require_oda {
    () => {{
        // Find ODA converter.  Final path looks something like:
        //   C:\Program Files\ODA\ODAFileConverter_title 20.12.0\ODAFileConverter.exe
        let mut full_oda_path = None;
        for entry in glob("C:/Program Files/ODA/ODAFileConverter*/ODAFileConverter.exe")
            .expect("failed to glob for ODA converter")
        {
            match entry {
                Ok(path) if path.is_file() => full_oda_path = Some(path),
                Ok(_) => (),
                Err(_) => (),
            }
        }
        if full_oda_path == None {
            // didn't find ODA converter directory
            return;
        }
        let full_oda_path = full_oda_path.unwrap();

        // make and report temporary directory
        let nanos = format!(
            "{}",
            SystemTime::now()
                .duration_since(SystemTime::UNIX_EPOCH)
                .unwrap()
                .as_nanos()
        );
        let temp_path = format!("{}/integration-tests/{}", env!("OUT_DIR"), nanos);
        let input_path = format!("{}/input", temp_path);
        let output_path = format!("{}/output", temp_path);
        create_dir_all(Path::new(&temp_path)).unwrap();
        create_dir_all(Path::new(&input_path)).unwrap();
        create_dir_all(Path::new(&output_path)).unwrap();
        Oda {
            temp_path,
            input_path,
            output_path,
            oda_path: String::from(full_oda_path.to_str().unwrap()),
        }
    }};
}

#[test]
fn simple_line_can_be_read_by_oda() {
    let oda = require_oda!();
    let mut drawing = Drawing::new();
    drawing.add_entity(Entity {
        common: Default::default(),
        specific: EntityType::Line(Line {
            p1: Point::new(1.0, 2.0, 3.0),
            p2: Point::new(4.0, 5.0, 6.0),
            ..Default::default()
        }),
    });

    let round_tripped = oda.convert_drawing(&drawing, AcadVersion::R2000);
    let entities = round_tripped.entities().collect::<Vec<_>>();
    assert_eq!(1, entities.len());
    match entities[0].specific {
        EntityType::Line(ref line) => {
            assert_eq!(Point::new(1.0, 2.0, 3.0), line.p1);
            assert_eq!(Point::new(4.0, 5.0, 6.0), line.p2);
        }
        _ => panic!("expected a line"),
    }
}
<commit_msg>remove unnecessary formatting<commit_after>use crate::entities::*;
use crate::enums::*;
use crate::*;

use std::fs::{create_dir_all, read_to_string, remove_dir_all};
use std::path::Path;
use std::process::Command;
use std::thread::panicking;
use std::time::SystemTime;

extern crate glob;
use glob::glob;

struct Oda {
    temp_path: String,
    input_path: String,
    output_path: String,
    oda_path: String,
}

impl Drop for Oda {
    fn drop(&mut self) {
        if panicking() {
            println!("Test drawings at '{}'", self.temp_path);
        } else {
            remove_dir_all(Path::new(&self.temp_path)).unwrap();
        }
    }
}

impl Oda {
    pub fn convert_drawing(&self, drawing: &Drawing, version: AcadVersion) -> Drawing {
        drawing
            .save_file(&format!("{}/drawing.dxf", self.input_path))
            .unwrap();
        // e.g.,
        //   ODAFileConverter.exe input_dir output_dir ACAD2000 DXF 0 1
        let mut oda_convert = Command::new(&self.oda_path)
            .arg(&self.input_path)
            .arg(&self.output_path)
            .arg(&Oda::version_string(version))
            .arg("DXF")
            .arg("0") // recurse
            .arg("1") // audit
            .spawn()
            .expect("Failed to spawn ODA converter");
        let exit_code = oda_convert
            .wait()
            .expect("Failed to wait for ODA converter");
        let mut error_messages = String::from("");
        for entry in glob(format!("{}/*.err", &self.output_path).as_str())
            .expect("failed to glob for ODA error logs")
        {
            match entry {
                Ok(path) if path.is_file() => {
                    error_messages.push_str(format!("{}:\n", path.to_str().unwrap()).as_str());
                    let error_contents = read_to_string(path).unwrap();
                    error_messages.push_str(error_contents.as_str());
                    error_messages.push_str("\n\n");
                }
                Ok(_) => (),
                Err(_) => (),
            }
        }
        if !error_messages.is_empty() {
            panic!("Error converting files:\n{}", error_messages);
        }

        assert!(exit_code.success());
        Drawing::load_file(&format!("{}/drawing.dxf", self.output_path)).unwrap()
    }
    fn version_string(version: AcadVersion) -> String {
        let s = match version {
            AcadVersion::R9 => "ACAD9",
            AcadVersion::R10 => "ACAD10",
            AcadVersion::R12 => "ACAD12",
            AcadVersion::R13 => "ACAD13",
            AcadVersion::R14 => "ACAD14",
            AcadVersion::R2000 => "ACAD2000",
            AcadVersion::R2004 => "ACAD2004",
            AcadVersion::R2007 => "ACAD2007",
            AcadVersion::R2010 => "ACAD2010",
            AcadVersion::R2013 => "ACAD2013",
            AcadVersion::R2018 => "ACAD2018",
            _ => panic!("Unsupported ODA version {}", version),
        };
        String::from(s)
    }
}

macro_rules! require_oda {
    () => {{
        // Find ODA converter.  Final path looks something like:
        //   C:\Program Files\ODA\ODAFileConverter_title 20.12.0\ODAFileConverter.exe
        let mut full_oda_path = None;
        for entry in glob("C:/Program Files/ODA/ODAFileConverter*/ODAFileConverter.exe")
            .expect("failed to glob for ODA converter")
        {
            match entry {
                Ok(path) if path.is_file() => full_oda_path = Some(path),
                Ok(_) => (),
                Err(_) => (),
            }
        }
        if full_oda_path == None {
            // didn't find ODA converter directory
            return;
        }
        let full_oda_path = full_oda_path.unwrap();

        // make and report temporary directory
        let nanos = format!(
            "{}",
            SystemTime::now()
                .duration_since(SystemTime::UNIX_EPOCH)
                .unwrap()
                .as_nanos()
        );
        let temp_path = format!("{}/integration-tests/{}", env!("OUT_DIR"), nanos);
        let input_path = format!("{}/input", temp_path);
        let output_path = format!("{}/output", temp_path);
        create_dir_all(Path::new(&temp_path)).unwrap();
        create_dir_all(Path::new(&input_path)).unwrap();
        create_dir_all(Path::new(&output_path)).unwrap();
        Oda {
            temp_path,
            input_path,
            output_path,
            oda_path: String::from(full_oda_path.to_str().unwrap()),
        }
    }};
}

#[test]
fn simple_line_can_be_read_by_oda() {
    let oda = require_oda!();
    let mut drawing = Drawing::new();
    drawing.add_entity(Entity {
        common: Default::default(),
        specific: EntityType::Line(Line {
            p1: Point::new(1.0, 2.0, 3.0),
            p2: Point::new(4.0, 5.0, 6.0),
            ..Default::default()
        }),
    });

    let round_tripped = oda.convert_drawing(&drawing, AcadVersion::R2000);
    let entities = round_tripped.entities().collect::<Vec<_>>();
    assert_eq!(1, entities.len());
    match entities[0].specific {
        EntityType::Line(ref line) => {
            assert_eq!(Point::new(1.0, 2.0, 3.0), line.p1);
            assert_eq!(Point::new(4.0, 5.0, 6.0), line.p2);
        }
        _ => panic!("expected a line"),
    }
}
<|endoftext|>