<commit_before>import _str.sbuf;
import _vec.vbuf;

native mod libc = "msvcrt.dll" {
    fn open(sbuf s, int flags, uint mode) -> int = "_open";
    fn read(int fd, vbuf buf, uint count) -> int = "_read";
    fn write(int fd, vbuf buf, uint count) -> int = "_write";
    fn close(int fd) -> int = "_close";

    type FILE;
    fn fopen(sbuf path, sbuf mode) -> FILE;
    fn _fdopen(int fd, sbuf mode) -> FILE;
    fn fclose(FILE f);
    fn fgetc(FILE f) -> int;
    fn ungetc(int c, FILE f);
    fn feof(FILE f) -> int;
    fn fread(vbuf buf, uint size, uint n, FILE f) -> uint;
    fn fwrite(vbuf buf, uint size, uint n, FILE f) -> uint;
    fn fseek(FILE f, int offset, int whence) -> int;
    fn ftell(FILE f) -> int;

    fn _pipe(vbuf fds, uint size, int mode) -> int;
}

mod libc_constants {
    fn O_RDONLY() -> int { ret 0x0000; }
    fn O_WRONLY() -> int { ret 0x0001; }
    fn O_RDWR()   -> int { ret 0x0002; }
    fn O_APPEND() -> int { ret 0x0400; }
    fn O_CREAT()  -> int { ret 0x0040; }
    fn O_EXCL()   -> int { ret 0x0080; }
    fn O_TRUNC()  -> int { ret 0x0200; }
    fn O_TEXT()   -> int { ret 0x4000; }
    fn O_BINARY() -> int { ret 0x8000; }

    fn S_IRUSR() -> uint { ret 0x0100u; } // really _S_IREAD  in win32
    fn S_IWUSR() -> uint { ret 0x0080u; } // really _S_IWRITE in win32
}

fn exec_suffix() -> str {
    ret ".exe";
}

fn target_os() -> str {
    ret "win32";
}

fn dylib_filename(str base) -> str {
    ret base + ".dll";
}

fn pipe() -> tup(int, int) {
    let vec[mutable int] fds = vec(mutable 0, 0);
    check(os.libc._pipe(_vec.buf[mutable int](fds), 1024u,
                        libc_constants.O_BINARY()) == 0);
    ret tup(fds.(0), fds.(1));
}

fn fd_FILE(int fd) -> libc.FILE {
    ret libc._fdopen(fd, _str.buf("r"));
}

native "rust" mod rustrt {
    fn rust_process_wait(int handle) -> int;
}

fn waitpid(int pid) -> int {
    ret rustrt.rust_process_wait(pid);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>stdlib: Add getenv(3) to win32_os.<commit_after>import _str.sbuf;
import _vec.vbuf;

native mod libc = "msvcrt.dll" {
    fn open(sbuf s, int flags, uint mode) -> int = "_open";
    fn read(int fd, vbuf buf, uint count) -> int = "_read";
    fn write(int fd, vbuf buf, uint count) -> int = "_write";
    fn close(int fd) -> int = "_close";

    type FILE;
    fn fopen(sbuf path, sbuf mode) -> FILE;
    fn _fdopen(int fd, sbuf mode) -> FILE;
    fn fclose(FILE f);
    fn fgetc(FILE f) -> int;
    fn ungetc(int c, FILE f);
    fn feof(FILE f) -> int;
    fn fread(vbuf buf, uint size, uint n, FILE f) -> uint;
    fn fwrite(vbuf buf, uint size, uint n, FILE f) -> uint;
    fn fseek(FILE f, int offset, int whence) -> int;
    fn ftell(FILE f) -> int;

    fn getenv(sbuf n) -> sbuf;

    fn _pipe(vbuf fds, uint size, int mode) -> int;
}

mod libc_constants {
    fn O_RDONLY() -> int { ret 0x0000; }
    fn O_WRONLY() -> int { ret 0x0001; }
    fn O_RDWR()   -> int { ret 0x0002; }
    fn O_APPEND() -> int { ret 0x0400; }
    fn O_CREAT()  -> int { ret 0x0040; }
    fn O_EXCL()   -> int { ret 0x0080; }
    fn O_TRUNC()  -> int { ret 0x0200; }
    fn O_TEXT()   -> int { ret 0x4000; }
    fn O_BINARY() -> int { ret 0x8000; }

    fn S_IRUSR() -> uint { ret 0x0100u; } // really _S_IREAD  in win32
    fn S_IWUSR() -> uint { ret 0x0080u; } // really _S_IWRITE in win32
}

fn exec_suffix() -> str {
    ret ".exe";
}

fn target_os() -> str {
    ret "win32";
}

fn dylib_filename(str base) -> str {
    ret base + ".dll";
}

fn pipe() -> tup(int, int) {
    let vec[mutable int] fds = vec(mutable 0, 0);
    check(os.libc._pipe(_vec.buf[mutable int](fds), 1024u,
                        libc_constants.O_BINARY()) == 0);
    ret tup(fds.(0), fds.(1));
}

fn fd_FILE(int fd) -> libc.FILE {
    ret libc._fdopen(fd, _str.buf("r"));
}

native "rust" mod rustrt {
    fn rust_process_wait(int handle) -> int;
}

fn waitpid(int pid) -> int {
    ret rustrt.rust_process_wait(pid);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>//! Random number generation

export rng, seed, seeded_rng, weighted, extensions;
export xorshift, seeded_xorshift;

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
iface 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 extensions for 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;
        ret ((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 {
            ret none;
        }
        let chosen = self.gen_uint_range(0u, total);
        let mut so_far = 0u;
        for v.each |item| {
            so_far += item.weight;
            if so_far > chosen {
                ret some(item.item);
            }
        }
        unreachable();
    }

    /**
     * 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::to_mut(values);
        self.shuffle_mut(m);
        ret vec::from_mut(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));
        }
    }

}

class rand_res {
    let c: *rctx;
    new(c: *rctx) { self.c = c; }
    drop { rustrt::rand_free(self.c); }
}

impl of rng for @rand_res {
    fn next() -> u32 { ret 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 {
    @rand_res(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 {
    @rand_res(rustrt::rand_new_seeded(seed)) as rng
}

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

impl of rng for xorshift_state {
    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();
        assert r.choose_option(~[]) == none::<int>;
        assert r.choose_option(~[1, 1, 1]) == some(1);
    }

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

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

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

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

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>Change syntax extension syntax: `#m[...]` -> `m!{...}`.<commit_after>//! Random number generation

export rng, seed, seeded_rng, weighted, extensions;
export xorshift, seeded_xorshift;

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
iface 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 extensions for 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;
        ret ((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 {
            ret none;
        }
        let chosen = self.gen_uint_range(0u, total);
        let mut so_far = 0u;
        for v.each |item| {
            so_far += item.weight;
            if so_far > chosen {
                ret some(item.item);
            }
        }
        unreachable();
    }

    /**
     * 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::to_mut(values);
        self.shuffle_mut(m);
        ret vec::from_mut(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));
        }
    }

}

class rand_res {
    let c: *rctx;
    new(c: *rctx) { self.c = c; }
    drop { rustrt::rand_free(self.c); }
}

impl of rng for @rand_res {
    fn next() -> u32 { ret 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 {
    @rand_res(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 {
    @rand_res(rustrt::rand_new_seeded(seed)) as rng
}

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

impl of rng for xorshift_state {
    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();
        assert r.choose_option(~[]) == none::<int>;
        assert r.choose_option(~[1, 1, 1]) == some(1);
    }

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

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

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

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

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


<commit_before>use std::io::{Read, Write};

use super::*;

pub(crate) fn read_blob(
    blob_ptr: Lsn,
    config: &Config,
) -> Result<Vec<u8>, ()> {
    let path = config.blob_path(blob_ptr);
    let mut f = std::fs::OpenOptions::new().read(true).open(&path)?;

    let mut crc_expected_bytes = [0u8; BLOB_INLINE_LEN];
    f.read_exact(&mut crc_expected_bytes).unwrap();
    let crc_expected = arr_to_u64(crc_expected_bytes);

    let mut buf = vec![];
    f.read_to_end(&mut buf)?;

    let crc_actual = crc64(&*buf);

    if crc_expected != crc_actual {
        warn!("blob {} failed crc check!", blob_ptr);

        Err(Error::Corruption {
            // FIXME Corruption pointer below should not have 0 as its LogId
            at: DiskPtr::Blob(0, blob_ptr),
        })
    } else {
        Ok(buf)
    }
}

pub(crate) fn write_blob(
    config: &Config,
    id: Lsn,
    data: Vec<u8>,
) -> Result<(), ()> {
    let path = config.blob_path(id);
    let mut f = std::fs::OpenOptions::new()
        .write(true)
        .create_new(true)
        .open(&path)?;

    let crc = u64_to_arr(crc64(&*data));

    f.write_all(&crc)
        .and_then(|_| f.write_all(&data))
        .map_err(|e| e.into())
}

pub(crate) fn gc_blobs(
    config: &Config,
    stable_lsn: Lsn,
) -> Result<(), ()> {
    let stable = config.blob_path(stable_lsn);
    let blob_dir = stable.parent().unwrap();
    let blobs = std::fs::read_dir(blob_dir)?;

    debug!(
        "gc_blobs removing any blob with an lsn above {}",
        stable_lsn
    );

    for blob in blobs {
        let path = blob?.path();
        let lsn_str = path.file_name().unwrap().to_str().unwrap();
        let lsn_res: std::result::Result<Lsn, _> = lsn_str.parse();

        if let Err(e) = lsn_res {
            return Err(Error::Unsupported(format!(
                "blobs directory contains \
                 unparsable path ({:?}): {}",
                path, e
            )));
        }

        let lsn = lsn_res.unwrap();

        if lsn > stable_lsn {
            warn!(
                "removing blob {:?} that has \
                 a higher lsn than our stable log: {:?}",
                path, stable
            );
            std::fs::remove_file(&path)?;
        }
    }

    Ok(())
}

pub(crate) fn remove_blob(
    id: Lsn,
    config: &Config,
) -> Result<(), ()> {
    let path = config.blob_path(id);

    if let Err(e) = std::fs::remove_file(&path) {
        warn!("removing blob at {:?} failed: {}", path, e);
    } else {
        trace!("successfully removed blob at {:?}", path);
    }

    // TODO return a future
    Ok(())
}
<commit_msg>Add logging when blobs are successfully written<commit_after>use std::io::{Read, Write};

use super::*;

pub(crate) fn read_blob(
    blob_ptr: Lsn,
    config: &Config,
) -> Result<Vec<u8>, ()> {
    let path = config.blob_path(blob_ptr);
    let mut f = std::fs::OpenOptions::new().read(true).open(&path)?;

    let mut crc_expected_bytes = [0u8; BLOB_INLINE_LEN];
    f.read_exact(&mut crc_expected_bytes).unwrap();
    let crc_expected = arr_to_u64(crc_expected_bytes);

    let mut buf = vec![];
    f.read_to_end(&mut buf)?;

    let crc_actual = crc64(&*buf);

    if crc_expected != crc_actual {
        warn!("blob {} failed crc check!", blob_ptr);

        Err(Error::Corruption {
            // FIXME Corruption pointer below should not have 0 as its LogId
            at: DiskPtr::Blob(0, blob_ptr),
        })
    } else {
        Ok(buf)
    }
}

pub(crate) fn write_blob(
    config: &Config,
    id: Lsn,
    data: Vec<u8>,
) -> Result<(), ()> {
    let path = config.blob_path(id);
    let mut f = std::fs::OpenOptions::new()
        .write(true)
        .create_new(true)
        .open(&path)?;

    let crc = u64_to_arr(crc64(&*data));

    f.write_all(&crc)
        .and_then(|_| f.write_all(&data))
        .map(|r| {
            trace!("successfully wrote blob at {:?}", path);
            r
        }).map_err(|e| e.into())
}

pub(crate) fn gc_blobs(
    config: &Config,
    stable_lsn: Lsn,
) -> Result<(), ()> {
    let stable = config.blob_path(stable_lsn);
    let blob_dir = stable.parent().unwrap();
    let blobs = std::fs::read_dir(blob_dir)?;

    debug!(
        "gc_blobs removing any blob with an lsn above {}",
        stable_lsn
    );

    for blob in blobs {
        let path = blob?.path();
        let lsn_str = path.file_name().unwrap().to_str().unwrap();
        let lsn_res: std::result::Result<Lsn, _> = lsn_str.parse();

        if let Err(e) = lsn_res {
            return Err(Error::Unsupported(format!(
                "blobs directory contains \
                 unparsable path ({:?}): {}",
                path, e
            )));
        }

        let lsn = lsn_res.unwrap();

        if lsn > stable_lsn {
            warn!(
                "removing blob {:?} that has \
                 a higher lsn than our stable log: {:?}",
                path, stable
            );
            std::fs::remove_file(&path)?;
        }
    }

    Ok(())
}

pub(crate) fn remove_blob(
    id: Lsn,
    config: &Config,
) -> Result<(), ()> {
    let path = config.blob_path(id);

    if let Err(e) = std::fs::remove_file(&path) {
        warn!("removing blob at {:?} failed: {}", path, e);
    } else {
        trace!("successfully removed blob at {:?}", path);
    }

    // TODO return a future
    Ok(())
}
<|endoftext|>


<commit_before>extern crate bf;
extern crate clap;

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

use clap::{Arg, App};

use bf::ast;
use bf::rle_ast;
use bf::flat;
use bf::peephole;
use bf::traits::Interpretable;

const VERSION: &'static str = "0.1.0";

#[derive(Debug, Clone)]
struct Options {
    program_text:  Vec<u8>,
    memory_size:   Option<usize>,
    compiler_pass: Pass,
}

#[derive(Debug, Clone, Copy)]
enum Pass {
    Ast,
    Rle,
    Flat,
    Peep,
}

fn main() {
    // Process command-line options:
    let options = get_options();

    // Parse the program to AST:
    let program = parse(&options);

    match options.compiler_pass {
        Pass::Ast => {
            interpret(&*program, &options);
        }

        Pass::Rle => {
            let program = rle_ast::compile(&program);
            interpret(&*program, &options);
        }

        Pass::Flat => {
            let program = rle_ast::compile(&program);
            let program = flat::compile(&program);
            interpret(&*program, &options);
        }

        Pass::Peep => {
            let program = rle_ast::compile(&program);
            let program = peephole::compile(&program);
            interpret(&*program, &options);
        }
    }
}

fn parse(options: &Options) -> Box<ast::Program> {
    ast::parse_program(&options.program_text)
        .unwrap_or_else(|e| error_exit(2, format!("Syntax error: {}.", e)))
}

fn interpret<P: Interpretable + ?Sized>(program: &P, options: &Options) {
    program.interpret_stdin(options.memory_size)
        .unwrap_or_else(|e| error_exit(3, format!("Runtime error: {}.", e)))
}

fn get_options() -> Options {
    let mut result = Options {
        program_text:  Vec::new(),
        memory_size:   None,
        compiler_pass: Pass::Flat,
    };

    let matches = build_clap_app().get_matches();

    if let Some(size) = matches.value_of("size") {
        let size = size.parse()
            .unwrap_or_else(|e| error_exit(1, format!("Could not parse memory size: {}", e)));
        result.memory_size = Some(size);
    }

    if matches.is_present("ast") {
        result.compiler_pass = Pass::Ast;
    } else if matches.is_present("rle") {
        result.compiler_pass = Pass::Rle;
    } else if matches.is_present("flat") {
        result.compiler_pass = Pass::Flat;
    } else if matches.is_present("peep") {
        result.compiler_pass = Pass::Peep;
    }

    if let Some(exprs) = matches.values_of("expr") {
        for e in exprs {
            result.program_text.extend(e.as_bytes());
        }
    } else if let Some(files) = matches.values_of("INPUT") {
        for f in files {
            let mut file = File::open(f)
                .unwrap_or_else(|e| error_exit(1, format!("{}: {}", e, f)));
            file.read_to_end(&mut result.program_text)
                .unwrap_or_else(|e| error_exit(1, format!("{}: {}", e, f)));
        }
    } else {
        error_exit(1, "No program given.".to_owned());
    }

    result
}

fn build_clap_app() -> App<'static, 'static> {
    App::new("bfi")
        .version(VERSION)
        .author("Jesse A. Tov <jesse.tov@gmail.com>")
        .about("A Brainfuck interpreter")
        .arg(Arg::with_name("expr")
            .short("e")
            .long("expr")
            .value_name("CODE")
            .help("BF code to execute")
            .multiple(true)
            .takes_value(true)
            .conflicts_with("INPUT"))
        .arg(Arg::with_name("INPUT")
            .help("The source file(s) to interpret")
            .multiple(true)
            .conflicts_with("expr")
            .index(1))
        .arg(Arg::with_name("size")
            .short("s")
            .long("size")
            .value_name("SIZE")
            .help("Memory size in bytes")
            .takes_value(true))
        .arg(Arg::with_name("ast")
            .long("ast")
            .help("Interpret the AST directly")
            .conflicts_with_all(&["flat", "rle", "peep"]))
        .arg(Arg::with_name("rle")
            .long("rle")
            .help("Interpret the run-length encoded AST directly")
            .conflicts_with_all(&["ast", "flat", "peep"]))
        .arg(Arg::with_name("flat")
            .long("flat")
            .help("Interpret the flattened bytecode (default)")
            .conflicts_with_all(&["ast", "rle", "peep"]))
        .arg(Arg::with_name("peep")
            .long("peep")
            .help("Interpret the peephole optimized bytecode (broken?)")
            .conflicts_with_all(&["ast", "rle", "flat"]))
}

fn error_exit(code: i32, msg: String) -> ! {
    writeln!(io::stderr(), "{}", msg).unwrap();
    exit(code)
}

<commit_msg>JIT works on mandelbrot.bf and factor.bf.<commit_after>extern crate bf;
extern crate clap;

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

use clap::{Arg, App};

use bf::ast;
use bf::rle_ast;
use bf::flat;
use bf::peephole;
use bf::jit;

use bf::traits::Interpretable;

const VERSION: &'static str = "0.1.0";

#[derive(Debug, Clone)]
struct Options {
    program_text:  Vec<u8>,
    memory_size:   Option<usize>,
    compiler_pass: Pass,
}

#[derive(Debug, Clone, Copy)]
enum Pass {
    Ast,
    Rle,
    Flat,
    Peep,
    Jit,
}

fn main() {
    // Process command-line options:
    let options = get_options();

    // Parse the program to AST:
    let program = parse(&options);

    match options.compiler_pass {
        Pass::Ast => {
            interpret(&*program, &options);
        }

        Pass::Rle => {
            let program = rle_ast::compile(&program);
            interpret(&*program, &options);
        }

        Pass::Flat => {
            let program = rle_ast::compile(&program);
            let program = flat::compile(&program);
            interpret(&*program, &options);
        }

        Pass::Peep => {
            let program = rle_ast::compile(&program);
            let program = peephole::compile(&program);
            interpret(&*program, &options);
        }

        Pass::Jit => {
            let program = rle_ast::compile(&program);
            let program = jit::compile(&program);
            interpret(&program, &options);
        }
    }
}

fn parse(options: &Options) -> Box<ast::Program> {
    ast::parse_program(&options.program_text)
        .unwrap_or_else(|e| error_exit(2, format!("Syntax error: {}.", e)))
}

fn interpret<P: Interpretable + ?Sized>(program: &P, options: &Options) {
    program.interpret_stdin(options.memory_size)
        .unwrap_or_else(|e| error_exit(3, format!("Runtime error: {}.", e)))
}

fn get_options() -> Options {
    let mut result = Options {
        program_text:  Vec::new(),
        memory_size:   None,
        compiler_pass: Pass::Flat,
    };

    let matches = build_clap_app().get_matches();

    if let Some(size) = matches.value_of("size") {
        let size = size.parse()
            .unwrap_or_else(|e| error_exit(1, format!("Could not parse memory size: {}", e)));
        result.memory_size = Some(size);
    }

    if matches.is_present("ast") {
        result.compiler_pass = Pass::Ast;
    } else if matches.is_present("rle") {
        result.compiler_pass = Pass::Rle;
    } else if matches.is_present("flat") {
        result.compiler_pass = Pass::Flat;
    } else if matches.is_present("peep") {
        result.compiler_pass = Pass::Peep;
    } else if matches.is_present("jit") {
        result.compiler_pass = Pass::Jit;
    }

    if let Some(exprs) = matches.values_of("expr") {
        for e in exprs {
            result.program_text.extend(e.as_bytes());
        }
    } else if let Some(files) = matches.values_of("INPUT") {
        for f in files {
            let mut file = File::open(f)
                .unwrap_or_else(|e| error_exit(1, format!("{}: {}", e, f)));
            file.read_to_end(&mut result.program_text)
                .unwrap_or_else(|e| error_exit(1, format!("{}: {}", e, f)));
        }
    } else {
        error_exit(1, "No program given.".to_owned());
    }

    result
}

fn build_clap_app() -> App<'static, 'static> {
    App::new("bfi")
        .version(VERSION)
        .author("Jesse A. Tov <jesse.tov@gmail.com>")
        .about("A Brainfuck interpreter")
        .arg(Arg::with_name("expr")
            .short("e")
            .long("expr")
            .value_name("CODE")
            .help("BF code to execute")
            .multiple(true)
            .takes_value(true)
            .conflicts_with("INPUT"))
        .arg(Arg::with_name("INPUT")
            .help("The source file(s) to interpret")
            .multiple(true)
            .conflicts_with("expr")
            .index(1))
        .arg(Arg::with_name("size")
            .short("s")
            .long("size")
            .value_name("SIZE")
            .help("Memory size in bytes")
            .takes_value(true))
        .arg(Arg::with_name("ast")
            .long("ast")
            .help("Interpret the AST directly")
            .conflicts_with_all(&["flat", "rle", "peep", "jit"]))
        .arg(Arg::with_name("rle")
            .long("rle")
            .help("Interpret the run-length encoded AST directly")
            .conflicts_with_all(&["ast", "flat", "peep", "jit"]))
        .arg(Arg::with_name("flat")
            .long("flat")
            .help("Interpret the flattened bytecode (default)")
            .conflicts_with_all(&["ast", "rle", "peep", "jit"]))
        .arg(Arg::with_name("peep")
            .long("peep")
            .help("Interpret the peephole optimized bytecode (broken?)")
            .conflicts_with_all(&["ast", "rle", "flat", "jit"]))
        .arg(Arg::with_name("jit")
            .long("jit")
            .help("Use native X-64 JIT")
            .conflicts_with_all(&["ast", "rle", "flat", "peep"]))
}

fn error_exit(code: i32, msg: String) -> ! {
    writeln!(io::stderr(), "{}", msg).unwrap();
    exit(code)
}

<|endoftext|>


<commit_before>//! Game Boy CPU emulation

use std::fmt::{Show, Formatter, FormatError};
use io::Interconnect;

use cpu::instructions::next_instruction;

mod instructions;

/// CPU state. Should be considered undetermined as long as
/// `Cpu::reset()` hasn't been called.
pub struct Cpu<'a> {
    // Time remaining for the current instruction to finish
    instruction_delay:   u32,
    // CPU registers (except for `F` register)
    regs:                Registers,
    // CPU flags (`F` register)
    flags:               Flags,
    // Interconnect to access external ressources (RAM, ROM, peripherals...)
    inter:               Interconnect<'a>,
}

/// CPU registers. They're 16bit wide but some of them can be accessed
/// as high and low byte.
struct Registers {
    /// 16bit Program Counter
    pc: u16,
    /// 16bit Stack Pointer
    sp: u16,
    /// 8bit `A` register
    a:  u8,
    /// 8bit `B` register
    b:  u8,
    /// 8bit `C` register
    c:  u8,
    /// 8bit `D` register
    d:  u8,
    /// 8bit `E` register
    e:  u8,
    /// 8bit `H` register
    h:  u8,
    /// 8bit `L` register
    l:  u8,
}

/// Flags contain `bool`s which are set or unset as a side effect of
/// the commands being executed. In turn, certain commands change
/// their behaviour based on the flag values.
struct Flags {
    /// Zero: set if the result of a math operation is zero or two
    /// values compare equal
    z: bool,
    /// Substract Flag: set if the last math operation performed a
    /// substraction
    n: bool,
    /// Half Carry Flag: set if a carry occurred from the lower nibble
    /// in the last math operation.
    h: bool,
    /// Carry Flag: set if a carry occured during the last math
    /// operation or if the first operand register compared smaller.
    c: bool,
}

impl<'a> Cpu<'a> {
    /// Create a new Cpu instance. The register's value should be
    /// treated as undetermined at that point so I fill them with
    /// garbage values.
    pub fn new<'n>(inter: Interconnect<'n>) -> Cpu<'n> {
        Cpu {
            instruction_delay:   0,
            regs: Registers { pc: 0xbaad,
                              sp: 0xbaad,
                              a : 0x01,
                              b : 0x23,
                              c : 0x45,
                              d : 0x67,
                              e : 0x89,
                              h : 0xcd,
                              l : 0xef,
            },
            flags: Flags { z: false,
                           n: false,
                           h: false,
                           c: false,
            },
            inter: inter,
        }
    }

    /// Reset CPU state to power up values
    pub fn reset(&mut self) {
        self.inter.reset();

        self.instruction_delay = 0;

        // Code always starts at 0x100
        self.regs.pc = 0x100;
        // Stack pointer default value
        self.regs.sp = 0xfffe;
        self.regs.a  = 0;
        self.regs.b  = 0;
        self.regs.c  = 0;
        self.regs.d  = 0;
        self.regs.e  = 0;
        self.regs.h  = 0;
        self.regs.l  = 0;

        self.clear_flags();
    }

    /// Called at each tick of the system clock. Move the emulated
    /// state one step forward.
    pub fn step(&mut self) {
        self.inter.step();

        // Are we done running the current instruction?
        if self.instruction_delay > 0 {
            // Nope, wait for the next cycle
            self.instruction_delay -= 1;
            return;
        }

        //println!("{}", *self);

        // Now we fetch the next instruction
        let (delay, instruction) = next_instruction(self);

        // Instruction delays are in CPU Machine cycles. There's 4
        // Clock cycles in one Machine cycle.
        self.instruction_delay = delay * 4 - 1;
        // Run the next instruction. This can change the entire CPU
        // state including the `instruction_delay` above (using the
        // `additional_delay` method).
        (instruction)(self);
    }

    /// Fetch byte at `addr` from the interconnect
    fn fetch_byte(&self, addr: u16) -> u8 {
        self.inter.get_byte(addr)
    }

    /// Store byte `val` at `addr` in the interconnect
    fn store_byte(&self, addr: u16, val: u8) {
        self.inter.set_byte(addr, val)
    }

    /// Certain instructions take a different amount of time to
    /// execute depending on the cpu state (conditional jumps and
    /// calls). `delay` is expressed in CPU Machine cycle, there's 4
    /// Clock cycles in one Machine cycle.
    fn additional_delay(&mut self, delay: u32) {
        self.instruction_delay += delay * 4;
    }

    /// Retrieve value of the `PC` register
    fn pc(&self) -> u16 {
        self.regs.pc
    }

    /// Set value of the `PC` register
    fn set_pc(&mut self, pc: u16) {
        self.regs.pc = pc;
    }

    /// Retrieve value of the `SP` register
    fn sp(&self) -> u16 {
        self.regs.sp
    }

    /// Set value of the `SP` register
    fn set_sp(&mut self, sp: u16) {
        self.regs.sp = sp;
    }

    /// Retrieve value of the `AF` register
    fn af(&self) -> u16 {
        let mut v = self.f() as u16;

        v |= (self.regs.a as u16) << 8;

        v
    }

    /// Set value of the `AF` register
    fn set_af(&mut self, af: u16) {
        self.regs.a = (af >> 8) as u8;
        self.set_f(af as u8);
    }

    /// Retrieve value of the `BC` register
    fn bc(&self) -> u16 {
        let mut v = self.regs.c as u16;

        v |= (self.regs.b as u16) << 8;

        v
    }

    /// Set value of the `BC` register
    fn set_bc(&mut self, bc: u16) {
        self.regs.b = (bc >> 8) as u8;
        self.regs.c = bc as u8;
    }

    /// Retrieve value of the `DE` register
    fn de(&self) -> u16 {
        let mut v = self.regs.e as u16;

        v |= (self.regs.d as u16) << 8;

        v
    }

    /// Set value of the `DE` register
    fn set_de(&mut self, de: u16) {
        self.regs.d = (de >> 8) as u8;
        self.regs.e = de as u8;
    }

    /// Retrieve value of the `HL` register
    fn hl(&self) -> u16 {
        let mut v = self.regs.l as u16;

        v |= (self.regs.h as u16) << 8;

        v
    }

    /// Set value of the `HL` register
    fn set_hl(&mut self, hl: u16) {
        self.regs.h = (hl >> 8) as u8;
        self.regs.l = hl as u8;
    }

    /// Retrieve value of the `A` register
    fn a(&self) -> u8 {
        self.regs.a
    }

    /// Set value of the `A` register
    fn set_a(&mut self, v: u8) {
        self.regs.a = v;
    }

    /// Retrieve value of the `B` register
    fn b(&self) -> u8 {
        self.regs.b
    }

    /// Set value of the `B` register
    fn set_b(&mut self, v: u8) {
        self.regs.b = v;
    }

    /// Retrieve value of the `C` register
    fn c(&self) -> u8 {
        self.regs.c
    }

    /// Set value of the `C` register
    fn set_c(&mut self, v: u8) {
        self.regs.c = v;
    }

    /// Retrieve value of the `D` register
    fn d(&self) -> u8 {
        self.regs.d
    }

    /// Set value of the `D` register
    fn set_d(&mut self, v: u8) {
        self.regs.d = v;
    }

    /// Retrieve value of the `E` register
    fn e(&self) -> u8 {
        self.regs.e
    }

    /// Set value of the `E` register
    fn set_e(&mut self, v: u8) {
        self.regs.e = v;
    }

    /// Retrieve value of the `F` register
    fn f(&self) -> u8 {
        let z = self.flags.z as u8;
        let n = self.flags.n as u8;
        let h = self.flags.h as u8;
        let c = self.flags.c as u8;

        (z << 7) | (n << 6) | ( h << 5) | (c << 4)
    }

    /// Set value of the `F` register
    fn set_f(&mut self, v: u8) {
        self.flags.z = (v & (1 << 7)) != 0;
        self.flags.n = (v & (1 << 6)) != 0;
        self.flags.h = (v & (1 << 5)) != 0;
        self.flags.c = (v & (1 << 4)) != 0;
    }

    /// Retrieve value of the `H` register
    fn h(&self) -> u8 {
        self.regs.h
    }

    /// Set value of the `H` register
    fn set_h(&mut self, v: u8) {
        self.regs.h = v;
    }

    /// Retrieve value of the `L` register
    fn l(&self) -> u8 {
        self.regs.l
    }

    /// Set value of the `L` register
    fn set_l(&mut self, v: u8) {
        self.regs.l = v;
    }

    /// Clear all flags
    fn clear_flags(&mut self) {
        self.flags.z = false;
        self.flags.n = false;
        self.flags.h = false;
        self.flags.c = false;
    }

    /// Get value of 'Z' flag
    fn zero(&self) -> bool {
        self.flags.z
    }

    /// set value of 'Z' flag
    fn set_zero(&mut self, s: bool) {
        self.flags.z = s;
    }

    /// Get value of 'C' flag
    fn carry(&self) -> bool {
        self.flags.c
    }

    /// Set value of 'C' flag
    fn set_carry(&mut self, s: bool) {
        self.flags.c = s;
    }

    /// Set value of 'H' flag
    fn set_halfcarry(&mut self, s: bool) {
        self.flags.h = s;
    }

    /// Set value of 'N' flag
    fn set_substract(&mut self, s: bool) {
        self.flags.n = s;
    }

    /// Disable Interrupts
    fn disable_interrupts(&mut self) {
        // TODO
    }

    /// Enable Interrupts
    fn enable_interrupts(&mut self) {
        // TODO
    }

    /// Halt and wait for interrupts
    fn halt(&mut self) {
        // TODO (also, check if interrupts are enabled)
    }
}

impl<'a> Show for Cpu<'a> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
        try!(writeln!(f, "Registers:"));

        try!(writeln!(f, "  pc: 0x{:04x} [{:02X}]",
                      self.pc(), self.fetch_byte(self.pc())));
        try!(writeln!(f, "  sp: 0x{:04x}", self.sp()));
        try!(writeln!(f, "  af: 0x{:04x}    a: {:3u}    f: {:3u}",
                      self.af(), self.a(), self.f()));
        try!(writeln!(f, "  bc: 0x{:04x}    b: {:3u}    c: {:3u}",
                      self.bc(), self.b(), self.c()));
        try!(writeln!(f, "  de: 0x{:04x}    d: {:3u}    d: {:3u}",
                      self.de(), self.d(), self.e()));
        try!(writeln!(f, "  hl: 0x{:04x}    h: {:3u}    l: {:3u}",
                      self.hl(), self.h(), self.l()));

        try!(writeln!(f, "Flags:"));

        try!(writeln!(f, "  z: {}  n: {}  h: {}  c: {}",
                      self.flags.z as int,
                      self.flags.n as int,
                      self.flags.h as int,
                      self.flags.c as int));

        Ok(())
    }
}
<commit_msg>Change power up values for CPU registers<commit_after>//! Game Boy CPU emulation

use std::fmt::{Show, Formatter, FormatError};
use io::Interconnect;

use cpu::instructions::next_instruction;

mod instructions;

/// CPU state. Should be considered undetermined as long as
/// `Cpu::reset()` hasn't been called.
pub struct Cpu<'a> {
    // Time remaining for the current instruction to finish
    instruction_delay:   u32,
    // CPU registers (except for `F` register)
    regs:                Registers,
    // CPU flags (`F` register)
    flags:               Flags,
    // Interconnect to access external ressources (RAM, ROM, peripherals...)
    inter:               Interconnect<'a>,
}

/// CPU registers. They're 16bit wide but some of them can be accessed
/// as high and low byte.
struct Registers {
    /// 16bit Program Counter
    pc: u16,
    /// 16bit Stack Pointer
    sp: u16,
    /// 8bit `A` register
    a:  u8,
    /// 8bit `B` register
    b:  u8,
    /// 8bit `C` register
    c:  u8,
    /// 8bit `D` register
    d:  u8,
    /// 8bit `E` register
    e:  u8,
    /// 8bit `H` register
    h:  u8,
    /// 8bit `L` register
    l:  u8,
}

/// Flags contain `bool`s which are set or unset as a side effect of
/// the commands being executed. In turn, certain commands change
/// their behaviour based on the flag values.
struct Flags {
    /// Zero: set if the result of a math operation is zero or two
    /// values compare equal
    z: bool,
    /// Substract Flag: set if the last math operation performed a
    /// substraction
    n: bool,
    /// Half Carry Flag: set if a carry occurred from the lower nibble
    /// in the last math operation.
    h: bool,
    /// Carry Flag: set if a carry occured during the last math
    /// operation or if the first operand register compared smaller.
    c: bool,
}

impl<'a> Cpu<'a> {
    /// Create a new Cpu instance and reset it
    pub fn new<'n>(inter: Interconnect<'n>) -> Cpu<'n> {
        let mut cpu = Cpu {
            instruction_delay:    0,
            regs: Registers { pc: 0,
                              sp: 0,
                              a : 0,
                              b : 0,
                              c : 0,
                              d : 0,
                              e : 0,
                              h : 0,
                              l : 0,
            },
            flags: Flags { z: false,
                           n: false,
                           h: false,
                           c: false,
            },
            inter: inter,
        };

        cpu.reset();

        cpu
    }

    /// Reset CPU state to power up values
    pub fn reset(&mut self) {
        self.inter.reset();

        self.instruction_delay = 0;

        // Code always starts at 0x100
        self.regs.pc = 0x100;
        // Values after ROM execution as pulled from the unofficial GB
        // CPU manual. Of course the program shouldn't rely on those
        // values, but who knows...
        self.regs.sp = 0xfffe;
        self.regs.a  = 0x01;
        self.regs.b  = 0x00;
        self.regs.c  = 0x13;
        self.regs.d  = 0x00;
        self.regs.e  = 0xd8;
        self.regs.h  = 0x01;
        self.regs.l  = 0x4D;

        self.set_zero(true);
        self.set_substract(false);
        self.set_halfcarry(true);
        self.set_carry(true);

        self.clear_flags();
    }

    /// Called at each tick of the system clock. Move the emulated
    /// state one step forward.
    pub fn step(&mut self) {
        self.inter.step();

        // Are we done running the current instruction?
        if self.instruction_delay > 0 {
            // Nope, wait for the next cycle
            self.instruction_delay -= 1;
            return;
        }

        //println!("{}", *self);

        // Now we fetch the next instruction
        let (delay, instruction) = next_instruction(self);

        // Instruction delays are in CPU Machine cycles. There's 4
        // Clock cycles in one Machine cycle.
        self.instruction_delay = delay * 4 - 1;
        // Run the next instruction. This can change the entire CPU
        // state including the `instruction_delay` above (using the
        // `additional_delay` method).
        (instruction)(self);
    }

    /// Fetch byte at `addr` from the interconnect
    fn fetch_byte(&self, addr: u16) -> u8 {
        self.inter.get_byte(addr)
    }

    /// Store byte `val` at `addr` in the interconnect
    fn store_byte(&self, addr: u16, val: u8) {
        self.inter.set_byte(addr, val)
    }

    /// Certain instructions take a different amount of time to
    /// execute depending on the cpu state (conditional jumps and
    /// calls). `delay` is expressed in CPU Machine cycle, there's 4
    /// Clock cycles in one Machine cycle.
    fn additional_delay(&mut self, delay: u32) {
        self.instruction_delay += delay * 4;
    }

    /// Retrieve value of the `PC` register
    fn pc(&self) -> u16 {
        self.regs.pc
    }

    /// Set value of the `PC` register
    fn set_pc(&mut self, pc: u16) {
        self.regs.pc = pc;
    }

    /// Retrieve value of the `SP` register
    fn sp(&self) -> u16 {
        self.regs.sp
    }

    /// Set value of the `SP` register
    fn set_sp(&mut self, sp: u16) {
        self.regs.sp = sp;
    }

    /// Retrieve value of the `AF` register
    fn af(&self) -> u16 {
        let mut v = self.f() as u16;

        v |= (self.regs.a as u16) << 8;

        v
    }

    /// Set value of the `AF` register
    fn set_af(&mut self, af: u16) {
        self.regs.a = (af >> 8) as u8;
        self.set_f(af as u8);
    }

    /// Retrieve value of the `BC` register
    fn bc(&self) -> u16 {
        let mut v = self.regs.c as u16;

        v |= (self.regs.b as u16) << 8;

        v
    }

    /// Set value of the `BC` register
    fn set_bc(&mut self, bc: u16) {
        self.regs.b = (bc >> 8) as u8;
        self.regs.c = bc as u8;
    }

    /// Retrieve value of the `DE` register
    fn de(&self) -> u16 {
        let mut v = self.regs.e as u16;

        v |= (self.regs.d as u16) << 8;

        v
    }

    /// Set value of the `DE` register
    fn set_de(&mut self, de: u16) {
        self.regs.d = (de >> 8) as u8;
        self.regs.e = de as u8;
    }

    /// Retrieve value of the `HL` register
    fn hl(&self) -> u16 {
        let mut v = self.regs.l as u16;

        v |= (self.regs.h as u16) << 8;

        v
    }

    /// Set value of the `HL` register
    fn set_hl(&mut self, hl: u16) {
        self.regs.h = (hl >> 8) as u8;
        self.regs.l = hl as u8;
    }

    /// Retrieve value of the `A` register
    fn a(&self) -> u8 {
        self.regs.a
    }

    /// Set value of the `A` register
    fn set_a(&mut self, v: u8) {
        self.regs.a = v;
    }

    /// Retrieve value of the `B` register
    fn b(&self) -> u8 {
        self.regs.b
    }

    /// Set value of the `B` register
    fn set_b(&mut self, v: u8) {
        self.regs.b = v;
    }

    /// Retrieve value of the `C` register
    fn c(&self) -> u8 {
        self.regs.c
    }

    /// Set value of the `C` register
    fn set_c(&mut self, v: u8) {
        self.regs.c = v;
    }

    /// Retrieve value of the `D` register
    fn d(&self) -> u8 {
        self.regs.d
    }

    /// Set value of the `D` register
    fn set_d(&mut self, v: u8) {
        self.regs.d = v;
    }

    /// Retrieve value of the `E` register
    fn e(&self) -> u8 {
        self.regs.e
    }

    /// Set value of the `E` register
    fn set_e(&mut self, v: u8) {
        self.regs.e = v;
    }

    /// Retrieve value of the `F` register
    fn f(&self) -> u8 {
        let z = self.flags.z as u8;
        let n = self.flags.n as u8;
        let h = self.flags.h as u8;
        let c = self.flags.c as u8;

        (z << 7) | (n << 6) | ( h << 5) | (c << 4)
    }

    /// Set value of the `F` register
    fn set_f(&mut self, v: u8) {
        self.flags.z = (v & (1 << 7)) != 0;
        self.flags.n = (v & (1 << 6)) != 0;
        self.flags.h = (v & (1 << 5)) != 0;
        self.flags.c = (v & (1 << 4)) != 0;
    }

    /// Retrieve value of the `H` register
    fn h(&self) -> u8 {
        self.regs.h
    }

    /// Set value of the `H` register
    fn set_h(&mut self, v: u8) {
        self.regs.h = v;
    }

    /// Retrieve value of the `L` register
    fn l(&self) -> u8 {
        self.regs.l
    }

    /// Set value of the `L` register
    fn set_l(&mut self, v: u8) {
        self.regs.l = v;
    }

    /// Clear all flags
    fn clear_flags(&mut self) {
        self.flags.z = false;
        self.flags.n = false;
        self.flags.h = false;
        self.flags.c = false;
    }

    /// Get value of 'Z' flag
    fn zero(&self) -> bool {
        self.flags.z
    }

    /// set value of 'Z' flag
    fn set_zero(&mut self, s: bool) {
        self.flags.z = s;
    }

    /// Get value of 'C' flag
    fn carry(&self) -> bool {
        self.flags.c
    }

    /// Set value of 'C' flag
    fn set_carry(&mut self, s: bool) {
        self.flags.c = s;
    }

    /// Set value of 'H' flag
    fn set_halfcarry(&mut self, s: bool) {
        self.flags.h = s;
    }

    /// Set value of 'N' flag
    fn set_substract(&mut self, s: bool) {
        self.flags.n = s;
    }

    /// Disable Interrupts
    fn disable_interrupts(&mut self) {
        // TODO
    }

    /// Enable Interrupts
    fn enable_interrupts(&mut self) {
        // TODO
    }

    /// Halt and wait for interrupts
    fn halt(&mut self) {
        // TODO (also, check if interrupts are enabled)
    }
}

impl<'a> Show for Cpu<'a> {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
        try!(writeln!(f, "Registers:"));

        try!(writeln!(f, "  pc: 0x{:04x} [{:02X}]",
                      self.pc(), self.fetch_byte(self.pc())));
        try!(writeln!(f, "  sp: 0x{:04x}", self.sp()));
        try!(writeln!(f, "  af: 0x{:04x}    a: {:3u}    f: {:3u}",
                      self.af(), self.a(), self.f()));
        try!(writeln!(f, "  bc: 0x{:04x}    b: {:3u}    c: {:3u}",
                      self.bc(), self.b(), self.c()));
        try!(writeln!(f, "  de: 0x{:04x}    d: {:3u}    d: {:3u}",
                      self.de(), self.d(), self.e()));
        try!(writeln!(f, "  hl: 0x{:04x}    h: {:3u}    l: {:3u}",
                      self.hl(), self.h(), self.l()));

        try!(writeln!(f, "Flags:"));

        try!(writeln!(f, "  z: {}  n: {}  h: {}  c: {}",
                      self.flags.z as int,
                      self.flags.n as int,
                      self.flags.h as int,
                      self.flags.c as int));

        Ok(())
    }
}
<|endoftext|>


<commit_before>// MRustC custom version of libproc_macro
//
// Unlike the original rustc version, this one is designed to live complely detached from its compiler.

macro_rules! some_else {
    ($e:expr => $alt:expr) => {match $e { Some(v) => v, None => $alt }};
}

macro_rules! debug {
    ( $($t:tt)* ) => {
        if ::std::env::var_os("MRUSTC_PM_DEBUG").is_some() {
            eprintln!($($t)*)
        }
    }
}
macro_rules! note {
    ( $($t:tt)* ) => {
        if ::std::env::var_os("MRUSTC_PM_DEBUG").is_some() {
            eprintln!($($t)*)
        }
    }
}

mod span;
mod token_tree;
/// Parse a TokenStream from a string
mod lex;
/// Raw IPC protocol
mod protocol;
/// Converts to/from TokenStream and IPC
mod serialisation;

mod token_stream {

    #[derive(Debug,Clone,Default)]
    pub struct TokenStream {
        pub(crate) inner: Vec<crate::TokenTree>,
    }

    #[derive(Clone)]
    pub struct IntoIter {
        it: ::std::vec::IntoIter<crate::TokenTree>,
    }
    impl Iterator for IntoIter {
        type Item = crate::TokenTree;
        fn next(&mut self) -> Option<crate::TokenTree> {
            self.it.next()
        }
    }

    impl TokenStream {
        // 1.29
        pub fn new() -> TokenStream {
            TokenStream {
                inner: Vec::new(),
            }
        }
        // 1.29
        pub fn is_empty(&self) -> bool {
            self.inner.is_empty()
        }
    }

    // 1.29
    impl IntoIterator for TokenStream
    {
        type Item = super::TokenTree;
        type IntoIter = IntoIter;
        fn into_iter(self) -> IntoIter {
            IntoIter {
                it: self.inner.into_iter(),
            }
        }
    }

    //impl ::std::string::ToString for TokenStream
    //{
    //    fn to_string(&self) -> String {
    //        use std::fmt::Write;
    //        let mut s = String::new();
    //        for v in &self.inner
    //        {
    //            write!(&mut s, "{}", v).unwrap();
    //        }
    //        s
    //    }
    //}
    impl ::std::fmt::Display for TokenStream
    {
        fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
            for v in &self.inner
            {
                write!(f, "{}", v)?;
                // Put a space after every token that isn't punctuation
                if let crate::TokenTree::Punct(_) = v {
                }
                else {
                    write!(f, " ")?;
                }
            }
            Ok(())
        }
    }

    // 1.29.0
    impl From<crate::TokenTree> for TokenStream
    {
        fn from(t: crate::TokenTree) -> TokenStream {
            TokenStream {
                inner: vec![t],
            }
        }
    }

    impl ::std::iter::FromIterator<TokenStream> for TokenStream
    {
        fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self
        {
            let mut rv = TokenStream::new();
            rv.extend(streams);
            rv
        }
    }
    impl ::std::iter::FromIterator<crate::TokenTree> for TokenStream
    {
        fn from_iter<I: IntoIterator<Item = crate::TokenTree>>(tokens: I) -> Self
        {
            let mut rv = TokenStream::new();
            rv.extend(tokens);
            rv
        }
    }

    // 1.30
    impl ::std::iter::Extend<TokenStream> for TokenStream
    {
        fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
            for i in streams {
                self.inner.extend(i.inner.into_iter())
            }
        }
    }
    // 1.30
    impl ::std::iter::Extend<crate::TokenTree> for TokenStream
    {
        fn extend<I: IntoIterator<Item = crate::TokenTree>>(&mut self, trees: I)
        {
            self.inner.extend(trees)
        }
    }
}

pub use crate::span::Span;

pub use crate::token_stream::TokenStream;

pub use crate::token_tree::{TokenTree,Group,Ident,Punct,Literal};
pub use crate::token_tree::{Delimiter,Spacing};

pub use crate::lex::LexError;

#[doc(hidden)]
pub struct MacroDesc
{
    name: &'static str,
    handler: fn(TokenStream)->TokenStream,
}

#[doc(hidden)]
pub fn main(macros: &[MacroDesc])
{
    //::env_logger::init();

    let mac_name = ::std::env::args().nth(1).expect("Was not passed a macro name");
    //eprintln!("Searching for macro {}\r", mac_name);
    for m in macros
    {
        if m.name == mac_name {
            use std::io::Write;
            ::std::io::stdout().write(&[0]).expect("Stdout write error?");
            ::std::io::stdout().flush().expect("Stdout write error?");
            debug!("Waiting for input\r");
            let input = crate::serialisation::recv_token_stream(::std::io::stdin().lock());
            debug!("INPUT = `{}`\r", input);
            let output = (m.handler)( input );
            debug!("OUTPUT = `{}`\r", output);
            crate::serialisation::send_token_stream(::std::io::stdout().lock(), output);
            ::std::io::Write::flush(&mut ::std::io::stdout()).expect("Stdout write error?");
            note!("Done");
            return ;
        }
    }
    panic!("Unknown macro name '{}'", mac_name);
}

<commit_msg>libproc_macro - Fix 1.19 incompatibility<commit_after>// MRustC custom version of libproc_macro
//
// Unlike the original rustc version, this one is designed to live complely detached from its compiler.

macro_rules! some_else {
    ($e:expr => $alt:expr) => {match $e { Some(v) => v, None => $alt }};
}

macro_rules! debug {
    ( $($t:tt)* ) => {
        if ::std::env::var_os("MRUSTC_PM_DEBUG").is_some() {
            eprintln!($($t)*)
        }
    }
}
macro_rules! note {
    ( $($t:tt)* ) => {
        if ::std::env::var_os("MRUSTC_PM_DEBUG").is_some() {
            eprintln!($($t)*)
        }
    }
}

mod span;
mod token_tree;
/// Parse a TokenStream from a string
mod lex;
/// Raw IPC protocol
mod protocol;
/// Converts to/from TokenStream and IPC
mod serialisation;

mod token_stream {

    #[derive(Debug,Clone,Default)]
    pub struct TokenStream {
        pub(crate) inner: Vec<crate::TokenTree>,
    }

    #[derive(Clone)]
    pub struct IntoIter {
        it: ::std::vec::IntoIter<crate::TokenTree>,
    }
    impl Iterator for IntoIter {
        type Item = crate::TokenTree;
        fn next(&mut self) -> Option<crate::TokenTree> {
            self.it.next()
        }
    }

    impl TokenStream {
        // 1.29
        pub fn new() -> TokenStream {
            TokenStream {
                inner: Vec::new(),
            }
        }
        // 1.29
        pub fn is_empty(&self) -> bool {
            self.inner.is_empty()
        }
    }

    // 1.29
    impl IntoIterator for TokenStream
    {
        type Item = super::TokenTree;
        type IntoIter = IntoIter;
        fn into_iter(self) -> IntoIter {
            IntoIter {
                it: self.inner.into_iter(),
            }
        }
    }

    //impl ::std::string::ToString for TokenStream
    //{
    //    fn to_string(&self) -> String {
    //        use std::fmt::Write;
    //        let mut s = String::new();
    //        for v in &self.inner
    //        {
    //            write!(&mut s, "{}", v).unwrap();
    //        }
    //        s
    //    }
    //}
    impl ::std::fmt::Display for TokenStream
    {
        fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
            for v in &self.inner
            {
                write!(f, "{}", v)?;
                // Put a space after every token that isn't punctuation
                if let &crate::TokenTree::Punct(_) = v {
                }
                else {
                    write!(f, " ")?;
                }
            }
            Ok(())
        }
    }

    // 1.29.0
    impl From<crate::TokenTree> for TokenStream
    {
        fn from(t: crate::TokenTree) -> TokenStream {
            TokenStream {
                inner: vec![t],
            }
        }
    }

    impl ::std::iter::FromIterator<TokenStream> for TokenStream
    {
        fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self
        {
            let mut rv = TokenStream::new();
            rv.extend(streams);
            rv
        }
    }
    impl ::std::iter::FromIterator<crate::TokenTree> for TokenStream
    {
        fn from_iter<I: IntoIterator<Item = crate::TokenTree>>(tokens: I) -> Self
        {
            let mut rv = TokenStream::new();
            rv.extend(tokens);
            rv
        }
    }

    // 1.30
    impl ::std::iter::Extend<TokenStream> for TokenStream
    {
        fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) {
            for i in streams {
                self.inner.extend(i.inner.into_iter())
            }
        }
    }
    // 1.30
    impl ::std::iter::Extend<crate::TokenTree> for TokenStream
    {
        fn extend<I: IntoIterator<Item = crate::TokenTree>>(&mut self, trees: I)
        {
            self.inner.extend(trees)
        }
    }
}

pub use crate::span::Span;

pub use crate::token_stream::TokenStream;

pub use crate::token_tree::{TokenTree,Group,Ident,Punct,Literal};
pub use crate::token_tree::{Delimiter,Spacing};

pub use crate::lex::LexError;

#[doc(hidden)]
pub struct MacroDesc
{
    name: &'static str,
    handler: fn(TokenStream)->TokenStream,
}

#[doc(hidden)]
pub fn main(macros: &[MacroDesc])
{
    //::env_logger::init();

    let mac_name = ::std::env::args().nth(1).expect("Was not passed a macro name");
    //eprintln!("Searching for macro {}\r", mac_name);
    for m in macros
    {
        if m.name == mac_name {
            use std::io::Write;
            ::std::io::stdout().write(&[0]).expect("Stdout write error?");
            ::std::io::stdout().flush().expect("Stdout write error?");
            debug!("Waiting for input\r");
            let input = crate::serialisation::recv_token_stream(::std::io::stdin().lock());
            debug!("INPUT = `{}`\r", input);
            let output = (m.handler)( input );
            debug!("OUTPUT = `{}`\r", output);
            crate::serialisation::send_token_stream(::std::io::stdout().lock(), output);
            ::std::io::Write::flush(&mut ::std::io::stdout()).expect("Stdout write error?");
            note!("Done");
            return ;
        }
    }
    panic!("Unknown macro name '{}'", mac_name);
}

<|endoftext|>


<commit_before>// Copyright 2015 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.
extern crate zmq;
extern crate tempfile;

use zmq::{Error, SNDMORE};
use backend::{Backend, DEFAULT_DB_ADDRESS};
use data::{Task, TaskReport, Service};

use std::thread;
use std::sync::Arc;
use std::sync::Mutex;

use std::ops::Deref;
use std::collections::HashMap;

use std::path::Path;
use std::fs::File;
// use tempfile::TempFile;
use std::io::{Write};
use std::io::Read;

pub struct TaskManager {
  pub source_port : usize,
  pub result_port : usize,
  pub queue_size : usize,
  pub message_size : usize,
  pub backend_address : String
}
pub struct Server {
  pub port : usize,
  pub queue_size : usize,
  pub message_size : usize,
  pub backend : Backend
}

impl Default for TaskManager {
  fn default() -> TaskManager {
    TaskManager {
        source_port : 5555,
        result_port : 5555,
        queue_size : 100,
        message_size : 100000,
        backend_address : DEFAULT_DB_ADDRESS.clone().to_string()
    } } }

impl TaskManager {
  pub fn start<'manager>(&'manager self) -> Result<(), Error> {
    // We'll use some local memoization shared between source and sink:
    let services: HashMap<String, Option<Service>> = HashMap::new();
    let progress_queue: HashMap<i64, Task> = HashMap::new();
    let done_queue: Vec<TaskReport> = Vec::new();

    let services_arc = Arc::new(Mutex::new(services));
    let progress_queue_arc = Arc::new(Mutex::new(progress_queue));
    let done_queue_arc = Arc::new(Mutex::new(done_queue));

    // First prepare the source ventilator
    let source_port = self.source_port.clone();
    let source_queue_size = self.queue_size.clone();
    let source_message_size = self.message_size.clone();
    let source_backend_address = self.backend_address.clone();

    let vent_services_arc = services_arc.clone();
    let vent_progress_queue_arc = progress_queue_arc.clone();
    let vent_thread = thread::spawn(move || {
      let sources = Server {
        port : source_port,
        queue_size : source_queue_size,
        message_size : source_message_size,
        backend : Backend::from_address(&source_backend_address)
      };
      sources.start_ventilator(vent_services_arc, vent_progress_queue_arc).unwrap();
    });

    // Next prepare the finalize thread which will persist finished jobs to the DB
    let finalize_backend_address = self.backend_address.clone();
    let finalize_done_queue_arc = done_queue_arc.clone();
    let finalize_thread = thread::spawn(move || {
      let finalize_backend = Backend::from_address(&finalize_backend_address);
      // Persist every 1 second, if there is something to record
      loop {
        thread::sleep_ms(1000);
        Server::mark_done_arc(&finalize_backend, &finalize_done_queue_arc);
      };
    });

    // Now prepare the results sink
    let result_port = self.result_port.clone();
    let result_queue_size = self.queue_size.clone();
    let result_message_size = self.message_size.clone();
    let result_backend_address = self.backend_address.clone();

    let sink_services_arc = services_arc.clone();
    let sink_progress_queue_arc = progress_queue_arc.clone();

    let sink_done_queue_arc = done_queue_arc.clone();
    let sink_thread = thread::spawn(move || {
      let results = Server {
        port : result_port,
        queue_size : result_queue_size,
        message_size : result_message_size,
        backend : Backend::from_address(&result_backend_address)
      };
      results.start_sink(sink_services_arc, sink_progress_queue_arc, sink_done_queue_arc).unwrap();
    });

    vent_thread.join().unwrap();
    sink_thread.join().unwrap();
    finalize_thread.join().unwrap();
    Ok(())
  }
}

impl Server {
  pub fn start_ventilator(&self,
      services_arc : Arc<Mutex<HashMap<String, Option<Service>>>>,
      progress_queue_arc : Arc<Mutex<HashMap<i64, Task>>>)
      -> Result <(),Error> {
    // We have a Ventilator-exclusive "queues" stack for tasks to be dispatched
    let mut queues : HashMap<String, Vec<Task>> = HashMap::new();
    // Assuming this is the only And tidy up the postgres tasks:
    self.backend.clear_limbo_tasks().unwrap();
    // Ok, let's bind to a port and start broadcasting
    let mut context = zmq::Context::new();
    let mut ventilator = context.socket(zmq::ROUTER).unwrap();
    let port_str = self.port.to_string();
    let address = "tcp://*:".to_string() + &port_str;
    assert!(ventilator.bind(&address).is_ok());
    let mut source_job_count = 0;

    loop {
      let mut msg = zmq::Message::new().unwrap();
      let mut identity = zmq::Message::new().unwrap();
      ventilator.recv(&mut identity, 0).unwrap();
      ventilator.recv(&mut msg, 0).unwrap();
      let service_name = msg.as_str().unwrap().to_string();
      println!("Task requested for service: {}", service_name.clone());
      source_job_count += 1;

      let mut dispatched_task : Option<Task> = None;
      match self.get_sync_service_record(&services_arc, service_name.clone()) {
        None => {},
        Some(service) => {
          if !queues.contains_key(&service_name) {
            queues.insert(service_name.clone(), Vec::new());
          }
          let mut task_queue : &mut Vec<Task> = queues.get_mut(&service_name).unwrap();
          if task_queue.is_empty() {
            task_queue.extend(self.backend.fetch_tasks(&service, self.queue_size).unwrap()); }
          match task_queue.pop() {
            Some(current_task) => {
              let taskid = current_task.id.unwrap();
              let file_opt = service.prepare_input_stream(current_task.clone());
              if file_opt.is_ok() {
                let mut file = file_opt.unwrap();
                dispatched_task = Some(current_task);

                ventilator.send_msg(identity, SNDMORE).unwrap();
                ventilator.send_str(&taskid.to_string(), SNDMORE).unwrap();

                let mut total_outgoing = 0;
                loop {
                  // Stream input data via zmq
                  let mut data = vec![0; self.message_size];
                  let size = file.read(&mut data).unwrap();
                  total_outgoing += size;
                  data.truncate(size);

                  if size < self.message_size {
                    // If exhausted, send the last frame
                    ventilator.send(&data,0).unwrap();
                    // And terminate
                    break;
                  } else {
                    // If more to go, send the frame and indicate there's more to come
                    ventilator.send(&data,SNDMORE).unwrap();
                  }
                }
                println!("Source job {}, message size: {}", source_job_count, total_outgoing);
              } else {
                // TODO: smart handling of failures
              }
            },
            None => {}
          };
        }
      };
      // Record that a task has been dispatched in the progress queue
      if dispatched_task.is_some() {
        Server::push_progress_task(&progress_queue_arc, dispatched_task.unwrap());
      }
    }
  }

  pub fn start_sink(&self,
      services_arc : Arc<Mutex<HashMap<String, Option<Service>>>>,
      progress_queue_arc : Arc<Mutex<HashMap<i64, Task>>>,
      done_queue_arc : Arc<Mutex<Vec<TaskReport>>>)
      -> Result <(),Error> {

    // Ok, let's bind to a port and start broadcasting
    let mut context = zmq::Context::new();
    let mut sink = context.socket(zmq::PULL).unwrap();
    let port_str = self.port.to_string();
    let address = "tcp://*:".to_string() + &port_str;
    assert!(sink.bind(&address).is_ok());

    let mut sink_job_count = 0;

    loop {
      let mut recv_msg = zmq::Message::new().unwrap();
      let mut taskid_msg = zmq::Message::new().unwrap();
      let mut service_msg = zmq::Message::new().unwrap();

      sink.recv(&mut service_msg, 0).unwrap();
      let service_name = service_msg.as_str().unwrap();

      sink.recv(&mut taskid_msg, 0).unwrap();
      let taskid_str = taskid_msg.as_str().unwrap();
      let taskid = taskid_str.parse::<i64>().unwrap();
      // We have a job, count it
      sink_job_count += 1;
      let mut total_incoming = 0;

      match Server::pop_progress_task(&progress_queue_arc, taskid) {
        None => {} // TODO: No such task, what to do?
        Some(task) => {

          // println!("{:?}", task);
          let service_option = Server::get_service_record(&services_arc, service_name.to_string());
          match service_option.clone() {
            None => {}, // TODO: Handle errors
            Some(service) => {
              // println!("Service: {:?}", service);
              if service.id.unwrap() == task.serviceid {
                // println!("Task and Service match up.");

                // Receive the rest of the input in the correct file
                let recv_dir = Path::new(&task.entry).parent().unwrap();
                let recv_pathname = recv_dir.to_str().unwrap().to_string() + "/" + &service.name + "_" + &service.version.round().to_string() + ".zip";
                let recv_path = Path::new(&recv_pathname);
                // println!("Will write to {:?}", recv_path);
                let mut file = File::create(recv_path).unwrap();
                loop {
                  sink.recv(&mut recv_msg, 0).unwrap();

                  total_incoming += file.write(recv_msg.deref()).unwrap();
                  if !sink.get_rcvmore().unwrap() {
                    break;
                  }
                }
                // Then mark the task done. This can be in a new thread later on
                let done_report = task.generate_report(recv_path);
                Server::push_done_queue(&done_queue_arc, done_report);
              }
              else {
                // Otherwise just discard the rest of the message
                loop {
                  sink.recv(&mut recv_msg, 0).unwrap();
                  if !sink.get_rcvmore().unwrap() {
                    break;
                  }
                }
              }
            }
          };
        }
      }
      println!("Sink job {}, message size: {}", sink_job_count, total_incoming);

      // let mut file = File::create("/tmp/cortex_sink_".to_string() + &sink_job_count.to_string()).unwrap();
      // file.write_all(&payload).unwrap();
    }
  }

  fn get_sync_service_record(&self, services_arc : &Arc<Mutex<HashMap<String, Option<Service>>>>, service_name : String) -> Option<Service> {
    let mut services = services_arc.lock().unwrap();
    let service_record = services.entry(service_name.clone()).or_insert(
      Service::from_name(&self.backend.connection, service_name.clone()).unwrap()).clone();
    service_record
  }

  fn get_service_record(services_arc : &Arc<Mutex<HashMap<String, Option<Service>>>>, service_name : String) -> Option<Service> {
    let services = services_arc.lock().unwrap();
    let service_record = services.get(&service_name);
    match service_record {
      None => None, // TODO: Handle errors
      Some(service_option) => service_option.clone()
    }
  }

  pub fn mark_done_arc(backend : &Backend, reports_arc: &Arc<Mutex<Vec<TaskReport>>>) {
    let mut reports = reports_arc.lock().unwrap();
    if reports.len() > 0 {
      backend.mark_done(&reports).unwrap(); // TODO: error handling if DB fails
      reports.clear();
    }
  }
  pub fn push_done_queue(reports_arc : &Arc<Mutex<Vec<TaskReport>>>, report : TaskReport) {
    let mut reports = reports_arc.lock().unwrap();
    reports.push(report)
  }

  fn pop_progress_task(progress_queue_arc : &Arc<Mutex<HashMap<i64, Task>>>, taskid: i64) -> Option<Task> {
    let mut progress_queue = progress_queue_arc.lock().unwrap();
    progress_queue.remove(&taskid)
  }

  fn push_progress_task(progress_queue_arc : &Arc<Mutex<HashMap<i64, Task>>>, progress_task: Task) {
    let mut progress_queue = progress_queue_arc.lock().unwrap();
    progress_queue.insert(progress_task.id.unwrap(), progress_task);
  }
}<commit_msg>sleep only when necessary<commit_after>// Copyright 2015 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.
extern crate zmq;
extern crate tempfile;

use zmq::{Error, SNDMORE};
use backend::{Backend, DEFAULT_DB_ADDRESS};
use data::{Task, TaskReport, Service};

use std::thread;
use std::sync::Arc;
use std::sync::Mutex;

use std::ops::Deref;
use std::collections::HashMap;

use std::path::Path;
use std::fs::File;
// use tempfile::TempFile;
use std::io::{Write};
use std::io::Read;

pub struct TaskManager {
  pub source_port : usize,
  pub result_port : usize,
  pub queue_size : usize,
  pub message_size : usize,
  pub backend_address : String
}
pub struct Server {
  pub port : usize,
  pub queue_size : usize,
  pub message_size : usize,
  pub backend : Backend
}

impl Default for TaskManager {
  fn default() -> TaskManager {
    TaskManager {
        source_port : 5555,
        result_port : 5555,
        queue_size : 100,
        message_size : 100000,
        backend_address : DEFAULT_DB_ADDRESS.clone().to_string()
    } } }

impl TaskManager {
  pub fn start<'manager>(&'manager self) -> Result<(), Error> {
    // We'll use some local memoization shared between source and sink:
    let services: HashMap<String, Option<Service>> = HashMap::new();
    let progress_queue: HashMap<i64, Task> = HashMap::new();
    let done_queue: Vec<TaskReport> = Vec::new();

    let services_arc = Arc::new(Mutex::new(services));
    let progress_queue_arc = Arc::new(Mutex::new(progress_queue));
    let done_queue_arc = Arc::new(Mutex::new(done_queue));

    // First prepare the source ventilator
    let source_port = self.source_port.clone();
    let source_queue_size = self.queue_size.clone();
    let source_message_size = self.message_size.clone();
    let source_backend_address = self.backend_address.clone();

    let vent_services_arc = services_arc.clone();
    let vent_progress_queue_arc = progress_queue_arc.clone();
    let vent_thread = thread::spawn(move || {
      let sources = Server {
        port : source_port,
        queue_size : source_queue_size,
        message_size : source_message_size,
        backend : Backend::from_address(&source_backend_address)
      };
      sources.start_ventilator(vent_services_arc, vent_progress_queue_arc).unwrap();
    });

    // Next prepare the finalize thread which will persist finished jobs to the DB
    let finalize_backend_address = self.backend_address.clone();
    let finalize_done_queue_arc = done_queue_arc.clone();
    let finalize_thread = thread::spawn(move || {
      let finalize_backend = Backend::from_address(&finalize_backend_address);
      // Persist every 1 second, if there is something to record
      loop {
        match Server::mark_done_arc(&finalize_backend, &finalize_done_queue_arc) {
          true => {
            true;
          } // we did some work, on to the next iteration
          false => { // If we have no reports to process, sleep for a second and recheck
            thread::sleep_ms(1000);
          }
        }
      };
    });

    // Now prepare the results sink
    let result_port = self.result_port.clone();
    let result_queue_size = self.queue_size.clone();
    let result_message_size = self.message_size.clone();
    let result_backend_address = self.backend_address.clone();

    let sink_services_arc = services_arc.clone();
    let sink_progress_queue_arc = progress_queue_arc.clone();

    let sink_done_queue_arc = done_queue_arc.clone();
    let sink_thread = thread::spawn(move || {
      let results = Server {
        port : result_port,
        queue_size : result_queue_size,
        message_size : result_message_size,
        backend : Backend::from_address(&result_backend_address)
      };
      results.start_sink(sink_services_arc, sink_progress_queue_arc, sink_done_queue_arc).unwrap();
    });

    vent_thread.join().unwrap();
    sink_thread.join().unwrap();
    finalize_thread.join().unwrap();
    Ok(())
  }
}

impl Server {
  pub fn start_ventilator(&self,
      services_arc : Arc<Mutex<HashMap<String, Option<Service>>>>,
      progress_queue_arc : Arc<Mutex<HashMap<i64, Task>>>)
      -> Result <(),Error> {
    // We have a Ventilator-exclusive "queues" stack for tasks to be dispatched
    let mut queues : HashMap<String, Vec<Task>> = HashMap::new();
    // Assuming this is the only And tidy up the postgres tasks:
    self.backend.clear_limbo_tasks().unwrap();
    // Ok, let's bind to a port and start broadcasting
    let mut context = zmq::Context::new();
    let mut ventilator = context.socket(zmq::ROUTER).unwrap();
    let port_str = self.port.to_string();
    let address = "tcp://*:".to_string() + &port_str;
    assert!(ventilator.bind(&address).is_ok());
    let mut source_job_count = 0;

    loop {
      let mut msg = zmq::Message::new().unwrap();
      let mut identity = zmq::Message::new().unwrap();
      ventilator.recv(&mut identity, 0).unwrap();
      ventilator.recv(&mut msg, 0).unwrap();
      let service_name = msg.as_str().unwrap().to_string();
      println!("Task requested for service: {}", service_name.clone());
      source_job_count += 1;

      let mut dispatched_task : Option<Task> = None;
      match self.get_sync_service_record(&services_arc, service_name.clone()) {
        None => {},
        Some(service) => {
          if !queues.contains_key(&service_name) {
            queues.insert(service_name.clone(), Vec::new());
          }
          let mut task_queue : &mut Vec<Task> = queues.get_mut(&service_name).unwrap();
          if task_queue.is_empty() {
            task_queue.extend(self.backend.fetch_tasks(&service, self.queue_size).unwrap()); }
          match task_queue.pop() {
            Some(current_task) => {
              let taskid = current_task.id.unwrap();
              let file_opt = service.prepare_input_stream(current_task.clone());
              if file_opt.is_ok() {
                let mut file = file_opt.unwrap();
                dispatched_task = Some(current_task);

                ventilator.send_msg(identity, SNDMORE).unwrap();
                ventilator.send_str(&taskid.to_string(), SNDMORE).unwrap();

                let mut total_outgoing = 0;
                loop {
                  // Stream input data via zmq
                  let mut data = vec![0; self.message_size];
                  let size = file.read(&mut data).unwrap();
                  total_outgoing += size;
                  data.truncate(size);

                  if size < self.message_size {
                    // If exhausted, send the last frame
                    ventilator.send(&data,0).unwrap();
                    // And terminate
                    break;
                  } else {
                    // If more to go, send the frame and indicate there's more to come
                    ventilator.send(&data,SNDMORE).unwrap();
                  }
                }
                println!("Source job {}, message size: {}", source_job_count, total_outgoing);
              } else {
                // TODO: smart handling of failures
              }
            },
            None => {}
          };
        }
      };
      // Record that a task has been dispatched in the progress queue
      if dispatched_task.is_some() {
        Server::push_progress_task(&progress_queue_arc, dispatched_task.unwrap());
      }
    }
  }

  pub fn start_sink(&self,
      services_arc : Arc<Mutex<HashMap<String, Option<Service>>>>,
      progress_queue_arc : Arc<Mutex<HashMap<i64, Task>>>,
      done_queue_arc : Arc<Mutex<Vec<TaskReport>>>)
      -> Result <(),Error> {

    // Ok, let's bind to a port and start broadcasting
    let mut context = zmq::Context::new();
    let mut sink = context.socket(zmq::PULL).unwrap();
    let port_str = self.port.to_string();
    let address = "tcp://*:".to_string() + &port_str;
    assert!(sink.bind(&address).is_ok());

    let mut sink_job_count = 0;

    loop {
      let mut recv_msg = zmq::Message::new().unwrap();
      let mut taskid_msg = zmq::Message::new().unwrap();
      let mut service_msg = zmq::Message::new().unwrap();

      sink.recv(&mut service_msg, 0).unwrap();
      let service_name = service_msg.as_str().unwrap();

      sink.recv(&mut taskid_msg, 0).unwrap();
      let taskid_str = taskid_msg.as_str().unwrap();
      let taskid = taskid_str.parse::<i64>().unwrap();
      // We have a job, count it
      sink_job_count += 1;
      let mut total_incoming = 0;

      match Server::pop_progress_task(&progress_queue_arc, taskid) {
        None => {} // TODO: No such task, what to do?
        Some(task) => {

          // println!("{:?}", task);
          let service_option = Server::get_service_record(&services_arc, service_name.to_string());
          match service_option.clone() {
            None => {}, // TODO: Handle errors
            Some(service) => {
              // println!("Service: {:?}", service);
              if service.id.unwrap() == task.serviceid {
                // println!("Task and Service match up.");

                // Receive the rest of the input in the correct file
                let recv_dir = Path::new(&task.entry).parent().unwrap();
                let recv_pathname = recv_dir.to_str().unwrap().to_string() + "/" + &service.name + "_" + &service.version.round().to_string() + ".zip";
                let recv_path = Path::new(&recv_pathname);
                // println!("Will write to {:?}", recv_path);
                let mut file = File::create(recv_path).unwrap();
                loop {
                  sink.recv(&mut recv_msg, 0).unwrap();

                  total_incoming += file.write(recv_msg.deref()).unwrap();
                  if !sink.get_rcvmore().unwrap() {
                    break;
                  }
                }
                // Then mark the task done. This can be in a new thread later on
                let done_report = task.generate_report(recv_path);
                Server::push_done_queue(&done_queue_arc, done_report);
              }
              else {
                // Otherwise just discard the rest of the message
                loop {
                  sink.recv(&mut recv_msg, 0).unwrap();
                  if !sink.get_rcvmore().unwrap() {
                    break;
                  }
                }
              }
            }
          };
        }
      }
      println!("Sink job {}, message size: {}", sink_job_count, total_incoming);

      // let mut file = File::create("/tmp/cortex_sink_".to_string() + &sink_job_count.to_string()).unwrap();
      // file.write_all(&payload).unwrap();
    }
  }

  fn get_sync_service_record(&self, services_arc : &Arc<Mutex<HashMap<String, Option<Service>>>>, service_name : String) -> Option<Service> {
    let mut services = services_arc.lock().unwrap();
    let service_record = services.entry(service_name.clone()).or_insert(
      Service::from_name(&self.backend.connection, service_name.clone()).unwrap()).clone();
    service_record
  }

  fn get_service_record(services_arc : &Arc<Mutex<HashMap<String, Option<Service>>>>, service_name : String) -> Option<Service> {
    let services = services_arc.lock().unwrap();
    let service_record = services.get(&service_name);
    match service_record {
      None => None, // TODO: Handle errors
      Some(service_option) => service_option.clone()
    }
  }

  pub fn mark_done_arc(backend : &Backend, reports_arc: &Arc<Mutex<Vec<TaskReport>>>) -> bool {
    let mut reports = reports_arc.lock().unwrap();
    if reports.len() > 0 {
      backend.mark_done(&reports).unwrap(); // TODO: error handling if DB fails
      reports.clear();
      true
    } else {
      false
    }
  }
  pub fn push_done_queue(reports_arc : &Arc<Mutex<Vec<TaskReport>>>, report : TaskReport) {
    let mut reports = reports_arc.lock().unwrap();
    reports.push(report)
  }

  fn pop_progress_task(progress_queue_arc : &Arc<Mutex<HashMap<i64, Task>>>, taskid: i64) -> Option<Task> {
    let mut progress_queue = progress_queue_arc.lock().unwrap();
    progress_queue.remove(&taskid)
  }

  fn push_progress_task(progress_queue_arc : &Arc<Mutex<HashMap<i64, Task>>>, progress_task: Task) {
    let mut progress_queue = progress_queue_arc.lock().unwrap();
    progress_queue.insert(progress_task.id.unwrap(), progress_task);
  }
}<|endoftext|>