<commit_before>// Setup linking for all targets.
#[cfg(target_os="macos")]
mod mac {
    #[cfg(mac_framework)]
    #[link_args="-framework SDL"]
    extern {}

    #[cfg(mac_dylib)]
    #[link_args="-lSDL"]
    extern {}
}

#[cfg(target_os="win32")]
#[cfg(target_os="linux")]
#[cfg(target_os="freebsd")]
mod others {
    #[link_args="-lSDL"]
    extern {}
}

pub mod ll {
    use core::libc::{c_int, c_uint, c_schar, uint32_t};

    pub type SDL_errorcode = c_uint;
    pub static SDL_ENOMEM: SDL_errorcode = 0;
    pub static SDL_EFREAD: SDL_errorcode = 1;
    pub static SDL_EFWRITE: SDL_errorcode = 2;
    pub static SDL_EFSEEK: SDL_errorcode = 3;
    pub static SDL_UNSUPPORTED: SDL_errorcode = 4;
    pub static SDL_LASTERROR: SDL_errorcode = 5;

    pub type SDL_InitFlag = uint32_t;
    pub static SDL_INIT_TIMER: SDL_InitFlag = 0x00000001;
    pub static SDL_INIT_AUDIO: SDL_InitFlag = 0x00000010;
    pub static SDL_INIT_VIDEO: SDL_InitFlag = 0x00000020;
    pub static SDL_INIT_CDROM: SDL_InitFlag = 0x00000100;
    pub static SDL_INIT_JOYSTICK: SDL_InitFlag = 0x00000200;
    pub static SDL_INIT_NOPARACHUTE: SDL_InitFlag = 0x00100000;
    pub static SDL_INIT_EVENTTHREAD: SDL_InitFlag = 0x01000000;
    pub static SDL_INIT_EVERYTHING: SDL_InitFlag = 0x0000FFFF;

    pub extern {
        fn SDL_ClearError();
        fn SDL_Error(code: SDL_errorcode);
        fn SDL_SetError(fmt: *c_schar);
        fn SDL_GetError() -> *c_schar;
        fn SDL_Quit();
        fn SDL_QuitSubSystem(flags: SDL_InitFlag);
        fn SDL_Init(flags: uint32_t) -> c_int;
        fn SDL_InitSubSystem(flags: SDL_InitFlag) -> c_int;
        fn SDL_WasInit(flags: SDL_InitFlag) -> SDL_InitFlag;
    }
}

#[deriving(Eq)]
pub struct Rect {
    pub x: i16,
    pub y: i16,
    pub w: u16,
    pub h: u16
}

pub fn Rect(x: i16, y: i16, w: u16, h: u16) -> Rect {
    Rect { x: x, y: y, w: w, h: h }
}

pub impl Rect {
    fn new(x: i16, y: i16, w: u16, h: u16) -> Rect {
        Rect {
            x: x,
            y: y,
            w: w,
            h: h
        }
    }
}

#[deriving(Eq)]
pub enum InitFlag {
    pub InitTimer = ll::SDL_INIT_TIMER as int,
    pub InitAudio = ll::SDL_INIT_AUDIO as int,
    pub InitVideo = ll::SDL_INIT_VIDEO as int,
    pub InitCDRom = ll::SDL_INIT_CDROM as int,
    pub InitJoystick = ll::SDL_INIT_JOYSTICK as int,
    pub InitNoParachute = ll::SDL_INIT_NOPARACHUTE as int,
    pub InitEventThread = ll::SDL_INIT_EVENTTHREAD as int,
    pub InitEverything = ll::SDL_INIT_EVERYTHING as int,
}

#[deriving(Eq)]
pub enum Error {
    pub NoMemError = ll::SDL_ENOMEM as int,
    pub ReadError = ll::SDL_EFREAD as int,
    pub WriteError = ll::SDL_EFWRITE as int,
    pub SeekError = ll::SDL_EFSEEK as int,
    pub UnsupportedError = ll::SDL_UNSUPPORTED as int
}

pub fn init(flags: &[InitFlag]) -> bool {
    unsafe {
        ll::SDL_Init(do vec::foldl(0, flags) |flags, &flag| {
            flags | flag as ll::SDL_InitFlag
        }) == 0
    }
}

pub fn init_subsystem(flags: &[InitFlag]) -> bool {
    unsafe {
        ll::SDL_InitSubSystem(do vec::foldl(0, flags) |flags, &flag| {
            flags | flag as ll::SDL_InitFlag
        }) == 0
    }
}

pub fn quit_subsystem(flags: &[InitFlag]) {
    let flags = do vec::foldl(0, flags) |flags, &flag| {
        flags | flag as ll::SDL_InitFlag
    };

    unsafe { ll::SDL_QuitSubSystem(flags); }
}

pub fn quit() {
    unsafe { ll::SDL_Quit(); }
}

pub fn was_inited(flags: &[InitFlag]) -> ~[InitFlag] {
    let flags = do vec::foldl(0, flags) |flags, &flag| {
        flags | flag as ll::SDL_InitFlag
    };
    let bitflags = unsafe { ll::SDL_WasInit(flags) };

    do [InitTimer,
        InitAudio,
        InitVideo,
        InitCDRom,
        InitJoystick,
        InitNoParachute,
        InitEventThread,
        InitEverything].filter_mapped |&flag| {
        if bitflags & (flag as ll::SDL_InitFlag) != 0 { Some(flag) }
        else { None }
    }
}

pub fn get_error() -> ~str {
    unsafe {
        let cstr = ll::SDL_GetError();

        str::raw::from_c_str(cast::reinterpret_cast(&cstr))
    }
}

pub fn set_error(err: &str) {
    do str::as_c_str(err) |buf| {
        unsafe { ll::SDL_SetError(buf); }
    }
}

pub fn set_error_from_code(err: Error) {
    unsafe { ll::SDL_Error(err as ll::SDL_errorcode) }
}

pub fn clear_error() {
    unsafe { ll::SDL_ClearError(); }
}
<commit_msg>wrap SDL_GetTicks<commit_after>// Setup linking for all targets.
#[cfg(target_os="macos")]
mod mac {
    #[cfg(mac_framework)]
    #[link_args="-framework SDL"]
    extern {}

    #[cfg(mac_dylib)]
    #[link_args="-lSDL"]
    extern {}
}

#[cfg(target_os="win32")]
#[cfg(target_os="linux")]
#[cfg(target_os="freebsd")]
mod others {
    #[link_args="-lSDL"]
    extern {}
}

pub mod ll {
    use core::libc::{c_int, c_uint, c_schar, uint32_t};

    pub type SDL_errorcode = c_uint;
    pub static SDL_ENOMEM: SDL_errorcode = 0;
    pub static SDL_EFREAD: SDL_errorcode = 1;
    pub static SDL_EFWRITE: SDL_errorcode = 2;
    pub static SDL_EFSEEK: SDL_errorcode = 3;
    pub static SDL_UNSUPPORTED: SDL_errorcode = 4;
    pub static SDL_LASTERROR: SDL_errorcode = 5;

    pub type SDL_InitFlag = uint32_t;
    pub static SDL_INIT_TIMER: SDL_InitFlag = 0x00000001;
    pub static SDL_INIT_AUDIO: SDL_InitFlag = 0x00000010;
    pub static SDL_INIT_VIDEO: SDL_InitFlag = 0x00000020;
    pub static SDL_INIT_CDROM: SDL_InitFlag = 0x00000100;
    pub static SDL_INIT_JOYSTICK: SDL_InitFlag = 0x00000200;
    pub static SDL_INIT_NOPARACHUTE: SDL_InitFlag = 0x00100000;
    pub static SDL_INIT_EVENTTHREAD: SDL_InitFlag = 0x01000000;
    pub static SDL_INIT_EVERYTHING: SDL_InitFlag = 0x0000FFFF;

    pub extern {
        fn SDL_ClearError();
        fn SDL_Error(code: SDL_errorcode);
        fn SDL_SetError(fmt: *c_schar);
        fn SDL_GetError() -> *c_schar;
        fn SDL_Quit();
        fn SDL_QuitSubSystem(flags: SDL_InitFlag);
        fn SDL_Init(flags: uint32_t) -> c_int;
        fn SDL_InitSubSystem(flags: SDL_InitFlag) -> c_int;
        fn SDL_WasInit(flags: SDL_InitFlag) -> SDL_InitFlag;
        fn SDL_GetTicks() -> uint32_t;
    }
}

#[deriving(Eq)]
pub struct Rect {
    pub x: i16,
    pub y: i16,
    pub w: u16,
    pub h: u16
}

pub fn Rect(x: i16, y: i16, w: u16, h: u16) -> Rect {
    Rect { x: x, y: y, w: w, h: h }
}

pub impl Rect {
    fn new(x: i16, y: i16, w: u16, h: u16) -> Rect {
        Rect {
            x: x,
            y: y,
            w: w,
            h: h
        }
    }
}

#[deriving(Eq)]
pub enum InitFlag {
    pub InitTimer = ll::SDL_INIT_TIMER as int,
    pub InitAudio = ll::SDL_INIT_AUDIO as int,
    pub InitVideo = ll::SDL_INIT_VIDEO as int,
    pub InitCDRom = ll::SDL_INIT_CDROM as int,
    pub InitJoystick = ll::SDL_INIT_JOYSTICK as int,
    pub InitNoParachute = ll::SDL_INIT_NOPARACHUTE as int,
    pub InitEventThread = ll::SDL_INIT_EVENTTHREAD as int,
    pub InitEverything = ll::SDL_INIT_EVERYTHING as int,
}

#[deriving(Eq)]
pub enum Error {
    pub NoMemError = ll::SDL_ENOMEM as int,
    pub ReadError = ll::SDL_EFREAD as int,
    pub WriteError = ll::SDL_EFWRITE as int,
    pub SeekError = ll::SDL_EFSEEK as int,
    pub UnsupportedError = ll::SDL_UNSUPPORTED as int
}

pub fn init(flags: &[InitFlag]) -> bool {
    unsafe {
        ll::SDL_Init(do vec::foldl(0, flags) |flags, &flag| {
            flags | flag as ll::SDL_InitFlag
        }) == 0
    }
}

pub fn init_subsystem(flags: &[InitFlag]) -> bool {
    unsafe {
        ll::SDL_InitSubSystem(do vec::foldl(0, flags) |flags, &flag| {
            flags | flag as ll::SDL_InitFlag
        }) == 0
    }
}

pub fn quit_subsystem(flags: &[InitFlag]) {
    let flags = do vec::foldl(0, flags) |flags, &flag| {
        flags | flag as ll::SDL_InitFlag
    };

    unsafe { ll::SDL_QuitSubSystem(flags); }
}

pub fn quit() {
    unsafe { ll::SDL_Quit(); }
}

pub fn was_inited(flags: &[InitFlag]) -> ~[InitFlag] {
    let flags = do vec::foldl(0, flags) |flags, &flag| {
        flags | flag as ll::SDL_InitFlag
    };
    let bitflags = unsafe { ll::SDL_WasInit(flags) };

    do [InitTimer,
        InitAudio,
        InitVideo,
        InitCDRom,
        InitJoystick,
        InitNoParachute,
        InitEventThread,
        InitEverything].filter_mapped |&flag| {
        if bitflags & (flag as ll::SDL_InitFlag) != 0 { Some(flag) }
        else { None }
    }
}

pub fn get_error() -> ~str {
    unsafe {
        let cstr = ll::SDL_GetError();

        str::raw::from_c_str(cast::reinterpret_cast(&cstr))
    }
}

pub fn set_error(err: &str) {
    do str::as_c_str(err) |buf| {
        unsafe { ll::SDL_SetError(buf); }
    }
}

pub fn set_error_from_code(err: Error) {
    unsafe { ll::SDL_Error(err as ll::SDL_errorcode) }
}

pub fn clear_error() {
    unsafe { ll::SDL_ClearError(); }
}

pub fn get_ticks() -> uint {
    unsafe { ll::SDL_GetTicks() as uint }
}
<|endoftext|>


<commit_before>// Copyright 2017 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.

//! Functions for randomly accessing and sampling sequences.

use super::Rng;
use std::collections::hash_map::HashMap;

/// Randomly sample *up to* `amount` elements from a finite iterator.
///
/// The values are non-repeating but the order of elements returned is *not* random.
///
/// This implementation uses `O(len(iterable))` time and `O(amount)` memory.
///
/// > If `len(iterable) <= amount` then the values will be in sequential order. In all other
/// > cases the order of the elements is neither random nor guaranteed.
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let sample = seq::sample_iter(&mut rng, 1..100, 5);
/// println!("{:?}", sample);
/// ```
pub fn sample_iter<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Vec<T>
    where I: IntoIterator<Item=T>,
          R: Rng,
{
    let mut iter = iterable.into_iter();
    let mut reservoir = Vec::with_capacity(amount);
    reservoir.extend(iter.by_ref().take(amount));

    // continue unless the iterator was exhausted
    //
    // note: this prevents iterators that "restart" from causing problems.
    // If the iterator stops once, then so do we.
    if reservoir.len() == amount {
        for (i, elem) in iter.enumerate() {
            let k = rng.gen_range(0, i + 1 + amount);
            if let Some(spot) = reservoir.get_mut(k) {
                *spot = elem;
            }
        }
    } else {
        // Don't hang onto extra memory. There is a corner case where
        // `amount <<< len(iterable)` that we want to avoid.
        reservoir.shrink_to_fit();
    }
    reservoir
}

/// Randomly sample exactly `amount` values from `slice`.
///
/// The values are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// Panics if `amount > self.len()`
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let values = vec![5, 6, 1, 3, 4, 6, 7];
/// println!("{:?}", seq::sample_slice(&mut rng, &values, 3));
/// ```
pub fn sample_slice<R, T>(rng: &mut R, slice: &[T], amount: usize) -> Vec<T>
    where R: Rng,
          T: Clone
{
    let indices = sample_indices(rng, slice.len(), amount);

    let mut out = Vec::with_capacity(amount);
    out.extend(indices.iter().map(|i| slice[*i].clone()));
    out
}

/// Randomly sample exactly `amount` references from `slice`.
///
/// The references are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// Panics if `amount > self.len()`
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let values = vec![5, 6, 1, 3, 4, 6, 7];
/// println!("{:?}", seq::sample_slice_ref(&mut rng, &values, 3));
/// ```
pub fn sample_slice_ref<'a, R, T>(rng: &mut R, slice: &'a [T], amount: usize) -> Vec<&'a T>
    where R: Rng
{
    let indices = sample_indices(rng, slice.len(), amount);

    let mut out = Vec::with_capacity(amount);
    out.extend(indices.iter().map(|i| &slice[*i]));
    out
}

/// Randomly sample exactly `amount` indices from `0..length`.
///
/// The values are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// This method is used internally by the slice sampling methods, but it can sometimes be useful to
/// have the indices themselves so this is provided as an alternative.
///
/// Panics if `amount > self.len()`
pub fn sample_indices<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize>
    where R: Rng,
{
    if amount > length {
        panic!("`amount` must be less than or equal to `slice.len()`");
    }

    // We are going to have to allocate at least `amount` for the output no matter what. However,
    // if we use the `cached` version we will have to allocate `amount` as a HashMap as well since
    // it inserts an element for every loop.
    //
    // Therefore, if `amount >= length / 2` then inplace will be both faster and use less memory.
    //
    // TODO: there is probably even more fine-tuning that can be done here since
    // `HashMap::with_capacity(amount)` probably allocates more than `amount` in practice,
    // and a trade off could probably be made between memory/cpu, since hashmap operations
    // are slower than array index swapping.
    if amount >= length / 2 {
        sample_indices_inplace(rng, length, amount)
    } else {
        sample_indices_cache(rng, length, amount)
    }
}

/// Sample an amount of indices using an inplace partial fisher yates method.
///
/// This allocates the entire `length` of indices and randomizes only the first `amount`.
/// It then truncates to `amount` and returns.
///
/// This is better than using a HashMap "cache" when `amount >= length / 2` since it does not
/// require allocating an extra cache and is much faster.
fn sample_indices_inplace<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize>
    where R: Rng,
{
    debug_assert!(amount <= length);
    let mut indices: Vec<usize> = Vec::with_capacity(length);
    indices.extend(0..length);
    let end_i = if length != 0 && amount == length {
        // It isn't necessary to shuffle the final element if we are shuffling
        // the whole array... it would just be shuffled with itself
        //
        // Also, `rng.gen_range(i, i)` panics.
        amount - 1
    } else {
        amount
    };
    for i in 0..end_i {
        let j: usize = rng.gen_range(i, length);
        let tmp = indices[i];
        indices[i] = indices[j];
        indices[j] = tmp;
    }
    indices.truncate(amount);
    debug_assert_eq!(indices.len(), amount);
    indices
}

/// This method performs a partial fisher-yates on a range of indices using a HashMap
/// as a cache to record potential collisions.
///
/// The cache avoids allocating the entire `length` of values. This is especially useful when
/// `amount <<< length`, i.e. select 3 non-repeating from 1_000_000
fn sample_indices_cache<R>(
    rng: &mut R,
    length: usize,
    amount: usize,
) -> Vec<usize>
    where R: Rng,
{
    debug_assert!(amount <= length);
    let mut cache = HashMap::with_capacity(amount);
    let mut out = Vec::with_capacity(amount);
    for i in 0..amount {
        let j: usize = rng.gen_range(i, length);

        // equiv: let tmp = slice[i];
        let tmp = match cache.get(&i) {
            Some(e) => *e,
            None => i,
        };

        // equiv: slice[i] = slice[j];
        let x = match cache.get(&j) {
            Some(x) => *x,
            None => j,
        };

        // equiv: slice[j] = tmp;
        cache.insert(j, tmp);

        // note that in the inplace version, slice[i] is automatically "returned" value
        out.push(x);
    }
    debug_assert_eq!(out.len(), amount);
    out
}

#[cfg(test)]
mod test {
    use super::*;
    use {thread_rng, XorShiftRng, SeedableRng};

    #[test]
    fn test_sample_iter() {
        let min_val = 1;
        let max_val = 100;

        let mut r = thread_rng();
        let vals = (min_val..max_val).collect::<Vec<i32>>();
        let small_sample = sample_iter(&mut r, vals.iter(), 5);
        let large_sample = sample_iter(&mut r, vals.iter(), vals.len() + 5);

        assert_eq!(small_sample.len(), 5);
        assert_eq!(large_sample.len(), vals.len());

        assert!(small_sample.iter().all(|e| {
            **e >= min_val && **e <= max_val
        }));
    }
    #[test]
    fn test_sample_slice_boundaries() {
        let empty: &[u8] = &[];

        let mut r = thread_rng();

        // sample 0 items
        assert_eq!(sample_slice(&mut r, empty, 0), vec![]);
        assert_eq!(sample_slice(&mut r, &[42, 2, 42], 0), vec![]);

        // sample 1 item
        assert_eq!(sample_slice(&mut r, &[42], 1), vec![42]);
        let v = sample_slice(&mut r, &[1, 42], 1)[0];
        assert!(v == 1 || v == 42);

        // sample "all" the items
        let v = sample_slice(&mut r, &[42, 133], 2);
        assert!(v == vec![42, 133] || v == vec![133, 42]);
    }

    #[test]
    fn test_sample_slice() {
        let xor_rng = XorShiftRng::from_seed;

        let max_range = 100;
        let mut r = thread_rng();

        for length in 1usize..max_range {
            let amount = r.gen_range(0, length);
            let seed: [u32; 4] = [
                r.next_u32(), r.next_u32(), r.next_u32(), r.next_u32()
            ];

            println!("Selecting indices: len={}, amount={}, seed={:?}", length, amount, seed);

            // assert that the two index methods give exactly the same result
            let inplace = sample_indices_inplace(
                &mut xor_rng(seed), length, amount);
            let cache = sample_indices_cache(
                &mut xor_rng(seed), length, amount);
            assert_eq!(inplace, cache);

            // assert the basics work
            let regular = sample_indices(
                &mut xor_rng(seed), length, amount);
            assert_eq!(regular.len(), amount);
            assert!(regular.iter().all(|e| *e < length));
            assert_eq!(regular, inplace);

            // also test that sampling the slice works
            let vec: Vec<usize> = (0..length).collect();
            {
                let result = sample_slice(&mut xor_rng(seed), &vec, amount);
                assert_eq!(result, regular);
            }

            {
                let result = sample_slice_ref(&mut xor_rng(seed), &vec, amount);
                let expected = regular.iter().map(|v| v).collect::<Vec<_>>();
                assert_eq!(result, expected);
            }
        }
    }
}
<commit_msg>clean up some warts<commit_after>// Copyright 2017 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.

//! Functions for randomly accessing and sampling sequences.

use super::Rng;
use std::collections::hash_map::HashMap;

/// Randomly sample *up to* `amount` elements from a finite iterator.
///
/// The values are non-repeating but the order of elements returned is *not* random.
///
/// This implementation uses `O(len(iterable))` time and `O(amount)` memory.
///
/// > If `len(iterable) <= amount` then the values will be in sequential order. In all other
/// > cases the order of the elements is neither random nor guaranteed.
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let sample = seq::sample_iter(&mut rng, 1..100, 5);
/// println!("{:?}", sample);
/// ```
pub fn sample_iter<T, I, R>(rng: &mut R, iterable: I, amount: usize) -> Vec<T>
    where I: IntoIterator<Item=T>,
          R: Rng,
{
    let mut iter = iterable.into_iter();
    let mut reservoir = Vec::with_capacity(amount);
    reservoir.extend(iter.by_ref().take(amount));

    // continue unless the iterator was exhausted
    //
    // note: this prevents iterators that "restart" from causing problems.
    // If the iterator stops once, then so do we.
    if reservoir.len() == amount {
        for (i, elem) in iter.enumerate() {
            let k = rng.gen_range(0, i + 1 + amount);
            if let Some(spot) = reservoir.get_mut(k) {
                *spot = elem;
            }
        }
    } else {
        // Don't hang onto extra memory. There is a corner case where
        // `amount <<< len(iterable)` that we want to avoid.
        reservoir.shrink_to_fit();
    }
    reservoir
}

/// Randomly sample exactly `amount` values from `slice`.
///
/// The values are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// Panics if `amount > self.len()`
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let values = vec![5, 6, 1, 3, 4, 6, 7];
/// println!("{:?}", seq::sample_slice(&mut rng, &values, 3));
/// ```
pub fn sample_slice<R, T>(rng: &mut R, slice: &[T], amount: usize) -> Vec<T>
    where R: Rng,
          T: Clone
{
    let indices = sample_indices(rng, slice.len(), amount);

    let mut out = Vec::with_capacity(amount);
    out.extend(indices.iter().map(|i| slice[*i].clone()));
    out
}

/// Randomly sample exactly `amount` references from `slice`.
///
/// The references are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// Panics if `amount > self.len()`
///
/// # Example
///
/// ```rust
/// use rand::{thread_rng, seq};
///
/// let mut rng = thread_rng();
/// let values = vec![5, 6, 1, 3, 4, 6, 7];
/// println!("{:?}", seq::sample_slice_ref(&mut rng, &values, 3));
/// ```
pub fn sample_slice_ref<'a, R, T>(rng: &mut R, slice: &'a [T], amount: usize) -> Vec<&'a T>
    where R: Rng
{
    let indices = sample_indices(rng, slice.len(), amount);

    let mut out = Vec::with_capacity(amount);
    out.extend(indices.iter().map(|i| &slice[*i]));
    out
}

/// Randomly sample exactly `amount` indices from `0..length`.
///
/// The values are non-repeating and in random order.
///
/// This implementation uses `O(amount)` time and memory.
///
/// This method is used internally by the slice sampling methods, but it can sometimes be useful to
/// have the indices themselves so this is provided as an alternative.
///
/// Panics if `amount > self.len()`
pub fn sample_indices<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize>
    where R: Rng,
{
    if amount > length {
        panic!("`amount` must be less than or equal to `slice.len()`");
    }

    // We are going to have to allocate at least `amount` for the output no matter what. However,
    // if we use the `cached` version we will have to allocate `amount` as a HashMap as well since
    // it inserts an element for every loop.
    //
    // Therefore, if `amount >= length / 2` then inplace will be both faster and use less memory.
    //
    // TODO: there is probably even more fine-tuning that can be done here since
    // `HashMap::with_capacity(amount)` probably allocates more than `amount` in practice,
    // and a trade off could probably be made between memory/cpu, since hashmap operations
    // are slower than array index swapping.
    if amount >= length / 2 {
        sample_indices_inplace(rng, length, amount)
    } else {
        sample_indices_cache(rng, length, amount)
    }
}

/// Sample an amount of indices using an inplace partial fisher yates method.
///
/// This allocates the entire `length` of indices and randomizes only the first `amount`.
/// It then truncates to `amount` and returns.
///
/// This is better than using a HashMap "cache" when `amount >= length / 2` since it does not
/// require allocating an extra cache and is much faster.
fn sample_indices_inplace<R>(rng: &mut R, length: usize, amount: usize) -> Vec<usize>
    where R: Rng,
{
    debug_assert!(amount <= length);
    let mut indices: Vec<usize> = Vec::with_capacity(length);
    indices.extend(0..length);
    for i in 0..amount {
        let j: usize = rng.gen_range(i, length);
        let tmp = indices[i];
        indices[i] = indices[j];
        indices[j] = tmp;
    }
    indices.truncate(amount);
    debug_assert_eq!(indices.len(), amount);
    indices
}

/// This method performs a partial fisher-yates on a range of indices using a HashMap
/// as a cache to record potential collisions.
///
/// The cache avoids allocating the entire `length` of values. This is especially useful when
/// `amount <<< length`, i.e. select 3 non-repeating from 1_000_000
fn sample_indices_cache<R>(
    rng: &mut R,
    length: usize,
    amount: usize,
) -> Vec<usize>
    where R: Rng,
{
    debug_assert!(amount <= length);
    let mut cache = HashMap::with_capacity(amount);
    let mut out = Vec::with_capacity(amount);
    for i in 0..amount {
        let j: usize = rng.gen_range(i, length);

        // equiv: let tmp = slice[i];
        let tmp = match cache.get(&i) {
            Some(e) => *e,
            None => i,
        };

        // equiv: slice[i] = slice[j];
        let x = match cache.get(&j) {
            Some(x) => *x,
            None => j,
        };

        // equiv: slice[j] = tmp;
        cache.insert(j, tmp);

        // note that in the inplace version, slice[i] is automatically "returned" value
        out.push(x);
    }
    debug_assert_eq!(out.len(), amount);
    out
}

#[cfg(test)]
mod test {
    use super::*;
    use {thread_rng, XorShiftRng, SeedableRng};

    #[test]
    fn test_sample_iter() {
        let min_val = 1;
        let max_val = 100;

        let mut r = thread_rng();
        let vals = (min_val..max_val).collect::<Vec<i32>>();
        let small_sample = sample_iter(&mut r, vals.iter(), 5);
        let large_sample = sample_iter(&mut r, vals.iter(), vals.len() + 5);

        assert_eq!(small_sample.len(), 5);
        assert_eq!(large_sample.len(), vals.len());

        assert!(small_sample.iter().all(|e| {
            **e >= min_val && **e <= max_val
        }));
    }
    #[test]
    fn test_sample_slice_boundaries() {
        let empty: &[u8] = &[];

        let mut r = thread_rng();

        // sample 0 items
        assert_eq!(sample_slice(&mut r, empty, 0), vec![]);
        assert_eq!(sample_slice(&mut r, &[42, 2, 42], 0), vec![]);

        // sample 1 item
        assert_eq!(sample_slice(&mut r, &[42], 1), vec![42]);
        let v = sample_slice(&mut r, &[1, 42], 1)[0];
        assert!(v == 1 || v == 42);

        // sample "all" the items
        let v = sample_slice(&mut r, &[42, 133], 2);
        assert!(v == vec![42, 133] || v == vec![133, 42]);

        assert_eq!(sample_indices_inplace(&mut r, 0, 0), vec![]);
        assert_eq!(sample_indices_inplace(&mut r, 1, 0), vec![]);
        assert_eq!(sample_indices_inplace(&mut r, 1, 1), vec![0]);

        assert_eq!(sample_indices_cache(&mut r, 0, 0), vec![]);
        assert_eq!(sample_indices_cache(&mut r, 1, 0), vec![]);
        assert_eq!(sample_indices_cache(&mut r, 1, 1), vec![0]);

    }

    #[test]
    fn test_sample_slice() {
        let xor_rng = XorShiftRng::from_seed;

        let max_range = 100;
        let mut r = thread_rng();

        for length in 1usize..max_range {
            let amount = r.gen_range(0, length);
            let seed: [u32; 4] = [
                r.next_u32(), r.next_u32(), r.next_u32(), r.next_u32()
            ];

            println!("Selecting indices: len={}, amount={}, seed={:?}", length, amount, seed);

            // assert that the two index methods give exactly the same result
            let inplace = sample_indices_inplace(
                &mut xor_rng(seed), length, amount);
            let cache = sample_indices_cache(
                &mut xor_rng(seed), length, amount);
            assert_eq!(inplace, cache);

            // assert the basics work
            let regular = sample_indices(
                &mut xor_rng(seed), length, amount);
            assert_eq!(regular.len(), amount);
            assert!(regular.iter().all(|e| *e < length));
            assert_eq!(regular, inplace);

            // also test that sampling the slice works
            let vec: Vec<usize> = (0..length).collect();
            {
                let result = sample_slice(&mut xor_rng(seed), &vec, amount);
                assert_eq!(result, regular);
            }

            {
                let result = sample_slice_ref(&mut xor_rng(seed), &vec, amount);
                let expected = regular.iter().map(|v| v).collect::<Vec<_>>();
                assert_eq!(result, expected);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Rocket's logging infrastructure.

use std::str::FromStr;

use log::{self, Log, LogLevel, LogRecord, LogMetadata};
use term_painter::Color::*;
use term_painter::ToStyle;

struct RocketLogger(LoggingLevel);

/// Defines the different levels for log messages.
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum LoggingLevel {
    /// Only shows errors and warning.
    Critical,
    /// Shows everything except debug and trace information.
    Normal,
    /// Shows everything.
    Debug,
}

impl LoggingLevel {
    #[inline(always)]
    fn max_log_level(&self) -> LogLevel {
        match *self {
            LoggingLevel::Critical => LogLevel::Warn,
            LoggingLevel::Normal => LogLevel::Info,
            LoggingLevel::Debug => LogLevel::Trace,
        }
    }
}

impl FromStr for LoggingLevel {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let level = match s {
            "critical" => LoggingLevel::Critical,
            "normal" => LoggingLevel::Normal,
            "debug" => LoggingLevel::Debug,
            _ => return Err(())
        };

        Ok(level)
    }
}

#[macro_export]
macro_rules! log_ {
    ($name:ident: $format:expr) => { log_!($name: $format,) };
    ($name:ident: $format:expr, $($args:expr),*) => {
        $name!(target: "_", $format, $($args),*);
    };
}

#[macro_export]
macro_rules! error_ { ($($args:expr),+) => { log_!(error: $($args),+); }; }
#[macro_export]
macro_rules! info_ { ($($args:expr),+) => { log_!(info: $($args),+); }; }
#[macro_export]
macro_rules! trace_ { ($($args:expr),+) => { log_!(trace: $($args),+); }; }
#[macro_export]
macro_rules! debug_ { ($($args:expr),+) => { log_!(debug: $($args),+); }; }
#[macro_export]
macro_rules! warn_ { ($($args:expr),+) => { log_!(warn: $($args),+); }; }

impl Log for RocketLogger {
    fn enabled(&self, md: &LogMetadata) -> bool {
        md.level() <= self.0.max_log_level()
    }

    fn log(&self, record: &LogRecord) {
        // Print nothing if this level isn't enabled.
        if !self.enabled(record.metadata()) {
            return;
        }

        // Don't print Hyper's messages unless Debug is enabled.
        let from_hyper = record.location().module_path().starts_with("hyper::");
        if from_hyper && self.0 != LoggingLevel::Debug {
            return;
        }

        // In Rocket, we abuse target with value "_" to indicate indentation.
        if record.target() == "_" && self.0 != LoggingLevel::Critical {
            print!("    {} ", White.paint("=>"));
        }

        use log::LogLevel::*;
        match record.level() {
            Info => println!("{}", Blue.paint(record.args())),
            Trace => println!("{}", Magenta.paint(record.args())),
            Error => {
                println!("{} {}",
                         Red.bold().paint("Error:"),
                         Red.paint(record.args()))
            }
            Warn => {
                println!("{} {}",
                         Yellow.bold().paint("Warning:"),
                         Yellow.paint(record.args()))
            }
            Debug => {
                let loc = record.location();
                print!("\n{} ", Blue.bold().paint("-->"));
                println!("{}:{}", Blue.paint(loc.file()), Blue.paint(loc.line()));
                println!("{}", record.args());
            }
        }
    }
}

#[doc(hidden)]
pub fn init(level: LoggingLevel) {
    let result = log::set_logger(|max_log_level| {
        max_log_level.set(level.max_log_level().to_log_level_filter());
        Box::new(RocketLogger(level))
    });

    if let Err(err) = result {
        println!("Logger failed to initialize: {}", err);
    }
}
<commit_msg>Hide all of the logger macros, for now.<commit_after>//! Rocket's logging infrastructure.

use std::str::FromStr;

use log::{self, Log, LogLevel, LogRecord, LogMetadata};
use term_painter::Color::*;
use term_painter::ToStyle;

struct RocketLogger(LoggingLevel);

/// Defines the different levels for log messages.
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum LoggingLevel {
    /// Only shows errors and warning.
    Critical,
    /// Shows everything except debug and trace information.
    Normal,
    /// Shows everything.
    Debug,
}

impl LoggingLevel {
    #[inline(always)]
    fn max_log_level(&self) -> LogLevel {
        match *self {
            LoggingLevel::Critical => LogLevel::Warn,
            LoggingLevel::Normal => LogLevel::Info,
            LoggingLevel::Debug => LogLevel::Trace,
        }
    }
}

impl FromStr for LoggingLevel {
    type Err = ();
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let level = match s {
            "critical" => LoggingLevel::Critical,
            "normal" => LoggingLevel::Normal,
            "debug" => LoggingLevel::Debug,
            _ => return Err(())
        };

        Ok(level)
    }
}

#[doc(hidden)] #[macro_export]
macro_rules! log_ {
    ($name:ident: $format:expr) => { log_!($name: $format,) };
    ($name:ident: $format:expr, $($args:expr),*) => {
        $name!(target: "_", $format, $($args),*);
    };
}

#[doc(hidden)] #[macro_export]
macro_rules! error_ { ($($args:expr),+) => { log_!(error: $($args),+); }; }
#[doc(hidden)] #[macro_export]
macro_rules! info_ { ($($args:expr),+) => { log_!(info: $($args),+); }; }
#[doc(hidden)] #[macro_export]
macro_rules! trace_ { ($($args:expr),+) => { log_!(trace: $($args),+); }; }
#[doc(hidden)] #[macro_export]
macro_rules! debug_ { ($($args:expr),+) => { log_!(debug: $($args),+); }; }
#[doc(hidden)] #[macro_export]
macro_rules! warn_ { ($($args:expr),+) => { log_!(warn: $($args),+); }; }

impl Log for RocketLogger {
    fn enabled(&self, md: &LogMetadata) -> bool {
        md.level() <= self.0.max_log_level()
    }

    fn log(&self, record: &LogRecord) {
        // Print nothing if this level isn't enabled.
        if !self.enabled(record.metadata()) {
            return;
        }

        // Don't print Hyper's messages unless Debug is enabled.
        let from_hyper = record.location().module_path().starts_with("hyper::");
        if from_hyper && self.0 != LoggingLevel::Debug {
            return;
        }

        // In Rocket, we abuse target with value "_" to indicate indentation.
        if record.target() == "_" && self.0 != LoggingLevel::Critical {
            print!("    {} ", White.paint("=>"));
        }

        use log::LogLevel::*;
        match record.level() {
            Info => println!("{}", Blue.paint(record.args())),
            Trace => println!("{}", Magenta.paint(record.args())),
            Error => {
                println!("{} {}",
                         Red.bold().paint("Error:"),
                         Red.paint(record.args()))
            }
            Warn => {
                println!("{} {}",
                         Yellow.bold().paint("Warning:"),
                         Yellow.paint(record.args()))
            }
            Debug => {
                let loc = record.location();
                print!("\n{} ", Blue.bold().paint("-->"));
                println!("{}:{}", Blue.paint(loc.file()), Blue.paint(loc.line()));
                println!("{}", record.args());
            }
        }
    }
}

#[doc(hidden)]
pub fn init(level: LoggingLevel) {
    let result = log::set_logger(|max_log_level| {
        max_log_level.set(level.max_log_level().to_log_level_filter());
        Box::new(RocketLogger(level))
    });

    if let Err(err) = result {
        println!("Logger failed to initialize: {}", err);
    }
}
<|endoftext|>


<commit_before>extern crate serde_json;

#[macro_use]
mod spec;
mod block;
mod view;
mod config;

use std::borrow::Borrow;
use std::ops::Deref;

use time::Timespec;

use byteorder::{ByteOrder, BigEndian};

use ::crypto::{PublicKey, Hash, hash};
use ::messages::{Any, Precommit, Message, ConfigMessage, ServiceTransaction, ConfigPropose, ConfigVote, TransactionMessage, RawMessage, AnyTx};
use ::storage::{StorageValue, Patch, Database, Fork, Error, Map, List};

pub use self::block::Block;
pub use self::view::{View, ConfigurationData, HeightBytecode};
pub use self::view::ConfigurationData;
pub use self::config::{StoredConfiguration, ConsensusCfg};

pub trait Blockchain: Sized + Clone + Send + Sync + 'static
    where Self: Deref<Target = <Self as Blockchain>::Database>
{
    type View: View<<<Self as Blockchain>::Database as Database>::Fork, Transaction=Self::Transaction>;
    type Database: Database;
    type Transaction: Message + StorageValue;

    fn last_hash(&self) -> Result<Option<Hash>, Error> {
        self.view().heights().last()
    }

    fn last_block(&self) -> Result<Option<Block>, Error> {
        let view = self.view();
        Ok(match view.heights().last()? {
            Some(hash) => Some(view.blocks().get(&hash)?.unwrap()),
            None => None,
        })
    }

    fn verify_tx(tx: &Self::Transaction) -> bool;
    fn state_hash(fork: &Self::View) -> Result<Hash, Error>;
    fn execute(fork: &Self::View, tx: &Self::Transaction) -> Result<(), Error>;
    // FIXME make private
    fn execute_service_tx(_: &Self::View, _: &ServiceTx) -> Result<(), Error> {
        unimplemented!();
    }

    // TODO use Iterator to avoid memory allocations?
    fn create_patch(&self,
                    height: u64,
                    round: u32,
                    time: Timespec,
                    txs: &[(Hash, AnyTx<Self::Transaction>)])
                    -> Result<(Hash, Vec<Hash>, Patch), Error> {
        // Get last hash
        let last_hash = self.last_hash()?.unwrap_or_else(|| hash(&[]));
        // Create fork
        let fork = self.view();
        // Save & execute transactions
        let mut tx_hashes = Vec::new();
        for &(hash, ref tx) in txs {

            match *tx {
                AnyTx::Application(ref tx) => Self::execute(&fork, tx)?,
                AnyTx::Service(ref tx) => Self::execute_service_tx(&fork, tx)?,
            }
            fork.transactions()
                .put(&hash, tx.clone())
                .unwrap();
            fork.block_txs(height)
                .append(hash)
                .unwrap();
            tx_hashes.push(hash);
        }
        // Get tx hash
        let tx_hash = fork.block_txs(height).root_hash()?;
        // Get state hash
        let state_hash = Self::state_hash(&fork)?;
        // Create block
        let block = Block::new(height, round, time, &last_hash, &tx_hash, &state_hash);
        // Eval block hash
        let block_hash = block.hash();
        // Update height
        // TODO: check that height == propose.height
        fork.heights().append(block_hash).is_ok();
        // Save block
        fork.blocks().put(&block_hash, block).is_ok();
        Ok((block_hash, tx_hashes, fork.changes()))
    }

    fn execute_service_tx(&self, tx: ServiceTransaction) {
        match tx {
            ServiceTransaction::ConfigChange(config_message) => {
                self.execute_config_change(config_message);
            }
        }
    }

    fn execute_config_change(&self, config_message: ConfigMessage) {
        match config_message {
            ConfigMessage::ConfigPropose(config_propose_tx) => {
                self.handle_config_propose(config_propose_tx);
            }
            ConfigMessage::ConfigVote(config_vote_tx) => {
                self.handle_config_vote(config_vote_tx);
            }
        }
    }

    fn get_height(&self) -> u64 {
        let r = self.last_block().unwrap();
        if let Some(last_block) = r {
            last_block.height() + 1
        } else {
            0
        }
    }

    fn get_actual_configuration(&self) -> Option<StoredConfiguration> {

        let h = self.get_height();

        let view = self.view();

        let heights = view.configs_heights();

        if let Ok(height_values) = heights.values() {

            if let Some(idx) = height_values.into_iter()
                .rposition(|r| u64::from(r) <= h) {
                if let Ok(Some(height)) = heights.get(idx as u64) {
                    return self.get_configuration_at_height(height.into());
                }
            }
        }
        None
    }

    fn get_configuration_at_height(&self, height: u64) -> Option<StoredConfiguration> {
        let view = self.view();
        let configs = view.configs();
        if let Ok(config) = configs.get(&height.into()) {
            match StoredConfiguration::deserialize(&config.unwrap()) {
                Ok(configuration) => {
                    return Some(configuration);
                }
                Err(_) => {
                    error!("Can't parse found configuration at height: {}", height);
                }
            }
        }
        None
    }

    fn handle_config_propose(&self, config_propose: ConfigPropose) {

        if let Some(config) = self.get_actual_configuration() {
            if !config.validators.contains(config_propose.from()) {
                error!("ConfigPropose from unknown validator: {:?}",
                       config_propose.from());
                return;
            }

            let view = self.view();
            let hash = <ConfigPropose as Message>::hash(&config_propose);
            if view.config_proposes().get(&hash).unwrap().is_some() {
                error!("Received config_propose has already been handled, msg={:?}",
                       config_propose);
                return;
            }

            trace!("Handle ConfigPropose");
            let _ = view.config_proposes().put(&hash, config_propose);
        }
    }

    fn handle_config_vote(&self, config_vote: ConfigVote) {

        if let Some(config) = self.get_actual_configuration() {

            if !config.validators.contains(config_vote.from()) {
                error!("ConfigVote from unknown validator: {:?}",
                       config_vote.from());
                return;
            }

            let view = self.view();
            if view.config_proposes().get(config_vote.hash_propose()).unwrap().is_some() {
                error!("Received config_vote for unknown transaciton, msg={:?}",
                       config_vote);
                return;
            }

            if let Some(vote) = view.config_votes().get(config_vote.from()).unwrap() {
                if vote.seed() != config_vote.seed() - 1 {
                    error!("Received config_vote with wrong seed, msg={:?}",
                           config_vote);
                    return;
                }
            }

            let msg = config_vote.clone();
            let _ = view.config_votes().put(msg.from(), config_vote.clone());

            let mut votes_count = 0;
            for pub_key in config.validators.clone() {
                if let Some(vote) = view.config_votes().get(&pub_key).unwrap() {
                    if !vote.revoke() {
                        votes_count += 1;
                    }
                }
            }

            if votes_count >= 2/3 * config.validators.len(){
                if let Some(config_propose) = view.config_proposes().get(config_vote.hash_propose()).unwrap() {
                    let height_bytecode = config_propose.actual_from_height().into();
                    view.configs().put(&height_bytecode, config_propose.config().to_vec()).unwrap();
                    view.configs_heights().append(height_bytecode).unwrap();
                    // TODO: clear storages
                }
            }
        }
    }

    fn commit<'a, I: Iterator<Item = &'a Precommit>>(&self,
                                                     block_hash: Hash,
                                                     patch: &Patch,
                                                     precommits: I)
                                                     -> Result<(), Error> {
        let patch = {
            let view = self.view();
            view.merge(patch);

            for precommit in precommits {
                view.precommits(&block_hash).append(precommit.clone())?;
            }

            view.changes()
        };

        self.merge(&patch)
    }

    fn view(&self) -> Self::View {
        Self::View::from_fork(self.borrow().fork())
    }

    fn merge(&self, patch: &Patch) -> Result<(), Error> {
        self.deref().merge(patch)
    }
}
<commit_msg>Fix clippy warnings and txs in drm<commit_after>extern crate serde_json;

#[macro_use]
mod spec;
mod block;
mod view;
mod config;

use std::borrow::Borrow;
use std::ops::Deref;

use time::Timespec;

use byteorder::{ByteOrder, BigEndian};

use ::crypto::{PublicKey, Hash, hash};
use ::messages::{Any, Precommit, Message, ConfigMessage, ServiceTransaction, ConfigPropose, ConfigVote, TransactionMessage, RawMessage, AnyTx};

use ::storage::{StorageValue, Patch, Database, Fork, Error, Map, List};

pub use self::block::Block;
pub use self::view::{View, ConfigurationData, HeightBytecode};
pub use self::view::ConfigurationData;
pub use self::config::{StoredConfiguration, ConsensusCfg};

pub trait Blockchain: Sized + Clone + Send + Sync + 'static
    where Self: Deref<Target = <Self as Blockchain>::Database>
{
    type View: View<<<Self as Blockchain>::Database as Database>::Fork, Transaction=Self::Transaction>;
    type Database: Database;
    type Transaction: Message + StorageValue;

    fn last_hash(&self) -> Result<Option<Hash>, Error> {
        self.view().heights().last()
    }

    fn last_block(&self) -> Result<Option<Block>, Error> {
        let view = self.view();
        Ok(match view.heights().last()? {
            Some(hash) => Some(view.blocks().get(&hash)?.unwrap()),
            None => None,
        })
    }

    fn verify_tx(tx: &Self::Transaction) -> bool;
    fn state_hash(fork: &Self::View) -> Result<Hash, Error>;
    fn execute(fork: &Self::View, tx: &Self::Transaction) -> Result<(), Error>;
    // FIXME make private
    fn execute_service_tx(_: &Self::View, _: &ServiceTx) -> Result<(), Error> {
        unimplemented!();
    }

    // TODO use Iterator to avoid memory allocations?
    fn create_patch(&self,
                    height: u64,
                    round: u32,
                    time: Timespec,
                    txs: &[(Hash, AnyTx<Self::Transaction>)])
                    -> Result<(Hash, Vec<Hash>, Patch), Error> {
        // Get last hash
        let last_hash = self.last_hash()?.unwrap_or_else(|| hash(&[]));
        // Create fork
        let fork = self.view();
        // Save & execute transactions
        let mut tx_hashes = Vec::new();
        for &(hash, ref tx) in txs {

            match *tx {
                AnyTx::Application(ref tx) => Self::execute(&fork, tx)?,
                AnyTx::Service(ref tx) => Self::execute_service_tx(&fork, tx)?,
            }
            fork.transactions()
                .put(&hash, tx.clone())
                .unwrap();
            fork.block_txs(height)
                .append(hash)
                .unwrap();
            tx_hashes.push(hash);
        }
        // Get tx hash
        let tx_hash = fork.block_txs(height).root_hash()?;
        // Get state hash
        let state_hash = Self::state_hash(&fork)?;
        // Create block
        let block = Block::new(height, round, time, &last_hash, &tx_hash, &state_hash);
        // Eval block hash
        let block_hash = block.hash();
        // Update height
        // TODO: check that height == propose.height
        fork.heights().append(block_hash).is_ok();
        // Save block
        fork.blocks().put(&block_hash, block).is_ok();
        Ok((block_hash, tx_hashes, fork.changes()))
    }

    fn execute_service_tx(&self, tx: ServiceTransaction) {
        match tx {
            ServiceTransaction::ConfigChange(config_message) => {
                self.execute_config_change(config_message);
            }
        }
    }

    fn execute_config_change(&self, config_message: ConfigMessage) {
        match config_message {
            ConfigMessage::ConfigPropose(config_propose_tx) => {
                self.handle_config_propose(config_propose_tx);
            }
            ConfigMessage::ConfigVote(config_vote_tx) => {
                self.handle_config_vote(config_vote_tx);
            }
        }
    }

    fn get_height(&self) -> u64 {
        let r = self.last_block().unwrap();
        if let Some(last_block) = r {
            last_block.height() + 1
        } else {
            0
        }
    }

    fn get_actual_configuration(&self) -> Option<StoredConfiguration> {

        let h = self.get_height();

        let view = self.view();

        let heights = view.configs_heights();

        if let Ok(height_values) = heights.values() {

            if let Some(idx) = height_values.into_iter()
                .rposition(|r| u64::from(r) <= h) {
                if let Ok(Some(height)) = heights.get(idx as u64) {
                    return self.get_configuration_at_height(height.into());
                }
            }
        }
        None
    }

    fn get_configuration_at_height(&self, height: u64) -> Option<StoredConfiguration> {
        let view = self.view();
        let configs = view.configs();
        if let Ok(config) = configs.get(&height.into()) {
            match StoredConfiguration::deserialize(&config.unwrap()) {
                Ok(configuration) => {
                    return Some(configuration);
                }
                Err(_) => {
                    error!("Can't parse found configuration at height: {}", height);
                }
            }
        }
        None
    }

    fn handle_config_propose(&self, config_propose: ConfigPropose) {

        if let Some(config) = self.get_actual_configuration() {
            if !config.validators.contains(config_propose.from()) {
                error!("ConfigPropose from unknown validator: {:?}",
                       config_propose.from());
                return;
            }

            let view = self.view();
            let hash = <ConfigPropose as Message>::hash(&config_propose);
            if view.config_proposes().get(&hash).unwrap().is_some() {
                error!("Received config_propose has already been handled, msg={:?}",
                       config_propose);
                return;
            }

            trace!("Handle ConfigPropose");
            let _ = view.config_proposes().put(&hash, config_propose);
        }
    }

    fn handle_config_vote(&self, config_vote: ConfigVote) {

        if let Some(config) = self.get_actual_configuration() {

            if !config.validators.contains(config_vote.from()) {
                error!("ConfigVote from unknown validator: {:?}",
                       config_vote.from());
                return;
            }

            let view = self.view();
            if view.config_proposes().get(config_vote.hash_propose()).unwrap().is_some() {
                error!("Received config_vote for unknown transaciton, msg={:?}",
                       config_vote);
                return;
            }

            if let Some(vote) = view.config_votes().get(config_vote.from()).unwrap() {
                if vote.seed() != config_vote.seed() - 1 {
                    error!("Received config_vote with wrong seed, msg={:?}",
                           config_vote);
                    return;
                }
            }

            let msg = config_vote.clone();
            let _ = view.config_votes().put(msg.from(), config_vote.clone());

            let mut votes_count = 0;
            for pub_key in config.validators.clone() {
                if let Some(vote) = view.config_votes().get(&pub_key).unwrap() {
                    if !vote.revoke() {
                        votes_count += 1;
                    }
                }
            }

            if votes_count >= 2 / 3 * config.validators.len() {
                if let Some(config_propose) = view.config_proposes()
                    .get(config_vote.hash_propose())
                    .unwrap() {
                    let height_bytecode = config_propose.actual_from_height().into();
                    view.configs().put(&height_bytecode, config_propose.config().to_vec()).unwrap();
                    view.configs_heights().append(height_bytecode).unwrap();
                    // TODO: clear storages
                }
            }
        }
    }

    fn commit<'a, I: Iterator<Item = &'a Precommit>>(&self,
                                                     block_hash: Hash,
                                                     patch: &Patch,
                                                     precommits: I)
                                                     -> Result<(), Error> {
        let patch = {
            let view = self.view();
            view.merge(patch);

            for precommit in precommits {
                view.precommits(&block_hash).append(precommit.clone())?;
            }

            view.changes()
        };

        self.merge(&patch)
    }

    fn view(&self) -> Self::View {
        Self::View::from_fork(self.borrow().fork())
    }

    fn merge(&self, patch: &Patch) -> Result<(), Error> {
        self.deref().merge(patch)
    }
}
<|endoftext|>


<commit_before>//! Enviroment data

use alloc::boxed::Box;

use fs::File;
use path::{Path, PathBuf};
use io::Result;
use string::{String, ToString};
use vec::Vec;

use system::error::{Error, ENOENT};
use system::syscall::sys_chdir;

static mut _args: *mut Vec<&'static str> = 0 as *mut Vec<&'static str>;

pub struct Args {
    i: usize
}

impl Iterator for Args {
    //Yes, this is supposed to be String, do not change it!
    //Only change it if https://doc.rust-lang.org/std/env/struct.Args.html changes from String
    type Item = String;
    fn next(&mut self) -> Option<String> {
        if let Some(arg) = unsafe { (*_args).get(self.i) } {
            self.i += 1;
            Some(arg.to_string())
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = if self.i <= unsafe { (*_args).len() } {
            unsafe { (*_args).len() - self.i }
        } else {
            0
        };
        (len, Some(len))
    }
}

impl ExactSizeIterator for Args {}

/// Arguments
pub fn args() -> Args {
    Args {
        i: 0
    }
}

/// Initialize arguments
pub unsafe fn args_init(args: Vec<&'static str>) {
    _args = Box::into_raw(box args);
}

/// Destroy arguments
pub unsafe fn args_destroy() {
    if _args as usize > 0 {
        drop(Box::from_raw(_args));
    }
}

/// Method to return the current directory
/// If the current directory cannot be found, None will be returned
pub fn current_dir() -> Result<PathBuf> {
    // Return the current path
    match File::open("./") {
        Ok(file) => {
            match file.path() {
                Ok(path) => Ok(path),
                Err(err) => Err(err),
            }
        }
        Err(err) => Err(err),
    }
}

/// Set the current directory
pub fn set_current_dir<P: AsRef<Path>>(path: P) -> Result<()> {
    let file_result = if path.as_ref().inner.is_empty() || path.as_ref().inner.ends_with('/') {
        File::open(&path.as_ref().inner)
    } else {
        File::open(&(path.as_ref().inner.to_string() + "/"))
    };

    match file_result {
        Ok(file) => {
            match file.path() {
                Ok(path) => {
                    if let Some(path_str) = path.to_str() {
                        let path_c = path_str.to_string() + "\0";
                        match Error::demux(unsafe { sys_chdir(path_c.as_ptr()) }) {
                            Ok(_) => Ok(()),
                            Err(err) => Err(err),
                        }
                    } else {
                        Err(Error::new(ENOENT))
                    }
                }
                Err(err) => Err(err),
            }
        }
        Err(err) => Err(err),
    }
}

// TODO: Fully implement `env::var()`
pub fn var(_key: &str) -> Result<String> {
    Ok("This is code filler".to_string())
}
<commit_msg>Method to return the path from a custom location<commit_after>//! Enviroment data

use alloc::boxed::Box;

use fs::File;
use path::{Path, PathBuf};
use io::Result;
use string::{String, ToString};
use vec::Vec;

use system::error::{Error, ENOENT};
use system::syscall::sys_chdir;

static mut _args: *mut Vec<&'static str> = 0 as *mut Vec<&'static str>;

pub struct Args {
    i: usize
}

impl Iterator for Args {
    //Yes, this is supposed to be String, do not change it!
    //Only change it if https://doc.rust-lang.org/std/env/struct.Args.html changes from String
    type Item = String;
    fn next(&mut self) -> Option<String> {
        if let Some(arg) = unsafe { (*_args).get(self.i) } {
            self.i += 1;
            Some(arg.to_string())
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = if self.i <= unsafe { (*_args).len() } {
            unsafe { (*_args).len() - self.i }
        } else {
            0
        };
        (len, Some(len))
    }
}

impl ExactSizeIterator for Args {}

/// Arguments
pub fn args() -> Args {
    Args {
        i: 0
    }
}

/// Initialize arguments
pub unsafe fn args_init(args: Vec<&'static str>) {
    _args = Box::into_raw(box args);
}

/// Destroy arguments
pub unsafe fn args_destroy() {
    if _args as usize > 0 {
        drop(Box::from_raw(_args));
    }
}

/// Private function to get the path from a custom location
/// If the custom directory cannot be found, None will be returned
fn get_path_from(location : &str) -> Result<PathBuf> {
    match File::open(dir) {
        Ok(file) => {
            match file.path() {
                Ok(path) => Ok(path),
                Err(err) => Err(err),
            }
        }
        Err(err) => Err(err),
    }
}

/// Set the current directory
pub fn set_current_dir<P: AsRef<Path>>(path: P) -> Result<()> {
    let file_result = if path.as_ref().inner.is_empty() || path.as_ref().inner.ends_with('/') {
        File::open(&path.as_ref().inner)
    } else {
        File::open(&(path.as_ref().inner.to_string() + "/"))
    };

    match file_result {
        Ok(file) => {
            match file.path() {
                Ok(path) => {
                    if let Some(path_str) = path.to_str() {
                        let path_c = path_str.to_string() + "\0";
                        match Error::demux(unsafe { sys_chdir(path_c.as_ptr()) }) {
                            Ok(_) => Ok(()),
                            Err(err) => Err(err),
                        }
                    } else {
                        Err(Error::new(ENOENT))
                    }
                }
                Err(err) => Err(err),
            }
        }
        Err(err) => Err(err),
    }
}

// TODO: Fully implement `env::var()`
pub fn var(_key: &str) -> Result<String> {
    Ok("This is code filler".to_string())
}
<|endoftext|>


<commit_before>// Copyright 2012-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.

macro_rules! assert_approx_eq {
    ($a:expr, $b:expr) => ({
        let (a, b) = (&$a, &$b);
        assert!((*a - *b).abs() < 1.0e-6,
                "{} is not approximately equal to {}", *a, *b);
    })
}

pub fn main() {
    use std::f32;
    use std::f64;

    assert_approx_eq!(64f32.sqrt(), 8f32);
    assert_approx_eq!(64f64.sqrt(), 8f64);

    assert_approx_eq!(25f32.powi(-2), 0.0016f32);
    assert_approx_eq!(23.2f64.powi(2), 538.24f64);

    assert_approx_eq!(0f32.sin(), 0f32);
    assert_approx_eq!((f64::consts::PI / 2f64).sin(), 1f64);

    assert_approx_eq!(0f32.cos(), 1f32);
    assert_approx_eq!((f64::consts::PI * 2f64).cos(), 1f64);

    assert_approx_eq!(25f32.powf(-2f32), 0.0016f32);
    assert_approx_eq!(400f64.powf(0.5f64), 20f64);

    assert_approx_eq!((1f32.exp() - f32::consts::E).abs(), 0f32);
    assert_approx_eq!(1f64.exp(), f64::consts::E);

    assert_approx_eq!(10f32.exp2(), 1024f32);
    assert_approx_eq!(50f64.exp2(), 1125899906842624f64);

    assert_approx_eq!((f32::consts::E.ln() - 1f32).abs(), 0f32);
    assert_approx_eq!(1f64.ln(), 0f64);

    assert_approx_eq!(10f32.log10(), 1f32);
    assert_approx_eq!(f64::consts::E.log10(), f64::consts::LOG10_E);

    assert_approx_eq!(8f32.log2(), 3f32);
    assert_approx_eq!(f64::consts::E.log2(), f64::consts::LOG2_E);

    assert_approx_eq!(1.0f32.mul_add(2.0f32, 5.0f32), 7.0f32);
    assert_approx_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E);

    assert_approx_eq!((-1.0f32).abs(), 1.0f32);
    assert_approx_eq!(34.2f64.abs(), 34.2f64);

    assert_approx_eq!(3.8f32.floor(), 3.0f32);
    assert_approx_eq!((-1.1f64).floor(), -2.0f64);

    assert_approx_eq!((-2.3f32).ceil(), -2.0f32);
    assert_approx_eq!(3.8f64.ceil(), 4.0f64);

    assert_approx_eq!(0.1f32.trunc(), 0.0f32);
    assert_approx_eq!((-0.1f64).trunc(), 0.0f64);
}
<commit_msg>test FMA a bit more<commit_after>// Copyright 2012-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.

macro_rules! assert_approx_eq {
    ($a:expr, $b:expr) => ({
        let (a, b) = (&$a, &$b);
        assert!((*a - *b).abs() < 1.0e-6,
                "{} is not approximately equal to {}", *a, *b);
    })
}

pub fn main() {
    use std::f32;
    use std::f64;

    assert_approx_eq!(64f32.sqrt(), 8f32);
    assert_approx_eq!(64f64.sqrt(), 8f64);

    assert_approx_eq!(25f32.powi(-2), 0.0016f32);
    assert_approx_eq!(23.2f64.powi(2), 538.24f64);

    assert_approx_eq!(0f32.sin(), 0f32);
    assert_approx_eq!((f64::consts::PI / 2f64).sin(), 1f64);

    assert_approx_eq!(0f32.cos(), 1f32);
    assert_approx_eq!((f64::consts::PI * 2f64).cos(), 1f64);

    assert_approx_eq!(25f32.powf(-2f32), 0.0016f32);
    assert_approx_eq!(400f64.powf(0.5f64), 20f64);

    assert_approx_eq!((1f32.exp() - f32::consts::E).abs(), 0f32);
    assert_approx_eq!(1f64.exp(), f64::consts::E);

    assert_approx_eq!(10f32.exp2(), 1024f32);
    assert_approx_eq!(50f64.exp2(), 1125899906842624f64);

    assert_approx_eq!((f32::consts::E.ln() - 1f32).abs(), 0f32);
    assert_approx_eq!(1f64.ln(), 0f64);

    assert_approx_eq!(10f32.log10(), 1f32);
    assert_approx_eq!(f64::consts::E.log10(), f64::consts::LOG10_E);

    assert_approx_eq!(8f32.log2(), 3f32);
    assert_approx_eq!(f64::consts::E.log2(), f64::consts::LOG2_E);

    assert_approx_eq!(3.0f32.mul_add(2.0f32, 5.0f32), 11.0);
    assert_eq!(0.0f32.mul_add(-2.0, f32::consts::E), f32::consts::E);
    assert_approx_eq!(3.0f64.mul_add(2.0, 5.0), 11.0);
    assert_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E);

    assert_approx_eq!((-1.0f32).abs(), 1.0f32);
    assert_approx_eq!(34.2f64.abs(), 34.2f64);

    assert_approx_eq!(3.8f32.floor(), 3.0f32);
    assert_approx_eq!((-1.1f64).floor(), -2.0f64);

    assert_approx_eq!((-2.3f32).ceil(), -2.0f32);
    assert_approx_eq!(3.8f64.ceil(), 4.0f64);

    assert_approx_eq!(0.1f32.trunc(), 0.0f32);
    assert_approx_eq!((-0.1f64).trunc(), 0.0f64);
}
<|endoftext|>


<commit_before>// Edge Operation Genome

use evo::prob::{Probability, ProbabilityValue};
use evo::crossover::linear_2point_crossover_random;
use evo::nsga2::Mate;
use rand::Rng;
use rand::distributions::{IndependentSample, Weighted};
use graph_edge_evolution::{EdgeOperation, GraphBuilder, NthEdgeI};
use owned_weighted_choice::OwnedWeightedChoice;
use std::str::FromStr;
use triadic_census::OptDenseDigraph;
use std::collections::BTreeMap;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Op {
    Dup,
    Split,
    Loop,
    Merge,
    Next,
    Parent,
    Reverse,
    Save,
    Restore,
}

impl FromStr for Op {
   type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "Dup" => Ok(Op::Dup),
            "Split" => Ok(Op::Split),
            "Loop" => Ok(Op::Loop),
            "Merge" => Ok(Op::Merge),
            "Next" => Ok(Op::Next),
            "Parent" => Ok(Op::Parent),
            "Reverse" => Ok(Op::Reverse),
            "Save" => Ok(Op::Save),
            "Restore" => Ok(Op::Restore),
            _ => Err(format!("Invalid opcode: {}", s)),
        }
    }
}

#[derive(Clone, Debug)]
pub struct EdgeOpsGenome {
    edge_ops: Vec<(Op, f32)>,
}

pub struct Toolbox {
    weighted_op_choice: OwnedWeightedChoice<Op>,
    prob_mutate_elem: Probability,
}

impl Mate<EdgeOpsGenome> for Toolbox {
    fn mate<R: Rng>(&mut self,
                    rng: &mut R,
                    p1: &EdgeOpsGenome,
                    p2: &EdgeOpsGenome)
                    -> EdgeOpsGenome {

        // either mutate or crossover.

        let mut child = EdgeOpsGenome {
            edge_ops: linear_2point_crossover_random(rng, &p1.edge_ops[..], &p2.edge_ops[..]),
        };
        self.mutate(rng, &mut child);
        child
    }
}

impl Toolbox {
    pub fn mutate<R: Rng>(&self, rng: &mut R, ind: &mut EdgeOpsGenome) {
        for edge_op in ind.edge_ops.iter_mut() {
            if rng.gen::<ProbabilityValue>().is_probable_with(self.prob_mutate_elem) {
                edge_op.1 = rng.gen::<f32>();
            }
        }
    }

    pub fn parse_weighted_op_choice_list(s: &str) -> Result<Vec<(Op, u32)>, String> {
        let mut v = Vec::new();
        for opstr in s.split(",") {
            if opstr.is_empty() {
                continue;
            }
            let mut i = opstr.splitn(2, ":");
            if let Some(ops) = i.next() {
                match Op::from_str(ops) {
                    Ok(op) => {
                        let ws = i.next().unwrap_or("1");
                        if let Ok(weight) = u32::from_str(ws) {
                            v.push((op, weight));
                        } else {
                            return Err(format!("Invalid weight: {}", ws));
                        }
                    }
                    Err(s) => {
                        return Err(s);
                    }
                }
            } else {
                return Err("missing op".to_string());
            }
        }
        return Ok(v);
    }

    pub fn new(prob_mutate_elem: Probability, weighted_op_choices: &[(Op, u32)]) -> Toolbox {
        let mut w = Vec::new();
        for &(op, weight) in weighted_op_choices {
            if weight > 0 {
                // an operation with weight=0 cannot be selected
                w.push(Weighted {
                    weight: weight,
                    item: op,
                });
            }
        }
        Toolbox {
            prob_mutate_elem: prob_mutate_elem,
            weighted_op_choice: OwnedWeightedChoice::new(w),
        }
    }

    fn generate_random_edge_operation<R: Rng>(&self, rng: &mut R) -> (Op, f32) /*EdgeOperation<f32, ()>*/ {
        (self.weighted_op_choice.ind_sample(rng), rng.gen::<f32>())
    }

    pub fn random_genome<R: Rng>(&self, rng: &mut R, len: usize) -> EdgeOpsGenome {
        EdgeOpsGenome {
            edge_ops: (0..len)
                          .map(|_| self.generate_random_edge_operation(rng))
                          .collect(),
        }
    }
}

impl EdgeOpsGenome {
    pub fn len(&self) -> usize {
        self.edge_ops.len()
    }

    pub fn to_graph(&self, max_degree: u32) -> OptDenseDigraph<(), ()> {
        let mut builder: GraphBuilder<f32, ()> = GraphBuilder::new();
        for &(op, f) in &self.edge_ops[..] {
            let n = (max_degree as f32 * f) as u32;
            let graph_op = match op {
                Op::Dup => {
                    EdgeOperation::Duplicate { weight: f }
                }
                Op::Split => {
                    EdgeOperation::Split { weight: f }
                }
                Op::Loop => {
                    EdgeOperation::Loop { weight: f }
                }
                Op::Merge => {
                    EdgeOperation::Merge { n: NthEdgeI(n) }
                }
                Op::Next => {
                    EdgeOperation::Next { n: NthEdgeI(n) }
                }
                Op::Parent => {
                    EdgeOperation::Parent { n: NthEdgeI(n) }
                }
                Op::Reverse => {
                    EdgeOperation::Reverse
                }
                Op::Save => {
                    EdgeOperation::Save
                }
                Op::Restore => {
                    EdgeOperation::Restore
                }
            };
            builder.apply_operation(graph_op);
        }

        let mut g: OptDenseDigraph<(), ()> = OptDenseDigraph::new(builder.total_number_of_nodes()); // XXX: rename to real_number

        // maps node_idx to index used within the graph.
        let mut node_map: BTreeMap<usize, usize> = BTreeMap::new(); // XXX: with_capacity

        builder.visit_nodes(|node_idx, _| {
            let graph_idx = g.add_node();
            node_map.insert(node_idx, graph_idx);
        });

        builder.visit_edges(|(a, b), _| {
            g.add_edge(node_map[&a], node_map[&b]);
        });

        return g;
    }
}

#[test]
fn test_parse_weighted_op_choice_list() {
    assert_eq!(Ok(vec![]), Toolbox::parse_weighted_op_choice_list(""));
    assert_eq!(Ok(vec![(Op::Dup, 1)]),
               Toolbox::parse_weighted_op_choice_list("Dup"));
    assert_eq!(Ok(vec![(Op::Dup, 1)]),
               Toolbox::parse_weighted_op_choice_list("Dup:1"));
    assert_eq!(Ok(vec![(Op::Dup, 2)]),
               Toolbox::parse_weighted_op_choice_list("Dup:2"));
    assert_eq!(Ok(vec![(Op::Dup, 2), (Op::Split, 1)]),
               Toolbox::parse_weighted_op_choice_list("Dup:2,Split"));
    assert_eq!(Err("Invalid weight: ".to_string()),
               Toolbox::parse_weighted_op_choice_list("Dup:2,Split:"));
    assert_eq!(Err("Invalid weight: a".to_string()),
               Toolbox::parse_weighted_op_choice_list("Dup:2,Split:a"));
    assert_eq!(Err("Invalid opcode: dup".to_string()),
               Toolbox::parse_weighted_op_choice_list("dup:2,Split:a"));
}
<commit_msg>Use NthEdgeF<commit_after>// Edge Operation Genome

use evo::prob::{Probability, ProbabilityValue};
use evo::crossover::linear_2point_crossover_random;
use evo::nsga2::Mate;
use rand::Rng;
use rand::distributions::{IndependentSample, Weighted};
use graph_edge_evolution::{EdgeOperation, GraphBuilder, NthEdgeF};
use owned_weighted_choice::OwnedWeightedChoice;
use std::str::FromStr;
use triadic_census::OptDenseDigraph;
use std::collections::BTreeMap;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Op {
    Dup,
    Split,
    Loop,
    Merge,
    Next,
    Parent,
    Reverse,
    Save,
    Restore,
}

impl FromStr for Op {
   type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "Dup" => Ok(Op::Dup),
            "Split" => Ok(Op::Split),
            "Loop" => Ok(Op::Loop),
            "Merge" => Ok(Op::Merge),
            "Next" => Ok(Op::Next),
            "Parent" => Ok(Op::Parent),
            "Reverse" => Ok(Op::Reverse),
            "Save" => Ok(Op::Save),
            "Restore" => Ok(Op::Restore),
            _ => Err(format!("Invalid opcode: {}", s)),
        }
    }
}

#[derive(Clone, Debug)]
pub struct EdgeOpsGenome {
    edge_ops: Vec<(Op, f32)>,
}

pub struct Toolbox {
    weighted_op_choice: OwnedWeightedChoice<Op>,
    prob_mutate_elem: Probability,
}

impl Mate<EdgeOpsGenome> for Toolbox {
    fn mate<R: Rng>(&mut self,
                    rng: &mut R,
                    p1: &EdgeOpsGenome,
                    p2: &EdgeOpsGenome)
                    -> EdgeOpsGenome {

        // either mutate or crossover.

        let mut child = EdgeOpsGenome {
            edge_ops: linear_2point_crossover_random(rng, &p1.edge_ops[..], &p2.edge_ops[..]),
        };
        self.mutate(rng, &mut child);
        child
    }
}

impl Toolbox {
    pub fn mutate<R: Rng>(&self, rng: &mut R, ind: &mut EdgeOpsGenome) {
        for edge_op in ind.edge_ops.iter_mut() {
            if rng.gen::<ProbabilityValue>().is_probable_with(self.prob_mutate_elem) {
                edge_op.1 = rng.gen::<f32>();
            }
        }
    }

    pub fn parse_weighted_op_choice_list(s: &str) -> Result<Vec<(Op, u32)>, String> {
        let mut v = Vec::new();
        for opstr in s.split(",") {
            if opstr.is_empty() {
                continue;
            }
            let mut i = opstr.splitn(2, ":");
            if let Some(ops) = i.next() {
                match Op::from_str(ops) {
                    Ok(op) => {
                        let ws = i.next().unwrap_or("1");
                        if let Ok(weight) = u32::from_str(ws) {
                            v.push((op, weight));
                        } else {
                            return Err(format!("Invalid weight: {}", ws));
                        }
                    }
                    Err(s) => {
                        return Err(s);
                    }
                }
            } else {
                return Err("missing op".to_string());
            }
        }
        return Ok(v);
    }

    pub fn new(prob_mutate_elem: Probability, weighted_op_choices: &[(Op, u32)]) -> Toolbox {
        let mut w = Vec::new();
        for &(op, weight) in weighted_op_choices {
            if weight > 0 {
                // an operation with weight=0 cannot be selected
                w.push(Weighted {
                    weight: weight,
                    item: op,
                });
            }
        }
        Toolbox {
            prob_mutate_elem: prob_mutate_elem,
            weighted_op_choice: OwnedWeightedChoice::new(w),
        }
    }

    fn generate_random_edge_operation<R: Rng>(&self, rng: &mut R) -> (Op, f32) /*EdgeOperation<f32, ()>*/ {
        (self.weighted_op_choice.ind_sample(rng), rng.gen::<f32>())
    }

    pub fn random_genome<R: Rng>(&self, rng: &mut R, len: usize) -> EdgeOpsGenome {
        EdgeOpsGenome {
            edge_ops: (0..len)
                          .map(|_| self.generate_random_edge_operation(rng))
                          .collect(),
        }
    }
}

impl EdgeOpsGenome {
    pub fn len(&self) -> usize {
        self.edge_ops.len()
    }

    pub fn to_graph(&self, max_degree: u32) -> OptDenseDigraph<(), ()> {
        let mut builder: GraphBuilder<f32, ()> = GraphBuilder::new();
        for &(op, f) in &self.edge_ops[..] {
            //let n = (max_degree as f32 * f) as u32;
            let graph_op = match op {
                Op::Dup => {
                    EdgeOperation::Duplicate { weight: f }
                }
                Op::Split => {
                    EdgeOperation::Split { weight: f }
                }
                Op::Loop => {
                    EdgeOperation::Loop { weight: f }
                }
                Op::Merge => {
                    EdgeOperation::Merge { n: NthEdgeF(f) }
                }
                Op::Next => {
                    EdgeOperation::Next { n: NthEdgeF(f) }
                }
                Op::Parent => {
                    EdgeOperation::Parent { n: NthEdgeF(f) }
                }
                Op::Reverse => {
                    EdgeOperation::Reverse
                }
                Op::Save => {
                    EdgeOperation::Save
                }
                Op::Restore => {
                    EdgeOperation::Restore
                }
            };
            builder.apply_operation(graph_op);
        }

        let mut g: OptDenseDigraph<(), ()> = OptDenseDigraph::new(builder.total_number_of_nodes()); // XXX: rename to real_number

        // maps node_idx to index used within the graph.
        let mut node_map: BTreeMap<usize, usize> = BTreeMap::new(); // XXX: with_capacity

        builder.visit_nodes(|node_idx, _| {
            let graph_idx = g.add_node();
            node_map.insert(node_idx, graph_idx);
        });

        builder.visit_edges(|(a, b), _| {
            g.add_edge(node_map[&a], node_map[&b]);
        });

        return g;
    }
}

#[test]
fn test_parse_weighted_op_choice_list() {
    assert_eq!(Ok(vec![]), Toolbox::parse_weighted_op_choice_list(""));
    assert_eq!(Ok(vec![(Op::Dup, 1)]),
               Toolbox::parse_weighted_op_choice_list("Dup"));
    assert_eq!(Ok(vec![(Op::Dup, 1)]),
               Toolbox::parse_weighted_op_choice_list("Dup:1"));
    assert_eq!(Ok(vec![(Op::Dup, 2)]),
               Toolbox::parse_weighted_op_choice_list("Dup:2"));
    assert_eq!(Ok(vec![(Op::Dup, 2), (Op::Split, 1)]),
               Toolbox::parse_weighted_op_choice_list("Dup:2,Split"));
    assert_eq!(Err("Invalid weight: ".to_string()),
               Toolbox::parse_weighted_op_choice_list("Dup:2,Split:"));
    assert_eq!(Err("Invalid weight: a".to_string()),
               Toolbox::parse_weighted_op_choice_list("Dup:2,Split:a"));
    assert_eq!(Err("Invalid opcode: dup".to_string()),
               Toolbox::parse_weighted_op_choice_list("dup:2,Split:a"));
}
<|endoftext|>


<commit_before>use std::thread;
use std::sync::mpsc::{Receiver, Sender};
use cancellation::CancellationTokenSource;

use caches::file_cache::*;
use resources::*;
use resources::common::*;
use resources::index_resource::*;
use resources::show_resource::*;
use resources::image_resource::*;
use resources::web_resource::*;

use std::sync::{Arc};
use std::sync::atomic::{AtomicBool, Ordering};

pub struct Requester {}

impl Requester {
    pub fn new(rx_req: Receiver<ChannelItem>, tx_res: Sender<ChannelItem>, working: Arc<AtomicBool>) -> Self {

        // web client
        thread::spawn(move || {
            let mut wr = WebResource::new();
            let mut fc = Box::new(FileCache::new());
            let ct = CancellationTokenSource::new();
            ct.cancel_after(::std::time::Duration::new(10, 0));
            while (*working).load(Ordering::Relaxed) {
                match rx_req.recv() {
                    Ok(item) => {

                        let th = thread::current();
                        ct.run(|| { th.unpark(); }, || match item.extra.clone() {
                            Some(o) => {
                                info!("request: {:?}", o);
                                match o {
                                    ChannelItemType::Index(_) => {
                                        let mut index_resource = IndexResource::new(&mut wr, &mut fc);
                                        tx_res.send(index_resource.fetch(&item)).expect("[web client] fail to send index request");
                                    }
                                    ChannelItemType::Show(_) => {
                                        let mut show_resource = ShowResource::new(&mut wr, &mut fc);
                                        tx_res.send(show_resource.fetch(&item)).expect("[web client] fail to send show request");
                                    }
                                    ChannelItemType::Image(_) => {
                                        let mut image_resource = ImageResource::new(&mut fc);
                                        tx_res.send(image_resource.fetch(&item)).expect("[web client] fail to send image request");
                                    }
                                }
                            }
                            None => { }
                        });

                        if ct.is_canceled() {
                            thread::park_timeout(::std::time::Duration::new(0, 250));
                            // Err(OperationCanceled)
                        } else {
                            // Ok(())
                        }
                    }
                    Err(_) => {}
                }
            }
        });

        Requester { }
    }
}
<commit_msg>[FIX] prevent blocking in requester<commit_after>use std::thread;
use std::sync::mpsc::{Receiver, Sender};
use cancellation::CancellationTokenSource;

use caches::file_cache::*;
use resources::*;
use resources::common::*;
use resources::index_resource::*;
use resources::show_resource::*;
use resources::image_resource::*;
use resources::web_resource::*;

use std::sync::{Arc};
use std::sync::atomic::{AtomicBool, Ordering};

pub struct Requester {}

impl Requester {
    pub fn new(rx_req: Receiver<ChannelItem>, tx_res: Sender<ChannelItem>, working: Arc<AtomicBool>) -> Self {

        // web client
        thread::spawn(move || {

            while (*working).load(Ordering::Relaxed) {
                match rx_req.recv() {
                    Ok(item) => {
                        let mut wr = WebResource::new();
                        let mut fc = Box::new(FileCache::new());
                        let ct = CancellationTokenSource::new();
                        ct.cancel_after(::std::time::Duration::new(10, 0));
                        let tx_res2 = tx_res.clone();
                        thread::spawn(move || {
                            info!("[requester] #recv");
                            let th = thread::current();
                            ct.run(|| { th.unpark(); }, || match item.extra.clone() {
                                Some(o) => {
                                    info!("request: {:?}", o);
                                    match o {
                                        ChannelItemType::Index(_) => {
                                            let mut index_resource = IndexResource::new(&mut wr, &mut fc);
                                            tx_res2.send(index_resource.fetch(&item)).expect("[web client] fail to send index request");
                                        }
                                        ChannelItemType::Show(_) => {
                                            let mut show_resource = ShowResource::new(&mut wr, &mut fc);
                                            tx_res2.send(show_resource.fetch(&item)).expect("[web client] fail to send show request");
                                        }
                                        ChannelItemType::Image(_) => {
                                            let mut image_resource = ImageResource::new(&mut fc);
                                            tx_res2.send(image_resource.fetch(&item)).expect("[web client] fail to send image request");
                                        }
                                    }
                                }
                                None => { tx_res2.send(Default::default()); }
                            });

                            if ct.is_canceled() {
                                tx_res2.send(Default::default());
                            }
                        });
                    }
                    Err(_) => {}
                }
            }
        });

        Requester { }
    }
}
<|endoftext|>