<commit_before>#![allow(dead_code)]

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::fmt::{Debug, Formatter, Result as FmtResult};

use rand::{thread_rng, Rng};
use sdl2::Sdl;
use sdl2::rect::Rect;
use ep::FromPrimitive;

use screen::Screen;
use instruction::{Opcodes, Instruction};

const FONT_SET: [u8; 80] = [
    0xf0, 0x90, 0x90, 0x90, 0xf0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xf0, 0x10, 0xf0, 0x80, 0xf0, // 2
    0xf0, 0x10, 0xf0, 0x10, 0xf0, // 3
    0x90, 0x90, 0xf0, 0x10, 0x10, // 4
    0xf0, 0x80, 0xf0, 0x10, 0xf0, // 5
    0xf0, 0x80, 0xf0, 0x90, 0xf0, // 6
    0xf0, 0x10, 0x20, 0x40, 0x40, // 7
    0xf0, 0x90, 0xf0, 0x90, 0xf0, // 8
    0xf0, 0x90, 0xf0, 0x10, 0xf0, // 9
    0xf0, 0x90, 0xf0, 0x90, 0x90, // A
    0xe0, 0x90, 0xe0, 0x90, 0xe0, // B
    0xf0, 0x80, 0x80, 0x80, 0x80, // C
    0xe0, 0x90, 0x90, 0x90, 0xe0, // D
    0xf0, 0x80, 0xf0, 0x80, 0xf0, // E
    0xf0, 0x80, 0xf0, 0x80, 0x80, // F
];

pub struct Chip8<'a> {
    regs:   [u8; 16],
    i:      u16,
    dt:     u8,
    st:     u8,
    pc:     usize,

    inst:   Instruction,
    jmp:    bool,

    keys:   [u8; 16],
    mem:    [u8; 4096],
    stack:  Vec<usize>,
    screen: Screen<'a>,
}

impl<'a> Debug for Chip8<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        self.regs[..].fmt(f)
    }
}

impl<'a> Chip8<'a> {
    pub fn new(sdl: &Sdl) -> Chip8<'a> {
        Chip8 {
            regs:   [0; 16],
            i:      0,
            dt:     0,
            st:     0,
            pc:     0x200,
            inst:   Instruction::new(),
            jmp:    false,
            keys:   [0; 16],
            mem:    [0; 4096],
            stack:  vec![],
            screen: Screen::new(sdl),
        }
    }

    pub fn load_rom(&mut self, path: &str) {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(Path::new(path)).unwrap();
        file.read_to_end(&mut rom).unwrap();
        for i in 0usize..rom.len() {
            self.mem[0x200 + i] = rom[i];
        }
        // TODO: move this
        for i in 0usize..FONT_SET.len() {
            self.mem[0x00 + i] = FONT_SET[i];
        }
    }

    pub fn run(&mut self) {
        let raw_data = (self.mem[self.pc], self.mem[self.pc +1]);
        self.inst.decode(raw_data);

        self.jmp  = false;

        println!("{:#x}: {:#x}", self.pc, self.inst.opcode);

        match Opcodes::from_u16(self.inst.opcode).unwrap() {
            Opcodes::CLS    => self.cls(),
            Opcodes::RET    => self.ret(),
            Opcodes::JMP    => self.jmp(),
            Opcodes::JMP_VA => self.jmp_va(),
            Opcodes::CALL   => self.call(),
            Opcodes::SE_VB  => self.se_vb(),
            Opcodes::SE_VV  => self.se_vv(),
            Opcodes::SNE_VB => self.sne_vb(),
            Opcodes::SNE_VV => self.sne_vv(),
            Opcodes::OR     => self.or(),
            Opcodes::ADD_VB => self.add_vb(),
            Opcodes::ADD_VV => self.add_vv(),
            Opcodes::ADD_IV => self.add_iv(),
            Opcodes::SUB    => self.sub(),
            Opcodes::XOR    => self.xor(),
            Opcodes::AND    => self.and(),
            Opcodes::LD_VB  => self.ld_vb(),
            Opcodes::LD_BV  => self.ld_bv(),
            Opcodes::LD_VV  => self.ld_vv(),
            Opcodes::LD_VI  => self.ld_vi(),
            Opcodes::LD_VK  => self.ld_vk(),
            Opcodes::LD_IV  => self.ld_iv(),
            Opcodes::LD_FV  => self.ld_fv(),
            Opcodes::LD_IA  => self.ld_ia(),
            Opcodes::LD_VDT => self.ld_vdt(),
            Opcodes::LD_DTV => self.ld_dtv(),
            Opcodes::LD_STV => self.ld_stv(),
            Opcodes::SKP    => self.skp(),
            Opcodes::SKNP   => self.sknp(),
            Opcodes::RND    => self.rnd(),
            Opcodes::SHR    => self.shr(),
            Opcodes::DRW    => self.drw(),
            _               => panic!("Unrecognized opcode: {:?}", self.inst.opcode),
        }

        if !self.jmp { self.inc_pc(); }

        if self.dt > 0 { self.dt -= 1; }
        if self.st > 0 { self.st -= 1; }
    }

    fn set_pc(&mut self, addr: u16) {
        self.pc = addr as usize;
    }

    fn inc_pc(&mut self) {
        self.pc += 2;
    }

    fn dec_pc(&mut self) {
        self.pc -= 2;
    }

    fn cls(&mut self) {
        self.screen.clear();
    }

    fn ret(&mut self) {
        let addr = self.stack.pop().unwrap();
        self.set_pc(addr as u16);
    }

    fn jmp(&mut self) {
        let addr = self.inst.nnn;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn jmp_va(&mut self) {
        let offset = self.regs[0] as u16;
        let addr = self.inst.nnn + offset;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn call(&mut self) {
        let old_addr = self.pc;
        let cur_addr = self.inst.nnn;
        self.stack.push(old_addr);
        self.set_pc(cur_addr);
        self.jmp = true;
    }

    fn se_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] == self.inst.kk {
            self.inc_pc();
        }
    }

    fn se_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] == self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn sne_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] != self.inst.kk {
            self.inc_pc();
        }
    }

    fn sne_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] != self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn or(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] |= self.regs[idx_y]
    }

    fn and(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] &= self.regs[idx_y];
    }

    fn add_vb(&mut self) {
        let idx_x = self.inst.x;

        // TODO: I guess this shouldn't be this way
        let res = self.regs[idx_x]  as u16 + self.inst.kk as u16;

        if res > 0xFF {
            self.regs[idx_x] = (res & 0xFF) as u8;
        } else {
            self.regs[idx_x] += self.inst.kk;
        }
    }

    fn add_vv(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x] as u16;
        let y = self.regs[self.inst.y] as u16;

        let res = x + y;
        if res > 0xFF {
            self.regs[15] = 1;
        } else {
            self.regs[15] = 0;
        }

        self.regs[idx_x] = res as u8;
    }

    fn add_iv(&mut self) {
        let idx = self.inst.x;
        let x   = self.regs[idx] as u16;
        self.regs[15] = if (self.i + x) > 0xFFF { 1 } else { 0 };
        self.i += x;
    }

    fn sub(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let x = self.regs[idx_x];
        let y = self.regs[idx_y];

        self.regs[15] = if x > y { 1 } else { 0 };
        self.regs[idx_x] -= y;
    }

    fn xor(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] ^= self.regs[idx_y];
    }

    fn shr(&mut self) {
        let idx_x = self.inst.x;
        let vx    = self.regs[idx_x];
        if vx & 0x01 == 0 {
            self.regs[15] = 1;
        }
        self.regs[idx_x] = vx >> 1;
    }

    fn ld_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] = self.regs[idx_y];
    }

    fn ld_vb(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.inst.kk;
    }

    fn ld_bv(&mut self) {
        let idx = self.inst.x;
        let mut vx  = self.regs[idx];
        let mut hundred = 100;

        for i in 0usize..3 {
            let bcd = vx / hundred;
            self.mem[self.i as usize + i] = bcd;
            vx -= bcd * hundred;
            hundred /= 10;
        }
    }

    fn ld_fv(&mut self) {
        let x = self.regs[self.inst.x];
        self.i = (x * 5) as u16;
    }

    fn ld_vi(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.regs[i] = self.mem[self.i as usize + i];
        }
    }

    fn ld_iv(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.mem[self.i as usize + i] = self.regs[i];
        }
    }

    fn ld_ia(&mut self) {
        self.i = self.inst.nnn;
    }

    fn ld_vk(&mut self) {
        let mut key_pressed = false;

        for i in 0..self.keys.len() {
            if self.keys[i] == 1 {
                self.regs[self.inst.x] = i as u8;
                key_pressed = true;
            }
        }

        if !key_pressed {
            self.dec_pc();
        }
    }

    fn ld_vdt(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.dt;
    }

    fn ld_dtv(&mut self) {
        let idx: usize = self.inst.x;
        self.dt = self.regs[idx];
    }

    fn ld_stv(&mut self) {
        let idx = self.inst.x;
        self.st = self.regs[idx];
    }

    fn rnd(&mut self) {
        let idx = self.inst.x;
        let byte = self.inst.kk;
        let n: u8 = thread_rng().gen_range(0,255);
        self.regs[idx] = n & byte;
    }

    fn drw(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let (x, y) = (self.regs[idx_x] as usize, self.regs[idx_y] as usize);
        let n = self.inst.n as usize;

        self.screen.renderer.clear();
        self.regs[15] = 0;

        for i in 0..n {
            let px = self.mem[(self.i + i as u16) as usize];
            for j in 0..8 {
                if px & (0x80 >> j) != 0 {
                    if self.screen.buffer[(x+j + (y+i) * 64) as usize] == 1 {
                        self.regs[15] = 1;
                    }
                    self.screen.buffer[(x+j + (y+i) * 64) as usize] ^= 1;
                }
            }
        }

        for i in 0usize..320 {
            for j in 0usize..640 {
                if self.screen.buffer[(j/10)+(i/10)*64] == 1 {
                    self.screen.renderer.fill_rect(
                        Rect::new(j as i32, i as i32, 1, 1)
                        );
                }
            }
        }

        self.screen.draw();
    }

    fn skp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 1{
            self.inc_pc();
        }
    }

    fn sknp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 0 {
            self.inc_pc();
        }
    }
    pub fn reset_keys(&mut self) {
        self.keys = [0;16];
    }

    pub fn press(&mut self, key: u8) {
        self.keys[key as usize] = 1;
    }
}
<commit_msg>fixed SUB instruction<commit_after>#![allow(dead_code)]

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::fmt::{Debug, Formatter, Result as FmtResult};

use rand::{thread_rng, Rng};
use sdl2::Sdl;
use sdl2::rect::Rect;
use ep::FromPrimitive;

use screen::Screen;
use instruction::{Opcodes, Instruction};

const FONT_SET: [u8; 80] = [
    0xf0, 0x90, 0x90, 0x90, 0xf0, // 0
    0x20, 0x60, 0x20, 0x20, 0x70, // 1
    0xf0, 0x10, 0xf0, 0x80, 0xf0, // 2
    0xf0, 0x10, 0xf0, 0x10, 0xf0, // 3
    0x90, 0x90, 0xf0, 0x10, 0x10, // 4
    0xf0, 0x80, 0xf0, 0x10, 0xf0, // 5
    0xf0, 0x80, 0xf0, 0x90, 0xf0, // 6
    0xf0, 0x10, 0x20, 0x40, 0x40, // 7
    0xf0, 0x90, 0xf0, 0x90, 0xf0, // 8
    0xf0, 0x90, 0xf0, 0x10, 0xf0, // 9
    0xf0, 0x90, 0xf0, 0x90, 0x90, // A
    0xe0, 0x90, 0xe0, 0x90, 0xe0, // B
    0xf0, 0x80, 0x80, 0x80, 0x80, // C
    0xe0, 0x90, 0x90, 0x90, 0xe0, // D
    0xf0, 0x80, 0xf0, 0x80, 0xf0, // E
    0xf0, 0x80, 0xf0, 0x80, 0x80, // F
];

pub struct Chip8<'a> {
    regs:   [u8; 16],
    i:      u16,
    dt:     u8,
    st:     u8,
    pc:     usize,

    inst:   Instruction,
    jmp:    bool,

    keys:   [u8; 16],
    mem:    [u8; 4096],
    stack:  Vec<usize>,
    screen: Screen<'a>,
}

impl<'a> Debug for Chip8<'a> {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        self.regs[..].fmt(f)
    }
}

impl<'a> Chip8<'a> {
    pub fn new(sdl: &Sdl) -> Chip8<'a> {
        Chip8 {
            regs:   [0; 16],
            i:      0,
            dt:     0,
            st:     0,
            pc:     0x200,
            inst:   Instruction::new(),
            jmp:    false,
            keys:   [0; 16],
            mem:    [0; 4096],
            stack:  vec![],
            screen: Screen::new(sdl),
        }
    }

    pub fn load_rom(&mut self, path: &str) {
        let mut rom: Vec<u8> = Vec::new();
        let mut file = File::open(Path::new(path)).unwrap();
        file.read_to_end(&mut rom).unwrap();
        for i in 0usize..rom.len() {
            self.mem[0x200 + i] = rom[i];
        }
        // TODO: move this
        for i in 0usize..FONT_SET.len() {
            self.mem[0x00 + i] = FONT_SET[i];
        }
    }

    pub fn run(&mut self) {
        let raw_data = (self.mem[self.pc], self.mem[self.pc +1]);
        self.inst.decode(raw_data);

        self.jmp  = false;

        println!("{:#x}: {:#x}", self.pc, self.inst.opcode);

        match Opcodes::from_u16(self.inst.opcode).unwrap() {
            Opcodes::CLS    => self.cls(),
            Opcodes::RET    => self.ret(),
            Opcodes::JMP    => self.jmp(),
            Opcodes::JMP_VA => self.jmp_va(),
            Opcodes::CALL   => self.call(),
            Opcodes::SE_VB  => self.se_vb(),
            Opcodes::SE_VV  => self.se_vv(),
            Opcodes::SNE_VB => self.sne_vb(),
            Opcodes::SNE_VV => self.sne_vv(),
            Opcodes::OR     => self.or(),
            Opcodes::ADD_VB => self.add_vb(),
            Opcodes::ADD_VV => self.add_vv(),
            Opcodes::ADD_IV => self.add_iv(),
            Opcodes::SUB    => self.sub(),
            Opcodes::XOR    => self.xor(),
            Opcodes::AND    => self.and(),
            Opcodes::LD_VB  => self.ld_vb(),
            Opcodes::LD_BV  => self.ld_bv(),
            Opcodes::LD_VV  => self.ld_vv(),
            Opcodes::LD_VI  => self.ld_vi(),
            Opcodes::LD_VK  => self.ld_vk(),
            Opcodes::LD_IV  => self.ld_iv(),
            Opcodes::LD_FV  => self.ld_fv(),
            Opcodes::LD_IA  => self.ld_ia(),
            Opcodes::LD_VDT => self.ld_vdt(),
            Opcodes::LD_DTV => self.ld_dtv(),
            Opcodes::LD_STV => self.ld_stv(),
            Opcodes::SKP    => self.skp(),
            Opcodes::SKNP   => self.sknp(),
            Opcodes::RND    => self.rnd(),
            Opcodes::SHR    => self.shr(),
            Opcodes::DRW    => self.drw(),
            _               => panic!("Unrecognized opcode: {:?}", self.inst.opcode),
        }

        if !self.jmp { self.inc_pc(); }

        if self.dt > 0 { self.dt -= 1; }
        if self.st > 0 { self.st -= 1; }
    }

    fn set_pc(&mut self, addr: u16) {
        self.pc = addr as usize;
    }

    fn inc_pc(&mut self) {
        self.pc += 2;
    }

    fn dec_pc(&mut self) {
        self.pc -= 2;
    }

    fn cls(&mut self) {
        self.screen.clear();
    }

    fn ret(&mut self) {
        let addr = self.stack.pop().unwrap();
        self.set_pc(addr as u16);
    }

    fn jmp(&mut self) {
        let addr = self.inst.nnn;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn jmp_va(&mut self) {
        let offset = self.regs[0] as u16;
        let addr = self.inst.nnn + offset;
        self.set_pc(addr);
        self.jmp = true;
    }

    fn call(&mut self) {
        let old_addr = self.pc;
        let cur_addr = self.inst.nnn;
        self.stack.push(old_addr);
        self.set_pc(cur_addr);
        self.jmp = true;
    }

    fn se_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] == self.inst.kk {
            self.inc_pc();
        }
    }

    fn se_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] == self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn sne_vb(&mut self) {
        let idx = self.inst.x;
        if self.regs[idx] != self.inst.kk {
            self.inc_pc();
        }
    }

    fn sne_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        if self.regs[idx_x] != self.regs[idx_y] {
            self.inc_pc();
        }
    }

    fn or(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] |= self.regs[idx_y]
    }

    fn and(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] &= self.regs[idx_y];
    }

    fn add_vb(&mut self) {
        let idx_x = self.inst.x;

        // TODO: I guess this shouldn't be this way
        let res = self.regs[idx_x]  as u16 + self.inst.kk as u16;

        if res > 0xFF {
            self.regs[idx_x] = (res & 0xFF) as u8;
        } else {
            self.regs[idx_x] += self.inst.kk;
        }
    }

    fn add_vv(&mut self) {
        let idx_x = self.inst.x;
        let x = self.regs[idx_x] as u16;
        let y = self.regs[self.inst.y] as u16;

        let res = x + y;
        if res > 0xFF {
            self.regs[15] = 1;
        } else {
            self.regs[15] = 0;
        }

        self.regs[idx_x] = res as u8;
    }

    fn add_iv(&mut self) {
        let idx = self.inst.x;
        let x   = self.regs[idx] as u16;
        self.regs[15] = if (self.i + x) > 0xFFF { 1 } else { 0 };
        self.i += x;
    }

    fn sub(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let x = self.regs[idx_x];
        let y = self.regs[idx_y];

        self.regs[15] = if x > y { 1 } else { 0 };

        if x <= y { self.regs[idx_x] = 0; }
        else { self.regs[idx_x] -= y; }
    }

    fn xor(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] ^= self.regs[idx_y];
    }

    fn shr(&mut self) {
        let idx_x = self.inst.x;
        let vx    = self.regs[idx_x];
        if vx & 0x01 == 0 {
            self.regs[15] = 1;
        }
        self.regs[idx_x] = vx >> 1;
    }

    fn ld_vv(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        self.regs[idx_x] = self.regs[idx_y];
    }

    fn ld_vb(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.inst.kk;
    }

    fn ld_bv(&mut self) {
        let idx = self.inst.x;
        let mut vx  = self.regs[idx];
        let mut hundred = 100;

        for i in 0usize..3 {
            let bcd = vx / hundred;
            self.mem[self.i as usize + i] = bcd;
            vx -= bcd * hundred;
            hundred /= 10;
        }
    }

    fn ld_fv(&mut self) {
        let x = self.regs[self.inst.x];
        self.i = (x * 5) as u16;
    }

    fn ld_vi(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.regs[i] = self.mem[self.i as usize + i];
        }
    }

    fn ld_iv(&mut self) {
        let x = self.inst.x as usize;

        for i in 0usize..x {
            self.mem[self.i as usize + i] = self.regs[i];
        }
    }

    fn ld_ia(&mut self) {
        self.i = self.inst.nnn;
    }

    fn ld_vk(&mut self) {
        let mut key_pressed = false;

        for i in 0..self.keys.len() {
            if self.keys[i] == 1 {
                self.regs[self.inst.x] = i as u8;
                key_pressed = true;
            }
        }

        if !key_pressed {
            self.dec_pc();
        }
    }

    fn ld_vdt(&mut self) {
        let idx = self.inst.x;
        self.regs[idx] = self.dt;
    }

    fn ld_dtv(&mut self) {
        let idx: usize = self.inst.x;
        self.dt = self.regs[idx];
    }

    fn ld_stv(&mut self) {
        let idx = self.inst.x;
        self.st = self.regs[idx];
    }

    fn rnd(&mut self) {
        let idx = self.inst.x;
        let byte = self.inst.kk;
        let n: u8 = thread_rng().gen_range(0,255);
        self.regs[idx] = n & byte;
    }

    fn drw(&mut self) {
        let idx_x = self.inst.x;
        let idx_y = self.inst.y;
        let (x, y) = (self.regs[idx_x] as usize, self.regs[idx_y] as usize);
        let n = self.inst.n as usize;

        self.screen.renderer.clear();
        self.regs[15] = 0;

        for i in 0..n {
            let px = self.mem[(self.i + i as u16) as usize];
            for j in 0..8 {
                if px & (0x80 >> j) != 0 {
                    if self.screen.buffer[(x+j + (y+i) * 64) as usize] == 1 {
                        self.regs[15] = 1;
                    }
                    self.screen.buffer[(x+j + (y+i) * 64) as usize] ^= 1;
                }
            }
        }

        for i in 0usize..320 {
            for j in 0usize..640 {
                if self.screen.buffer[(j/10)+(i/10)*64] == 1 {
                    self.screen.renderer.fill_rect(
                        Rect::new(j as i32, i as i32, 1, 1)
                        );
                }
            }
        }

        self.screen.draw();
    }

    fn skp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 1{
            self.inc_pc();
        }
    }

    fn sknp(&mut self) {
        let x = self.regs[self.inst.x];
        if self.keys[x as usize] == 0 {
            self.inc_pc();
        }
    }
    pub fn reset_keys(&mut self) {
        self.keys = [0;16];
    }

    pub fn press(&mut self, key: u8) {
        self.keys[key as usize] = 1;
    }
}
<|endoftext|>


<commit_before>//! Tools for cleaning up subtitle files and getting them into some
//! kind of normalized format.

use regex::Regex;
use srt::{Subtitle,SubtitleFile};

// Used to remove the following common sorts of closed-caption clutter:
//
//     SPEAKER:
//     ( sound effect )
//     ♪ music ♪
static CLUTTER: Regex = regex!(r"(\([^)]*\)|♪[^♪]*♪|[A-Z]{2,}:)");

// Used to compress and normalize consecutive whitespace.
static WHITESPACE: Regex = regex!(r"\s+");

// Clean up a single subtitle line.
fn clean_line(line: &str) -> String {
    WHITESPACE.replace_all(CLUTTER.replace_all(line, "").as_slice(), " ")
        .trim().to_string()
}

// Clean up a subtitle, or discard it if it looks useless.
fn clean_subtitle(sub: &Subtitle) -> Option<Subtitle> {
    if sub.end <= sub.begin { return None; }
    let lines: Vec<String> = sub.lines.iter()
        .map(|l| clean_line(l.as_slice()))
        .filter(|l| l.len() > 0)
        .map(|l| l.to_string()).collect();
    if lines.len() == 0 { return None; }
    Some(Subtitle{index: sub.index, begin: sub.begin, end: sub.end,
                  lines: lines})
}

/// Clean up various issues with subtitle files, including:
///
/// * Out of order subtitles.
/// * Overlapping subtitles.
/// * Sound effects.
/// * Music symbols.
pub fn clean_subtitle_file(file: &SubtitleFile) -> SubtitleFile {
    // Clean individual subtitles and sort.
    let mut subs: Vec<Subtitle> =
        file.subtitles.iter().filter_map(clean_subtitle).collect();
    subs.sort_by(|a, b| { a.begin.partial_cmp(&b.begin).unwrap() });

    // Fix overlaps.
    if subs.len() >= 2 {
        for i in range(0, subs.len()-1) {
            if subs[i].end > subs[i+1].begin {
                subs[i].end = subs[i+1].begin - 0.001;
            }
        }
    }

    // Renumber and return.
    for (i, ref mut sub) in subs.iter_mut().enumerate() {
        sub.index = i+1;
    }
    SubtitleFile{subtitles: subs}
}

#[test]
fn test_clean_subtitle_file() {
    let dirty = SubtitleFile::from_str(r"19
00:01:03,163 --> 00:01:04,664
They've arrived.
( door slams )

20
00:01:07,700 --> 00:01:10,736
( cheering )

21
00:01:12,839 --> 00:01:13,840
♪ ♪

18
00:01:02,328 --> 00:01:03,162
JOE: Hey! ( waves arms )

51
00:02:35,636 --> 00:02:32,895
Negative length.

53
00:02:47,965 --> 00:02:50,684
Out of order.

52
00:02:42,658 --> 00:02:48,865
Overlapping.
").unwrap();

    let cleaned = "\uFEFF1
00:01:02,328 --> 00:01:03,162
Hey!

2
00:01:03,163 --> 00:01:04,664
They've arrived.

3
00:02:42,658 --> 00:02:47,964
Overlapping.

4
00:02:47,965 --> 00:02:50,684
Out of order.
";

    assert_eq!(cleaned, clean_subtitle_file(&dirty).to_string().as_slice());
}
<commit_msg>Allow space between speaker name and colon<commit_after>//! Tools for cleaning up subtitle files and getting them into some
//! kind of normalized format.

use regex::Regex;
use srt::{Subtitle,SubtitleFile};

// Used to remove the following common sorts of closed-caption clutter:
//
//     SPEAKER:
//     ( sound effect )
//     ♪ music ♪
static CLUTTER: Regex = regex!(r"(\([^)]*\)|♪[^♪]*♪|[A-Z]{2,} ?:)");

// Used to compress and normalize consecutive whitespace.
static WHITESPACE: Regex = regex!(r"\s+");

// Clean up a single subtitle line.
fn clean_line(line: &str) -> String {
    WHITESPACE.replace_all(CLUTTER.replace_all(line, "").as_slice(), " ")
        .trim().to_string()
}

// Clean up a subtitle, or discard it if it looks useless.
fn clean_subtitle(sub: &Subtitle) -> Option<Subtitle> {
    if sub.end <= sub.begin { return None; }
    let lines: Vec<String> = sub.lines.iter()
        .map(|l| clean_line(l.as_slice()))
        .filter(|l| l.len() > 0)
        .map(|l| l.to_string()).collect();
    if lines.len() == 0 { return None; }
    Some(Subtitle{index: sub.index, begin: sub.begin, end: sub.end,
                  lines: lines})
}

/// Clean up various issues with subtitle files, including:
///
/// * Out of order subtitles.
/// * Overlapping subtitles.
/// * Sound effects.
/// * Music symbols.
pub fn clean_subtitle_file(file: &SubtitleFile) -> SubtitleFile {
    // Clean individual subtitles and sort.
    let mut subs: Vec<Subtitle> =
        file.subtitles.iter().filter_map(clean_subtitle).collect();
    subs.sort_by(|a, b| { a.begin.partial_cmp(&b.begin).unwrap() });

    // Fix overlaps.
    if subs.len() >= 2 {
        for i in range(0, subs.len()-1) {
            if subs[i].end > subs[i+1].begin {
                subs[i].end = subs[i+1].begin - 0.001;
            }
        }
    }

    // Renumber and return.
    for (i, ref mut sub) in subs.iter_mut().enumerate() {
        sub.index = i+1;
    }
    SubtitleFile{subtitles: subs}
}

#[test]
fn test_clean_subtitle_file() {
    let dirty = SubtitleFile::from_str(r"19
00:01:03,163 --> 00:01:04,664
They've arrived.
( door slams )

20
00:01:07,700 --> 00:01:10,736
( cheering )

21
00:01:12,839 --> 00:01:13,840
♪ ♪

18
00:01:02,328 --> 00:01:03,162
JOE: Hey! ( waves arms )

51
00:02:35,636 --> 00:02:32,895
Negative length.

53
00:02:47,965 --> 00:02:50,684
Out of order.

52
00:02:42,658 --> 00:02:48,865
Overlapping.
").unwrap();

    let cleaned = "\uFEFF1
00:01:02,328 --> 00:01:03,162
Hey!

2
00:01:03,163 --> 00:01:04,664
They've arrived.

3
00:02:42,658 --> 00:02:47,964
Overlapping.

4
00:02:47,965 --> 00:02:50,684
Out of order.
";

    assert_eq!(cleaned, clean_subtitle_file(&dirty).to_string().as_slice());
}
<|endoftext|>


<commit_before>use std::rc::{self, Rc};
use std::sync::{self, Arc};

pub trait Downgrade {
    type Target;

    fn downgrade(&self) -> Self::Target;
}

impl<T> Downgrade for Arc<T> {
    type Target = sync::Weak<T>;

    fn downgrade(&self) -> Self::Target {
        Arc::downgrade(self)
    }
}

impl<T> Downgrade for Rc<T> {
    type Target = rc::Weak<T>;

    fn downgrade(&self) -> Self::Target {
        Rc::downgrade(self)
    }
}

pub trait Upgrade {
    type Target;

    fn upgrade(&self) -> Option<Self::Target>;
}

impl<T> Upgrade for sync::Weak<T> {
    type Target = Arc<T>;

    fn upgrade(&self) -> Option<Self::Target> {
        self.upgrade()
    }
}

impl<T> Upgrade for rc::Weak<T> {
    type Target = Rc<T>;

    fn upgrade(&self) -> Option<Self::Target> {
        self.upgrade()
    }
}

#[macro_export]
macro_rules! to_type_before {
    (_) => ();
    ($variable:ident) => (
        let $variable = $variable.clone();
    );
    (@weak $variable:ident) => (
        let $variable = $crate::clone::Downgrade::downgrade(&$variable);
    );
}

#[macro_export]
macro_rules! to_type_after {
    (_) => ();
    ($variable:ident) => ();
    (@weak $variable:ident) => (
        let $variable = match $crate::clone::Upgrade::upgrade(&$variable) {
            Some(val) => val,
            None => panic!("cannot upgrade weak reference `{}`", stringify!($n)),
        };
    );
}

#[macro_export]
macro_rules! clone {
    ($($(@ $weak:ident)? $variables:ident),+ => move | $($pattern:pat),* | $body:block )=> (
        {
            $( $crate::to_type_before!($(@ $weak)? $variables) )*;
            move |$($pattern)*| {
                $( $crate::to_type_after!($(@ $weak)? $variables ))*;
                $body
            }
        }
    );
}
<commit_msg>Fix clone macro<commit_after>use std::rc::{self, Rc};
use std::sync::{self, Arc};

pub trait Downgrade {
    type Target;

    fn downgrade(&self) -> Self::Target;
}

impl<T> Downgrade for Arc<T> {
    type Target = sync::Weak<T>;

    fn downgrade(&self) -> Self::Target {
        Arc::downgrade(self)
    }
}

impl<T> Downgrade for Rc<T> {
    type Target = rc::Weak<T>;

    fn downgrade(&self) -> Self::Target {
        Rc::downgrade(self)
    }
}

pub trait Upgrade {
    type Target;

    fn upgrade(&self) -> Option<Self::Target>;
}

impl<T> Upgrade for sync::Weak<T> {
    type Target = Arc<T>;

    fn upgrade(&self) -> Option<Self::Target> {
        self.upgrade()
    }
}

impl<T> Upgrade for rc::Weak<T> {
    type Target = Rc<T>;

    fn upgrade(&self) -> Option<Self::Target> {
        self.upgrade()
    }
}

#[macro_export]
macro_rules! to_type_before {
    (_) => ();
    ($variable:ident) => (
        let $variable = $variable.clone();
    );
    (@weak $variable:ident) => (
        let $variable = $crate::clone::Downgrade::downgrade(&$variable);
    );
}

#[macro_export]
macro_rules! to_type_after {
    (_) => ();
    ($variable:ident) => ();
    (@weak $variable:ident) => (
        let $variable = match $crate::clone::Upgrade::upgrade(&$variable) {
            Some(val) => val,
            None => panic!("cannot upgrade weak reference `{}`", stringify!($n)),
        };
    );
}

#[macro_export]
macro_rules! clone {
    ($($(@ $weak:ident)? $variables:ident),+ => move | $($pattern:pat),* | $body:block )=> (
        {
            $( $crate::to_type_before!($(@ $weak)? $variables); )*
            move |$($pattern)*| {
                $( $crate::to_type_after!($(@ $weak)? $variables );)*
                $body
            }
        }
    );
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;

pub fn single_night(file: &str) -> i64 {
    let input = File::open(file).expect("File open fail.");
    let reader = BufReader::new(input);

    let mut nodes = Vec::new();
    let mut edges = Vec::new();
    for line in reader.lines() {
        let line = line.unwrap();
        // println!("{}", s);

        let words: Vec<&str> = line.split_whitespace().collect();
        let from = words[0];
        let to = words[2];
        let distance = words[4].parse::<i64>().expect("parse error");

        nodes.push(Node::new(from, i64::max_value()));
        nodes.push(Node::new(to, i64::max_value()));
        edges.push(Edge::new(from, to, distance));
        edges.push(Edge::new(to, from, distance)); // bi-directed
    }
    // remove duplicate nodes
    nodes.sort_by(|a, b| a.name.cmp(&b.name));
    nodes.dedup();

    println!("nodes");
    for node in nodes.clone() {
        println!("{:?}", node);
    }

    let node_list = nodes.clone();
    let mut results = Vec::new();
    for n in node_list {
        // make n node source
        let mut nodes = nodes.clone();
        if let Ok(n_index) = nodes.binary_search(&n) {
            let mut node = nodes.get_mut(n_index).unwrap();
            *node = Node::new(n.name, 0);
        }
        println!("calculating next...");
        results.push(dijkstra(nodes, edges.clone()));
    }

    println!("results");
    for result in results.clone() {
        println!("{}", result);
    }
    results.iter().cloned().min().unwrap()
}

fn dijkstra(mut nodes: Vec<Node>, edges: Vec<Edge>) -> i64 {
    let mut out: Vec<Node> = Vec::new();
    loop {
        if nodes.is_empty() {
            break;
        }
        println!("\nsort nodes");
        nodes.sort_by(|a, b| b.distance.cmp(&a.distance));

        let node = nodes.pop().unwrap();
        println!("pop min {:?}", node);

        nodes.sort_by(|a, b| a.name.cmp(&b.name));

        // for each neighbor of n
        for edge in edges.clone().iter() {
            let Edge { ref a, ref b, ref len } = *edge;
            if a == &node.name {
                if let Ok(neighbor_index) = nodes.binary_search_by(|n| n.name.cmp(&b)) {
                    println!("edge {:?} {:?} {:?}", a, b, len);
                    let mut neighbor = nodes.get_mut(neighbor_index).unwrap();
                    println!("neighbor {:?}", &neighbor);
                    let alt = node.distance + *len;
                    // assign new weight to neighbor
                    if alt < neighbor.distance {
                        println!("{:?} <- {:?}", neighbor.name, alt);
                        // *neighbor = Node::new(b, alt);
                    } else {
                        println!("{:?} - {:?}", neighbor.name, neighbor.distance);
                    }
                }
            }
        }
        out.push(node.clone());
    }
    print!("Out: ");
    for node in out.clone() {
        print!("{:?},", node);
    }
    out.iter().fold(0, |acc, ref n| acc + n.distance)
}

#[derive(Debug, Eq, Ord, PartialOrd)]
struct Node {
    name: String,
    distance: i64,
}

#[derive(Debug)]
struct Edge {
    a: String,
    b: String,
    len: i64,
}

impl Node {
    fn new<S>(name: S, distance: i64) -> Self
        where S: Into<String>
    {
        Node {
            name: name.into(),
            distance: distance,
        }
    }
}

impl Edge {
    fn new<S>(a: S, b: S, len: i64) -> Self
        where S: Into<String>
    {
        Edge {
            a: a.into(),
            b: b.into(),
            len: len,
        }
    }
}

impl PartialEq for Node {
    fn eq(&self, other: &Node) -> bool {
        self.name.eq(&other.name)
    }
    fn ne(&self, other: &Node) -> bool {
        !self.name.eq(&other.name)
    }
}

impl Clone for Node {
    fn clone(&self) -> Self {
        Node {
            name: self.name.clone(),
            distance: self.distance,
        }
    }
}

impl Clone for Edge {
    fn clone(&self) -> Self {
        Edge {
            a: self.a.clone(),
            b: self.b.clone(),
            len: self.len,
        }
    }
}
<commit_msg>Try new ideas with dijkstra's.<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::collections::HashMap;

pub fn single_night(file: &str) -> i64 {
    let input = File::open(file).expect("File open fail.");
    let reader = BufReader::new(input);

    let edge_cmds = reader.lines()
        .filter_map(Result::ok)
        .map(|line| {
            let words = line.split_whitespace().collect::<Vec<&str>>();
            let from = words[0].to_owned();
            let to = words[2].to_owned();
            let distance = words[4].parse::<i64>().expect("parse error");

            (from, to, distance)
        })
    .collect::<Vec<(String, String, i64)>>();
    println!("{:?}", edge_cmds);

    let mut nodes = Vec::new();
    for &(ref from, ref to, _) in edge_cmds.iter() {
        nodes.push(from);
        nodes.push(to);
    }
    nodes.sort();
    nodes.dedup();
    println!("{:?}", nodes);

    let mut edge_distances = HashMap::new();
    let mut edges = HashMap::new();
    for &(ref from, ref to, ref distance) in edge_cmds.iter() {
        if let Ok(from_idx) = nodes.binary_search(&&from) {
            if let Ok(to_idx) = nodes.binary_search(&&to) {
                println!("{} <-> {}", from_idx, to_idx);
                {
                    edge_distances.insert((from_idx, to_idx), *distance);
                    let mut neighbors = edges.entry(from_idx).or_insert(Vec::new());
                    neighbors.push(to_idx);
                }
                {
                    // bi-directional
                    edge_distances.insert((to_idx, from_idx), *distance);
                    let mut neighbors = edges.entry(to_idx).or_insert(Vec::new());
                    neighbors.push(from_idx);
                }
            }
        }
    }
    println!("{:?}", edge_distances);
    println!("{:?}", edges);

    //let node_list = nodes.clone();
    //let mut results = Vec::new();
    //for n in node_list {
    //    // make n node source
    //    let mut nodes = nodes.clone();
    //    if let Ok(n_index) = nodes.binary_search(&n) {
    //        let mut node = nodes.get_mut(n_index).unwrap();
    //        *node = Node::new(n.name, 0);
    //    }
    //    println!("calculating next...");
    //    results.push(dijkstra(nodes, edge_distances.clone()));
    //}

    //println!("results");
    //for result in results.clone() {
    //    println!("{}", result);
    //}
    //results.iter().cloned().min().unwrap()
    dijkstra(nodes, edges, edge_distances, 0)
}

fn dijkstra(
    nodes: Vec<&String>,
    edges: HashMap<usize, Vec<usize>>,
    edge_distances: HashMap<(usize, usize), i64>,
    source: usize) -> i64 {

    let mut q = nodes.iter().enumerate().map(|en| { let (i, _) = en; i }).collect::<Vec<usize>>();
    let mut dist = vec![i64::max_value();nodes.len()];
    let mut prev = Vec::new();
    dist[source] = 0;
    println!("{:?}", q);
    println!("{:?}", dist);
//    let mut out: Vec<Node> = Vec::new();
    loop {
        if q.is_empty() {
            break;
        }
//        println!("\nsort nodes");
//        nodes.sort_by(|a, b| b.distance.cmp(&a.distance));
//
        if let Some(min) = edge_distances.iter().map(|ed| {
            ed
        }).min() {
            let node_idx = q.remove(min).unwrap();

            if let Some(neighbors) = edges.get(&node_idx) {
                for neighbor in neighbors {
                    let edge_key = (node_idx, *neighbor);
                    if let Some(distance) = edge_distances.get(&edge_key) {
                        let alt = dist[node_idx] + distance;
                        if alt < dist[*neighbor] {
                            dist[*neighbor] = alt;
                            //prev[neighbor] = node_idx;
                            prev.push(node_idx);
                        }
                    }
                }
            }
        }
//        println!("pop min {:?}", node);
//
//        nodes.sort_by(|a, b| a.name.cmp(&b.name));
//
//        // for each neighbor of n
//        for edge in edge_distances.clone().iter() {
//            let Edge { ref a, ref b, ref len } = *edge;
//            if a == &node.name {
//                if let Ok(neighbor_index) = nodes.binary_search_by(|n| n.name.cmp(&b)) {
//                    println!("edge {:?} {:?} {:?}", a, b, len);
//                    let mut neighbor = nodes.get_mut(neighbor_index).unwrap();
//                    println!("neighbor {:?}", &neighbor);
//                    let alt = node.distance + *len;
//                    // assign new weight to neighbor
//                    if alt < neighbor.distance {
//                        println!("{:?} <- {:?}", neighbor.name, alt);
//                        // *neighbor = Node::new(b, alt);
//                    } else {
//                        println!("{:?} - {:?}", neighbor.name, neighbor.distance);
//                    }
//                }
//            }
//        }
//        out.push(node.clone());
    }
    println!("distances: {:?},", dist);
    println!("path: {:?},", prev);
//    out.iter().fold(0, |acc, ref n| acc + n.distance)
    42
}

#[derive(Debug)]
struct Edge {
    from: usize,
    to: usize,
    length: i64,
}
<|endoftext|>


<commit_before>//! C API extensions to experiment with eager execution of kernels.
//!
//! WARNING: The underlying C-API for the eager execution is not guaranteed to be
//! stable and can be changed without notice, which could result in breaking.

mod context;
pub use context::*;

mod tensor_handle;
pub use tensor_handle::*;

mod op;

pub use op::raw_ops;

use crate::{Result, Tensor, TensorType};

#[cfg(feature = "ndarray")]
use ndarray::{ArrayBase, Data, Dimension};

/// A helper trait to convert a Tensor or some other types into a TensorHandle
/// for use in eager execution.
pub trait ToTensorHandle<'a> {
    /// Convert a Tensor or values into a new TensorHandle.
    ///
    /// _Warning_ : This function may create multiple handles to the same
    /// underlying tensor. Users should be careful not to modify the tensor
    /// after converting it to a TensorHandle. Also, users should be careful
    /// not to modify the Tensor generated from the TensorHandle's `resolve`
    /// method.
    fn to_handle(&self, ctx: &'a Context) -> Result<TensorHandle<'a>>;
}

impl<'a, T> ToTensorHandle<'a> for Tensor<T>
where
    T: TensorType,
{
    fn to_handle(&self, ctx: &'a Context) -> Result<TensorHandle<'a>> {
        TensorHandle::new(ctx, self)
    }
}

impl<'a> ToTensorHandle<'a> for TensorHandle<'a> {
    fn to_handle(&self, _: &'a Context) -> Result<TensorHandle<'a>> {
        self.copy_sharing_tensor()
    }
}

impl<'a, T: TensorType> ToTensorHandle<'a> for T {
    fn to_handle(&self, ctx: &'a Context) -> Result<TensorHandle<'a>> {
        let mut tensor = Tensor::<T>::new(&[]);
        tensor[0] = self.clone();
        TensorHandle::new(ctx, &tensor)
    }
}

impl<'a, T: TensorType> ToTensorHandle<'a> for [T] {
    fn to_handle(&self, ctx: &'a Context) -> Result<TensorHandle<'a>> {
        let mut tensor = Tensor::<T>::new(&[self.len() as u64]);
        for (e, v) in tensor.iter_mut().zip(self) {
            e.clone_from(v);
        }
        TensorHandle::new(ctx, &tensor)
    }
}

impl<'a, T: TensorType, const N: usize> ToTensorHandle<'a> for [T; N] {
    fn to_handle(&self, ctx: &'a Context) -> Result<TensorHandle<'a>> {
        let tensor = Tensor::from(&self[..]);
        TensorHandle::new(ctx, &tensor)
    }
}

#[cfg(feature = "ndarray")]
/// Convert any ndarray::ArrayBase type into a TensorHandle
impl<'a, T, S, D> ToTensorHandle<'a> for ArrayBase<S, D>
where
    T: TensorType,
    S: Data<Elem = T>,
    D: Dimension,
{
    fn to_handle(&self, ctx: &'a Context) -> Result<TensorHandle<'a>> {
        let dims: Vec<u64> = self.shape().iter().map(|x| *x as u64).collect();
        let mut tensor: Tensor<T> = Tensor::new(&dims);
        for (e, v) in tensor.iter_mut().zip(self.iter()) {
            e.clone_from(v);
        }
        TensorHandle::new(ctx, &tensor)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::eager::{Context, ContextOptions};
    use crate::Tensor;

    #[cfg(feature = "ndarray")]
    use ndarray::array;

    #[test]
    fn tensor_to_handle() {
        let ctx = Context::new(ContextOptions::new()).unwrap();
        let tensor = Tensor::<i32>::new(&[1, 2, 3, 4]);
        let handle = tensor.to_handle(&ctx).unwrap();
        assert_eq!(handle.num_dims().unwrap(), 4);
        assert_eq!(handle.dim(0).unwrap(), 1);
        assert_eq!(handle.dim(1).unwrap(), 2);
        assert_eq!(handle.dim(2).unwrap(), 3);
        assert_eq!(handle.dim(3).unwrap(), 4);

        let tensor = Tensor::<i32>::new(&[1, 2, 3, 4]);
        let handle = &tensor.to_handle(&ctx).unwrap();
        assert_eq!(handle.num_dims().unwrap(), 4);
        assert_eq!(handle.dim(0).unwrap(), 1);
        assert_eq!(handle.dim(1).unwrap(), 2);
        assert_eq!(handle.dim(2).unwrap(), 3);
        assert_eq!(handle.dim(3).unwrap(), 4);
    }

    #[test]
    fn handle_to_handle() {
        let ctx = Context::new(ContextOptions::new()).unwrap();
        let tensor = Tensor::<i32>::new(&[1, 2, 3, 4]);
        let handle = tensor.to_handle(&ctx).unwrap();
        let handle2 = handle.to_handle(&ctx).unwrap();
        let tensor2: Tensor<i32> = handle2.resolve().unwrap();
        assert_eq!(&tensor[..], &tensor2[..]);
    }

    #[test]
    fn tensortype_to_handle() {
        let ctx = Context::new(ContextOptions::new()).unwrap();
        let v = 1i32;
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<i32> = handle.resolve().unwrap();
        assert_eq!(&[v], &tensor[..]);

        let v = 1i64;
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<i64> = handle.resolve().unwrap();
        assert_eq!(&[v], &tensor[..]);

        let v = 1f32;
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<f32> = handle.resolve().unwrap();
        assert_eq!(&[v], &tensor[..]);

        let v = 1f64;
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<f64> = handle.resolve().unwrap();
        assert_eq!(&[v], &tensor[..]);
    }

    #[test]
    fn tarray_to_handle() {
        let ctx = Context::new(ContextOptions::new()).unwrap();
        let v = [1i32, 2, 3, 4];
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<i32> = handle.resolve().unwrap();
        assert_eq!(&v, &tensor[..]);

        let v = [1i64, 2, 3, 4];
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<i64> = handle.resolve().unwrap();
        assert_eq!(&v, &tensor[..]);

        let v = [1f32, 2.0, 3.0, 4.0];
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<f32> = handle.resolve().unwrap();
        assert_eq!(&v, &tensor[..]);

        let v = [1f64, 2.0, 3.0, 4.0];
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<f64> = handle.resolve().unwrap();
        assert_eq!(&v, &tensor[..]);
    }

    #[cfg(feature = "ndarray")]
    #[test]
    fn ndarray_to_handle() {
        let a = array![[1i32, 2], [3, 4]];

        let ctx = Context::new(ContextOptions::new()).unwrap();
        let handle = a.to_handle(&ctx).unwrap();
        let tensor: Tensor<i32> = handle.resolve().unwrap();
        assert_eq!(a.as_slice().unwrap(), &tensor[..]);

        let at = Tensor::from(a);
        assert_eq!(at, tensor);
    }
}
<commit_msg>add the Rust's memory design unittest.<commit_after>//! C API extensions to experiment with eager execution of kernels.
//!
//! WARNING: The underlying C-API for the eager execution is not guaranteed to be
//! stable and can be changed without notice, which could result in breaking.

mod context;
pub use context::*;

mod tensor_handle;
pub use tensor_handle::*;

mod op;

pub use op::raw_ops;

use crate::{Result, Tensor, TensorType};

#[cfg(feature = "ndarray")]
use ndarray::{ArrayBase, Data, Dimension};

/// A helper trait to convert a Tensor or some other types into a TensorHandle
/// for use in eager execution.
pub trait ToTensorHandle<'a> {
    /// Convert a Tensor or values into a new TensorHandle.
    ///
    /// _Warning_ : This function may create multiple handles to the same
    /// underlying tensor. Users should be careful not to modify the tensor
    /// after converting it to a TensorHandle. Also, users should be careful
    /// not to modify the Tensor generated from the TensorHandle's `resolve`
    /// method.
    fn to_handle(&self, ctx: &'a Context) -> Result<TensorHandle<'a>>;
}

impl<'a, T> ToTensorHandle<'a> for Tensor<T>
where
    T: TensorType,
{
    fn to_handle(&self, ctx: &'a Context) -> Result<TensorHandle<'a>> {
        TensorHandle::new(ctx, self)
    }
}

impl<'a> ToTensorHandle<'a> for TensorHandle<'a> {
    fn to_handle(&self, _: &'a Context) -> Result<TensorHandle<'a>> {
        self.copy_sharing_tensor()
    }
}

impl<'a, T: TensorType> ToTensorHandle<'a> for T {
    fn to_handle(&self, ctx: &'a Context) -> Result<TensorHandle<'a>> {
        let mut tensor = Tensor::<T>::new(&[]);
        tensor[0] = self.clone();
        TensorHandle::new(ctx, &tensor)
    }
}

impl<'a, T: TensorType> ToTensorHandle<'a> for [T] {
    fn to_handle(&self, ctx: &'a Context) -> Result<TensorHandle<'a>> {
        let mut tensor = Tensor::<T>::new(&[self.len() as u64]);
        for (e, v) in tensor.iter_mut().zip(self) {
            e.clone_from(v);
        }
        TensorHandle::new(ctx, &tensor)
    }
}

impl<'a, T: TensorType, const N: usize> ToTensorHandle<'a> for [T; N] {
    fn to_handle(&self, ctx: &'a Context) -> Result<TensorHandle<'a>> {
        let tensor = Tensor::from(&self[..]);
        TensorHandle::new(ctx, &tensor)
    }
}

#[cfg(feature = "ndarray")]
/// Convert any ndarray::ArrayBase type into a TensorHandle
impl<'a, T, S, D> ToTensorHandle<'a> for ArrayBase<S, D>
where
    T: TensorType,
    S: Data<Elem = T>,
    D: Dimension,
{
    fn to_handle(&self, ctx: &'a Context) -> Result<TensorHandle<'a>> {
        let dims: Vec<u64> = self.shape().iter().map(|x| *x as u64).collect();
        let mut tensor: Tensor<T> = Tensor::new(&dims);
        for (e, v) in tensor.iter_mut().zip(self.iter()) {
            e.clone_from(v);
        }
        TensorHandle::new(ctx, &tensor)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::eager::{Context, ContextOptions};
    use crate::Tensor;

    #[cfg(feature = "ndarray")]
    use ndarray::array;

    #[test]
    fn underlying_memories() {
        // This test is to ensure that the eager execution API does not
        // break the Rust's memory design.

        let ctx = Context::new(ContextOptions::new()).unwrap();

        // Create a tensor with a single element
        let t: Tensor<i32> = Tensor::from(0);

        // Create a handle to the tensor
        let h = t.to_handle(&ctx).unwrap();

        // Get a tensor as mutable from the handle
        let mut t2: Tensor<i32> = h.resolve().unwrap();

        // According to the Rust's memory design, the following assignment should affect only the tensor `t2`.
        t2[0] = 1;

        // Since the tensor `t` is immutable and expected not to be modified, `t` and `t2` should not be equal.
        assert_ne!(t[0], t2[0]);
    }

    #[test]
    fn tensor_to_handle() {
        let ctx = Context::new(ContextOptions::new()).unwrap();
        let tensor = Tensor::<i32>::new(&[1, 2, 3, 4]);
        let handle = tensor.to_handle(&ctx).unwrap();
        assert_eq!(handle.num_dims().unwrap(), 4);
        assert_eq!(handle.dim(0).unwrap(), 1);
        assert_eq!(handle.dim(1).unwrap(), 2);
        assert_eq!(handle.dim(2).unwrap(), 3);
        assert_eq!(handle.dim(3).unwrap(), 4);

        let tensor = Tensor::<i32>::new(&[1, 2, 3, 4]);
        let handle = &tensor.to_handle(&ctx).unwrap();
        assert_eq!(handle.num_dims().unwrap(), 4);
        assert_eq!(handle.dim(0).unwrap(), 1);
        assert_eq!(handle.dim(1).unwrap(), 2);
        assert_eq!(handle.dim(2).unwrap(), 3);
        assert_eq!(handle.dim(3).unwrap(), 4);
    }

    #[test]
    fn handle_to_handle() {
        let ctx = Context::new(ContextOptions::new()).unwrap();
        let tensor = Tensor::<i32>::new(&[1, 2, 3, 4]);
        let handle = tensor.to_handle(&ctx).unwrap();
        let handle2 = handle.to_handle(&ctx).unwrap();
        let tensor2: Tensor<i32> = handle2.resolve().unwrap();
        assert_eq!(&tensor[..], &tensor2[..]);
    }

    #[test]
    fn tensortype_to_handle() {
        let ctx = Context::new(ContextOptions::new()).unwrap();
        let v = 1i32;
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<i32> = handle.resolve().unwrap();
        assert_eq!(&[v], &tensor[..]);

        let v = 1i64;
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<i64> = handle.resolve().unwrap();
        assert_eq!(&[v], &tensor[..]);

        let v = 1f32;
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<f32> = handle.resolve().unwrap();
        assert_eq!(&[v], &tensor[..]);

        let v = 1f64;
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<f64> = handle.resolve().unwrap();
        assert_eq!(&[v], &tensor[..]);
    }

    #[test]
    fn tarray_to_handle() {
        let ctx = Context::new(ContextOptions::new()).unwrap();
        let v = [1i32, 2, 3, 4];
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<i32> = handle.resolve().unwrap();
        assert_eq!(&v, &tensor[..]);

        let v = [1i64, 2, 3, 4];
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<i64> = handle.resolve().unwrap();
        assert_eq!(&v, &tensor[..]);

        let v = [1f32, 2.0, 3.0, 4.0];
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<f32> = handle.resolve().unwrap();
        assert_eq!(&v, &tensor[..]);

        let v = [1f64, 2.0, 3.0, 4.0];
        let handle = v.to_handle(&ctx).unwrap();
        let tensor: Tensor<f64> = handle.resolve().unwrap();
        assert_eq!(&v, &tensor[..]);
    }

    #[cfg(feature = "ndarray")]
    #[test]
    fn ndarray_to_handle() {
        let a = array![[1i32, 2], [3, 4]];

        let ctx = Context::new(ContextOptions::new()).unwrap();
        let handle = a.to_handle(&ctx).unwrap();
        let tensor: Tensor<i32> = handle.resolve().unwrap();
        assert_eq!(a.as_slice().unwrap(), &tensor[..]);

        let at = Tensor::from(a);
        assert_eq!(at, tensor);
    }
}
<|endoftext|>


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

use std::cast;
use std::libc;
use std::libc::c_long;

// a raw Core Foundation reference. It may or may not have been
// CFRetain'ed, depending on whether it was obtained via ownership or
// borrow semantics.
pub trait AbstractCFTypeRef {
    fn as_type_ref(&self) -> CFTypeRef;

    // FIXME https://github.com/mozilla-servo/rust-core-foundation/issues/17
    fn type_id(_dummy: Option<Self>) -> CFTypeID;
}

pub type Boolean = u8;

pub type CFIndex = c_long;
pub type CFOptionFlags = u32;
pub struct CFRange {
    location: CFIndex,
    length: CFIndex
}

pub fn CFRangeMake(off: CFIndex, len: CFIndex) -> CFRange {
    CFRange { location: off, length: len }
}

struct __CFAllocator { private: () }
pub type CFAllocatorRef = *__CFAllocator;

struct __CFNull { private: () }
pub type CFNullRef = *__CFNull;

pub type CFHashCode = libc::c_ulong;
pub type CFTypeID = libc::c_ulong;

struct __CFType { private: () }
pub type CFTypeRef = *__CFType;

impl AbstractCFTypeRef for CFTypeRef {
    fn as_type_ref(&self) -> CFTypeRef { *self }
    // this can't be used, because CFType is the supertype and has no type id.
    fn type_id(_dummy: Option<CFTypeRef>) -> CFTypeID { fail!(); }
}

#[fixed_stack_segment]
pub fn downcast<T:AbstractCFTypeRef>(r: CFTypeRef) -> T {
    unsafe {
        let dummy: Option<T> = None;
        assert!(CFGetTypeID(r) == AbstractCFTypeRef::type_id(dummy));
        cast::transmute::<CFTypeRef, T>(r)
    }
}

pub struct RawCFWrapper {
    obj: CFTypeRef
}

pub struct CFWrapper<T, PlaceholderType1, PlaceholderType2> {
    obj: T
}

#[unsafe_destructor]
impl<T,E1,E2> Drop for CFWrapper<T,E1,E2> {
    #[fixed_stack_segment]
    fn drop(&self) {
        unsafe {
            // sadly, cannot use obj.as_type_ref() here, because drop
            // cannot make virtual method calls using trait
            // types. Instead, just transmute the bugger.
            let this: &RawCFWrapper = cast::transmute::<&CFWrapper<T,E1,E2>, &RawCFWrapper>(self);
            assert!(CFGetRetainCount(this.obj) > 0 as CFIndex);
            CFRelease(this.obj)
        }
    }
}

pub type CFType = CFWrapper<CFTypeRef, (), ()>;

impl<'self, T:Clone + AbstractCFTypeRef, E1, E2> CFWrapper<T,E1,E2> {
    pub fn borrow_ref(&'self self) -> &'self T {
        &self.obj
    }

    pub fn borrow_type_ref(&self) -> &'self CFTypeRef {
        unsafe {
            cast::transmute::<&T, &CFTypeRef>(&self.obj)
        }
    }

    // Use this when following Core Foundation's "Create" rule; i.e., the wrapper assumes ownership.
    // The object has already been retained, so we need not increment the retain count ourself.
    pub fn wrap_owned(some_ref: T) -> CFWrapper<T,E1,E2> {
        // N.B. we can't make any assertions about retain count here,
        // because returned things are only guaranteed to be already
        // retained. Strings, for example, could be interned.
        CFWrapper { obj: some_ref }
    }

    // Use this when following Core Foundation's "Get" rule. The wrapper does not have ownership.
    // Twe need to increment object's the retain count so it isn't freed out from under our noses.
    #[fixed_stack_segment]
    pub fn wrap_shared(some_ref: T) -> CFWrapper<T,E1,E2> {
        unsafe { CFRetain(some_ref.as_type_ref()); }
        CFWrapper { obj: some_ref }
    }

    // Unwraps the wrapper, returning the underlying AbstractCFType.
    pub fn unwrap(wrapper: CFWrapper<T,E1,E2>) -> T {
        wrapper.obj.clone()
    }

    pub fn to_CFType(wrapper: CFWrapper<T,E1,E2>) -> CFType {
        unsafe {
            cast::transmute::<CFWrapper<T, E1, E2>, CFType>(wrapper)
        }
    }

    pub fn from_CFType(wrapper: CFType) -> CFWrapper<T,E1,E2> {
        unsafe {
            let dummy: Option<T> = None;
            assert!(wrapper.type_id() == AbstractCFTypeRef::type_id(dummy));
            cast::transmute::<CFType,CFWrapper<T,E1,E2>>(wrapper)
        }
    }

    pub fn clone(wrapper: &CFWrapper<T,E1,E2>) -> CFWrapper<T,E1,E2> {
        CFWrapper::wrap_shared((*wrapper.borrow_ref()).clone())
    }

    #[fixed_stack_segment]
    pub fn retain_count(&self) -> CFIndex {
        unsafe {
            CFGetRetainCount(*self.borrow_type_ref())
        }
    }

    #[fixed_stack_segment]
    pub fn type_id(&self) -> CFTypeID {
        unsafe {
            CFGetTypeID(*self.borrow_type_ref())
        }
    }

    #[fixed_stack_segment]
    pub fn show(&self) {
        unsafe {
            CFShow(*self.borrow_type_ref());
        }
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFBase.h
     */

    /* CFAllocator Reference */
    // N.B. Many CFAllocator functions and constants are omitted here.
    pub static kCFAllocatorDefault: CFAllocatorRef;
    pub static kCFAllocatorSystemDefault: CFAllocatorRef;
    pub static kCFAllocatorMalloc: CFAllocatorRef;
    pub static kCFAllocatorMallocZone: CFAllocatorRef;
    pub static kCFAllocatorNull: CFAllocatorRef;
    pub static kCFAllocatorUseContext: CFAllocatorRef;

    /* CFNull Reference */

    pub static kCFNull: CFNullRef;

    /* CFType Reference */

    //fn CFCopyDescription
    //fn CFCopyTypeIDDescription
    //fn CFEqual
    //fn CFGetAllocator
    pub fn CFGetRetainCount(cf: CFTypeRef) -> CFIndex;
    pub fn CFGetTypeID(cf: CFTypeRef) -> CFTypeID;
    pub fn CFHash(cf: CFTypeRef) -> CFHashCode;
    //fn CFMakeCollectable
    pub fn CFRelease(cf: CFTypeRef);
    pub fn CFRetain(cf: CFTypeRef) -> CFTypeRef;
    pub fn CFShow(obj: CFTypeRef);

    /* Base Utilities Reference */
    // N.B. Some things missing here.
}
<commit_msg>Upgrade Rust.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::cast;
use std::libc;
use std::libc::c_long;

// a raw Core Foundation reference. It may or may not have been
// CFRetain'ed, depending on whether it was obtained via ownership or
// borrow semantics.
pub trait AbstractCFTypeRef {
    fn as_type_ref(&self) -> CFTypeRef;

    // FIXME https://github.com/mozilla-servo/rust-core-foundation/issues/17
    fn type_id(_dummy: Option<Self>) -> CFTypeID;
}

pub type Boolean = u8;

pub type CFIndex = c_long;
pub type CFOptionFlags = u32;
pub struct CFRange {
    location: CFIndex,
    length: CFIndex
}

pub fn CFRangeMake(off: CFIndex, len: CFIndex) -> CFRange {
    CFRange { location: off, length: len }
}

struct __CFAllocator { private: () }
pub type CFAllocatorRef = *__CFAllocator;

struct __CFNull { private: () }
pub type CFNullRef = *__CFNull;

pub type CFHashCode = libc::c_ulong;
pub type CFTypeID = libc::c_ulong;

struct __CFType { private: () }
pub type CFTypeRef = *__CFType;

impl AbstractCFTypeRef for CFTypeRef {
    fn as_type_ref(&self) -> CFTypeRef { *self }
    // this can't be used, because CFType is the supertype and has no type id.
    fn type_id(_dummy: Option<CFTypeRef>) -> CFTypeID { fail!(); }
}

#[fixed_stack_segment]
pub fn downcast<T:AbstractCFTypeRef>(r: CFTypeRef) -> T {
    unsafe {
        let dummy: Option<T> = None;
        assert!(CFGetTypeID(r) == AbstractCFTypeRef::type_id(dummy));
        cast::transmute::<CFTypeRef, T>(r)
    }
}

pub struct RawCFWrapper {
    obj: CFTypeRef
}

pub struct CFWrapper<T, PlaceholderType1, PlaceholderType2> {
    obj: T
}

#[unsafe_destructor]
impl<T,E1,E2> Drop for CFWrapper<T,E1,E2> {
    #[fixed_stack_segment]
    fn drop(&mut self) {
        unsafe {
            // sadly, cannot use obj.as_type_ref() here, because drop
            // cannot make virtual method calls using trait
            // types. Instead, just transmute the bugger.
            let this: &RawCFWrapper = cast::transmute::<&CFWrapper<T,E1,E2>, &RawCFWrapper>(self);
            assert!(CFGetRetainCount(this.obj) > 0 as CFIndex);
            CFRelease(this.obj)
        }
    }
}

pub type CFType = CFWrapper<CFTypeRef, (), ()>;

impl<'self, T:Clone + AbstractCFTypeRef, E1, E2> CFWrapper<T,E1,E2> {
    pub fn borrow_ref(&'self self) -> &'self T {
        &self.obj
    }

    pub fn borrow_type_ref(&self) -> &'self CFTypeRef {
        unsafe {
            cast::transmute::<&T, &CFTypeRef>(&self.obj)
        }
    }

    // Use this when following Core Foundation's "Create" rule; i.e., the wrapper assumes ownership.
    // The object has already been retained, so we need not increment the retain count ourself.
    pub fn wrap_owned(some_ref: T) -> CFWrapper<T,E1,E2> {
        // N.B. we can't make any assertions about retain count here,
        // because returned things are only guaranteed to be already
        // retained. Strings, for example, could be interned.
        CFWrapper { obj: some_ref }
    }

    // Use this when following Core Foundation's "Get" rule. The wrapper does not have ownership.
    // Twe need to increment object's the retain count so it isn't freed out from under our noses.
    #[fixed_stack_segment]
    pub fn wrap_shared(some_ref: T) -> CFWrapper<T,E1,E2> {
        unsafe { CFRetain(some_ref.as_type_ref()); }
        CFWrapper { obj: some_ref }
    }

    // Unwraps the wrapper, returning the underlying AbstractCFType.
    pub fn unwrap(wrapper: CFWrapper<T,E1,E2>) -> T {
        wrapper.obj.clone()
    }

    pub fn to_CFType(wrapper: CFWrapper<T,E1,E2>) -> CFType {
        unsafe {
            cast::transmute::<CFWrapper<T, E1, E2>, CFType>(wrapper)
        }
    }

    pub fn from_CFType(wrapper: CFType) -> CFWrapper<T,E1,E2> {
        unsafe {
            let dummy: Option<T> = None;
            assert!(wrapper.type_id() == AbstractCFTypeRef::type_id(dummy));
            cast::transmute::<CFType,CFWrapper<T,E1,E2>>(wrapper)
        }
    }

    pub fn clone(wrapper: &CFWrapper<T,E1,E2>) -> CFWrapper<T,E1,E2> {
        CFWrapper::wrap_shared((*wrapper.borrow_ref()).clone())
    }

    #[fixed_stack_segment]
    pub fn retain_count(&self) -> CFIndex {
        unsafe {
            CFGetRetainCount(*self.borrow_type_ref())
        }
    }

    #[fixed_stack_segment]
    pub fn type_id(&self) -> CFTypeID {
        unsafe {
            CFGetTypeID(*self.borrow_type_ref())
        }
    }

    #[fixed_stack_segment]
    pub fn show(&self) {
        unsafe {
            CFShow(*self.borrow_type_ref());
        }
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    /*
     * CFBase.h
     */

    /* CFAllocator Reference */
    // N.B. Many CFAllocator functions and constants are omitted here.
    pub static kCFAllocatorDefault: CFAllocatorRef;
    pub static kCFAllocatorSystemDefault: CFAllocatorRef;
    pub static kCFAllocatorMalloc: CFAllocatorRef;
    pub static kCFAllocatorMallocZone: CFAllocatorRef;
    pub static kCFAllocatorNull: CFAllocatorRef;
    pub static kCFAllocatorUseContext: CFAllocatorRef;

    /* CFNull Reference */

    pub static kCFNull: CFNullRef;

    /* CFType Reference */

    //fn CFCopyDescription
    //fn CFCopyTypeIDDescription
    //fn CFEqual
    //fn CFGetAllocator
    pub fn CFGetRetainCount(cf: CFTypeRef) -> CFIndex;
    pub fn CFGetTypeID(cf: CFTypeRef) -> CFTypeID;
    pub fn CFHash(cf: CFTypeRef) -> CFHashCode;
    //fn CFMakeCollectable
    pub fn CFRelease(cf: CFTypeRef);
    pub fn CFRetain(cf: CFTypeRef) -> CFTypeRef;
    pub fn CFShow(obj: CFTypeRef);

    /* Base Utilities Reference */
    // N.B. Some things missing here.
}
<|endoftext|>


<commit_before>extern crate core;

use std::str::FromStr;
use std::old_io::IoError;
use std::error::{Error, FromError};
use std::fmt;
use rustc_serialize::{Encoder, Encodable};
use utils::ForceEncodable;

#[derive(Debug, Copy, RustcEncodable)]
pub enum MpdErrorCode {
    NotList,
    Argument,
    Password,
    Permission,
    UnknownCmd,
    NoExist,
    PlaylistMax,
    System,
    PlaylistLoad,
    UpdateAlready,
    PlayerSync,
    Exist,
    Other(usize)
}

impl FromStr for MpdErrorCode {
    type Err = core::num::ParseIntError;
    fn from_str(s: &str) -> Result<MpdErrorCode, core::num::ParseIntError> {
        match s {
            "1" => Ok(MpdErrorCode::NotList),
            "2" => Ok(MpdErrorCode::Argument),
            "3" => Ok(MpdErrorCode::Password),
            "4" => Ok(MpdErrorCode::Permission),
            "5" => Ok(MpdErrorCode::UnknownCmd),

            "50" => Ok(MpdErrorCode::NoExist),
            "51" => Ok(MpdErrorCode::PlaylistMax),
            "52" => Ok(MpdErrorCode::System),
            "53" => Ok(MpdErrorCode::PlaylistLoad),
            "54" => Ok(MpdErrorCode::UpdateAlready),
            "55" => Ok(MpdErrorCode::PlayerSync),
            "56" => Ok(MpdErrorCode::Exist),

            _ => s.parse().map(|v| MpdErrorCode::Other(v))
        }
    }
}

#[derive(Debug, RustcEncodable)]
pub struct MpdServerError {
    pub code: MpdErrorCode,
    pub pos: usize,
    pub command: String,
    pub detail: String
}

#[derive(Debug)]
pub enum MpdError {
    Mpd(MpdServerError),
    Io(IoError),
}

impl Encodable for MpdError {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match *self {
            MpdError::Mpd(ref err) => err.encode(s),
            MpdError::Io(ref err) => {
                s.emit_struct("IoError", 3, |s| {
                    s.emit_struct_field("kind", 0, |s| format!("{:?}", err.kind).encode(s)).and_then(|_|
                    s.emit_struct_field("desc", 1, |s| err.desc.encode(s))).and_then(|_|
                    s.emit_struct_field("detail", 2, |s| err.detail.encode(s)))
                })
            }
        }
    }
}

impl Error for MpdServerError {
    fn description(&self) -> &str {
        match self.code {
            MpdErrorCode::NotList => "not a list",
            MpdErrorCode::Argument => "invalid argument",
            MpdErrorCode::Password => "invalid password",
            MpdErrorCode::Permission => "access denied",
            MpdErrorCode::UnknownCmd => "unknown command",
            MpdErrorCode::NoExist => "object not found",
            MpdErrorCode::PlaylistMax => "playlist overflow",
            MpdErrorCode::System => "system error",
            MpdErrorCode::PlaylistLoad => "playlist load error",
            MpdErrorCode::UpdateAlready => "database already updating",
            MpdErrorCode::PlayerSync => "player sync error",
            MpdErrorCode::Exist => "object already exists",
            MpdErrorCode::Other(_) => "unknown error",
        }
    }
}

impl fmt::Display for MpdServerError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(fmt)
    }
}

impl Error for MpdError {
    fn description(&self) -> &str {
        match *self {
            MpdError::Io(ref err) => err.description(),
            MpdError::Mpd(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            MpdError::Io(ref err) => Some(err as &Error),
            MpdError::Mpd(ref err) => Some(err as &Error),
        }
    }
}

impl fmt::Display for MpdError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            MpdError::Mpd(ref err) => err.fmt(fmt),
            MpdError::Io(ref err) => err.fmt(fmt),
        }
    }
}

impl FromError<IoError> for MpdError {
    fn from_error(err: IoError) -> MpdError {
        MpdError::Io(err)
    }
}

impl FromError<MpdServerError> for MpdError {
    fn from_error(err: MpdServerError) -> MpdError {
        MpdError::Mpd(err)
    }
}

#[derive(Copy, Debug)]
pub struct MpdServerResponseParseError {
    kind: MpdServerResponseParseErrorKind
}

#[derive(Copy, Debug)]
enum MpdServerResponseParseErrorKind {
    InvalidAck,
    InvalidPair,
}

impl FromStr for MpdServerError {
    type Err = MpdServerResponseParseError;
    fn from_str(s: &str) -> Result<MpdServerError, MpdServerResponseParseError> {
        // ACK [<code>@<index>] {<command>} <description>
        if s.starts_with("ACK [") {
            let s = &s[5..];
            if let (Some(atsign), Some(right_bracket)) = (s.find('@'), s.find(']')) {
                if let (Ok(code), Ok(pos)) = (s[..atsign].parse(), s[atsign + 1..right_bracket].parse()) {
                    let s = &s[right_bracket + 1..];
                    if let (Some(left_brace), Some(right_brace)) = (s.find('{'), s.find('}')) {
                        let command = s[left_brace + 1..right_brace].to_string();
                        let detail = s[right_brace + 1..].trim().to_string();
                        return Ok(MpdServerError {
                            code: code,
                            pos: pos,
                            command: command,
                            detail: detail
                        });
                    }
                }
            }
        }
        Err(MpdServerResponseParseError {
            kind: MpdServerResponseParseErrorKind::InvalidAck
        })
    }
}

pub type MpdResult<T> = Result<T, MpdError>;

impl<T: Encodable> ForceEncodable for MpdResult<T> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match *self {
            Ok(ref v) => v.encode(s),
            Err(ref e) => e.encode(s)
        }
    }
}
<commit_msg>refactor mpd error string parser<commit_after>extern crate core;

use std::str::FromStr;
use std::old_io::IoError;
use std::error::{Error, FromError};
use std::fmt;
use rustc_serialize::{Encoder, Encodable};
use utils::ForceEncodable;

#[derive(Debug, Copy, RustcEncodable)]
pub enum MpdErrorCode {
    NotList,
    Argument,
    Password,
    Permission,
    UnknownCmd,
    NoExist,
    PlaylistMax,
    System,
    PlaylistLoad,
    UpdateAlready,
    PlayerSync,
    Exist,
    Other(usize)
}

impl FromStr for MpdErrorCode {
    type Err = core::num::ParseIntError;
    fn from_str(s: &str) -> Result<MpdErrorCode, core::num::ParseIntError> {
        match s {
            "1" => Ok(MpdErrorCode::NotList),
            "2" => Ok(MpdErrorCode::Argument),
            "3" => Ok(MpdErrorCode::Password),
            "4" => Ok(MpdErrorCode::Permission),
            "5" => Ok(MpdErrorCode::UnknownCmd),

            "50" => Ok(MpdErrorCode::NoExist),
            "51" => Ok(MpdErrorCode::PlaylistMax),
            "52" => Ok(MpdErrorCode::System),
            "53" => Ok(MpdErrorCode::PlaylistLoad),
            "54" => Ok(MpdErrorCode::UpdateAlready),
            "55" => Ok(MpdErrorCode::PlayerSync),
            "56" => Ok(MpdErrorCode::Exist),

            _ => s.parse().map(|v| MpdErrorCode::Other(v))
        }
    }
}

#[derive(Debug, RustcEncodable)]
pub struct MpdServerError {
    pub code: MpdErrorCode,
    pub pos: usize,
    pub command: String,
    pub detail: String
}

#[derive(Debug)]
pub enum MpdError {
    Mpd(MpdServerError),
    Io(IoError),
}

impl Encodable for MpdError {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match *self {
            MpdError::Mpd(ref err) => err.encode(s),
            MpdError::Io(ref err) => {
                s.emit_struct("IoError", 3, |s| {
                    s.emit_struct_field("kind", 0, |s| format!("{:?}", err.kind).encode(s)).and_then(|_|
                    s.emit_struct_field("desc", 1, |s| err.desc.encode(s))).and_then(|_|
                    s.emit_struct_field("detail", 2, |s| err.detail.encode(s)))
                })
            }
        }
    }
}

impl Error for MpdServerError {
    fn description(&self) -> &str {
        match self.code {
            MpdErrorCode::NotList => "not a list",
            MpdErrorCode::Argument => "invalid argument",
            MpdErrorCode::Password => "invalid password",
            MpdErrorCode::Permission => "access denied",
            MpdErrorCode::UnknownCmd => "unknown command",
            MpdErrorCode::NoExist => "object not found",
            MpdErrorCode::PlaylistMax => "playlist overflow",
            MpdErrorCode::System => "system error",
            MpdErrorCode::PlaylistLoad => "playlist load error",
            MpdErrorCode::UpdateAlready => "database already updating",
            MpdErrorCode::PlayerSync => "player sync error",
            MpdErrorCode::Exist => "object already exists",
            MpdErrorCode::Other(_) => "unknown error",
        }
    }
}

impl fmt::Display for MpdServerError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(fmt)
    }
}

impl Error for MpdError {
    fn description(&self) -> &str {
        match *self {
            MpdError::Io(ref err) => err.description(),
            MpdError::Mpd(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            MpdError::Io(ref err) => Some(err as &Error),
            MpdError::Mpd(ref err) => Some(err as &Error),
        }
    }
}

impl fmt::Display for MpdError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            MpdError::Mpd(ref err) => err.fmt(fmt),
            MpdError::Io(ref err) => err.fmt(fmt),
        }
    }
}

impl FromError<IoError> for MpdError {
    fn from_error(err: IoError) -> MpdError {
        MpdError::Io(err)
    }
}

impl FromError<MpdServerError> for MpdError {
    fn from_error(err: MpdServerError) -> MpdError {
        MpdError::Mpd(err)
    }
}

#[derive(Copy, Debug)]
pub struct ParseMpdServerError {
    kind: MpdServerResponseParseErrorKind
}

#[derive(Copy, Debug)]
enum ParseMpdServerErrorKind {
    NoCodePos
    InvalidCode,
    InvalidPos,
    NoMessage
}

impl FromStr for Option<MpdServerError> {
    type Err = ParseMpdServerError;
    fn from_str(s: &str) -> Result<Option<MpdServerError>, ParseMpdServerError> {
        // ACK [<code>@<index>] {<command>} <description>
        if s.starts_with("ACK [") {
            let s = &s[5..];
            if let (Some(atsign), Some(right_bracket)) = (s.find('@'), s.find(']')) {
                match (s[..atsign].parse(), s[atsign + 1..right_bracket].parse()) {
                    (Ok(code), Ok(pos)) => {
                        let s = &s[right_bracket + 1..];
                        if let (Some(left_brace), Some(right_brace)) = (s.find('{'), s.find('}')) {
                            let command = s[left_brace + 1..right_brace].to_string();
                            let detail = s[right_brace + 1..].trim().to_string();
                            Ok(Some(MpdServerError {
                                code: code,
                                pos: pos,
                                command: command,
                                detail: detail
                            }))
                        } else {
                            Err(ParseMpdServerError { kind: ParseMpdServerErrorKind::NoMessage })
                        }
                    }
                    (Err(_), _) => Err(ParseMpdServerError { kind: ParseMpdServerErrorKind::InvalidCode }),
                    (_, Err(_)) => Err(ParseMpdServerError { kind: ParseMpdServerErrorKind::InvalidPos }),
                }
            } else {
                Err(ParseMpdServerError { kind: ParseMpdServerErrorKind::NoCodePos })
            }
        } else {
            Ok(None)
        }
    }
}

pub type MpdResult<T> = Result<T, MpdError>;

impl<T: Encodable> ForceEncodable for MpdResult<T> {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        match *self {
            Ok(ref v) => v.encode(s),
            Err(ref e) => e.encode(s)
        }
    }
}
<|endoftext|>


<commit_before>//! Abstractions for the events passed back from i3.

use reply;
use serde;
use std::str::FromStr;

pub enum EventType {
    Workspace,
    Output,
    Mode,
    Window,
    BarConfig,
    BindingEvent
}

pub enum Event {
    EWorkspace(Workspace),
    EOutput(Output),
    EMode(Mode),
    EWindow(Window),
    EBarConfig(BarConfig),
    EBindingEvent(BindingEvent),
}

/// Indicates the type of change.
pub enum WorkspaceChange {
    Focus,
    Init,
    Empty,
    Urgent
}

/// The data for the workspace event.
pub struct Workspace {
    /// The type of change.
    pub change: WorkspaceChange,
    /// Will be `Some` if the type of event affects the workspace.
    pub current: Option<reply::Workspace>,
    /// Will be `Some` only when `change == Focus` *and* there was a previous workspace.
    /// Note that if the previous workspace was empty it will get destroyed when switching, but
    /// will still appear here.
    pub old: Option<reply::Workspace>
}

impl FromStr for Workspace {
    type Err = serde::json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        panic!("not implemented");
    }
}

/// Indicates the type of change (currently only unspecified).
pub enum OutputChange {
    Unspecified
}

/// The data for the output event.
pub struct Output {
    /// The type of change.
    pub change: OutputChange
}

impl FromStr for Output {
    type Err = serde::json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        panic!("not implemented");
    }
}

/// The data for the mode event.
pub struct Mode {
    /// The name of current mode in use. It is the same as specified in config when creating a
    /// mode. The default mode is simply named default.
    pub change: String
}

impl FromStr for Mode {
    type Err = serde::json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        panic!("not implemented");
    }
}

/// The type of the window change.
pub enum WindowChange {
    /// The window has become managed by i3.
    New,
    /// The window has closed>.
    Close,
    /// The window has received input focus.
    Focus,
    /// The window's title has changed.
    Title,
    /// The window has entered or exited fullscreen mode.
    FullscreenMode,
    /// The window has changed its position in the tree.
    Move,
    /// The window has transitioned to or from floating.
    Floating,
    /// The window has become urgent or lost its urgent status.
    Urgent
}

/// The data for the window event.
pub struct Window {
    /// Indicates the type of change
    pub change: WindowChange,
    pub container: reply::Tree
}

impl FromStr for Window {
    type Err = serde::json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        panic!("not implemented");
    }
}

/// The data for the barconfig_update event.
pub type BarConfig = reply::BarConfig;

impl FromStr for BarConfig {
    type Err = serde::json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        panic!("not implemented");
    }
}

pub enum InputType {
    Keyboard,
    Mouse
}

/// Contains details about the binding that was run.
pub struct Binding {
    /// The i3 command that is configured to run for this binding.
    pub command: String,

    /// The modifier keys that were configured with this binding.
    pub mods: Vec<String>,

    /// If the binding was configured with blindcode, this will be the key code that was given for
    /// the binding. If the binding is a mouse binding, it will be the number of times the mouse
    /// button was pressed. Otherwise it will be 0.
    pub input_code: i32,

    /// If this is a keyboard binding that was configured with bindsym, this field will contain the
    /// given symbol. Otherwise it will be None.
    pub symbol: Option<String>,

    /// Will be Keyboard or Mouse depending on whether this was a keyboard or mouse binding.
    pub input_type: InputType
}

/// The type of change.
pub enum BindingEventChange {
    Run
}

/// This event reports on the details of a binding that ran a command because of user input. The
/// change field indicates what sort of binding event was triggered (right now it will always be
/// "run" but may be expanded in the future).
pub struct BindingEvent {
    /// Indicates what sort of binding event was triggered (right now it will always be "run" but
    /// that may be expanded in the future).
    pub change: BindingEventChange,
    pub binding: Binding
}

impl FromStr for BindingEvent {
    type Err = serde::json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        panic!("not implemented");
    }
}
<commit_msg>Correct event::Workspace<commit_after>//! Abstractions for the events passed back from i3.

use reply;
use serde;
use std::str::FromStr;

pub enum EventType {
    Workspace,
    Output,
    Mode,
    Window,
    BarConfig,
    BindingEvent
}

pub enum Event {
    EWorkspace(Workspace),
    EOutput(Output),
    EMode(Mode),
    EWindow(Window),
    EBarConfig(BarConfig),
    EBindingEvent(BindingEvent),
}

/// Indicates the type of change.
pub enum WorkspaceChange {
    Focus,
    Init,
    Empty,
    Urgent
}

/// The data for the workspace event.
pub struct Workspace {
    /// The type of change.
    pub change: WorkspaceChange,
    /// Will be `Some` if the type of event affects the workspace.
    pub current: Option<reply::Tree>,
    /// Will be `Some` only when `change == Focus` *and* there was a previous workspace.
    /// Note that if the previous workspace was empty it will get destroyed when switching, but
    /// will still appear here.
    pub old: Option<reply::Tree>
}

impl FromStr for Workspace {
    type Err = serde::json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        panic!("not implemented");
    }
}

/// Indicates the type of change (currently only unspecified).
pub enum OutputChange {
    Unspecified
}

/// The data for the output event.
pub struct Output {
    /// The type of change.
    pub change: OutputChange
}

impl FromStr for Output {
    type Err = serde::json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        panic!("not implemented");
    }
}

/// The data for the mode event.
pub struct Mode {
    /// The name of current mode in use. It is the same as specified in config when creating a
    /// mode. The default mode is simply named default.
    pub change: String
}

impl FromStr for Mode {
    type Err = serde::json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        panic!("not implemented");
    }
}

/// The type of the window change.
pub enum WindowChange {
    /// The window has become managed by i3.
    New,
    /// The window has closed>.
    Close,
    /// The window has received input focus.
    Focus,
    /// The window's title has changed.
    Title,
    /// The window has entered or exited fullscreen mode.
    FullscreenMode,
    /// The window has changed its position in the tree.
    Move,
    /// The window has transitioned to or from floating.
    Floating,
    /// The window has become urgent or lost its urgent status.
    Urgent
}

/// The data for the window event.
pub struct Window {
    /// Indicates the type of change
    pub change: WindowChange,
    pub container: reply::Tree
}

impl FromStr for Window {
    type Err = serde::json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        panic!("not implemented");
    }
}

/// The data for the barconfig_update event.
pub type BarConfig = reply::BarConfig;

impl FromStr for BarConfig {
    type Err = serde::json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        panic!("not implemented");
    }
}

pub enum InputType {
    Keyboard,
    Mouse
}

/// Contains details about the binding that was run.
pub struct Binding {
    /// The i3 command that is configured to run for this binding.
    pub command: String,

    /// The modifier keys that were configured with this binding.
    pub mods: Vec<String>,

    /// If the binding was configured with blindcode, this will be the key code that was given for
    /// the binding. If the binding is a mouse binding, it will be the number of times the mouse
    /// button was pressed. Otherwise it will be 0.
    pub input_code: i32,

    /// If this is a keyboard binding that was configured with bindsym, this field will contain the
    /// given symbol. Otherwise it will be None.
    pub symbol: Option<String>,

    /// Will be Keyboard or Mouse depending on whether this was a keyboard or mouse binding.
    pub input_type: InputType
}

/// The type of change.
pub enum BindingEventChange {
    Run
}

/// This event reports on the details of a binding that ran a command because of user input. The
/// change field indicates what sort of binding event was triggered (right now it will always be
/// "run" but may be expanded in the future).
pub struct BindingEvent {
    /// Indicates what sort of binding event was triggered (right now it will always be "run" but
    /// that may be expanded in the future).
    pub change: BindingEventChange,
    pub binding: Binding
}

impl FromStr for BindingEvent {
    type Err = serde::json::error::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        panic!("not implemented");
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate image;

use std::collections::HashMap;
use rand::random;

use std::fs::File;
use std::path::Path;

/// Single map point
pub struct Field{
    state: u32,
}

impl Field{
    pub fn new(state: u32) -> Field{
        Field{
            state: state,
        }
    }
}

/// Whole map
pub struct Map{
    height: u32,
    width: u32,
    fields: HashMap<(u32,u32),Field>,
}

pub struct Params{
    iterations: u32,
    chances: (u32,u32,u32,u32,u32),
}

impl Map {
    pub fn new(x: u32, y: u32) -> Map{
        let mut map = Map{
            height: y,
            width: x,
            fields: HashMap::new(),
        };

        for i in 0..y {
            for j in 0..x{
                map.fields.insert((j,i),Field::new(0));
            }
        }
        map
    }

    /// Print map into stdout
    pub fn print(&self){
        for i in 0..self.height {
            for j in 0..self.width {
                let sym = if self.fields.get(&(j,i)).unwrap().state > 0
                    { '*' } else { ' ' };
                print!(" {}", sym);
            }
            println!("");
        }
    }

    pub fn export(&self){

        let mut imgbuf = image::ImageBuffer::new(self.width, self.height);

        for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
            let color = if self.fields.get(&(x,y)).unwrap().state > 0
            { [0,125,0] } else { [0,0,125] };

            *pixel = image::Rgb(color);
        }

        let ref mut fout = File::create(&Path::new("out.png")).unwrap();

        image::ImageRgb8(imgbuf).save(fout, image::PNG);

    }

    /// Find neighbours for single map point
    fn calc_weight(&self, p: (u32,u32)) -> u32{
        let mut res = self.fields.get(&p).unwrap().state;

        // right cell
        if p.0 < self.width -1 {
            res += self.fields.get(&(p.0 + 1 , p.1)).unwrap().state;
        }
        // left cell
        if p.0 > 0 {
            res += self.fields.get(&(p.0 - 1, p.1)).unwrap().state;
        }
        // upper cell
        if p.1 > 0 {
            res += self.fields.get(&(p.0, p.1 - 1)).unwrap().state;
        }
        // down cell
        if p.1 < self.height -1 {
            res += self.fields.get(&(p.0, p.1 + 1)).unwrap().state;
        }
        res
    }

    /// Create neighbours map
    fn calc_neighbours(&self,pre_map: &mut HashMap<(u32,u32),u32>){
        for i in 0..self.height {
            for j in 0..self.width {
                let w = self.calc_weight((j,i));
                pre_map.insert((j,i),w);
            }
        }
    }

    fn algo(&mut self, params: Params){
        let mut neighbours = HashMap::<(u32,u32),u32>::new();

        for _ in 0..params.iterations {
            self.calc_neighbours(&mut neighbours);

            for (p, field) in self.fields.iter_mut() {
                if field.state > 0 {
                    continue;
                }

                let weight = neighbours.get(&p).unwrap();
                let chance = random::<u32>() % 100;

                match *weight {
                    0 => if chance < params.chances.0 { field.state = 1 },
                    1 => if chance < params.chances.1 { field.state = 1 },
                    2 => if chance < params.chances.2 { field.state = 1 },
                    3 => if chance < params.chances.3 { field.state = 1 },
                    4 => if chance < params.chances.4 { field.state = 1 },
                    _ => {},
                }
            }
        }
    }

    //TODO add target fill rate
    /// Generate map
    pub fn generate(&mut self){

        // seed map
        for (_,field) in self.fields.iter_mut() {
            if random::<u32>() % 100 == 1 {
                field.state = 1;
            }
        }

        self.algo(Params{iterations: 25, chances: (0,20,40,50,80)});

    }
}
<commit_msg>moved seed to separate func<commit_after>extern crate rand;
extern crate image;

use std::collections::HashMap;
use rand::random;

use std::fs::File;
use std::path::Path;

/// Single map point
pub struct Field{
    state: u32,
}

impl Field{
    pub fn new(state: u32) -> Field{
        Field{
            state: state,
        }
    }
}

/// Whole map
pub struct Map{
    height: u32,
    width: u32,
    fields: HashMap<(u32,u32),Field>,
}

/// Params for algo func
pub struct Params{
    /// algo iteration count
    iterations: u32,
    /// chances (0..100) to fill tile as earth
    /// for tiles with 0,1,2,3,4 neighbours
    chances: (u32,u32,u32,u32,u32),
}

impl Map {
    pub fn new(x: u32, y: u32) -> Map{
        let mut map = Map{
            height: y,
            width: x,
            fields: HashMap::new(),
        };

        for i in 0..y {
            for j in 0..x{
                map.fields.insert((j,i),Field::new(0));
            }
        }
        map
    }

    /// Print map into stdout
    pub fn print(&self){
        for i in 0..self.height {
            for j in 0..self.width {
                let sym = if self.fields.get(&(j,i)).unwrap().state > 0
                    { '*' } else { ' ' };
                print!(" {}", sym);
            }
            println!("");
        }
    }

    pub fn export(&self){

        let mut imgbuf = image::ImageBuffer::new(self.width, self.height);

        for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
            let color = if self.fields.get(&(x,y)).unwrap().state > 0
            { [0,125,0] } else { [0,0,125] };

            *pixel = image::Rgb(color);
        }

        let ref mut fout = File::create(&Path::new("out.png")).unwrap();

        image::ImageRgb8(imgbuf).save(fout, image::PNG);

    }

    /// Find neighbours for single map point
    fn calc_weight(&self, p: (u32,u32)) -> u32{
        let mut res = self.fields.get(&p).unwrap().state;

        // right cell
        if p.0 < self.width -1 {
            res += self.fields.get(&(p.0 + 1 , p.1)).unwrap().state;
        }
        // left cell
        if p.0 > 0 {
            res += self.fields.get(&(p.0 - 1, p.1)).unwrap().state;
        }
        // upper cell
        if p.1 > 0 {
            res += self.fields.get(&(p.0, p.1 - 1)).unwrap().state;
        }
        // down cell
        if p.1 < self.height -1 {
            res += self.fields.get(&(p.0, p.1 + 1)).unwrap().state;
        }
        res
    }

    /// Create neighbours map
    fn calc_neighbours(&self,pre_map: &mut HashMap<(u32,u32),u32>){
        for i in 0..self.height {
            for j in 0..self.width {
                let w = self.calc_weight((j,i));
                pre_map.insert((j,i),w);
            }
        }
    }

    fn algo(&mut self, params: Params){
        let mut neighbours = HashMap::<(u32,u32),u32>::new();

        for _ in 0..params.iterations {
            self.calc_neighbours(&mut neighbours);

            for (p, field) in self.fields.iter_mut() {
                if field.state > 0 {
                    continue;
                }

                let weight = neighbours.get(&p).unwrap();
                let chance = random::<u32>() % 100;

                match *weight {
                    0 => if chance < params.chances.0 { field.state = 1 },
                    1 => if chance < params.chances.1 { field.state = 1 },
                    2 => if chance < params.chances.2 { field.state = 1 },
                    3 => if chance < params.chances.3 { field.state = 1 },
                    4 => if chance < params.chances.4 { field.state = 1 },
                    _ => {},
                }
            }
        }
    }

    fn seed(&mut self, chance: u32){
        // seed map
        for (_,field) in self.fields.iter_mut() {
            if random::<u32>() % 100 == chance {
                field.state = 1;
            }
        }
    }

    //TODO add target fill rate
    /// Generate map
    pub fn generate(&mut self){

        self.seed(1);

        self.algo(Params{iterations: 25, chances: (0,20,40,50,80)});

    }
}
<|endoftext|>