<commit_before>use {Epoch, Index, StorageId};

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct PointerData(u64);

const INDEX_BITS: u8 = 40;
const EPOCH_BITS: u8 = 16;
const STORAGE_ID_BITS: u8 = 8;
const INDEX_MASK: u64 = (1 << INDEX_BITS) - 1;
const EPOCH_OFFSET: u8 = INDEX_BITS;
const EPOCH_MASK: u64 = ((1 << EPOCH_BITS) - 1) << EPOCH_OFFSET;
const STORAGE_ID_OFFSET: u8 = EPOCH_OFFSET + EPOCH_BITS;
const STORAGE_ID_MASK: u64 = ((1 << STORAGE_ID_BITS) - 1) << STORAGE_ID_OFFSET;

impl PointerData {
    #[inline]
    pub fn new(index: Index, epoch: Epoch, storage: StorageId) -> Self {
        debug_assert_eq!(index >> INDEX_BITS, 0);
        PointerData(index as u64 + ((epoch as u64) << EPOCH_OFFSET) +
            ((storage as u64) << STORAGE_ID_OFFSET))
    }

    #[inline]
    pub fn get_index(&self) -> Index {
        (self.0 & INDEX_MASK) as Index
    }

    #[inline]
    pub fn get_epoch(&self) -> Epoch {
        ((self.0 & EPOCH_MASK) >> EPOCH_OFFSET) as Epoch
    }

    #[inline]
    pub fn get_storage_id(&self) -> StorageId {
        ((self.0 & STORAGE_ID_MASK) >> STORAGE_ID_OFFSET) as StorageId
    }

    #[inline]
    pub fn with_epoch(&self, epoch: Epoch) -> PointerData {
        PointerData((self.0 & !EPOCH_MASK) + ((epoch as u64) << EPOCH_OFFSET))
    }
}

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

    #[test]
    fn sizes() {
        assert_eq!(INDEX_BITS + EPOCH_BITS + STORAGE_ID_BITS, 64);
        assert!(size_of::<Index>() * 8 >= INDEX_BITS as usize);
        assert!(size_of::<Epoch>() * 8 >= EPOCH_BITS as usize);
        assert!(size_of::<StorageId>() * 8 >= STORAGE_ID_BITS as usize);
    }

    #[test]
    fn new() {
        let pd = PointerData::new(1, 2, 3);
        assert_eq!(pd.get_index(), 1);
        assert_eq!(pd.get_epoch(), 2);
        assert_eq!(pd.get_storage_id(), 3);
        assert_eq!(pd.with_epoch(5).get_epoch(), 5);
    }
}
<commit_msg>Fix index offset for 32-bit architecture<commit_after>use {Epoch, Index, StorageId};

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct PointerData(u64);

#[cfg(target_pointer_width = "32")]
const INDEX_BITS: u8 = 20;
#[cfg(target_pointer_width = "32")]
const EPOCH_BITS: u8 = 8;
#[cfg(target_pointer_width = "32")]
const STORAGE_ID_BITS: u8 = 4;

#[cfg(target_pointer_width = "64")]
const INDEX_BITS: u8 = 40;
#[cfg(target_pointer_width = "64")]
const EPOCH_BITS: u8 = 16;
#[cfg(target_pointer_width = "64")]
const STORAGE_ID_BITS: u8 = 8;

const INDEX_MASK: u64 = (1 << INDEX_BITS) - 1;
const EPOCH_OFFSET: u8 = INDEX_BITS;
const EPOCH_MASK: u64 = ((1 << EPOCH_BITS) - 1) << EPOCH_OFFSET;
const STORAGE_ID_OFFSET: u8 = EPOCH_OFFSET + EPOCH_BITS;
const STORAGE_ID_MASK: u64 = ((1 << STORAGE_ID_BITS) - 1) << STORAGE_ID_OFFSET;

impl PointerData {
    #[inline]
    pub fn new(index: Index, epoch: Epoch, storage: StorageId) -> Self {
        debug_assert_eq!(index >> INDEX_BITS, 0);
        PointerData(index as u64 + ((epoch as u64) << EPOCH_OFFSET) +
            ((storage as u64) << STORAGE_ID_OFFSET))
    }

    #[inline]
    pub fn get_index(&self) -> Index {
        (self.0 & INDEX_MASK) as Index
    }

    #[inline]
    pub fn get_epoch(&self) -> Epoch {
        ((self.0 & EPOCH_MASK) >> EPOCH_OFFSET) as Epoch
    }

    #[inline]
    pub fn get_storage_id(&self) -> StorageId {
        ((self.0 & STORAGE_ID_MASK) >> STORAGE_ID_OFFSET) as StorageId
    }

    #[inline]
    pub fn with_epoch(&self, epoch: Epoch) -> PointerData {
        PointerData((self.0 & !EPOCH_MASK) + ((epoch as u64) << EPOCH_OFFSET))
    }
}

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

    #[test]
    fn sizes() {
        #[cfg(target_pointer_width = "32")]
        assert_eq!(INDEX_BITS + EPOCH_BITS + STORAGE_ID_BITS, 32);
        #[cfg(target_pointer_width = "64")]
        assert_eq!(INDEX_BITS + EPOCH_BITS + STORAGE_ID_BITS, 64);
        assert!(size_of::<Index>() * 8 >= INDEX_BITS as usize);
        assert!(size_of::<Epoch>() * 8 >= EPOCH_BITS as usize);
        assert!(size_of::<StorageId>() * 8 >= STORAGE_ID_BITS as usize);
    }

    #[test]
    fn new() {
        let pd = PointerData::new(1, 2, 3);
        assert_eq!(pd.get_index(), 1);
        assert_eq!(pd.get_epoch(), 2);
        assert_eq!(pd.get_storage_id(), 3);
        assert_eq!(pd.with_epoch(5).get_epoch(), 5);
    }
}
<|endoftext|>


<commit_before>//! [Church booleans](https://en.wikipedia.org/wiki/Church_encoding#Church_Booleans)

use term::*;
use term::Term::*;

/// A Church-encoded boolean `true`.
///
/// TRUE := λab.a = λ λ 2
pub fn tru() -> Term { abs(abs(Var(2))) }

/// A Church-encoded boolean `false`.
///
/// FALSE := λab.b = λ λ 1
pub fn fls() -> Term { abs(abs(Var(1))) }

/// Applied to two Church-encoded booleans it returns their Church-encoded conjunction.
///
/// AND := λpq.p q p = λ λ 2 1 2
///
/// # Examples
/// ```
/// use lambda_calculus::booleans::{and, tru, fls};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(and().app(tru()).app(tru())), tru());
/// assert_eq!(beta_full(and().app(tru()).app(fls())), fls());
/// assert_eq!(beta_full(and().app(fls()).app(tru())), fls());
/// assert_eq!(beta_full(and().app(fls()).app(fls())), fls());
/// ```
pub fn and() -> Term {
    abs(abs(
        app!(Var(2), Var(1), Var(2))
    ))
}

/// Applied to two Church-encoded booleans it returns their Church-encoded disjunction.
///
/// OR := λpq.p p q = λ λ 2 2 1
///
/// # Examples
/// ```
/// use lambda_calculus::booleans::{or, tru, fls};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(or().app(tru()).app(tru())), tru());
/// assert_eq!(beta_full(or().app(tru()).app(fls())), tru());
/// assert_eq!(beta_full(or().app(fls()).app(tru())), tru());
/// assert_eq!(beta_full(or().app(fls()).app(fls())), fls());
/// ```
pub fn or() -> Term {
    abs(abs(
        app!(Var(2), Var(2), Var(1))
    ))
}

/// Applied to a Church-encoded boolean it returns its Church-encoded negation.
///
/// NOT := λp.p FALSE TRUE = λ 1 FALSE TRUE
///
/// # Examples
/// ```
/// use lambda_calculus::booleans::{not, tru, fls};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(not().app(tru())), fls());
/// assert_eq!(beta_full(not().app(fls())), tru());
/// ```
pub fn not() -> Term {
    abs(
        app!(Var(1), fls(), tru())
    )
}

/// Applied to a Church-encoded boolean it returns its Church-encoded exclusive disjunction.
///
/// XOR := λab.a (NOT b) b = λ λ 2 (NOT 1) 1
///
/// # Examples
/// ```
/// use lambda_calculus::booleans::{xor, tru, fls};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(xor().app(tru()).app(tru())), fls());
/// assert_eq!(beta_full(xor().app(tru()).app(fls())), tru());
/// assert_eq!(beta_full(xor().app(fls()).app(tru())), tru());
/// assert_eq!(beta_full(xor().app(fls()).app(fls())), fls());
/// ```
pub fn xor() -> Term {
    abs(abs(
        app!(Var(2), app!(not(), Var(1)), Var(1))
    ))
}

/// Applied to a Church encoded predicate and two terms it returns the first one if the predicate
/// is true or the second one if the predicate is false.
///
/// IF_ELSE := λpab.p a b = λ λ λ 3 2 1
///
/// # Examples
/// ```
/// use lambda_calculus::booleans::{if_else, tru, fls};
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(if_else().app(tru()).app(one()).app(zero())), one());
/// assert_eq!(beta_full(if_else().app(fls()).app(one()).app(zero())), zero());
/// ```
pub fn if_else() -> Term {
    abs(abs(abs(
        app!(Var(3), Var(2), Var(1))
    )))
}

impl From<bool> for Term {
    fn from(b: bool) -> Self {
        if b { tru() } else { fls() }
    }
}
<commit_msg>rewrite bool docs with app!()<commit_after>//! [Church booleans](https://en.wikipedia.org/wiki/Church_encoding#Church_Booleans)

use term::*;
use term::Term::*;

/// A Church-encoded boolean `true`.
///
/// TRUE := λab.a = λ λ 2
pub fn tru() -> Term { abs(abs(Var(2))) }

/// A Church-encoded boolean `false`.
///
/// FALSE := λab.b = λ λ 1
pub fn fls() -> Term { abs(abs(Var(1))) }

/// Applied to two Church-encoded booleans it returns their Church-encoded conjunction.
///
/// AND := λpq.p q p = λ λ 2 1 2
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{and, tru, fls};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(app!(and(), tru(), tru())), tru());
/// assert_eq!(beta_full(app!(and(), tru(), fls())), fls());
/// assert_eq!(beta_full(app!(and(), fls(), tru())), fls());
/// assert_eq!(beta_full(app!(and(), fls(), fls())), fls());
/// # }
/// ```
pub fn and() -> Term {
    abs(abs(
        app!(Var(2), Var(1), Var(2))
    ))
}

/// Applied to two Church-encoded booleans it returns their Church-encoded disjunction.
///
/// OR := λpq.p p q = λ λ 2 2 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{or, tru, fls};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(app!(or(), tru(), tru())), tru());
/// assert_eq!(beta_full(app!(or(), tru(), fls())), tru());
/// assert_eq!(beta_full(app!(or(), fls(), tru())), tru());
/// assert_eq!(beta_full(app!(or(), fls(), fls())), fls());
/// # }
/// ```
pub fn or() -> Term {
    abs(abs(
        app!(Var(2), Var(2), Var(1))
    ))
}

/// Applied to a Church-encoded boolean it returns its Church-encoded negation.
///
/// NOT := λp.p FALSE TRUE = λ 1 FALSE TRUE
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{not, tru, fls};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(app!(not(), tru())), fls());
/// assert_eq!(beta_full(app!(not(), fls())), tru());
/// # }
/// ```
pub fn not() -> Term {
    abs(
        app!(Var(1), fls(), tru())
    )
}

/// Applied to a Church-encoded boolean it returns its Church-encoded exclusive disjunction.
///
/// XOR := λab.a (NOT b) b = λ λ 2 (NOT 1) 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{xor, tru, fls};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(app!(xor(), tru(), tru())), fls());
/// assert_eq!(beta_full(app!(xor(), tru(), fls())), tru());
/// assert_eq!(beta_full(app!(xor(), fls(), tru())), tru());
/// assert_eq!(beta_full(app!(xor(), fls(), fls())), fls());
/// # }
/// ```
pub fn xor() -> Term {
    abs(abs(
        app!(Var(2), app!(not(), Var(1)), Var(1))
    ))
}

/// Applied to a Church encoded predicate and two terms it returns the first one if the predicate
/// is true or the second one if the predicate is false.
///
/// IF_ELSE := λpab.p a b = λ λ λ 3 2 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{if_else, tru, fls};
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta_full;
///
/// assert_eq!(beta_full(app!(if_else(), tru(), one(), zero())), one());
/// assert_eq!(beta_full(app!(if_else(), fls(), one(), zero())), zero());
/// # }
/// ```
pub fn if_else() -> Term {
    abs(abs(abs(
        app!(Var(3), Var(2), Var(1))
    )))
}

impl From<bool> for Term {
    fn from(b: bool) -> Self {
        if b { tru() } else { fls() }
    }
}
<|endoftext|>


<commit_before>#[doc = "Random number generation"];

export rng, seed, seeded_rng, weighted, extensions;

enum rctx {}

#[abi = "cdecl"]
native mod rustrt {
    fn rand_seed() -> [u8];
    fn rand_new() -> *rctx;
    fn rand_new_seeded(seed: [u8]) -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

#[doc = "A random number generator"]
iface rng {
    #[doc = "Return the next random integer"]
    fn next() -> u32;
}

#[doc = "A value with a particular weight compared to other values"]
type weighted<T> = { weight: uint, item: T };

#[doc = "Extension methods for random number generators"]
impl extensions for rng {

    #[doc = "Return a random int"]
    fn gen_int() -> int {
        self.gen_i64() as int
    }

    #[doc = "Return an int randomly chosen from the range [start, end], \
             failing if start > end"]
    fn gen_int_from(start: int, end: int) -> int {
        assert start <= end;
        start + int::abs(self.gen_int() % (end - start + 1))
    }

    #[doc = "Return a random i8"]
    fn gen_i8() -> i8 {
        self.next() as i8
    }

    #[doc = "Return a random i16"]
    fn gen_i16() -> i16 {
        self.next() as i16
    }

    #[doc = "Return a random i32"]
    fn gen_i32() -> i32 {
        self.next() as i32
    }

    #[doc = "Return a random i64"]
    fn gen_i64() -> i64 {
        (self.next() as i64 << 32) | self.next() as i64
    }

    #[doc = "Return a random uint"]
    fn gen_uint() -> uint {
        self.gen_u64() as uint
    }

    #[doc = "Return a uint randomly chosen from the range [start, end], \
             failing if start > end"]
    fn gen_uint_from(start: uint, end: uint) -> uint {
        assert start <= end;
        start + (self.gen_uint() % (end - start + 1u))
    }

    #[doc = "Return a random u8"]
    fn gen_u8() -> u8 {
        self.next() as u8
    }

    #[doc = "Return a random u16"]
    fn gen_u16() -> u16 {
        self.next() as u16
    }

    #[doc = "Return a random u32"]
    fn gen_u32() -> u32 {
        self.next()
    }

    #[doc = "Return a random u64"]
    fn gen_u64() -> u64 {
        (self.next() as u64 << 32) | self.next() as u64
    }

    #[doc = "Return a random float"]
    fn gen_float() -> float {
        self.gen_f64() as float
    }

    #[doc = "Return a random f32"]
    fn gen_f32() -> f32 {
        self.gen_f64() as f32
    }

    #[doc = "Return a random f64"]
    fn gen_f64() -> f64 {
        let u1 = self.next() as f64;
        let u2 = self.next() as f64;
        let u3 = self.next() as f64;
        let scale = u32::max_value as f64;
        ret ((u1 / scale + u2) / scale + u3) / scale;
    }

    #[doc = "Return a random char"]
    fn gen_char() -> char {
        self.next() as char
    }

    #[doc = "Return a char randomly chosen from chars, failing if chars is \
             empty"]
    fn gen_char_from(chars: str) -> char {
        assert !chars.is_empty();
        self.choose(str::chars(chars))
    }

    #[doc = "Return a random bool"]
    fn gen_bool() -> bool {
        self.next() & 1u32 == 1u32
    }

    #[doc = "Return a bool with a 1 in n chance of true"]
    fn gen_weighted_bool(n: uint) -> bool {
        if n == 0u {
            true
        } else {
            self.gen_uint_from(1u, n) == 1u
        }
    }

    #[doc = "Return a random string of the specified length composed of A-Z, \
             a-z, 0-9"]
    fn gen_str(len: uint) -> str {
        let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                      "abcdefghijklmnopqrstuvwxyz" +
                      "0123456789";
        let mut s = "";
        let mut i = 0u;
        while (i < len) {
            s = s + str::from_char(self.gen_char_from(charset));
            i += 1u;
        }
        s
    }

    #[doc = "Return a random byte string of the specified length"]
    fn gen_bytes(len: uint) -> [u8] {
        vec::from_fn(len) {|_i|
            self.gen_u8()
        }
    }

    #[doc = "Choose an item randomly, failing if values is empty"]
    fn choose<T:copy>(values: [T]) -> T {
        self.choose_option(values).get()
    }

    #[doc = "Choose some(item) randomly, returning none if values is empty"]
    fn choose_option<T:copy>(values: [T]) -> option<T> {
        if values.is_empty() {
            none
        } else {
            some(values[self.gen_uint_from(0u, values.len() - 1u)])
        }
    }

    #[doc = "Choose an item respecting the relative weights, failing if \
             the sum of the weights is 0"]
    fn choose_weighted<T: copy>(v : [weighted<T>]) -> T {
        self.choose_weighted_option(v).get()
    }

    #[doc = "Choose some(item) respecting the relative weights, returning \
             none if the sum of the weights is 0"]
    fn choose_weighted_option<T:copy>(v: [weighted<T>]) -> option<T> {
        let mut total = 0u;
        for v.each {|item|
            total += item.weight;
        }
        if total == 0u {
            ret none;
        }
        let chosen = self.gen_uint_from(0u, total - 1u);
        let mut so_far = 0u;
        for v.each {|item|
            so_far += item.weight;
            if so_far > chosen {
                ret some(item.item);
            }
        }
        unreachable();
    }

    #[doc = "Return a vec containing copies of the items, in order, where \
             the weight of the item determines how many copies there are"]
    fn weighted_vec<T:copy>(v: [weighted<T>]) -> [T] {
        let mut r = [];
        for v.each {|item|
            uint::range(0u, item.weight) {|_i|
                r += [item.item];
            }
        }
        r
    }

    #[doc = "Shuffle a vec"]
    fn shuffle<T:copy>(values: [T]) -> [T] {
        let mut m = vec::to_mut(values);
        self.shuffle_mut(m);
        ret vec::from_mut(m);
    }

    #[doc = "Shuffle a mutable vec in place"]
    fn shuffle_mut<T>(&values: [mut T]) {
        let mut i = values.len();
        while i >= 2u {
            // invariant: elements with index >= i have been locked in place.
            i -= 1u;
            // lock element i in place.
            vec::swap(values, i, self.gen_uint_from(0u, i));
        }
    }

}

resource rand_res(c: *rctx) { rustrt::rand_free(c); }

impl of rng for @rand_res {
    fn next() -> u32 { ret rustrt::rand_next(**self); }
}

#[doc = "Create a new random seed for seeded_rng"]
fn seed() -> [u8] {
    rustrt::rand_seed()
}

#[doc = "Create a random number generator with a system specified seed"]
fn rng() -> rng {
    @rand_res(rustrt::rand_new()) as rng
}

#[doc = "Create a random number generator using the specified seed. A \
         generator constructed with a given seed will generate the same \
         sequence of values as all other generators constructed with the \
         same seed. The seed may be any length."]
fn seeded_rng(seed: [u8]) -> rng {
    @rand_res(rustrt::rand_new_seeded(seed)) as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn rng_seeded() {
        let seed = rand::seed();
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed() {
        // much shorter than generated seeds which are 1024 bytes
        let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn gen_int_from() {
        let r = rand::rng();
        let a = r.gen_int_from(-3, 42);
        assert a >= -3 && a <= 42;
        assert r.gen_int_from(0, 0) == 0;
        assert r.gen_int_from(-12, -12) == -12;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win3"))]
    fn gen_int_from_fail() {
        rand::rng().gen_int_from(5, -2);
    }

    #[test]
    fn gen_uint_from() {
        let r = rand::rng();
        let a = r.gen_uint_from(3u, 42u);
        assert a >= 3u && a <= 42u;
        assert r.gen_uint_from(0u, 0u) == 0u;
        assert r.gen_uint_from(12u, 12u) == 12u;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win3"))]
    fn gen_uint_from_fail() {
        rand::rng().gen_uint_from(5u, 2u);
    }

    #[test]
    fn gen_float() {
        let r = rand::rng();
        let a = r.gen_float();
        let b = r.gen_float();
        log(debug, (a, b));
    }

    #[test]
    fn gen_weighted_bool() {
        let r = rand::rng();
        assert r.gen_weighted_bool(0u) == true;
        assert r.gen_weighted_bool(1u) == true;
    }

    #[test]
    fn gen_str() {
        let r = rand::rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert r.gen_str(0u).len() == 0u;
        assert r.gen_str(10u).len() == 10u;
        assert r.gen_str(16u).len() == 16u;
    }

    #[test]
    fn gen_bytes() {
        let r = rand::rng();
        assert r.gen_bytes(0u).len() == 0u;
        assert r.gen_bytes(10u).len() == 10u;
        assert r.gen_bytes(16u).len() == 16u;
    }

    #[test]
    fn choose() {
        let r = rand::rng();
        assert r.choose([1, 1, 1]) == 1;
    }

    #[test]
    fn choose_option() {
        let r = rand::rng();
        assert r.choose_option([]) == none::<int>;
        assert r.choose_option([1, 1, 1]) == some(1);
    }

    #[test]
    fn choose_weighted() {
        let r = rand::rng();
        assert r.choose_weighted([{weight: 1u, item: 42}]) == 42;
        assert r.choose_weighted([
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == 43;
    }

    #[test]
    fn choose_weighted_option() {
        let r = rand::rng();
        assert r.choose_weighted_option([{weight: 1u, item: 42}]) == some(42);
        assert r.choose_weighted_option([
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == some(43);
        assert r.choose_weighted_option([]) == none::<int>;
    }

    #[test]
    fn weighted_vec() {
        let r = rand::rng();
        let empty: [int] = [];
        assert r.weighted_vec([]) == empty;
        assert r.weighted_vec([
            {weight: 0u, item: 3u},
            {weight: 1u, item: 2u},
            {weight: 2u, item: 1u}
        ]) == [2u, 1u, 1u];
    }

    #[test]
    fn shuffle() {
        let r = rand::rng();
        let empty: [int] = [];
        assert r.shuffle([]) == empty;
        assert r.shuffle([1, 1, 1]) == [1, 1, 1];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>core: Rework some rand functions to be more consistent<commit_after>#[doc = "Random number generation"];

export rng, seed, seeded_rng, weighted, extensions;

enum rctx {}

#[abi = "cdecl"]
native mod rustrt {
    fn rand_seed() -> [u8];
    fn rand_new() -> *rctx;
    fn rand_new_seeded(seed: [u8]) -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

#[doc = "A random number generator"]
iface rng {
    #[doc = "Return the next random integer"]
    fn next() -> u32;
}

#[doc = "A value with a particular weight compared to other values"]
type weighted<T> = { weight: uint, item: T };

#[doc = "Extension methods for random number generators"]
impl extensions for rng {

    #[doc = "Return a random int"]
    fn gen_int() -> int {
        self.gen_i64() as int
    }

    #[doc = "Return an int randomly chosen from the range [start, end), \
             failing if start >= end"]
    fn gen_int_range(start: int, end: int) -> int {
        assert start < end;
        start + int::abs(self.gen_int() % (end - start))
    }

    #[doc = "Return a random i8"]
    fn gen_i8() -> i8 {
        self.next() as i8
    }

    #[doc = "Return a random i16"]
    fn gen_i16() -> i16 {
        self.next() as i16
    }

    #[doc = "Return a random i32"]
    fn gen_i32() -> i32 {
        self.next() as i32
    }

    #[doc = "Return a random i64"]
    fn gen_i64() -> i64 {
        (self.next() as i64 << 32) | self.next() as i64
    }

    #[doc = "Return a random uint"]
    fn gen_uint() -> uint {
        self.gen_u64() as uint
    }

    #[doc = "Return a uint randomly chosen from the range [start, end), \
             failing if start >= end"]
    fn gen_uint_range(start: uint, end: uint) -> uint {
        assert start < end;
        start + (self.gen_uint() % (end - start))
    }

    #[doc = "Return a random u8"]
    fn gen_u8() -> u8 {
        self.next() as u8
    }

    #[doc = "Return a random u16"]
    fn gen_u16() -> u16 {
        self.next() as u16
    }

    #[doc = "Return a random u32"]
    fn gen_u32() -> u32 {
        self.next()
    }

    #[doc = "Return a random u64"]
    fn gen_u64() -> u64 {
        (self.next() as u64 << 32) | self.next() as u64
    }

    #[doc = "Return a random float"]
    fn gen_float() -> float {
        self.gen_f64() as float
    }

    #[doc = "Return a random f32"]
    fn gen_f32() -> f32 {
        self.gen_f64() as f32
    }

    #[doc = "Return a random f64"]
    fn gen_f64() -> f64 {
        let u1 = self.next() as f64;
        let u2 = self.next() as f64;
        let u3 = self.next() as f64;
        let scale = u32::max_value as f64;
        ret ((u1 / scale + u2) / scale + u3) / scale;
    }

    #[doc = "Return a random char"]
    fn gen_char() -> char {
        self.next() as char
    }

    #[doc = "Return a char randomly chosen from chars, failing if chars is \
             empty"]
    fn gen_char_from(chars: str) -> char {
        assert !chars.is_empty();
        self.choose(str::chars(chars))
    }

    #[doc = "Return a random bool"]
    fn gen_bool() -> bool {
        self.next() & 1u32 == 1u32
    }

    #[doc = "Return a bool with a 1 in n chance of true"]
    fn gen_weighted_bool(n: uint) -> bool {
        if n == 0u {
            true
        } else {
            self.gen_uint_range(1u, n + 1u) == 1u
        }
    }

    #[doc = "Return a random string of the specified length composed of A-Z, \
             a-z, 0-9"]
    fn gen_str(len: uint) -> str {
        let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                      "abcdefghijklmnopqrstuvwxyz" +
                      "0123456789";
        let mut s = "";
        let mut i = 0u;
        while (i < len) {
            s = s + str::from_char(self.gen_char_from(charset));
            i += 1u;
        }
        s
    }

    #[doc = "Return a random byte string of the specified length"]
    fn gen_bytes(len: uint) -> [u8] {
        vec::from_fn(len) {|_i|
            self.gen_u8()
        }
    }

    #[doc = "Choose an item randomly, failing if values is empty"]
    fn choose<T:copy>(values: [T]) -> T {
        self.choose_option(values).get()
    }

    #[doc = "Choose some(item) randomly, returning none if values is empty"]
    fn choose_option<T:copy>(values: [T]) -> option<T> {
        if values.is_empty() {
            none
        } else {
            some(values[self.gen_uint_range(0u, values.len())])
        }
    }

    #[doc = "Choose an item respecting the relative weights, failing if \
             the sum of the weights is 0"]
    fn choose_weighted<T: copy>(v : [weighted<T>]) -> T {
        self.choose_weighted_option(v).get()
    }

    #[doc = "Choose some(item) respecting the relative weights, returning \
             none if the sum of the weights is 0"]
    fn choose_weighted_option<T:copy>(v: [weighted<T>]) -> option<T> {
        let mut total = 0u;
        for v.each {|item|
            total += item.weight;
        }
        if total == 0u {
            ret none;
        }
        let chosen = self.gen_uint_range(0u, total);
        let mut so_far = 0u;
        for v.each {|item|
            so_far += item.weight;
            if so_far > chosen {
                ret some(item.item);
            }
        }
        unreachable();
    }

    #[doc = "Return a vec containing copies of the items, in order, where \
             the weight of the item determines how many copies there are"]
    fn weighted_vec<T:copy>(v: [weighted<T>]) -> [T] {
        let mut r = [];
        for v.each {|item|
            uint::range(0u, item.weight) {|_i|
                r += [item.item];
            }
        }
        r
    }

    #[doc = "Shuffle a vec"]
    fn shuffle<T:copy>(values: [T]) -> [T] {
        let mut m = vec::to_mut(values);
        self.shuffle_mut(m);
        ret vec::from_mut(m);
    }

    #[doc = "Shuffle a mutable vec in place"]
    fn shuffle_mut<T>(&values: [mut T]) {
        let mut i = values.len();
        while i >= 2u {
            // invariant: elements with index >= i have been locked in place.
            i -= 1u;
            // lock element i in place.
            vec::swap(values, i, self.gen_uint_range(0u, i + 1u));
        }
    }

}

resource rand_res(c: *rctx) { rustrt::rand_free(c); }

impl of rng for @rand_res {
    fn next() -> u32 { ret rustrt::rand_next(**self); }
}

#[doc = "Create a new random seed for seeded_rng"]
fn seed() -> [u8] {
    rustrt::rand_seed()
}

#[doc = "Create a random number generator with a system specified seed"]
fn rng() -> rng {
    @rand_res(rustrt::rand_new()) as rng
}

#[doc = "Create a random number generator using the specified seed. A \
         generator constructed with a given seed will generate the same \
         sequence of values as all other generators constructed with the \
         same seed. The seed may be any length."]
fn seeded_rng(seed: [u8]) -> rng {
    @rand_res(rustrt::rand_new_seeded(seed)) as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn rng_seeded() {
        let seed = rand::seed();
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed() {
        // much shorter than generated seeds which are 1024 bytes
        let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn gen_int_range() {
        let r = rand::rng();
        let a = r.gen_int_range(-3, 42);
        assert a >= -3 && a < 42;
        assert r.gen_int_range(0, 1) == 0;
        assert r.gen_int_range(-12, -11) == -12;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win3"))]
    fn gen_int_from_fail() {
        rand::rng().gen_int_range(5, -2);
    }

    #[test]
    fn gen_uint_range() {
        let r = rand::rng();
        let a = r.gen_uint_range(3u, 42u);
        assert a >= 3u && a < 42u;
        assert r.gen_uint_range(0u, 1u) == 0u;
        assert r.gen_uint_range(12u, 13u) == 12u;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win3"))]
    fn gen_uint_range_fail() {
        rand::rng().gen_uint_range(5u, 2u);
    }

    #[test]
    fn gen_float() {
        let r = rand::rng();
        let a = r.gen_float();
        let b = r.gen_float();
        log(debug, (a, b));
    }

    #[test]
    fn gen_weighted_bool() {
        let r = rand::rng();
        assert r.gen_weighted_bool(0u) == true;
        assert r.gen_weighted_bool(1u) == true;
    }

    #[test]
    fn gen_str() {
        let r = rand::rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert r.gen_str(0u).len() == 0u;
        assert r.gen_str(10u).len() == 10u;
        assert r.gen_str(16u).len() == 16u;
    }

    #[test]
    fn gen_bytes() {
        let r = rand::rng();
        assert r.gen_bytes(0u).len() == 0u;
        assert r.gen_bytes(10u).len() == 10u;
        assert r.gen_bytes(16u).len() == 16u;
    }

    #[test]
    fn choose() {
        let r = rand::rng();
        assert r.choose([1, 1, 1]) == 1;
    }

    #[test]
    fn choose_option() {
        let r = rand::rng();
        assert r.choose_option([]) == none::<int>;
        assert r.choose_option([1, 1, 1]) == some(1);
    }

    #[test]
    fn choose_weighted() {
        let r = rand::rng();
        assert r.choose_weighted([{weight: 1u, item: 42}]) == 42;
        assert r.choose_weighted([
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == 43;
    }

    #[test]
    fn choose_weighted_option() {
        let r = rand::rng();
        assert r.choose_weighted_option([{weight: 1u, item: 42}]) == some(42);
        assert r.choose_weighted_option([
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == some(43);
        assert r.choose_weighted_option([]) == none::<int>;
    }

    #[test]
    fn weighted_vec() {
        let r = rand::rng();
        let empty: [int] = [];
        assert r.weighted_vec([]) == empty;
        assert r.weighted_vec([
            {weight: 0u, item: 3u},
            {weight: 1u, item: 2u},
            {weight: 2u, item: 1u}
        ]) == [2u, 1u, 1u];
    }

    #[test]
    fn shuffle() {
        let r = rand::rng();
        let empty: [int] = [];
        assert r.shuffle([]) == empty;
        assert r.shuffle([1, 1, 1]) == [1, 1, 1];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate libc;

use std::io;
use std::mem;
use std::os::unix::io::RawFd;

use consts::{FIDO_USAGE_PAGE, FIDO_USAGE_U2FHID};
use util::from_unix_result;

#[allow(non_camel_case_types)]
#[repr(C)]
pub struct ReportDescriptor {
    size: ::libc::c_int,
    value: [u8; 4096],
}

impl ReportDescriptor {
    fn iter(self) -> ReportDescriptorIterator {
        ReportDescriptorIterator::new(self)
    }
}

const NRBITS: u32 = 8;
const TYPEBITS: u32 = 8;

const READ: u8 = 2;
const SIZEBITS: u8 = 14;

const NRSHIFT: u32 = 0;
const TYPESHIFT: u32 = NRSHIFT + NRBITS as u32;
const SIZESHIFT: u32 = TYPESHIFT + TYPEBITS as u32;
const DIRSHIFT: u32 = SIZESHIFT + SIZEBITS as u32;

macro_rules! ioctl {
    ($dir:expr, $name:ident, $ioty:expr, $nr:expr; $ty:ty) => (
        pub unsafe fn $name(fd: libc::c_int, val: *mut $ty) -> io::Result<libc::c_int> {
            let size = mem::size_of::<$ty>();
            let ioc = (($dir as u32) << DIRSHIFT) |
                      (($ioty as u32) << TYPESHIFT) |
                      (($nr as u32) << NRSHIFT) |
                      ((size as u32) << SIZESHIFT);
            from_unix_result(libc::ioctl(fd, ioc as libc::c_ulong, val))
        }
    );
}

// https://github.com/torvalds/linux/blob/master/include/uapi/linux/hidraw.h
ioctl!(READ, hidiocgrdescsize, b'H', 0x01; ::libc::c_int);
ioctl!(READ, hidiocgrdesc, b'H', 0x02; /*struct*/ ReportDescriptor);

enum Data {
    UsagePage { data: u32 },
    Usage { data: u32 },
}

struct ReportDescriptorIterator {
    desc: ReportDescriptor,
    pos: usize,
}

impl ReportDescriptorIterator {
    fn new(desc: ReportDescriptor) -> Self {
        Self { desc, pos: 0 }
    }
}

impl Iterator for ReportDescriptorIterator {
    type Item = Data;

    fn next(&mut self) -> Option<Self::Item> {
        let value_len = self.desc.value.len();
        if self.pos >= value_len {
            return None;
        }

        let key = self.desc.value[self.pos];
        if key & 0xf0 == 0xf0 {
            self.pos = value_len;
            return None; // Invalid data.
        }

        // Determine length.
        let data_len = match key & 0x3 {
            s @ 0...2 => s as usize,
            _ => 4, /* key & 0x3 == 3 */
        };

        if self.pos + data_len >= value_len {
            self.pos = value_len;
            return None; // Invalid data.
        }

        let range = self.pos + 1..self.pos + 1 + data_len;
        let data = read_uint_le(&self.desc.value[range]);
        self.pos += 1 + data_len;

        match key & 0xfc {
            0x4 => Some(Data::UsagePage { data: data }),
            0x8 => Some(Data::Usage { data: data }),
            _ => self.next(),
        }
    }
}

fn read_uint_le(buf: &[u8]) -> u32 {
    assert!(buf.len() <= 4);
    // Parse the number in little endian byte order.
    buf.iter().rev().fold(0, |num, b| (num << 8) | (*b as u32))
}

pub fn is_u2f_device(fd: RawFd) -> bool {
    match read_report_descriptor(fd) {
        Ok(desc) => has_fido_usage(desc),
        Err(_) => false, // Upon failure, just say it's not a U2F device.
    }
}

fn read_report_descriptor(fd: RawFd) -> io::Result<ReportDescriptor> {
    let mut desc = ReportDescriptor {
        size: 0,
        value: [0; 4096],
    };
    let _ = unsafe { hidiocgrdescsize(fd, &mut desc.size)? };
    let _ = unsafe { hidiocgrdesc(fd, &mut desc)? };
    Ok(desc)
}

fn has_fido_usage(desc: ReportDescriptor) -> bool {
    let mut usage_page = None;
    let mut usage = None;

    for data in desc.iter() {
        match data {
            Data::UsagePage { data } => usage_page = Some(data),
            Data::Usage { data } => usage = Some(data),
        }

        // Check the values we found.
        if let (Some(usage_page), Some(usage)) = (usage_page, usage) {
            return usage_page == FIDO_USAGE_PAGE as u32 && usage == FIDO_USAGE_U2FHID as u32;
        }
    }

    false
}
<commit_msg>Cleanup linux/hidraw, support long item format<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate libc;

use std::io;
use std::mem;
use std::os::unix::io::RawFd;

use consts::{FIDO_USAGE_PAGE, FIDO_USAGE_U2FHID};
use util::{from_unix_result, io_err};

#[allow(non_camel_case_types)]
#[repr(C)]
pub struct ReportDescriptor {
    size: ::libc::c_int,
    value: [u8; 4096],
}

impl ReportDescriptor {
    fn iter(self) -> ReportDescriptorIterator {
        ReportDescriptorIterator::new(self)
    }
}

const NRBITS: u32 = 8;
const TYPEBITS: u32 = 8;

const READ: u8 = 2;
const SIZEBITS: u8 = 14;

const NRSHIFT: u32 = 0;
const TYPESHIFT: u32 = NRSHIFT + NRBITS as u32;
const SIZESHIFT: u32 = TYPESHIFT + TYPEBITS as u32;
const DIRSHIFT: u32 = SIZESHIFT + SIZEBITS as u32;

// The 4 MSBs (the tag) are set when it's a long item.
const HID_MASK_LONG_ITEM_TAG: u8 = 0b11110000;
// The 2 LSBs denote the size of a short item.
const HID_MASK_SHORT_ITEM_SIZE: u8 = 0b00000011;
// The 6 MSBs denote the tag (4) and type (2).
const HID_MASK_ITEM_TAGTYPE: u8 = 0b11111100;
// tag=0000, type=10 (local)
const HID_ITEM_TAGTYPE_USAGE: u8 = 0b00001000;
// tag=0000, type=01 (global)
const HID_ITEM_TAGTYPE_USAGE_PAGE: u8 = 0b00000100;

// https://github.com/torvalds/linux/blob/master/include/uapi/linux/hid.h
const HID_MAX_DESCRIPTOR_SIZE: usize = 4096;

macro_rules! ioctl {
    ($dir:expr, $name:ident, $ioty:expr, $nr:expr; $ty:ty) => (
        pub unsafe fn $name(fd: libc::c_int, val: *mut $ty) -> io::Result<libc::c_int> {
            let size = mem::size_of::<$ty>();
            let ioc = (($dir as u32) << DIRSHIFT) |
                      (($ioty as u32) << TYPESHIFT) |
                      (($nr as u32) << NRSHIFT) |
                      ((size as u32) << SIZESHIFT);
            from_unix_result(libc::ioctl(fd, ioc as libc::c_ulong, val))
        }
    );
}

// https://github.com/torvalds/linux/blob/master/include/uapi/linux/hidraw.h
ioctl!(READ, hidiocgrdescsize, b'H', 0x01; ::libc::c_int);
ioctl!(READ, hidiocgrdesc, b'H', 0x02; /*struct*/ ReportDescriptor);

enum Data {
    UsagePage { data: u32 },
    Usage { data: u32 },
}

struct ReportDescriptorIterator {
    desc: ReportDescriptor,
    pos: usize,
}

impl ReportDescriptorIterator {
    fn new(desc: ReportDescriptor) -> Self {
        Self { desc, pos: 0 }
    }

    fn next_item(&mut self) -> Option<Data> {
        let item = get_hid_item(&self.desc.value[self.pos..]);
        if item.is_none() {
            self.pos = self.desc.size as usize; // Close, invalid data.
            return None;
        }

        let (tag_type, key_len, data) = item.unwrap();

        // Advance if we have a valid item.
        self.pos += key_len + data.len();

        // We only check short items.
        if key_len > 1 {
            return None; // Check next item.
        }

        // Short items have max. length of 4 bytes.
        assert!(data.len() <= mem::size_of::<u32>());

        // Convert data bytes to a uint.
        let data = read_uint_le(data);

        match tag_type {
            HID_ITEM_TAGTYPE_USAGE_PAGE => Some(Data::UsagePage { data }),
            HID_ITEM_TAGTYPE_USAGE => Some(Data::Usage { data }),
            _ => None,
        }
    }
}

impl Iterator for ReportDescriptorIterator {
    type Item = Data;

    fn next(&mut self) -> Option<Self::Item> {
        if self.pos >= self.desc.size as usize {
            return None;
        }

        self.next_item().or_else(|| self.next())
    }
}

fn get_hid_item<'a>(buf: &'a [u8]) -> Option<(u8, usize, &'a [u8])> {
    if (buf[0] & HID_MASK_LONG_ITEM_TAG) == HID_MASK_LONG_ITEM_TAG {
        get_hid_long_item(buf)
    } else {
        get_hid_short_item(buf)
    }
}

fn get_hid_long_item<'a>(buf: &'a [u8]) -> Option<(u8, usize, &'a [u8])> {
    // A valid long item has at least three bytes.
    if buf.len() < 3 {
        return None;
    }

    let len = buf[1] as usize;

    // Ensure that there are enough bytes left in the buffer.
    if len > buf.len() - 3 {
        return None;
    }

    Some((buf[2], 3 /* key length */, &buf[3..]))
}

fn get_hid_short_item<'a>(buf: &'a [u8]) -> Option<(u8, usize, &'a [u8])> {
    // This is a short item. The bottom two bits of the key
    // contain the length of the data section (value) for this key.
    let len = match buf[0] & HID_MASK_SHORT_ITEM_SIZE {
        s @ 0...2 => s as usize,
        _ => 4, /* _ == 3 */
    };

    // Ensure that there are enough bytes left in the buffer.
    if len > buf.len() - 1 {
        return None;
    }

    Some((
        buf[0] & HID_MASK_ITEM_TAGTYPE,
        1, /* key length */
        &buf[1..1 + len],
    ))
}

fn read_uint_le(buf: &[u8]) -> u32 {
    assert!(buf.len() <= 4);
    // Parse the number in little endian byte order.
    buf.iter().rev().fold(0, |num, b| (num << 8) | (*b as u32))
}

pub fn is_u2f_device(fd: RawFd) -> bool {
    match read_report_descriptor(fd) {
        Ok(desc) => has_fido_usage(desc),
        Err(_) => false, // Upon failure, just say it's not a U2F device.
    }
}

fn read_report_descriptor(fd: RawFd) -> io::Result<ReportDescriptor> {
    let mut desc = ReportDescriptor {
        size: 0,
        value: [0; HID_MAX_DESCRIPTOR_SIZE],
    };

    let _ = unsafe { hidiocgrdescsize(fd, &mut desc.size)? };
    if desc.size == 0 || desc.size as usize > desc.value.len() {
        return Err(io_err("unexpected hidiocgrdescsize() result"));
    }

    let _ = unsafe { hidiocgrdesc(fd, &mut desc)? };
    Ok(desc)
}

fn has_fido_usage(desc: ReportDescriptor) -> bool {
    let mut usage_page = None;
    let mut usage = None;

    for data in desc.iter() {
        match data {
            Data::UsagePage { data } => usage_page = Some(data),
            Data::Usage { data } => usage = Some(data),
        }

        // Check the values we found.
        if let (Some(usage_page), Some(usage)) = (usage_page, usage) {
            return usage_page == FIDO_USAGE_PAGE as u32 && usage == FIDO_USAGE_U2FHID as u32;
        }
    }

    false
}
<|endoftext|>


<commit_before>use std::f32::consts::PI;

use cgmath::{vec3};
use cgmath::prelude::*;

use num_traits::clamp;

// type Point3 = cgmath::Point3<f32>;
// type Vector3 = cgmath::Vector3<f32>;
// type Matrix4 = cgmath::Matrix4<f32>;

use render::Camera;
use render::math::*;

// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
#[derive(PartialEq)]
pub enum CameraMovement {
    FORWARD,
    BACKWARD,
    LEFT,
    RIGHT,
}
use self::CameraMovement::*;

#[derive(Debug)]
pub struct CameraParams {
    pub position: Vector3,
    pub view_matrix: Matrix4,
    pub projection_matrix: Matrix4,
}

// Default camera values
const YAW: f32 = -90.0;
const PITCH: f32 = 0.0;
const SPEED: f32 = 2.5;
const SENSITIVTY: f32 = 0.1;
const ZOOM_SENSITIVITY: f32 = 0.1;
pub const ZOOM: f32 = 45.0;
const MIN_ZOOM: f32 = 1.0;
const MAZ_ZOOM: f32 = 170.0;

pub struct CameraControls {
    // Camera Attributes
    pub position: Point3,

    /// mutually exlusive: if center is set, it is used
    pub front: Vector3,
    pub center: Option<Point3>,

    pub up: Vector3,
    pub right: Vector3,
    pub world_up: Vector3,
    // Euler Angles
    pub yaw: f32,
    pub pitch: f32,
    // Camera options
    pub movement_speed: f32,
    pub mouse_sensitivity: f32,

    pub camera: Camera,

    // pub moving_up: bool,
    pub moving_left: bool,
    // pub moving_down: bool,
    pub moving_right: bool,
    pub moving_forward: bool,
    pub moving_backward: bool,
}

impl Default for CameraControls {
    fn default() -> CameraControls {
        let mut controls = CameraControls {
            position: Point3::new(0.0, 0.0, 0.0),
            front: vec3(0.0, 0.0, -1.0),
            center: None,
            up: Vector3::zero(), // initialized later
            right: Vector3::zero(), // initialized later
            world_up: Vector3::unit_y(),
            yaw: YAW,
            pitch: PITCH,
            movement_speed: SPEED,
            mouse_sensitivity: SENSITIVTY,

            camera: Camera::default(),

            // moving_up: false,
            moving_left: false,
            // moving_down: false,
            moving_right: false,
            moving_forward: false,
            moving_backward: false,
        };
        // TODO!!: overriding default order...? -> NO!
        controls.update_camera_vectors();
        controls
    }
}

impl CameraControls {
    pub fn camera_params(&self) -> CameraParams {
        CameraParams {
            position: self.position.to_vec(),
            view_matrix: self.view_matrix(),
            projection_matrix: self.camera.projection_matrix,
        }
    }

    /// Returns the view matrix calculated using Euler Angles and the LookAt Matrix
    pub fn view_matrix(&self) -> Matrix4 {
        if let Some(center) = self.center {
            Matrix4::look_at(self.position, center, self.up)
        }
        else {
            Matrix4::look_at(self.position, self.position + self.front, self.up)
        }
    }

    pub fn update(&mut self, delta_time: f64) {
        let velocity = self.movement_speed * delta_time as f32;
        if self.moving_forward {
            self.position += self.front * velocity;
        }
        if self.moving_backward {
            self.position += -(self.front * velocity);
        }
        if self.moving_left {
            self.position += -(self.right * velocity);
        }
        if self.moving_right {
            self.position += self.right * velocity;
        }
    }

    pub fn process_keyboard(&mut self, direction: CameraMovement, pressed: bool) {
        match direction {
            FORWARD => self.moving_forward = pressed,
            BACKWARD => self.moving_backward= pressed,
            LEFT => self.moving_left = pressed,
            RIGHT => self.moving_right = pressed,
        }
    }

    /// Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
    pub fn process_mouse_movement(&mut self, mut xoffset: f32, mut yoffset: f32, constrain_pitch: bool) {
        xoffset *= self.mouse_sensitivity;
        yoffset *= self.mouse_sensitivity;

        self.yaw += xoffset;
        self.pitch += yoffset;

        // Make sure that when pitch is out of bounds, screen doesn't get flipped
        if constrain_pitch {
            if self.pitch > 89.0 {
                self.pitch = 89.0;
            }
            if self.pitch < -89.0 {
                self.pitch = -89.0;
            }
        }

        // Update front, Right and Up Vectors using the updated Eular angles
        self.update_camera_vectors();
    }

    /// Calculates the front vector from the Camera's (updated) Eular Angles
    fn update_camera_vectors(&mut self) {
        if let Some(center) = self.center {
            self.front = center - self.position; // TODO!!!: overwritten again immediately...
            self.center = None;
        }
        // Calculate the new front vector
        let front = Vector3 {
            x: self.yaw.to_radians().cos() * self.pitch.to_radians().cos(),
            y: self.pitch.to_radians().sin(),
            z: self.yaw.to_radians().sin() * self.pitch.to_radians().cos(),
        };
        self.front = front.normalize();
        // Also re-calculate the Right and Up vector
        self.right = self.front.cross(self.world_up).normalize(); // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
        self.up = self.right.cross(self.front).normalize();
    }

    pub fn set_camera(&mut self, camera: &Camera, transform: &Matrix4) {
        // spec: If no transformation is specified, the location of the camera is at the origin.
        let pos = transform * Vector4::zero();

        // spec: ... the lens looks towards the local -Z axis ...
        let look_at = transform * vec4(0.0, 0.0, -1.0, 0.0);

        self.position = Point3::new(pos.x, pos.y, pos.z);
        self.center = Some(Point3::new(look_at.x, look_at.y, look_at.z));

        // TODO!!: handle better (camera zoom/fovy)
        let mut camera = camera.clone();
        camera.fovy = self.camera.fovy;
        self.camera = camera;

        self.update_camera_vectors();
    }
}

#[derive(Clone)]
pub enum NavState {
    None,
    Rotating,
    Panning,
}

/// Inspirted by ThreeJS OrbitControls
pub struct OrbitControls {
    pub camera: Camera,

    pub position: Point3,

    // "target" sets the location of focus, where the object orbits around
	pub target: Point3,

    pub state: NavState,

	// current position in spherical coordinates
	spherical: Spherical,
	spherical_delta: Spherical,

    scale: f32,
    pan_offset: Vector3,

    rotate_start: Option<Vector2>,
    rotate_end: Vector2,

	pan_start: Option<Vector2>,
	pan_end: Vector2,

    pub screen_width: f32,
    pub screen_height: f32,

    //
    offset: Vector3,

    // quat: Quaternion,

    // TODO!!: unused?
    last_position: Vector3,
    last_quaternion: Quaternion,
}

impl OrbitControls {
    pub fn new(position: Point3, screen_width: f32, screen_height: f32) -> Self {
        OrbitControls {
            camera: Camera::default(),

            position,
            target: Point3::new(0.0, 0.0, 0.0),

            state: NavState::None,

            // current position in spherical coordinates
            spherical: Spherical::default(),
            spherical_delta: Spherical::default(),

            scale: 1.0,
            pan_offset: Vector3::zero(),

            rotate_start: None,
            rotate_end: Vector2::zero(),

            pan_start: None,
            pan_end: Vector2::zero(),

            screen_width,
            screen_height,

            //
            offset: Vector3::zero(),

            // NOTE: original uses sth like Quaternion::from_arc from "up" to "y up"
            // and stores inverse quaternion
            // quat: Quaternion::one(),

            last_position: Vector3::zero(),
            last_quaternion: Quaternion::zero(),
        }
    }

    // TODO!!: cache/return reference? often many of them stay the same...
    pub fn camera_params(&self) -> CameraParams {
        CameraParams {
            position: self.position.to_vec(),
            view_matrix: self.view_matrix(),
            projection_matrix: self.camera.projection_matrix,
        }
    }

    fn view_matrix(&self) -> Matrix4 {
        Matrix4::look_at(self.position, self.target, vec3(0.0, 1.0, 0.0))
    }

    pub fn handle_mouse_move(&mut self, x: f32, y: f32) {
        match self.state {
            NavState::Rotating => self.handle_mouse_move_rotate(x, y),
            NavState::Panning => self.handle_mouse_move_pan(x, y),
            NavState::None => ()
        }
    }

    fn handle_mouse_move_rotate(&mut self, x: f32, y: f32) {
        self.rotate_end.x = x;
        self.rotate_end.y = y;
        let rotate_delta = if let Some(rotate_start) = self.rotate_start {
            self.rotate_end - rotate_start
        } else {
            Vector2::zero()
        };

        // rotating across whole screen goes 360 degrees around
        let rotate_speed = 1.0; // TODO: const/param/remove?
        let angle = 2.0 * PI * rotate_delta.x / self.screen_width * rotate_speed;
        self.rotate_left(angle);

        // rotating up and down along whole screen attempts to go 360, but limited to 180
        let angle = 2.0 * PI * rotate_delta.y / self.screen_height * rotate_speed;
		self.rotate_up(angle);

        self.rotate_start = Some(self.rotate_end);

		self.update();
    }

    pub fn handle_mouse_up(&mut self) {
        self.rotate_start = None;
        self.pan_start = None;
    }

    fn rotate_left(&mut self, angle: f32) {
        self.spherical_delta.theta -= angle;
    }

    fn rotate_up(&mut self, angle: f32) {
        self.spherical_delta.phi -= angle;
    }

    fn handle_mouse_move_pan(&mut self, x: f32, y: f32) {
        self.pan_end.x = x;
        self.pan_end.y = y;

        let pan_delta = if let Some(pan_start) = self.pan_start {
            self.pan_end - pan_start
        } else {
            Vector2::zero()
        };

        self.pan(&pan_delta);

        self.pan_start = Some(self.pan_end);

        self.update();
    }

    fn pan(&mut self, delta: &Vector2) {
        if self.camera.is_perspective() {
            self.offset = self.position - self.target;
            let mut target_distance = self.offset.magnitude();

            // half of the fov is center to top of screen
            target_distance *= (self.camera.fovy / 2.0).tan() * PI / 180.0;

            // we actually don't use screen_width, since perspective camera is fixed to screen height
            let distance = 2.0 * delta.x * target_distance / self.screen_height;
            self.pan_left(distance);
            let distance = 2.0 * delta.y * target_distance / self.screen_height;
            self.pan_up(distance);
        } else {
            unimplemented!("orthographic camera zoom")
        }
    }

    pub fn pan_left(&mut self, distance: f32) {
        self.pan_offset.x -= distance
    }

    pub fn pan_up(&mut self, distance: f32) {
        self.pan_offset.y -= distance
    }

    // Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
    pub fn process_mouse_scroll(&mut self, mut yoffset: f32) {
        yoffset *= ZOOM_SENSITIVITY;
        if self.camera.fovy >= MIN_ZOOM && self.camera.fovy <= MAZ_ZOOM {
            self.camera.fovy -= yoffset;
        }
        if self.camera.fovy <= MIN_ZOOM {
            self.camera.fovy = MIN_ZOOM;
        }
        if self.camera.fovy >= MAZ_ZOOM {
            self.camera.fovy = MAZ_ZOOM;
        }
        self.camera.update_projection_matrix();
    }

    fn update(&mut self) {
        self.offset = self.position - self.target;

        // rotate offset to "y-axis-is-up" space
        // self.offset = self.quat.rotate_vector(self.offset);

        // angle from z-axis around y-axis
        self.spherical = Spherical::from_vec3(self.offset);

        self.spherical.theta += self.spherical_delta.theta;
        self.spherical.phi += self.spherical_delta.phi;

        // TODO!: left out theta restrictions / make_safe for now

        // restrict phi to be between desired limits
        let epsilon = 0.0001;
        self.spherical.phi = clamp(self.spherical.phi, epsilon, PI - epsilon);

        self.spherical.radius *= self.scale;

        // TODO?: restrict radius to be between desired limits?

        // move target to panned location
        self.target += self.pan_offset;

        self.offset = self.spherical.to_vec3();

        // NOTE: skipped from original: rotate offset back to "camera-up-vector-is-up" space

        self.position = self.target + self.offset;

        // self.position += self.pan_offset;

        // TODO!!: how to do this?
        // scope.object.lookAt( scope.target );

        // TODO!: if enable_damping...?
        self.spherical_delta.radius = 0.0;
        self.spherical_delta.phi = 0.0;
        self.spherical_delta.theta = 0.0;

        self.scale = 1.0;
        self.pan_offset = Vector3::zero();

        // TODO!: zoomChanged stuff

        // TODO!!!
    }
}
<commit_msg>small refactor<commit_after>use std::f32::consts::PI;

use cgmath::{vec3};
use cgmath::prelude::*;

use num_traits::clamp;

// type Point3 = cgmath::Point3<f32>;
// type Vector3 = cgmath::Vector3<f32>;
// type Matrix4 = cgmath::Matrix4<f32>;

use render::Camera;
use render::math::*;

// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
#[derive(PartialEq)]
pub enum CameraMovement {
    FORWARD,
    BACKWARD,
    LEFT,
    RIGHT,
}
use self::CameraMovement::*;

#[derive(Debug)]
pub struct CameraParams {
    pub position: Vector3,
    pub view_matrix: Matrix4,
    pub projection_matrix: Matrix4,
}

// Default camera values
const YAW: f32 = -90.0;
const PITCH: f32 = 0.0;
const SPEED: f32 = 2.5;
const SENSITIVTY: f32 = 0.1;
const ZOOM_SENSITIVITY: f32 = 0.1;
pub const ZOOM: f32 = 45.0;
const MIN_ZOOM: f32 = 1.0;
const MAZ_ZOOM: f32 = 170.0;

pub struct CameraControls {
    // Camera Attributes
    pub position: Point3,

    /// mutually exlusive: if center is set, it is used
    pub front: Vector3,
    pub center: Option<Point3>,

    pub up: Vector3,
    pub right: Vector3,
    pub world_up: Vector3,
    // Euler Angles
    pub yaw: f32,
    pub pitch: f32,
    // Camera options
    pub movement_speed: f32,
    pub mouse_sensitivity: f32,

    pub camera: Camera,

    // pub moving_up: bool,
    pub moving_left: bool,
    // pub moving_down: bool,
    pub moving_right: bool,
    pub moving_forward: bool,
    pub moving_backward: bool,
}

impl Default for CameraControls {
    fn default() -> CameraControls {
        let mut controls = CameraControls {
            position: Point3::new(0.0, 0.0, 0.0),
            front: vec3(0.0, 0.0, -1.0),
            center: None,
            up: Vector3::zero(), // initialized later
            right: Vector3::zero(), // initialized later
            world_up: Vector3::unit_y(),
            yaw: YAW,
            pitch: PITCH,
            movement_speed: SPEED,
            mouse_sensitivity: SENSITIVTY,

            camera: Camera::default(),

            // moving_up: false,
            moving_left: false,
            // moving_down: false,
            moving_right: false,
            moving_forward: false,
            moving_backward: false,
        };
        // TODO!!: overriding default order...? -> NO!
        controls.update_camera_vectors();
        controls
    }
}

impl CameraControls {
    pub fn camera_params(&self) -> CameraParams {
        CameraParams {
            position: self.position.to_vec(),
            view_matrix: self.view_matrix(),
            projection_matrix: self.camera.projection_matrix,
        }
    }

    /// Returns the view matrix calculated using Euler Angles and the LookAt Matrix
    pub fn view_matrix(&self) -> Matrix4 {
        if let Some(center) = self.center {
            Matrix4::look_at(self.position, center, self.up)
        }
        else {
            Matrix4::look_at(self.position, self.position + self.front, self.up)
        }
    }

    pub fn update(&mut self, delta_time: f64) {
        let velocity = self.movement_speed * delta_time as f32;
        if self.moving_forward {
            self.position += self.front * velocity;
        }
        if self.moving_backward {
            self.position += -(self.front * velocity);
        }
        if self.moving_left {
            self.position += -(self.right * velocity);
        }
        if self.moving_right {
            self.position += self.right * velocity;
        }
    }

    pub fn process_keyboard(&mut self, direction: CameraMovement, pressed: bool) {
        match direction {
            FORWARD => self.moving_forward = pressed,
            BACKWARD => self.moving_backward= pressed,
            LEFT => self.moving_left = pressed,
            RIGHT => self.moving_right = pressed,
        }
    }

    /// Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
    pub fn process_mouse_movement(&mut self, mut xoffset: f32, mut yoffset: f32, constrain_pitch: bool) {
        xoffset *= self.mouse_sensitivity;
        yoffset *= self.mouse_sensitivity;

        self.yaw += xoffset;
        self.pitch += yoffset;

        // Make sure that when pitch is out of bounds, screen doesn't get flipped
        if constrain_pitch {
            if self.pitch > 89.0 {
                self.pitch = 89.0;
            }
            if self.pitch < -89.0 {
                self.pitch = -89.0;
            }
        }

        // Update front, Right and Up Vectors using the updated Eular angles
        self.update_camera_vectors();
    }

    /// Calculates the front vector from the Camera's (updated) Eular Angles
    fn update_camera_vectors(&mut self) {
        if let Some(center) = self.center {
            self.front = center - self.position; // TODO!!!: overwritten again immediately...
            self.center = None;
        }
        // Calculate the new front vector
        let front = Vector3 {
            x: self.yaw.to_radians().cos() * self.pitch.to_radians().cos(),
            y: self.pitch.to_radians().sin(),
            z: self.yaw.to_radians().sin() * self.pitch.to_radians().cos(),
        };
        self.front = front.normalize();
        // Also re-calculate the Right and Up vector
        self.right = self.front.cross(self.world_up).normalize(); // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
        self.up = self.right.cross(self.front).normalize();
    }

    pub fn set_camera(&mut self, camera: &Camera, transform: &Matrix4) {
        // spec: If no transformation is specified, the location of the camera is at the origin.
        let pos = transform * Vector4::zero();

        // spec: ... the lens looks towards the local -Z axis ...
        let look_at = transform * vec4(0.0, 0.0, -1.0, 0.0);

        self.position = Point3::new(pos.x, pos.y, pos.z);
        self.center = Some(Point3::new(look_at.x, look_at.y, look_at.z));

        // TODO!!: handle better (camera zoom/fovy)
        let mut camera = camera.clone();
        camera.fovy = self.camera.fovy;
        self.camera = camera;

        self.update_camera_vectors();
    }
}

#[derive(Clone)]
pub enum NavState {
    None,
    Rotating,
    Panning,
}

/// Inspirted by ThreeJS OrbitControls
pub struct OrbitControls {
    pub camera: Camera,

    pub position: Point3,

    // "target" sets the location of focus, where the object orbits around
	pub target: Point3,

    pub state: NavState,

	// current position in spherical coordinates
	spherical: Spherical,
	spherical_delta: Spherical,

    scale: f32,
    pan_offset: Vector3,

    rotate_start: Option<Vector2>,
    rotate_end: Vector2,

	pan_start: Option<Vector2>,
	pan_end: Vector2,

    pub screen_width: f32,
    pub screen_height: f32,

    // quat: Quaternion,

    // TODO!!: unused?
    last_position: Vector3,
    last_quaternion: Quaternion,
}

impl OrbitControls {
    pub fn new(position: Point3, screen_width: f32, screen_height: f32) -> Self {
        OrbitControls {
            camera: Camera::default(),

            position,
            target: Point3::new(0.0, 0.0, 0.0),

            state: NavState::None,

            // current position in spherical coordinates
            spherical: Spherical::default(),
            spherical_delta: Spherical::default(),

            scale: 1.0,
            pan_offset: Vector3::zero(),

            rotate_start: None,
            rotate_end: Vector2::zero(),

            pan_start: None,
            pan_end: Vector2::zero(),

            screen_width,
            screen_height,

            //

            // NOTE: original uses sth like Quaternion::from_arc from "up" to "y up"
            // and stores inverse quaternion
            // quat: Quaternion::one(),

            last_position: Vector3::zero(),
            last_quaternion: Quaternion::zero(),
        }
    }

    // TODO!!: cache/return reference? often many of them stay the same...
    pub fn camera_params(&self) -> CameraParams {
        CameraParams {
            position: self.position.to_vec(),
            view_matrix: self.view_matrix(),
            projection_matrix: self.camera.projection_matrix,
        }
    }

    fn view_matrix(&self) -> Matrix4 {
        Matrix4::look_at(self.position, self.target, vec3(0.0, 1.0, 0.0))
    }

    pub fn handle_mouse_move(&mut self, x: f32, y: f32) {
        match self.state {
            NavState::Rotating => self.handle_mouse_move_rotate(x, y),
            NavState::Panning => self.handle_mouse_move_pan(x, y),
            NavState::None => ()
        }
    }

    fn handle_mouse_move_rotate(&mut self, x: f32, y: f32) {
        self.rotate_end.x = x;
        self.rotate_end.y = y;
        let rotate_delta = if let Some(rotate_start) = self.rotate_start {
            self.rotate_end - rotate_start
        } else {
            Vector2::zero()
        };

        // rotating across whole screen goes 360 degrees around
        let rotate_speed = 1.0; // TODO: const/param/remove?
        let angle = 2.0 * PI * rotate_delta.x / self.screen_width * rotate_speed;
        self.rotate_left(angle);

        // rotating up and down along whole screen attempts to go 360, but limited to 180
        let angle = 2.0 * PI * rotate_delta.y / self.screen_height * rotate_speed;
		self.rotate_up(angle);

        self.rotate_start = Some(self.rotate_end);

		self.update();
    }

    pub fn handle_mouse_up(&mut self) {
        self.rotate_start = None;
        self.pan_start = None;
    }

    fn rotate_left(&mut self, angle: f32) {
        self.spherical_delta.theta -= angle;
    }

    fn rotate_up(&mut self, angle: f32) {
        self.spherical_delta.phi -= angle;
    }

    fn handle_mouse_move_pan(&mut self, x: f32, y: f32) {
        self.pan_end.x = x;
        self.pan_end.y = y;

        let pan_delta = if let Some(pan_start) = self.pan_start {
            self.pan_end - pan_start
        } else {
            Vector2::zero()
        };

        self.pan(&pan_delta);

        self.pan_start = Some(self.pan_end);

        self.update();
    }

    fn pan(&mut self, delta: &Vector2) {
        if self.camera.is_perspective() {
            let offset = self.position - self.target;
            let mut target_distance = offset.magnitude();

            // half of the fov is center to top of screen
            target_distance *= (self.camera.fovy / 2.0).tan() * PI / 180.0;

            // we actually don't use screen_width, since perspective camera is fixed to screen height
            let distance = 2.0 * delta.x * target_distance / self.screen_height;
            self.pan_left(distance);
            let distance = 2.0 * delta.y * target_distance / self.screen_height;
            self.pan_up(distance);
        } else {
            unimplemented!("orthographic camera zoom")
        }
    }

    pub fn pan_left(&mut self, distance: f32) {
        self.pan_offset.x -= distance
    }

    pub fn pan_up(&mut self, distance: f32) {
        self.pan_offset.y -= distance
    }

    // Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
    pub fn process_mouse_scroll(&mut self, mut yoffset: f32) {
        yoffset *= ZOOM_SENSITIVITY;
        if self.camera.fovy >= MIN_ZOOM && self.camera.fovy <= MAZ_ZOOM {
            self.camera.fovy -= yoffset;
        }
        if self.camera.fovy <= MIN_ZOOM {
            self.camera.fovy = MIN_ZOOM;
        }
        if self.camera.fovy >= MAZ_ZOOM {
            self.camera.fovy = MAZ_ZOOM;
        }
        self.camera.update_projection_matrix();
    }

    fn update(&mut self) {
        let mut offset = self.position - self.target;

        // rotate offset to "y-axis-is-up" space
        // self.offset = self.quat.rotate_vector(self.offset);

        // angle from z-axis around y-axis
        self.spherical = Spherical::from_vec3(offset);

        self.spherical.theta += self.spherical_delta.theta;
        self.spherical.phi += self.spherical_delta.phi;

        // TODO!: left out theta restrictions / make_safe for now

        // restrict phi to be between desired limits
        let epsilon = 0.0001;
        self.spherical.phi = clamp(self.spherical.phi, epsilon, PI - epsilon);

        self.spherical.radius *= self.scale;

        // TODO?: restrict radius to be between desired limits?

        // move target to panned location
        self.target += self.pan_offset;

        offset = self.spherical.to_vec3();

        // NOTE: skipped from original: rotate offset back to "camera-up-vector-is-up" space

        self.position = self.target + offset;

        // TODO!!: how to do this?
        // scope.object.lookAt( scope.target );

        // TODO!: if enable_damping...?
        self.spherical_delta = Spherical::from_vec3(Vector3::zero());

        self.scale = 1.0;
        self.pan_offset = Vector3::zero();

        // TODO!: zoomChanged stuff

        // TODO!!!
    }
}
<|endoftext|>


<commit_before><commit_msg>add unique.rs<commit_after><|endoftext|>


<commit_before>use std::net;
use std::collections::{HashMap, BTreeMap};
use std::sync::{Arc, Mutex, RwLock};
use bincode::{self, serde as bincode_serde};
use linear_map::LinearMap;
use dht::DHT;
use hash::hash;
use version_vector::*;
use storage::Storage;
use fabric::Fabric;
use fabric_msg::*;

const PEER_LOG_SIZE: usize = 1000;

pub struct ReqState {
    replies: usize,
    required: usize,
    total: usize,
    // only used for get
    container: DottedCausalContainer<Vec<u8>>,
}

pub struct Database {
    dht: DHT<()>,
    fabric: Fabric,
    vnodes: RwLock<HashMap<u16, Mutex<VNode>>>,
    replication_factor: usize,
    inflight: Mutex<HashMap<u64, ReqState>>,
}

struct VNodePeer {
    knowledge: u64,
    log: BTreeMap<u64, Vec<u8>>,
}

struct VNode {
    num: u16,
    clock: BitmappedVersionVector,
    log: BTreeMap<u64, Vec<u8>>,
    peers: LinearMap<u64, VNodePeer>,
    storage: Storage,
}

impl Database {
    pub fn new(node: net::SocketAddr) -> Arc<Database> {
        let db = Arc::new(Database {
            replication_factor: 3,
            fabric: Fabric::new(node).unwrap(),
            dht: DHT::new(node, (), 64),
            inflight: Mutex::new(Default::default()),
            vnodes: RwLock::new(Default::default()),
        });
        register_handlers(db.clone());
        db
    }

    pub fn init_vnode(&self, vnode_n: u16) {
        self.vnodes
            .write()
            .unwrap()
            .entry(vnode_n)
            .or_insert_with(|| Mutex::new(VNode::new(vnode_n)));
    }

    pub fn remove_vnode(&self, vnode_n: u16) {
        self.vnodes.write().unwrap().remove(&vnode_n);
    }

    pub fn get(&self, token: usize, key: &[u8]) {
        let vnode_n = self.dht.key_vnode(key);
        let nodes = self.dht.nodes_for_key(key, self.replication_factor);
        let cookie = token as u64;
        let _a = self.inflight
            .lock()
            .unwrap()
            .insert(cookie,
                    ReqState {
                        required: self.replication_factor / 2 + 1,
                        total: self.replication_factor,
                        replies: 0,
                        container: DottedCausalContainer::new(),
                    });
        debug_assert!(_a.is_none());
        for node in nodes {
            if node == self.dht.node() {
                self.get_local(cookie, key);
            } else {
                self.get_remote(&node, vnode_n, cookie, key);
            }
        }
    }

    fn get_callback(&self, cookie: u64, container: Option<DottedCausalContainer<Vec<u8>>>) {
        let mut inflight = self.inflight.lock().unwrap();
        if {
            let state = inflight.get_mut(&cookie).unwrap();
            container.map(|dcc| state.container.sync(dcc));
            state.replies += 1;
            if state.replies == state.required {
                // return to client
            }
            if state.replies == state.total {
                // remove state
                true
            } else {
                false
            }
        } {
            inflight.remove(&cookie).unwrap();
        }
    }

    fn get_local(&self, cookie: u64, key: &[u8]) {
        let vnode_n = self.dht.key_vnode(key);
        let container = self.vnodes
            .read()
            .unwrap()
            .get(&vnode_n)
            .map(|vn| vn.lock().unwrap().get(self, key));
        self.get_callback(cookie, container);
    }

    fn get_remote(&self, addr: &net::SocketAddr, vnode: u16, cookie: u64, key: &[u8]) {
        self.fabric
            .send_message(addr,
                          FabricMsg::Get(FabricMsgGet {
                              cookie: cookie,
                              vnode: vnode,
                              key: key.into(),
                          }))
            .unwrap();
    }

    pub fn get_remote_handler(&self, from: &net::SocketAddr, msg: FabricMsgGet) {
        let container = self.vnodes
            .read()
            .unwrap()
            .get(&msg.vnode)
            .map(|vn| vn.lock().unwrap().get(self, &msg.key));
        self.fabric
            .send_message(&from,
                          FabricMsg::GetAck(FabricMsgGetAck {
                              cookie: msg.cookie,
                              vnode: msg.vnode,
                              container: container.unwrap(),
                          }))
            .unwrap();
    }

    pub fn get_remote_ack_handler(&self, _from: &net::SocketAddr, msg: FabricMsgGetAck) {
        self.get_callback(msg.cookie, Some(msg.container));
    }

    pub fn set(&self, token: usize, key: &[u8], value_opt: Option<&[u8]>, vv: VersionVector) {
        let vnode_n = self.dht.key_vnode(key);
        let nodes = self.dht.nodes_for_key(key, self.replication_factor);
        let cookie = token as u64;
        let _a = self.inflight
            .lock()
            .unwrap()
            .insert(cookie,
                    ReqState {
                        required: self.replication_factor / 2 + 1,
                        total: self.replication_factor,
                        replies: 0,
                        container: DottedCausalContainer::new(),
                    });
        debug_assert!(_a.is_none());

        let dcc = self.set_local(cookie, key, value_opt, &vv);
        for node in nodes {
            if node == self.dht.node() {

            } else {
                self.set_remote(&node, vnode_n, cookie, key, dcc.clone());
            }
        }
    }

    fn set_callback(&self, cookie: u64) {
        let mut inflight = self.inflight.lock().unwrap();
        if {
            let state = inflight.get_mut(&cookie).unwrap();
            state.replies += 1;
            if state.replies == state.required {
                // return to client
            }
            if state.replies == state.total {
                // remove state
                true
            } else {
                false
            }
        } {
            inflight.remove(&cookie).unwrap();
        }
    }

    fn set_local(&self, cookie: u64, key: &[u8], value_opt: Option<&[u8]>, vv: &VersionVector)
                 -> DottedCausalContainer<Vec<u8>> {
        let vnode_n = self.dht.key_vnode(key);
        debug!("set_local {:?}", vnode_n);
        let dcc = self.vnodes
            .read()
            .unwrap()
            .get(&vnode_n)
            .map(|vn| {
                vn.lock().unwrap().set_local(self, hash(self.dht.node()), key, value_opt, vv)
            });
        self.set_callback(cookie);
        dcc.unwrap()
    }

    pub fn set_remote(&self, addr: &net::SocketAddr, vnode: u16, cookie: u64, key: &[u8],
                      dcc: DottedCausalContainer<Vec<u8>>) {
        self.fabric
            .send_message(addr,
                          FabricMsg::Set(FabricMsgSet {
                              cookie: cookie,
                              vnode: vnode,
                              key: key.into(),
                              container: dcc.clone(),
                          }))
            .unwrap();
    }

    pub fn set_handler(&self, from: &net::SocketAddr, msg: FabricMsgSet) {
        unimplemented!()
    }

    pub fn set_ack_handler(&self, from: &net::SocketAddr, msg: FabricMsgSetAck) {
        unimplemented!()
    }

    pub fn set_remote_handler(&self, from: &net::SocketAddr, msg: FabricMsgSet) {
        self.vnodes
            .read()
            .unwrap()
            .get(&msg.vnode)
            .map(move |vn| {
                vn.lock().unwrap().set_remote(self, hash(from), &msg.key, msg.container)
            });
    }

    pub fn set_remote_ack_handler(&self, _from: &net::SocketAddr, msg: FabricMsgSetAck) {
        self.set_callback(msg.cookie);
    }

    fn inflight(&self, cookie: u64) -> Option<ReqState> {
        self.inflight.lock().unwrap().remove(&cookie)
    }
}

impl VNodePeer {
    fn new() -> VNodePeer {
        VNodePeer {
            knowledge: 0,
            log: Default::default(),
        }
    }

    fn advance_knowledge(&mut self, until: u64) {
        debug_assert!(until > self.knowledge);
        self.knowledge = until;
    }

    fn log(&mut self, dot: u64, key: Vec<u8>) {
        let prev = self.log.insert(dot, key);
        debug_assert!(prev.is_none());
        while self.log.len() > PEER_LOG_SIZE {
            let min = self.log.keys().next().cloned().unwrap();
            self.log.remove(&min).unwrap();
        }
    }
}

impl VNode {
    fn new(num: u16) -> VNode {
        use std::path::Path;
        VNode {
            num: num,
            clock: BitmappedVersionVector::new(),
            peers: Default::default(),
            storage: Storage::open(Path::new("./vnode_t"), num as i32, true).unwrap(),
            log: Default::default(),
        }
    }

    fn get(&self, _db: &Database, key: &[u8]) -> DottedCausalContainer<Vec<u8>> {
        let mut dcc = if let Some(bytes) = self.storage.get_vec(key) {
            bincode_serde::deserialize(&bytes).unwrap()
        } else {
            DottedCausalContainer::new()
        };
        dcc.fill(&self.clock);
        dcc
    }

    fn set_local(&mut self, db: &Database, id: u64, key: &[u8], value_opt: Option<&[u8]>,
                 vv: &VersionVector)
                 -> DottedCausalContainer<Vec<u8>> {
        let mut dcc = self.get(db, key);
        dcc.discard(vv);
        let dot = self.clock.event(id);
        if let Some(value) = value_opt {
            dcc.add(id, dot, value.into());
        }
        dcc.strip(&self.clock);

        if dcc.is_empty() {
            self.storage.del(key);
        } else {
            let mut bytes = Vec::new();
            bincode_serde::serialize_into(&mut bytes, &dcc, bincode::SizeLimit::Infinite).unwrap();
            self.storage.set(key, &bytes);
        }

        self.log.insert(dot, key.into());
        dcc
    }

    fn set_remote(&mut self, db: &Database, peer_id: u64, key: &[u8],
                  mut new_dcc: DottedCausalContainer<Vec<u8>>) {
        let old_dcc = self.get(db, key);
        new_dcc.add_to_bvv(&mut self.clock);
        new_dcc.sync(old_dcc);
        new_dcc.strip(&self.clock);

        if new_dcc.is_empty() {
            self.storage.del(key);
        } else {
            let mut bytes = Vec::new();
            bincode_serde::serialize_into(&mut bytes, &new_dcc, bincode::SizeLimit::Infinite)
                .unwrap();
            self.storage.set(key, &bytes);
        }

        self.peers
            .entry(peer_id)
            .or_insert_with(|| VNodePeer::new())
            .log(self.clock.get(peer_id).unwrap().base(), key.into());
    }
}

// boilerplate
fn register_handlers(db: Arc<Database>) {
    // FIXME: these create a circular ref :/
    let cdb = db.clone();
    db.fabric.register_msg_handler(FabricMsgType::Get,
                                   Box::new(move |f, m| {
                                       cdb.get_remote_handler(&f, fmsg!(m, FabricMsg::Get))
                                   }));
    let cdb = db.clone();
    db.fabric.register_msg_handler(FabricMsgType::GetAck,
                                   Box::new(move |f, m| {
                                       cdb.get_remote_ack_handler(&f, fmsg!(m, FabricMsg::GetAck))
                                   }));
    let cdb = db.clone();
    db.fabric.register_msg_handler(FabricMsgType::Set,
                                   Box::new(move |f, m| {
                                       cdb.set_handler(&f, fmsg!(m, FabricMsg::Set))
                                   }));
    let cdb = db.clone();
    db.fabric.register_msg_handler(FabricMsgType::SetAck,
                                   Box::new(move |f, m| {
                                       cdb.set_ack_handler(&f, fmsg!(m, FabricMsg::SetAck))
                                   }));
    let cdb = db.clone();
    db.fabric.register_msg_handler(FabricMsgType::SetRemote,
                                   Box::new(move |f, m| {
                                       cdb.set_remote_handler(&f, fmsg!(m, FabricMsg::Set))
                                   }));
    let cdb = db.clone();
    db.fabric.register_msg_handler(FabricMsgType::SetRemoteAck,
                                   Box::new(move |f, m| {
                                       cdb.set_remote_ack_handler(&f, fmsg!(m, FabricMsg::SetAck))
                                   }));
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs;
    use env_logger;
    use version_vector::VersionVector;

    #[test]
    fn test() {
        let _ = fs::remove_dir_all("./vnode_t");
        let _ = env_logger::init();
        let db = Database::new("127.0.0.1:9000".parse().unwrap());
        for i in 0u16..64 {
            db.init_vnode(i);
        }
        db.get(1, b"test");
        assert!(db.inflight(1).unwrap().container.is_empty());

        db.set(1, b"test", Some(b"value1"), VersionVector::new());
        assert!(db.inflight(1).unwrap().container.is_empty());

        db.get(1, b"test");
        assert!(db.inflight(1).unwrap().container.values().eq(vec![b"value1"]));

        db.set(1, b"test", Some(b"value2"), VersionVector::new());
        assert!(db.inflight(1).unwrap().container.is_empty());

        db.get(1, b"test");
        let state = db.inflight(1).unwrap();
        assert!(state.container.values().eq(vec![b"value1", b"value2"]));

        db.set(1,
               b"test",
               Some(b"value12"),
               state.container.version_vector().clone());
        assert!(db.inflight(1).unwrap().container.is_empty());

        db.get(1, b"test");
        let state = db.inflight(1).unwrap();
        assert!(state.container.values().eq(vec![b"value12"]));

        db.set(1, b"test", None, state.container.version_vector().clone());
        assert!(db.inflight(1).unwrap().container.is_empty());

        db.get(1, b"test");
        assert!(db.inflight(1).unwrap().container.is_empty());
    }
}
<commit_msg>proxy set commands<commit_after>use std::net;
use std::path::Path;
use std::collections::{HashMap, BTreeMap};
use std::sync::{Arc, Mutex, RwLock};
use bincode::{self, serde as bincode_serde};
use linear_map::LinearMap;
use dht::DHT;
use hash::hash;
use version_vector::*;
use storage::Storage;
use fabric::Fabric;
use fabric_msg::*;
use rand::{Rng, thread_rng};

const PEER_LOG_SIZE: usize = 1000;

pub struct ReqState {
    replies: usize,
    required: usize,
    total: usize,
    from: net::SocketAddr,
    // only used for get
    container: DottedCausalContainer<Vec<u8>>,
}

pub struct Database {
    dht: DHT<()>,
    fabric: Fabric,
    vnodes: RwLock<HashMap<u16, Mutex<VNode>>>,
    replication_factor: usize,
    //TODO: move this inside vnode?
    //TODO: create a thread to walk inflight and handle timeouts
    inflight: Mutex<HashMap<u64, ReqState>>,
}

struct VNodePeer {
    knowledge: u64,
    log: BTreeMap<u64, Vec<u8>>,
}

struct VNode {
    num: u16,
    clock: BitmappedVersionVector,
    log: BTreeMap<u64, Vec<u8>>,
    peers: LinearMap<u64, VNodePeer>,
    storage: Storage,
}

impl Database {
    pub fn new(node: net::SocketAddr) -> Arc<Database> {
        let db = Arc::new(Database {
            replication_factor: 3,
            fabric: Fabric::new(node).unwrap(),
            dht: DHT::new(node, (), 64),
            inflight: Mutex::new(Default::default()),
            vnodes: RwLock::new(Default::default()),
        });
        register_handlers(db.clone());
        db
    }

    pub fn init_vnode(&self, vnode_n: u16) {
        self.vnodes
            .write()
            .unwrap()
            .entry(vnode_n)
            .or_insert_with(|| Mutex::new(VNode::new(vnode_n)));
    }

    pub fn remove_vnode(&self, vnode_n: u16) {
        self.vnodes.write().unwrap().remove(&vnode_n);
    }

    fn new_state_from(&self, token: usize, from: net::SocketAddr) -> u64 {
        let cookie = token as u64;
        let _a = self.inflight
            .lock()
            .unwrap()
            .insert(cookie,
                    ReqState {
                        from: from,
                        required: self.replication_factor / 2 + 1,
                        total: self.replication_factor,
                        replies: 0,
                        container: DottedCausalContainer::new(),
                    });
        debug_assert!(_a.is_none());
        cookie
    }

    fn new_state(&self, token: usize) -> u64 {
        self.new_state_from(token, self.dht.node())
    }

    pub fn get(&self, token: usize, key: &[u8]) {
        let vnode_n = self.dht.key_vnode(key);
        let nodes = self.dht.nodes_for_key(key, self.replication_factor);
        let cookie = self.new_state(token);

        for node in nodes {
            if node == self.dht.node() {
                self.get_local(cookie, key);
            } else {
                self.send_get_remote(&node, vnode_n, cookie, key);
            }
        }
    }

    fn get_callback(&self, cookie: u64, container: Option<DottedCausalContainer<Vec<u8>>>) {
        let mut inflight = self.inflight.lock().unwrap();
        if {
            let state = inflight.get_mut(&cookie).unwrap();
            container.map(|dcc| state.container.sync(dcc));
            state.replies += 1;
            if state.replies == state.required {
                // return to client
            }
            if state.replies == state.total {
                // remove state
                true
            } else {
                false
            }
        } {
            inflight.remove(&cookie).unwrap();
        }
    }

    fn get_local(&self, cookie: u64, key: &[u8]) {
        let vnode_n = self.dht.key_vnode(key);
        let container = self.vnodes
            .read()
            .unwrap()
            .get(&vnode_n)
            .map(|vn| vn.lock().unwrap().get(self, key));
        self.get_callback(cookie, container);
    }

    fn send_get_remote(&self, addr: &net::SocketAddr, vnode: u16, cookie: u64, key: &[u8]) {
        self.fabric
            .send_message(addr,
                          FabricMsg::Get(FabricMsgGet {
                              cookie: cookie,
                              vnode: vnode,
                              key: key.into(),
                          }))
            .unwrap();
    }

    pub fn get_remote_handler(&self, from: &net::SocketAddr, msg: FabricMsgGet) {
        let container = self.vnodes
            .read()
            .unwrap()
            .get(&msg.vnode)
            .map(|vn| vn.lock().unwrap().get(self, &msg.key));
        self.fabric
            .send_message(&from,
                          FabricMsg::GetAck(FabricMsgGetAck {
                              cookie: msg.cookie,
                              vnode: msg.vnode,
                              container: container.unwrap(),
                          }))
            .unwrap();
    }

    pub fn get_remote_ack_handler(&self, _from: &net::SocketAddr, msg: FabricMsgGetAck) {
        self.get_callback(msg.cookie, Some(msg.container));
    }

    pub fn set(&self, token: usize, key: &[u8], value_opt: Option<&[u8]>, vv: VersionVector) {
        self.set_(self.dht.node(), token, key, value_opt, vv)
    }

    pub fn set_(&self, from: net::SocketAddr, token: usize, key: &[u8], value_opt: Option<&[u8]>,
                vv: VersionVector) {
        let vnode_n = self.dht.key_vnode(key);
        let nodes = self.dht.nodes_for_key(key, self.replication_factor);
        let cookie = self.new_state_from(token, from);

        if nodes.iter().position(|n| n == &self.dht.node()).is_none() {
            // forward if we can't coordinate it
            self.send_set(thread_rng().choose(&nodes).unwrap(),
                          vnode_n,
                          cookie,
                          key,
                          value_opt,
                          vv);
        } else {
            // otherwise proceed normally
            let dcc = self.set_local(cookie, key, value_opt, &vv);
            for node in nodes {
                if node != self.dht.node() {
                    self.send_set_remote(&node, vnode_n, cookie, key, dcc.clone());
                }
            }
        }
    }

    fn set_callback(&self, cookie: u64) {
        let mut inflight = self.inflight.lock().unwrap();
        if {
            let state = inflight.get_mut(&cookie).unwrap();
            state.replies += 1;
            if state.replies == state.required {
                if state.from == self.dht.node() {
                    // return to proxy
                } else {
                    // return to client
                }
            }
            if state.replies == state.total {
                // remove state
                true
            } else {
                false
            }
        } {
            inflight.remove(&cookie).unwrap();
        }
    }

    fn set_local(&self, cookie: u64, key: &[u8], value_opt: Option<&[u8]>, vv: &VersionVector)
                 -> DottedCausalContainer<Vec<u8>> {
        let vnode_n = self.dht.key_vnode(key);
        debug!("set_local {:?}", vnode_n);
        let dcc = self.vnodes
            .read()
            .unwrap()
            .get(&vnode_n)
            .map(|vn| {
                vn.lock().unwrap().set_local(self, hash(self.dht.node()), key, value_opt, vv)
            });
        self.set_callback(cookie);
        dcc.unwrap()
    }

    pub fn send_set(&self, addr: &net::SocketAddr, vnode: u16, cookie: u64, key: &[u8],
                    value_opt: Option<&[u8]>, vv: VersionVector) {
        self.fabric
            .send_message(addr,
                          FabricMsg::Set(FabricMsgSet {
                              cookie: cookie,
                              vnode: vnode,
                              key: key.into(),
                              value: value_opt.map(|x| x.into()),
                              version_vector: vv,
                          }))
            .unwrap();
    }

    pub fn send_set_remote(&self, addr: &net::SocketAddr, vnode: u16, cookie: u64, key: &[u8],
                           dcc: DottedCausalContainer<Vec<u8>>) {
        self.fabric
            .send_message(addr,
                          FabricMsg::SetRemote(FabricMsgSetRemote {
                              cookie: cookie,
                              vnode: vnode,
                              key: key.into(),
                              container: dcc.clone(),
                          }))
            .unwrap();
    }

    pub fn set_handler(&self, from: &net::SocketAddr, msg: FabricMsgSet) {
        unimplemented!()
    }

    pub fn set_ack_handler(&self, from: &net::SocketAddr, msg: FabricMsgSetAck) {
        unimplemented!()
    }

    pub fn set_remote_handler(&self, from: &net::SocketAddr, msg: FabricMsgSetRemote) {
        self.vnodes
            .read()
            .unwrap()
            .get(&msg.vnode)
            .map(move |vn| {
                vn.lock().unwrap().set_remote(self, hash(from), &msg.key, msg.container)
            });
    }

    pub fn set_remote_ack_handler(&self, _from: &net::SocketAddr, msg: FabricMsgSetRemoteAck) {
        self.set_callback(msg.cookie);
    }

    fn inflight(&self, cookie: u64) -> Option<ReqState> {
        self.inflight.lock().unwrap().remove(&cookie)
    }
}

impl VNodePeer {
    fn new() -> VNodePeer {
        VNodePeer {
            knowledge: 0,
            log: Default::default(),
        }
    }

    fn advance_knowledge(&mut self, until: u64) {
        debug_assert!(until > self.knowledge);
        self.knowledge = until;
    }

    fn log(&mut self, dot: u64, key: Vec<u8>) {
        let prev = self.log.insert(dot, key);
        debug_assert!(prev.is_none());
        while self.log.len() > PEER_LOG_SIZE {
            let min = self.log.keys().next().cloned().unwrap();
            self.log.remove(&min).unwrap();
        }
    }
}

impl VNode {
    fn new(num: u16) -> VNode {
        VNode {
            num: num,
            clock: BitmappedVersionVector::new(),
            peers: Default::default(),
            storage: Storage::open(Path::new("./vnode_t"), num as i32, true).unwrap(),
            log: Default::default(),
        }
    }

    fn get(&self, _db: &Database, key: &[u8]) -> DottedCausalContainer<Vec<u8>> {
        let mut dcc = if let Some(bytes) = self.storage.get_vec(key) {
            bincode_serde::deserialize(&bytes).unwrap()
        } else {
            DottedCausalContainer::new()
        };
        dcc.fill(&self.clock);
        dcc
    }

    fn set_local(&mut self, db: &Database, id: u64, key: &[u8], value_opt: Option<&[u8]>,
                 vv: &VersionVector)
                 -> DottedCausalContainer<Vec<u8>> {
        let mut dcc = self.get(db, key);
        dcc.discard(vv);
        let dot = self.clock.event(id);
        if let Some(value) = value_opt {
            dcc.add(id, dot, value.into());
        }
        dcc.strip(&self.clock);

        if dcc.is_empty() {
            self.storage.del(key);
        } else {
            let mut bytes = Vec::new();
            bincode_serde::serialize_into(&mut bytes, &dcc, bincode::SizeLimit::Infinite).unwrap();
            self.storage.set(key, &bytes);
        }

        self.log.insert(dot, key.into());
        dcc
    }

    fn set_remote(&mut self, db: &Database, peer_id: u64, key: &[u8],
                  mut new_dcc: DottedCausalContainer<Vec<u8>>) {
        let old_dcc = self.get(db, key);
        new_dcc.add_to_bvv(&mut self.clock);
        new_dcc.sync(old_dcc);
        new_dcc.strip(&self.clock);

        if new_dcc.is_empty() {
            self.storage.del(key);
        } else {
            let mut bytes = Vec::new();
            bincode_serde::serialize_into(&mut bytes, &new_dcc, bincode::SizeLimit::Infinite)
                .unwrap();
            self.storage.set(key, &bytes);
        }

        self.peers
            .entry(peer_id)
            .or_insert_with(|| VNodePeer::new())
            .log(self.clock.get(peer_id).unwrap().base(), key.into());
    }
}

// boilerplate
fn register_handlers(db: Arc<Database>) {
    // FIXME: these create a circular ref :/
    let cdb = db.clone();
    db.fabric.register_msg_handler(FabricMsgType::Get,
                                   Box::new(move |f, m| {
                                       cdb.get_remote_handler(&f, fmsg!(m, FabricMsg::Get))
                                   }));
    let cdb = db.clone();
    db.fabric.register_msg_handler(FabricMsgType::GetAck,
                                   Box::new(move |f, m| {
                                       cdb.get_remote_ack_handler(&f, fmsg!(m, FabricMsg::GetAck))
                                   }));
    let cdb = db.clone();
    db.fabric.register_msg_handler(FabricMsgType::Set,
                                   Box::new(move |f, m| {
                                       cdb.set_handler(&f, fmsg!(m, FabricMsg::Set))
                                   }));
    let cdb = db.clone();
    db.fabric.register_msg_handler(FabricMsgType::SetAck,
                                   Box::new(move |f, m| {
                                       cdb.set_ack_handler(&f, fmsg!(m, FabricMsg::SetAck))
                                   }));
    let cdb = db.clone();
    db.fabric.register_msg_handler(FabricMsgType::SetRemote,
                                   Box::new(move |f, m| {
                                       cdb.set_remote_handler(&f, fmsg!(m, FabricMsg::SetRemote))
                                   }));
    let cdb = db.clone();
    db.fabric.register_msg_handler(FabricMsgType::SetRemoteAck,
                                   Box::new(move |f, m| {
                                       cdb.set_remote_ack_handler(&f,
                                                                  fmsg!(m, FabricMsg::SetRemoteAck))
                                   }));
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs;
    use env_logger;
    use version_vector::VersionVector;

    #[test]
    fn test() {
        let _ = fs::remove_dir_all("./vnode_t");
        let _ = env_logger::init();
        let db = Database::new("127.0.0.1:9000".parse().unwrap());
        for i in 0u16..64 {
            db.init_vnode(i);
        }
        db.get(1, b"test");
        assert!(db.inflight(1).unwrap().container.is_empty());

        db.set(1, b"test", Some(b"value1"), VersionVector::new());
        assert!(db.inflight(1).unwrap().container.is_empty());

        db.get(1, b"test");
        assert!(db.inflight(1).unwrap().container.values().eq(vec![b"value1"]));

        db.set(1, b"test", Some(b"value2"), VersionVector::new());
        assert!(db.inflight(1).unwrap().container.is_empty());

        db.get(1, b"test");
        let state = db.inflight(1).unwrap();
        assert!(state.container.values().eq(vec![b"value1", b"value2"]));

        db.set(1,
               b"test",
               Some(b"value12"),
               state.container.version_vector().clone());
        assert!(db.inflight(1).unwrap().container.is_empty());

        db.get(1, b"test");
        let state = db.inflight(1).unwrap();
        assert!(state.container.values().eq(vec![b"value12"]));

        db.set(1, b"test", None, state.container.version_vector().clone());
        assert!(db.inflight(1).unwrap().container.is_empty());

        db.get(1, b"test");
        assert!(db.inflight(1).unwrap().container.is_empty());
    }
}
<|endoftext|>