<commit_before>#![feature(phase)]
#![feature(globs)]

extern crate getopts;
#[phase(plugin, link)]
extern crate log;

extern crate shadowsocks;

use getopts::{optopt, optflag, getopts, usage, Matches};

use std::os;

use std::io::net::udp::UdpSocket;
use std::io::net::tcp::TcpStream;
use std::io::net::ip::SocketAddr;
use std::io::net::ip::{IpAddr, Port};
use std::io::net::addrinfo::get_host_addresses;
use std::io::{MemWriter, BufReader};
use std::io::stdio::{stdin, stdout};
use std::io::{Reader, Writer, mod};

use shadowsocks::relay::socks5::*;

fn do_tcp(_: &Matches, svr_addr: &Address, proxy_addr: &SocketAddr) {
    let mut proxy_stream = TcpStream::connect(proxy_addr.ip.to_string().as_slice(), proxy_addr.port).unwrap();

    let shake_req = HandshakeRequest::new(vec![0x00]);
    shake_req.write_to(&mut proxy_stream).unwrap();
    let shake_resp = HandshakeResponse::read_from(&mut proxy_stream).unwrap();

    if shake_resp.chosen_method != 0x00 {
        panic!("Proxy server needs authentication");
    }

    let data = stdin().read_to_end().unwrap();

    let req_header = TcpRequestHeader::new(TcpConnect, svr_addr.clone());
    req_header.write_to(&mut proxy_stream).unwrap();
    proxy_stream.write(data.as_slice()).unwrap();

    let resp_header = TcpResponseHeader::read_from(&mut proxy_stream).unwrap();
    match resp_header.reply {
        Succeeded => {},
        _ => {
            panic!("Failed with error {}", resp_header.reply);
        }
    }

    io::util::copy(&mut proxy_stream, &mut stdout()).unwrap();
}

fn do_udp(matches: &Matches, svr_addr: &Address, proxy_addr: &SocketAddr) {
    let udp_proxy_addr = {
        let mut proxy_stream = TcpStream::connect(proxy_addr.ip.to_string().as_slice(), proxy_addr.port).unwrap();

        let shake_req = HandshakeRequest::new(vec![0x00]);
        shake_req.write_to(&mut proxy_stream).unwrap();
        let shake_resp = HandshakeResponse::read_from(&mut proxy_stream).unwrap();

        if shake_resp.chosen_method != 0x00 {
            panic!("Proxy server needs authentication");
        }

        let req_header = TcpRequestHeader::new(UdpAssociate, svr_addr.clone());
        req_header.write_to(&mut proxy_stream).unwrap();

        let resp_header = TcpResponseHeader::read_from(&mut proxy_stream).unwrap();
        match resp_header.reply {
            Succeeded => {},
            _ => {
                panic!("Failed with error {}", resp_header.reply);
            }
        }

        resp_header.address
    };

    let local_addr = SocketAddr {
        ip: from_str(matches.opt_str("b").expect("Require local address").as_slice()).unwrap(),
        port: from_str(matches.opt_str("l").expect("Require local port").as_slice()).unwrap(),
    };

    let mut udp_socket = UdpSocket::bind(local_addr).unwrap();

    let proxy_real_addr = match udp_proxy_addr {
        SocketAddress(ip, port) => SocketAddr {
            ip: ip,
            port: port,
        },
        DomainNameAddress(dm, port) => {
            SocketAddr {
                ip: get_host_addresses(dm.as_slice()).unwrap().head().unwrap().clone(),
                port: port,
            }
        }
    };

    let data = stdin().read_to_end().unwrap();

    let mut bufw = MemWriter::new();
    let udp_header = UdpAssociateHeader::new(0, svr_addr.clone());
    udp_header.write_to(&mut bufw).unwrap();
    bufw.write(data.as_slice()).unwrap();
    udp_socket.send_to(bufw.unwrap().as_slice(), proxy_real_addr).unwrap();

    let mut buf = [0, ..0xffff];
    let (len, _) = udp_socket.recv_from(buf).unwrap();

    let mut bufr = BufReader::new(buf.slice_to(len));
    let _ = UdpAssociateHeader::read_from(&mut bufr).unwrap();

    io::util::copy(&mut bufr, &mut stdout()).unwrap();
}

fn main() {

    let opts = [
        optflag("h", "help", "Print help message"),
        optopt("s", "server-addr", "Server address", ""),
        optopt("p", "server-port", "Server port", ""),
        optopt("b", "local-addr", "Local address for binding", ""),
        optopt("l", "local-port", "Local port for binding", ""),
        optopt("x", "proxy-addr", "Proxy address", ""),
        optopt("o", "proxy-port", "Proxy port", ""),
        optopt("t", "protocol", "Protocol to use", "tcp"),
    ];

    let matches = getopts(os::args().tail(), opts).unwrap();

    if matches.opt_present("h") {
        println!("{}", usage(format!("Usage: {} [Options]", os::args()[0]).as_slice(),
                            opts));
        return;
    }

    let is_tcp = match matches.opt_str("t").expect("Required to specify protocol").as_slice() {
        "tcp" => true,
        "udp" => false,
        _ => panic!("Unsupported protocol")
    };

    let proxy_addr = SocketAddr {
        ip: from_str(matches.opt_str("x").expect("Require proxy address").as_slice()).unwrap(),
        port: from_str(matches.opt_str("o").expect("Require proxy port").as_slice()).unwrap(),
    };

    let svr_port: Port = from_str(matches.opt_str("p").expect("Require server port").as_slice()).unwrap();
    let svr_addr = match from_str::<IpAddr>(matches.opt_str("s").expect("Require server address").as_slice()) {
        Some(ip) => SocketAddress(ip, svr_port),
        None => DomainNameAddress(matches.opt_str("s").unwrap(), svr_port),
    };

    if is_tcp {
        do_tcp(&matches, &svr_addr, &proxy_addr);
    } else {
        do_udp(&matches, &svr_addr, &proxy_addr);
    }
}
<commit_msg>updated tester<commit_after>#![allow(unstable)]

extern crate getopts;
#[macro_use]
extern crate log;

extern crate shadowsocks;

use getopts::{optopt, optflag, getopts, usage, Matches};

use std::os;

use std::io::net::udp::UdpSocket;
use std::io::net::tcp::TcpStream;
use std::io::net::ip::SocketAddr;
use std::io::net::ip::{IpAddr, Port};
use std::io::net::addrinfo::get_host_addresses;
use std::io::BufReader;
use std::io::stdio::{stdin, stdout};
use std::io::{Reader, Writer, self};

use shadowsocks::relay::socks5::*;

fn do_tcp(_: &Matches, svr_addr: &Address, proxy_addr: &SocketAddr) {
    let mut proxy_stream = TcpStream::connect(proxy_addr.to_string().as_slice()).unwrap();

    let shake_req = HandshakeRequest::new(vec![0x00]);
    shake_req.write_to(&mut proxy_stream).unwrap();
    let shake_resp = HandshakeResponse::read_from(&mut proxy_stream).unwrap();

    if shake_resp.chosen_method != 0x00 {
        panic!("Proxy server needs authentication");
    }

    let data = stdin().read_to_end().unwrap();

    let req_header = TcpRequestHeader::new(Command::TcpConnect, svr_addr.clone());
    req_header.write_to(&mut proxy_stream).unwrap();
    proxy_stream.write(data.as_slice()).unwrap();

    let resp_header = TcpResponseHeader::read_from(&mut proxy_stream).unwrap();
    match resp_header.reply {
        Reply::Succeeded => {},
        _ => {
            panic!("Failed with error {:?}", resp_header.reply);
        }
    }

    io::util::copy(&mut proxy_stream, &mut stdout()).unwrap();
}

fn do_udp(matches: &Matches, svr_addr: &Address, proxy_addr: &SocketAddr) {
    let udp_proxy_addr = {
        let mut proxy_stream = TcpStream::connect(proxy_addr.to_string().as_slice()).unwrap();

        let shake_req = HandshakeRequest::new(vec![0x00]);
        shake_req.write_to(&mut proxy_stream).unwrap();
        let shake_resp = HandshakeResponse::read_from(&mut proxy_stream).unwrap();

        if shake_resp.chosen_method != 0x00 {
            panic!("Proxy server needs authentication");
        }

        let req_header = TcpRequestHeader::new(Command::UdpAssociate, svr_addr.clone());
        req_header.write_to(&mut proxy_stream).unwrap();

        let resp_header = TcpResponseHeader::read_from(&mut proxy_stream).unwrap();
        match resp_header.reply {
            Reply::Succeeded => {},
            _ => {
                panic!("Failed with error {:?}", resp_header.reply);
            }
        }

        resp_header.address
    };

    let local_addr = SocketAddr {
        ip: matches.opt_str("b").expect("Require local address").parse().unwrap(),
        port: matches.opt_str("l").expect("Require local port").parse().unwrap(),
    };

    let mut udp_socket = UdpSocket::bind(local_addr).unwrap();

    let proxy_real_addr = match udp_proxy_addr {
        Address::SocketAddress(ip, port) => SocketAddr {
            ip: ip,
            port: port,
        },
        Address::DomainNameAddress(dm, port) => {
            SocketAddr {
                ip: get_host_addresses(dm.as_slice()).unwrap().first().unwrap().clone(),
                port: port,
            }
        }
    };

    let data = stdin().read_to_end().unwrap();

    let mut bufw = Vec::new();
    let udp_header = UdpAssociateHeader::new(0, svr_addr.clone());
    udp_header.write_to(&mut bufw).unwrap();
    bufw.write(data.as_slice()).unwrap();
    udp_socket.send_to(bufw.as_slice(), proxy_real_addr).unwrap();

    let mut buf = [0; 0xffff];
    let (len, _) = udp_socket.recv_from(&mut buf).unwrap();

    let mut bufr = BufReader::new(buf.slice_to(len));
    let _ = UdpAssociateHeader::read_from(&mut bufr).unwrap();

    io::util::copy(&mut bufr, &mut stdout()).unwrap();
}

fn main() {

    let opts = [
        optflag("h", "help", "Print help message"),
        optopt("s", "server-addr", "Server address", ""),
        optopt("p", "server-port", "Server port", ""),
        optopt("b", "local-addr", "Local address for binding", ""),
        optopt("l", "local-port", "Local port for binding", ""),
        optopt("x", "proxy-addr", "Proxy address", ""),
        optopt("o", "proxy-port", "Proxy port", ""),
        optopt("t", "protocol", "Protocol to use", "tcp"),
    ];

    let matches = getopts(os::args().tail(), &opts).unwrap();

    if matches.opt_present("h") {
        println!("{}", usage(format!("Usage: {} [Options]", os::args()[0]).as_slice(),
                             &opts));
        return;
    }

    let is_tcp = match matches.opt_str("t").expect("Required to specify protocol").as_slice() {
        "tcp" => true,
        "udp" => false,
        _ => panic!("Unsupported protocol")
    };

    let proxy_addr = SocketAddr {
        ip: matches.opt_str("x").expect("Require proxy address").parse().unwrap(),
        port: matches.opt_str("o").expect("Require proxy port").parse().unwrap(),
    };

    let svr_port: Port = matches.opt_str("p").expect("Require server port").parse().unwrap();
    let svr_addr = match matches.opt_str("s").expect("Require server address").parse::<IpAddr>() {
        Some(ip) => Address::SocketAddress(ip, svr_port),
        None => Address::DomainNameAddress(matches.opt_str("s").unwrap(), svr_port),
    };

    if is_tcp {
        do_tcp(&matches, &svr_addr, &proxy_addr);
    } else {
        do_udp(&matches, &svr_addr, &proxy_addr);
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;

pub struct Machine {
    memory: Vec<u32>,
    counter: u32,
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            memory: vec![0; 2097152],
            counter: 0,
        }
    }

    pub fn with_data(data: Vec<u32>) -> Machine {
        Machine {
            memory: data,
            counter: 0,
        }
    }

    pub fn loc(&self) -> u32 {
        self.counter
    }

    pub fn dump(&self) -> &Vec<u32> {
        &self.memory
    }

    pub fn load(&mut self, data: Vec<u32>) {
        self.memory = data;
    }

    pub fn exec(&mut self, opcode: u32, a: u32, b: u32, c: u32) {
        match opcode {
            // PC <- M[A]
            1 => {
                self.counter = self.memory[a as usize];
            },

            // If M[B] = 0, then PC <- M[A]
            2 => {
                if 0 == self.memory[b as usize] {
                  self.counter = self.memory[a as usize];
                }
            },

            // M[A] <- PC
            3 => {
                self.memory[a as usize] = self.counter;
                self.counter += 4;
            },

            // M[A] <- M[B]
            4 => {
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[A] <- M[M[B]]
            5 => {
                let b = self.memory[b as usize];
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[M[B]] <- M[A]
            6 => {
                let b = self.memory[b as usize];
                self.memory[b as usize] = self.memory[a as usize];
                self.counter += 4;
            },

            // M[A] <- M[B] + M[C]
            7 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b + c;
                self.counter += 4;
            },

            // Unknown opcode
            _ => {
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Machine;

    #[test]
    fn it_loads_data() {
        let mut m = Machine::new();
        assert_eq!(Some(&0), m.dump().first());

        m.load(vec![1]);
        assert_eq!(Some(&1), m.dump().first());
    }

    #[test]
    fn it_runs_opcode_1() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(1, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_if() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_else() {
        let mut m = Machine::with_data(vec![1, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(0, m.loc());
    }

    #[test]
    fn it_runs_opcode_3() {
        let mut m = Machine::with_data(vec![1]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(3, 0, 0, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_4() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(4, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_5() {
        let mut m = Machine::with_data(vec![1, 2, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(5, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_6() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(6, 1, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_7() {
        let mut m = Machine::with_data(vec![1, 2, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(7, 0, 1, 2);
        assert_eq!(Some(&5), m.dump().first());
        assert_eq!(4, m.loc());
    }
}
<commit_msg>Test that opcode 8 works.<commit_after>use std::vec::Vec;

pub struct Machine {
    memory: Vec<u32>,
    counter: u32,
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            memory: vec![0; 2097152],
            counter: 0,
        }
    }

    pub fn with_data(data: Vec<u32>) -> Machine {
        Machine {
            memory: data,
            counter: 0,
        }
    }

    pub fn loc(&self) -> u32 {
        self.counter
    }

    pub fn dump(&self) -> &Vec<u32> {
        &self.memory
    }

    pub fn load(&mut self, data: Vec<u32>) {
        self.memory = data;
    }

    pub fn exec(&mut self, opcode: u32, a: u32, b: u32, c: u32) {
        match opcode {
            // PC <- M[A]
            1 => {
                self.counter = self.memory[a as usize];
            },

            // If M[B] = 0, then PC <- M[A]
            2 => {
                if 0 == self.memory[b as usize] {
                  self.counter = self.memory[a as usize];
                }
            },

            // M[A] <- PC
            3 => {
                self.memory[a as usize] = self.counter;
                self.counter += 4;
            },

            // M[A] <- M[B]
            4 => {
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[A] <- M[M[B]]
            5 => {
                let b = self.memory[b as usize];
                self.memory[a as usize] = self.memory[b as usize];
                self.counter += 4;
            },

            // M[M[B]] <- M[A]
            6 => {
                let b = self.memory[b as usize];
                self.memory[b as usize] = self.memory[a as usize];
                self.counter += 4;
            },

            // M[A] <- M[B] + M[C]
            7 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b + c;
                self.counter += 4;
            },

            // M[A] <- M[B] - M[C]
            8 => {
                let b = self.memory[b as usize];
                let c = self.memory[c as usize];
                self.memory[a as usize] = b - c;
                self.counter += 4;
            },

            // Unknown opcode
            _ => {
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Machine;

    #[test]
    fn it_loads_data() {
        let mut m = Machine::new();
        assert_eq!(Some(&0), m.dump().first());

        m.load(vec![1]);
        assert_eq!(Some(&1), m.dump().first());
    }

    #[test]
    fn it_runs_opcode_1() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(1, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_if() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_else() {
        let mut m = Machine::with_data(vec![1, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0, 0);
        assert_eq!(0, m.loc());
    }

    #[test]
    fn it_runs_opcode_3() {
        let mut m = Machine::with_data(vec![1]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(3, 0, 0, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_4() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(4, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_5() {
        let mut m = Machine::with_data(vec![1, 2, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(5, 0, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_6() {
        let mut m = Machine::with_data(vec![1, 0]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(6, 1, 1, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_7() {
        let mut m = Machine::with_data(vec![1, 2, 3]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(7, 0, 1, 2);
        assert_eq!(Some(&5), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_8() {
        let mut m = Machine::with_data(vec![0, 3, 2]);

        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(8, 0, 1, 2);
        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(4, m.loc());
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;

pub struct Machine {
    memory: Vec<u32>,
    counter: u32,
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            memory: vec![0; 2097152],
            counter: 0,
        }
    }

    pub fn with_data(data: Vec<u32>) -> Machine {
        Machine {
            memory: data,
            counter: 0,
        }
    }

    pub fn loc(&self) -> u32 {
        self.counter
    }

    pub fn dump(&self) -> &Vec<u32> {
        &self.memory
    }

    pub fn load(&mut self, data: Vec<u32>) {
        self.memory = data;
    }

    pub fn exec(&mut self, opcode: u32, a: u32, b: u32) {
        match opcode {
            // PC <- M[A]
            1 => {
                self.counter = self.memory[a as usize];
            },

            // If M[B] = 0, then PC <- M[A]
            2 => {
                if 0 == self.memory[b as usize] {
                  self.counter = self.memory[a as usize];
                }
            },

            // M[A] <- PC
            3 => {
                self.memory[a as usize] = self.counter;
                self.counter += 4;
            },

            // Unknown opcode
            _ => {
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Machine;

    #[test]
    fn it_loads_data() {
        let mut m = Machine::new();
        assert_eq!(Some(&0), m.dump().first());

        m.load(vec![1]);
        assert_eq!(Some(&1), m.dump().first());
    }

    #[test]
    fn it_runs_opcode_1() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(1, 1, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_if() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_else() {
        let mut m = Machine::with_data(vec![1, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0);
        assert_eq!(0, m.loc());
    }

    #[test]
    fn it_runs_opcode_3() {
        let mut m = Machine::with_data(vec![1]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(3, 0, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }
}
<commit_msg>Test that opcode 4 works.<commit_after>use std::vec::Vec;

pub struct Machine {
    memory: Vec<u32>,
    counter: u32,
}

impl Machine {
    pub fn new() -> Machine {
        Machine {
            memory: vec![0; 2097152],
            counter: 0,
        }
    }

    pub fn with_data(data: Vec<u32>) -> Machine {
        Machine {
            memory: data,
            counter: 0,
        }
    }

    pub fn loc(&self) -> u32 {
        self.counter
    }

    pub fn dump(&self) -> &Vec<u32> {
        &self.memory
    }

    pub fn load(&mut self, data: Vec<u32>) {
        self.memory = data;
    }

    pub fn exec(&mut self, opcode: u32, a: u32, b: u32) {
        match opcode {
            // PC <- M[A]
            1 => {
                self.counter = self.memory[a as usize];
            },

            // If M[B] = 0, then PC <- M[A]
            2 => {
                if 0 == self.memory[b as usize] {
                  self.counter = self.memory[a as usize];
                }
            },

            // M[A] <- PC
            3 => {
                self.memory[a as usize] = self.counter;
                self.counter += 4;
            },

            // M[A] <- M[M[B]]
            4 => {
                let b = self.memory[b as usize];
                self.memory[a as usize] = self.memory[b as usize];
            },

            // Unknown opcode
            _ => {
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Machine;

    #[test]
    fn it_loads_data() {
        let mut m = Machine::new();
        assert_eq!(Some(&0), m.dump().first());

        m.load(vec![1]);
        assert_eq!(Some(&1), m.dump().first());
    }

    #[test]
    fn it_runs_opcode_1() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(1, 1, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_if() {
        let mut m = Machine::with_data(vec![0, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0);
        assert_eq!(2, m.loc());
    }

    #[test]
    fn it_runs_opcode_2_else() {
        let mut m = Machine::with_data(vec![1, 2]);

        assert_eq!(0, m.loc());
        m.exec(2, 1, 0);
        assert_eq!(0, m.loc());
    }

    #[test]
    fn it_runs_opcode_3() {
        let mut m = Machine::with_data(vec![1]);

        assert_eq!(Some(&1), m.dump().first());
        assert_eq!(0, m.loc());
        m.exec(3, 0, 0);
        assert_eq!(Some(&0), m.dump().first());
        assert_eq!(4, m.loc());
    }

    #[test]
    fn it_runs_opcode_4() {
        let mut m = Machine::with_data(vec![1, 2, 0]);

        assert_eq!(Some(&1), m.dump().first());
        m.exec(4, 0, 1);
        assert_eq!(Some(&0), m.dump().first());
    }
}
<|endoftext|>


<commit_before>//! The Adapter manager
//!
//! This structure serves two roles:
//! - adapters use it to (un)register themselves, as well as services and channels;
//! - it exposes an implementation of the taxonomy API.

use backend::*;
use adapter::{ Adapter, AdapterManagerHandle };

use foxbox_taxonomy::api::{ API, Error, ResultMap, WatchEvent };
use foxbox_taxonomy::selector::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::util::*;
use foxbox_taxonomy::values::{ Range, Value };

use transformable_channels::mpsc::*;

use std::thread;

/// An implementation of the AdapterManager.
pub struct AdapterManager {
    tx: RawSender<Op>
}

impl AdapterManager {
    /// Create an empty AdapterManager.
    /// This function does not attempt to load any state from the disk.
    pub fn new() -> Self {
        let (tx, rx) = channel();
        thread::spawn(move || {
            let mut back_end = AdapterManagerState::new();
            for msg in rx {
                back_end.execute(msg);
            }
            // The loop will exit once self.tx is dropped.
        });
        AdapterManager {
            tx: tx
        }
    }

    fn dispatch<T>(&self, op: Op, rx_back: Receiver<T>) -> T {
        // Send to the back-end thread. This will panic iff the back-end thread has
        // already panicked, i.e. probably if one of the adapters has panicked. At
        // this stage, we probably want to relaunch the foxbox.
        self.tx.send(op).unwrap();
        // Again, this will panic iff the back-end thread has already panicked.
        rx_back.recv().unwrap()
    }
}

impl Default for AdapterManager {
    fn default() -> Self {
        Self::new()
    }
}

impl AdapterManagerHandle for AdapterManager {
    /// Add an adapter to the system.
    ///
    /// # Errors
    ///
    /// Returns an error if an adapter with the same id is already present.
    fn add_adapter(&self, adapter: Box<Adapter>) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::AddAdapter {
            adapter: adapter,
            tx: tx
        }, rx)
    }

    /// Remove an adapter from the system, including all its services and channels.
    ///
    /// # Errors
    ///
    /// Returns an error if no adapter with this identifier exists. Otherwise, attempts
    /// to cleanup as much as possible, even if for some reason the system is in an
    /// inconsistent state.
    fn remove_adapter(&self, id: &Id<AdapterId>) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::RemoveAdapter {
            id: id.clone(),
            tx: tx
        }, rx)
    }

    /// Add a service to the system. Called by the adapter when a new
    /// service (typically a new device) has been detected/configured.
    ///
    /// The `service` must NOT have any channels yet. Channels must be added through
    /// `add_channel`.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if any of:
    /// - `service` has channels;
    /// - a service with id `service.id` is already installed on the system;
    /// - there is no adapter with id `service.adapter`.
    fn add_service(&self, service: Service) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::AddService {
            service: service,
            tx: tx
        }, rx)
    }

    /// Remove a service previously registered on the system. Typically, called by
    /// an adapter when a service (e.g. a device) is disconnected.
    ///
    /// # Error
    ///
    /// Returns an error if any of:
    /// - there is no such service;
    /// - there is an internal inconsistency, in which case this method will still attempt to
    /// cleanup before returning an error.
    fn remove_service(&self, id: &Id<ServiceId>) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::RemoveService {
            id: id.clone(),
            tx: tx
        }, rx)
    }

    /// Add a setter to the system. Typically, this is called by the adapter when a new
    /// service has been detected/configured. Some services may gain/lose getters at
    /// runtime depending on their configuration.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if the adapter is not registered, the parent service is not
    /// registered, or a channel with the same identifier is already registered.
    /// In either cases, this method reverts all its changes.
    fn add_getter(&self, getter: Channel<Getter>) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::AddGetter {
            getter: getter,
            tx: tx,
        }, rx)
    }

    /// Remove a setter previously registered on the system. Typically, called by
    /// an adapter when a service is reconfigured to remove one of its getters.
    ///
    /// # Error
    ///
    /// This method returns an error if the setter is not registered or if the service
    /// is not registered. In either case, it attemps to clean as much as possible, even
    /// if the state is inconsistent.
    fn remove_getter(&self, id: &Id<Getter>) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::RemoveGetter {
            id: id.clone(),
            tx: tx,
        }, rx)
    }

    /// Add a setter to the system. Typically, this is called by the adapter when a new
    /// service has been detected/configured. Some services may gain/lose setters at
    /// runtime depending on their configuration.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if the adapter is not registered, the parent service is not
    /// registered, or a channel with the same identifier is already registered.
    /// In either cases, this method reverts all its changes.
    fn add_setter(&self, setter: Channel<Setter>) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::AddSetter {
            setter: setter,
            tx: tx,
        }, rx)
    }

    /// Remove a setter previously registered on the system. Typically, called by
    /// an adapter when a service is reconfigured to remove one of its setters.
    ///
    /// # Error
    ///
    /// This method returns an error if the setter is not registered or if the service
    /// is not registered. In either case, it attemps to clean as much as possible, even
    /// if the state is inconsistent.
    fn remove_setter(&self, id: &Id<Setter>) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::RemoveSetter {
            id: id.clone(),
            tx: tx
        }, rx)
    }
}

/// A handle to the public API.
impl API for AdapterManager {
    /// Get the metadata on services matching some conditions.
    ///
    /// A call to `API::get_services(vec![req1, req2, ...])` will return
    /// the metadata on all services matching _either_ `req1` or `req2`
    /// or ...
    fn get_services(&self, selectors: Vec<ServiceSelector>) -> Vec<Service> {
        let (tx, rx) = channel();
        self.dispatch(Op::GetServices {
            selectors: selectors,
            tx: tx
        }, rx)
    }

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    fn add_service_tags(&self, selectors: Vec<ServiceSelector>, tags: Vec<Id<TagId>>) -> usize {
        let (tx, rx) = channel();
        self.dispatch(Op::AddServiceTags {
            selectors: selectors,
            tags: tags,
            tx: tx
        }, rx)
    }

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    fn remove_service_tags(&self, selectors: Vec<ServiceSelector>, tags: Vec<Id<TagId>>) -> usize {
        let (tx, rx) = channel();
        self.dispatch(Op::RemoveServiceTags {
            selectors: selectors,
            tags: tags,
            tx: tx,
        }, rx)
    }

    /// Get a list of channels matching some conditions
    fn get_getter_channels(&self, selectors: Vec<GetterSelector>) -> Vec<Channel<Getter>> {
        let (tx, rx) = channel();
        self.dispatch(Op::GetGetterChannels {
            selectors: selectors,
            tx: tx,
        }, rx)
    }
    fn get_setter_channels(&self, selectors: Vec<SetterSelector>) -> Vec<Channel<Setter>> {
        let (tx, rx) = channel();
        self.dispatch(Op::GetSetterChannels {
            selectors: selectors,
            tx: tx,
        }, rx)
    }

    /// Label a set of channels with a set of tags.
    ///
    /// A call to `API::put_{setter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the channels matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    fn add_getter_tags(&self, selectors: Vec<GetterSelector>, tags: Vec<Id<TagId>>) -> usize {
        let (tx, rx) = channel();
        self.dispatch(Op::AddGetterTags {
            selectors: selectors,
            tags: tags,
            tx: tx,
        }, rx)

    }
    fn add_setter_tags(&self, selectors: Vec<SetterSelector>, tags: Vec<Id<TagId>>) -> usize {
        let (tx, rx) = channel();
        self.dispatch(Op::AddSetterTags {
            selectors: selectors,
            tags: tags,
            tx: tx,
        }, rx)
    }

    /// Remove a set of tags from a set of channels.
    ///
    /// A call to `API::delete_{setter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the channels matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    fn remove_getter_tags(&self, selectors: Vec<GetterSelector>, tags: Vec<Id<TagId>>) -> usize {
        let (tx, rx) = channel();
        self.dispatch(Op::RemoveGetterTags {
            selectors: selectors,
            tags: tags,
            tx: tx,
        }, rx)
    }
    fn remove_setter_tags(&self, selectors: Vec<SetterSelector>, tags: Vec<Id<TagId>>) -> usize {
        let (tx, rx) = channel();
        self.dispatch(Op::RemoveSetterTags {
            selectors: selectors,
            tags: tags,
            tx: tx,
        }, rx)
    }

    /// Read the latest value from a set of channels
    fn fetch_values(&self, selectors: Vec<GetterSelector>) ->
        ResultMap<Id<Getter>, Option<Value>, Error>
    {
        let (tx, rx) = channel();
        self.dispatch(Op::FetchValues {
            selectors: selectors,
            tx: tx,
        }, rx)
    }

    /// Send a bunch of values to a set of channels
    fn send_values(&self, keyvalues: Vec<(Vec<SetterSelector>, Value)>) ->
        ResultMap<Id<Setter>, (), Error>
    {
        let (tx, rx) = channel();
        self.dispatch(Op::SendValues {
            keyvalues: keyvalues,
            tx: tx,
        }, rx)
    }

    /// Watch for any change
    fn register_channel_watch(&self, watch: Vec<(Vec<GetterSelector>, Exactly<Range>)>,
        on_event: Box<ExtSender<WatchEvent>>) -> Self::WatchGuard
    {
        let (tx, rx) = channel();
        let (tx_dropped, key, is_dropped) = self.dispatch(Op::RegisterChannelWatch {
            watch: watch,
            on_event: on_event,
            tx: tx
        }, rx);
        WatchGuard::new(Box::new(self.tx.clone()), tx_dropped, key, is_dropped)
    }

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard = WatchGuard;
}<commit_msg>AdapterManager now derives Clone<commit_after>//! The Adapter manager
//!
//! This structure serves two roles:
//! - adapters use it to (un)register themselves, as well as services and channels;
//! - it exposes an implementation of the taxonomy API.

use backend::*;
use adapter::{ Adapter, AdapterManagerHandle };

use foxbox_taxonomy::api::{ API, Error, ResultMap, WatchEvent };
use foxbox_taxonomy::selector::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::util::*;
use foxbox_taxonomy::values::{ Range, Value };

use transformable_channels::mpsc::*;

use std::thread;

/// An implementation of the AdapterManager.
#[derive(Clone)]
pub struct AdapterManager {
    tx: RawSender<Op>
}

impl AdapterManager {
    /// Create an empty AdapterManager.
    /// This function does not attempt to load any state from the disk.
    pub fn new() -> Self {
        let (tx, rx) = channel();
        thread::spawn(move || {
            let mut back_end = AdapterManagerState::new();
            for msg in rx {
                back_end.execute(msg);
            }
            // The loop will exit once self.tx is dropped.
        });
        AdapterManager {
            tx: tx
        }
    }

    fn dispatch<T>(&self, op: Op, rx_back: Receiver<T>) -> T {
        // Send to the back-end thread. This will panic iff the back-end thread has
        // already panicked, i.e. probably if one of the adapters has panicked. At
        // this stage, we probably want to relaunch the foxbox.
        self.tx.send(op).unwrap();
        // Again, this will panic iff the back-end thread has already panicked.
        rx_back.recv().unwrap()
    }
}

impl Default for AdapterManager {
    fn default() -> Self {
        Self::new()
    }
}

impl AdapterManagerHandle for AdapterManager {
    /// Add an adapter to the system.
    ///
    /// # Errors
    ///
    /// Returns an error if an adapter with the same id is already present.
    fn add_adapter(&self, adapter: Box<Adapter>) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::AddAdapter {
            adapter: adapter,
            tx: tx
        }, rx)
    }

    /// Remove an adapter from the system, including all its services and channels.
    ///
    /// # Errors
    ///
    /// Returns an error if no adapter with this identifier exists. Otherwise, attempts
    /// to cleanup as much as possible, even if for some reason the system is in an
    /// inconsistent state.
    fn remove_adapter(&self, id: &Id<AdapterId>) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::RemoveAdapter {
            id: id.clone(),
            tx: tx
        }, rx)
    }

    /// Add a service to the system. Called by the adapter when a new
    /// service (typically a new device) has been detected/configured.
    ///
    /// The `service` must NOT have any channels yet. Channels must be added through
    /// `add_channel`.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if any of:
    /// - `service` has channels;
    /// - a service with id `service.id` is already installed on the system;
    /// - there is no adapter with id `service.adapter`.
    fn add_service(&self, service: Service) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::AddService {
            service: service,
            tx: tx
        }, rx)
    }

    /// Remove a service previously registered on the system. Typically, called by
    /// an adapter when a service (e.g. a device) is disconnected.
    ///
    /// # Error
    ///
    /// Returns an error if any of:
    /// - there is no such service;
    /// - there is an internal inconsistency, in which case this method will still attempt to
    /// cleanup before returning an error.
    fn remove_service(&self, id: &Id<ServiceId>) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::RemoveService {
            id: id.clone(),
            tx: tx
        }, rx)
    }

    /// Add a setter to the system. Typically, this is called by the adapter when a new
    /// service has been detected/configured. Some services may gain/lose getters at
    /// runtime depending on their configuration.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if the adapter is not registered, the parent service is not
    /// registered, or a channel with the same identifier is already registered.
    /// In either cases, this method reverts all its changes.
    fn add_getter(&self, getter: Channel<Getter>) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::AddGetter {
            getter: getter,
            tx: tx,
        }, rx)
    }

    /// Remove a setter previously registered on the system. Typically, called by
    /// an adapter when a service is reconfigured to remove one of its getters.
    ///
    /// # Error
    ///
    /// This method returns an error if the setter is not registered or if the service
    /// is not registered. In either case, it attemps to clean as much as possible, even
    /// if the state is inconsistent.
    fn remove_getter(&self, id: &Id<Getter>) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::RemoveGetter {
            id: id.clone(),
            tx: tx,
        }, rx)
    }

    /// Add a setter to the system. Typically, this is called by the adapter when a new
    /// service has been detected/configured. Some services may gain/lose setters at
    /// runtime depending on their configuration.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if the adapter is not registered, the parent service is not
    /// registered, or a channel with the same identifier is already registered.
    /// In either cases, this method reverts all its changes.
    fn add_setter(&self, setter: Channel<Setter>) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::AddSetter {
            setter: setter,
            tx: tx,
        }, rx)
    }

    /// Remove a setter previously registered on the system. Typically, called by
    /// an adapter when a service is reconfigured to remove one of its setters.
    ///
    /// # Error
    ///
    /// This method returns an error if the setter is not registered or if the service
    /// is not registered. In either case, it attemps to clean as much as possible, even
    /// if the state is inconsistent.
    fn remove_setter(&self, id: &Id<Setter>) -> Result<(), Error> {
        let (tx, rx) = channel();
        self.dispatch(Op::RemoveSetter {
            id: id.clone(),
            tx: tx
        }, rx)
    }
}

/// A handle to the public API.
impl API for AdapterManager {
    /// Get the metadata on services matching some conditions.
    ///
    /// A call to `API::get_services(vec![req1, req2, ...])` will return
    /// the metadata on all services matching _either_ `req1` or `req2`
    /// or ...
    fn get_services(&self, selectors: Vec<ServiceSelector>) -> Vec<Service> {
        let (tx, rx) = channel();
        self.dispatch(Op::GetServices {
            selectors: selectors,
            tx: tx
        }, rx)
    }

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    fn add_service_tags(&self, selectors: Vec<ServiceSelector>, tags: Vec<Id<TagId>>) -> usize {
        let (tx, rx) = channel();
        self.dispatch(Op::AddServiceTags {
            selectors: selectors,
            tags: tags,
            tx: tx
        }, rx)
    }

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_service_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the selectors.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    fn remove_service_tags(&self, selectors: Vec<ServiceSelector>, tags: Vec<Id<TagId>>) -> usize {
        let (tx, rx) = channel();
        self.dispatch(Op::RemoveServiceTags {
            selectors: selectors,
            tags: tags,
            tx: tx,
        }, rx)
    }

    /// Get a list of channels matching some conditions
    fn get_getter_channels(&self, selectors: Vec<GetterSelector>) -> Vec<Channel<Getter>> {
        let (tx, rx) = channel();
        self.dispatch(Op::GetGetterChannels {
            selectors: selectors,
            tx: tx,
        }, rx)
    }
    fn get_setter_channels(&self, selectors: Vec<SetterSelector>) -> Vec<Channel<Setter>> {
        let (tx, rx) = channel();
        self.dispatch(Op::GetSetterChannels {
            selectors: selectors,
            tx: tx,
        }, rx)
    }

    /// Label a set of channels with a set of tags.
    ///
    /// A call to `API::put_{setter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the channels matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    fn add_getter_tags(&self, selectors: Vec<GetterSelector>, tags: Vec<Id<TagId>>) -> usize {
        let (tx, rx) = channel();
        self.dispatch(Op::AddGetterTags {
            selectors: selectors,
            tags: tags,
            tx: tx,
        }, rx)

    }
    fn add_setter_tags(&self, selectors: Vec<SetterSelector>, tags: Vec<Id<TagId>>) -> usize {
        let (tx, rx) = channel();
        self.dispatch(Op::AddSetterTags {
            selectors: selectors,
            tags: tags,
            tx: tx,
        }, rx)
    }

    /// Remove a set of tags from a set of channels.
    ///
    /// A call to `API::delete_{setter, setter}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the channels matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of channels
    /// matching any of the selectors.
    ///
    /// Some of the channels may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if channels
    /// are added after the call, they will not be affected.
    fn remove_getter_tags(&self, selectors: Vec<GetterSelector>, tags: Vec<Id<TagId>>) -> usize {
        let (tx, rx) = channel();
        self.dispatch(Op::RemoveGetterTags {
            selectors: selectors,
            tags: tags,
            tx: tx,
        }, rx)
    }
    fn remove_setter_tags(&self, selectors: Vec<SetterSelector>, tags: Vec<Id<TagId>>) -> usize {
        let (tx, rx) = channel();
        self.dispatch(Op::RemoveSetterTags {
            selectors: selectors,
            tags: tags,
            tx: tx,
        }, rx)
    }

    /// Read the latest value from a set of channels
    fn fetch_values(&self, selectors: Vec<GetterSelector>) ->
        ResultMap<Id<Getter>, Option<Value>, Error>
    {
        let (tx, rx) = channel();
        self.dispatch(Op::FetchValues {
            selectors: selectors,
            tx: tx,
        }, rx)
    }

    /// Send a bunch of values to a set of channels
    fn send_values(&self, keyvalues: Vec<(Vec<SetterSelector>, Value)>) ->
        ResultMap<Id<Setter>, (), Error>
    {
        let (tx, rx) = channel();
        self.dispatch(Op::SendValues {
            keyvalues: keyvalues,
            tx: tx,
        }, rx)
    }

    /// Watch for any change
    fn register_channel_watch(&self, watch: Vec<(Vec<GetterSelector>, Exactly<Range>)>,
        on_event: Box<ExtSender<WatchEvent>>) -> Self::WatchGuard
    {
        let (tx, rx) = channel();
        let (tx_dropped, key, is_dropped) = self.dispatch(Op::RegisterChannelWatch {
            watch: watch,
            on_event: on_event,
            tx: tx
        }, rx);
        WatchGuard::new(Box::new(self.tx.clone()), tx_dropped, key, is_dropped)
    }

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard = WatchGuard;
}<|endoftext|>


<commit_before>// Copyright 2016 Serde YAML Developers
//
// 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.

use std::fmt;
use std::iter::FromIterator;
use std::ops::{Index, IndexMut};

use linked_hash_map::{self, LinkedHashMap};
use serde::{self, Serialize, Deserialize, Deserializer};

use value::Value;

/// A YAML mapping in which the keys and values are both `serde_yaml::Value`.
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd)]
pub struct Mapping {
    map: LinkedHashMap<Value, Value>,
}

impl Mapping {
    #[inline]
    pub fn new() -> Self {
        Self::default()
    }

    #[inline]
    pub fn with_capacity(capacity: usize) -> Self {
        Mapping { map: LinkedHashMap::with_capacity(capacity) }
    }

    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.map.reserve(additional)
    }

    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.map.shrink_to_fit()
    }

    #[inline]
    pub fn insert(&mut self, k: Value, v: Value) -> Option<Value> {
        self.map.insert(k, v)
    }

    #[inline]
    pub fn contains_key(&self, k: &Value) -> bool {
        self.map.contains_key(k)
    }

    #[inline]
    pub fn get(&self, k: &Value) -> Option<&Value> {
        self.map.get(k)
    }

    #[inline]
    pub fn get_mut(&mut self, k: &Value) -> Option<&mut Value> {
        self.map.get_mut(k)
    }

    #[inline]
    pub fn remove(&mut self, k: &Value) -> Option<Value> {
        self.map.remove(k)
    }

    #[inline]
    pub fn capacity(&self) -> usize {
        self.map.capacity()
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.map.len()
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    #[inline]
    pub fn clear(&mut self) {
        self.map.clear()
    }

    #[inline]
    pub fn iter(&self) -> Iter {
        Iter { iter: self.map.iter() }
    }

    #[inline]
    pub fn iter_mut(&mut self) -> IterMut {
        IterMut { iter: self.map.iter_mut() }
    }
}

impl<'a> Index<&'a Value> for Mapping {
    type Output = Value;
    #[inline]
    fn index(&self, index: &'a Value) -> &Value {
        self.map.index(index)
    }
}

impl<'a> IndexMut<&'a Value> for Mapping {
    #[inline]
    fn index_mut(&mut self, index: &'a Value) -> &mut Value {
        self.map.index_mut(index)
    }
}

impl Extend<(Value, Value)> for Mapping {
    #[inline]
    fn extend<I: IntoIterator<Item = (Value, Value)>>(&mut self, iter: I) {
        self.map.extend(iter);
    }
}

impl FromIterator<(Value, Value)> for Mapping {
    #[inline]
    fn from_iter<I: IntoIterator<Item = (Value, Value)>>(iter: I) -> Self {
        Mapping { map: LinkedHashMap::from_iter(iter) }
    }
}

macro_rules! delegate_iterator {
    (($name:ident $($generics:tt)*) => $item:ty) => {
        impl $($generics)* Iterator for $name $($generics)* {
            type Item = $item;
            #[inline]
            fn next(&mut self) -> Option<Self::Item> {
                self.iter.next()
            }
            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                self.iter.size_hint()
            }
        }

        impl $($generics)* ExactSizeIterator for $name $($generics)* {
            #[inline]
            fn len(&self) -> usize {
                self.iter.len()
            }
        }
    }
}

pub struct Iter<'a> {
    iter: linked_hash_map::Iter<'a, Value, Value>,
}

delegate_iterator!((Iter<'a>) => (&'a Value, &'a Value));

impl<'a> IntoIterator for &'a Mapping {
    type Item = (&'a Value, &'a Value);
    type IntoIter = Iter<'a>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        Iter { iter: self.map.iter() }
    }
}

pub struct IterMut<'a> {
    iter: linked_hash_map::IterMut<'a, Value, Value>,
}

delegate_iterator!((IterMut<'a>) => (&'a Value, &'a mut Value));

impl<'a> IntoIterator for &'a mut Mapping {
    type Item = (&'a Value, &'a mut Value);
    type IntoIter = IterMut<'a>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IterMut { iter: self.map.iter_mut() }
    }
}

pub struct IntoIter {
    iter: linked_hash_map::IntoIter<Value, Value>,
}

delegate_iterator!((IntoIter) => (Value, Value));

impl IntoIterator for Mapping {
    type Item = (Value, Value);
    type IntoIter = IntoIter;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IntoIter { iter: self.map.into_iter() }
    }
}

impl Serialize for Mapping {
    #[inline]
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        use serde::ser::SerializeMap;
        let mut map_serializer = try!(serializer.serialize_map(Some(self.len())));
        for (k, v) in self {
            try!(map_serializer.serialize_key(k));
            try!(map_serializer.serialize_value(v));
        }
        map_serializer.end()
    }
}

impl<'de> Deserialize<'de> for Mapping {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        struct Visitor;

        impl<'de> serde::de::Visitor<'de> for Visitor {
            type Value = Mapping;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a YAML mapping")
            }

            #[inline]
            fn visit_unit<E>(self) -> Result<Self::Value, E>
                where E: serde::de::Error
            {
                Ok(Mapping::new())
            }

            #[inline]
            fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
                where V: serde::de::MapAccess<'de>
            {
                let mut values = Mapping::new();
                while let Some((k, v)) = try!(visitor.next_entry()) {
                    values.insert(k, v);
                }
                Ok(values)
            }
        }

        deserializer.deserialize_map(Visitor)
    }
}
<commit_msg>Use ? instead of try<commit_after>// Copyright 2016 Serde YAML Developers
//
// 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.

use std::fmt;
use std::iter::FromIterator;
use std::ops::{Index, IndexMut};

use linked_hash_map::{self, LinkedHashMap};
use serde::{self, Serialize, Deserialize, Deserializer};

use value::Value;

/// A YAML mapping in which the keys and values are both `serde_yaml::Value`.
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd)]
pub struct Mapping {
    map: LinkedHashMap<Value, Value>,
}

impl Mapping {
    #[inline]
    pub fn new() -> Self {
        Self::default()
    }

    #[inline]
    pub fn with_capacity(capacity: usize) -> Self {
        Mapping { map: LinkedHashMap::with_capacity(capacity) }
    }

    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.map.reserve(additional)
    }

    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.map.shrink_to_fit()
    }

    #[inline]
    pub fn insert(&mut self, k: Value, v: Value) -> Option<Value> {
        self.map.insert(k, v)
    }

    #[inline]
    pub fn contains_key(&self, k: &Value) -> bool {
        self.map.contains_key(k)
    }

    #[inline]
    pub fn get(&self, k: &Value) -> Option<&Value> {
        self.map.get(k)
    }

    #[inline]
    pub fn get_mut(&mut self, k: &Value) -> Option<&mut Value> {
        self.map.get_mut(k)
    }

    #[inline]
    pub fn remove(&mut self, k: &Value) -> Option<Value> {
        self.map.remove(k)
    }

    #[inline]
    pub fn capacity(&self) -> usize {
        self.map.capacity()
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.map.len()
    }

    #[inline]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    #[inline]
    pub fn clear(&mut self) {
        self.map.clear()
    }

    #[inline]
    pub fn iter(&self) -> Iter {
        Iter { iter: self.map.iter() }
    }

    #[inline]
    pub fn iter_mut(&mut self) -> IterMut {
        IterMut { iter: self.map.iter_mut() }
    }
}

impl<'a> Index<&'a Value> for Mapping {
    type Output = Value;
    #[inline]
    fn index(&self, index: &'a Value) -> &Value {
        self.map.index(index)
    }
}

impl<'a> IndexMut<&'a Value> for Mapping {
    #[inline]
    fn index_mut(&mut self, index: &'a Value) -> &mut Value {
        self.map.index_mut(index)
    }
}

impl Extend<(Value, Value)> for Mapping {
    #[inline]
    fn extend<I: IntoIterator<Item = (Value, Value)>>(&mut self, iter: I) {
        self.map.extend(iter);
    }
}

impl FromIterator<(Value, Value)> for Mapping {
    #[inline]
    fn from_iter<I: IntoIterator<Item = (Value, Value)>>(iter: I) -> Self {
        Mapping { map: LinkedHashMap::from_iter(iter) }
    }
}

macro_rules! delegate_iterator {
    (($name:ident $($generics:tt)*) => $item:ty) => {
        impl $($generics)* Iterator for $name $($generics)* {
            type Item = $item;
            #[inline]
            fn next(&mut self) -> Option<Self::Item> {
                self.iter.next()
            }
            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                self.iter.size_hint()
            }
        }

        impl $($generics)* ExactSizeIterator for $name $($generics)* {
            #[inline]
            fn len(&self) -> usize {
                self.iter.len()
            }
        }
    }
}

pub struct Iter<'a> {
    iter: linked_hash_map::Iter<'a, Value, Value>,
}

delegate_iterator!((Iter<'a>) => (&'a Value, &'a Value));

impl<'a> IntoIterator for &'a Mapping {
    type Item = (&'a Value, &'a Value);
    type IntoIter = Iter<'a>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        Iter { iter: self.map.iter() }
    }
}

pub struct IterMut<'a> {
    iter: linked_hash_map::IterMut<'a, Value, Value>,
}

delegate_iterator!((IterMut<'a>) => (&'a Value, &'a mut Value));

impl<'a> IntoIterator for &'a mut Mapping {
    type Item = (&'a Value, &'a mut Value);
    type IntoIter = IterMut<'a>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IterMut { iter: self.map.iter_mut() }
    }
}

pub struct IntoIter {
    iter: linked_hash_map::IntoIter<Value, Value>,
}

delegate_iterator!((IntoIter) => (Value, Value));

impl IntoIterator for Mapping {
    type Item = (Value, Value);
    type IntoIter = IntoIter;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IntoIter { iter: self.map.into_iter() }
    }
}

impl Serialize for Mapping {
    #[inline]
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        use serde::ser::SerializeMap;
        let mut map_serializer = serializer.serialize_map(Some(self.len()))?;
        for (k, v) in self {
            map_serializer.serialize_entry(k, v)?;
        }
        map_serializer.end()
    }
}

impl<'de> Deserialize<'de> for Mapping {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        struct Visitor;

        impl<'de> serde::de::Visitor<'de> for Visitor {
            type Value = Mapping;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a YAML mapping")
            }

            #[inline]
            fn visit_unit<E>(self) -> Result<Self::Value, E>
                where E: serde::de::Error
            {
                Ok(Mapping::new())
            }

            #[inline]
            fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
                where V: serde::de::MapAccess<'de>
            {
                let mut values = Mapping::new();
                while let Some((k, v)) = visitor.next_entry()? {
                    values.insert(k, v);
                }
                Ok(values)
            }
        }

        deserializer.deserialize_map(Visitor)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{Event, Metadata};

use once_cell::sync::OnceCell;
use std::sync::Arc;

static LOGGER: OnceCell<Arc<dyn Logger>> = OnceCell::new();

/// A trait encapsulating the operations required of a logger.
pub trait Logger: Sync + Send + 'static {
    /// Determines if an event with the specified metadata would be logged
    fn enabled(&self, metadata: &Metadata) -> bool;

    /// Record an event
    fn record(&self, event: &Event);
}

pub(crate) fn dispatch(event: &Event) {
    if let Some(logger) = LOGGER.get() {
        logger.record(event)
    }
}

pub(crate) fn enabled(metadata: &Metadata) -> bool {
    LOGGER
        .get()
        .map(|logger| logger.enabled(metadata))
        .unwrap_or(false)
}

pub fn set_global_logger(logger: Arc<dyn Logger>) {
    if LOGGER.set(logger).is_err() {
        eprintln!("Global logger has already been set");
    }
}
<commit_msg>logger: increment a counter when we dispatch a log event<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{counters::STRUCT_LOG_COUNT, Event, Metadata};

use once_cell::sync::OnceCell;
use std::sync::Arc;

static LOGGER: OnceCell<Arc<dyn Logger>> = OnceCell::new();

/// A trait encapsulating the operations required of a logger.
pub trait Logger: Sync + Send + 'static {
    /// Determines if an event with the specified metadata would be logged
    fn enabled(&self, metadata: &Metadata) -> bool;

    /// Record an event
    fn record(&self, event: &Event);
}

pub(crate) fn dispatch(event: &Event) {
    if let Some(logger) = LOGGER.get() {
        STRUCT_LOG_COUNT.inc();
        logger.record(event)
    }
}

pub(crate) fn enabled(metadata: &Metadata) -> bool {
    LOGGER
        .get()
        .map(|logger| logger.enabled(metadata))
        .unwrap_or(false)
}

pub fn set_global_logger(logger: Arc<dyn Logger>) {
    if LOGGER.set(logger).is_err() {
        eprintln!("Global logger has already been set");
    }
}
<|endoftext|>


<commit_before>//! Special indicator values
use crate::Len;

/// Indicates `NULL` values.
pub const NULL_DATA: Len = -1;

/// Indicates that the size of the value is not known. ODBC returns this value in indicator buffers
/// for truncated values of unknown size.
pub const NO_TOTAL: Len = -4;

/// Use this as the indicator argument to `SQLBindParameter` in order to indicate that the data is
/// send at statement execution time.
pub const DATA_AT_EXEC: Len = -2;

/// Use result as the indicator argument to `SQLBindParameter` in order to indicate that the data is
/// send at statement execution time. In contrast to `DATA_AT_EXEC` the total size is passed to the
/// driver manager.
pub fn len_data_at_exec(length: Len) -> Len {
    const SQL_LEN_DATA_AT_EXEC_OFFSET: Len = -100;

    -(length) + SQL_LEN_DATA_AT_EXEC_OFFSET
}
<commit_msg>check for overflow in lon_data_at_exec<commit_after>//! Special indicator values
use crate::Len;

/// Indicates `NULL` values.
pub const NULL_DATA: Len = -1;

/// Indicates that the size of the value is not known. ODBC returns this value in indicator buffers
/// for truncated values of unknown size.
pub const NO_TOTAL: Len = -4;

/// Use this as the indicator argument to `SQLBindParameter` in order to indicate that the data is
/// send at statement execution time.
pub const DATA_AT_EXEC: Len = -2;

/// Use result as the indicator argument to `SQLBindParameter` in order to indicate that the data is
/// send at statement execution time. In contrast to `DATA_AT_EXEC` the total size is passed to the
/// driver manager.
pub fn len_data_at_exec(length: Len) -> Len {
    const SQL_LEN_DATA_AT_EXEC_OFFSET: Len = -100;

    (-length).checked_add(SQL_LEN_DATA_AT_EXEC_OFFSET).unwrap()
}
<|endoftext|>


<commit_before>//! Video RAM display

use sdl2;
use io::constants::*;
use cpu;
use cpu::*;

use sdl2::rect::Point;
use sdl2::rect::Rect;
use sdl2::pixels::*;

use io::graphics::Drawable;

pub struct VidRamBGDisplay {
    pub tile_data_select: TileDataSelect,
}

/// Display for backround screen buffer
impl Drawable for VidRamBGDisplay {
    fn get_initial_size(&self) -> (u32, u32) {
        (SCREEN_BUFFER_SIZE_X, SCREEN_BUFFER_SIZE_Y)
    }

    fn draw(&mut self, renderer: &mut sdl2::render::Renderer, cpu: &mut Cpu) {
        // TODO add toggle for this also?
        // FIXME pretty sure this is swapped, but for some reason works better
        let tile_map_offset = if cpu.lcdc_bg_tile_map() {
            TILE_MAP_2_START
        } else {
            TILE_MAP_1_START
        };

        let bg_select = &self.tile_data_select;

        let tile_patterns_offset = match *bg_select {
            TileDataSelect::Auto => {
                if cpu.lcdc_bg_win_tile_data() {
                    TILE_PATTERN_TABLE_1_ORIGIN
                } else {
                    TILE_PATTERN_TABLE_2_ORIGIN
                }
            }
            TileDataSelect::Mode1 => TILE_PATTERN_TABLE_1_ORIGIN,
            TileDataSelect::Mode2 => TILE_PATTERN_TABLE_2_ORIGIN,
        };

        draw_background_buffer(renderer, cpu, tile_map_offset, tile_patterns_offset, 0);
        draw_objects(renderer, cpu, cpu.scx() as i32, cpu.scy() as i32);
    }

    fn click(&mut self, _: sdl2::mouse::MouseButton, _: Point, _: &mut Cpu) {
        self.tile_data_select = match self.tile_data_select {
            TileDataSelect::Auto => TileDataSelect::Mode1,
            TileDataSelect::Mode1 => TileDataSelect::Mode2,
            TileDataSelect::Mode2 => TileDataSelect::Auto,
        };
        debug!("BG buffer tile data: {:?}", self.tile_data_select);
    }
}

pub struct VidRamTileDisplay {
    pub tile_data_select: TileDataSelect,
}

/// Display for tile data. Display tiles in `TILE_COLUMNS` with
/// `BORDER_PX` spacing.
impl Drawable for VidRamTileDisplay {
    fn get_initial_size(&self) -> (u32, u32) {
        let cell_size = TILE_SIZE_PX + BORDER_PX;
        let tile_num = TILE_PATTERN_TABLES_SIZE / TILE_SIZE_BYTES;
        ((TILE_COLUMNS * cell_size) as u32, ((tile_num / TILE_COLUMNS) * cell_size) as u32)
    }

    fn draw(&mut self, renderer: &mut sdl2::render::Renderer, cpu: &mut Cpu) {
        draw_tile_patterns(renderer, cpu);
    }

    fn click(&mut self, button: sdl2::mouse::MouseButton, position: Point, _: &mut Cpu) {
        debug!("Clicked tile display @ {:?} with {:?}", position, button);
    }
}

/// Draw single tile at given screen position
pub fn draw_tile(renderer: &mut sdl2::render::Renderer,
                 gameboy: &Cpu,
                 mem_offset: u16,
                 tile_idx: u16, // technically when used by GB it's only 8bit
                 screen_offset_x: i32,
                 screen_offset_y: i32) {
    #[inline]
    fn get_bit(n: u8, offset: u8) -> u8 {
        (n >> (7 - offset)) & 1u8
    }

    for px in 0..TILE_SIZE_PX {
        for py in 0..TILE_SIZE_PX {
            let col_byte_off = py * 2;
            let offset = mem_offset + (tile_idx * TILE_SIZE_BYTES);
            let col_byte1_v = gameboy.mem[(offset + col_byte_off) as usize];
            let col_byte2_v = gameboy.mem[(offset + col_byte_off + 1) as usize];
            let col_bit_1 = get_bit(col_byte1_v, px as u8);
            let col_bit_2 = get_bit(col_byte2_v, px as u8);
            let px_color = (col_bit_2 << 1) | col_bit_1;

            // let d = 255/4;
            // let px_val = px_color*d;
            // renderer.set_draw_color(Color::RGB(px_val, px_val, px_val));

            let px_pal_col = TILE_PALETTE[px_color as usize];
            renderer.set_draw_color(px_pal_col);

            let point = Point::new(screen_offset_x + px as i32, screen_offset_y + py as i32);
            match renderer.draw_point(point) {
                Ok(_) => (),
                Err(_) => error!("Could not draw point at {:?}", point),
            };
        }
    }
}

// TODO cache tiles into texture and use blending options (?) to make
// desired color "trasnparent".
/// Draw single tile at given screen position without drawing "0" color.
pub fn draw_tile_transparent(renderer: &mut sdl2::render::Renderer,
                             gameboy: &Cpu,
                             mem_offset: u16,
                             tile_idx: u16, // technically when used by GB it's only 8bit
                             screen_offset_x: i32,
                             screen_offset_y: i32) {

    #[inline]
    fn get_bit(n: u8, offset: u8) -> u8 {
        (n >> (7 - offset)) & 1u8
    }

    for px in 0..TILE_SIZE_PX {
        for py in 0..TILE_SIZE_PX {
            let col_byte_off = py * 2;
            let offset = mem_offset + (tile_idx * TILE_SIZE_BYTES);
            let col_byte1_v = gameboy.mem[(offset + col_byte_off) as usize];
            let col_byte2_v = gameboy.mem[(offset + col_byte_off + 1) as usize];
            let col_bit_1 = get_bit(col_byte1_v, px as u8);
            let col_bit_2 = get_bit(col_byte2_v, px as u8);
            let px_color = (col_bit_2 << 1) | col_bit_1;

            // let d = 255/4;
            // let px_val = px_color*d;
            // renderer.set_draw_color(Color::RGB(px_val, px_val, px_val));

            // TODO add toggle for this or remove it
            const DEBUG_OAM_BG: bool = false;

            if DEBUG_OAM_BG || px_color != 0 {
                let px_pal_col = OBJECT_PALETTE[px_color as usize];
                renderer.set_draw_color(px_pal_col);

                let point = Point::new((screen_offset_x as u8).wrapping_add(px as u8) as i32,
                                       (screen_offset_y as u8).wrapping_add(py as u8) as i32);
                renderer.draw_point(point).unwrap();
            }
        }
    }
}

/// This is the dumbest and straightforward code for displaying Tile
/// Patterns. It displays both background and sprite "tiles" as they
/// overlap in memory.
pub fn draw_tile_patterns(renderer: &mut sdl2::render::Renderer, gameboy: &Cpu) {

    for tile_idx in 0..(TILE_PATTERN_TABLES_SIZE / TILE_SIZE_BYTES) + 1 {

        let tile_start_x = (tile_idx % TILE_COLUMNS) * (TILE_SIZE_PX + BORDER_PX);
        let y_pos = tile_idx / TILE_COLUMNS;
        let tile_start_y = (TILE_SIZE_PX + BORDER_PX) * y_pos;

        draw_tile(renderer,
                  gameboy,
                  TILE_PATTERN_TABLE_1_START,
                  tile_idx,
                  tile_start_x as i32,
                  tile_start_y as i32);
    }
}

/// Draw whole background buffer (256x256 px)
pub fn draw_background_buffer(renderer: &mut sdl2::render::Renderer,
                              gameboy: &Cpu,
                              tile_map_offset: cpu::constants::MemAddr,
                              tile_patterns_offset: cpu::constants::MemAddr,
                              screen_offset_x: i32) {

    // TODO implement proper windows/widgets
    const TOP_Y: i32 = 1;
    let screen_offset_y = TOP_Y;

    // FIXME rethink how to do this better
    match tile_patterns_offset {
        TILE_PATTERN_TABLE_1_ORIGIN => {
            for tile in 0..(SCREEN_BUFFER_TILES_X * SCREEN_BUFFER_TILES_Y) {
                let tile_index = gameboy.mem[(tile_map_offset + tile as u16) as usize];

                let tile_x = tile % SCREEN_BUFFER_TILES_X;
                let tile_y = tile / SCREEN_BUFFER_TILES_Y;

                draw_tile(renderer,
                          gameboy,
                          TILE_PATTERN_TABLE_1_START,
                          tile_index as u16, // use index as unsigned 8bit
                          screen_offset_x + (tile_x * TILE_SIZE_PX as u32) as i32,
                          screen_offset_y + (tile_y * TILE_SIZE_PX as u32) as i32);

            }
        }
        TILE_PATTERN_TABLE_2_ORIGIN => {
            for tile in 0..(SCREEN_BUFFER_TILES_X * SCREEN_BUFFER_TILES_Y) {
                let tile_index = gameboy.mem[(tile_map_offset + tile as u16) as usize];

                let tile_x = tile % SCREEN_BUFFER_TILES_X;
                let tile_y = tile / SCREEN_BUFFER_TILES_Y;

                draw_tile(renderer,
                          gameboy,
                          TILE_PATTERN_TABLE_2_START, // reposition origin
                          add_u16_i8(128u16, (tile_index as i8)), // index is signed 8bit
                          screen_offset_x + (tile_x * TILE_SIZE_PX as u32) as i32,
                          screen_offset_y + (tile_y * TILE_SIZE_PX as u32) as i32);

            }

        }
        _ => panic!("Wrong tile data select"),
    };

    draw_screen_border(renderer, gameboy, screen_offset_x, TOP_Y);
}

/// Draw rectangle showing values of SCX and SCY registers,
/// i.e. visible screen area.
fn draw_screen_border(renderer: &mut sdl2::render::Renderer,
                      gameboy: &Cpu,
                      screen_offset_x: i32,
                      screen_offset_y: i32) {
    renderer.set_draw_color(Color::RGB(255, 255, 255));
    let scx: u8 = gameboy.scx();
    let scy: u8 = gameboy.scy();

    renderer.set_clip_rect(Some(Rect::new(screen_offset_x,
                                          screen_offset_y,
                                          SCREEN_BUFFER_SIZE_X,
                                          SCREEN_BUFFER_SIZE_Y)));
    // Draw 9 versions to do wrap around
    // FIXME is this inefficient/dumb and there is a better way? probably.
    for x in -1..2 {
        for y in -1..2 {
            let offset_x = screen_offset_x.wrapping_add(x * SCREEN_BUFFER_SIZE_X as i32);
            let offset_y = screen_offset_y.wrapping_add(y * SCREEN_BUFFER_SIZE_X as i32);
            renderer.draw_rect(Rect::new(offset_x + scx as i32 - 1,
                                         offset_y + scy as i32 - 1,
                                         GB_SCREEN_WIDTH as u32 + 2,
                                         GB_SCREEN_HEIGHT as u32 + 2))
                .unwrap();
        }
    }
    renderer.set_clip_rect(None);
}

/// Draw "sprites" (something gameboy calls "Objects").
pub fn draw_objects(renderer: &mut sdl2::render::Renderer,
                    gameboy: &Cpu,
                    screen_offset_x: i32,
                    screen_offset_y: i32) {

    // TODO sprites should use palletes
    // TODO sprites can have transparent color
    // TODO sprites are sorted by x/y/idx

    for obj_idx in 0..40 + 1 {
        let offset = OBJECT_ATTRIBUTE_START + obj_idx * OBJECT_ATTRIBUTE_BLOCK_SIZE;
        let sprite_y: u8 = gameboy.mem[offset as usize];
        let sprite_x: u8 = gameboy.mem[offset as usize + 1];
        let tile_index: u8 = gameboy.mem[offset as usize + 2];
        // TODO implement flag handling (priority, flips...)
        //let flags: u8 = gameboy.mem[offset as usize + 3];
        if sprite_x == 0 && sprite_y == 0 {
            // sprite is "hidden"
            continue;
        }
        let screen_x = sprite_x.wrapping_sub(8);
        let screen_y = sprite_y.wrapping_sub(16);

        // This table is fixed for OAM
        let pattern_table = TILE_PATTERN_TABLE_1_START;

        if gameboy.lcdc_sprite_size() {
            // "Tall 8x16 sprites" mode
            // FIXME Not sure this is how 8x16 sprites work
            let tile_16 = tile_index & !1;
            draw_tile_transparent(renderer,
                                  gameboy,
                                  pattern_table,
                                  tile_16 as u16,
                                  screen_offset_x + screen_x as i32,
                                  screen_offset_y + screen_y as i32);
            // Draw second sprite below the first one
            draw_tile_transparent(renderer,
                                  gameboy,
                                  pattern_table,
                                  tile_16 as u16 + 1,
                                  screen_offset_x + screen_x as i32,
                                  screen_offset_y + screen_y.wrapping_add(8) as i32);
        } else {
            // 8x8 sprites mode
            draw_tile_transparent(renderer,
                                  gameboy,
                                  pattern_table,
                                  tile_index as u16,
                                  screen_offset_x + screen_x as i32,
                                  screen_offset_y + screen_y as i32);

        }

    }

}
<commit_msg>Add proper sprite flipping<commit_after>//! Video RAM display

use sdl2;
use io::constants::*;
use cpu;
use cpu::*;

use sdl2::rect::Point;
use sdl2::rect::Rect;
use sdl2::pixels::*;

use io::graphics::Drawable;

pub struct VidRamBGDisplay {
    pub tile_data_select: TileDataSelect,
}

/// Display for backround screen buffer
impl Drawable for VidRamBGDisplay {
    fn get_initial_size(&self) -> (u32, u32) {
        (SCREEN_BUFFER_SIZE_X, SCREEN_BUFFER_SIZE_Y)
    }

    fn draw(&mut self, renderer: &mut sdl2::render::Renderer, cpu: &mut Cpu) {
        // TODO add toggle for this also?
        // FIXME pretty sure this is swapped, but for some reason works better
        let tile_map_offset = if cpu.lcdc_bg_tile_map() {
            TILE_MAP_2_START
        } else {
            TILE_MAP_1_START
        };

        let bg_select = &self.tile_data_select;

        let tile_patterns_offset = match *bg_select {
            TileDataSelect::Auto => {
                if cpu.lcdc_bg_win_tile_data() {
                    TILE_PATTERN_TABLE_1_ORIGIN
                } else {
                    TILE_PATTERN_TABLE_2_ORIGIN
                }
            }
            TileDataSelect::Mode1 => TILE_PATTERN_TABLE_1_ORIGIN,
            TileDataSelect::Mode2 => TILE_PATTERN_TABLE_2_ORIGIN,
        };

        draw_background_buffer(renderer, cpu, tile_map_offset, tile_patterns_offset, 0);
        draw_objects(renderer, cpu, cpu.scx() as i32, cpu.scy() as i32);
    }

    fn click(&mut self, _: sdl2::mouse::MouseButton, _: Point, _: &mut Cpu) {
        self.tile_data_select = match self.tile_data_select {
            TileDataSelect::Auto => TileDataSelect::Mode1,
            TileDataSelect::Mode1 => TileDataSelect::Mode2,
            TileDataSelect::Mode2 => TileDataSelect::Auto,
        };
        debug!("BG buffer tile data: {:?}", self.tile_data_select);
    }
}

pub struct VidRamTileDisplay {
    pub tile_data_select: TileDataSelect,
}

/// Display for tile data. Display tiles in `TILE_COLUMNS` with
/// `BORDER_PX` spacing.
impl Drawable for VidRamTileDisplay {
    fn get_initial_size(&self) -> (u32, u32) {
        let cell_size = TILE_SIZE_PX + BORDER_PX;
        let tile_num = TILE_PATTERN_TABLES_SIZE / TILE_SIZE_BYTES;
        ((TILE_COLUMNS * cell_size) as u32, ((tile_num / TILE_COLUMNS) * cell_size) as u32)
    }

    fn draw(&mut self, renderer: &mut sdl2::render::Renderer, cpu: &mut Cpu) {
        draw_tile_patterns(renderer, cpu);
    }

    fn click(&mut self, button: sdl2::mouse::MouseButton, position: Point, _: &mut Cpu) {
        debug!("Clicked tile display @ {:?} with {:?}", position, button);
    }
}

/// Draw single tile at given screen position
pub fn draw_tile(renderer: &mut sdl2::render::Renderer,
                 gameboy: &Cpu,
                 mem_offset: u16,
                 tile_idx: u16, // technically when used by GB it's only 8bit
                 screen_offset_x: i32,
                 screen_offset_y: i32) {
    #[inline]
    fn get_bit(n: u8, offset: u8) -> u8 {
        (n >> (7 - offset)) & 1u8
    }

    for px in 0..TILE_SIZE_PX {
        for py in 0..TILE_SIZE_PX {
            let col_byte_off = py * 2;
            let offset = mem_offset + (tile_idx * TILE_SIZE_BYTES);
            let col_byte1_v = gameboy.mem[(offset + col_byte_off) as usize];
            let col_byte2_v = gameboy.mem[(offset + col_byte_off + 1) as usize];
            let col_bit_1 = get_bit(col_byte1_v, px as u8);
            let col_bit_2 = get_bit(col_byte2_v, px as u8);
            let px_color = (col_bit_2 << 1) | col_bit_1;

            // let d = 255/4;
            // let px_val = px_color*d;
            // renderer.set_draw_color(Color::RGB(px_val, px_val, px_val));

            let px_pal_col = TILE_PALETTE[px_color as usize];
            renderer.set_draw_color(px_pal_col);

            let point = Point::new(screen_offset_x + px as i32, screen_offset_y + py as i32);
            match renderer.draw_point(point) {
                Ok(_) => (),
                Err(_) => error!("Could not draw point at {:?}", point),
            };
        }
    }
}

// TODO cache tiles into texture and use blending options (?) to make
// desired color "trasnparent".
/// Draw single tile at given screen position without drawing "0" color.
pub fn draw_tile_transparent(renderer: &mut sdl2::render::Renderer,
                             gameboy: &Cpu,
                             mem_offset: u16,
                             tile_idx: u16, // technically when used by GB it's only 8bit
                             screen_offset_x: i32,
                             screen_offset_y: i32,
                             flip_x: bool,
                             flip_y: bool) {

    #[inline]
    fn get_bit(n: u8, offset: u8) -> u8 {
        (n >> (7 - offset)) & 1u8
    }

    for px in 0..TILE_SIZE_PX {
        for py in 0..TILE_SIZE_PX {
            let col_byte_off = py * 2;
            let offset = mem_offset + (tile_idx * TILE_SIZE_BYTES);
            let col_byte1_v = gameboy.mem[(offset + col_byte_off) as usize];
            let col_byte2_v = gameboy.mem[(offset + col_byte_off + 1) as usize];
            let col_bit_1 = get_bit(col_byte1_v, px as u8);
            let col_bit_2 = get_bit(col_byte2_v, px as u8);
            let px_color = (col_bit_2 << 1) | col_bit_1;

            // let d = 255/4;
            // let px_val = px_color*d;
            // renderer.set_draw_color(Color::RGB(px_val, px_val, px_val));

            // TODO add toggle for this or remove it
            const DEBUG_OAM_BG: bool = false;

            let realpx = if flip_x { TILE_SIZE_PX - px } else { px } as u8;
            let realpy = if flip_y { TILE_SIZE_PX - py } else { py } as u8;

            if DEBUG_OAM_BG || px_color != 0 {
                let px_pal_col = OBJECT_PALETTE[px_color as usize];
                renderer.set_draw_color(px_pal_col);

                let point = Point::new((screen_offset_x as u8).wrapping_add(realpx) as i32,
                                       (screen_offset_y as u8).wrapping_add(realpy) as i32);
                renderer.draw_point(point).unwrap();
            }
        }
    }
}

/// This is the dumbest and straightforward code for displaying Tile
/// Patterns. It displays both background and sprite "tiles" as they
/// overlap in memory.
pub fn draw_tile_patterns(renderer: &mut sdl2::render::Renderer, gameboy: &Cpu) {

    for tile_idx in 0..(TILE_PATTERN_TABLES_SIZE / TILE_SIZE_BYTES) + 1 {

        let tile_start_x = (tile_idx % TILE_COLUMNS) * (TILE_SIZE_PX + BORDER_PX);
        let y_pos = tile_idx / TILE_COLUMNS;
        let tile_start_y = (TILE_SIZE_PX + BORDER_PX) * y_pos;

        draw_tile(renderer,
                  gameboy,
                  TILE_PATTERN_TABLE_1_START,
                  tile_idx,
                  tile_start_x as i32,
                  tile_start_y as i32);
    }
}

/// Draw whole background buffer (256x256 px)
pub fn draw_background_buffer(renderer: &mut sdl2::render::Renderer,
                              gameboy: &Cpu,
                              tile_map_offset: cpu::constants::MemAddr,
                              tile_patterns_offset: cpu::constants::MemAddr,
                              screen_offset_x: i32) {

    // TODO implement proper windows/widgets
    const TOP_Y: i32 = 1;
    let screen_offset_y = TOP_Y;

    // FIXME rethink how to do this better
    match tile_patterns_offset {
        TILE_PATTERN_TABLE_1_ORIGIN => {
            for tile in 0..(SCREEN_BUFFER_TILES_X * SCREEN_BUFFER_TILES_Y) {
                let tile_index = gameboy.mem[(tile_map_offset + tile as u16) as usize];

                let tile_x = tile % SCREEN_BUFFER_TILES_X;
                let tile_y = tile / SCREEN_BUFFER_TILES_Y;

                draw_tile(renderer,
                          gameboy,
                          TILE_PATTERN_TABLE_1_START,
                          tile_index as u16, // use index as unsigned 8bit
                          screen_offset_x + (tile_x * TILE_SIZE_PX as u32) as i32,
                          screen_offset_y + (tile_y * TILE_SIZE_PX as u32) as i32);

            }
        }
        TILE_PATTERN_TABLE_2_ORIGIN => {
            for tile in 0..(SCREEN_BUFFER_TILES_X * SCREEN_BUFFER_TILES_Y) {
                let tile_index = gameboy.mem[(tile_map_offset + tile as u16) as usize];

                let tile_x = tile % SCREEN_BUFFER_TILES_X;
                let tile_y = tile / SCREEN_BUFFER_TILES_Y;

                draw_tile(renderer,
                          gameboy,
                          TILE_PATTERN_TABLE_2_START, // reposition origin
                          add_u16_i8(128u16, (tile_index as i8)), // index is signed 8bit
                          screen_offset_x + (tile_x * TILE_SIZE_PX as u32) as i32,
                          screen_offset_y + (tile_y * TILE_SIZE_PX as u32) as i32);

            }

        }
        _ => panic!("Wrong tile data select"),
    };

    draw_screen_border(renderer, gameboy, screen_offset_x, TOP_Y);
}

/// Draw rectangle showing values of SCX and SCY registers,
/// i.e. visible screen area.
fn draw_screen_border(renderer: &mut sdl2::render::Renderer,
                      gameboy: &Cpu,
                      screen_offset_x: i32,
                      screen_offset_y: i32) {
    renderer.set_draw_color(Color::RGB(255, 255, 255));
    let scx: u8 = gameboy.scx();
    let scy: u8 = gameboy.scy();

    renderer.set_clip_rect(Some(Rect::new(screen_offset_x,
                                          screen_offset_y,
                                          SCREEN_BUFFER_SIZE_X,
                                          SCREEN_BUFFER_SIZE_Y)));
    // Draw 9 versions to do wrap around
    // FIXME is this inefficient/dumb and there is a better way? probably.
    for x in -1..2 {
        for y in -1..2 {
            let offset_x = screen_offset_x.wrapping_add(x * SCREEN_BUFFER_SIZE_X as i32);
            let offset_y = screen_offset_y.wrapping_add(y * SCREEN_BUFFER_SIZE_X as i32);
            renderer.draw_rect(Rect::new(offset_x + scx as i32 - 1,
                                         offset_y + scy as i32 - 1,
                                         GB_SCREEN_WIDTH as u32 + 2,
                                         GB_SCREEN_HEIGHT as u32 + 2))
                .unwrap();
        }
    }
    renderer.set_clip_rect(None);
}

/// Draw "sprites" (something gameboy calls "Objects").
pub fn draw_objects(renderer: &mut sdl2::render::Renderer,
                    gameboy: &Cpu,
                    screen_offset_x: i32,
                    screen_offset_y: i32) {

    // TODO sprites should use palletes
    // TODO sprites can have transparent color
    // TODO sprites are sorted by x/y/idx

    for obj_idx in 0..40 + 1 {
        let offset = OBJECT_ATTRIBUTE_START + obj_idx * OBJECT_ATTRIBUTE_BLOCK_SIZE;
        let sprite_y: u8 = gameboy.mem[offset as usize];
        let sprite_x: u8 = gameboy.mem[offset as usize + 1];
        let tile_index: u8 = gameboy.mem[offset as usize + 2];
        // TODO implement flag handling (priority, flips...)
        let flags: u8 = gameboy.mem[offset as usize + 3];
        let x_flip = ((flags >> 5) & 1) == 1;
        let y_flip = ((flags >> 6) & 1) == 1;

        if sprite_x == 0 && sprite_y == 0 {
            // sprite is "hidden"
            continue;
        }
        let screen_x = sprite_x.wrapping_sub(8);
        let screen_y = sprite_y.wrapping_sub(16);

        // This table is fixed for OAM
        let pattern_table = TILE_PATTERN_TABLE_1_START;

        if gameboy.lcdc_sprite_size() {
            // "Tall 8x16 sprites" mode
            // FIXME Not sure this is how 8x16 sprites work
            let tile_16 = tile_index & !1;
            draw_tile_transparent(renderer,
                                  gameboy,
                                  pattern_table,
                                  tile_16 as u16,
                                  screen_offset_x + screen_x as i32,
                                  screen_offset_y + screen_y as i32,
                                  x_flip,
                                  y_flip);
            // Draw second sprite below the first one
            draw_tile_transparent(renderer,
                                  gameboy,
                                  pattern_table,
                                  tile_16 as u16 + 1,
                                  screen_offset_x + screen_x as i32,
                                  screen_offset_y + screen_y.wrapping_add(8) as i32,
                                  x_flip,
                                  y_flip);
        } else {
            // 8x8 sprites mode
            draw_tile_transparent(renderer,
                                  gameboy,
                                  pattern_table,
                                  tile_index as u16,
                                  screen_offset_x + screen_x as i32,
                                  screen_offset_y + screen_y as i32,
                                  x_flip,
                                  y_flip);

        }

    }

}
<|endoftext|>