<commit_before>use std;
import io::{writer_util, reader_util};
import std::map;
import map::hashmap;
import result;

export rowreader, rowiter,
       new_reader, new_reader_readlen,
       hashmap_iter, hashmap_iter_full;

enum state {
    fieldstart(bool),
    infield(uint, uint),
    inquotedfield(uint, uint),
    inquote(uint, uint)
}

type rowreader = {
    readlen: uint,
    delim: char,
    quote: char,
    f : io::reader,
    mut offset : uint,
    mut buffers : [[char]],
    mut bufferlens: [uint],
    mut state : state,
    mut trailing_nl : bool,
    mut terminating : bool
};

type bufferdescr = {
    escaped: bool,
    sb: uint,
    eb: uint,
    start: uint,
    end: uint
};

enum fieldtype {
    emptyfield(),
    bufferfield(bufferdescr)
}

iface rowiter {
    fn readrow(&row: [str]) -> bool;
}

fn new_reader(+f: io::reader, +delim: char, +quote: char) -> rowreader {
    {
        new_reader_readlen(f, delim, quote, 1024u)
    }
}

fn new_reader_readlen(+f: io::reader, +delim: char, +quote: char, rl: uint) -> rowreader {
    {
        readlen: rl,
        delim: delim,
        quote: quote,
        f: f,
        mut offset : 0u,
        mut buffers : [],
        mut bufferlens: [],
        mut state : fieldstart(false),
        mut trailing_nl : false,
        mut terminating: false
    }
}

fn statestr(state: state) -> str {
    alt state {
        fieldstart(after_delim) {
            #fmt("fieldstart : after_delim %b", after_delim)
        }
        infield(b,o) {
            #fmt("field : %u %u", b, o)
        }
        inquotedfield(b, o) {
            #fmt("inquotedfield : %u %u", b, o)
        }
        inquote(b, o) {
            #fmt("inquote : %u %u", b, o)
        }
    }
}

fn unescape(escaped: [char]) -> [char] {
    let mut r : [char] = [];
    vec::reserve(r, vec::len(escaped));
    let mut in_q = false;
    for c in escaped {
        if in_q {
            assert(c == '"');
            in_q = false;
        } else {
            in_q = c == '"';
            r += [c];
        }
    }
    ret r;
}

impl of rowiter for rowreader {
    #[inline]
    fn readrow(&row: [str]) -> bool {
        fn row_from_buf(self: rowreader, &fields: [str]) -> bool {
            fn decode(buffers: [[char]], field: fieldtype) -> str {
                alt field {
                    emptyfield() { "" }
                    bufferfield(desc) {
                        let mut buf = [];
                        vec::reserve(buf, 256u);
                        let mut i = desc.sb;
                        while i <= desc.eb {
                            let from = if (i == desc.sb)
                                { desc.start } else { 0u };
                            let to = if (i == desc.eb)
                                { desc.end } else { vec::len(buffers[i]) };
                            let mut j = from;
                            while j < to {
                                buf += [buffers[i][j]];
                                j += 1u;
                            }
                            i = i + 1u;
                        }
                        if desc.escaped {
                            buf = unescape(buf);
                        }
                        str::from_chars(buf)
                    }
                }
            }
            #[inline]
            fn new_bufferfield(self: rowreader, escaped: bool, sb: uint, so: uint, eo: uint) -> fieldtype {
                let mut eb = vec::len(self.buffers) - 1u;
                let mut sb = sb, so = so, eo = eo;
                if escaped {
                    so += 1u;
                    if so > self.bufferlens[sb] {
                        sb += 1u;
                        so = self.bufferlens[sb] - 1u;
                    }
                    if eo > 0u {
                        eo -= 1u;
                    } else {
                        eb -= 1u;
                        eo = self.bufferlens[eb] - 1u;
                    }
                }
                bufferfield({ escaped: escaped, sb: sb, eb: eb, start: so, end: eo })
            }
            let cbuffer = vec::len(self.buffers) - 1u;
            let buf = self.buffers[cbuffer];
            while self.offset < vec::len(buf) {
                let coffset = self.offset;
                let c : char = buf[coffset];
                #debug("got '%c' | %s", c, statestr(self.state));
                self.offset += 1u;
                alt self.state {
                    fieldstart(after_delim) {
                        #debug("fieldstart : after_delim %b", after_delim);
                        if c == self.quote {
                            self.state = inquotedfield(cbuffer, coffset);
                        } else if c == '\n' {
                            if after_delim {
                                fields += [decode(self.buffers, emptyfield)];
                            }
                            ret true;
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [decode(self.buffers, emptyfield)];
                        } else {
                            self.state = infield(cbuffer, coffset);
                        }
                    }
                    infield(b,o) {
                        #debug("field : %u %u", b, o);
                        if c == '\n' {
                            fields += [decode(self.buffers, new_bufferfield(self, false, b, o, coffset))];
                            ret true;
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [decode(self.buffers, new_bufferfield(self, false, b, o, coffset))];
                        }
                    }
                    inquotedfield(b, o) {
                        #debug("inquotedfield : %u %u", b, o);
                        if c == self.quote {
                            self.state = inquote(b, o);
                        }
                    }
                    inquote(b, o) {
                        #debug("inquote : %u %u", b, o);
                        if c == '\n' {
                            fields += [decode(self.buffers, new_bufferfield(self, true, b, o, coffset))];
                            ret true;
                        } else if c == self.quote {
                            self.state = inquotedfield(b, o);
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [decode(self.buffers, new_bufferfield(self, true, b, o, coffset))];
                        }
                        // swallow odd chars, eg. space between field and "
                    }
                }
                #debug("now %s", statestr(self.state));
            }
            ret false;
        }
        self.state = fieldstart(false);
        let mut do_read = vec::len(self.buffers) == 0u;
        row = [];
        while !self.terminating {
            if do_read {
                let mut data = self.f.read_chars(self.readlen);
                if vec::len(data) == 0u {
                    if !self.trailing_nl {
                        self.terminating = true;
                        data = ['\n'];
                    } else {
                        ret false;
                    }
                }
                // this is horrible, but it avoids the whole parser needing
                // to know about \r.
                data = vec::filter(data) { |c| c != '\r' };
                let data_len = vec::len(data);
                if data_len == 0u {
                    cont;
                }
                self.trailing_nl = data[data_len - 1u] == '\n';
                self.buffers += [data];
                self.bufferlens += [data_len];
                self.offset = 0u;
            }

            if row_from_buf(self, row) {
                let buflen = vec::len(self.buffers);
                if buflen > 1u {
                    self.buffers = [self.buffers[buflen-1u]];
                    self.bufferlens = [self.bufferlens[buflen-1u]];
                }
                ret true;
            }
            do_read = true;
        }
        ret false;
    }
}

fn hashmap_iter_cols(r: rowreader, cols: [str], f: fn(map::hashmap<str, str>)) {
    let mut fields : [str] = [];
    // can reuse, we're just shoving new vals in same cols..
    let m : map::hashmap<str, str> = map::str_hash();
    let ncols = vec::len(cols);
    while r.readrow(fields) {
        log(error, fields);
        if vec::len(fields) != ncols {
            cont; // FIXME: how to flag that we dropped a crazy row?
        }
        let mut col = 0u;
        vec::iter(fields) { |s|
            m.insert(cols[col], s);
            col += 1u;
        };
        f(m);
    }
}

// reads the first row as a header, to derive keys for a hashmap
// emitted for each subsequent row
fn hashmap_iter(r: rowreader, f: fn(map::hashmap<str, str>)) {
    let mut row: [str] = [];
    if r.readrow(row) {
        hashmap_iter_cols(r, row, f);
    }
}

// as hashmap_iter, but first apply 'hc' to each header; allows
// cleaning up headers; also allows verification that heads are
// satisfactory
fn hashmap_iter_full(r: rowreader, hmap: fn(&&h: str) -> str, hver: fn(cols: [str]) -> bool, f: fn(map::hashmap<str, str>)) {
    let mut row: [str] = [];
    if r.readrow(row) {
        let cols : [str] = vec::map(row, hmap);
        if !hver(cols) {
            ret;
        }
        hashmap_iter_cols(r, cols, f);
    }
}

#[cfg(test)]
mod test {
    fn rowmatch(testdata: str, expected: [[str]]) {
        let chk = fn@(s: str, mk: fn(io::reader) -> rowreader) {
            let f = io::str_reader(s);
            let r = mk(f);
            let mut i = 0u;
            let mut row: [str] = [];
            loop {
                if !r.readrow(row) {
                    break;
                }
                let expect = expected[i];
                assert(vec::len(row) == vec::len(expect));
                let mut j = 0u;
                while j < row.len() {
                    assert(row[j] == expect[j]);
                    j += 1u;
                }
                i += 1u;
            }
            assert(i == vec::len(expected));
        };
        let runchecks = fn@(s: str) {
            // test default reader params
            chk(s) { |inp|
                new_reader_readlen(inp, ',', '"', 2u)
            };
            // test default constructor
            chk(s) { |inp|
                new_reader(inp, ',', '"')
            };
            // test continuations over read buffers
            let mut j = 1u;
            while j < str::len(s) {
                chk(s) { |inp|
                    new_reader_readlen(inp, ',', '"', j)
                };
                j += 1u;
            }
            ret;
        };
        // so we can test trailing newline case, testdata
        // must not end in \n - leave off the last newline
        runchecks(testdata);
        runchecks(str::replace(testdata, "\n", "\r\n"));
        if !str::ends_with(testdata, "\n") {
            runchecks(testdata+"\n");
            runchecks(str::replace(testdata+"\n", "\n", "\r\n"));
        }
    }

    #[test]
    fn simple() {
        rowmatch("a,b,c,d\n1,2,3,4",
                 [["a", "b", "c", "d"], ["1", "2", "3", "4"]]);
    }

    #[test]
    fn trailing_comma() {
        rowmatch("a,b,c,d\n1,2,3,4,",
                 [["a", "b", "c", "d"], ["1", "2", "3", "4", ""]]);
    }

    #[test]
    fn leading_comma() {
        rowmatch("a,b,c,d\n,1,2,3,4",
                 [["a", "b", "c", "d"], ["", "1", "2", "3", "4"]]);
    }

    #[test]
    fn quote_simple() {
        rowmatch("\"Hello\",\"There\"\na,b,\"c\",d",
                 [["Hello", "There"], ["a", "b", "c", "d"]]);
    }

    #[test]
    fn quote_nested() {
        rowmatch("\"Hello\",\"There is a \"\"fly\"\" in my soup\"\na,b,\"c\",d",
                 [["Hello", "There is a \"fly\" in my soup"], ["a", "b", "c", "d"]]);
    }

    #[test]
    fn quote_with_comma() {
        rowmatch("\"1,2\"",
                 [["1,2"]])
    }

    #[test]
    fn quote_with_other_comma() {
        rowmatch("1,2,3,\"a,b,c\"",
                 [["1", "2", "3", "a,b,c"]])
    }

    #[test]
    fn blank_line() {
        rowmatch("\n\n", [[], []]);
    }
}

<commit_msg>remove hashmap iter stuff<commit_after>use std;
import io::{writer_util, reader_util};
import std::map;
import map::hashmap;
import result;

export rowreader, rowiter,
       new_reader, new_reader_readlen;

enum state {
    fieldstart(bool),
    infield(uint, uint),
    inquotedfield(uint, uint),
    inquote(uint, uint)
}

type rowreader = {
    readlen: uint,
    delim: char,
    quote: char,
    f : io::reader,
    mut offset : uint,
    mut buffers : [[char]],
    mut state : state,
    mut trailing_nl : bool,
    mut terminating : bool
};

type bufferdescr = {
    escaped: bool,
    sb: uint,
    eb: uint,
    start: uint,
    end: uint
};

enum fieldtype {
    emptyfield(),
    bufferfield(bufferdescr)
}

iface rowiter {
    fn readrow(&row: [str]) -> bool;
}

fn new_reader(+f: io::reader, +delim: char, +quote: char) -> rowreader {
    {
        new_reader_readlen(f, delim, quote, 1024u)
    }
}

fn new_reader_readlen(+f: io::reader, +delim: char, +quote: char, rl: uint) -> rowreader {
    {
        readlen: rl,
        delim: delim,
        quote: quote,
        f: f,
        mut offset : 0u,
        mut buffers : [],
        mut state : fieldstart(false),
        mut trailing_nl : false,
        mut terminating: false
    }
}

fn statestr(state: state) -> str {
    alt state {
        fieldstart(after_delim) {
            #fmt("fieldstart : after_delim %b", after_delim)
        }
        infield(b,o) {
            #fmt("field : %u %u", b, o)
        }
        inquotedfield(b, o) {
            #fmt("inquotedfield : %u %u", b, o)
        }
        inquote(b, o) {
            #fmt("inquote : %u %u", b, o)
        }
    }
}

fn unescape(escaped: [char]) -> [char] {
    let mut r : [char] = [];
    vec::reserve(r, vec::len(escaped));
    let mut in_q = false;
    for c in escaped {
        if in_q {
            assert(c == '"');
            in_q = false;
        } else {
            in_q = c == '"';
            r += [c];
        }
    }
    ret r;
}

impl of rowiter for rowreader {
    #[inline]
    fn readrow(&row: [str]) -> bool {
        fn row_from_buf(self: rowreader, &fields: [str]) -> bool {
            fn decode(buffers: [[char]], field: fieldtype) -> str {
                alt field {
                    emptyfield() { "" }
                    bufferfield(desc) {
                        let mut buf = [];
                        vec::reserve(buf, 256u);
                        let mut i = desc.sb;
                        while i <= desc.eb {
                            let from = if (i == desc.sb)
                                { desc.start } else { 0u };
                            let to = if (i == desc.eb)
                                { desc.end } else { vec::len(buffers[i]) };
                            let mut j = from;
                            while j < to {
                                buf += [buffers[i][j]];
                                j += 1u;
                            }
                            i = i + 1u;
                        }
                        if desc.escaped {
                            buf = unescape(buf);
                        }
                        str::from_chars(buf)
                    }
                }
            }
            #[inline]
            fn new_bufferfield(self: rowreader, escaped: bool, sb: uint, so: uint, eo: uint) -> fieldtype {
                let mut eb = vec::len(self.buffers) - 1u;
                let mut sb = sb, so = so, eo = eo;
                if escaped {
                    so += 1u;
                    if so > vec::len(self.buffers[sb]) {
                        sb += 1u;
                        so = vec::len(self.buffers[sb]) - 1u;
                    }
                    if eo > 0u {
                        eo -= 1u;
                    } else {
                        eb -= 1u;
                        eo = vec::len(self.buffers[eb]) - 1u;
                    }
                }
                bufferfield({ escaped: escaped, sb: sb, eb: eb, start: so, end: eo })
            }
            let cbuffer = vec::len(self.buffers) - 1u;
            let buf = self.buffers[cbuffer];
            while self.offset < vec::len(buf) {
                let coffset = self.offset;
                let c : char = buf[coffset];
                #debug("got '%c' | %s", c, statestr(self.state));
                self.offset += 1u;
                alt self.state {
                    fieldstart(after_delim) {
                        #debug("fieldstart : after_delim %b", after_delim);
                        if c == self.quote {
                            self.state = inquotedfield(cbuffer, coffset);
                        } else if c == '\n' {
                            if after_delim {
                                fields += [decode(self.buffers, emptyfield)];
                            }
                            ret true;
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [decode(self.buffers, emptyfield)];
                        } else {
                            self.state = infield(cbuffer, coffset);
                        }
                    }
                    infield(b,o) {
                        #debug("field : %u %u", b, o);
                        if c == '\n' {
                            fields += [decode(self.buffers, new_bufferfield(self, false, b, o, coffset))];
                            ret true;
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [decode(self.buffers, new_bufferfield(self, false, b, o, coffset))];
                        }
                    }
                    inquotedfield(b, o) {
                        #debug("inquotedfield : %u %u", b, o);
                        if c == self.quote {
                            self.state = inquote(b, o);
                        }
                    }
                    inquote(b, o) {
                        #debug("inquote : %u %u", b, o);
                        if c == '\n' {
                            fields += [decode(self.buffers, new_bufferfield(self, true, b, o, coffset))];
                            ret true;
                        } else if c == self.quote {
                            self.state = inquotedfield(b, o);
                        } else if c == self.delim {
                            self.state = fieldstart(true);
                            fields += [decode(self.buffers, new_bufferfield(self, true, b, o, coffset))];
                        }
                        // swallow odd chars, eg. space between field and "
                    }
                }
                #debug("now %s", statestr(self.state));
            }
            ret false;
        }
        self.state = fieldstart(false);
        let mut do_read = vec::len(self.buffers) == 0u;
        row = [];
        while !self.terminating {
            if do_read {
                let mut data = self.f.read_chars(self.readlen);
                if vec::len(data) == 0u {
                    if !self.trailing_nl {
                        self.terminating = true;
                        data = ['\n'];
                    } else {
                        ret false;
                    }
                }
                // this is horrible, but it avoids the whole parser needing
                // to know about \r.
                data = vec::filter(data) { |c| c != '\r' };
                let data_len = vec::len(data);
                if data_len == 0u {
                    cont;
                }
                self.trailing_nl = data[data_len - 1u] == '\n';
                self.buffers += [data];
                self.offset = 0u;
            }

            if row_from_buf(self, row) {
                let buflen = vec::len(self.buffers);
                if buflen > 1u {
                    self.buffers = [self.buffers[buflen-1u]];
                }
                ret true;
            }
            do_read = true;
        }
        ret false;
    }
}

#[cfg(test)]
mod test {
    fn rowmatch(testdata: str, expected: [[str]]) {
        let chk = fn@(s: str, mk: fn(io::reader) -> rowreader) {
            let f = io::str_reader(s);
            let r = mk(f);
            let mut i = 0u;
            let mut row: [str] = [];
            loop {
                if !r.readrow(row) {
                    break;
                }
                let expect = expected[i];
                assert(vec::len(row) == vec::len(expect));
                let mut j = 0u;
                while j < row.len() {
                    assert(row[j] == expect[j]);
                    j += 1u;
                }
                i += 1u;
            }
            assert(i == vec::len(expected));
        };
        let runchecks = fn@(s: str) {
            // test default reader params
            chk(s) { |inp|
                new_reader_readlen(inp, ',', '"', 2u)
            };
            // test default constructor
            chk(s) { |inp|
                new_reader(inp, ',', '"')
            };
            // test continuations over read buffers
            let mut j = 1u;
            while j < str::len(s) {
                chk(s) { |inp|
                    new_reader_readlen(inp, ',', '"', j)
                };
                j += 1u;
            }
            ret;
        };
        // so we can test trailing newline case, testdata
        // must not end in \n - leave off the last newline
        runchecks(testdata);
        runchecks(str::replace(testdata, "\n", "\r\n"));
        if !str::ends_with(testdata, "\n") {
            runchecks(testdata+"\n");
            runchecks(str::replace(testdata+"\n", "\n", "\r\n"));
        }
    }

    #[test]
    fn simple() {
        rowmatch("a,b,c,d\n1,2,3,4",
                 [["a", "b", "c", "d"], ["1", "2", "3", "4"]]);
    }

    #[test]
    fn trailing_comma() {
        rowmatch("a,b,c,d\n1,2,3,4,",
                 [["a", "b", "c", "d"], ["1", "2", "3", "4", ""]]);
    }

    #[test]
    fn leading_comma() {
        rowmatch("a,b,c,d\n,1,2,3,4",
                 [["a", "b", "c", "d"], ["", "1", "2", "3", "4"]]);
    }

    #[test]
    fn quote_simple() {
        rowmatch("\"Hello\",\"There\"\na,b,\"c\",d",
                 [["Hello", "There"], ["a", "b", "c", "d"]]);
    }

    #[test]
    fn quote_nested() {
        rowmatch("\"Hello\",\"There is a \"\"fly\"\" in my soup\"\na,b,\"c\",d",
                 [["Hello", "There is a \"fly\" in my soup"], ["a", "b", "c", "d"]]);
    }

    #[test]
    fn quote_with_comma() {
        rowmatch("\"1,2\"",
                 [["1,2"]])
    }

    #[test]
    fn quote_with_other_comma() {
        rowmatch("1,2,3,\"a,b,c\"",
                 [["1", "2", "3", "a,b,c"]])
    }

    #[test]
    fn blank_line() {
        rowmatch("\n\n", [[], []]);
    }
}

<|endoftext|>


<commit_before>extern crate hmacsha1;
extern crate uuid;
extern crate byteorder;

use self::uuid::Uuid;

use std::time::{Instant,Duration};
use std::io::prelude::*;
use std::net::Shutdown;
use std::fs::File;
use std::net::TcpStream;
use std::collections::HashMap;

use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel,Receiver,Sender};

use player::Player;
use chat::{read_text,write_text};
use opcode;
use events::Event;

pub const KEY_LEN: usize = 20;
pub const ID_LEN: usize = 16;

#[derive(Debug,Clone)]
pub struct ClientBase {
    pub key: Vec<u8>,
    pub id: Uuid,
}

#[derive(Debug)]
pub struct Client {
    pub base: ClientBase,
    pub stream: Option<TcpStream>,

    pub player_cache: HashMap<Uuid,Player>,
    pub msg_cache: HashMap<Uuid,Vec<String>>, //NOTE: 'events' orders of these messages

    pub ping_start: Instant,
    pub ping_delta: f32,

    pub events: Sender<Event>,
}

impl Client {
    #[allow(dead_code)]
    pub fn new (key: [u8;KEY_LEN], uuid: Uuid) -> (Client, Receiver<Event>) {
        let (tx,rx) = channel();

        (Client { base: ClientBase { key:From::from(&key[..]),
                                     id:uuid, },
                  stream: None,
                  player_cache: HashMap::new(),
                  msg_cache: HashMap::new(),

                  ping_start: Instant::now(),
                  ping_delta: 0.0,

                  events: tx,
        },
         rx)
    }

    #[allow(unused_must_use)]
    pub fn default () -> (Client, Receiver<Event>) {
        let id = uuid::Uuid::new_v4();
        let m = hmacsha1::hmac_sha1(uuid::Uuid::new_v4().as_bytes(),
                                    id.as_bytes());

        Client::new(m,id)
    }
    #[allow(unused_must_use)]
    pub fn save (client: &Client, path: &str) -> bool {
        let f = File::create(path);
        if let Ok(mut f) = f {
            f.write_all(&client.base.key);
            f.write_all(client.base.id.as_bytes()).is_ok()
        }
        else { false }
    }

    pub fn id (&self) -> &Uuid {
        &self.base.id
    }

    pub fn key (&self) -> &[u8] {
        &self.base.key[..]
    }

    #[allow(dead_code)]
    pub fn key_as_ref (&self) -> &Vec<u8> {
        &self.base.key
    }

    pub fn load_file (path: &str) -> Option<(Client, Receiver<Event>)> {
        let f = File::open(path);
        if let Ok(mut f) = f {
            return Client::load(&mut f)
        }

        None
    }

    pub fn load<S:Read> (s: &mut S) -> Option<(Client, Receiver<Event>)> {
        let mut key = [0u8;KEY_LEN];
        let mut id = [0u8;ID_LEN];
        if let Ok(_) = s.read_exact(&mut key) {
            if let Ok(_) = s.read_exact(&mut id) {
                if let Ok(id) = Uuid::from_bytes(&id) {
                    return Some(Client::new(key, id))
                }
                //else { println!("cannot uuid file") }
            }
        }

        None
    }

    #[allow(unused_must_use)]
    pub fn connect (&mut self, server: &str)  {
        if let Ok(s) = TcpStream::connect(server) {
            self.stream = Some(s);
        }
    }

    #[allow(unused_must_use)]
    pub fn login (client: &Arc<Mutex<Client>>) -> bool {
        let c = client.clone();
        if let Ok(ref mut client) = client.lock() {
            let base = client.base.clone();

            if let Some(ref mut s) = client.stream {

                let mut m = [0u8;ID_LEN];
                if let Ok(_) = s.read_exact(&mut m) {
                    s.write_all(&[0]);

                    let hm = hmacsha1::hmac_sha1(&base.key, &m);

                    s.write_all(&hm);
                    s.write_all(base.id.as_bytes());

                    thread::spawn(move || {
                        Client::handler(c)
                    });

                    return true
                }
            }
        }

        false
    }

    #[allow(unused_must_use)]
    pub fn register (&mut self) {
        if let Some(ref mut s) = self.stream {
            s.write_all(&[1]);
            s.write_all(&self.base.key);
            s.write_all(self.base.id.as_bytes());
        }
    }

    #[allow(unused_must_use)]
    pub fn chat (&mut self, text: &str) {
        if let Some(ref mut s) = self.stream {
            write_text(s, text);
        }
    }

    #[allow(unused_must_use)]
    pub fn nick (&mut self, nick: &str) {
        if let Some(ref mut s) = self.stream {
            s.write_all(&Player::to_bytes(None,
                                          &Player { nick: nick.to_owned() }));
        }
    }

    #[allow(unused_must_use)]
    pub fn ping (&mut self) -> bool {
        if let Some(ref mut s) = self.stream {
            self.ping_start = Instant::now();

            return s.write(&[opcode::PING]).is_ok()
        }

        false
    }

    pub fn handler (client: Arc<Mutex<Client>>) {
        let mut cmd = [0u8;1];
        let mut s; // NOTE: this should be read from only!

        if let Ok(mut client) = client.lock() {
            client.ping();

            if let Some(ref s_) = client.stream {
                if let Ok(s_) = s_.try_clone() {
                    s = s_;
                }
                else { return }
            }
            else { return }
        }
        else { return }

        'handler: loop {
            if let Ok(_) = s.read_exact(&mut cmd) {
                match cmd[0] {
                    opcode::CHAT => {
                        if let Some(text) = read_text(&mut s) {
                            let mut id = [0u8;ID_LEN];
                            if let Ok(_) = s.read_exact(&mut id) {
                                if let Ok(uuid) = Uuid::from_bytes(&id) {
                                    if let Ok(mut client) = client.lock() {

                                        // this lil dance makes BC happy
                                        let mut has_uuid = false;
                                        if let Some(msg) = client.msg_cache.get_mut(&uuid) {
                                            msg.push(text.clone());
                                            has_uuid = true;
                                        }

                                        if !has_uuid { client.msg_cache.insert(uuid,vec![text]); }

                                        let _ = client.events.send(Event(opcode::CHAT,
                                                                           uuid));
                                    }
                                }
                            }
                        }
                    },
                    opcode::PLAYER => {
                        if let (Some(uuid),Some(player)) = Player::from_stream(&mut s, true) {
                            if let Ok(mut client) = client.lock() {
                                client.player_cache.insert(uuid, player);

                                let _ = client.events.send(Event(opcode::PLAYER,
                                                                   uuid));
                            }
                        }
                    },
                    opcode::PING => { // recv server ping, respond
                        if let Ok(mut client) = client.lock() {
                            if let Some(ref mut s) = client.stream {
                                let _ = s.write_all(&[opcode::PONG]);
                            }
                        }
                    },
                    opcode::PONG => { // recv client ping back?
                        if let Ok(mut client) = client.lock() {
                            client.ping_delta = client.ping_start.elapsed().as_secs() as f32;
                        }
                    },
                    _ => { },
                }
            }

            // check ping delay, shutdown
            if let Ok(mut client) = client.lock() {
                client.ping_delta += client.ping_start.elapsed().as_secs() as f32;
                if client.ping_delta > 8.0 { break 'handler }

                // ping every so often
                if client.ping_start.elapsed() > Duration::new(5, 0) {
                    if !client.ping() { break 'handler }
                }
            }
        }

        if let Ok(mut client) = client.lock() {
            client.shutdown();
        }
    }

    pub fn shutdown(&mut self) {
        if let Some(ref mut s) = self.stream {
            let _ = s.flush();
            let _ = s.shutdown(Shutdown::Both);
        }

        self.stream = None;
    }
}

impl Drop for Client {
    fn drop (&mut self) {
        self.shutdown();
    }
}
<commit_msg>make ordered<commit_after>extern crate hmacsha1;
extern crate uuid;
extern crate byteorder;

use self::uuid::Uuid;

use std::time::{Instant,Duration};
use std::io::prelude::*;
use std::net::Shutdown;
use std::fs::File;
use std::net::TcpStream;
use std::collections::BTreeMap;

use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel,Receiver,Sender};

use player::Player;
use chat::{read_text,write_text};
use opcode;
use events::Event;

pub const KEY_LEN: usize = 20;
pub const ID_LEN: usize = 16;

#[derive(Debug,Clone)]
pub struct ClientBase {
    pub key: Vec<u8>,
    pub id: Uuid,
}

#[derive(Debug)]
pub struct Client {
    pub base: ClientBase,
    pub stream: Option<TcpStream>,

    pub player_cache: BTreeMap<Uuid,Player>,
    pub msg_cache: BTreeMap<Uuid,Vec<String>>, //NOTE: 'events' orders of these messages

    pub ping_start: Instant,
    pub ping_delta: f32,

    pub events: Sender<Event>,
}

impl Client {
    #[allow(dead_code)]
    pub fn new (key: [u8;KEY_LEN], uuid: Uuid) -> (Client, Receiver<Event>) {
        let (tx,rx) = channel();

        (Client { base: ClientBase { key:From::from(&key[..]),
                                     id:uuid, },
                  stream: None,
                  player_cache: BTreeMap::new(),
                  msg_cache: BTreeMap::new(),

                  ping_start: Instant::now(),
                  ping_delta: 0.0,

                  events: tx,
        },
         rx)
    }

    #[allow(unused_must_use)]
    pub fn default () -> (Client, Receiver<Event>) {
        let id = uuid::Uuid::new_v4();
        let m = hmacsha1::hmac_sha1(uuid::Uuid::new_v4().as_bytes(),
                                    id.as_bytes());

        Client::new(m,id)
    }
    #[allow(unused_must_use)]
    pub fn save (client: &Client, path: &str) -> bool {
        let f = File::create(path);
        if let Ok(mut f) = f {
            f.write_all(&client.base.key);
            f.write_all(client.base.id.as_bytes()).is_ok()
        }
        else { false }
    }

    pub fn id (&self) -> &Uuid {
        &self.base.id
    }

    pub fn key (&self) -> &[u8] {
        &self.base.key[..]
    }

    #[allow(dead_code)]
    pub fn key_as_ref (&self) -> &Vec<u8> {
        &self.base.key
    }

    pub fn load_file (path: &str) -> Option<(Client, Receiver<Event>)> {
        let f = File::open(path);
        if let Ok(mut f) = f {
            return Client::load(&mut f)
        }

        None
    }

    pub fn load<S:Read> (s: &mut S) -> Option<(Client, Receiver<Event>)> {
        let mut key = [0u8;KEY_LEN];
        let mut id = [0u8;ID_LEN];
        if let Ok(_) = s.read_exact(&mut key) {
            if let Ok(_) = s.read_exact(&mut id) {
                if let Ok(id) = Uuid::from_bytes(&id) {
                    return Some(Client::new(key, id))
                }
                //else { println!("cannot uuid file") }
            }
        }

        None
    }

    #[allow(unused_must_use)]
    pub fn connect (&mut self, server: &str)  {
        if let Ok(s) = TcpStream::connect(server) {
            self.stream = Some(s);
        }
    }

    #[allow(unused_must_use)]
    pub fn login (client: &Arc<Mutex<Client>>) -> bool {
        let c = client.clone();
        if let Ok(ref mut client) = client.lock() {
            let base = client.base.clone();

            if let Some(ref mut s) = client.stream {

                let mut m = [0u8;ID_LEN];
                if let Ok(_) = s.read_exact(&mut m) {
                    s.write_all(&[0]);

                    let hm = hmacsha1::hmac_sha1(&base.key, &m);

                    s.write_all(&hm);
                    s.write_all(base.id.as_bytes());

                    thread::spawn(move || {
                        Client::handler(c)
                    });

                    return true
                }
            }
        }

        false
    }

    #[allow(unused_must_use)]
    pub fn register (&mut self) {
        if let Some(ref mut s) = self.stream {
            s.write_all(&[1]);
            s.write_all(&self.base.key);
            s.write_all(self.base.id.as_bytes());
        }
    }

    #[allow(unused_must_use)]
    pub fn chat (&mut self, text: &str) {
        if let Some(ref mut s) = self.stream {
            write_text(s, text);
        }
    }

    #[allow(unused_must_use)]
    pub fn nick (&mut self, nick: &str) {
        if let Some(ref mut s) = self.stream {
            s.write_all(&Player::to_bytes(None,
                                          &Player { nick: nick.to_owned() }));
        }
    }

    #[allow(unused_must_use)]
    pub fn ping (&mut self) -> bool {
        if let Some(ref mut s) = self.stream {
            self.ping_start = Instant::now();

            return s.write(&[opcode::PING]).is_ok()
        }

        false
    }

    pub fn handler (client: Arc<Mutex<Client>>) {
        let mut cmd = [0u8;1];
        let mut s; // NOTE: this should be read from only!

        if let Ok(mut client) = client.lock() {
            client.ping();

            if let Some(ref s_) = client.stream {
                if let Ok(s_) = s_.try_clone() {
                    s = s_;
                }
                else { return }
            }
            else { return }
        }
        else { return }

        'handler: loop {
            if let Ok(_) = s.read_exact(&mut cmd) {
                match cmd[0] {
                    opcode::CHAT => {
                        if let Some(text) = read_text(&mut s) {
                            let mut id = [0u8;ID_LEN];
                            if let Ok(_) = s.read_exact(&mut id) {
                                if let Ok(uuid) = Uuid::from_bytes(&id) {
                                    if let Ok(mut client) = client.lock() {

                                        // this lil dance makes BC happy
                                        let mut has_uuid = false;
                                        if let Some(msg) = client.msg_cache.get_mut(&uuid) {
                                            msg.push(text.clone());
                                            has_uuid = true;
                                        }

                                        if !has_uuid { client.msg_cache.insert(uuid,vec![text]); }

                                        let _ = client.events.send(Event(opcode::CHAT,
                                                                           uuid));
                                    }
                                }
                            }
                        }
                    },
                    opcode::PLAYER => {
                        if let (Some(uuid),Some(player)) = Player::from_stream(&mut s, true) {
                            if let Ok(mut client) = client.lock() {
                                client.player_cache.insert(uuid, player);

                                let _ = client.events.send(Event(opcode::PLAYER,
                                                                   uuid));
                            }
                        }
                    },
                    opcode::PING => { // recv server ping, respond
                        if let Ok(mut client) = client.lock() {
                            if let Some(ref mut s) = client.stream {
                                let _ = s.write_all(&[opcode::PONG]);
                            }
                        }
                    },
                    opcode::PONG => { // recv client ping back?
                        if let Ok(mut client) = client.lock() {
                            client.ping_delta = client.ping_start.elapsed().as_secs() as f32;
                        }
                    },
                    _ => { },
                }
            }

            // check ping delay, shutdown
            if let Ok(mut client) = client.lock() {
                client.ping_delta += client.ping_start.elapsed().as_secs() as f32;
                if client.ping_delta > 8.0 { break 'handler }

                // ping every so often
                if client.ping_start.elapsed() > Duration::new(5, 0) {
                    if !client.ping() { break 'handler }
                }
            }
        }

        if let Ok(mut client) = client.lock() {
            client.shutdown();
        }
    }

    pub fn shutdown(&mut self) {
        if let Some(ref mut s) = self.stream {
            let _ = s.flush();
            let _ = s.shutdown(Shutdown::Both);
        }

        self.stream = None;
    }
}

impl Drop for Client {
    fn drop (&mut self) {
        self.shutdown();
    }
}
<|endoftext|>


<commit_before>// should-ice
#![allow(incomplete_features)]
#![feature(or_patterns)]
#![deny(unreachable_patterns)]

// The ice will get removed once or-patterns are correctly implemented
fn main() {
    // We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
    match (0u8,) {
        (1 | 2,) => {}
        //~^ ERROR simplifyable pattern found
        // This above is the ICE error message
        _ => {}
    }

    match (0u8,) {
        (1 | 2,) => {}
        (1,) => {} //~ ERROR unreachable pattern
        _ => {}
    }
    match (0u8,) {
        (1 | 2,) => {}
        (2,) => {} //~ ERROR unreachable pattern
        _ => {}
    }
    match (0u8,) {
        (1,) => {}
        (2,) => {}
        (1 | 2,) => {} //~ ERROR unreachable pattern
        _ => {}
    }
    match (0u8,) {
        (1 | 1,) => {} // redundancy not detected for now
        _ => {}
    }
    match (0u8, 0u8) {
        (1 | 2, 3 | 4) => {}
        (1, 2) => {}
        (1, 3) => {} //~ ERROR unreachable pattern
        (1, 4) => {} //~ ERROR unreachable pattern
        (2, 4) => {} //~ ERROR unreachable pattern
        (2 | 1, 4) => {} //~ ERROR unreachable pattern
        _ => {}
    }
}
<commit_msg>Add some more tests<commit_after>// should-ice
#![allow(incomplete_features)]
#![feature(or_patterns)]
#![deny(unreachable_patterns)]

// The ice will get removed once or-patterns are correctly implemented
fn main() {
    // We wrap patterns in a tuple because top-level or-patterns are special-cased for now.
    match (0u8,) {
        (1 | 2,) => {}
        //~^ ERROR simplifyable pattern found
        // This above is the ICE error message
        _ => {}
    }

    match (0u8,) {
        (1 | 2,) => {}
        (1,) => {} //~ ERROR unreachable pattern
        _ => {}
    }
    match (0u8,) {
        (1 | 2,) => {}
        (2,) => {} //~ ERROR unreachable pattern
        _ => {}
    }
    match (0u8,) {
        (1,) => {}
        (2,) => {}
        (1 | 2,) => {} //~ ERROR unreachable pattern
        _ => {}
    }
    match (0u8,) {
        (1 | 1,) => {} // redundancy not detected for now
        _ => {}
    }
    match (0u8, 0u8) {
        (1 | 2, 3 | 4) => {}
        (1, 2) => {}
        (1, 3) => {} //~ ERROR unreachable pattern
        (1, 4) => {} //~ ERROR unreachable pattern
        (2, 4) => {} //~ ERROR unreachable pattern
        (2 | 1, 4) => {} //~ ERROR unreachable pattern
        _ => {}
    }
    match (Some(0u8),) {
        (None | Some(1 | 2),) => {}
        (Some(1),) => {} //~ ERROR unreachable pattern
        (None,) => {} //~ ERROR unreachable pattern
        (Some(_),) => {}
    }
    match ((0u8,),) {
        ((1 | 2,) | (3 | 4,),) => {},
        ((1..=4,),) => {}, //~ ERROR unreachable pattern
        ((_,),) => {},
    }
}
<|endoftext|>


<commit_before>//
// sprocketnes/mapper.rs
//
// Author: Patrick Walton
//

use mem::Mem;
use rom::Rom;
use util;

use core::cast::transmute;

#[deriving_eq]
pub enum MapperResult {
    Continue,
    Irq,
}

pub trait Mapper {
    fn prg_loadb(&mut self, addr: u16) -> u8;
    fn prg_storeb(&mut self, addr: u16, val: u8);
    fn chr_loadb(&mut self, addr: u16) -> u8;
    fn chr_storeb(&mut self, addr: u16, val: u8);
    fn next_scanline(&mut self) -> MapperResult;
}

impl Mapper {
    static fn with_mapper<R>(rom: ~Rom, f: &fn(&Mapper) -> R) -> R {
        match rom.header.mapper() {
            0 => {
                unsafe {
                    let mut nrom = Nrom { rom: rom };
                    let mut nrom_ptr: &static/Nrom = transmute(&mut nrom);  // FIXME: Wat?
                    f(nrom_ptr as &Mapper)
                }
            },
            1 => {
                unsafe {
                    let mut sxrom = SxRom::new(rom);
                    let sxrom_ptr: &static/SxRom = transmute(&mut sxrom);   // FIXME: Wat?
                    f(sxrom_ptr as &Mapper)
                }
            }
            4 => {
                unsafe {
                    let mut txrom = TxRom::new(rom);
                    let txrom_ptr: &'static TxRom = transmute(&mut txrom);   // FIXME: Wat?
                    f(txrom_ptr as &Mapper)
                }
            }
            _ => fail!(~"unsupported mapper")
        }
    }
}

//
// Mapper 0 (NROM)
//
// See http://wiki.nesdev.com/w/index.php/NROM
//

// TODO: RAM.
pub struct Nrom {
    rom: ~Rom,
}

impl Mapper for Nrom {
    fn prg_loadb(&mut self, addr: u16) -> u8 {
        if addr < 0x8000 {
            0
        } else if self.rom.prg.len() > 16384 {
            self.rom.prg[addr & 0x7fff]
        } else {
            self.rom.prg[addr & 0x3fff]
        }
    }
    fn prg_storeb(&mut self, _: u16, _: u8) {}  // Can't store to PRG-ROM.
    fn chr_loadb(&mut self, addr: u16) -> u8 { self.rom.chr[addr] }
    fn chr_storeb(&mut self, _: u16, _: u8) {}  // Can't store to CHR-ROM.
    fn next_scanline(&mut self) -> MapperResult { Continue }
}

//
// Mapper 1 (SxROM/MMC1)
//
// See http://wiki.nesdev.com/w/index.php/Nintendo_MMC1
//

struct SxCtrl(u8);

pub enum Mirroring {
    OneScreenLower,
    OneScreenUpper,
    Vertical,
    Horizontal,
}

enum SxPrgBankMode {
    Switch32K,      // Switch 32K at $8000, ignore low bit
    FixFirstBank,   // Fix first bank at $8000, switch 16K bank at $C000
    FixLastBank,    // Fix last bank at $C000, switch 16K bank at $8000
}

enum SxChrBankMode {
    Switch8K,       // Switch 8K at a time
    SwitchTwo4K,    // Switch two separate 4K banks
}

impl SxCtrl {
    fn mirroring(self) -> Mirroring {
        match *self & 3 {
            0 => OneScreenLower,
            1 => OneScreenUpper,
            2 => Vertical,
            3 => Horizontal,
            _ => fail!(~"can't happen")
        }
    }
    fn prg_rom_mode(self) -> SxPrgBankMode {
        match (*self >> 2) & 3 {
            0 | 1 => Switch32K,
            2 => FixFirstBank,
            3 => FixLastBank,
            _ => fail!(~"can't happen")
        }
    }
    fn chr_rom_mode(self) -> SxChrBankMode {
        if ((*self >> 4) & 1) == 0 { Switch8K } else { SwitchTwo4K }
    }
}

pub struct SxRegs {
    ctrl: SxCtrl,   // $8000-$9FFF
    chr_bank_0: u8, // $A000-$BFFF
    chr_bank_1: u8, // $C000-$DFFF
    prg_bank: u8,   // $E000-$FFFF
}

pub struct SxRom {
    rom: ~Rom,
    regs: SxRegs,
    // The internal accumulator.
    accum: u8,
    // The write count. At the 5th write, we update the register.
    write_count: u8,
    prg_ram: ~([u8 * 8192]),
    chr_ram: ~([u8 * 8192]),
}

impl SxRom {
    static fn new(rom: ~Rom) -> SxRom {
        SxRom {
            rom: rom,
            regs: SxRegs {
                ctrl: SxCtrl(3 << 2),
                chr_bank_0: 0,
                chr_bank_1: 0,
                prg_bank: 0,
            },
            accum: 0,
            write_count: 0,
            prg_ram: ~([ 0, ..8192 ]),
            chr_ram: ~([ 0, ..8192 ]),
        }
    }
}

impl Mapper for SxRom {
    fn prg_loadb(&mut self, addr: u16) -> u8 {
        unsafe {
            if addr < 0x8000 {
                0
            } else if addr < 0xc000 {
                let bank = match self.regs.ctrl.prg_rom_mode() {
                    Switch32K => self.regs.prg_bank & 0xfe,
                    FixFirstBank => 0,
                    FixLastBank => self.regs.prg_bank,
                };
                self.rom.prg[(bank as uint * 16384) | ((addr & 0x3fff) as uint)]
            } else {
                let bank = match self.regs.ctrl.prg_rom_mode() {
                    Switch32K => (self.regs.prg_bank & 0xfe) | 1,
                    FixFirstBank => self.regs.prg_bank,
                    FixLastBank => (*self.rom).header.prg_rom_size - 1,
                };
                self.rom.prg[(bank as uint * 16384) | ((addr & 0x3fff) as uint)]
            }
        }
    }

    fn prg_storeb(&mut self, addr: u16, val: u8) {
        if addr < 0x8000 {
            return;
        }

        // Check the reset flag.
        if (val & 0x80) != 0 {
            self.write_count = 0;
            self.accum = 0;
            self.regs.ctrl = SxCtrl(*self.regs.ctrl | (3 << 2));
            return;
        }

        // Write the lowest bit of the value into the right location of the accumulator.
        self.accum = self.accum | ((val & 1) << self.write_count);

        self.write_count += 1;
        if self.write_count == 5 {
            self.write_count = 0;

            // Write to the right internal register.
            if addr <= 0x9fff {
                self.regs.ctrl = SxCtrl(self.accum);
            } else if addr <= 0xbfff {
                self.regs.chr_bank_0 = self.accum;
            } else if addr <= 0xdfff {
                self.regs.chr_bank_1 = self.accum;
            } else {
                self.regs.prg_bank = self.accum;
            }

            self.accum = 0;
        }
    }

    // FIXME: Apparently this mapper can have CHR-ROM as well. Handle this case.
    fn chr_loadb(&mut self, addr: u16) -> u8     { self.chr_ram[addr]       }
    fn chr_storeb(&mut self, addr: u16, val: u8) { self.chr_ram[addr] = val }

    fn next_scanline(&mut self) -> MapperResult { Continue }
}

//
// Mapper 4 (TxROM/MMC3)
//
// See http://wiki.nesdev.com/w/index.php/MMC3
//

struct TxBankSelect(u8);

enum TxPrgBankMode {
    Swappable8000,
    SwappableC000,
}

impl TxBankSelect {
    fn bank_update_select(self) -> u8 { *self & 0x7 }
    fn prg_bank_mode(self) -> TxPrgBankMode {
        if (*self & 0x40) == 0 { Swappable8000 } else { SwappableC000 }
    }
}

struct TxRegs {
    bank_select: TxBankSelect,  // Bank select (0x8000-0x9ffe even)
}

struct TxRom {
    rom: ~Rom,
    regs: TxRegs,
    prg_ram: ~([u8 * 8192]),

    chr_banks_2k: [u8 * 2],     // 2KB CHR-ROM banks
    chr_banks_1k: [u8 * 4],     // 1KB CHR-ROM banks
    prg_banks:    [u8 * 2],     // 8KB PRG-ROM banks

    scanline_counter: u8,
    irq_reload: u8,             // Copied into the scanline counter when it hits zero.
    irq_enabled: bool,
}

impl TxRom {
    static fn new(rom: ~Rom) -> TxRom {
        TxRom {
            rom: rom,
            regs: TxRegs { bank_select: TxBankSelect(0) },
            prg_ram: ~([ 0, ..8192 ]),

            chr_banks_2k: [ 0, 0 ],
            chr_banks_1k: [ 0, 0, 0, 0 ],
            prg_banks: [ 0, 0 ],

            scanline_counter: 0,
            irq_reload: 0,
            irq_enabled: false,
        }
    }

    fn prg_bank_count(&self) -> u8 { self.rom.header.prg_rom_size * 2 }
}

impl Mapper for TxRom {
    fn prg_loadb(&mut self, addr: u16) -> u8 {
        unsafe {
            if addr < 0x6000 {
                0
            } else if addr < 0x8000 {
                self.prg_ram[addr & 0x1fff]
            } else if addr < 0xa000 {
                // $8000-$9FFF might be switchable or fixed to the second to last bank.
                let bank = match self.regs.bank_select.prg_bank_mode() {
                    Swappable8000 => self.prg_banks[0],
                    SwappableC000 => self.prg_bank_count() - 2,
                };
                self.rom.prg[(bank as uint * 8192) | (addr as uint & 0x1fff)]
            } else if addr < 0xc000 {
                // $A000-$BFFF is switchable.
                self.rom.prg[(self.prg_banks[1] as uint * 8192) | (addr as uint & 0x1fff)]
            } else if addr < 0xe000 {
                // $C000-$DFFF might be switchable or fixed to the second to last bank.
                let bank = match self.regs.bank_select.prg_bank_mode() {
                    Swappable8000 => self.prg_bank_count() - 2,
                    SwappableC000 => self.prg_banks[0],
                };
                self.rom.prg[(bank as uint * 8192) | (addr as uint & 0x1fff)]
            } else {
                // $E000-$FFFF is fixed to the last bank.
                let bank = self.prg_bank_count() - 1;
                self.rom.prg[(bank as uint * 8192) | (addr as uint & 0x1fff)]
            }
        }
    }

    fn prg_storeb(&mut self, addr: u16, val: u8) {
        if addr < 0x6000 {
            return;
        }

        if addr < 0x8000 {
            self.prg_ram[addr & 0x1fff] = val;
        } else if addr < 0xa000 {
            if (addr & 1) == 0 {
                // Bank select.
                self.regs.bank_select = TxBankSelect(val);
            } else {
                // Bank data.
                let bank_update_select = self.regs.bank_select.bank_update_select();
                match bank_update_select {
                    0..1 => self.chr_banks_2k[bank_update_select] = val,
                    2..5 => self.chr_banks_1k[bank_update_select - 2] = val,
                    6..7 => self.prg_banks[bank_update_select - 6] = val,
                    _ => fail!()
                }
            }
        } else if addr < 0xc000 {
            // TODO: Mirroring and PRG-RAM protect
        } else if addr < 0xe000 {
            if (addr & 1) == 0 {
                // IRQ latch.
                self.irq_reload = val;
            } else {
                // IRQ reload.
                self.scanline_counter = self.irq_reload;
            }
        } else {
            // IRQ enable.
            self.irq_enabled = (addr & 1) == 1;
        }
    }

    fn chr_loadb(&mut self, addr: u16) -> u8 {
        // TODO: Banking
        self.rom.chr[addr]
    }
    fn chr_storeb(&mut self, _: u16, _: u8) {
        // TODO: CHR-RAM
    }

    fn next_scanline(&mut self) -> MapperResult {
        if self.scanline_counter != 0 {
            self.scanline_counter -= 1;
            if self.scanline_counter == 0 {
                self.scanline_counter = self.irq_reload;

                if self.irq_enabled {
                    util::debug_print("*** Generated IRQ! ***");
                    return Irq;
                }
            }
        }
        Continue
    }
}

<commit_msg>Add support for CHR bank switching on TxROM<commit_after>//
// sprocketnes/mapper.rs
//
// Author: Patrick Walton
//

use mem::Mem;
use rom::Rom;
use util;

use core::cast::transmute;

#[deriving_eq]
pub enum MapperResult {
    Continue,
    Irq,
}

pub trait Mapper {
    fn prg_loadb(&mut self, addr: u16) -> u8;
    fn prg_storeb(&mut self, addr: u16, val: u8);
    fn chr_loadb(&mut self, addr: u16) -> u8;
    fn chr_storeb(&mut self, addr: u16, val: u8);
    fn next_scanline(&mut self) -> MapperResult;
}

impl Mapper {
    static fn with_mapper<R>(rom: ~Rom, f: &fn(&Mapper) -> R) -> R {
        match rom.header.mapper() {
            0 => {
                unsafe {
                    let mut nrom = Nrom { rom: rom };
                    let mut nrom_ptr: &static/Nrom = transmute(&mut nrom);  // FIXME: Wat?
                    f(nrom_ptr as &Mapper)
                }
            },
            1 => {
                unsafe {
                    let mut sxrom = SxRom::new(rom);
                    let sxrom_ptr: &static/SxRom = transmute(&mut sxrom);   // FIXME: Wat?
                    f(sxrom_ptr as &Mapper)
                }
            }
            4 => {
                unsafe {
                    let mut txrom = TxRom::new(rom);
                    let txrom_ptr: &'static TxRom = transmute(&mut txrom);   // FIXME: Wat?
                    f(txrom_ptr as &Mapper)
                }
            }
            _ => fail!(~"unsupported mapper")
        }
    }
}

//
// Mapper 0 (NROM)
//
// See http://wiki.nesdev.com/w/index.php/NROM
//

// TODO: RAM.
pub struct Nrom {
    rom: ~Rom,
}

impl Mapper for Nrom {
    fn prg_loadb(&mut self, addr: u16) -> u8 {
        if addr < 0x8000 {
            0
        } else if self.rom.prg.len() > 16384 {
            self.rom.prg[addr & 0x7fff]
        } else {
            self.rom.prg[addr & 0x3fff]
        }
    }
    fn prg_storeb(&mut self, _: u16, _: u8) {}  // Can't store to PRG-ROM.
    fn chr_loadb(&mut self, addr: u16) -> u8 { self.rom.chr[addr] }
    fn chr_storeb(&mut self, _: u16, _: u8) {}  // Can't store to CHR-ROM.
    fn next_scanline(&mut self) -> MapperResult { Continue }
}

//
// Mapper 1 (SxROM/MMC1)
//
// See http://wiki.nesdev.com/w/index.php/Nintendo_MMC1
//

struct SxCtrl(u8);

pub enum Mirroring {
    OneScreenLower,
    OneScreenUpper,
    Vertical,
    Horizontal,
}

enum SxPrgBankMode {
    Switch32K,      // Switch 32K at $8000, ignore low bit
    FixFirstBank,   // Fix first bank at $8000, switch 16K bank at $C000
    FixLastBank,    // Fix last bank at $C000, switch 16K bank at $8000
}

enum SxChrBankMode {
    Switch8K,       // Switch 8K at a time
    SwitchTwo4K,    // Switch two separate 4K banks
}

impl SxCtrl {
    fn mirroring(self) -> Mirroring {
        match *self & 3 {
            0 => OneScreenLower,
            1 => OneScreenUpper,
            2 => Vertical,
            3 => Horizontal,
            _ => fail!(~"can't happen")
        }
    }
    fn prg_rom_mode(self) -> SxPrgBankMode {
        match (*self >> 2) & 3 {
            0 | 1 => Switch32K,
            2 => FixFirstBank,
            3 => FixLastBank,
            _ => fail!(~"can't happen")
        }
    }
    fn chr_rom_mode(self) -> SxChrBankMode {
        if ((*self >> 4) & 1) == 0 { Switch8K } else { SwitchTwo4K }
    }
}

pub struct SxRegs {
    ctrl: SxCtrl,   // $8000-$9FFF
    chr_bank_0: u8, // $A000-$BFFF
    chr_bank_1: u8, // $C000-$DFFF
    prg_bank: u8,   // $E000-$FFFF
}

pub struct SxRom {
    rom: ~Rom,
    regs: SxRegs,
    // The internal accumulator.
    accum: u8,
    // The write count. At the 5th write, we update the register.
    write_count: u8,
    prg_ram: ~([u8 * 8192]),
    chr_ram: ~([u8 * 8192]),
}

impl SxRom {
    static fn new(rom: ~Rom) -> SxRom {
        SxRom {
            rom: rom,
            regs: SxRegs {
                ctrl: SxCtrl(3 << 2),
                chr_bank_0: 0,
                chr_bank_1: 0,
                prg_bank: 0,
            },
            accum: 0,
            write_count: 0,
            prg_ram: ~([ 0, ..8192 ]),
            chr_ram: ~([ 0, ..8192 ]),
        }
    }
}

impl Mapper for SxRom {
    fn prg_loadb(&mut self, addr: u16) -> u8 {
        unsafe {
            if addr < 0x8000 {
                0
            } else if addr < 0xc000 {
                let bank = match self.regs.ctrl.prg_rom_mode() {
                    Switch32K => self.regs.prg_bank & 0xfe,
                    FixFirstBank => 0,
                    FixLastBank => self.regs.prg_bank,
                };
                self.rom.prg[(bank as uint * 16384) | ((addr & 0x3fff) as uint)]
            } else {
                let bank = match self.regs.ctrl.prg_rom_mode() {
                    Switch32K => (self.regs.prg_bank & 0xfe) | 1,
                    FixFirstBank => self.regs.prg_bank,
                    FixLastBank => (*self.rom).header.prg_rom_size - 1,
                };
                self.rom.prg[(bank as uint * 16384) | ((addr & 0x3fff) as uint)]
            }
        }
    }

    fn prg_storeb(&mut self, addr: u16, val: u8) {
        if addr < 0x8000 {
            return;
        }

        // Check the reset flag.
        if (val & 0x80) != 0 {
            self.write_count = 0;
            self.accum = 0;
            self.regs.ctrl = SxCtrl(*self.regs.ctrl | (3 << 2));
            return;
        }

        // Write the lowest bit of the value into the right location of the accumulator.
        self.accum = self.accum | ((val & 1) << self.write_count);

        self.write_count += 1;
        if self.write_count == 5 {
            self.write_count = 0;

            // Write to the right internal register.
            if addr <= 0x9fff {
                self.regs.ctrl = SxCtrl(self.accum);
            } else if addr <= 0xbfff {
                self.regs.chr_bank_0 = self.accum;
            } else if addr <= 0xdfff {
                self.regs.chr_bank_1 = self.accum;
            } else {
                self.regs.prg_bank = self.accum;
            }

            self.accum = 0;
        }
    }

    // FIXME: Apparently this mapper can have CHR-ROM as well. Handle this case.
    fn chr_loadb(&mut self, addr: u16) -> u8     { self.chr_ram[addr]       }
    fn chr_storeb(&mut self, addr: u16, val: u8) { self.chr_ram[addr] = val }

    fn next_scanline(&mut self) -> MapperResult { Continue }
}

//
// Mapper 4 (TxROM/MMC3)
//
// See http://wiki.nesdev.com/w/index.php/MMC3
//

struct TxBankSelect(u8);

enum TxPrgBankMode {
    Swappable8000,
    SwappableC000,
}

impl TxBankSelect {
    fn bank_update_select(self) -> u8 { *self & 0x7 }
    fn prg_bank_mode(self) -> TxPrgBankMode {
        if (*self & 0x40) == 0 { Swappable8000 } else { SwappableC000 }
    }
    fn chr_a12_inversion(self) -> bool { (*self & 0x80) != 0 }
}

struct TxRegs {
    bank_select: TxBankSelect,  // Bank select (0x8000-0x9ffe even)
}

struct TxRom {
    rom: ~Rom,
    regs: TxRegs,
    prg_ram: ~([u8 * 8192]),

    chr_banks_2k: [u8 * 2],     // 2KB CHR-ROM banks
    chr_banks_1k: [u8 * 4],     // 1KB CHR-ROM banks
    prg_banks:    [u8 * 2],     // 8KB PRG-ROM banks

    scanline_counter: u8,
    irq_reload: u8,             // Copied into the scanline counter when it hits zero.
    irq_enabled: bool,
}

impl TxRom {
    static fn new(rom: ~Rom) -> TxRom {
        TxRom {
            rom: rom,
            regs: TxRegs { bank_select: TxBankSelect(0) },
            prg_ram: ~([ 0, ..8192 ]),

            chr_banks_2k: [ 0, 0 ],
            chr_banks_1k: [ 0, 0, 0, 0 ],
            prg_banks: [ 0, 0 ],

            scanline_counter: 0,
            irq_reload: 0,
            irq_enabled: false,
        }
    }

    fn prg_bank_count(&self) -> u8 { self.rom.header.prg_rom_size * 2 }
}

impl Mapper for TxRom {
    fn prg_loadb(&mut self, addr: u16) -> u8 {
        unsafe {
            if addr < 0x6000 {
                0
            } else if addr < 0x8000 {
                self.prg_ram[addr & 0x1fff]
            } else if addr < 0xa000 {
                // $8000-$9FFF might be switchable or fixed to the second to last bank.
                let bank = match self.regs.bank_select.prg_bank_mode() {
                    Swappable8000 => self.prg_banks[0],
                    SwappableC000 => self.prg_bank_count() - 2,
                };
                self.rom.prg[(bank as uint * 8192) | (addr as uint & 0x1fff)]
            } else if addr < 0xc000 {
                // $A000-$BFFF is switchable.
                self.rom.prg[(self.prg_banks[1] as uint * 8192) | (addr as uint & 0x1fff)]
            } else if addr < 0xe000 {
                // $C000-$DFFF might be switchable or fixed to the second to last bank.
                let bank = match self.regs.bank_select.prg_bank_mode() {
                    Swappable8000 => self.prg_bank_count() - 2,
                    SwappableC000 => self.prg_banks[0],
                };
                self.rom.prg[(bank as uint * 8192) | (addr as uint & 0x1fff)]
            } else {
                // $E000-$FFFF is fixed to the last bank.
                let bank = self.prg_bank_count() - 1;
                self.rom.prg[(bank as uint * 8192) | (addr as uint & 0x1fff)]
            }
        }
    }

    fn prg_storeb(&mut self, addr: u16, val: u8) {
        if addr < 0x6000 {
            return;
        }

        if addr < 0x8000 {
            self.prg_ram[addr & 0x1fff] = val;
        } else if addr < 0xa000 {
            if (addr & 1) == 0 {
                // Bank select.
                self.regs.bank_select = TxBankSelect(val);
            } else {
                // Bank data.
                let bank_update_select = self.regs.bank_select.bank_update_select();
                match bank_update_select {
                    0..1 => self.chr_banks_2k[bank_update_select] = val,
                    2..5 => self.chr_banks_1k[bank_update_select - 2] = val,
                    6..7 => self.prg_banks[bank_update_select - 6] = val,
                    _ => fail!()
                }
            }
        } else if addr < 0xc000 {
            // TODO: Mirroring and PRG-RAM protect
        } else if addr < 0xe000 {
            if (addr & 1) == 0 {
                // IRQ latch.
                self.irq_reload = val;
            } else {
                // IRQ reload.
                self.scanline_counter = self.irq_reload;
            }
        } else {
            // IRQ enable.
            self.irq_enabled = (addr & 1) == 1;
        }
    }

    fn chr_loadb(&mut self, addr: u16) -> u8 {
        let (bank, two_kb) = match (addr, self.regs.bank_select.chr_a12_inversion()) {
            (0x0000..0x07ff, false) | (0x1000..0x17ff, true) => (self.chr_banks_2k[0], true),
            (0x0800..0x0fff, false) | (0x1800..0x1fff, true) => (self.chr_banks_2k[1], true),
            (0x1000..0x13ff, false) | (0x0000..0x03ff, true) => (self.chr_banks_1k[0], false),
            (0x1400..0x17ff, false) | (0x0400..0x07ff, true) => (self.chr_banks_1k[1], false),
            (0x1800..0x1bff, false) | (0x0800..0x0bff, true) => (self.chr_banks_1k[2], false),
            (0x1c00..0x1fff, false) | (0x0c00..0x0fff, true) => (self.chr_banks_1k[3], false),
            _ => return 0,
        };
        if two_kb {
            self.rom.chr[(bank as uint * 1024) + (addr as uint & 0x7ff)]
        } else {
            self.rom.chr[(bank as uint * 1024) | (addr as uint & 0x3ff)]
        }
    }

    fn chr_storeb(&mut self, _: u16, _: u8) {
        // TODO: CHR-RAM
    }

    fn next_scanline(&mut self) -> MapperResult {
        if self.scanline_counter != 0 {
            self.scanline_counter -= 1;
            if self.scanline_counter == 0 {
                self.scanline_counter = self.irq_reload;

                if self.irq_enabled {
                    util::debug_print("*** Generated IRQ! ***");
                    return Irq;
                }
            }
        }
        Continue
    }
}

<|endoftext|>


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

#[link(name = "core_foundation", vers = "0.1")];

extern mod std;

pub mod array;
pub mod base;
pub mod boolean;
pub mod data;
pub mod dictionary;
pub mod number;
pub mod set;
pub mod string;
pub mod url;

#[cfg(test)]
pub mod test {
    #[test]
    fn test_stuff() {
        use boolean::CFBoolean;
        use number::CFNumber;
        use dictionary::CFDictionary;
        use string::CFString;

        /*let n = CFNumber::new_number(42 as i32);
        io::println(format!("%d", (&n).retain_count() as int));
        (&n).show();*/

        let bar = CFString::new_static("Bar");
        let baz = CFString::new_static("Baz");
        let boo = CFString::new_static("Boo");
        let foo = CFString::new_static("Foo");
        let tru = CFBoolean::true_value();
        let n42 = CFNumber::new(42 as i32);

        let d = CFDictionary::new([
            (*bar.contents.borrow_ref(), *boo.contents.borrow_type_ref()),
            (*baz.contents.borrow_ref(), *tru.contents.borrow_type_ref()),
            (*foo.contents.borrow_ref(), *n42.contents.borrow_type_ref()),
        ]);
        d.contents.show();
    }
}
<commit_msg>Fix tests for bindings changes.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[link(name = "core_foundation", vers = "0.1")];

extern mod std;

pub mod array;
pub mod base;
pub mod boolean;
pub mod data;
pub mod dictionary;
pub mod number;
pub mod set;
pub mod string;
pub mod url;

#[cfg(test)]
pub mod test {
    #[test]
    fn test_stuff() {
        use boolean::CFBoolean;
        use number::number;
        use dictionary::CFDictionary;
        use string::CFString;

        /*let n = CFNumber::new_number(42 as i32);
        io::println(format!("%d", (&n).retain_count() as int));
        (&n).show();*/

        let bar = CFString::from_static_string("Bar");
        let baz = CFString::from_static_string("Baz");
        let boo = CFString::from_static_string("Boo");
        let foo = CFString::from_static_string("Foo");
        let tru = CFBoolean::true_value();
        let n42 = number(42);

        let d = CFDictionary::from_CFType_pairs([
            (bar.as_CFType(), boo.as_CFType()),
            (baz.as_CFType(), tru.as_CFType()),
            (foo.as_CFType(), n42.as_CFType()),
        ]);
        d.contents.show();
    }
}
<|endoftext|>


<commit_before>//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
mod lower;

use std::{iter, sync::Arc};

use hir_expand::{
    hygiene::Hygiene,
    name::{AsName, Name},
};
use ra_db::CrateId;
use ra_syntax::ast;

use crate::{type_ref::TypeRef, InFile};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ModPath {
    pub kind: PathKind,
    pub segments: Vec<Name>,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum PathKind {
    Plain,
    /// `self::` is `Super(0)`
    Super(u8),
    Crate,
    /// Absolute path (::foo)
    Abs,
    /// `$crate` from macro expansion
    DollarCrate(CrateId),
}

impl ModPath {
    pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
        lower::lower_path(path, hygiene).map(|it| it.mod_path)
    }

    pub fn from_simple_segments(
        kind: PathKind,
        segments: impl IntoIterator<Item = Name>,
    ) -> ModPath {
        let segments = segments.into_iter().collect::<Vec<_>>();
        ModPath { kind, segments }
    }

    pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> ModPath {
        name_ref.as_name().into()
    }

    /// Converts an `tt::Ident` into a single-identifier `Path`.
    pub(crate) fn from_tt_ident(ident: &tt::Ident) -> ModPath {
        ident.as_name().into()
    }

    /// Calls `cb` with all paths, represented by this use item.
    pub(crate) fn expand_use_item(
        item_src: InFile<ast::UseItem>,
        hygiene: &Hygiene,
        mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<Name>),
    ) {
        if let Some(tree) = item_src.value.use_tree() {
            lower::lower_use_tree(None, tree, hygiene, &mut cb);
        }
    }

    pub fn is_ident(&self) -> bool {
        self.kind == PathKind::Plain && self.segments.len() == 1
    }

    pub fn is_self(&self) -> bool {
        self.kind == PathKind::Super(0) && self.segments.is_empty()
    }

    /// If this path is a single identifier, like `foo`, return its name.
    pub fn as_ident(&self) -> Option<&Name> {
        if self.kind != PathKind::Plain || self.segments.len() > 1 {
            return None;
        }
        self.segments.first()
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Path {
    /// Type based path like `<T>::foo`.
    /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`.
    type_anchor: Option<Box<TypeRef>>,
    mod_path: ModPath,
    /// Invariant: the same len as self.path.segments
    generic_args: Vec<Option<Arc<GenericArgs>>>,
}

/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GenericArgs {
    pub args: Vec<GenericArg>,
    /// This specifies whether the args contain a Self type as the first
    /// element. This is the case for path segments like `<T as Trait>`, where
    /// `T` is actually a type parameter for the path `Trait` specifying the
    /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type
    /// is left out.
    pub has_self_type: bool,
    /// Associated type bindings like in `Iterator<Item = T>`.
    pub bindings: Vec<(Name, TypeRef)>,
}

/// A single generic argument.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GenericArg {
    Type(TypeRef),
    // or lifetime...
}

impl Path {
    /// Converts an `ast::Path` to `Path`. Works with use trees.
    /// DEPRECATED: It does not handle `$crate` from macro call.
    pub fn from_ast(path: ast::Path) -> Option<Path> {
        lower::lower_path(path, &Hygiene::new_unhygienic())
    }

    /// Converts an `ast::Path` to `Path`. Works with use trees.
    /// It correctly handles `$crate` based path from macro call.
    pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
        lower::lower_path(path, hygiene)
    }

    /// Converts an `ast::NameRef` into a single-identifier `Path`.
    pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
        Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] }
    }

    /// Converts a known mod path to `Path`.
    pub(crate) fn from_known_path(
        path: ModPath,
        generic_args: Vec<Option<Arc<GenericArgs>>>,
    ) -> Path {
        Path { type_anchor: None, mod_path: path, generic_args }
    }

    pub fn kind(&self) -> &PathKind {
        &self.mod_path.kind
    }

    pub fn type_anchor(&self) -> Option<&TypeRef> {
        self.type_anchor.as_deref()
    }

    pub fn segments(&self) -> PathSegments<'_> {
        PathSegments {
            segments: self.mod_path.segments.as_slice(),
            generic_args: self.generic_args.as_slice(),
        }
    }

    pub fn mod_path(&self) -> &ModPath {
        &self.mod_path
    }

    pub fn qualifier(&self) -> Option<Path> {
        if self.mod_path.is_ident() {
            return None;
        }
        let res = Path {
            type_anchor: self.type_anchor.clone(),
            mod_path: ModPath {
                kind: self.mod_path.kind.clone(),
                segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(),
            },
            generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(),
        };
        Some(res)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PathSegment<'a> {
    pub name: &'a Name,
    pub args_and_bindings: Option<&'a GenericArgs>,
}

pub struct PathSegments<'a> {
    segments: &'a [Name],
    generic_args: &'a [Option<Arc<GenericArgs>>],
}

impl<'a> PathSegments<'a> {
    pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] };
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
    pub fn len(&self) -> usize {
        self.segments.len()
    }
    pub fn first(&self) -> Option<PathSegment<'a>> {
        self.get(0)
    }
    pub fn last(&self) -> Option<PathSegment<'a>> {
        self.get(self.len().checked_sub(1)?)
    }
    pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        let res = PathSegment {
            name: self.segments.get(idx)?,
            args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it),
        };
        Some(res)
    }
    pub fn skip(&self, len: usize) -> PathSegments<'a> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] }
    }
    pub fn take(&self, len: usize) -> PathSegments<'a> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] }
    }
    pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
        self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment {
            name,
            args_and_bindings: args.as_ref().map(|it| &**it),
        })
    }
}

impl GenericArgs {
    pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> {
        lower::lower_generic_args(node)
    }

    pub(crate) fn empty() -> GenericArgs {
        GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
    }
}

impl From<Name> for Path {
    fn from(name: Name) -> Path {
        Path {
            type_anchor: None,
            mod_path: ModPath::from_simple_segments(PathKind::Plain, iter::once(name)),
            generic_args: vec![None],
        }
    }
}

impl From<Name> for ModPath {
    fn from(name: Name) -> ModPath {
        ModPath::from_simple_segments(PathKind::Plain, iter::once(name))
    }
}

pub use hir_expand::name as __name;

#[macro_export]
macro_rules! __known_path {
    (std::iter::IntoIterator) => {};
    (std::result::Result) => {};
    (std::ops::Range) => {};
    (std::ops::RangeFrom) => {};
    (std::ops::RangeFull) => {};
    (std::ops::RangeTo) => {};
    (std::ops::RangeToInclusive) => {};
    (std::ops::RangeInclusive) => {};
    (std::boxed::Box) => {};
    (std::future::Future) => {};
    (std::ops::Try) => {};
    (std::ops::Neg) => {};
    (std::ops::Not) => {};
    (std::ops::Index) => {};
    ($path:path) => {
        compile_error!("Please register your known path in the path module")
    };
}

#[macro_export]
macro_rules! __path {
    ($start:ident $(:: $seg:ident)*) => ({
        $crate::__known_path!($start $(:: $seg)*);
        $crate::path::ModPath::from_simple_segments($crate::path::PathKind::Abs, vec![
            $crate::path::__name![$start], $($crate::path::__name![$seg],)*
        ])
    });
}

pub use crate::__path as path;
<commit_msg>Remove unused hard-coded paths<commit_after>//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
mod lower;

use std::{iter, sync::Arc};

use hir_expand::{
    hygiene::Hygiene,
    name::{AsName, Name},
};
use ra_db::CrateId;
use ra_syntax::ast;

use crate::{type_ref::TypeRef, InFile};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ModPath {
    pub kind: PathKind,
    pub segments: Vec<Name>,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum PathKind {
    Plain,
    /// `self::` is `Super(0)`
    Super(u8),
    Crate,
    /// Absolute path (::foo)
    Abs,
    /// `$crate` from macro expansion
    DollarCrate(CrateId),
}

impl ModPath {
    pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
        lower::lower_path(path, hygiene).map(|it| it.mod_path)
    }

    pub fn from_simple_segments(
        kind: PathKind,
        segments: impl IntoIterator<Item = Name>,
    ) -> ModPath {
        let segments = segments.into_iter().collect::<Vec<_>>();
        ModPath { kind, segments }
    }

    pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> ModPath {
        name_ref.as_name().into()
    }

    /// Converts an `tt::Ident` into a single-identifier `Path`.
    pub(crate) fn from_tt_ident(ident: &tt::Ident) -> ModPath {
        ident.as_name().into()
    }

    /// Calls `cb` with all paths, represented by this use item.
    pub(crate) fn expand_use_item(
        item_src: InFile<ast::UseItem>,
        hygiene: &Hygiene,
        mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<Name>),
    ) {
        if let Some(tree) = item_src.value.use_tree() {
            lower::lower_use_tree(None, tree, hygiene, &mut cb);
        }
    }

    pub fn is_ident(&self) -> bool {
        self.kind == PathKind::Plain && self.segments.len() == 1
    }

    pub fn is_self(&self) -> bool {
        self.kind == PathKind::Super(0) && self.segments.is_empty()
    }

    /// If this path is a single identifier, like `foo`, return its name.
    pub fn as_ident(&self) -> Option<&Name> {
        if self.kind != PathKind::Plain || self.segments.len() > 1 {
            return None;
        }
        self.segments.first()
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Path {
    /// Type based path like `<T>::foo`.
    /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`.
    type_anchor: Option<Box<TypeRef>>,
    mod_path: ModPath,
    /// Invariant: the same len as self.path.segments
    generic_args: Vec<Option<Arc<GenericArgs>>>,
}

/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GenericArgs {
    pub args: Vec<GenericArg>,
    /// This specifies whether the args contain a Self type as the first
    /// element. This is the case for path segments like `<T as Trait>`, where
    /// `T` is actually a type parameter for the path `Trait` specifying the
    /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type
    /// is left out.
    pub has_self_type: bool,
    /// Associated type bindings like in `Iterator<Item = T>`.
    pub bindings: Vec<(Name, TypeRef)>,
}

/// A single generic argument.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum GenericArg {
    Type(TypeRef),
    // or lifetime...
}

impl Path {
    /// Converts an `ast::Path` to `Path`. Works with use trees.
    /// DEPRECATED: It does not handle `$crate` from macro call.
    pub fn from_ast(path: ast::Path) -> Option<Path> {
        lower::lower_path(path, &Hygiene::new_unhygienic())
    }

    /// Converts an `ast::Path` to `Path`. Works with use trees.
    /// It correctly handles `$crate` based path from macro call.
    pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
        lower::lower_path(path, hygiene)
    }

    /// Converts an `ast::NameRef` into a single-identifier `Path`.
    pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
        Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] }
    }

    /// Converts a known mod path to `Path`.
    pub(crate) fn from_known_path(
        path: ModPath,
        generic_args: Vec<Option<Arc<GenericArgs>>>,
    ) -> Path {
        Path { type_anchor: None, mod_path: path, generic_args }
    }

    pub fn kind(&self) -> &PathKind {
        &self.mod_path.kind
    }

    pub fn type_anchor(&self) -> Option<&TypeRef> {
        self.type_anchor.as_deref()
    }

    pub fn segments(&self) -> PathSegments<'_> {
        PathSegments {
            segments: self.mod_path.segments.as_slice(),
            generic_args: self.generic_args.as_slice(),
        }
    }

    pub fn mod_path(&self) -> &ModPath {
        &self.mod_path
    }

    pub fn qualifier(&self) -> Option<Path> {
        if self.mod_path.is_ident() {
            return None;
        }
        let res = Path {
            type_anchor: self.type_anchor.clone(),
            mod_path: ModPath {
                kind: self.mod_path.kind.clone(),
                segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(),
            },
            generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(),
        };
        Some(res)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PathSegment<'a> {
    pub name: &'a Name,
    pub args_and_bindings: Option<&'a GenericArgs>,
}

pub struct PathSegments<'a> {
    segments: &'a [Name],
    generic_args: &'a [Option<Arc<GenericArgs>>],
}

impl<'a> PathSegments<'a> {
    pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] };
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
    pub fn len(&self) -> usize {
        self.segments.len()
    }
    pub fn first(&self) -> Option<PathSegment<'a>> {
        self.get(0)
    }
    pub fn last(&self) -> Option<PathSegment<'a>> {
        self.get(self.len().checked_sub(1)?)
    }
    pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        let res = PathSegment {
            name: self.segments.get(idx)?,
            args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it),
        };
        Some(res)
    }
    pub fn skip(&self, len: usize) -> PathSegments<'a> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] }
    }
    pub fn take(&self, len: usize) -> PathSegments<'a> {
        assert_eq!(self.segments.len(), self.generic_args.len());
        PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] }
    }
    pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
        self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment {
            name,
            args_and_bindings: args.as_ref().map(|it| &**it),
        })
    }
}

impl GenericArgs {
    pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> {
        lower::lower_generic_args(node)
    }

    pub(crate) fn empty() -> GenericArgs {
        GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
    }
}

impl From<Name> for Path {
    fn from(name: Name) -> Path {
        Path {
            type_anchor: None,
            mod_path: ModPath::from_simple_segments(PathKind::Plain, iter::once(name)),
            generic_args: vec![None],
        }
    }
}

impl From<Name> for ModPath {
    fn from(name: Name) -> ModPath {
        ModPath::from_simple_segments(PathKind::Plain, iter::once(name))
    }
}

pub use hir_expand::name as __name;

#[macro_export]
macro_rules! __known_path {
    (std::iter::IntoIterator) => {};
    (std::result::Result) => {};
    (std::ops::Range) => {};
    (std::ops::RangeFrom) => {};
    (std::ops::RangeFull) => {};
    (std::ops::RangeTo) => {};
    (std::ops::RangeToInclusive) => {};
    (std::ops::RangeInclusive) => {};
    (std::future::Future) => {};
    (std::ops::Try) => {};
    ($path:path) => {
        compile_error!("Please register your known path in the path module")
    };
}

#[macro_export]
macro_rules! __path {
    ($start:ident $(:: $seg:ident)*) => ({
        $crate::__known_path!($start $(:: $seg)*);
        $crate::path::ModPath::from_simple_segments($crate::path::PathKind::Abs, vec![
            $crate::path::__name![$start], $($crate::path::__name![$seg],)*
        ])
    });
}

pub use crate::__path as path;
<|endoftext|>


<commit_before>// This test should really be part of ruma_serde, but some tooling doesn't like
// cyclic dev-dependencies, which are required for this test to be moved there.

#![allow(clippy::exhaustive_structs)]

use ruma::{Outgoing, UserId};

#[allow(unused)]
pub struct Thing<'t, T> {
    some: &'t str,
    t: &'t T,
}

#[derive(Debug)]
pub struct IncomingThing<T> {
    some: String,
    t: T,
}

#[allow(unused)]
#[derive(Copy, Clone, Debug, Outgoing, serde::Serialize)]
#[serde(crate = "serde")]
pub struct OtherThing<'t> {
    pub some: &'t str,
    pub t: &'t [u8],
}

#[derive(Outgoing)]
#[incoming_derive(!Deserialize)]
pub struct FakeRequest<'a, T> {
    pub abc: &'a str,
    pub thing: Thing<'a, T>,
    pub device_id: &'a ::ruma_identifiers::DeviceId,
    pub user_id: &'a UserId,
    pub bytes: &'a [u8],
    pub recursive: &'a [Thing<'a, T>],
    pub option: Option<&'a [u8]>,
    pub depth: Option<&'a [(&'a str, &'a str)]>,
    pub arc_type: std::sync::Arc<&'a ::ruma_identifiers::ServerName>,
    pub thing_ref: &'a Thing<'a, T>,
    pub double_ref: &'a &'a u8,
    pub triple_ref: &'a &'a &'a str,
}

#[derive(Outgoing)]
#[incoming_derive(!Deserialize)]
pub enum EnumThing<'a, T> {
    Abc(&'a str),
    Stuff(Thing<'a, T>),
    Boxy(&'a ::ruma_identifiers::DeviceId),
    Other(Option<&'a str>),
    StructVar { stuff: &'a str, more: &'a ::ruma_identifiers::ServerName },
}
<commit_msg>Silence Clippy lint for Outgoing derive test<commit_after>// This test should really be part of ruma_serde, but some tooling doesn't like
// cyclic dev-dependencies, which are required for this test to be moved there.

#![allow(clippy::exhaustive_structs, clippy::redundant_allocation)]

use ruma::{Outgoing, UserId};

#[allow(unused)]
pub struct Thing<'t, T> {
    some: &'t str,
    t: &'t T,
}

#[derive(Debug)]
pub struct IncomingThing<T> {
    some: String,
    t: T,
}

#[allow(unused)]
#[derive(Copy, Clone, Debug, Outgoing, serde::Serialize)]
#[serde(crate = "serde")]
pub struct OtherThing<'t> {
    pub some: &'t str,
    pub t: &'t [u8],
}

#[derive(Outgoing)]
#[incoming_derive(!Deserialize)]
pub struct FakeRequest<'a, T> {
    pub abc: &'a str,
    pub thing: Thing<'a, T>,
    pub device_id: &'a ::ruma_identifiers::DeviceId,
    pub user_id: &'a UserId,
    pub bytes: &'a [u8],
    pub recursive: &'a [Thing<'a, T>],
    pub option: Option<&'a [u8]>,
    pub depth: Option<&'a [(&'a str, &'a str)]>,
    pub arc_type: std::sync::Arc<&'a ::ruma_identifiers::ServerName>,
    pub thing_ref: &'a Thing<'a, T>,
    pub double_ref: &'a &'a u8,
    pub triple_ref: &'a &'a &'a str,
}

#[derive(Outgoing)]
#[incoming_derive(!Deserialize)]
pub enum EnumThing<'a, T> {
    Abc(&'a str),
    Stuff(Thing<'a, T>),
    Boxy(&'a ::ruma_identifiers::DeviceId),
    Other(Option<&'a str>),
    StructVar { stuff: &'a str, more: &'a ::ruma_identifiers::ServerName },
}
<|endoftext|>


<commit_before>use actix::actors::signal;
use actix::prelude::*;
use bytes::BytesMut;
use godcoin_p2p::{session::*, NetCmd, Network, Payload};
use log::{error, info};
use std::{
    collections::HashSet,
    time::{Duration, Instant},
};
use tokio::{prelude::*, timer::Delay};

struct Signals;

impl Actor for Signals {
    type Context = Context<Self>;
}

impl Handler<signal::Signal> for Signals {
    type Result = ();

    fn handle(&mut self, msg: signal::Signal, _: &mut Context<Self>) {
        if let signal::SignalType::Int = msg.0 {
            info!("SIGINT received, exiting");
            System::current().stop();
        }
    }
}

struct NetState {
    net_id: usize,
    messages: HashSet<BytesMut>,
}

impl NetState {
    pub fn new(net_id: usize) -> Self {
        NetState {
            net_id,
            messages: HashSet::new(),
        }
    }
}

fn connected(state: &mut NetState, ses: SessionInfo) {
    match ses.conn_type {
        ConnectionType::Inbound => {
            info!(
                "[net:{}] Accepted connection -> {}",
                state.net_id, ses.peer_addr
            );
        }
        ConnectionType::Outbound => {
            info!(
                "[net:{}] Connected to node -> {}",
                state.net_id, ses.peer_addr
            );
        }
    }
}

fn disconnected(state: &mut NetState, ses: SessionInfo) {
    info!(
        "[net:{}] Connection disconnected -> {}",
        state.net_id, ses.peer_addr
    );
}

fn message(state: &mut NetState, id: SessionId, payload: &Payload) -> bool {
    info!(
        "[net:{}] Received message from {} with: {:?}",
        state.net_id, id, payload
    );
    // TODO: evict messages
    state.messages.contains(&payload.id)
}

fn main() {
    let env = env_logger::Env::new()
        .filter_or(env_logger::DEFAULT_FILTER_ENV, "godcoin_simulation=debug");
    env_logger::init_from_env(env);

    let sys = System::new("simulation");

    {
        let sig_addr = Signals.start();
        let addr = signal::ProcessSignals::from_registry();
        addr.do_send(signal::Subscribe(sig_addr.recipient()));
    }

    let nets = {
        let net_count = 3;
        let port = 7777;
        let mut nets = Vec::with_capacity(net_count);
        for net_id in 0..net_count {
            let net = Network::new(NetState::new(net_id), message)
                .on_connect(connected)
                .on_disconnect(disconnected)
                .start();
            net.do_send(NetCmd::Listen(
                format!("127.0.0.1:{}", port + net_id).parse().unwrap(),
            ));
            info!("[net:{}] Accepting connections on 127.0.0.1:7777", net_id);
            nets.push(net);
        }
        nets
    };

    nets[1].do_send(NetCmd::Connect("127.0.0.1:7777".parse().unwrap()));
    nets[2].do_send(NetCmd::Connect("127.0.0.1:7777".parse().unwrap()));
    nets[2].do_send(NetCmd::Connect("127.0.0.1:7778".parse().unwrap()));

    let deadline = Instant::now() + Duration::from_secs(1);
    Arbiter::spawn(
        Delay::new(deadline)
            .and_then(move |_| {
                let payload = Payload {
                    id: BytesMut::from(vec![1, 2, 3]),
                    msg: BytesMut::from(vec![4, 5, 6]),
                };
                info!("[net:2] Broadcasting message: {:?}", &payload);
                nets[2].do_send(NetCmd::Broadcast(payload));
                Ok(())
            })
            .map_err(|e| {
                error!("Timer failed: {:?}", e);
            }),
    );

    sys.run();
}
<commit_msg>Evict messages when every node has received the message<commit_after>use actix::actors::signal;
use actix::prelude::*;
use bytes::BytesMut;
use godcoin_p2p::{session::*, NetCmd, Network, Payload};
use log::{error, info};
use std::{
    collections::HashSet,
    time::{Duration, Instant},
    cell::RefCell,
    rc::Rc
};
use tokio::{prelude::*, timer::Delay};

struct Signals;

impl Actor for Signals {
    type Context = Context<Self>;
}

impl Handler<signal::Signal> for Signals {
    type Result = ();

    fn handle(&mut self, msg: signal::Signal, _: &mut Context<Self>) {
        if let signal::SignalType::Int = msg.0 {
            info!("SIGINT received, exiting");
            System::current().stop();
        }
    }
}

struct NetState {
    net_id: usize,
    messages: HashSet<BytesMut>,
    msg_counter: Rc<RefCell<usize>>,
    msg_threshold: usize,
}

impl NetState {
    pub fn new(net_id: usize, msg_counter: Rc<RefCell<usize>>, msg_threshold: usize) -> Self {
        NetState {
            net_id,
            messages: HashSet::new(),
            msg_counter,
            msg_threshold
        }
    }
}

fn connected(state: &mut NetState, ses: SessionInfo) {
    match ses.conn_type {
        ConnectionType::Inbound => {
            info!(
                "[net:{}] Accepted connection -> {}",
                state.net_id, ses.peer_addr
            );
        }
        ConnectionType::Outbound => {
            info!(
                "[net:{}] Connected to node -> {}",
                state.net_id, ses.peer_addr
            );
        }
    }
}

fn disconnected(state: &mut NetState, ses: SessionInfo) {
    info!(
        "[net:{}] Connection disconnected -> {}",
        state.net_id, ses.peer_addr
    );
}

fn message(state: &mut NetState, id: SessionId, payload: &Payload) -> bool {
    info!(
        "[net:{}] Received message from {} with: {:?}",
        state.net_id, id, payload
    );
    let broadcast = state.messages.contains(&payload.id);
    *state.msg_counter.borrow_mut() += 1;
    if *state.msg_counter.borrow() == state.msg_threshold {
        info!("Threshold reached => evicting cached messages");
        state.messages.clear();
    }
    broadcast
}

fn main() {
    let env = env_logger::Env::new()
        .filter_or(env_logger::DEFAULT_FILTER_ENV, "godcoin_simulation=debug");
    env_logger::init_from_env(env);

    let sys = System::new("simulation");

    {
        let sig_addr = Signals.start();
        let addr = signal::ProcessSignals::from_registry();
        addr.do_send(signal::Subscribe(sig_addr.recipient()));
    }

    let nets = {
        let net_count = 3;
        let port = 7777;
        let mut nets = Vec::with_capacity(net_count);
        let msg_counter = Rc::new(RefCell::new(0));
        // The threshold is always one less to exclude the current network from being counted
        let threshold = net_count - 1;
        for net_id in 0..net_count {
            let msg_counter = Rc::clone(&msg_counter);
            let net = Network::new(NetState::new(net_id, msg_counter, threshold), message)
                .on_connect(connected)
                .on_disconnect(disconnected)
                .start();
            net.do_send(NetCmd::Listen(
                format!("127.0.0.1:{}", port + net_id).parse().unwrap(),
            ));
            info!("[net:{}] Accepting connections on 127.0.0.1:7777", net_id);
            nets.push(net);
        }
        nets
    };

    nets[1].do_send(NetCmd::Connect("127.0.0.1:7777".parse().unwrap()));
    nets[2].do_send(NetCmd::Connect("127.0.0.1:7777".parse().unwrap()));
    nets[2].do_send(NetCmd::Connect("127.0.0.1:7778".parse().unwrap()));

    let deadline = Instant::now() + Duration::from_secs(1);
    Arbiter::spawn(
        Delay::new(deadline)
            .and_then(move |_| {
                let payload = Payload {
                    id: BytesMut::from(vec![1, 2, 3]),
                    msg: BytesMut::from(vec![4, 5, 6]),
                };
                info!("[net:2] Broadcasting message: {:?}", &payload);
                nets[2].do_send(NetCmd::Broadcast(payload));
                Ok(())
            })
            .map_err(|e| {
                error!("Timer failed: {:?}", e);
            }),
    );

    sys.run();
}
<|endoftext|>