<commit_before>//! Random number generation

export Rng, seed, seeded_rng, Weighted, extensions;
export xorshift, seeded_xorshift;

#[allow(non_camel_case_types)] // runtime type
enum rctx {}

#[abi = "cdecl"]
extern 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);
}

/// A random number generator
trait Rng {
    /// Return the next random integer
    fn next() -> u32;
}

/// A value with a particular weight compared to other values
type Weighted<T> = { weight: uint, item: T };

/// Extension methods for random number generators
impl Rng {

    /// Return a random int
    fn gen_int() -> int {
        self.gen_i64() as int
    }

    /**
     * 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))
    }

    /// Return a random i8
    fn gen_i8() -> i8 {
        self.next() as i8
    }

    /// Return a random i16
    fn gen_i16() -> i16 {
        self.next() as i16
    }

    /// Return a random i32
    fn gen_i32() -> i32 {
        self.next() as i32
    }

    /// Return a random i64
    fn gen_i64() -> i64 {
        (self.next() as i64 << 32) | self.next() as i64
    }

    /// Return a random uint
    fn gen_uint() -> uint {
        self.gen_u64() as uint
    }

    /**
     * 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))
    }

    /// Return a random u8
    fn gen_u8() -> u8 {
        self.next() as u8
    }

    /// Return a random u16
    fn gen_u16() -> u16 {
        self.next() as u16
    }

    /// Return a random u32
    fn gen_u32() -> u32 {
        self.next()
    }

    /// Return a random u64
    fn gen_u64() -> u64 {
        (self.next() as u64 << 32) | self.next() as u64
    }

    /// Return a random float in the interval [0,1]
    fn gen_float() -> float {
        self.gen_f64() as float
    }

    /// Return a random f32 in the interval [0,1]
    fn gen_f32() -> f32 {
        self.gen_f64() as f32
    }

    /// Return a random f64 in the interval [0,1]
    fn gen_f64() -> f64 {
        let u1 = self.next() as f64;
        let u2 = self.next() as f64;
        let u3 = self.next() as f64;
        const scale : f64 = (u32::max_value as f64) + 1.0f64;
        return ((u1 / scale + u2) / scale + u3) / scale;
    }

    /// Return a random char
    fn gen_char() -> char {
        self.next() as char
    }

    /**
     * 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))
    }

    /// Return a random bool
    fn gen_bool() -> bool {
        self.next() & 1u32 == 1u32
    }

    /// 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
        }
    }

    /**
     * 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
    }

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

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

    /// 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())])
        }
    }

    /**
     * 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()
    }

    /**
     * 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 {
            return 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 {
                return Some(item.item);
            }
        }
        unreachable();
    }

    /**
     * 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| {
            for uint::range(0u, item.weight) |_i| {
                vec::push(r, item.item);
            }
        }
        r
    }

    /// Shuffle a vec
    fn shuffle<T:copy>(values: &[T]) -> ~[T] {
        let mut m = vec::from_slice(values);
        self.shuffle_mut(m);
        return m;
    }

    /// 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));
        }
    }

}

struct RandRes {
    c: *rctx,
    drop { rustrt::rand_free(self.c); }
}

fn RandRes(c: *rctx) -> RandRes {
    RandRes {
        c: c
    }
}

impl @RandRes: Rng {
    fn next() -> u32 { return rustrt::rand_next((*self).c); }
}

/// Create a new random seed for seeded_rng
fn seed() -> ~[u8] {
    rustrt::rand_seed()
}

/// Create a random number generator with a system specified seed
fn Rng() -> Rng {
    @RandRes(rustrt::rand_new()) as Rng
}

/**
 * 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 {
    @RandRes(rustrt::rand_new_seeded(seed)) as Rng
}

type XorShiftState = {
    mut x: u32,
    mut y: u32,
    mut z: u32,
    mut w: u32
};

impl XorShiftState: Rng {
    fn next() -> u32 {
        let x = self.x;
        let mut t = x ^ (x << 11);
        self.x = self.y;
        self.y = self.z;
        self.z = self.w;
        let w = self.w;
        self.w = w ^ (w >> 19) ^ (t ^ (t >> 8));
        self.w
    }
}

fn xorshift() -> Rng {
    // constants taken from http://en.wikipedia.org/wiki/Xorshift
    seeded_xorshift(123456789u32, 362436069u32, 521288629u32, 88675123u32)
}

fn seeded_xorshift(x: u32, y: u32, z: u32, w: u32) -> Rng {
    {mut x: x, mut y: y, mut z: z, mut w: w} 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 rng_seeded_custom_seed2() {
        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        // Regression test that isaac is actually using the above vector
        let r = ra.next();
        error!("%?", r);
        assert r == 890007737u32 // on x86_64
            || r == 2935188040u32; // on x86
    }

    #[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(windows))]
    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(windows))]
    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();
        let x: Option<int> = r.choose_option([]);
        assert x.is_none();
        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);
        let v: Option<int> = r.choose_weighted_option([]);
        assert v.is_none();
    }

    #[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>Convert all kind bounds to camel case. Remove send, owned keywords.<commit_after>//! Random number generation

export Rng, seed, seeded_rng, Weighted, extensions;
export xorshift, seeded_xorshift;

#[allow(non_camel_case_types)] // runtime type
enum rctx {}

#[abi = "cdecl"]
extern 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);
}

/// A random number generator
trait Rng {
    /// Return the next random integer
    fn next() -> u32;
}

/// A value with a particular weight compared to other values
type Weighted<T> = { weight: uint, item: T };

/// Extension methods for random number generators
impl Rng {

    /// Return a random int
    fn gen_int() -> int {
        self.gen_i64() as int
    }

    /**
     * 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))
    }

    /// Return a random i8
    fn gen_i8() -> i8 {
        self.next() as i8
    }

    /// Return a random i16
    fn gen_i16() -> i16 {
        self.next() as i16
    }

    /// Return a random i32
    fn gen_i32() -> i32 {
        self.next() as i32
    }

    /// Return a random i64
    fn gen_i64() -> i64 {
        (self.next() as i64 << 32) | self.next() as i64
    }

    /// Return a random uint
    fn gen_uint() -> uint {
        self.gen_u64() as uint
    }

    /**
     * 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))
    }

    /// Return a random u8
    fn gen_u8() -> u8 {
        self.next() as u8
    }

    /// Return a random u16
    fn gen_u16() -> u16 {
        self.next() as u16
    }

    /// Return a random u32
    fn gen_u32() -> u32 {
        self.next()
    }

    /// Return a random u64
    fn gen_u64() -> u64 {
        (self.next() as u64 << 32) | self.next() as u64
    }

    /// Return a random float in the interval [0,1]
    fn gen_float() -> float {
        self.gen_f64() as float
    }

    /// Return a random f32 in the interval [0,1]
    fn gen_f32() -> f32 {
        self.gen_f64() as f32
    }

    /// Return a random f64 in the interval [0,1]
    fn gen_f64() -> f64 {
        let u1 = self.next() as f64;
        let u2 = self.next() as f64;
        let u3 = self.next() as f64;
        const scale : f64 = (u32::max_value as f64) + 1.0f64;
        return ((u1 / scale + u2) / scale + u3) / scale;
    }

    /// Return a random char
    fn gen_char() -> char {
        self.next() as char
    }

    /**
     * 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))
    }

    /// Return a random bool
    fn gen_bool() -> bool {
        self.next() & 1u32 == 1u32
    }

    /// 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
        }
    }

    /**
     * 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
    }

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

    /// Choose an item randomly, failing if values is empty
    fn choose<T:Copy>(values: &[T]) -> T {
        self.choose_option(values).get()
    }

    /// 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())])
        }
    }

    /**
     * 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()
    }

    /**
     * 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 {
            return 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 {
                return Some(item.item);
            }
        }
        unreachable();
    }

    /**
     * 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| {
            for uint::range(0u, item.weight) |_i| {
                vec::push(r, item.item);
            }
        }
        r
    }

    /// Shuffle a vec
    fn shuffle<T:Copy>(values: &[T]) -> ~[T] {
        let mut m = vec::from_slice(values);
        self.shuffle_mut(m);
        return m;
    }

    /// 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));
        }
    }

}

struct RandRes {
    c: *rctx,
    drop { rustrt::rand_free(self.c); }
}

fn RandRes(c: *rctx) -> RandRes {
    RandRes {
        c: c
    }
}

impl @RandRes: Rng {
    fn next() -> u32 { return rustrt::rand_next((*self).c); }
}

/// Create a new random seed for seeded_rng
fn seed() -> ~[u8] {
    rustrt::rand_seed()
}

/// Create a random number generator with a system specified seed
fn Rng() -> Rng {
    @RandRes(rustrt::rand_new()) as Rng
}

/**
 * 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 {
    @RandRes(rustrt::rand_new_seeded(seed)) as Rng
}

type XorShiftState = {
    mut x: u32,
    mut y: u32,
    mut z: u32,
    mut w: u32
};

impl XorShiftState: Rng {
    fn next() -> u32 {
        let x = self.x;
        let mut t = x ^ (x << 11);
        self.x = self.y;
        self.y = self.z;
        self.z = self.w;
        let w = self.w;
        self.w = w ^ (w >> 19) ^ (t ^ (t >> 8));
        self.w
    }
}

fn xorshift() -> Rng {
    // constants taken from http://en.wikipedia.org/wiki/Xorshift
    seeded_xorshift(123456789u32, 362436069u32, 521288629u32, 88675123u32)
}

fn seeded_xorshift(x: u32, y: u32, z: u32, w: u32) -> Rng {
    {mut x: x, mut y: y, mut z: z, mut w: w} 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 rng_seeded_custom_seed2() {
        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        // Regression test that isaac is actually using the above vector
        let r = ra.next();
        error!("%?", r);
        assert r == 890007737u32 // on x86_64
            || r == 2935188040u32; // on x86
    }

    #[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(windows))]
    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(windows))]
    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();
        let x: Option<int> = r.choose_option([]);
        assert x.is_none();
        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);
        let v: Option<int> = r.choose_weighted_option([]);
        assert v.is_none();
    }

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

// rust - central access to other rust tools
// FIXME #2238 Make commands run and test emit proper file endings on windows
// FIXME #2238 Make run only accept source that emits an executable

#[link(name = "rust",
       vers = "0.8-pre",
       uuid = "4a24da33-5cc8-4037-9352-2cbe9bd9d27c",
       url = "https://github.com/mozilla/rust/tree/master/src/rust")];

#[license = "MIT/ASL2"];
#[crate_type = "lib"];

extern mod rustpkg;
extern mod rustdoc;
extern mod rusti;
extern mod rustc;

use std::io;
use std::os;
use std::run;
use std::libc::exit;

enum ValidUsage {
    Valid(int), Invalid
}

impl ValidUsage {
    fn is_valid(&self) -> bool {
        match *self {
            Valid(_)   => true,
            Invalid    => false
        }
    }
}

enum Action {
    Call(extern "Rust" fn(args: &[~str]) -> ValidUsage),
    CallMain(&'static str, extern "Rust" fn(&[~str])),
}

enum UsageSource<'self> {
    UsgStr(&'self str),
    UsgCall(extern "Rust" fn()),
}

struct Command<'self> {
    cmd: &'self str,
    action: Action,
    usage_line: &'self str,
    usage_full: UsageSource<'self>,
}

static COMMANDS: &'static [Command<'static>] = &'static [
    Command {
        cmd: "build",
        action: CallMain("rustc", rustc::main_args),
        usage_line: "compile rust source files",
        usage_full: UsgCall(rustc_help),
    },
    Command {
        cmd: "run",
        action: Call(cmd_run),
        usage_line: "build an executable, and run it",
        usage_full: UsgStr(
            "The run command is an shortcut for the command line \n\
             \"rustc <filename> -o <filestem>~ && ./<filestem>~ [<arguments>...]\".\
            \n\nUsage:\trust run <filename> [<arguments>...]"
        )
    },
    Command {
        cmd: "test",
        action: Call(cmd_test),
        usage_line: "build a test executable, and run it",
        usage_full: UsgStr(
            "The test command is an shortcut for the command line \n\
            \"rustc --test <filename> -o <filestem>test~ && \
            ./<filestem>test~\"\n\nUsage:\trust test <filename>"
        )
    },
    Command {
        cmd: "doc",
        action: CallMain("rustdoc", rustdoc::main_args),
        usage_line: "generate documentation from doc comments",
        usage_full: UsgCall(rustdoc::config::usage),
    },
    Command {
        cmd: "pkg",
        action: CallMain("rustpkg", rustpkg::main_args),
        usage_line: "download, build, install rust packages",
        usage_full: UsgCall(rustpkg::usage::general),
    },
    Command {
        cmd: "sketch",
        action: CallMain("rusti", rusti::main_args),
        usage_line: "run a rust interpreter",
        usage_full: UsgStr("\nUsage:\trusti"),
    },
    Command {
        cmd: "help",
        action: Call(cmd_help),
        usage_line: "show detailed usage of a command",
        usage_full: UsgStr(
            "The help command displays the usage text of another command.\n\
            The text is either build in, or provided by the corresponding \
            program.\n\nUsage:\trust help <command>"
        )
    }
];

fn rustc_help() {
    rustc::usage(os::args()[0].clone())
}

fn find_cmd(command_string: &str) -> Option<Command> {
    do COMMANDS.iter().find |command| {
        command.cmd == command_string
    }.map_move(|x| *x)
}

fn cmd_help(args: &[~str]) -> ValidUsage {
    fn print_usage(command_string: ~str) -> ValidUsage {
        match find_cmd(command_string) {
            Some(command) => {
                match command.action {
                    CallMain(prog, _) => printfln!(
                        "The %s command is an alias for the %s program.",
                        command.cmd, prog),
                    _       => ()
                }
                match command.usage_full {
                    UsgStr(msg) => printfln!("%s\n", msg),
                    UsgCall(f)  => f(),
                }
                Valid(0)
            },
            None => Invalid
        }
    }

    match args {
        [ref command_string] => print_usage((*command_string).clone()),
        _                    => Invalid
    }
}

fn cmd_test(args: &[~str]) -> ValidUsage {
    match args {
        [ref filename] => {
            let p = Path(*filename);
            let test_exec = p.filestem().unwrap() + "test~";
            invoke("rustc", &[~"--test", filename.to_owned(),
                              ~"-o", test_exec.to_owned()], rustc::main_args);
            let exit_code = run::process_status(~"./" + test_exec, []);
            Valid(exit_code)
        }
        _ => Invalid
    }
}

fn cmd_run(args: &[~str]) -> ValidUsage {
    match args {
        [ref filename, ..prog_args] => {
            let p = Path(*filename);
            let exec = p.filestem().unwrap() + "~";
            invoke("rustc", &[filename.to_owned(), ~"-o", exec.to_owned()],
                   rustc::main_args);
            let exit_code = run::process_status(~"./"+exec, prog_args);
            Valid(exit_code)
        }
        _ => Invalid
    }
}

fn invoke(prog: &str, args: &[~str], f: &fn(&[~str])) {
    let mut osargs = ~[prog.to_owned()];
    osargs.push_all_move(args.to_owned());
    f(osargs);
}

fn do_command(command: &Command, args: &[~str]) -> ValidUsage {
    match command.action {
        Call(f) => f(args),
        CallMain(prog, f) => {
            invoke(prog, args, f);
            Valid(0)
        }
    }
}

fn usage() {
    static INDENT: uint = 8;

    io::print(
        "The rust tool is a convenience for managing rust source code.\n\
        It acts as a shortcut for programs of the rust tool chain.\n\
        \n\
        Usage:\trust <command> [arguments]\n\
        \n\
        The commands are:\n\
        \n"
    );

    for command in COMMANDS.iter() {
        let padding = " ".repeat(INDENT - command.cmd.len());
        printfln!("    %s%s%s", command.cmd, padding, command.usage_line);
    }

    io::print(
        "\n\
        Use \"rust help <command>\" for more information about a command.\n\
        \n"
    );

}

pub fn main() {
    #[fixed_stack_segment]; #[inline(never)];

    let os_args = os::args();

    if (os_args.len() > 1 && (os_args[1] == ~"-v" || os_args[1] == ~"--version")) {
        rustc::version(os_args[0]);
        unsafe { exit(0); }
    }

    let args = os_args.tail();

    if !args.is_empty() {
        let r = find_cmd(*args.head());
        for command in r.iter() {
            let result = do_command(command, args.tail());
            match result {
                Valid(exit_code) => unsafe { exit(exit_code.to_i32()) },
                _                => loop
            }
        }
    }

    usage();
}
<commit_msg>rust test: pass the remaining arguments through<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// rust - central access to other rust tools
// FIXME #2238 Make commands run and test emit proper file endings on windows
// FIXME #2238 Make run only accept source that emits an executable

#[link(name = "rust",
       vers = "0.8-pre",
       uuid = "4a24da33-5cc8-4037-9352-2cbe9bd9d27c",
       url = "https://github.com/mozilla/rust/tree/master/src/rust")];

#[license = "MIT/ASL2"];
#[crate_type = "lib"];

extern mod rustpkg;
extern mod rustdoc;
extern mod rusti;
extern mod rustc;

use std::io;
use std::os;
use std::run;
use std::libc::exit;

enum ValidUsage {
    Valid(int), Invalid
}

impl ValidUsage {
    fn is_valid(&self) -> bool {
        match *self {
            Valid(_)   => true,
            Invalid    => false
        }
    }
}

enum Action {
    Call(extern "Rust" fn(args: &[~str]) -> ValidUsage),
    CallMain(&'static str, extern "Rust" fn(&[~str])),
}

enum UsageSource<'self> {
    UsgStr(&'self str),
    UsgCall(extern "Rust" fn()),
}

struct Command<'self> {
    cmd: &'self str,
    action: Action,
    usage_line: &'self str,
    usage_full: UsageSource<'self>,
}

static COMMANDS: &'static [Command<'static>] = &'static [
    Command {
        cmd: "build",
        action: CallMain("rustc", rustc::main_args),
        usage_line: "compile rust source files",
        usage_full: UsgCall(rustc_help),
    },
    Command {
        cmd: "run",
        action: Call(cmd_run),
        usage_line: "build an executable, and run it",
        usage_full: UsgStr(
            "The run command is an shortcut for the command line \n\
             \"rustc <filename> -o <filestem>~ && ./<filestem>~ [<arguments>...]\".\
            \n\nUsage:\trust run <filename> [<arguments>...]"
        )
    },
    Command {
        cmd: "test",
        action: Call(cmd_test),
        usage_line: "build a test executable, and run it",
        usage_full: UsgStr(
            "The test command is an shortcut for the command line \n\
            \"rustc --test <filename> -o <filestem>test~ && \
            ./<filestem>test~ [<arguments>...]\"\
            \n\nUsage:\trust test <filename> [<arguments>...]"
        )
    },
    Command {
        cmd: "doc",
        action: CallMain("rustdoc", rustdoc::main_args),
        usage_line: "generate documentation from doc comments",
        usage_full: UsgCall(rustdoc::config::usage),
    },
    Command {
        cmd: "pkg",
        action: CallMain("rustpkg", rustpkg::main_args),
        usage_line: "download, build, install rust packages",
        usage_full: UsgCall(rustpkg::usage::general),
    },
    Command {
        cmd: "sketch",
        action: CallMain("rusti", rusti::main_args),
        usage_line: "run a rust interpreter",
        usage_full: UsgStr("\nUsage:\trusti"),
    },
    Command {
        cmd: "help",
        action: Call(cmd_help),
        usage_line: "show detailed usage of a command",
        usage_full: UsgStr(
            "The help command displays the usage text of another command.\n\
            The text is either build in, or provided by the corresponding \
            program.\n\nUsage:\trust help <command>"
        )
    }
];

fn rustc_help() {
    rustc::usage(os::args()[0].clone())
}

fn find_cmd(command_string: &str) -> Option<Command> {
    do COMMANDS.iter().find |command| {
        command.cmd == command_string
    }.map_move(|x| *x)
}

fn cmd_help(args: &[~str]) -> ValidUsage {
    fn print_usage(command_string: ~str) -> ValidUsage {
        match find_cmd(command_string) {
            Some(command) => {
                match command.action {
                    CallMain(prog, _) => printfln!(
                        "The %s command is an alias for the %s program.",
                        command.cmd, prog),
                    _       => ()
                }
                match command.usage_full {
                    UsgStr(msg) => printfln!("%s\n", msg),
                    UsgCall(f)  => f(),
                }
                Valid(0)
            },
            None => Invalid
        }
    }

    match args {
        [ref command_string] => print_usage((*command_string).clone()),
        _                    => Invalid
    }
}

fn cmd_test(args: &[~str]) -> ValidUsage {
    match args {
        [ref filename, ..prog_args] => {
            let p = Path(*filename);
            let test_exec = p.filestem().unwrap() + "test~";
            invoke("rustc", &[~"--test", filename.to_owned(),
                              ~"-o", test_exec.to_owned()], rustc::main_args);
            let exit_code = run::process_status(~"./" + test_exec, prog_args);
            Valid(exit_code)
        }
        _ => Invalid
    }
}

fn cmd_run(args: &[~str]) -> ValidUsage {
    match args {
        [ref filename, ..prog_args] => {
            let p = Path(*filename);
            let exec = p.filestem().unwrap() + "~";
            invoke("rustc", &[filename.to_owned(), ~"-o", exec.to_owned()],
                   rustc::main_args);
            let exit_code = run::process_status(~"./"+exec, prog_args);
            Valid(exit_code)
        }
        _ => Invalid
    }
}

fn invoke(prog: &str, args: &[~str], f: &fn(&[~str])) {
    let mut osargs = ~[prog.to_owned()];
    osargs.push_all_move(args.to_owned());
    f(osargs);
}

fn do_command(command: &Command, args: &[~str]) -> ValidUsage {
    match command.action {
        Call(f) => f(args),
        CallMain(prog, f) => {
            invoke(prog, args, f);
            Valid(0)
        }
    }
}

fn usage() {
    static INDENT: uint = 8;

    io::print(
        "The rust tool is a convenience for managing rust source code.\n\
        It acts as a shortcut for programs of the rust tool chain.\n\
        \n\
        Usage:\trust <command> [arguments]\n\
        \n\
        The commands are:\n\
        \n"
    );

    for command in COMMANDS.iter() {
        let padding = " ".repeat(INDENT - command.cmd.len());
        printfln!("    %s%s%s", command.cmd, padding, command.usage_line);
    }

    io::print(
        "\n\
        Use \"rust help <command>\" for more information about a command.\n\
        \n"
    );

}

pub fn main() {
    #[fixed_stack_segment]; #[inline(never)];

    let os_args = os::args();

    if (os_args.len() > 1 && (os_args[1] == ~"-v" || os_args[1] == ~"--version")) {
        rustc::version(os_args[0]);
        unsafe { exit(0); }
    }

    let args = os_args.tail();

    if !args.is_empty() {
        let r = find_cmd(*args.head());
        for command in r.iter() {
            let result = do_command(command, args.tail());
            match result {
                Valid(exit_code) => unsafe { exit(exit_code.to_i32()) },
                _                => loop
            }
        }
    }

    usage();
}
<|endoftext|>


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

//! Traits for working with Errors.
//!
//! # The `Error` trait
//!
//! `Error` is a trait representing the basic expectations for error values,
//! i.e. values of type `E` in `Result<T, E>`. At a minimum, errors must provide
//! a description, but they may optionally provide additional detail (via
//! `Display`) and cause chain information:
//!
//! ```
//! use std::fmt::Display;
//!
//! trait Error: Display {
//!     fn description(&self) -> &str;
//!
//!     fn cause(&self) -> Option<&Error> { None }
//! }
//! ```
//!
//! The `cause` method is generally used when errors cross "abstraction
//! boundaries", i.e.  when a one module must report an error that is "caused"
//! by an error from a lower-level module. This setup makes it possible for the
//! high-level module to provide its own errors that do not commit to any
//! particular implementation, but also reveal some of its implementation for
//! debugging via `cause` chains.

#![stable(feature = "rust1", since = "1.0.0")]

// A note about crates and the facade:
//
// Originally, the `Error` trait was defined in libcore, and the impls
// were scattered about. However, coherence objected to this
// arrangement, because to create the blanket impls for `Box` required
// knowing that `&str: !Error`, and we have no means to deal with that
// sort of conflict just now. Therefore, for the time being, we have
// moved the `Error` trait into libstd. As we evolve a sol'n to the
// coherence challenge (e.g., specialization, neg impls, etc) we can
// reconsider what crate these items belong in.

use boxed::Box;
use convert::From;
use fmt::{self, Debug, Display};
use marker::Send;
use num;
use option::Option;
use option::Option::None;
use str;
use string::{self, String};

/// Base functionality for all errors in Rust.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Error: Debug + Display {
    /// A short description of the error.
    ///
    /// The description should not contain newlines or sentence-ending
    /// punctuation, to facilitate embedding in larger user-facing
    /// strings.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn description(&self) -> &str;

    /// The lower-level cause of this error, if any.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn cause(&self) -> Option<&Error> { None }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, E: Error + 'a> From<E> for Box<Error + 'a> {
    fn from(err: E) -> Box<Error + 'a> {
        Box::new(err)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, E: Error + Send + 'a> From<E> for Box<Error + Send + 'a> {
    fn from(err: E) -> Box<Error + Send + 'a> {
        Box::new(err)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b> From<&'b str> for Box<Error + Send + 'a> {
    fn from(err: &'b str) -> Box<Error + Send + 'a> {
        #[derive(Debug)]
        struct StringError(String);

        impl Error for StringError {
            fn description(&self) -> &str { &self.0 }
        }

        impl Display for StringError {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                Display::fmt(&self.0, f)
            }
        }

        Box::new(StringError(String::from_str(err)))
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Error for str::ParseBoolError {
    fn description(&self) -> &str { "failed to parse bool" }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Error for str::Utf8Error {
    fn description(&self) -> &str {
        match *self {
            str::Utf8Error::TooShort => "invalid utf-8: not enough bytes",
            str::Utf8Error::InvalidByte(..) => "invalid utf-8: corrupt contents",
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Error for num::ParseIntError {
    fn description(&self) -> &str {
        self.description()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Error for num::ParseFloatError {
    fn description(&self) -> &str {
        self.description()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Error for string::FromUtf8Error {
    fn description(&self) -> &str {
        "invalid utf-8"
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Error for string::FromUtf16Error {
    fn description(&self) -> &str {
        "invalid utf-16"
    }
}

<commit_msg>std: impl From<String> for Box<Error + Send><commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Traits for working with Errors.
//!
//! # The `Error` trait
//!
//! `Error` is a trait representing the basic expectations for error values,
//! i.e. values of type `E` in `Result<T, E>`. At a minimum, errors must provide
//! a description, but they may optionally provide additional detail (via
//! `Display`) and cause chain information:
//!
//! ```
//! use std::fmt::Display;
//!
//! trait Error: Display {
//!     fn description(&self) -> &str;
//!
//!     fn cause(&self) -> Option<&Error> { None }
//! }
//! ```
//!
//! The `cause` method is generally used when errors cross "abstraction
//! boundaries", i.e.  when a one module must report an error that is "caused"
//! by an error from a lower-level module. This setup makes it possible for the
//! high-level module to provide its own errors that do not commit to any
//! particular implementation, but also reveal some of its implementation for
//! debugging via `cause` chains.

#![stable(feature = "rust1", since = "1.0.0")]

// A note about crates and the facade:
//
// Originally, the `Error` trait was defined in libcore, and the impls
// were scattered about. However, coherence objected to this
// arrangement, because to create the blanket impls for `Box` required
// knowing that `&str: !Error`, and we have no means to deal with that
// sort of conflict just now. Therefore, for the time being, we have
// moved the `Error` trait into libstd. As we evolve a sol'n to the
// coherence challenge (e.g., specialization, neg impls, etc) we can
// reconsider what crate these items belong in.

use boxed::Box;
use convert::From;
use fmt::{self, Debug, Display};
use marker::Send;
use num;
use option::Option;
use option::Option::None;
use str;
use string::{self, String};

/// Base functionality for all errors in Rust.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Error: Debug + Display {
    /// A short description of the error.
    ///
    /// The description should not contain newlines or sentence-ending
    /// punctuation, to facilitate embedding in larger user-facing
    /// strings.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn description(&self) -> &str;

    /// The lower-level cause of this error, if any.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn cause(&self) -> Option<&Error> { None }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, E: Error + 'a> From<E> for Box<Error + 'a> {
    fn from(err: E) -> Box<Error + 'a> {
        Box::new(err)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, E: Error + Send + 'a> From<E> for Box<Error + Send + 'a> {
    fn from(err: E) -> Box<Error + Send + 'a> {
        Box::new(err)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl From<String> for Box<Error + Send> {
    fn from(err: String) -> Box<Error + Send> {
        #[derive(Debug)]
        struct StringError(String);

        impl Error for StringError {
            fn description(&self) -> &str { &self.0 }
        }

        impl Display for StringError {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                Display::fmt(&self.0, f)
            }
        }

        Box::new(StringError(err))
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b> From<&'b str> for Box<Error + Send + 'a> {
    fn from(err: &'b str) -> Box<Error + Send + 'a> {
        From::from(String::from_str(err))
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Error for str::ParseBoolError {
    fn description(&self) -> &str { "failed to parse bool" }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Error for str::Utf8Error {
    fn description(&self) -> &str {
        match *self {
            str::Utf8Error::TooShort => "invalid utf-8: not enough bytes",
            str::Utf8Error::InvalidByte(..) => "invalid utf-8: corrupt contents",
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Error for num::ParseIntError {
    fn description(&self) -> &str {
        self.description()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Error for num::ParseFloatError {
    fn description(&self) -> &str {
        self.description()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Error for string::FromUtf8Error {
    fn description(&self) -> &str {
        "invalid utf-8"
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Error for string::FromUtf16Error {
    fn description(&self) -> &str {
        "invalid utf-16"
    }
}

<|endoftext|>


<commit_before>#[feature(macro_rules)];

use std::os;
use std::rt::io::buffered::BufferedWriter;
use std::rt::io::file::{open, FileStream};
use std::rt::io;
pub mod branchify;
pub mod keycode;
pub mod scancode;

fn main() {
    let args = os::args();
    match args.len() {
        0 => {
            println("usage: codegen [keycode|scancode].rs destdir");
            os::set_exit_status(1);
        },
        3 => {
            let output_dir = GenericPath::new(args[2].clone());
            // TODO: maybe not 0777?
            os::make_dir(&output_dir, 0b111_111_111);

            match args[1] {
                ~"keycode.rs" => keycode::generate(&output_dir),
                ~"scancode.rs" => scancode::generate(&output_dir),
                s => {
                    println!("unknown thing-to-generate '{}'", s);
                    os::set_exit_status(1);
                }
            }
        },
        _ => {
            println!("usage: {} [keycode|scancode].rs destdir", args[0]);
            os::set_exit_status(1);
        }
    }
}

pub fn get_writer(output_dir: &Path, filename: &str) -> ~BufferedWriter<FileStream> {
    match open(&output_dir.join(filename), io::Truncate, io::Write) {
        Some(writer) => ~BufferedWriter::new(writer),
        None => fail!("Unable to write file"),
    }
}
<commit_msg>Corrected codegen to use CreateOrTruncate for generated files<commit_after>#[feature(macro_rules)];

use std::os;
use std::rt::io::buffered::BufferedWriter;
use std::rt::io::file::{open, FileStream};
use std::rt::io;
pub mod branchify;
pub mod keycode;
pub mod scancode;

fn main() {
    let args = os::args();
    match args.len() {
        0 => {
            println("usage: codegen [keycode|scancode].rs destdir");
            os::set_exit_status(1);
        },
        3 => {
            let output_dir = GenericPath::new(args[2].clone());
            // TODO: maybe not 0777?
            os::make_dir(&output_dir, 0b111_111_111);

            match args[1] {
                ~"keycode.rs" => keycode::generate(&output_dir),
                ~"scancode.rs" => scancode::generate(&output_dir),
                s => {
                    println!("unknown thing-to-generate '{}'", s);
                    os::set_exit_status(1);
                }
            }
        },
        _ => {
            println!("usage: {} [keycode|scancode].rs destdir", args[0]);
            os::set_exit_status(1);
        }
    }
}

pub fn get_writer(output_dir: &Path, filename: &str) -> ~BufferedWriter<FileStream> {
    match open(&output_dir.join(filename), io::CreateOrTruncate, io::Write) {
        Some(writer) => ~BufferedWriter::new(writer),
        None => fail!("Unable to write file"),
    }
}
<|endoftext|>


<commit_before>use std::num::Float;

use linalg::vector;

/// Point is a standard 3 component point but transforms as a point
/// point when transformations are applied
#[deriving(Show, Copy, PartialEq)]
pub struct Point {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

impl Point {
    /// Initialize the point and set values for x, y, z
    pub fn new(x: f32, y: f32, z: f32) -> Point {
        Point { x: x, y: y, z: z }
    }
    /// Initialize the point with the same value of x, y, z
    pub fn broadcast(x: f32) -> Point {
        Point { x: x, y: x, z: x }
    }
    /// Compute the squared length of the point
    pub fn length_sqr(&self) -> f32 {
        self.x * self.x + self.y * self.y + self.z * self.x
    }
    /// Compute the length of the point
    pub fn length(&self) -> f32 {
        Float::sqrt(self.length_sqr())
    }
    /// Get a pointized copy of this point
    pub fn pointized(&self) -> Point {
        let len = self.length();
        Point { x: self.x / len, y: self.y / len, z: self.z / len }
    }
    /// Compute the squared distance between this point and another
    pub fn distance_sqr(&self, a: &Point) -> f32 {
        (*self - *a).length_sqr()
    }
    /// Compute the distance between this point and another
    pub fn distance(&self, a: &Point) -> f32 {
        (*self - *a).length()
    }
}

impl Add<Point, Point> for Point {
    /// Add two points together
    fn add(self, rhs: Point) -> Point {
        Point { x: self.x + rhs.x, y: self.y + rhs.y, z: self.z + rhs.z }
    }
}

impl Add<vector::Vector, Point> for Point {
    /// Add two points together
    fn add(self, rhs: vector::Vector) -> Point {
        Point { x: self.x + rhs.x, y: self.y + rhs.y, z: self.z + rhs.z }
    }
}

impl Sub<Point, vector::Vector> for Point {
    /// Subtract two points to get the vector between them
    fn sub(self, rhs: Point) -> vector::Vector {
        vector::Vector { x: self.x - rhs.x, y: self.y - rhs.y, z: self.z - rhs.z }
    }
}

impl Sub<vector::Vector, Point> for Point {
    /// Subtract a vector from a point, translating the point by -vector
    fn sub(self, rhs: vector::Vector) -> Point {
        Point { x: self.x - rhs.x, y: self.y - rhs.y, z: self.z - rhs.z }
    }
}

impl Mul<f32, Point> for Point {
    /// Scale the point by some value
    fn mul(self, rhs: f32) -> Point {
        Point { x: self.x * rhs, y: self.y * rhs, z: self.z * rhs }
    }
}

impl Mul<Point, Point> for f32 {
    /// Scale the point by some value
    fn mul(self, rhs: Point) -> Point {
        rhs * self
    }
}

impl Div<Point, Point> for Point {
    /// Divide the points components by the right hand side's components
    fn div(self, rhs: Point) -> Point {
        Point { x: self.x / rhs.x, y: self.y / rhs.y, z: self.z / rhs.z }
    }
}

impl Div<f32, Point> for Point {
    /// Divide the points components by scalar
    fn div(self, rhs: f32) -> Point {
        Point { x: self.x / rhs, y: self.y / rhs, z: self.z / rhs }
    }
}

impl Neg<Point> for Point {
    /// Negate the point
    fn neg(self) -> Point {
        Point { x: -self.x, y: -self.y, z: -self.z }
    }
}

impl Index<uint, f32> for Point {
    /// Access the point by index
    ///
    /// - 0 = x
    /// - 1 = y
    /// - 2+ = z
    fn index(&self, i: &uint) -> &f32 {
        match *i {
            0 => &self.x,
            1 => &self.y,
            _ => &self.z,
        }
    }
}

impl IndexMut<uint, f32> for Point {
    /// Access the point by index
    ///
    /// - 0 = x
    /// - 1 = y
    /// - 2+ = z
    fn index_mut(&mut self, i: &uint) -> &mut f32 {
        match *i {
            0 => &mut self.x,
            1 => &mut self.y,
            _ => &mut self.z,
        }
    }
}

<commit_msg>Unsure what i wrote there.. points don't have lengths<commit_after>use std::num::Float;

use linalg::vector;

/// Point is a standard 3 component point but transforms as a point
/// point when transformations are applied
#[deriving(Show, Copy, PartialEq)]
pub struct Point {
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

impl Point {
    /// Initialize the point and set values for x, y, z
    pub fn new(x: f32, y: f32, z: f32) -> Point {
        Point { x: x, y: y, z: z }
    }
    /// Initialize the point with the same value of x, y, z
    pub fn broadcast(x: f32) -> Point {
        Point { x: x, y: x, z: x }
    }
    /// Compute the squared distance between this point and another
    pub fn distance_sqr(&self, a: &Point) -> f32 {
        (*self - *a).length_sqr()
    }
    /// Compute the distance between this point and another
    pub fn distance(&self, a: &Point) -> f32 {
        (*self - *a).length()
    }
}

impl Add<Point, Point> for Point {
    /// Add two points together
    fn add(self, rhs: Point) -> Point {
        Point { x: self.x + rhs.x, y: self.y + rhs.y, z: self.z + rhs.z }
    }
}

impl Add<vector::Vector, Point> for Point {
    /// Add two points together
    fn add(self, rhs: vector::Vector) -> Point {
        Point { x: self.x + rhs.x, y: self.y + rhs.y, z: self.z + rhs.z }
    }
}

impl Sub<Point, vector::Vector> for Point {
    /// Subtract two points to get the vector between them
    fn sub(self, rhs: Point) -> vector::Vector {
        vector::Vector { x: self.x - rhs.x, y: self.y - rhs.y, z: self.z - rhs.z }
    }
}

impl Sub<vector::Vector, Point> for Point {
    /// Subtract a vector from a point, translating the point by -vector
    fn sub(self, rhs: vector::Vector) -> Point {
        Point { x: self.x - rhs.x, y: self.y - rhs.y, z: self.z - rhs.z }
    }
}

impl Mul<f32, Point> for Point {
    /// Scale the point by some value
    fn mul(self, rhs: f32) -> Point {
        Point { x: self.x * rhs, y: self.y * rhs, z: self.z * rhs }
    }
}

impl Mul<Point, Point> for f32 {
    /// Scale the point by some value
    fn mul(self, rhs: Point) -> Point {
        rhs * self
    }
}

impl Div<Point, Point> for Point {
    /// Divide the points components by the right hand side's components
    fn div(self, rhs: Point) -> Point {
        Point { x: self.x / rhs.x, y: self.y / rhs.y, z: self.z / rhs.z }
    }
}

impl Div<f32, Point> for Point {
    /// Divide the points components by scalar
    fn div(self, rhs: f32) -> Point {
        Point { x: self.x / rhs, y: self.y / rhs, z: self.z / rhs }
    }
}

impl Neg<Point> for Point {
    /// Negate the point
    fn neg(self) -> Point {
        Point { x: -self.x, y: -self.y, z: -self.z }
    }
}

impl Index<uint, f32> for Point {
    /// Access the point by index
    ///
    /// - 0 = x
    /// - 1 = y
    /// - 2+ = z
    fn index(&self, i: &uint) -> &f32 {
        match *i {
            0 => &self.x,
            1 => &self.y,
            _ => &self.z,
        }
    }
}

impl IndexMut<uint, f32> for Point {
    /// Access the point by index
    ///
    /// - 0 = x
    /// - 1 = y
    /// - 2+ = z
    fn index_mut(&mut self, i: &uint) -> &mut f32 {
        match *i {
            0 => &mut self.x,
            1 => &mut self.y,
            _ => &mut self.z,
        }
    }
}

<|endoftext|>


<commit_before>extern crate eventual;
extern crate sbahn;

use eventual::*;
use sbahn::client;
use sbahn::handler;
use sbahn::message::*;
use sbahn::storage::HashMapBackend;
use sbahn::storage_node::StorageNode;
use std::net::{Ipv4Addr, SocketAddrV4, TcpListener};
use std::thread;
use std::time::Duration;

// Milis to wait before trying to connect to any node.
static DELAY: u64 = 100;

static mut PORT: u16 = 1100;
/// Obtain an open port
fn get_port() -> u16 {
    let mut port = 0;
    loop {
        unsafe {
          PORT += 1;
          port = PORT;
        }
        let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port);
        if TcpListener::bind(&addr).is_ok() {
            // Check wether the port is open, and only return it if it is.
            return port;
        }
    }
}

fn get_storage_node(pos: usize, shard_count: usize) -> SocketAddrV4 {
    let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), get_port());
    let mut sn: StorageNode<HashMapBackend> = StorageNode::new(&addr, pos, shard_count);
    thread::spawn(move || {
        &sn.listen();
    });
    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening
    addr
}

fn setup_handler_node(shards: &Vec<Vec<SocketAddrV4>>) -> SocketAddrV4 {
    let shards = shards.clone();
    let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), get_port());
    thread::spawn(move || {
        let _ = handler::listen(&addr, &shards);
    });
    thread::sleep(Duration::from_millis(DELAY));  // Wait for handler node to start listening
    addr
}

/// Listen on `address` for incoming client requests, and do nothing.
pub fn dead_node(address: &SocketAddrV4) -> Future<(), ()> {
    let address = address.to_owned();

    let read_timeout = Some(Duration::from_millis(300));
    let write_timeout = Some(Duration::from_millis(300));

    Future::spawn(move || {
        match TcpListener::bind(&address) {
            Ok(listener) => {
                // Accept connections and process them, spawning a new thread for each one.
                for stream in listener.incoming() {
                    match stream {
                        Ok(stream) => {
                            let _ = stream.set_read_timeout(read_timeout);
                            let _ = stream.set_write_timeout(write_timeout);
                            thread::spawn(|| {
                                thread::sleep(Duration::from_millis(500));
                            });
                        }
                        Err(e) => panic!("Connection failed!: {:?}", e),
                    }
                }
            }
            Err(e) => panic!("Error while binding to {:?}: {:?}", address, e),
        }
    })
}

fn get_dead_storage_node() -> SocketAddrV4 {
    let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), get_port());
    thread::spawn(move || {
        let _ = dead_node(&addr);
    });
    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening
    addr
}

fn setup_cluster() -> (SocketAddrV4, Vec<Vec<SocketAddrV4>>) {
    setup_bad_cluster(0)
}

fn setup_bad_cluster(bad_nodes: u32) -> (SocketAddrV4, Vec<Vec<SocketAddrV4>>) {
    let mut shards: Vec<Vec<SocketAddrV4>> = vec![];
    for i in 0..3 {
        let mut shard: Vec<SocketAddrV4> = vec![];
        for _ in 0..bad_nodes {
            shard.push(get_dead_storage_node());
        }
        for _ in bad_nodes..3 {
            shard.push(get_storage_node(i, 3));
        }
        shards.push(shard);
    }

    (setup_handler_node(&shards), shards)
}

fn write_to_storage_node(target: &SocketAddrV4, key: &Key, value: &Vec<u8>, timestamp: u64) {
    let request = InternodeRequest::Write {
        key: key.to_owned(),
        value: Value::Value {
            content: value.to_owned(),
            timestamp: timestamp,
        },
    };
    let r: Future<InternodeResponse, Error> = client::Client::send_to_node(target, &request);
    let _ = r.await();
}

fn key_and_value() -> (Key, Vec<u8>) {
    let key = Key {
        dataset: vec![1, 2, 3],
        pkey: vec![4, 5, 6],
        lkey: vec![7, 8, 9],
    };
    let value: Vec<u8> = vec![9, 8, 7];
    (key, value)
}

#[test]
fn read_what_you_insert() {
    let (handler_addr, _) = setup_cluster();
    let (local_key, local_value) = key_and_value();

    let client = client::Client::new(vec![handler_addr]);
    // Should succeed
    let r = client.insert(&local_key, &local_value);
    let r = r.await().unwrap();
    match r.message {
        Response::WriteAck {key, ..} => assert_eq!(key, local_key),
        _ => assert!(false),
    }
    // Should succeed
    let r = client.get(&local_key);
    let r = r.await().unwrap();
    match r.message {
        Response::Value {key, value} => {
            assert_eq!(key, local_key);
            match value {
                Value::Value {content, ..} => assert_eq!(content, local_value),
                _ => assert!(false),
            }
        },
        _ => assert!(false),
    }
}

#[test]
fn read_consistency_one_all_nodes_available() {
    let (handler_addr, shards) = setup_cluster();
    let (local_key, local_value) = key_and_value();

    for shard in shards {
        for node in shard {
            write_to_storage_node(&node, &local_key, &local_value, 100000);
        }
    }
    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::One);

    // Should succeed
    let r = client.get(&local_key);
    let r = r.await().unwrap();
    match r.message {
        Response::Value {key, value} => {
            assert_eq!(key, local_key);
            match value {
                Value::Value {content, ..} => assert_eq!(content, local_value),
                _ => assert!(false),
            }
        },
        _ => assert!(false),
    }
}

#[test]
fn read_consistency_one_one_node_available() {
    let (handler_addr, shards) = setup_cluster();
    let (local_key, local_value) = key_and_value();

    // Write to only one node (local_key corresponds to shard 2).
    write_to_storage_node(&shards[2][0], &local_key, &local_value, 100000);

    thread::sleep(Duration::from_millis(DELAY*3));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::One);

    // Should succeed
    let r = client.get(&local_key);
    let r = r.await().unwrap();
    match r.message {
        Response::Value {key, value} => {
            assert_eq!(key, local_key);
            match value {
                Value::Value {content, ..} => assert_eq!(content, local_value),
                _ => assert!(false),
            }
        },
        _ => assert!(false),
    }
}

#[test]
fn read_consistency_latest_all_same() {
    // Should succeed
    let (handler_addr, shards) = setup_cluster();
    let (local_key, local_value) = key_and_value();

    for shard in shards {
        for node in shard {
            write_to_storage_node(&node, &local_key, &local_value, 100000);
        }
    }
    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::Latest);

    // Should succeed
    let r = client.get(&local_key);
    let r = r.await().unwrap();
    match r.message {
        Response::Value {key, value} => {
            assert_eq!(key, local_key);
            match value {
                Value::Value {content, ..} => assert_eq!(content, local_value),
                _ => assert!(false),
            }
        },
        _ => assert!(false),
    }
}

#[test]
fn read_consistency_latest_all_different() {
    // Should succeed
}

#[test]
fn read_consistency_latest_one_node_available() {
    let (handler_addr, shards) = setup_cluster();
    let (local_key, local_value) = key_and_value();

    // Write to only one node (local_key corresponds to shard 2).
    write_to_storage_node(&shards[2][0], &local_key, &local_value, 100000);

    thread::sleep(Duration::from_millis(DELAY*3));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::Latest);

    // Should fail
    let r = client.get(&local_key);
    let r = r.await().unwrap();
    match r.message {
        Response::Error {key, ..} => {
            assert_eq!(key, local_key);
        }
        _ => assert!(false),
    }
}

#[test]
fn write_consistency_one_all_available() {
    let (handler_addr, _) = setup_cluster();
    let (local_key, local_value) = key_and_value();

    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::Latest);

    // Should succeed
    let r = client.insert(&local_key, &local_value);
    let r = r.await().unwrap();
    match r.message {
        Response::WriteAck {key, timestamp} => {
            assert_eq!(key, local_key);
            assert!(timestamp > 0);
        },
        _ => assert!(false),
    }
}

#[test]
fn write_consistency_one_none_available() {
    let (handler_addr, _) = setup_bad_cluster(3);
    let (local_key, local_value) = key_and_value();

    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::One);

    // Should fail
    match client.insert(&local_key, &local_value).await() {
        Ok(r) => {
            match r.message {
                Response::Error {key, message} => {
                    assert_eq!(key, local_key);
                    assert_eq!("Quorum write could not be accomplished.".to_string(), message);
                },
                _ => assert!(false),
            }
        }
        Err(_) => assert!(true),
    }
}

#[test]
fn write_consistency_latest_all_available() {
    let (handler_addr, _) = setup_cluster();
    let (local_key, local_value) = key_and_value();

    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::Latest);

    // Should succeed
    let r = client.insert(&local_key, &local_value);
    let r = r.await().unwrap();
    match r.message {
        Response::WriteAck {key, timestamp} => {
            assert_eq!(key, local_key);
            assert!(timestamp > 0);
        },
        _ => assert!(false),
    }
}

#[test]
fn write_consistency_latest_quorum_available() {
    let (handler_addr, _) = setup_bad_cluster(1);
    let (local_key, local_value) = key_and_value();

    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::Latest);

    // Should succeed
    let r = client.insert(&local_key, &local_value);
    let r = r.await().unwrap();
    match r.message {
        Response::WriteAck {key, timestamp} => {
            assert_eq!(key, local_key);
            assert!(timestamp > 0);
        },
        _ => assert!(false),
    }
}

#[test]
fn write_consistency_latest_one_available() {
    let (handler_addr, _) = setup_bad_cluster(2);
    let (local_key, local_value) = key_and_value();

    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::Latest);

    // Should fail
    let r = client.insert(&local_key, &local_value);
    let r = r.await().unwrap();
    match r.message {
        Response::Error {key, message} => {
            assert_eq!(local_key, key);
            assert_eq!("Quorum write could not be accomplished.".to_string(), message);
        }
        _ => assert!(false),
    }
}

#[test]
fn write_consistency_latest_none_available() {
    // Should fail
    let (handler_addr, _) = setup_bad_cluster(3);
    let (local_key, local_value) = key_and_value();

    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::Latest);

    // Should fail
    match client.insert(&local_key, &local_value).await() {
        Ok(r) => {
            match r.message {
                Response::Error {key, message} => {
                    assert_eq!(local_key, key);
                    assert_eq!("Quorum write could not be accomplished.".to_string(), message);
                }
                _ => assert!(false),
            }
        }
        Err(_) => assert!(true),
    }
}

#[test]
fn single_node() {
    let addr = get_storage_node(0, 1);
    let (insert_key, _) = key_and_value();

    {
        let content = InternodeRequest::Write {
            key: insert_key.to_owned(),
            value: Value::Value {
                content: vec![1],
                timestamp: 10000000,
            },
        };
        let addr = &addr.to_owned();
        let r: Future<InternodeResponse, Error> = client::Client::send_to_node(addr, &content);
        match r.await().unwrap() {
            InternodeResponse::WriteAck {key, timestamp} => {
                assert_eq!(key, insert_key);
                assert_eq!(timestamp, 10000000);
            },
            e => panic!("{:?}", e),
        }
    }
    {
        let content = InternodeRequest::Read {
            key: insert_key.to_owned(),
        };
        let addr = &addr.to_owned();
        let r: Future<InternodeResponse, Error> = client::Client::send_to_node(addr, &content);
        let r = r.await();
        match r {
            Ok(r) => match r {
                InternodeResponse::Value {key, value} => {
                    assert_eq!(key, insert_key);
                    match value {
                        Value::Value {content, timestamp} => {
                            assert_eq!(&content[..], &[1][..]);
                            assert_eq!(timestamp, 10000000);
                        },
                        _ => panic!(),
                    }
                },
                _ => panic!(),
            },
            Err(_) => panic!(),
        }
    }
}
<commit_msg>Fix test<commit_after>extern crate eventual;
extern crate sbahn;

use eventual::*;
use sbahn::client;
use sbahn::handler;
use sbahn::message::*;
use sbahn::storage::HashMapBackend;
use sbahn::storage_node::StorageNode;
use std::net::{Ipv4Addr, SocketAddrV4, TcpListener};
use std::thread;
use std::time::Duration;

// Milis to wait before trying to connect to any node.
static DELAY: u64 = 100;

static mut PORT: u16 = 1100;
/// Obtain an open port
fn get_port() -> u16 {
    let mut port = 0;
    loop {
        unsafe {
          PORT += 1;
          port = PORT;
        }
        let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port);
        if TcpListener::bind(&addr).is_ok() {
            // Check wether the port is open, and only return it if it is.
            return port;
        }
    }
}

fn get_storage_node(pos: usize, shard_count: usize) -> SocketAddrV4 {
    let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), get_port());
    let mut sn: StorageNode<HashMapBackend> = StorageNode::new(&addr, pos, shard_count);
    thread::spawn(move || {
        &sn.listen();
    });
    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening
    addr
}

fn setup_handler_node(shards: &Vec<Vec<SocketAddrV4>>) -> SocketAddrV4 {
    let shards = shards.clone();
    let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), get_port());
    thread::spawn(move || {
        let _ = handler::listen(&addr, &shards);
    });
    thread::sleep(Duration::from_millis(DELAY));  // Wait for handler node to start listening
    addr
}

/// Listen on `address` for incoming client requests, and do nothing.
pub fn dead_node(address: &SocketAddrV4) -> Future<(), ()> {
    let address = address.to_owned();

    let read_timeout = Some(Duration::from_millis(300));
    let write_timeout = Some(Duration::from_millis(300));

    Future::spawn(move || {
        match TcpListener::bind(&address) {
            Ok(listener) => {
                // Accept connections and process them, spawning a new thread for each one.
                for stream in listener.incoming() {
                    match stream {
                        Ok(stream) => {
                            let _ = stream.set_read_timeout(read_timeout);
                            let _ = stream.set_write_timeout(write_timeout);
                            thread::spawn(|| {
                                thread::sleep(Duration::from_millis(500));
                            });
                        }
                        Err(e) => panic!("Connection failed!: {:?}", e),
                    }
                }
            }
            Err(e) => panic!("Error while binding to {:?}: {:?}", address, e),
        }
    })
}

fn get_dead_storage_node() -> SocketAddrV4 {
    let addr = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), get_port());
    thread::spawn(move || {
        let _ = dead_node(&addr);
    });
    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening
    addr
}

fn setup_cluster() -> (SocketAddrV4, Vec<Vec<SocketAddrV4>>) {
    setup_bad_cluster(0)
}

fn setup_bad_cluster(bad_nodes: u32) -> (SocketAddrV4, Vec<Vec<SocketAddrV4>>) {
    let mut shards: Vec<Vec<SocketAddrV4>> = vec![];
    for i in 0..3 {
        let mut shard: Vec<SocketAddrV4> = vec![];
        for _ in 0..bad_nodes {
            shard.push(get_dead_storage_node());
        }
        for _ in bad_nodes..3 {
            shard.push(get_storage_node(i, 3));
        }
        shards.push(shard);
    }

    (setup_handler_node(&shards), shards)
}

fn write_to_storage_node(target: &SocketAddrV4, key: &Key, value: &Vec<u8>, timestamp: u64) {
    let request = InternodeRequest::Write {
        key: key.to_owned(),
        value: Value::Value {
            content: value.to_owned(),
            timestamp: timestamp,
        },
    };
    let r: Future<InternodeResponse, Error> = client::Client::send_to_node(target, &request);
    let _ = r.await();
}

fn key_and_value() -> (Key, Vec<u8>) {
    let key = Key {
        dataset: vec![1, 2, 3],
        pkey: vec![4, 5, 6],
        lkey: vec![7, 8, 9],
    };
    let value: Vec<u8> = vec![9, 8, 7];
    (key, value)
}

#[test]
fn read_what_you_insert() {
    let (handler_addr, _) = setup_cluster();
    let (local_key, local_value) = key_and_value();

    let client = client::Client::new(vec![handler_addr]);
    // Should succeed
    let r = client.insert(&local_key, &local_value);
    let r = r.await().unwrap();
    match r.message {
        Response::WriteAck {key, ..} => assert_eq!(key, local_key),
        _ => assert!(false),
    }
    // Should succeed
    let r = client.get(&local_key);
    let r = r.await().unwrap();
    match r.message {
        Response::Value {key, value} => {
            assert_eq!(key, local_key);
            match value {
                Value::Value {content, ..} => assert_eq!(content, local_value),
                _ => assert!(false),
            }
        },
        _ => assert!(false),
    }
}

#[test]
fn read_consistency_one_all_nodes_available() {
    let (handler_addr, shards) = setup_cluster();
    let (local_key, local_value) = key_and_value();

    for shard in shards {
        for node in shard {
            write_to_storage_node(&node, &local_key, &local_value, 100000);
        }
    }
    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::One);

    // Should succeed
    let r = client.get(&local_key);
    let r = r.await().unwrap();
    match r.message {
        Response::Value {key, value} => {
            assert_eq!(key, local_key);
            match value {
                Value::Value {content, ..} => assert_eq!(content, local_value),
                _ => assert!(false),
            }
        },
        _ => assert!(false),
    }
}

#[test]
fn read_consistency_one_one_node_available() {
    let (handler_addr, shards) = setup_cluster();
    let (local_key, local_value) = key_and_value();

    // Write to only one node (local_key corresponds to shard 2).
    write_to_storage_node(&shards[2][0], &local_key, &local_value, 100000);

    thread::sleep(Duration::from_millis(DELAY*3));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::One);

    // Should succeed
    let r = client.get(&local_key);
    let r = r.await().unwrap();
    match r.message {
        Response::Value {key, value} => {
            assert_eq!(key, local_key);
            match value {
                Value::Value {content, ..} => assert_eq!(content, local_value),
                _ => assert!(false),
            }
        },
        _ => assert!(false),
    }
}

#[test]
fn read_consistency_latest_all_same() {
    // Should succeed
    let (handler_addr, shards) = setup_cluster();
    let (local_key, local_value) = key_and_value();

    for shard in shards {
        for node in shard {
            write_to_storage_node(&node, &local_key, &local_value, 100000);
        }
    }
    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::Latest);

    // Should succeed
    let r = client.get(&local_key);
    let r = r.await().unwrap();
    match r.message {
        Response::Value {key, value} => {
            assert_eq!(key, local_key);
            match value {
                Value::Value {content, ..} => assert_eq!(content, local_value),
                _ => assert!(false),
            }
        },
        _ => assert!(false),
    }
}

#[test]
fn read_consistency_latest_all_different() {
    // Should succeed
}

#[test]
fn read_consistency_latest_one_node_available() {
    let (handler_addr, shards) = setup_cluster();
    let (local_key, local_value) = key_and_value();

    // Write to only one node (local_key corresponds to shard 2).
    write_to_storage_node(&shards[2][0], &local_key, &local_value, 100000);

    thread::sleep(Duration::from_millis(DELAY*3));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::Latest);

    // Should fail
    match client.get(&local_key).await() {
        Ok(r) => {
            match r.message {
                Response::Error {key, ..} => {
                    assert_eq!(key, local_key);
                }
                _ => assert!(false),
            }
        }
        Err(_) => assert!(true),
    }
}

#[test]
fn write_consistency_one_all_available() {
    let (handler_addr, _) = setup_cluster();
    let (local_key, local_value) = key_and_value();

    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::Latest);

    // Should succeed
    let r = client.insert(&local_key, &local_value);
    let r = r.await().unwrap();
    match r.message {
        Response::WriteAck {key, timestamp} => {
            assert_eq!(key, local_key);
            assert!(timestamp > 0);
        },
        _ => assert!(false),
    }
}

#[test]
fn write_consistency_one_none_available() {
    let (handler_addr, _) = setup_bad_cluster(3);
    let (local_key, local_value) = key_and_value();

    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::One);

    // Should fail
    match client.insert(&local_key, &local_value).await() {
        Ok(r) => {
            match r.message {
                Response::Error {key, message} => {
                    assert_eq!(key, local_key);
                    assert_eq!("Quorum write could not be accomplished.".to_string(), message);
                },
                _ => assert!(false),
            }
        }
        Err(_) => assert!(true),
    }
}

#[test]
fn write_consistency_latest_all_available() {
    let (handler_addr, _) = setup_cluster();
    let (local_key, local_value) = key_and_value();

    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::Latest);

    // Should succeed
    let r = client.insert(&local_key, &local_value);
    let r = r.await().unwrap();
    match r.message {
        Response::WriteAck {key, timestamp} => {
            assert_eq!(key, local_key);
            assert!(timestamp > 0);
        },
        _ => assert!(false),
    }
}

#[test]
fn write_consistency_latest_quorum_available() {
    let (handler_addr, _) = setup_bad_cluster(1);
    let (local_key, local_value) = key_and_value();

    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::Latest);

    // Should succeed
    let r = client.insert(&local_key, &local_value);
    let r = r.await().unwrap();
    match r.message {
        Response::WriteAck {key, timestamp} => {
            assert_eq!(key, local_key);
            assert!(timestamp > 0);
        },
        _ => assert!(false),
    }
}

#[test]
fn write_consistency_latest_one_available() {
    let (handler_addr, _) = setup_bad_cluster(2);
    let (local_key, local_value) = key_and_value();

    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::Latest);

    // Should fail
    match client.insert(&local_key, &local_value).await() {
        Ok(r) => {
            match r.message {
                Response::Error {key, message} => {
                    assert_eq!(local_key, key);
                    assert_eq!("Quorum write could not be accomplished.".to_string(), message);
                }
                _ => assert!(false),
            }
        }
        Err(_) => assert!(true),
    }
}

#[test]
fn write_consistency_latest_none_available() {
    let (handler_addr, _) = setup_bad_cluster(3);
    let (local_key, local_value) = key_and_value();

    thread::sleep(Duration::from_millis(DELAY));  // Wait for storage node to start listening

    let client = client::Client::with_consistency(vec![handler_addr], Consistency::Latest);

    // Should fail
    match client.insert(&local_key, &local_value).await() {
        Ok(r) => {
            match r.message {
                Response::Error {key, message} => {
                    assert_eq!(local_key, key);
                    assert_eq!("Quorum write could not be accomplished.".to_string(), message);
                }
                _ => assert!(false),
            }
        }
        Err(_) => assert!(true),
    }
}

#[test]
fn single_node() {
    let addr = get_storage_node(0, 1);
    let (insert_key, _) = key_and_value();

    {
        let content = InternodeRequest::Write {
            key: insert_key.to_owned(),
            value: Value::Value {
                content: vec![1],
                timestamp: 10000000,
            },
        };
        let addr = &addr.to_owned();
        let r: Future<InternodeResponse, Error> = client::Client::send_to_node(addr, &content);
        match r.await().unwrap() {
            InternodeResponse::WriteAck {key, timestamp} => {
                assert_eq!(key, insert_key);
                assert_eq!(timestamp, 10000000);
            },
            e => panic!("{:?}", e),
        }
    }
    {
        let content = InternodeRequest::Read {
            key: insert_key.to_owned(),
        };
        let addr = &addr.to_owned();
        let r: Future<InternodeResponse, Error> = client::Client::send_to_node(addr, &content);
        let r = r.await();
        match r {
            Ok(r) => match r {
                InternodeResponse::Value {key, value} => {
                    assert_eq!(key, insert_key);
                    match value {
                        Value::Value {content, timestamp} => {
                            assert_eq!(&content[..], &[1][..]);
                            assert_eq!(timestamp, 10000000);
                        },
                        _ => panic!(),
                    }
                },
                _ => panic!(),
            },
            Err(_) => panic!(),
        }
    }
}
<|endoftext|>


<commit_before>//
// url.rs - module for url-encoding
//

import vec::len;

export query_escape, query_unescape;

enum enc_mode { query, path, fragment, userinfo }

fn query_escape(s: str) -> str { url_escape(s, query) }
fn query_unescape(s: str) -> str { url_unescape(s, query) }

#[inline(always)]
pure fn ishex(c: u8) -> bool {
    if 48u8 <= c && c <= 57u8 { true }
    else if 65u8 <= c && c <= 90u8  { true }
    else if 97u8 <= c && c <= 122u8 { true }
    else { false }
}

#[inline(always)]
pure fn unhex(c: u8) -> u8 {
    alt c {
        48u8 to  57u8 { c - 48u8 }        // 0 .. 9
        65u8 to  90u8 { c - 65u8 + 10u8 } // A .. Z
        97u8 to 122u8 { c - 97u8 + 10u8 } // a .. z
        _ { fail "should be unreachable"; }
    }
}

#[inline(always)]
pure fn should_escape(c: u8, mode: enc_mode) -> bool {
    alt c {
        48u8 to  57u8 { ret false; } // 0 .. 9
        65u8 to  90u8 { ret false; } // A .. Z
        97u8 to 122u8 { ret false; } // a .. z
        _ { }
    }

    alt c {
        45u8  | 95u8 | 46u8 | 33u8 | // '-', '_', '.', '!'
        126u8 | 42u8 | 39u8 | 40u8 | // '~', '*', '\'', '('
        41u8 { false }               // ')'

        36u8 | 38u8 | 43u8 | 44u8 |  // '$', '&', '+', ','
        47u8 | 58u8 | 59u8 | 61u8 |  // '/', ':', ';', '='
        63u8 | 64u8 {                // '?', '@'
            alt mode {
                query    { true }
                fragment { false }
                path     { (c == 63u8) }
                userinfo { (c == 47u8 || c == 58u8 || c == 64u8) }
            }
        }

        _ { true }
    }
}

fn url_escape(s: str, mode: enc_mode) -> str {
    let bs = str::bytes(s);
    let src_length = len(bs);
    let mut space_count = 0u;
    let mut hex_count = 0u;
    let table =
        [48u8, 49u8, 50u8, 51u8, 52u8, 53u8, 54u8, 55u8,
         56u8, 57u8, 65u8, 66u8, 67u8, 68u8, 69u8, 70u8];

    uint::range(0u, src_length) {|i|
        let c = bs[i];
        if should_escape(bs[i], mode) {
            if c == 32u8 && mode == query {
                space_count += 1u;
            } else {
                hex_count += 1u;
            }
        }
    }

    // Nothing to do if there's no space and no escapable chars in `s`
    if space_count == 0u && hex_count == 0u {
        ret s;
    }

    let ts = vec::to_mut(vec::from_elem(src_length + 2u * hex_count, 0u8));
    let mut i = 0u;
    let mut j = 0u;
    let mut c = 0u8;

    while i < src_length {
        c = bs[i];
        if c == 32u8 && mode == query {
            ts[j] = '+' as u8;
            j += 1u;
        } else if should_escape(c, mode) {
            ts[j] = '%' as u8;
            ts[j+1u] = table[c >> 4u8];
            ts[j+2u] = table[c & 0x0f_u8];
            j += 3u;
        } else {
            ts[j] = c;
            j += 1u;
        }
        i += 1u;
    }

    str::from_bytes(vec::from_mut(ts))
}

fn url_unescape(s: str, mode: enc_mode) -> str {
    let bs = str::bytes(s);
    let src_length = len(bs);
    let mut n = 0u;
    let mut i = 0u;
    let mut hasplus = false;

    while i < src_length {
        let c = bs[i];
        if c == 37u8 {
            n += 1u;
            if i+2u >= src_length || !ishex(bs[i+1u]) || !ishex(bs[i+2u]) {
                fail #fmt["Invalid URL escape: '%s'", s];
            }
            i += 3u;
        } else if c == 43u8 {
            hasplus = mode == query;
            i += 1u;
        } else {
            i += 1u;
        }
    }

    if n == 0u && !hasplus {
        ret s;
    }

    let ts = vec::to_mut(vec::from_elem(src_length - 2u * n, 0u8));
    let mut i = 0u;
    let mut j = 0u;

    while i < src_length {
        let c = bs[i];
        if c == 37u8 {
            ts[j] = unhex(bs[i+1u]) << 4u | unhex(bs[i+2u]);
            j += 1u;
            i += 3u;
        } else if c == 43u8 {
            if mode == query { ts[j] = 32u8; }
            else { ts[j] = 43u8; }
            j += 1u;
            i += 1u;
        } else {
            ts[j] = c;
            j += 1u;
            i += 1u;
        }
    }

    str::from_bytes(vec::from_mut(ts))
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_should_escape() {
        assert should_escape('A' as u8, path) == false;
        assert should_escape('0' as u8, path) == false;
        assert should_escape('?' as u8, path) == true;
        assert should_escape('A' as u8, query) == false;
        assert should_escape('0' as u8, query) == false;
        assert should_escape('@' as u8, query) == true;
        assert should_escape('/' as u8, userinfo) == true;
        assert should_escape(':' as u8, userinfo) == true;
        assert should_escape('$' as u8, userinfo) == false;
        assert should_escape('A' as u8, fragment) == false;
        assert should_escape('0' as u8, fragment) == false;
        assert should_escape(';' as u8, fragment) == false;
    }
    #[test]
    fn test_query_escape() {
        assert query_escape("a") == "a";
        assert query_escape("a z") == "a+z";
        assert query_escape("å") == "%C3%A5";
        assert query_escape("?") == "%3F";
        assert query_escape("あ") == "%E3%81%82";
    }
    #[test]
    fn test_query_unescape() {
        assert query_unescape("a") == "a";
        assert query_unescape("a+z") == "a z";
        assert query_unescape("%3f") == "?";
        assert query_unescape("%C3%A5") == "å";
        assert query_unescape("%E3%81%82") == "あ";
    }
}
<commit_msg>Use alt expr instead of if ... else<commit_after>//
// url.rs - module for url-encoding
//

import vec::len;

export query_escape, query_unescape;

enum enc_mode { query, path, fragment, userinfo }

fn query_escape(s: str) -> str { url_escape(s, query) }
fn query_unescape(s: str) -> str { url_unescape(s, query) }

#[inline(always)]
pure fn ishex(c: u8) -> bool {
    alt c {
        48u8 to  57u8 { true } // 0 .. 9
        65u8 to  90u8 { true } // A .. Z
        97u8 to 122u8 { true } // a .. z
        _ { false }
    }
}

#[inline(always)]
pure fn unhex(c: u8) -> u8 {
    alt c {
        48u8 to  57u8 { c - 48u8 }        // 0 .. 9
        65u8 to  90u8 { c - 65u8 + 10u8 } // A .. Z
        97u8 to 122u8 { c - 97u8 + 10u8 } // a .. z
        _ { fail "should be unreachable"; }
    }
}

#[inline(always)]
pure fn should_escape(c: u8, mode: enc_mode) -> bool {
    alt c {
        48u8 to  57u8 { ret false; } // 0 .. 9
        65u8 to  90u8 { ret false; } // A .. Z
        97u8 to 122u8 { ret false; } // a .. z
        _ { }
    }

    alt c {
        45u8  | 95u8 | 46u8 | 33u8 | // '-', '_', '.', '!'
        126u8 | 42u8 | 39u8 | 40u8 | // '~', '*', '\'', '('
        41u8 { false }               // ')'

        36u8 | 38u8 | 43u8 | 44u8 |  // '$', '&', '+', ','
        47u8 | 58u8 | 59u8 | 61u8 |  // '/', ':', ';', '='
        63u8 | 64u8 {                // '?', '@'
            alt mode {
                query    { true }
                fragment { false }
                path     { (c == 63u8) }
                userinfo { (c == 47u8 || c == 58u8 || c == 64u8) }
            }
        }

        _ { true }
    }
}

fn url_escape(s: str, mode: enc_mode) -> str {
    let bs = str::bytes(s);
    let src_length = len(bs);
    let mut space_count = 0u;
    let mut hex_count = 0u;
    let table =
        [48u8, 49u8, 50u8, 51u8, 52u8, 53u8, 54u8, 55u8,
         56u8, 57u8, 65u8, 66u8, 67u8, 68u8, 69u8, 70u8];

    uint::range(0u, src_length) {|i|
        let c = bs[i];
        if should_escape(bs[i], mode) {
            if c == 32u8 && mode == query {
                space_count += 1u;
            } else {
                hex_count += 1u;
            }
        }
    }

    // Nothing to do if there's no space and no escapable chars in `s`
    if space_count == 0u && hex_count == 0u {
        ret s;
    }

    let ts = vec::to_mut(vec::from_elem(src_length + 2u * hex_count, 0u8));
    let mut i = 0u;
    let mut j = 0u;
    let mut c = 0u8;

    while i < src_length {
        c = bs[i];
        if c == 32u8 && mode == query {
            ts[j] = '+' as u8;
            j += 1u;
        } else if should_escape(c, mode) {
            ts[j] = '%' as u8;
            ts[j+1u] = table[c >> 4u8];
            ts[j+2u] = table[c & 0x0f_u8];
            j += 3u;
        } else {
            ts[j] = c;
            j += 1u;
        }
        i += 1u;
    }

    str::from_bytes(vec::from_mut(ts))
}

fn url_unescape(s: str, mode: enc_mode) -> str {
    let bs = str::bytes(s);
    let src_length = len(bs);
    let mut n = 0u;
    let mut i = 0u;
    let mut hasplus = false;

    while i < src_length {
        let c = bs[i];
        if c == 37u8 {
            n += 1u;
            if i+2u >= src_length || !ishex(bs[i+1u]) || !ishex(bs[i+2u]) {
                fail #fmt["Invalid URL escape: '%s'", s];
            }
            i += 3u;
        } else if c == 43u8 {
            hasplus = mode == query;
            i += 1u;
        } else {
            i += 1u;
        }
    }

    if n == 0u && !hasplus {
        ret s;
    }

    let ts = vec::to_mut(vec::from_elem(src_length - 2u * n, 0u8));
    let mut i = 0u;
    let mut j = 0u;

    while i < src_length {
        let c = bs[i];
        if c == 37u8 {
            ts[j] = unhex(bs[i+1u]) << 4u | unhex(bs[i+2u]);
            j += 1u;
            i += 3u;
        } else if c == 43u8 {
            if mode == query { ts[j] = 32u8; }
            else { ts[j] = 43u8; }
            j += 1u;
            i += 1u;
        } else {
            ts[j] = c;
            j += 1u;
            i += 1u;
        }
    }

    str::from_bytes(vec::from_mut(ts))
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_should_escape() {
        assert should_escape('A' as u8, path) == false;
        assert should_escape('0' as u8, path) == false;
        assert should_escape('?' as u8, path) == true;
        assert should_escape('A' as u8, query) == false;
        assert should_escape('0' as u8, query) == false;
        assert should_escape('@' as u8, query) == true;
        assert should_escape('/' as u8, userinfo) == true;
        assert should_escape(':' as u8, userinfo) == true;
        assert should_escape('$' as u8, userinfo) == false;
        assert should_escape('A' as u8, fragment) == false;
        assert should_escape('0' as u8, fragment) == false;
        assert should_escape(';' as u8, fragment) == false;
    }
    #[test]
    fn test_query_escape() {
        assert query_escape("a") == "a";
        assert query_escape("a z") == "a+z";
        assert query_escape("å") == "%C3%A5";
        assert query_escape("?") == "%3F";
        assert query_escape("あ") == "%E3%81%82";
    }
    #[test]
    fn test_query_unescape() {
        assert query_unescape("a") == "a";
        assert query_unescape("a+z") == "a z";
        assert query_unescape("%3f") == "?";
        assert query_unescape("%C3%A5") == "å";
        assert query_unescape("%E3%81%82") == "あ";
    }
}
<|endoftext|>