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

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

enum rctx {}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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 gen_int_range() {
        let r = rand::rng();
        let a = r.gen_int_range(-3, 42);
        assert a >= -3 && a < 42;
        assert r.gen_int_range(0, 1) == 0;
        assert r.gen_int_range(-12, -11) == -12;
    }

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

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

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    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>rt: Fix iaac_init using wrong type and not seeding correctly<commit_after>#[doc = "Random number generation"];

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

enum rctx {}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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(target_os = "win32"))]
    fn gen_int_from_fail() {
        rand::rng().gen_int_range(5, -2);
    }

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

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    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>#![allow(dead_code)]

#[cfg(test)]
mod test;

/// A game state
pub trait GameState {
    /// constructs the initial game state
    fn new() -> Self;
}

/// An game action
pub trait Action {
    /// The states these actions modify
    type GameState: GameState;

    /// Tests if the action is applicable to the given state
    fn test(self: &Self, state: &Self::GameState) -> bool;

    /// Executes the action on the given state
    fn execute(self: &Self, state: &mut Self::GameState);
}

/// An history item for use in the game tree
#[derive(Debug)]
struct HistoryItem<SomeAction>
    where SomeAction: Action
{
    /// The path to the parent item
    parent: Path,

    /// An action to be executed after the parent iten
    action: SomeAction,
}

/// The game tree
///
/// A game is a tree of history items representing actions.
/// This allows for easy undo/redo. Represents the tree
/// as a flat array of items interlinked by parent-ids.
#[derive(Debug)]
pub struct Game<SomeAction>
    where SomeAction: Action
{
    data: Vec<HistoryItem<SomeAction>>,
}

/// The path to one game tree item
///
/// Stores the path as an id to the parent item.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Path {
    /// There is no parent (we mean the trees root)
    Empty,
    /// The parents id
    HistoryItemId(usize),
}

impl<SomeAction> Game<SomeAction>
    where SomeAction: Action
{
    /// Creates a new game
    pub fn new() -> Self {
        Game { data: Vec::new() }
    }

    /// Inserts the action after parent
    ///
    /// Does reconstruct the game state at path and applies action
    pub fn insert(self: &mut Self, parent: &Path, action: SomeAction) -> Path {
        let state = self.get_state(parent);

        if action.test(&state) {
            self.data.push(HistoryItem {
                parent: parent.clone(),
                action: action,
            });

            Path::HistoryItemId(self.data.len() - 1)
        } else {
            Path::Empty
        }
    }

    /// Returns the state at the given path
    ///
    /// Does reapply all previous actions
    pub fn get_state(self: &Self, at: &Path) -> SomeAction::GameState {
        let mut state = SomeAction::GameState::new();

        if let &Path::HistoryItemId(up_to) = at {
            let mut path = Vec::<usize>::new();
            let mut curr = up_to;

            while let Path::HistoryItemId(next) = self.data[curr].parent {
                path.push(curr);
                curr = next;
            }

            path.push(curr);

            for idx in path.iter().rev() {
                self.data[*idx].action.execute(&mut state);
            }
        }

        state
    }
}
<commit_msg>Fix typo.<commit_after>#![allow(dead_code)]

#[cfg(test)]
mod test;

/// A game state
pub trait GameState {
    /// constructs the initial game state
    fn new() -> Self;
}

/// A game action
pub trait Action {
    /// The states these actions modify
    type GameState: GameState;

    /// Tests if the action is applicable to the given state
    fn test(self: &Self, state: &Self::GameState) -> bool;

    /// Executes the action on the given state
    fn execute(self: &Self, state: &mut Self::GameState);
}

/// An history item for use in the game tree
#[derive(Debug)]
struct HistoryItem<SomeAction>
    where SomeAction: Action
{
    /// The path to the parent item
    parent: Path,

    /// An action to be executed after the parent iten
    action: SomeAction,
}

/// The game tree
///
/// A game is a tree of history items representing actions.
/// This allows for easy undo/redo. Represents the tree
/// as a flat array of items interlinked by parent-ids.
#[derive(Debug)]
pub struct Game<SomeAction>
    where SomeAction: Action
{
    data: Vec<HistoryItem<SomeAction>>,
}

/// The path to one game tree item
///
/// Stores the path as an id to the parent item.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Path {
    /// There is no parent (we mean the trees root)
    Empty,
    /// The parents id
    HistoryItemId(usize),
}

impl<SomeAction> Game<SomeAction>
    where SomeAction: Action
{
    /// Creates a new game
    pub fn new() -> Self {
        Game { data: Vec::new() }
    }

    /// Inserts the action after parent
    ///
    /// Does reconstruct the game state at path and applies action
    pub fn insert(self: &mut Self, parent: &Path, action: SomeAction) -> Path {
        let state = self.get_state(parent);

        if action.test(&state) {
            self.data.push(HistoryItem {
                parent: parent.clone(),
                action: action,
            });

            Path::HistoryItemId(self.data.len() - 1)
        } else {
            Path::Empty
        }
    }

    /// Returns the state at the given path
    ///
    /// Does reapply all previous actions
    pub fn get_state(self: &Self, at: &Path) -> SomeAction::GameState {
        let mut state = SomeAction::GameState::new();

        if let &Path::HistoryItemId(up_to) = at {
            let mut path = Vec::<usize>::new();
            let mut curr = up_to;

            while let Path::HistoryItemId(next) = self.data[curr].parent {
                path.push(curr);
                curr = next;
            }

            path.push(curr);

            for idx in path.iter().rev() {
                self.data[*idx].action.execute(&mut state);
            }
        }

        state
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_features)]

use raft::raftpb::{Entry, Snapshot};
use std::collections::VecDeque;

// unstable.entris[i] has raft log position i+unstable.offset.
// Note that unstable.offset may be less than the highest log
// position in storage; this means that the next write to storage
// might need to truncate the log before persisting unstable.entries.
#[derive(Debug, PartialEq)]
pub struct Unstable {
    // the incoming unstable snapshot, if any.
    snapshot: Option<Box<Snapshot>>,
    // all entries that have not yet been written to storage.
    entries: VecDeque<Entry>,
    offset: u64,
}

impl Unstable {
    // maybe_first_index returns the last index if it has at least one
    // unstable entry or snapshot.
    fn maybe_first_index(&self) -> Option<u64> {
        self.snapshot
            .as_ref()
            .map_or(None, |snap| Some(snap.get_metadata().get_index() + 1))
    }

    // maybe_last_index returns the last index if it has at least one
    // unstable entry or snapshot.
    fn maybe_last_index(&self) -> Option<u64> {
        match self.entries.len() {
            0 => {
                self.snapshot
                    .as_ref()
                    .map_or(None, |snap| Some(snap.get_metadata().get_index()))
            }
            len => Some(self.offset + len as u64 - 1),
        }
    }

    // maybe_term returns the term of the entry at index idx, if there
    // is any.
    fn maybe_term(&self, idx: u64) -> Option<u64> {
        if idx < self.offset {
            if self.snapshot.is_none() {
                return None;
            }

            let meta = self.snapshot.as_ref().unwrap().get_metadata().clone();
            if idx == meta.get_index() {
                return Some(meta.get_term());
            }
            return None;
        }
        match self.maybe_last_index() {
            None => None,
            Some(last) => {
                if idx > last {
                    return None;
                }
                Some(self.entries[(idx - self.offset) as usize].get_Term())
            }
        }
    }

    fn stable_to(&mut self, idx: u64, term: u64) {
        let t = self.maybe_term(idx);
        if t.is_none() {
            return;
        }

        if t.unwrap() == term && idx >= self.offset {
            let start = idx + 1 - self.offset;
            for _ in 0..start {
                self.entries.pop_front();
            }
            self.offset = idx + 1;
        }
    }

    fn stable_snap_to(&mut self, idx: u64) {
        if self.snapshot.is_none() {
            return;
        }
        if idx == self.snapshot.as_ref().unwrap().get_metadata().get_index() {
            self.snapshot = None;
        }
    }

    fn restore(&mut self, snap: Snapshot) {
        self.entries.clear();
        self.offset = snap.get_metadata().get_index() + 1;
        self.snapshot = Some(Box::new(snap));
    }

    fn truncate_and_append(&mut self, ents: &[Entry]) {
        let after = ents[0].get_Index() - 1;
        if after == self.offset + self.entries.len() as u64 - 1 {
            for e in ents {
                self.entries.push_back(e.clone());
            }
        } else if after < self.offset {
            // The log is being truncated to before our current offset
            // portion, so set the offset and replace the entries
            self.offset = after + 1;
            self.entries.clear();

            for e in ents {
                self.entries.push_back(e.clone());
            }
        } else {
            // truncate to after and copy to self.entries
            // then append
            let off = self.offset.clone();
            let cut_ents = self.cut_slice(off, after + 1);
            self.entries.clear();
            for e in cut_ents {
                self.entries.push_back(e);
            }

            for e in ents {
                self.entries.push_back(e.clone());
            }
        }
    }

    fn cut_slice(&mut self, lo: u64, hi: u64) -> Vec<Entry> {
        self.must_check_outofbounds(lo, hi);
        let l = lo as usize;
        let h = hi as usize;
        let off = self.offset as usize;
        return self.entries.drain(l - off..h - off).map(|e| e).collect();
    }

    fn must_check_outofbounds(&self, lo: u64, hi: u64) {
        if lo > hi {
            panic!("invalid unstable.slice {} > {}", lo, hi)
        }
        let upper = self.offset + self.entries.len() as u64;
        if lo < self.offset || hi > upper {
            panic!("unstable.slice[{}, {}] out of bound[{}, {}]",
                   lo,
                   hi,
                   self.offset,
                   upper)
        }
    }
}

#[cfg(test)]
mod test {
    use raft::raftpb::{Entry, Snapshot};
    use raft::log_unstable::Unstable;
    use std::collections::VecDeque;

    fn new_entry(index: u64, term: u64) -> Entry {
        let mut e = Entry::new();
        e.set_Term(term);
        e.set_Index(index);
        e
    }

    fn new_snapshot(index: u64, term: u64) -> Snapshot {
        use raft::raftpb::{SnapshotMetadata, Snapshot};
        let mut snap = Snapshot::new();
        let mut meta = SnapshotMetadata::new();
        meta.set_index(index);
        meta.set_term(term);
        snap.set_metadata(meta);
        snap
    }

    #[test]
    fn test_maybe_first_index() {
        // entry, offset, snap, wok, windex,
        let tests: Vec<(Option<Entry>, u64, Option<Snapshot>, bool, u64)> = vec![
            // no snapshot
            (Some(new_entry(5,1)), 5, None, false, 0),
            (None, 0, None, false, 0),
            // has snapshot
            (Some(new_entry(5, 1)), 5, Some(new_snapshot(4,1)), true, 5),
            (None, 5, Some(new_snapshot(4,1)), true, 5),
        ];

        for (entries, offset, snapshot, wok, windex) in tests {
            let u = Unstable {
                entries: entries.map_or(VecDeque::new(), |entry| {
                    vec![entry].into_iter().collect::<VecDeque<Entry>>()
                }),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            let index = u.maybe_first_index();
            match index {
                None => assert!(!wok),
                Some(index) => assert_eq!(index, windex),
            }
        }
    }

    #[test]
    fn test_maybe_last_index() {
        // entry, offset, snap, wok, windex,
        let tests: Vec<(Option<Entry>, u64, Option<Snapshot>, bool, u64)> = vec![
            (Some(new_entry(5,1)), 5, None, true, 5),
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), true, 5),
            // last in snapshot
            (None, 5, Some(new_snapshot(4,1)), true, 4),
            // empty unstable
            (None, 0, None, false, 0),
       ];

        for (entries, offset, snapshot, wok, windex) in tests {
            let u = Unstable {
                entries: entries.map_or(VecDeque::new(), |entry| {
                    vec![entry].into_iter().collect::<VecDeque<Entry>>()
                }),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            let index = u.maybe_last_index();
            match index {
                None => assert!(!wok),
                Some(index) => assert_eq!(index, windex),
            }
        }
    }

    #[test]
    fn test_maybe_term() {
        // entry, offset, snap, index, wok, wterm
        let tests: Vec<(Option<Entry>, u64, Option<Snapshot>, u64, bool, u64)> = vec![
            // term from entries
            (Some(new_entry(5,1)), 5, None, 5, true, 1),
            (Some(new_entry(5,1)), 5, None, 6, false, 0),
            (Some(new_entry(5,1)), 5, None, 4, false, 0),
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), 5, true, 1),
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), 6, false, 0),
            // term from snapshot
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), 4, true, 1),
            (None, 5, Some(new_snapshot(4,1)), 5, false, 0),
            (None, 5, Some(new_snapshot(4,1)), 4, true, 1),
            (None, 0, None, 5, false, 0),
       ];

        for (entries, offset, snapshot, index, wok, wterm) in tests {
            let u = Unstable {
                entries: entries.map_or(VecDeque::new(), |entry| {
                    vec![entry].into_iter().collect::<VecDeque<Entry>>()
                }),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            let term = u.maybe_term(index);
            match term {
                None => assert!(!wok),
                Some(term) => assert_eq!(term, wterm),
            }
        }
    }

    #[test]
    fn test_restore() {
        let mut u = Unstable {
            entries: vec![new_entry(5, 1)].into_iter().collect::<VecDeque<Entry>>(),
            offset: 5,
            snapshot: Some(Box::new(new_snapshot(4, 1))),
        };

        let s = new_snapshot(6, 2);
        u.restore(s.clone());

        assert_eq!(u.offset, s.get_metadata().get_index() + 1);
        assert_eq!(u.entries.len(), 0);
        assert_eq!(*u.snapshot.unwrap(), s);
    }

    #[test]
    fn test_stable_to() {
        // entries, offset, snap, index, term, woffset, wlen
        let tests: Vec<(Vec<Entry>, u64, Option<Snapshot>, u64, u64, u64, usize)> = vec![
            (vec![], 0, None, 5, 1, 0, 0),
            // stable to the first entry
            (vec![new_entry(5,1)], 5, None, 5, 1, 6, 0),
            (vec![new_entry(5,1), new_entry(6, 0)], 5, None, 5, 1, 6, 1),
            // stable to the first entry and term mismatch
            (vec![new_entry(6,2)], 5, None, 6, 1, 5, 1),
            // stable to old entry
            (vec![new_entry(5,1)], 5, None, 4, 1, 5, 1),
            (vec![new_entry(5,1)], 5, None, 4, 2, 5, 1),
            // with snapshot
            // stable to the first entry
            (vec![new_entry(5,1)], 5, Some(new_snapshot(4,1)), 5, 1, 6, 0),
            // stable to the first entry
            (vec![new_entry(5,1), new_entry(6,1)], 5, Some(new_snapshot(4,1)), 5, 1, 6, 1),
            // stable to the first entry and term mismatch
            (vec![new_entry(6,2)], 5, Some(new_snapshot(5,1)), 6, 1, 5, 1),
            // stable to snapshot
            (vec![new_entry(5,1)], 5, Some(new_snapshot(4,1)), 4, 1, 5, 1),
            // stable to old entry
            (vec![new_entry(5,2)], 5, Some(new_snapshot(4,2)), 4, 1, 5, 1),
       ];

        for (entries, offset, snapshot, index, term, woffset, wlen) in tests {
            let mut u = Unstable {
                entries: entries.into_iter().collect::<VecDeque<Entry>>(),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            u.stable_to(index, term);
            assert_eq!(u.offset, woffset);
            assert_eq!(u.entries.len(), wlen);
        }
    }

    #[test]
    fn test_truncate_and_append() {
        // entries, offset, snap, to_append, woffset, wentries
        let tests: Vec<(Vec<Entry>,
                        u64,
                        Option<Snapshot>,
                        Vec<Entry>,
                        u64,
                        Vec<Entry>)> = vec![
            // replace to the end
            (vec![new_entry(5, 1)], 5, None,
                vec![new_entry(6, 1), new_entry(7, 1)],
                    5, vec![new_entry(5,1), new_entry(6,1), new_entry(7,1)]),

            // replace to unstable entries
           (vec![new_entry(5, 1)], 5, None,
               vec![new_entry(5, 2), new_entry(6, 2)],
                   5, vec![new_entry(5, 2), new_entry(6, 2)]),

            (vec![new_entry(5, 1)], 5, None,
                vec![new_entry(4, 2), new_entry(5, 2), new_entry(6, 2)],
                    4, vec![new_entry(4,2), new_entry(5, 2), new_entry(6, 2)]),

            // truncate existing entries and append
           (vec![new_entry(5, 1), new_entry(6, 1), new_entry(7, 1)], 5, None,
               vec![new_entry(6, 2)],
                   5, vec![new_entry(5, 1), new_entry(6, 2)]),

            (vec![new_entry(5, 1), new_entry(6, 1), new_entry(7, 1)], 5, None,
                vec![new_entry(7, 2), new_entry(8, 2)],
                    5, vec![new_entry(5, 1), new_entry(6, 1), new_entry(7, 2), new_entry(8, 2)]),
      ];

        for (entries, offset, snapshot, to_append, woffset, wentries) in tests {
            let mut u = Unstable {
                entries: entries.into_iter().collect::<VecDeque<Entry>>(),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            u.truncate_and_append(&to_append);
            assert_eq!(u.offset, woffset);
            assert_eq!(u.entries, wentries.into_iter().collect::<VecDeque<Entry>>());
        }
    }
}
<commit_msg>Tiny clean up<commit_after>#![allow(dead_code)]

use raft::raftpb::{Entry, Snapshot};
use std::collections::VecDeque;

// unstable.entris[i] has raft log position i+unstable.offset.
// Note that unstable.offset may be less than the highest log
// position in storage; this means that the next write to storage
// might need to truncate the log before persisting unstable.entries.
#[derive(Debug, PartialEq)]
pub struct Unstable {
    // the incoming unstable snapshot, if any.
    snapshot: Option<Box<Snapshot>>,
    // all entries that have not yet been written to storage.
    entries: VecDeque<Entry>,
    offset: u64,
}

impl Unstable {
    // maybe_first_index returns the last index if it has at least one
    // unstable entry or snapshot.
    fn maybe_first_index(&self) -> Option<u64> {
        self.snapshot
            .as_ref()
            .map_or(None, |snap| Some(snap.get_metadata().get_index() + 1))
    }

    // maybe_last_index returns the last index if it has at least one
    // unstable entry or snapshot.
    fn maybe_last_index(&self) -> Option<u64> {
        match self.entries.len() {
            0 => {
                self.snapshot
                    .as_ref()
                    .map_or(None, |snap| Some(snap.get_metadata().get_index()))
            }
            len => Some(self.offset + len as u64 - 1),
        }
    }

    // maybe_term returns the term of the entry at index idx, if there
    // is any.
    fn maybe_term(&self, idx: u64) -> Option<u64> {
        if idx < self.offset {
            if self.snapshot.is_none() {
                return None;
            }

            let meta = self.snapshot.as_ref().unwrap().get_metadata().clone();
            if idx == meta.get_index() {
                return Some(meta.get_term());
            }
            return None;
        }
        match self.maybe_last_index() {
            None => None,
            Some(last) => {
                if idx > last {
                    return None;
                }
                Some(self.entries[(idx - self.offset) as usize].get_Term())
            }
        }
    }

    fn stable_to(&mut self, idx: u64, term: u64) {
        let t = self.maybe_term(idx);
        if t.is_none() {
            return;
        }

        if t.unwrap() == term && idx >= self.offset {
            let start = idx + 1 - self.offset;
            for _ in 0..start {
                self.entries.pop_front();
            }
            self.offset = idx + 1;
        }
    }

    fn stable_snap_to(&mut self, idx: u64) {
        if self.snapshot.is_none() {
            return;
        }
        if idx == self.snapshot.as_ref().unwrap().get_metadata().get_index() {
            self.snapshot = None;
        }
    }

    fn restore(&mut self, snap: Snapshot) {
        self.entries.clear();
        self.offset = snap.get_metadata().get_index() + 1;
        self.snapshot = Some(Box::new(snap));
    }

    fn truncate_and_append(&mut self, ents: &[Entry]) {
        let after = ents[0].get_Index() - 1;
        if after == self.offset + self.entries.len() as u64 - 1 {
            for e in ents {
                self.entries.push_back(e.clone());
            }
        } else if after < self.offset {
            // The log is being truncated to before our current offset
            // portion, so set the offset and replace the entries
            self.offset = after + 1;
            self.entries.clear();

            for e in ents {
                self.entries.push_back(e.clone());
            }
        } else {
            // truncate to after and copy to self.entries
            // then append
            let off = self.offset.clone();
            let cut_ents = self.cut_slice(off, after + 1);
            self.entries.clear();
            for e in cut_ents {
                self.entries.push_back(e);
            }

            for e in ents {
                self.entries.push_back(e.clone());
            }
        }
    }

    fn cut_slice(&mut self, lo: u64, hi: u64) -> Vec<Entry> {
        self.must_check_outofbounds(lo, hi);
        let l = lo as usize;
        let h = hi as usize;
        let off = self.offset as usize;
        return self.entries.drain(l - off..h - off).map(|e| e).collect();
    }

    fn must_check_outofbounds(&self, lo: u64, hi: u64) {
        if lo > hi {
            panic!("invalid unstable.slice {} > {}", lo, hi)
        }
        let upper = self.offset + self.entries.len() as u64;
        if lo < self.offset || hi > upper {
            panic!("unstable.slice[{}, {}] out of bound[{}, {}]",
                   lo,
                   hi,
                   self.offset,
                   upper)
        }
    }
}

#[cfg(test)]
mod test {
    use raft::raftpb::{Entry, Snapshot};
    use raft::log_unstable::Unstable;
    use std::collections::VecDeque;

    fn new_entry(index: u64, term: u64) -> Entry {
        let mut e = Entry::new();
        e.set_Term(term);
        e.set_Index(index);
        e
    }

    fn new_snapshot(index: u64, term: u64) -> Snapshot {
        use raft::raftpb::{SnapshotMetadata, Snapshot};
        let mut snap = Snapshot::new();
        let mut meta = SnapshotMetadata::new();
        meta.set_index(index);
        meta.set_term(term);
        snap.set_metadata(meta);
        snap
    }

    #[test]
    fn test_maybe_first_index() {
        // entry, offset, snap, wok, windex,
        let tests: Vec<(Option<Entry>, u64, Option<Snapshot>, bool, u64)> = vec![
            // no snapshot
            (Some(new_entry(5,1)), 5, None, false, 0),
            (None, 0, None, false, 0),
            // has snapshot
            (Some(new_entry(5, 1)), 5, Some(new_snapshot(4,1)), true, 5),
            (None, 5, Some(new_snapshot(4,1)), true, 5),
        ];

        for (entries, offset, snapshot, wok, windex) in tests {
            let u = Unstable {
                entries: entries.map_or(VecDeque::new(), |entry| {
                    vec![entry].into_iter().collect::<VecDeque<Entry>>()
                }),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            let index = u.maybe_first_index();
            match index {
                None => assert!(!wok),
                Some(index) => assert_eq!(index, windex),
            }
        }
    }

    #[test]
    fn test_maybe_last_index() {
        // entry, offset, snap, wok, windex,
        let tests: Vec<(Option<Entry>, u64, Option<Snapshot>, bool, u64)> = vec![
            (Some(new_entry(5,1)), 5, None, true, 5),
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), true, 5),
            // last in snapshot
            (None, 5, Some(new_snapshot(4,1)), true, 4),
            // empty unstable
            (None, 0, None, false, 0),
       ];

        for (entries, offset, snapshot, wok, windex) in tests {
            let u = Unstable {
                entries: entries.map_or(VecDeque::new(), |entry| {
                    vec![entry].into_iter().collect::<VecDeque<Entry>>()
                }),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            let index = u.maybe_last_index();
            match index {
                None => assert!(!wok),
                Some(index) => assert_eq!(index, windex),
            }
        }
    }

    #[test]
    fn test_maybe_term() {
        // entry, offset, snap, index, wok, wterm
        let tests: Vec<(Option<Entry>, u64, Option<Snapshot>, u64, bool, u64)> = vec![
            // term from entries
            (Some(new_entry(5,1)), 5, None, 5, true, 1),
            (Some(new_entry(5,1)), 5, None, 6, false, 0),
            (Some(new_entry(5,1)), 5, None, 4, false, 0),
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), 5, true, 1),
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), 6, false, 0),
            // term from snapshot
            (Some(new_entry(5,1)), 5, Some(new_snapshot(4,1)), 4, true, 1),
            (None, 5, Some(new_snapshot(4,1)), 5, false, 0),
            (None, 5, Some(new_snapshot(4,1)), 4, true, 1),
            (None, 0, None, 5, false, 0),
       ];

        for (entries, offset, snapshot, index, wok, wterm) in tests {
            let u = Unstable {
                entries: entries.map_or(VecDeque::new(), |entry| {
                    vec![entry].into_iter().collect::<VecDeque<Entry>>()
                }),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            let term = u.maybe_term(index);
            match term {
                None => assert!(!wok),
                Some(term) => assert_eq!(term, wterm),
            }
        }
    }

    #[test]
    fn test_restore() {
        let mut u = Unstable {
            entries: vec![new_entry(5, 1)].into_iter().collect::<VecDeque<Entry>>(),
            offset: 5,
            snapshot: Some(Box::new(new_snapshot(4, 1))),
        };

        let s = new_snapshot(6, 2);
        u.restore(s.clone());

        assert_eq!(u.offset, s.get_metadata().get_index() + 1);
        assert_eq!(u.entries.len(), 0);
        assert_eq!(*u.snapshot.unwrap(), s);
    }

    #[test]
    fn test_stable_to() {
        // entries, offset, snap, index, term, woffset, wlen
        let tests: Vec<(Vec<Entry>, u64, Option<Snapshot>, u64, u64, u64, usize)> = vec![
            (vec![], 0, None, 5, 1, 0, 0),
            // stable to the first entry
            (vec![new_entry(5,1)], 5, None, 5, 1, 6, 0),
            (vec![new_entry(5,1), new_entry(6, 0)], 5, None, 5, 1, 6, 1),
            // stable to the first entry and term mismatch
            (vec![new_entry(6,2)], 5, None, 6, 1, 5, 1),
            // stable to old entry
            (vec![new_entry(5,1)], 5, None, 4, 1, 5, 1),
            (vec![new_entry(5,1)], 5, None, 4, 2, 5, 1),
            // with snapshot
            // stable to the first entry
            (vec![new_entry(5,1)], 5, Some(new_snapshot(4,1)), 5, 1, 6, 0),
            // stable to the first entry
            (vec![new_entry(5,1), new_entry(6,1)], 5, Some(new_snapshot(4,1)), 5, 1, 6, 1),
            // stable to the first entry and term mismatch
            (vec![new_entry(6,2)], 5, Some(new_snapshot(5,1)), 6, 1, 5, 1),
            // stable to snapshot
            (vec![new_entry(5,1)], 5, Some(new_snapshot(4,1)), 4, 1, 5, 1),
            // stable to old entry
            (vec![new_entry(5,2)], 5, Some(new_snapshot(4,2)), 4, 1, 5, 1),
       ];

        for (entries, offset, snapshot, index, term, woffset, wlen) in tests {
            let mut u = Unstable {
                entries: entries.into_iter().collect::<VecDeque<Entry>>(),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            u.stable_to(index, term);
            assert_eq!(u.offset, woffset);
            assert_eq!(u.entries.len(), wlen);
        }
    }

    #[test]
    fn test_truncate_and_append() {
        // entries, offset, snap, to_append, woffset, wentries
        let tests: Vec<(Vec<Entry>,
                        u64,
                        Option<Snapshot>,
                        Vec<Entry>,
                        u64,
                        Vec<Entry>)> = vec![
            // replace to the end
            (vec![new_entry(5, 1)], 5, None,
                vec![new_entry(6, 1), new_entry(7, 1)],
                    5, vec![new_entry(5,1), new_entry(6,1), new_entry(7,1)]),

            // replace to unstable entries
           (vec![new_entry(5, 1)], 5, None,
               vec![new_entry(5, 2), new_entry(6, 2)],
                   5, vec![new_entry(5, 2), new_entry(6, 2)]),

            (vec![new_entry(5, 1)], 5, None,
                vec![new_entry(4, 2), new_entry(5, 2), new_entry(6, 2)],
                    4, vec![new_entry(4,2), new_entry(5, 2), new_entry(6, 2)]),

            // truncate existing entries and append
           (vec![new_entry(5, 1), new_entry(6, 1), new_entry(7, 1)], 5, None,
               vec![new_entry(6, 2)],
                   5, vec![new_entry(5, 1), new_entry(6, 2)]),

            (vec![new_entry(5, 1), new_entry(6, 1), new_entry(7, 1)], 5, None,
                vec![new_entry(7, 2), new_entry(8, 2)],
                    5, vec![new_entry(5, 1), new_entry(6, 1), new_entry(7, 2), new_entry(8, 2)]),
      ];

        for (entries, offset, snapshot, to_append, woffset, wentries) in tests {
            let mut u = Unstable {
                entries: entries.into_iter().collect::<VecDeque<Entry>>(),
                offset: offset,
                snapshot: snapshot.map_or(None, |snap| Some(Box::new(snap))),
            };
            u.truncate_and_append(&to_append);
            assert_eq!(u.offset, woffset);
            assert_eq!(u.entries, wentries.into_iter().collect::<VecDeque<Entry>>());
        }
    }
}
<|endoftext|>


<commit_before>#![crate_id = "gossip"]
#![crate_type = "lib"]
#![feature(globs, macro_rules, unsafe_destructor)]
#![deny(missing_doc)]
#![allow(unused_must_use,dead_code, unused_imports, unused_variable)]

//! Gossip.rs is a gossip/epidemic protocol based on the
//! paper "Epidemic Broadcast Trees" in which it introduced
//! the novel idea of the Plumtree.
//!
//! Gossip provides a way for a group of nodes, otherwise
//! known as a cluster, to communicate and achieve
//! consensus. However, it's specifically meant to be a
//! highly available system (AP); thus, it supports
//! eventual consistency in face of partitions.
//!
//! This trade-off is fine for many distributed systems
//! that need to be highly available and fault-tolerant. Things
//! such as data processing, analytics, etc... are all great
//! candidates.

extern crate collections;
extern crate uuid;
extern crate rand;
extern crate serialize;
extern crate core;

extern crate msgpack;

pub mod server;
pub mod state;
pub mod message;
pub mod broadcast;
pub mod protocol;
pub mod transport;
pub mod tcp;
pub mod connection;
pub mod result;
pub mod response;
pub mod version;
pub mod health;
pub mod tagged;
pub mod addr;
<commit_msg>Removed deny missing docs<commit_after>#![crate_id = "gossip"]
#![crate_type = "lib"]
#![feature(globs, macro_rules, unsafe_destructor)]
#![allow(unused_must_use,dead_code, unused_imports, unused_variable)]

//! Gossip.rs is a gossip/epidemic protocol based on the
//! paper "Epidemic Broadcast Trees" in which it introduced
//! the novel idea of the Plumtree.
//!
//! Gossip provides a way for a group of nodes, otherwise
//! known as a cluster, to communicate and achieve
//! consensus. However, it's specifically meant to be a
//! highly available system (AP); thus, it supports
//! eventual consistency in face of partitions.
//!
//! This trade-off is fine for many distributed systems
//! that need to be highly available and fault-tolerant. Things
//! such as data processing, analytics, etc... are all great
//! candidates.

extern crate collections;
extern crate uuid;
extern crate rand;
extern crate serialize;
extern crate core;

extern crate msgpack;

pub mod server;
pub mod state;
pub mod message;
pub mod broadcast;
pub mod protocol;
pub mod transport;
pub mod tcp;
pub mod connection;
pub mod result;
pub mod response;
pub mod version;
pub mod health;
pub mod tagged;
pub mod addr;
<|endoftext|>


<commit_before>use url::Url;
use hyper::Client;
use hyper::header::{ContentType, ContentLength};
use hyper::net::Fresh;
use hyper::client::Request;
use hyper::status::StatusCode;
use hyper::error::Error;
use std::io::Read;

pub struct HttpResponse {
    pub status: StatusCode,
    pub body: String
}

pub fn get(url: &Url) -> Result<HttpResponse, Error> {
    let mut client = Client::new();
    let mut res = client.get(&url.to_string())
        .send()
        .unwrap();
    let mut body = String::new();
    let result = res.read_to_string(&mut body);
    match result {
        Ok(_) => {
            Ok(HttpResponse{status: res.status, body: body})
        },
        Err(err) => {
            Err(Error::Io(err))
        }
    }
}

//pub fn post<E>(url: &Url) -> Result<HttpResponse, E> {
    //let mut client = Client::new();
    //client.post(url.to_string().as_slice()).header(ContentType("application/json".parse().unwrap()));
    //let mut req = Request::post(url.clone()).unwrap();
    //req.headers_mut().set(ContentType(from_str("application/json").unwrap()));
    //req.headers_mut().set(ContentLength(0));
    //make_request(req)
//}

//pub fn post_json<E>(url: &Url, json: &str) -> Result<HttpResponse, E> {
    //let mut client = Client::new();
    //client.post(url.to_string().as_slice()).header(ContentType("application/json".parse().unwrap()));
    //let mut req = Request::post(url.clone()).unwrap();
    //req.headers_mut().set(ContentType(from_str("application/json").unwrap()));
    //req.headers_mut().set(ContentLength(json.len()));
    //match req.start() {
        //Ok(mut req) => {
            //try!(req.write(json.to_string().into_bytes().as_slice()));
            //match req.send() {
                //Ok(mut resp) => {
                    //match resp.read_to_string() {
                        //Ok(body) => Ok(HttpResponse{code: resp.status as u16, body: body}),
                        //Err(e) => Err(FromError::from_error(e))
                    //}
                //},
                //Err(e) => Err(e)
            //}
        //},
        //Err(e) => Err(e)
    //}
//}

//fn make_request<C, E>(client: &mut Client<C>) -> Result<HttpResponse, E> {

    //match req.start() {
        //Ok(req) => {
            //match req.send() {
                //Ok(mut resp) => {
                    //match resp.read_to_string() {
                        //Ok(body) => Ok(HttpResponse{code: resp.status as u16, body: body}),
                        //Err(e) => Err(FromError::from_error(e))
                    //}
                //},
                //Err(e) => Err(e)
            //}
        //},
        //Err(e) => Err(e)
    //}
//}
<commit_msg>Added handling istead of unwrap() for utils#get<commit_after>use url::Url;
use hyper::Client;
use hyper::header::{ContentType, ContentLength};
use hyper::net::Fresh;
use hyper::client::Request;
use hyper::status::StatusCode;
use hyper::error::Error;
use std::io::Read;

pub struct HttpResponse {
    pub status: StatusCode,
    pub body: String
}

pub fn get(url: &Url) -> Result<HttpResponse, Error> {
    let mut client = Client::new();
    let mut result_response = client.get(&url.to_string()).send();
    match result_response {
        Ok(mut res) => {
            let mut body = String::new();
            let result = res.read_to_string(&mut body);
            match result {
                Ok(_) => {
                    Ok(HttpResponse{status: res.status, body: body})
                },
                Err(err) => {
                    Err(Error::Io(err))
                }
            }
        },
        Err(err) => Err(err)
    }
}

//pub fn post<E>(url: &Url) -> Result<HttpResponse, E> {
    //let mut client = Client::new();
    //client.post(url.to_string().as_slice()).header(ContentType("application/json".parse().unwrap()));
    //let mut req = Request::post(url.clone()).unwrap();
    //req.headers_mut().set(ContentType(from_str("application/json").unwrap()));
    //req.headers_mut().set(ContentLength(0));
    //make_request(req)
//}

//pub fn post_json<E>(url: &Url, json: &str) -> Result<HttpResponse, E> {
    //let mut client = Client::new();
    //client.post(url.to_string().as_slice()).header(ContentType("application/json".parse().unwrap()));
    //let mut req = Request::post(url.clone()).unwrap();
    //req.headers_mut().set(ContentType(from_str("application/json").unwrap()));
    //req.headers_mut().set(ContentLength(json.len()));
    //match req.start() {
        //Ok(mut req) => {
            //try!(req.write(json.to_string().into_bytes().as_slice()));
            //match req.send() {
                //Ok(mut resp) => {
                    //match resp.read_to_string() {
                        //Ok(body) => Ok(HttpResponse{code: resp.status as u16, body: body}),
                        //Err(e) => Err(FromError::from_error(e))
                    //}
                //},
                //Err(e) => Err(e)
            //}
        //},
        //Err(e) => Err(e)
    //}
//}

//fn make_request<C, E>(client: &mut Client<C>) -> Result<HttpResponse, E> {

    //match req.start() {
        //Ok(req) => {
            //match req.send() {
                //Ok(mut resp) => {
                    //match resp.read_to_string() {
                        //Ok(body) => Ok(HttpResponse{code: resp.status as u16, body: body}),
                        //Err(e) => Err(FromError::from_error(e))
                    //}
                //},
                //Err(e) => Err(e)
            //}
        //},
        //Err(e) => Err(e)
    //}
//}
<|endoftext|>


<commit_before>//! Codegen the MIR to the LLVM IR.
//!
//! Hopefully useful general knowledge about codegen:
//!
//! * There's no way to find out the [`Ty`] type of a [`Value`]. Doing so
//!   would be "trying to get the eggs out of an omelette" (credit:
//!   pcwalton). You can, instead, find out its [`llvm::Type`] by calling [`val_ty`],
//!   but one [`llvm::Type`] corresponds to many [`Ty`]s; for instance, `tup(int, int,
//!   int)` and `rec(x=int, y=int, z=int)` will have the same [`llvm::Type`].
//!
//! [`Ty`]: rustc_middle::ty::Ty
//! [`val_ty`]: common::val_ty

use super::ModuleLlvm;

use crate::attributes;
use crate::builder::Builder;
use crate::common;
use crate::context::CodegenCx;
use crate::llvm;
use crate::value::Value;

use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
use rustc_codegen_ssa::mono_item::MonoItemExt;
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_middle::dep_graph;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::middle::exported_symbols;
use rustc_middle::mir::mono::{Linkage, Visibility};
use rustc_middle::ty::TyCtxt;
use rustc_session::config::DebugInfo;
use rustc_span::symbol::Symbol;
use rustc_target::spec::SanitizerSet;

use std::ffi::CString;
use std::time::Instant;

pub fn write_compressed_metadata<'tcx>(
    tcx: TyCtxt<'tcx>,
    metadata: &EncodedMetadata,
    llvm_module: &mut ModuleLlvm,
) {
    use snap::write::FrameEncoder;
    use std::io::Write;

    // Historical note:
    //
    // When using link.exe it was seen that the section name `.note.rustc`
    // was getting shortened to `.note.ru`, and according to the PE and COFF
    // specification:
    //
    // > Executable images do not use a string table and do not support
    // > section names longer than 8 characters
    //
    // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
    //
    // As a result, we choose a slightly shorter name! As to why
    // `.note.rustc` works on MinGW, that's another good question...
    let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" };

    let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
    let mut compressed = tcx.metadata_encoding_version();
    FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();

    let llmeta = common::bytes_in_context(metadata_llcx, &compressed);
    let llconst = common::struct_in_context(metadata_llcx, &[llmeta], false);
    let name = exported_symbols::metadata_symbol_name(tcx);
    let buf = CString::new(name).unwrap();
    let llglobal =
        unsafe { llvm::LLVMAddGlobal(metadata_llmod, common::val_ty(llconst), buf.as_ptr()) };
    unsafe {
        llvm::LLVMSetInitializer(llglobal, llconst);
        let name = SmallCStr::new(section_name);
        llvm::LLVMSetSection(llglobal, name.as_ptr());

        // Also generate a .section directive to force no
        // flags, at least for ELF outputs, so that the
        // metadata doesn't get loaded into memory.
        let directive = format!(".section {}", section_name);
        llvm::LLVMSetModuleInlineAsm2(metadata_llmod, directive.as_ptr().cast(), directive.len())
    }
}

pub struct ValueIter<'ll> {
    cur: Option<&'ll Value>,
    step: unsafe extern "C" fn(&'ll Value) -> Option<&'ll Value>,
}

impl Iterator for ValueIter<'ll> {
    type Item = &'ll Value;

    fn next(&mut self) -> Option<&'ll Value> {
        let old = self.cur;
        if let Some(old) = old {
            self.cur = unsafe { (self.step)(old) };
        }
        old
    }
}

pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> {
    unsafe { ValueIter { cur: llvm::LLVMGetFirstGlobal(llmod), step: llvm::LLVMGetNextGlobal } }
}

pub fn compile_codegen_unit(
    tcx: TyCtxt<'tcx>,
    cgu_name: Symbol,
) -> (ModuleCodegen<ModuleLlvm>, u64) {
    let start_time = Instant::now();

    let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
    let (module, _) =
        tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
    let time_to_codegen = start_time.elapsed();

    // We assume that the cost to run LLVM on a CGU is proportional to
    // the time we needed for codegenning it.
    let cost = time_to_codegen.as_nanos() as u64;

    fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm> {
        let cgu = tcx.codegen_unit(cgu_name);
        let _prof_timer = tcx.prof.generic_activity_with_args(
            "codegen_module",
            &[cgu_name.to_string(), cgu.size_estimate().to_string()],
        );
        // Instantiate monomorphizations without filling out definitions yet...
        let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str());
        {
            let cx = CodegenCx::new(tcx, cgu, &llvm_module);
            let mono_items = cx.codegen_unit.items_in_deterministic_order(cx.tcx);
            for &(mono_item, (linkage, visibility)) in &mono_items {
                mono_item.predefine::<Builder<'_, '_, '_>>(&cx, linkage, visibility);
            }

            // ... and now that we have everything pre-defined, fill out those definitions.
            for &(mono_item, _) in &mono_items {
                mono_item.define::<Builder<'_, '_, '_>>(&cx);
            }

            // If this codegen unit contains the main function, also create the
            // wrapper here
            if let Some(entry) = maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx) {
                attributes::sanitize(&cx, SanitizerSet::empty(), entry);
            }

            // Run replace-all-uses-with for statics that need it
            for &(old_g, new_g) in cx.statics_to_rauw().borrow().iter() {
                unsafe {
                    let bitcast = llvm::LLVMConstPointerCast(new_g, cx.val_ty(old_g));
                    llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
                    llvm::LLVMDeleteGlobal(old_g);
                }
            }

            // Finalize code coverage by injecting the coverage map. Note, the coverage map will
            // also be added to the `llvm.used` variable, created next.
            if cx.sess().instrument_coverage() {
                cx.coverageinfo_finalize();
            }

            // Create the llvm.used variable
            // This variable has type [N x i8*] and is stored in the llvm.metadata section
            if !cx.used_statics().borrow().is_empty() {
                cx.create_used_variable()
            }

            // Finalize debuginfo
            if cx.sess().opts.debuginfo != DebugInfo::None {
                cx.debuginfo_finalize();
            }
        }

        ModuleCodegen {
            name: cgu_name.to_string(),
            module_llvm: llvm_module,
            kind: ModuleKind::Regular,
        }
    }

    (module, cost)
}

pub fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) {
    let sect = match attrs.link_section {
        Some(name) => name,
        None => return,
    };
    unsafe {
        let buf = SmallCStr::new(&sect.as_str());
        llvm::LLVMSetSection(llval, buf.as_ptr());
    }
}

pub fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage {
    match linkage {
        Linkage::External => llvm::Linkage::ExternalLinkage,
        Linkage::AvailableExternally => llvm::Linkage::AvailableExternallyLinkage,
        Linkage::LinkOnceAny => llvm::Linkage::LinkOnceAnyLinkage,
        Linkage::LinkOnceODR => llvm::Linkage::LinkOnceODRLinkage,
        Linkage::WeakAny => llvm::Linkage::WeakAnyLinkage,
        Linkage::WeakODR => llvm::Linkage::WeakODRLinkage,
        Linkage::Appending => llvm::Linkage::AppendingLinkage,
        Linkage::Internal => llvm::Linkage::InternalLinkage,
        Linkage::Private => llvm::Linkage::PrivateLinkage,
        Linkage::ExternalWeak => llvm::Linkage::ExternalWeakLinkage,
        Linkage::Common => llvm::Linkage::CommonLinkage,
    }
}

pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
    match linkage {
        Visibility::Default => llvm::Visibility::Default,
        Visibility::Hidden => llvm::Visibility::Hidden,
        Visibility::Protected => llvm::Visibility::Protected,
    }
}
<commit_msg>Add link to historic note<commit_after>//! Codegen the MIR to the LLVM IR.
//!
//! Hopefully useful general knowledge about codegen:
//!
//! * There's no way to find out the [`Ty`] type of a [`Value`]. Doing so
//!   would be "trying to get the eggs out of an omelette" (credit:
//!   pcwalton). You can, instead, find out its [`llvm::Type`] by calling [`val_ty`],
//!   but one [`llvm::Type`] corresponds to many [`Ty`]s; for instance, `tup(int, int,
//!   int)` and `rec(x=int, y=int, z=int)` will have the same [`llvm::Type`].
//!
//! [`Ty`]: rustc_middle::ty::Ty
//! [`val_ty`]: common::val_ty

use super::ModuleLlvm;

use crate::attributes;
use crate::builder::Builder;
use crate::common;
use crate::context::CodegenCx;
use crate::llvm;
use crate::value::Value;

use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
use rustc_codegen_ssa::mono_item::MonoItemExt;
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_middle::dep_graph;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::middle::cstore::EncodedMetadata;
use rustc_middle::middle::exported_symbols;
use rustc_middle::mir::mono::{Linkage, Visibility};
use rustc_middle::ty::TyCtxt;
use rustc_session::config::DebugInfo;
use rustc_span::symbol::Symbol;
use rustc_target::spec::SanitizerSet;

use std::ffi::CString;
use std::time::Instant;

pub fn write_compressed_metadata<'tcx>(
    tcx: TyCtxt<'tcx>,
    metadata: &EncodedMetadata,
    llvm_module: &mut ModuleLlvm,
) {
    use snap::write::FrameEncoder;
    use std::io::Write;

    // Historical note:
    //
    // When using link.exe it was seen that the section name `.note.rustc`
    // was getting shortened to `.note.ru`, and according to the PE and COFF
    // specification:
    //
    // > Executable images do not use a string table and do not support
    // > section names longer than 8 characters
    //
    // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
    //
    // As a result, we choose a slightly shorter name! As to why
    // `.note.rustc` works on MinGW, see
    // https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/lld/COFF/Writer.cpp#L1190-L1197
    let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" };

    let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod());
    let mut compressed = tcx.metadata_encoding_version();
    FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();

    let llmeta = common::bytes_in_context(metadata_llcx, &compressed);
    let llconst = common::struct_in_context(metadata_llcx, &[llmeta], false);
    let name = exported_symbols::metadata_symbol_name(tcx);
    let buf = CString::new(name).unwrap();
    let llglobal =
        unsafe { llvm::LLVMAddGlobal(metadata_llmod, common::val_ty(llconst), buf.as_ptr()) };
    unsafe {
        llvm::LLVMSetInitializer(llglobal, llconst);
        let name = SmallCStr::new(section_name);
        llvm::LLVMSetSection(llglobal, name.as_ptr());

        // Also generate a .section directive to force no
        // flags, at least for ELF outputs, so that the
        // metadata doesn't get loaded into memory.
        let directive = format!(".section {}", section_name);
        llvm::LLVMSetModuleInlineAsm2(metadata_llmod, directive.as_ptr().cast(), directive.len())
    }
}

pub struct ValueIter<'ll> {
    cur: Option<&'ll Value>,
    step: unsafe extern "C" fn(&'ll Value) -> Option<&'ll Value>,
}

impl Iterator for ValueIter<'ll> {
    type Item = &'ll Value;

    fn next(&mut self) -> Option<&'ll Value> {
        let old = self.cur;
        if let Some(old) = old {
            self.cur = unsafe { (self.step)(old) };
        }
        old
    }
}

pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> {
    unsafe { ValueIter { cur: llvm::LLVMGetFirstGlobal(llmod), step: llvm::LLVMGetNextGlobal } }
}

pub fn compile_codegen_unit(
    tcx: TyCtxt<'tcx>,
    cgu_name: Symbol,
) -> (ModuleCodegen<ModuleLlvm>, u64) {
    let start_time = Instant::now();

    let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
    let (module, _) =
        tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
    let time_to_codegen = start_time.elapsed();

    // We assume that the cost to run LLVM on a CGU is proportional to
    // the time we needed for codegenning it.
    let cost = time_to_codegen.as_nanos() as u64;

    fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<ModuleLlvm> {
        let cgu = tcx.codegen_unit(cgu_name);
        let _prof_timer = tcx.prof.generic_activity_with_args(
            "codegen_module",
            &[cgu_name.to_string(), cgu.size_estimate().to_string()],
        );
        // Instantiate monomorphizations without filling out definitions yet...
        let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str());
        {
            let cx = CodegenCx::new(tcx, cgu, &llvm_module);
            let mono_items = cx.codegen_unit.items_in_deterministic_order(cx.tcx);
            for &(mono_item, (linkage, visibility)) in &mono_items {
                mono_item.predefine::<Builder<'_, '_, '_>>(&cx, linkage, visibility);
            }

            // ... and now that we have everything pre-defined, fill out those definitions.
            for &(mono_item, _) in &mono_items {
                mono_item.define::<Builder<'_, '_, '_>>(&cx);
            }

            // If this codegen unit contains the main function, also create the
            // wrapper here
            if let Some(entry) = maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx) {
                attributes::sanitize(&cx, SanitizerSet::empty(), entry);
            }

            // Run replace-all-uses-with for statics that need it
            for &(old_g, new_g) in cx.statics_to_rauw().borrow().iter() {
                unsafe {
                    let bitcast = llvm::LLVMConstPointerCast(new_g, cx.val_ty(old_g));
                    llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
                    llvm::LLVMDeleteGlobal(old_g);
                }
            }

            // Finalize code coverage by injecting the coverage map. Note, the coverage map will
            // also be added to the `llvm.used` variable, created next.
            if cx.sess().instrument_coverage() {
                cx.coverageinfo_finalize();
            }

            // Create the llvm.used variable
            // This variable has type [N x i8*] and is stored in the llvm.metadata section
            if !cx.used_statics().borrow().is_empty() {
                cx.create_used_variable()
            }

            // Finalize debuginfo
            if cx.sess().opts.debuginfo != DebugInfo::None {
                cx.debuginfo_finalize();
            }
        }

        ModuleCodegen {
            name: cgu_name.to_string(),
            module_llvm: llvm_module,
            kind: ModuleKind::Regular,
        }
    }

    (module, cost)
}

pub fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) {
    let sect = match attrs.link_section {
        Some(name) => name,
        None => return,
    };
    unsafe {
        let buf = SmallCStr::new(&sect.as_str());
        llvm::LLVMSetSection(llval, buf.as_ptr());
    }
}

pub fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage {
    match linkage {
        Linkage::External => llvm::Linkage::ExternalLinkage,
        Linkage::AvailableExternally => llvm::Linkage::AvailableExternallyLinkage,
        Linkage::LinkOnceAny => llvm::Linkage::LinkOnceAnyLinkage,
        Linkage::LinkOnceODR => llvm::Linkage::LinkOnceODRLinkage,
        Linkage::WeakAny => llvm::Linkage::WeakAnyLinkage,
        Linkage::WeakODR => llvm::Linkage::WeakODRLinkage,
        Linkage::Appending => llvm::Linkage::AppendingLinkage,
        Linkage::Internal => llvm::Linkage::InternalLinkage,
        Linkage::Private => llvm::Linkage::PrivateLinkage,
        Linkage::ExternalWeak => llvm::Linkage::ExternalWeakLinkage,
        Linkage::Common => llvm::Linkage::CommonLinkage,
    }
}

pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
    match linkage {
        Visibility::Default => llvm::Visibility::Default,
        Visibility::Hidden => llvm::Visibility::Hidden,
        Visibility::Protected => llvm::Visibility::Protected,
    }
}
<|endoftext|>


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

use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::RTCDataChannelInit;
use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::RTCDataChannelMethods;
use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::{RTCErrorDetailType, RTCErrorInit};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::blob::Blob;
use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::rtcerror::RTCError;
use crate::dom::rtcerrorevent::RTCErrorEvent;
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use js::rust::CustomAutoRooterGuard;
use js::typedarray::{ArrayBuffer, ArrayBufferView};
use servo_media::webrtc::{
    WebRtcController, WebRtcDataChannelBackend, WebRtcDataChannelInit, WebRtcError,
};
use std::sync::mpsc;

#[dom_struct]
pub struct RTCDataChannel {
    eventtarget: EventTarget,
    #[ignore_malloc_size_of = "defined in servo-media"]
    channel: Box<dyn WebRtcDataChannelBackend>,
    label: USVString,
    ordered: bool,
    max_packet_life_time: Option<u16>,
    max_retransmits: Option<u16>,
    protocol: USVString,
    negotiated: bool,
    id: Option<u16>,
}

impl RTCDataChannel {
    #[allow(unrooted_must_root)]
    pub fn new_inherited(
        webrtc_controller: &DomRefCell<Option<WebRtcController>>,
        label: USVString,
        options: &RTCDataChannelInit,
    ) -> RTCDataChannel {
        let webrtc = webrtc_controller.borrow();
        let webrtc = webrtc.as_ref().unwrap();

        let (sender, receiver) = mpsc::channel::<Box<dyn WebRtcDataChannelBackend>>();

        let mut init: WebRtcDataChannelInit = options.into();
        init.label = label.to_string();

        webrtc.create_data_channel(init, sender);
        let channel = receiver.recv().unwrap();

        let rtc_data_channel = RTCDataChannel {
            eventtarget: EventTarget::new_inherited(),
            channel,
            label,
            ordered: options.ordered,
            max_packet_life_time: options.maxPacketLifeTime,
            max_retransmits: options.maxRetransmits,
            protocol: options.protocol.clone(),
            negotiated: options.negotiated,
            id: options.id,
        };

        let trusted = Trusted::new(&rtc_data_channel);

        let this = trusted.clone();
        rtc_data_channel.channel.set_on_open(Box::new(move || {
            let this_ = this.clone();
            let global = this.root().global();
            let task_source = global.networking_task_source();
            let _ = task_source.queue(
                task!(on_open: move || {
                    this_.root().on_open();
                }),
                global.upcast(),
            );
        }));

        let this = trusted.clone();
        rtc_data_channel.channel.set_on_close(Box::new(move || {
            let this_ = this.clone();
            let global = this.root().global();
            let task_source = global.networking_task_source();
            let _ = task_source.queue(
                task!(on_close: move || {
                    this_.root().on_close();
                }),
                global.upcast(),
            );
        }));

        let this = trusted.clone();
        rtc_data_channel
            .channel
            .set_on_error(Box::new(move |error| {
                let this_ = this.clone();
                let global = this.root().global();
                let task_source = global.networking_task_source();
                let _ = task_source.queue(
                    task!(on_error: move || {
                        this_.root().on_error(error);
                    }),
                    global.upcast(),
                );
            }));

        let this = trusted.clone();
        rtc_data_channel
            .channel
            .set_on_message(Box::new(move |message| {
                let this_ = this.clone();
                let global = this.root().global();
                let task_source = global.networking_task_source();
                let _ = task_source.queue(
                    task!(on_message: move || {
                        this_.root().on_message(message);
                    }),
                    global.upcast(),
                );
            }));

        rtc_data_channel
    }

    pub fn new(
        global: &GlobalScope,
        webrtc_controller: &DomRefCell<Option<WebRtcController>>,
        label: USVString,
        options: &RTCDataChannelInit,
    ) -> DomRoot<RTCDataChannel> {
        reflect_dom_object(
            Box::new(RTCDataChannel::new_inherited(
                webrtc_controller,
                label,
                options,
            )),
            global,
        )
    }

    fn on_open(&self) {
        let event = Event::new(
            &self.global(),
            atom!("open"),
            EventBubbles::DoesNotBubble,
            EventCancelable::NotCancelable,
        );
        event.upcast::<Event>().fire(self.upcast());
    }

    fn on_close(&self) {
        let event = Event::new(
            &self.global(),
            atom!("close"),
            EventBubbles::DoesNotBubble,
            EventCancelable::NotCancelable,
        );
        event.upcast::<Event>().fire(self.upcast());
    }

    fn on_error(&self, error: WebRtcError) {
        let init = RTCErrorInit {
            errorDetail: RTCErrorDetailType::Data_channel_failure,
            httpRequestStatusCode: None,
            receivedAlert: None,
            sctpCauseCode: None,
            sdpLineNumber: None,
            sentAlert: None,
        };
        let message = match error {
            WebRtcError::Backend(message) => DOMString::from(message),
        };
        let error = RTCError::new(&self.global(), &init, message);
        let event = RTCErrorEvent::new(&self.global(), atom!("error"), false, false, &error);
        event.upcast::<Event>().fire(self.upcast());
    }

    fn on_message(&self, message: String) {}
}

impl RTCDataChannelMethods for RTCDataChannel {
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onopen
    event_handler!(open, GetOnopen, SetOnopen);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onbufferedamountlow
    event_handler!(
        bufferedamountlow,
        GetOnbufferedamountlow,
        SetOnbufferedamountlow
    );
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onerror
    event_handler!(error, GetOnerror, SetOnerror);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclosing
    event_handler!(closing, GetOnclosing, SetOnclosing);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclose
    event_handler!(close, GetOnclose, SetOnclose);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onmessage
    event_handler!(message, GetOnmessage, SetOnmessage);

    // https://www.w3.org/TR/webrtc/#dom-datachannel-label
    fn Label(&self) -> USVString {
        self.label.clone()
    }
    // https://www.w3.org/TR/webrtc/#dom-datachannel-ordered
    fn Ordered(&self) -> bool {
        self.ordered
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-maxpacketlifetime
    fn GetMaxPacketLifeTime(&self) -> Option<u16> {
        self.max_packet_life_time
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-maxretransmits
    fn GetMaxRetransmits(&self) -> Option<u16> {
        self.max_retransmits
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-protocol
    fn Protocol(&self) -> USVString {
        self.protocol.clone()
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-negotiated
    fn Negotiated(&self) -> bool {
        self.negotiated
    }

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-id
    fn GetId(&self) -> Option<u16> {
        self.id
    }

    //    fn ReadyState(&self) -> RTCDataChannelState;
    //    fn BufferedAmount(&self) -> u32;
    //    fn BufferedAmountLowThreshold(&self) -> u32;
    //    fn SetBufferedAmountLowThreshold(&self, value: u32) -> ();

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-close
    fn Close(&self) -> () {}

    //    fn BinaryType(&self) -> DOMString;
    //    fn SetBinaryType(&self, value: DOMString) -> ();

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send
    fn Send(&self, data: USVString) -> () {}

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-1
    fn Send_(&self, data: &Blob) -> () {}

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-2
    fn Send__(&self, data: CustomAutoRooterGuard<ArrayBuffer>) -> () {}

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-3
    fn Send___(&self, data: CustomAutoRooterGuard<ArrayBufferView>) -> () {}
}

impl From<&RTCDataChannelInit> for WebRtcDataChannelInit {
    fn from(init: &RTCDataChannelInit) -> WebRtcDataChannelInit {
        WebRtcDataChannelInit {
            label: String::new(),
            id: init.id,
            max_packet_life_time: init.maxPacketLifeTime,
            max_retransmits: init.maxRetransmits,
            negotiated: init.negotiated,
            ordered: init.ordered,
            protocol: init.protocol.to_string(),
        }
    }
}
<commit_msg>On data channel message handler<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::RTCDataChannelInit;
use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::RTCDataChannelMethods;
use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::{RTCErrorDetailType, RTCErrorInit};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::blob::Blob;
use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageevent::MessageEvent;
use crate::dom::rtcerror::RTCError;
use crate::dom::rtcerrorevent::RTCErrorEvent;
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use js::conversions::ToJSValConvertible;
use js::jsapi::JSAutoRealm;
use js::jsval::UndefinedValue;
use js::rust::CustomAutoRooterGuard;
use js::typedarray::{ArrayBuffer, ArrayBufferView};
use servo_media::webrtc::{
    WebRtcController, WebRtcDataChannelBackend, WebRtcDataChannelInit, WebRtcError,
};
use std::sync::mpsc;

#[dom_struct]
pub struct RTCDataChannel {
    eventtarget: EventTarget,
    #[ignore_malloc_size_of = "defined in servo-media"]
    channel: Box<dyn WebRtcDataChannelBackend>,
    label: USVString,
    ordered: bool,
    max_packet_life_time: Option<u16>,
    max_retransmits: Option<u16>,
    protocol: USVString,
    negotiated: bool,
    id: Option<u16>,
}

impl RTCDataChannel {
    #[allow(unrooted_must_root)]
    pub fn new_inherited(
        webrtc_controller: &DomRefCell<Option<WebRtcController>>,
        label: USVString,
        options: &RTCDataChannelInit,
    ) -> RTCDataChannel {
        let webrtc = webrtc_controller.borrow();
        let webrtc = webrtc.as_ref().unwrap();

        let (sender, receiver) = mpsc::channel::<Box<dyn WebRtcDataChannelBackend>>();

        let mut init: WebRtcDataChannelInit = options.into();
        init.label = label.to_string();

        webrtc.create_data_channel(init, sender);
        let channel = receiver.recv().unwrap();

        let rtc_data_channel = RTCDataChannel {
            eventtarget: EventTarget::new_inherited(),
            channel,
            label,
            ordered: options.ordered,
            max_packet_life_time: options.maxPacketLifeTime,
            max_retransmits: options.maxRetransmits,
            protocol: options.protocol.clone(),
            negotiated: options.negotiated,
            id: options.id,
        };

        let trusted = Trusted::new(&rtc_data_channel);

        let this = trusted.clone();
        rtc_data_channel.channel.set_on_open(Box::new(move || {
            let this_ = this.clone();
            let global = this.root().global();
            let task_source = global.networking_task_source();
            let _ = task_source.queue(
                task!(on_open: move || {
                    this_.root().on_open();
                }),
                global.upcast(),
            );
        }));

        let this = trusted.clone();
        rtc_data_channel.channel.set_on_close(Box::new(move || {
            let this_ = this.clone();
            let global = this.root().global();
            let task_source = global.networking_task_source();
            let _ = task_source.queue(
                task!(on_close: move || {
                    this_.root().on_close();
                }),
                global.upcast(),
            );
        }));

        let this = trusted.clone();
        rtc_data_channel
            .channel
            .set_on_error(Box::new(move |error| {
                let this_ = this.clone();
                let global = this.root().global();
                let task_source = global.networking_task_source();
                let _ = task_source.queue(
                    task!(on_error: move || {
                        this_.root().on_error(error);
                    }),
                    global.upcast(),
                );
            }));

        let this = trusted.clone();
        rtc_data_channel
            .channel
            .set_on_message(Box::new(move |message| {
                let this_ = this.clone();
                let global = this.root().global();
                let task_source = global.networking_task_source();
                let _ = task_source.queue(
                    task!(on_message: move || {
                        this_.root().on_message(message);
                    }),
                    global.upcast(),
                );
            }));

        rtc_data_channel
    }

    pub fn new(
        global: &GlobalScope,
        webrtc_controller: &DomRefCell<Option<WebRtcController>>,
        label: USVString,
        options: &RTCDataChannelInit,
    ) -> DomRoot<RTCDataChannel> {
        reflect_dom_object(
            Box::new(RTCDataChannel::new_inherited(
                webrtc_controller,
                label,
                options,
            )),
            global,
        )
    }

    fn on_open(&self) {
        let event = Event::new(
            &self.global(),
            atom!("open"),
            EventBubbles::DoesNotBubble,
            EventCancelable::NotCancelable,
        );
        event.upcast::<Event>().fire(self.upcast());
    }

    fn on_close(&self) {
        let event = Event::new(
            &self.global(),
            atom!("close"),
            EventBubbles::DoesNotBubble,
            EventCancelable::NotCancelable,
        );
        event.upcast::<Event>().fire(self.upcast());
    }

    fn on_error(&self, error: WebRtcError) {
        let init = RTCErrorInit {
            errorDetail: RTCErrorDetailType::Data_channel_failure,
            httpRequestStatusCode: None,
            receivedAlert: None,
            sctpCauseCode: None,
            sdpLineNumber: None,
            sentAlert: None,
        };
        let message = match error {
            WebRtcError::Backend(message) => DOMString::from(message),
        };
        let error = RTCError::new(&self.global(), &init, message);
        let event = RTCErrorEvent::new(&self.global(), atom!("error"), false, false, &error);
        event.upcast::<Event>().fire(self.upcast());
    }

    #[allow(unsafe_code)]
    fn on_message(&self, text: String) {
        // XXX(ferjm) Support binary messages
        unsafe {
            let global = self.global();
            let cx = global.get_cx();
            let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get());
            rooted!(in(*cx) let mut message = UndefinedValue());
            text.to_jsval(*cx, message.handle_mut());

            MessageEvent::dispatch_jsval(
                self.upcast(),
                &global,
                message.handle(),
                Some(&global.origin().immutable().ascii_serialization()),
                None,
                vec![],
            );
        }
    }
}

impl RTCDataChannelMethods for RTCDataChannel {
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onopen
    event_handler!(open, GetOnopen, SetOnopen);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onbufferedamountlow
    event_handler!(
        bufferedamountlow,
        GetOnbufferedamountlow,
        SetOnbufferedamountlow
    );
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onerror
    event_handler!(error, GetOnerror, SetOnerror);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclosing
    event_handler!(closing, GetOnclosing, SetOnclosing);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclose
    event_handler!(close, GetOnclose, SetOnclose);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onmessage
    event_handler!(message, GetOnmessage, SetOnmessage);

    // https://www.w3.org/TR/webrtc/#dom-datachannel-label
    fn Label(&self) -> USVString {
        self.label.clone()
    }
    // https://www.w3.org/TR/webrtc/#dom-datachannel-ordered
    fn Ordered(&self) -> bool {
        self.ordered
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-maxpacketlifetime
    fn GetMaxPacketLifeTime(&self) -> Option<u16> {
        self.max_packet_life_time
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-maxretransmits
    fn GetMaxRetransmits(&self) -> Option<u16> {
        self.max_retransmits
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-protocol
    fn Protocol(&self) -> USVString {
        self.protocol.clone()
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-negotiated
    fn Negotiated(&self) -> bool {
        self.negotiated
    }

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-id
    fn GetId(&self) -> Option<u16> {
        self.id
    }

    //    fn ReadyState(&self) -> RTCDataChannelState;
    //    fn BufferedAmount(&self) -> u32;
    //    fn BufferedAmountLowThreshold(&self) -> u32;
    //    fn SetBufferedAmountLowThreshold(&self, value: u32) -> ();

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-close
    fn Close(&self) -> () {}

    //    fn BinaryType(&self) -> DOMString;
    //    fn SetBinaryType(&self, value: DOMString) -> ();

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send
    fn Send(&self, data: USVString) -> () {}

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-1
    fn Send_(&self, data: &Blob) -> () {}

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-2
    fn Send__(&self, data: CustomAutoRooterGuard<ArrayBuffer>) -> () {}

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-3
    fn Send___(&self, data: CustomAutoRooterGuard<ArrayBufferView>) -> () {}
}

impl From<&RTCDataChannelInit> for WebRtcDataChannelInit {
    fn from(init: &RTCDataChannelInit) -> WebRtcDataChannelInit {
        WebRtcDataChannelInit {
            label: String::new(),
            id: init.id,
            max_packet_life_time: init.maxPacketLifeTime,
            max_retransmits: init.maxRetransmits,
            negotiated: init.negotiated,
            ordered: init.ordered,
            protocol: init.protocol.to_string(),
        }
    }
}
<|endoftext|>