<commit_before>extern crate num;
use self::num::integer::Integer;
use std::rand::{task_rng, Rng};
use cpu::{Cpu, join_bytes, separate_byte};
use std::mem;

pub fn to_opcode(v: i8) -> Opcode {
    unsafe { mem::transmute(v) }
}

pub enum Opcode {
    Nop = 0,
	Cls,
	Vblnk,
	Bgc,
	Spr,
	Drw,
	Drw2,
	Rnd,
	Flip,
	Snd0,
	Snd1,
	Snd2,
	Snd3,
	Snp,
	Sng,
	Jmp = 0x10,
	Jmc,
	Jx,
	Jme,
	Call,
	Ret,
	Jmp2,
	Cx,
	Call2,
	Ldi = 0x20,
	Ldi2,
	Ldm,
	Ldm2,
	Mov,
	Stm = 0x30,
	Stm2,
	Addi = 0x40,
	Add,
	Add2,
	Subi = 0x50,
	Sub,
	Sub2,
	Cmpi,
	Cmp,
	Andi = 0x60,
	And,
	And2,
	Tsti,
	Tst,
	Ori = 0x70,
	Or,
	Or2,
	Xori = 0x80,
	Xor,
	Xor2,
	Muli = 0x90,
	Mul,
	Mul2,
	Divi = 0xA0,
	Div,
	Div2,
	Modi,
	Mod,
	Mod2,
	Remi,
	Rem,
	Rem2,
	Shl = 0xB0,
	Shr,
	Sar,
	Shl2,
	Shr2,
	Sar2,
	Push = 0xC0,
	Pop,
	Pushall,
	Popall,
	Pushf,
	Popf,
	Pal = 0xD0,
	Pal2,
	Noti = 0xE0,
	Not,
	Not2,
	Negi,
	Neg,
	Neg2,
}

impl Opcode {
	pub fn execute(&self, cpu: &mut Cpu, byte1: i8, byte2: i8, byte3: i8) {
	    match *self {
		    Nop => nop(),
			Cls => cpu.clear_fg_bg(),
			Vblnk => vblnk(cpu),
			Bgc => cpu.set_bg(byte2 as u8),
			Spr => cpu.set_spr_wh(byte2 as u8, byte3 as u8),
			Drw => nop(),
			Drw2 => nop(),
			Rnd => rnd(cpu, byte1, join_bytes(byte2, byte3)),
			Flip => flip(cpu, byte3),
			Snd0 => nop(),
			Snd1 => nop(),
			Snd2 => nop(),
			Snd3 => nop(),
			Snp => nop(),
			Sng => nop(),
			Jmp => jmp(cpu, join_bytes(byte2, byte3)),
			Jmc => jmc(cpu, join_bytes(byte2, byte3)),
			Jx => jx(cpu, byte1, join_bytes(byte2, byte3)),
			Jme => jme(cpu, separate_byte(byte1), join_bytes(byte2, byte3)),
			Call => call(cpu, join_bytes(byte2, byte3)),
			Ret => ret(cpu),
			Jmp2 => {
				let rx = cpu.get_rx(byte1);
				jmp(cpu, rx)
			},
			Cx => cx(cpu, byte1, join_bytes(byte2, byte3)),
			Call2 => {
				let rx = cpu.get_rx(byte1);
				call(cpu, rx)
			},
			Ldi => ldi(cpu, byte1, join_bytes(byte2, byte3)),
			Ldi2 => ldisp(cpu, join_bytes(byte2, byte3)),
			Ldm => ldm(cpu, byte1, join_bytes(byte2, byte3)),
			Ldm2 => ldmrx(cpu, separate_byte(byte1)),
			Mov => mov(cpu, separate_byte(byte1)),
			Stm => stm(cpu, byte1, join_bytes(byte2, byte3)),
			Stm2 => {
				let (x, y) = separate_byte(byte1);
				ldmrx(cpu, (y, x));
			},
			Addi => addi(cpu, byte1, join_bytes(byte2, byte3)),
			Add => {
				let (y, x) = separate_byte(byte1);
				add(cpu, (y, x), x);
			},
			Add2 => add(cpu, separate_byte(byte1), byte2),
			Subi => subi(cpu, byte1, join_bytes(byte2, byte3)),
			Sub => {
				let (y, x) = separate_byte(byte1);
				sub(cpu, (y, x), x);
			},
			Sub2 => sub(cpu, separate_byte(byte1), byte2),
			Cmpi => {cmpi(cpu, byte1, join_bytes(byte2, byte3));},
			Cmp => {cmp(cpu, separate_byte(byte1));},
			Andi => andi(cpu, byte1, join_bytes(byte2, byte3)),
			And => {
				let (y, x) = separate_byte(byte1);
				and(cpu, (y, x), x);
			},
			And2 => and(cpu, separate_byte(byte1), byte2),
			Tsti => {tsti(cpu, byte1, join_bytes(byte2, byte3));},
			Tst => {tst(cpu, join_bytes(byte2, byte3));},
			Ori => nop(),
			Or => nop(),
			Or2 => nop(),
			Xori => nop(),
			Xor => nop(),
			Xor2 => nop(),
			Muli => nop(),
			Mul => nop(),
			Mul2 => nop(),
			Divi => nop(),
			Div => nop(),
			Div2 => nop(),
			Modi => nop(),
			Mod => nop(),
			Mod2 => nop(),
			Remi => nop(),
			Rem => nop(),
			Rem2 => nop(),
			Shl => nop(),
			Shr => nop(),
			Sar => nop(),
			Shl2 => nop(),
			Shr2 => nop(),
			Sar2 => nop(),
			Push => nop(),
			Pop => nop(),
			Pushall => nop(),
			Popall => nop(),
			Pushf => nop(),
			Popf => nop(),
			Pal => nop(),
			Pal2 => nop(),
			Noti => nop(),
			Not => nop(),
			Not2 => nop(),
			Negi => nop(),
			Neg => nop(),
			Neg2 => nop(),
		}
	}
}

fn nop() -> () {
	()
}

fn vblnk(cpu: &mut Cpu)-> () {
	if !cpu.vblank {
		cpu.pc = cpu.pc - 4
	}
}

fn flip(cpu: &mut Cpu, byte3: i8) -> () {
	cpu.flip(byte3 > 1, byte3.is_odd())
}

fn rnd(cpu: &mut Cpu, rx: i8, max_rand: i16) -> () {
	cpu.set_rx(rx, task_rng().gen_range(0, max_rand as u16) as i16);
}

fn jmp(cpu: &mut Cpu, new_dir: i16) -> () {
	cpu.pc = new_dir;
}

fn jmc(cpu: &mut Cpu, new_dir: i16) -> () {
	if cpu.has_carry() {
		jmp(cpu, new_dir);
	}
}

fn jx(cpu: &mut Cpu, flag_index: i8, new_dir: i16) -> () {
	if cpu.check_flags(flag_index) {
		jmp(cpu, new_dir);
	}
}

fn jme(cpu: &mut Cpu, (y, x): (i8, i8), new_dir: i16) -> () {
	if cpu.get_rx(x) == cpu.get_rx(y) {
		jmp(cpu, new_dir);
	}
}

fn call(cpu: &mut Cpu, new_dir: i16) -> () {
	let pc = cpu.pc;
	cpu.push_stack(pc);
	cpu.pc = new_dir;
}

fn ret(cpu: &mut Cpu) -> () {
	let pc = cpu.pop_stack();
	cpu.pc = pc;
}

fn cx(cpu: &mut Cpu, flag_index: i8, new_dir: i16) -> () {
	if cpu.check_flags(flag_index) {
		call(cpu, new_dir);
	}
}

fn ldi(cpu: &mut Cpu, rx: i8, value: i16) -> () {
	cpu.set_rx(rx, value);
}

fn ldisp(cpu: &mut Cpu, value: i16) -> () {
	cpu.sp = value;
}

fn ldm(cpu: &mut Cpu, rx: i8, dir: i16) -> () {
	let value = cpu.memory.read_word(dir as uint);
	cpu.set_rx(rx, value);
}

fn ldmrx(cpu: &mut Cpu, (y, x): (i8, i8)) -> () {
	let value = cpu.memory.read_word(cpu.get_rx(y) as uint);
	cpu.set_rx(x, value);
}

fn mov(cpu: &mut Cpu, (y, x): (i8, i8)) -> () {
	let value = cpu.get_rx(y);
	cpu.set_rx(x, value);
}

fn stm(cpu: &mut Cpu, rx: i8, dir: i16) -> () {
	let value = cpu.get_rx(rx);
	cpu.memory.write_word(dir as uint, value);
}

fn sign(number: i16) -> int{
	if number > 0 {
		return 1;
	} else if number < 0 {
		return -1;
	} else {
		return 0;
	}
}

fn change_flags_add(cpu: &mut Cpu, original: i16, value: i16, result: i16) -> () {
	cpu.put_carry((original as u32 + value as u32) > (1 << 15));
	cpu.put_zero(result == 0);
	cpu.put_overflow(sign(original) == sign(value) && sign(result) != sign(original));
	cpu.put_negative(result < 0);
}

fn addi(cpu: &mut Cpu, rx:i8, value: i16) -> () {
	let rx_val = cpu.get_rx(rx);
	let result = rx_val + value;
	change_flags_add(cpu, rx_val, value, result);
	cpu.set_rx(rx, value);
}

fn add(cpu: &mut Cpu, (ry, rx): (i8, i8), rz: i8) -> () {
	let rx_val = cpu.get_rx(rx);
	let ry_val = cpu.get_rx(ry);
	let result = rx_val + ry_val;
	change_flags_add(cpu, rx_val, ry_val, result);
	cpu.set_rx(rz, result)
}

fn change_flags_sub(cpu: &mut Cpu, original: i16, value: i16, result: i16) -> () {
	cpu.put_carry((original as u32 - value as u32) > (1 << 15));
	cpu.put_zero(result == 0);
	cpu.put_overflow(sign(original) == sign(value) && sign(result) != sign(original));
	cpu.put_negative(result < 0);
}

fn subi(cpu: &mut Cpu, rx:i8, value: i16) -> () {
	let result = cmpi(cpu, rx, value);
	cpu.set_rx(rx, result);
}

fn sub(cpu: &mut Cpu, (ry, rx): (i8, i8), rz: i8) -> () {
	let result = cmp(cpu, (ry, rx));
	cpu.set_rx(rz, result);
}

fn cmpi(cpu: &mut Cpu, rx:i8, value: i16) -> i16 {
	let rx_val = cpu.get_rx(rx);
	let result = rx_val - value;
	change_flags_sub(cpu, rx_val, value, result);
	result
}

fn cmp(cpu: &mut Cpu, (ry, rx): (i8, i8)) -> i16 {
	let rx_val = cpu.get_rx(rx);
	let ry_val = cpu.get_rx(ry);
	let result = rx_val + ry_val;
	change_flags_sub(cpu, rx_val, ry_val, result);
	result
}

fn change_flags_and(cpu: &mut Cpu, original: i16, value: i16, result: i16) -> () {
	cpu.put_zero(result == 0);
	cpu.put_negative(result < 0);
}

fn andi(cpu: &mut Cpu, rx:i8, value: i16) -> () {
	let result = tsti(cpu, rx, value);
	cpu.set_rx(rx, result);
}

fn and(cpu: &mut Cpu, (ry, rx): (i8, i8), rz: i8) -> () {
	let result = tst(cpu, (ry, rx));
	cpu.set_rx(rz, result);
}

fn tsti(cpu: &mut Cpu, rx:i8, value: i16) -> i16 {
	let rx_val = cpu.get_rx(rx);
	let result = rx_val & value;
	change_flags_and(cpu, rx_val, value, result);
	result
}

fn tst(cpu: &mut Cpu, (ry, rx): (i8, i8)) -> i16 {
	let rx_val = cpu.get_rx(rx);
	let ry_val = cpu.get_rx(ry);
	let result = rx_val & ry_val;
	change_flags_and(cpu, rx_val, ry_val, result);
	result
}<commit_msg>Finished Or and Xor opcodes<commit_after>extern crate num;
use self::num::integer::Integer;
use std::rand::{task_rng, Rng};
use cpu::{Cpu, join_bytes, separate_byte};
use std::mem;

pub fn to_opcode(v: i8) -> Opcode {
    unsafe { mem::transmute(v) }
}

pub enum Opcode {
    Nop = 0,
	Cls,
	Vblnk,
	Bgc,
	Spr,
	Drw,
	Drw2,
	Rnd,
	Flip,
	Snd0,
	Snd1,
	Snd2,
	Snd3,
	Snp,
	Sng,
	Jmp = 0x10,
	Jmc,
	Jx,
	Jme,
	Call,
	Ret,
	Jmp2,
	Cx,
	Call2,
	Ldi = 0x20,
	Ldi2,
	Ldm,
	Ldm2,
	Mov,
	Stm = 0x30,
	Stm2,
	Addi = 0x40,
	Add,
	Add2,
	Subi = 0x50,
	Sub,
	Sub2,
	Cmpi,
	Cmp,
	Andi = 0x60,
	And,
	And2,
	Tsti,
	Tst,
	Ori = 0x70,
	Or,
	Or2,
	Xori = 0x80,
	Xor,
	Xor2,
	Muli = 0x90,
	Mul,
	Mul2,
	Divi = 0xA0,
	Div,
	Div2,
	Modi,
	Mod,
	Mod2,
	Remi,
	Rem,
	Rem2,
	Shl = 0xB0,
	Shr,
	Sar,
	Shl2,
	Shr2,
	Sar2,
	Push = 0xC0,
	Pop,
	Pushall,
	Popall,
	Pushf,
	Popf,
	Pal = 0xD0,
	Pal2,
	Noti = 0xE0,
	Not,
	Not2,
	Negi,
	Neg,
	Neg2,
}

impl Opcode {
	pub fn execute(&self, cpu: &mut Cpu, byte1: i8, byte2: i8, byte3: i8) {
	    match *self {
		    Nop => nop(),
			Cls => cpu.clear_fg_bg(),
			Vblnk => vblnk(cpu),
			Bgc => cpu.set_bg(byte2 as u8),
			Spr => cpu.set_spr_wh(byte2 as u8, byte3 as u8),
			Drw => nop(),
			Drw2 => nop(),
			Rnd => rnd(cpu, byte1, join_bytes(byte2, byte3)),
			Flip => flip(cpu, byte3),
			Snd0 => nop(),
			Snd1 => nop(),
			Snd2 => nop(),
			Snd3 => nop(),
			Snp => nop(),
			Sng => nop(),
			Jmp => jmp(cpu, join_bytes(byte2, byte3)),
			Jmc => jmc(cpu, join_bytes(byte2, byte3)),
			Jx => jx(cpu, byte1, join_bytes(byte2, byte3)),
			Jme => jme(cpu, separate_byte(byte1), join_bytes(byte2, byte3)),
			Call => call(cpu, join_bytes(byte2, byte3)),
			Ret => ret(cpu),
			Jmp2 => {
				let rx = cpu.get_rx(byte1);
				jmp(cpu, rx)
			},
			Cx => cx(cpu, byte1, join_bytes(byte2, byte3)),
			Call2 => {
				let rx = cpu.get_rx(byte1);
				call(cpu, rx)
			},
			Ldi => ldi(cpu, byte1, join_bytes(byte2, byte3)),
			Ldi2 => ldisp(cpu, join_bytes(byte2, byte3)),
			Ldm => ldm(cpu, byte1, join_bytes(byte2, byte3)),
			Ldm2 => ldmrx(cpu, separate_byte(byte1)),
			Mov => mov(cpu, separate_byte(byte1)),
			Stm => stm(cpu, byte1, join_bytes(byte2, byte3)),
			Stm2 => {
				let (x, y) = separate_byte(byte1);
				ldmrx(cpu, (y, x));
			},
			Addi => addi(cpu, byte1, join_bytes(byte2, byte3)),
			Add => {
				let (y, x) = separate_byte(byte1);
				add(cpu, (y, x), x);
			},
			Add2 => add(cpu, separate_byte(byte1), byte2),
			Subi => subi(cpu, byte1, join_bytes(byte2, byte3)),
			Sub => {
				let (y, x) = separate_byte(byte1);
				sub(cpu, (y, x), x);
			},
			Sub2 => sub(cpu, separate_byte(byte1), byte2),
			Cmpi => {cmpi(cpu, byte1, join_bytes(byte2, byte3));},
			Cmp => {cmp(cpu, separate_byte(byte1));},
			Andi => andi(cpu, byte1, join_bytes(byte2, byte3)),
			And => {
				let (y, x) = separate_byte(byte1);
				and(cpu, (y, x), x);
			},
			And2 => and(cpu, separate_byte(byte1), byte2),
			Tsti => {tsti(cpu, byte1, join_bytes(byte2, byte3));},
			Tst => {tst(cpu, separate_byte(byte1));},
			Ori => ori(cpu, byte1, join_bytes(byte2, byte3)),
			Or => {
				let (y, x) = separate_byte(byte1);
				or(cpu, (y, x), x);
			},
			Or2 => or(cpu, separate_byte(byte1), byte2),
			Xori => xori(cpu, byte1, join_bytes(byte2, byte3)),
			Xor => {
				let (y, x) = separate_byte(byte1);
				xor(cpu, (y, x), x);
			},
			Xor2 => xor(cpu, separate_byte(byte1), byte2),
			Muli => nop(),
			Mul => nop(),
			Mul2 => nop(),
			Divi => nop(),
			Div => nop(),
			Div2 => nop(),
			Modi => nop(),
			Mod => nop(),
			Mod2 => nop(),
			Remi => nop(),
			Rem => nop(),
			Rem2 => nop(),
			Shl => nop(),
			Shr => nop(),
			Sar => nop(),
			Shl2 => nop(),
			Shr2 => nop(),
			Sar2 => nop(),
			Push => nop(),
			Pop => nop(),
			Pushall => nop(),
			Popall => nop(),
			Pushf => nop(),
			Popf => nop(),
			Pal => nop(),
			Pal2 => nop(),
			Noti => nop(),
			Not => nop(),
			Not2 => nop(),
			Negi => nop(),
			Neg => nop(),
			Neg2 => nop(),
		}
	}
}

fn nop() -> () {
	()
}

fn vblnk(cpu: &mut Cpu)-> () {
	if !cpu.vblank {
		cpu.pc = cpu.pc - 4
	}
}

fn flip(cpu: &mut Cpu, byte3: i8) -> () {
	cpu.flip(byte3 > 1, byte3.is_odd())
}

fn rnd(cpu: &mut Cpu, rx: i8, max_rand: i16) -> () {
	cpu.set_rx(rx, task_rng().gen_range(0, max_rand as u16) as i16);
}

fn jmp(cpu: &mut Cpu, new_dir: i16) -> () {
	cpu.pc = new_dir;
}

fn jmc(cpu: &mut Cpu, new_dir: i16) -> () {
	if cpu.has_carry() {
		jmp(cpu, new_dir);
	}
}

fn jx(cpu: &mut Cpu, flag_index: i8, new_dir: i16) -> () {
	if cpu.check_flags(flag_index) {
		jmp(cpu, new_dir);
	}
}

fn jme(cpu: &mut Cpu, (y, x): (i8, i8), new_dir: i16) -> () {
	if cpu.get_rx(x) == cpu.get_rx(y) {
		jmp(cpu, new_dir);
	}
}

fn call(cpu: &mut Cpu, new_dir: i16) -> () {
	let pc = cpu.pc;
	cpu.push_stack(pc);
	cpu.pc = new_dir;
}

fn ret(cpu: &mut Cpu) -> () {
	let pc = cpu.pop_stack();
	cpu.pc = pc;
}

fn cx(cpu: &mut Cpu, flag_index: i8, new_dir: i16) -> () {
	if cpu.check_flags(flag_index) {
		call(cpu, new_dir);
	}
}

fn ldi(cpu: &mut Cpu, rx: i8, value: i16) -> () {
	cpu.set_rx(rx, value);
}

fn ldisp(cpu: &mut Cpu, value: i16) -> () {
	cpu.sp = value;
}

fn ldm(cpu: &mut Cpu, rx: i8, dir: i16) -> () {
	let value = cpu.memory.read_word(dir as uint);
	cpu.set_rx(rx, value);
}

fn ldmrx(cpu: &mut Cpu, (y, x): (i8, i8)) -> () {
	let value = cpu.memory.read_word(cpu.get_rx(y) as uint);
	cpu.set_rx(x, value);
}

fn mov(cpu: &mut Cpu, (y, x): (i8, i8)) -> () {
	let value = cpu.get_rx(y);
	cpu.set_rx(x, value);
}

fn stm(cpu: &mut Cpu, rx: i8, dir: i16) -> () {
	let value = cpu.get_rx(rx);
	cpu.memory.write_word(dir as uint, value);
}

fn sign(number: i16) -> int{
	if number > 0 {
		return 1;
	} else if number < 0 {
		return -1;
	} else {
		return 0;
	}
}

fn change_flags_add(cpu: &mut Cpu, original: i16, value: i16, result: i16) -> () {
	cpu.put_carry((original as u32 + value as u32) > (1 << 15));
	cpu.put_zero(result == 0);
	cpu.put_overflow(sign(original) == sign(value) && sign(result) != sign(original));
	cpu.put_negative(result < 0);
}

fn addi(cpu: &mut Cpu, rx:i8, value: i16) -> () {
	let rx_val = cpu.get_rx(rx);
	let result = rx_val + value;
	change_flags_add(cpu, rx_val, value, result);
	cpu.set_rx(rx, value);
}

fn add(cpu: &mut Cpu, (ry, rx): (i8, i8), rz: i8) -> () {
	let rx_val = cpu.get_rx(rx);
	let ry_val = cpu.get_rx(ry);
	let result = rx_val + ry_val;
	change_flags_add(cpu, rx_val, ry_val, result);
	cpu.set_rx(rz, result)
}

fn change_flags_sub(cpu: &mut Cpu, original: i16, value: i16, result: i16) -> () {
	cpu.put_carry((original as u32 - value as u32) > (1 << 15));
	cpu.put_zero(result == 0);
	cpu.put_overflow(sign(original) == sign(value) && sign(result) != sign(original));
	cpu.put_negative(result < 0);
}

fn subi(cpu: &mut Cpu, rx:i8, value: i16) -> () {
	let result = cmpi(cpu, rx, value);
	cpu.set_rx(rx, result);
}

fn sub(cpu: &mut Cpu, (ry, rx): (i8, i8), rz: i8) -> () {
	let result = cmp(cpu, (ry, rx));
	cpu.set_rx(rz, result);
}

fn cmpi(cpu: &mut Cpu, rx:i8, value: i16) -> i16 {
	let rx_val = cpu.get_rx(rx);
	let result = rx_val - value;
	change_flags_sub(cpu, rx_val, value, result);
	result
}

fn cmp(cpu: &mut Cpu, (ry, rx): (i8, i8)) -> i16 {
	let rx_val = cpu.get_rx(rx);
	let ry_val = cpu.get_rx(ry);
	let result = rx_val + ry_val;
	change_flags_sub(cpu, rx_val, ry_val, result);
	result
}

fn change_flags_bitwise(cpu: &mut Cpu, result: i16) -> () {
	cpu.put_zero(result == 0);
	cpu.put_negative(result < 0);
}

fn andi(cpu: &mut Cpu, rx:i8, value: i16) -> () {
	let result = tsti(cpu, rx, value);
	cpu.set_rx(rx, result);
}

fn and(cpu: &mut Cpu, (ry, rx): (i8, i8), rz: i8) -> () {
	let result = tst(cpu, (ry, rx));
	cpu.set_rx(rz, result);
}

fn tsti(cpu: &mut Cpu, rx:i8, value: i16) -> i16 {
	let rx_val = cpu.get_rx(rx);
	let result = rx_val & value;
	change_flags_bitwise(cpu, result);
	result
}

fn tst(cpu: &mut Cpu, (ry, rx): (i8, i8)) -> i16 {
	let rx_val = cpu.get_rx(rx);
	let ry_val = cpu.get_rx(ry);
	let result = rx_val & ry_val;
	change_flags_bitwise(cpu, result);
	result
}

fn ori(cpu: &mut Cpu, rx:i8, value: i16) -> () {
	let rx_val = cpu.get_rx(rx);
	let result = rx_val | value;
	change_flags_bitwise(cpu, result);
	cpu.set_rx(rx, result);
}

fn or(cpu: &mut Cpu, (ry, rx): (i8, i8), rz: i8) -> () {
	let rx_val = cpu.get_rx(rx);
	let ry_val = cpu.get_rx(ry);
	let result = rx_val | ry_val;
	change_flags_bitwise(cpu, result);
	cpu.set_rx(rz, result);
}

fn xori(cpu: &mut Cpu, rx:i8, value: i16) -> () {
	let rx_val = cpu.get_rx(rx);
	let result = rx_val ^ value;
	change_flags_bitwise(cpu, result);
	cpu.set_rx(rx, result);
}

fn xor(cpu: &mut Cpu, (ry, rx): (i8, i8), rz: i8) -> () {
	let rx_val = cpu.get_rx(rx);
	let ry_val = cpu.get_rx(ry);
	let result = rx_val ^ ry_val;
	change_flags_bitwise(cpu, result);
	cpu.set_rx(rz, result);
}<|endoftext|>


<commit_before>pub use self::ProtType::*;

use libc;

use std::ptr;

static mut PAGE_SIZE: u32 = 0;
static mut PAGE_SIZE_BITS: u32 = 0;

#[cfg(target_family = "unix")]
pub fn init_page_size() {
    unsafe {
        let val = libc::sysconf(libc::_SC_PAGESIZE);

        if val <= 0 {
            panic!("could not determine page size.");
        }

        PAGE_SIZE = val as u32;

        assert!((PAGE_SIZE & (PAGE_SIZE - 1)) == 0);

        PAGE_SIZE_BITS = log2(PAGE_SIZE);
    }
}

/// determine log_2 of given value
fn log2(mut val: u32) -> u32 {
    let mut log = 0;

    if (val & 0xFFFF0000) != 0 { val >>= 16; log += 16; }
    if val >= 256 { val >>= 8; log += 8; }
    if val >= 16 { val >>= 4; log += 4; }
    if val >= 4 { val >>= 2; log += 2; }

    log + (val >> 1)
}

#[test]
fn test_log2() {
    assert_eq!(0, log2(0));
    assert_eq!(0, log2(1));
    assert_eq!(1, log2(2));
    assert_eq!(2, log2(4));
    assert_eq!(3, log2(8));
    assert_eq!(4, log2(16));
    assert_eq!(5, log2(32));
    assert_eq!(6, log2(64));
    assert_eq!(7, log2(128));
    assert_eq!(8, log2(256));
    assert_eq!(9, log2(512));
    assert_eq!(10, log2(1024));
    assert_eq!(11, log2(2048));
    assert_eq!(12, log2(4096));
    assert_eq!(16, log2(65536));
    assert_eq!(19, log2(1 << 19));
    assert_eq!(31, log2(1 << 31));
}

#[cfg(target_family = "unix")]
pub fn page_size() -> u32 {
    unsafe { PAGE_SIZE }
}

#[cfg(target_family = "unix")]
pub fn page_size_bits() -> u32 {
    unsafe { PAGE_SIZE_BITS }
}

#[cfg(target_family = "windows")]
pub fn page_size() -> u32 {
    use kernel32::GetSystemInfo;
    use winapi::sysinfoapi::SYSTEM_INFO;
    use std::mem;

    unsafe {
        let mut system_info: SYSTEM_INFO = mem::uninitialized();
        GetSystemInfo(&mut system_info);

        system_info.dwPageSize
    }
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum ProtType {
    Executable,
    Writable,
}

#[cfg(target_family = "unix")]
pub fn mmap(size: usize, exec: ProtType) -> *const u8 {
    let prot_exec = if exec == Executable {
        libc::PROT_EXEC
    } else {
        0
    };

    let ptr = unsafe {
        libc::mmap(ptr::null_mut(),
                   size,
                   libc::PROT_READ | libc::PROT_WRITE | prot_exec,
                   libc::MAP_PRIVATE | libc::MAP_ANON,
                   -1,
                   0) as *mut libc::c_void
    };

    if ptr == libc::MAP_FAILED {
        panic!("mmap failed");
    }

    ptr as *const u8
}

#[cfg(target_family = "windows")]
pub fn mmap(size: usize, exec: ProtType) -> *const u8 {
    use kernel32::VirtualAlloc;
    use winapi::winnt::{MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READWRITE, PAGE_READWRITE};

    let prot = if exec == Executable {
        PAGE_EXECUTE_READWRITE
    } else {
        PAGE_READWRITE
    };

    let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size as u64, MEM_COMMIT | MEM_RESERVE, prot) };

    if ptr.is_null() {
        panic!("VirtualAlloc failed");
    }

    ptr as *const u8
}

#[cfg(target_family = "unix")]
pub fn munmap(ptr: *const u8, size: usize) {
    let res = unsafe { libc::munmap(ptr as *mut libc::c_void, size) };

    if res != 0 {
        panic!("munmap failed");
    }
}

#[cfg(target_family = "windows")]
pub fn munmap(ptr: *const u8, size: usize) {
    use kernel32::VirtualFree;
    use winapi::winnt::MEM_RELEASE;
    use winapi;

    let res = unsafe { VirtualFree(ptr as *mut winapi::c_void, 0, MEM_RELEASE) };

    if res == 0 {
        panic!("VirtualFree failed");
    }
}
<commit_msg>init_page_size should work for windows too<commit_after>pub use self::ProtType::*;

use libc;

use std::ptr;

static mut PAGE_SIZE: u32 = 0;
static mut PAGE_SIZE_BITS: u32 = 0;

pub fn init_page_size() {
    unsafe {
        PAGE_SIZE = determine_page_size();
        assert!((PAGE_SIZE & (PAGE_SIZE - 1)) == 0);

        PAGE_SIZE_BITS = log2(PAGE_SIZE);
    }
}

#[cfg(target_family = "unix")]
fn determine_page_size() -> u32 {
    let val = unsafe {
        libc::sysconf(libc::_SC_PAGESIZE)
    };

    if val <= 0 {
        panic!("could not determine page size.");
    }

    val as u32
}

#[cfg(target_family = "windows")]
pub fn determine_page_size() -> u32 {
    use kernel32::GetSystemInfo;
    use winapi::sysinfoapi::SYSTEM_INFO;
    use std::mem;

    unsafe {
        let mut system_info: SYSTEM_INFO = mem::uninitialized();
        GetSystemInfo(&mut system_info);

        system_info.dwPageSize
    }
}

/// determine log_2 of given value
fn log2(mut val: u32) -> u32 {
    let mut log = 0;

    if (val & 0xFFFF0000) != 0 { val >>= 16; log += 16; }
    if val >= 256 { val >>= 8; log += 8; }
    if val >= 16 { val >>= 4; log += 4; }
    if val >= 4 { val >>= 2; log += 2; }

    log + (val >> 1)
}

#[test]
fn test_log2() {
    assert_eq!(0, log2(0));
    assert_eq!(0, log2(1));
    assert_eq!(1, log2(2));
    assert_eq!(2, log2(4));
    assert_eq!(3, log2(8));
    assert_eq!(4, log2(16));
    assert_eq!(5, log2(32));
    assert_eq!(6, log2(64));
    assert_eq!(7, log2(128));
    assert_eq!(8, log2(256));
    assert_eq!(9, log2(512));
    assert_eq!(10, log2(1024));
    assert_eq!(11, log2(2048));
    assert_eq!(12, log2(4096));
    assert_eq!(16, log2(65536));
    assert_eq!(19, log2(1 << 19));
    assert_eq!(31, log2(1 << 31));
}

pub fn page_size() -> u32 {
    unsafe { PAGE_SIZE }
}

pub fn page_size_bits() -> u32 {
    unsafe { PAGE_SIZE_BITS }
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum ProtType {
    Executable,
    Writable,
}

#[cfg(target_family = "unix")]
pub fn mmap(size: usize, exec: ProtType) -> *const u8 {
    let prot_exec = if exec == Executable {
        libc::PROT_EXEC
    } else {
        0
    };

    let ptr = unsafe {
        libc::mmap(ptr::null_mut(),
                   size,
                   libc::PROT_READ | libc::PROT_WRITE | prot_exec,
                   libc::MAP_PRIVATE | libc::MAP_ANON,
                   -1,
                   0) as *mut libc::c_void
    };

    if ptr == libc::MAP_FAILED {
        panic!("mmap failed");
    }

    ptr as *const u8
}

#[cfg(target_family = "windows")]
pub fn mmap(size: usize, exec: ProtType) -> *const u8 {
    use kernel32::VirtualAlloc;
    use winapi::winnt::{MEM_COMMIT, MEM_RESERVE, PAGE_EXECUTE_READWRITE, PAGE_READWRITE};

    let prot = if exec == Executable {
        PAGE_EXECUTE_READWRITE
    } else {
        PAGE_READWRITE
    };

    let ptr = unsafe { VirtualAlloc(ptr::null_mut(), size as u64, MEM_COMMIT | MEM_RESERVE, prot) };

    if ptr.is_null() {
        panic!("VirtualAlloc failed");
    }

    ptr as *const u8
}

#[cfg(target_family = "unix")]
pub fn munmap(ptr: *const u8, size: usize) {
    let res = unsafe { libc::munmap(ptr as *mut libc::c_void, size) };

    if res != 0 {
        panic!("munmap failed");
    }
}

#[cfg(target_family = "windows")]
pub fn munmap(ptr: *const u8, size: usize) {
    use kernel32::VirtualFree;
    use winapi::winnt::MEM_RELEASE;
    use winapi;

    let res = unsafe { VirtualFree(ptr as *mut winapi::c_void, 0, MEM_RELEASE) };

    if res == 0 {
        panic!("VirtualFree failed");
    }
}
<|endoftext|>


<commit_before>//! Implements the extraction of the principal variation from the
//! transposition table.

use std::cmp::min;
use moves::Move;
use value::*;
use depth::*;
use hash_table::*;
use search_node::SearchNode;

/// A sequence of moves from some starting position, together with the
/// value assigned to the final position.
pub struct Variation {
    /// A sequence of moves from some starting position.
    pub moves: Vec<Move>,

    /// The value assigned to the final position.
    ///
    /// The value is from the point of view of player that has the
    /// move in the starting position.
    pub value: Value,

    /// The accuracy of the assigned value.
    pub bound: BoundType,
}

/// Extracts the principal variation for a given position from the
/// transposition table.
///
/// The principal variation (PV) is the sequence of moves that the
/// engine considers best and therefore expects to be played.
pub fn extract_pv<T: HashTable, N: SearchNode>(tt: &T, position: &N) -> Variation {
    let mut p = position.clone();
    let mut our_turn = true;
    let mut moves = Vec::with_capacity(32);
    let mut root_value = VALUE_UNKNOWN;
    let mut value = VALUE_MAX;
    let mut bound = BOUND_UPPER;
    let mut depth = DEPTH_MAX + 1;

    'move_extraction: while let Some(e) = tt.probe(p.hash()) {
        depth = min(depth - 1, e.depth());

        if e.bound() == BOUND_EXACT || root_value == VALUE_UNKNOWN && e.bound() != BOUND_NONE {
            // In half of the cases the value is from other side's perspective.
            if our_turn {
                value = e.value();
                bound = e.bound();
            } else {
                value = -e.value();
                bound = match e.bound() {
                    BOUND_UPPER => BOUND_LOWER,
                    BOUND_LOWER => BOUND_UPPER,
                    b => b,
                };
            }
            assert!(value != VALUE_UNKNOWN);

            // Set the root value on the first iteration.
            if root_value == VALUE_UNKNOWN {
                root_value = value;
            }

            // Consider adding current entry's hash move to the
            // PV. There are 3 conditions for this:
            //
            // 1) The depth limit has not been reached yet.
            // 2) The value is either exact or a lower bound. This
            //    ensures that the move is either best move or a
            //    refutation move.
            // 3) The value has not diverged from the root value.
            if depth > 0 && bound & BOUND_LOWER != 0 &&
               match root_value {
                v if v < VALUE_EVAL_MIN => v as isize == value as isize + moves.len() as isize,
                v if v > VALUE_EVAL_MAX => v as isize == value as isize - moves.len() as isize,
                v => v == value,
            } {
                // Verify that the hash move is legal.
                if let Some(m) = p.try_move_digest(e.move_digest()) {
                    if p.do_move(m) {
                        moves.push(m);
                        if bound == BOUND_EXACT {
                            our_turn = !our_turn;
                            continue 'move_extraction;
                        }
                    }
                }
            }
        }
        break 'move_extraction;
    }

    Variation {
        value: if root_value != VALUE_UNKNOWN {
            root_value
        } else {
            value
        },
        bound: bound,
        moves: moves,
    }
}
<commit_msg>fix subtle bug in extract_pv()<commit_after>//! Implements the extraction of the principal variation from the
//! transposition table.

use std::cmp::min;
use moves::Move;
use value::*;
use depth::*;
use hash_table::*;
use search_node::SearchNode;

/// A sequence of moves from some starting position, together with the
/// value assigned to the final position.
pub struct Variation {
    /// A sequence of moves from some starting position.
    pub moves: Vec<Move>,

    /// The value assigned to the final position.
    ///
    /// The value is from the point of view of player that has the
    /// move in the starting position.
    pub value: Value,

    /// The accuracy of the assigned value.
    pub bound: BoundType,
}

/// Extracts the principal variation for a given position from the
/// transposition table.
///
/// The principal variation (PV) is the sequence of moves that the
/// engine considers best and therefore expects to be played.
pub fn extract_pv<T: HashTable, N: SearchNode>(tt: &T, position: &N) -> Variation {
    let mut p = position.clone();
    let mut our_turn = true;
    let mut moves = Vec::with_capacity(32);
    let mut root_value = VALUE_UNKNOWN;
    let mut value = VALUE_MAX;
    let mut bound = BOUND_UPPER;
    let mut depth = DEPTH_MAX + 1;

    'move_extraction: while let Some(e) = tt.probe(p.hash()) {
        depth = min(depth - 1, e.depth());

        if e.bound() == BOUND_EXACT || root_value == VALUE_UNKNOWN && e.bound() != BOUND_NONE {
            // In half of the cases the value is from other side's perspective.
            if our_turn {
                value = e.value();
                bound = e.bound();
            } else {
                value = -e.value();
                bound = match e.bound() {
                    BOUND_UPPER => BOUND_LOWER,
                    BOUND_LOWER => BOUND_UPPER,
                    b => b,
                };
            }
            assert!(value != VALUE_UNKNOWN);

            // Set the root value on the first iteration.
            if root_value == VALUE_UNKNOWN {
                root_value = value;
            }

            // Consider adding current entry's hash move to the
            // PV. There are 3 conditions for this:
            //
            // 1) The depth limit has not been reached yet.
            // 2) The move is either best move or a refutation move.
            // 3) The value has not diverged from the root value.
            if depth > 0 && e.bound() & BOUND_LOWER != 0 &&
               match root_value {
                v if v < VALUE_EVAL_MIN => v as isize == value as isize + moves.len() as isize,
                v if v > VALUE_EVAL_MAX => v as isize == value as isize - moves.len() as isize,
                v => v == value,
            } {
                // Verify that the hash move is legal.
                if let Some(m) = p.try_move_digest(e.move_digest()) {
                    if p.do_move(m) {
                        moves.push(m);

                        // Note: we stop expanding the PV on refutation moves.
                        if e.bound() == BOUND_EXACT {
                            our_turn = !our_turn;
                            continue 'move_extraction;
                        }
                    }
                }
            }
        }
        break 'move_extraction;
    }

    Variation {
        value: if root_value != VALUE_UNKNOWN {
            root_value
        } else {
            value
        },
        bound: bound,
        moves: moves,
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate encoding;

use std::borrow::Cow;
use std::default::Default;
use std::error;
use std::fmt;
use std::io;

use self::byteorder::{ByteOrder, BigEndian, LittleEndian};
use self::encoding::label::encoding_from_whatwg_label;
use self::encoding::types::EncodingRef;
use self::encoding::types::DecoderTrap::Strict;

use super::{Catalog, Message};
use super::plurals::Resolver;
use metadata::parse_metadata;

#[allow(non_upper_case_globals)]
static utf8_encoding: EncodingRef = &encoding::codec::utf_8::UTF8Encoding;

/// Represents an error encountered while parsing an MO file.
#[derive(Debug)]
pub enum Error {
    /// An incorrect magic number has been encountered
    BadMagic,
    /// An invalid byte sequence for the given encoding has been encountered
    DecodingError,
    /// An unexpected EOF occured
    Eof,
    /// An I/O error occured
    Io(io::Error),
    /// Incorrect syntax encountered while parsing the meta information
    MalformedMetadata,
    /// Meta information string was not the first string in the catalog
    MisplacedMetadata,
    /// An unknown encoding was specified in the metadata
    UnknownEncoding,
}
// Can not use use `Error::*` as per this issue:
// (https://github.com/rust-lang/rust/issues/4865)
use Error::{BadMagic, DecodingError, Eof, Io, MalformedMetadata, MisplacedMetadata,
            UnknownEncoding};

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            BadMagic => "bad magic number",
            DecodingError => "invalid byte sequence in a string",
            Eof => "unxpected end of file",
            Io(ref err) => err.description(),
            MalformedMetadata => "metadata syntax error",
            MisplacedMetadata => "misplaced metadata",
            UnknownEncoding => "unknown encoding specified",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let self_err: &error::Error = self;
        write!(fmt, "{}", self_err.description())
    }
}

impl From<io::Error> for Error {
    fn from(inner: io::Error) -> Error {
        Io(inner)
    }
}

impl From<Cow<'static, str>> for Error {
    fn from(_: Cow<'static, str>) -> Error {
        DecodingError
    }
}

/// ParseOptions allows setting options for parsing MO catalogs.
///
/// # Examples
/// ```ignore
/// use std::fs::File;
///
/// extern crate encoding;
/// use encoding::all::ISO_8859_1;
///
/// let file = File::open("french.mo").unwrap();
/// let catalog = ParseOptions::new().force_encoding(ISO_8859_1).parse(file).unwrap();
/// ```
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct ParseOptions {
    force_encoding: Option<EncodingRef>,
    force_plural: Option<Box<Fn(u64) -> usize + 'static>>,
}

impl ParseOptions {
    /// Returns a new instance of ParseOptions with default options.
    pub fn new() -> Self {
        Default::default()
    }

    /// Tries to parse the catalog from the given reader using the specified options.
    pub fn parse<R: io::Read>(self, reader: R) -> Result<Catalog, Error> {
        parse_catalog(reader, self)
    }

    /// Forces a use of a specific encoding
    /// when parsing strings from a catalog.
    /// If this option is not enabled,
    /// the parser tries to use the encoding specified in the metadata
    /// or UTF-8 if metadata is non-existent.
    pub fn force_encoding(mut self, encoding: EncodingRef) -> Self {
        self.force_encoding = Some(encoding);
        self
    }

    /// Forces a use of the given plural formula
    /// for deciding the proper plural form for a message.
    /// If this option is not enabled,
    /// the parser uses the default formula
    /// (`n != 1`).
    pub fn force_plural<T: Fn(u64) -> usize + 'static>(mut self, plural: T) -> Self {
        self.force_plural = Some(Box::new(plural));
        self
    }
}

/// According to the given magic number of a MO file,
/// returns the function which reads a `u32` in the relevant endianness.
fn get_read_u32_fn(magic: &[u8]) -> Option<fn(&[u8]) -> u32> {
    if magic == [0xde, 0x12, 0x04, 0x95] {
        Some(LittleEndian::read_u32)
    } else if magic == [0x95, 0x04, 0x12, 0xde] {
        Some(BigEndian::read_u32)
    } else {
        None
    }
}

pub fn parse_catalog<R: io::Read>(mut file: R, opts: ParseOptions) -> Result<Catalog, Error> {
    let mut contents = vec![];
    let n = try!(file.read_to_end(&mut contents));
    if n < 28 {
        return Err(Eof);
    }

    let read_u32 = match get_read_u32_fn(&contents[0..4]) {
        Some(f) => f,
        None => return Err(BadMagic),
    };

    // ignore hashing tables (bytes at 20..28)
    let num_strings = read_u32(&contents[8..12]) as usize;
    let mut off_otable = read_u32(&contents[12..16]) as usize;
    let mut off_ttable = read_u32(&contents[16..20]) as usize;
    if n < off_otable || n < off_ttable {
        return Err(Eof);
    }

    let mut catalog = Catalog::new();
    let resolver = match opts.force_plural {
        Some(func) => Some(Resolver::Function(func)),
        None => None,
    };
    let mut encoding = opts.force_encoding.unwrap_or(utf8_encoding);

    for i in 0..num_strings {
        let id;
        let context;
        let translated: Vec<String>;
        // Parse the original string
        {
            if n < off_otable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_otable..off_otable + 4]) as usize;
            let off = read_u32(&contents[off_otable + 4..off_otable + 8]) as usize;
            // +1 compensates for the ending NUL byte which is not included in length
            if n < off + len + 1 {
                return Err(Eof);
            }
            let mut original = &contents[off..off + len + 1];
            // check for context
            context = match original.iter().position(|x| *x == 4) {
                Some(idx) => {
                    let ctx = &original[..idx];
                    original = &original[idx + 1..];
                    Some(try!(encoding.decode(ctx, Strict)))
                }
                None => None,
            };
            // extract msg_id singular, ignoring the plural
            id = match original.iter().position(|x| *x == 0).map(|i| &original[..i]) {
                Some(b) => try!(encoding.decode(b, Strict)),
                None => return Err(Eof),
            };
            if id == "" && i != 0 {
                return Err(MisplacedMetadata);
            }
        }

        // Parse the translation strings
        {
            if n < off_ttable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_ttable..off_ttable + 4]) as usize;
            let off = read_u32(&contents[off_ttable + 4..off_ttable + 8]) as usize;
            // +1 compensates for the ending NUL byte which is not included in length
            if n < off + len + 1 {
                return Err(Eof);
            }
            translated = try!((&contents[off..off + len])
                                  .split(|x| *x == 0)
                                  .map(|b| encoding.decode(b, Strict))
                                  .collect::<Result<Vec<_>, _>>());
            if id == "" {
                let map = parse_metadata(&*translated[0]).unwrap();
                if let (Some(c), None) = (map.charset(), opts.force_encoding) {
                    encoding = match encoding_from_whatwg_label(c) {
                        Some(enc_ref) => enc_ref,
                        None => return Err(UnknownEncoding),
                    }
                }
            }
        }

        catalog.insert(Message::new(id, context, translated));

        off_otable += 8;
        off_ttable += 8;
    }

    if let Some(r) = resolver {
        catalog.resolver = r;
    }

    Ok(catalog)
}

#[test]
fn test_get_read_u32_fn() {
    use std::mem;

    assert!(get_read_u32_fn(&[]).is_none());
    assert!(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95, 0x00]).is_none());

    {
        let le_ptr: *const ();
        let ret_ptr;
        unsafe {
            le_ptr = mem::transmute(LittleEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95]).unwrap());
        }
        assert_eq!(le_ptr, ret_ptr);
    }

    {
        let be_ptr: *const ();
        let ret_ptr;
        unsafe {
            be_ptr = mem::transmute(BigEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0x95, 0x04, 0x12, 0xde]).unwrap());
        }
        assert_eq!(be_ptr, ret_ptr);
    }
}

#[test]
fn test_parse_catalog() {
    macro_rules! assert_variant {
        ($value:expr, $variant:path) => {
            match $value {
                $variant => (),
                _ => panic!("Expected {:?}, got {:?}", $variant, $value),
            }
        };
    }

    let fluff = [0; 24]; // zeros to pad our magic test cases to satisfy the length requirements

    {
        let mut reader = vec![1u8, 2, 3];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, Eof);
    }

    {
        let mut reader = vec![1u8, 2, 3, 4];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, BadMagic);
    }

    {
        let mut reader = vec![0x95, 0x04, 0x12, 0xde];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let mut reader = vec![0xde, 0x12, 0x04, 0x95];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/1.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 1);
        assert_eq!(catalog.strings["this is context\x04Text"],
                   Message::new("Text", Some("this is context"), vec!["Tekstas", "Tekstai"]));
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/2.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 2);
        assert_eq!(catalog.strings["Image"],
                   Message::new("Image", None, vec!["Nuotrauka", "Nuotraukos"]));
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/invalid_utf8.mo");
        let err = parse_catalog(reader, ParseOptions::new()).unwrap_err();
        assert_variant!(err, DecodingError);
    }
}
<commit_msg>We can now use Error::*<commit_after>extern crate byteorder;
extern crate encoding;

use std::borrow::Cow;
use std::default::Default;
use std::error;
use std::fmt;
use std::io;

use self::byteorder::{ByteOrder, BigEndian, LittleEndian};
use self::encoding::label::encoding_from_whatwg_label;
use self::encoding::types::EncodingRef;
use self::encoding::types::DecoderTrap::Strict;

use super::{Catalog, Message};
use super::plurals::Resolver;
use metadata::parse_metadata;

#[allow(non_upper_case_globals)]
static utf8_encoding: EncodingRef = &encoding::codec::utf_8::UTF8Encoding;

/// Represents an error encountered while parsing an MO file.
#[derive(Debug)]
pub enum Error {
    /// An incorrect magic number has been encountered
    BadMagic,
    /// An invalid byte sequence for the given encoding has been encountered
    DecodingError,
    /// An unexpected EOF occured
    Eof,
    /// An I/O error occured
    Io(io::Error),
    /// Incorrect syntax encountered while parsing the meta information
    MalformedMetadata,
    /// Meta information string was not the first string in the catalog
    MisplacedMetadata,
    /// An unknown encoding was specified in the metadata
    UnknownEncoding,
}
use Error::*;

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            BadMagic => "bad magic number",
            DecodingError => "invalid byte sequence in a string",
            Eof => "unxpected end of file",
            Io(ref err) => err.description(),
            MalformedMetadata => "metadata syntax error",
            MisplacedMetadata => "misplaced metadata",
            UnknownEncoding => "unknown encoding specified",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let self_err: &error::Error = self;
        write!(fmt, "{}", self_err.description())
    }
}

impl From<io::Error> for Error {
    fn from(inner: io::Error) -> Error {
        Io(inner)
    }
}

impl From<Cow<'static, str>> for Error {
    fn from(_: Cow<'static, str>) -> Error {
        DecodingError
    }
}

/// ParseOptions allows setting options for parsing MO catalogs.
///
/// # Examples
/// ```ignore
/// use std::fs::File;
///
/// extern crate encoding;
/// use encoding::all::ISO_8859_1;
///
/// let file = File::open("french.mo").unwrap();
/// let catalog = ParseOptions::new().force_encoding(ISO_8859_1).parse(file).unwrap();
/// ```
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct ParseOptions {
    force_encoding: Option<EncodingRef>,
    force_plural: Option<Box<Fn(u64) -> usize + 'static>>,
}

impl ParseOptions {
    /// Returns a new instance of ParseOptions with default options.
    pub fn new() -> Self {
        Default::default()
    }

    /// Tries to parse the catalog from the given reader using the specified options.
    pub fn parse<R: io::Read>(self, reader: R) -> Result<Catalog, Error> {
        parse_catalog(reader, self)
    }

    /// Forces a use of a specific encoding
    /// when parsing strings from a catalog.
    /// If this option is not enabled,
    /// the parser tries to use the encoding specified in the metadata
    /// or UTF-8 if metadata is non-existent.
    pub fn force_encoding(mut self, encoding: EncodingRef) -> Self {
        self.force_encoding = Some(encoding);
        self
    }

    /// Forces a use of the given plural formula
    /// for deciding the proper plural form for a message.
    /// If this option is not enabled,
    /// the parser uses the default formula
    /// (`n != 1`).
    pub fn force_plural<T: Fn(u64) -> usize + 'static>(mut self, plural: T) -> Self {
        self.force_plural = Some(Box::new(plural));
        self
    }
}

/// According to the given magic number of a MO file,
/// returns the function which reads a `u32` in the relevant endianness.
fn get_read_u32_fn(magic: &[u8]) -> Option<fn(&[u8]) -> u32> {
    if magic == [0xde, 0x12, 0x04, 0x95] {
        Some(LittleEndian::read_u32)
    } else if magic == [0x95, 0x04, 0x12, 0xde] {
        Some(BigEndian::read_u32)
    } else {
        None
    }
}

pub fn parse_catalog<R: io::Read>(mut file: R, opts: ParseOptions) -> Result<Catalog, Error> {
    let mut contents = vec![];
    let n = try!(file.read_to_end(&mut contents));
    if n < 28 {
        return Err(Eof);
    }

    let read_u32 = match get_read_u32_fn(&contents[0..4]) {
        Some(f) => f,
        None => return Err(BadMagic),
    };

    // ignore hashing tables (bytes at 20..28)
    let num_strings = read_u32(&contents[8..12]) as usize;
    let mut off_otable = read_u32(&contents[12..16]) as usize;
    let mut off_ttable = read_u32(&contents[16..20]) as usize;
    if n < off_otable || n < off_ttable {
        return Err(Eof);
    }

    let mut catalog = Catalog::new();
    let resolver = match opts.force_plural {
        Some(func) => Some(Resolver::Function(func)),
        None => None,
    };
    let mut encoding = opts.force_encoding.unwrap_or(utf8_encoding);

    for i in 0..num_strings {
        let id;
        let context;
        let translated: Vec<String>;
        // Parse the original string
        {
            if n < off_otable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_otable..off_otable + 4]) as usize;
            let off = read_u32(&contents[off_otable + 4..off_otable + 8]) as usize;
            // +1 compensates for the ending NUL byte which is not included in length
            if n < off + len + 1 {
                return Err(Eof);
            }
            let mut original = &contents[off..off + len + 1];
            // check for context
            context = match original.iter().position(|x| *x == 4) {
                Some(idx) => {
                    let ctx = &original[..idx];
                    original = &original[idx + 1..];
                    Some(try!(encoding.decode(ctx, Strict)))
                }
                None => None,
            };
            // extract msg_id singular, ignoring the plural
            id = match original.iter().position(|x| *x == 0).map(|i| &original[..i]) {
                Some(b) => try!(encoding.decode(b, Strict)),
                None => return Err(Eof),
            };
            if id == "" && i != 0 {
                return Err(MisplacedMetadata);
            }
        }

        // Parse the translation strings
        {
            if n < off_ttable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_ttable..off_ttable + 4]) as usize;
            let off = read_u32(&contents[off_ttable + 4..off_ttable + 8]) as usize;
            // +1 compensates for the ending NUL byte which is not included in length
            if n < off + len + 1 {
                return Err(Eof);
            }
            translated = try!((&contents[off..off + len])
                                  .split(|x| *x == 0)
                                  .map(|b| encoding.decode(b, Strict))
                                  .collect::<Result<Vec<_>, _>>());
            if id == "" {
                let map = parse_metadata(&*translated[0]).unwrap();
                if let (Some(c), None) = (map.charset(), opts.force_encoding) {
                    encoding = match encoding_from_whatwg_label(c) {
                        Some(enc_ref) => enc_ref,
                        None => return Err(UnknownEncoding),
                    }
                }
            }
        }

        catalog.insert(Message::new(id, context, translated));

        off_otable += 8;
        off_ttable += 8;
    }

    if let Some(r) = resolver {
        catalog.resolver = r;
    }

    Ok(catalog)
}

#[test]
fn test_get_read_u32_fn() {
    use std::mem;

    assert!(get_read_u32_fn(&[]).is_none());
    assert!(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95, 0x00]).is_none());

    {
        let le_ptr: *const ();
        let ret_ptr;
        unsafe {
            le_ptr = mem::transmute(LittleEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95]).unwrap());
        }
        assert_eq!(le_ptr, ret_ptr);
    }

    {
        let be_ptr: *const ();
        let ret_ptr;
        unsafe {
            be_ptr = mem::transmute(BigEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0x95, 0x04, 0x12, 0xde]).unwrap());
        }
        assert_eq!(be_ptr, ret_ptr);
    }
}

#[test]
fn test_parse_catalog() {
    macro_rules! assert_variant {
        ($value:expr, $variant:path) => {
            match $value {
                $variant => (),
                _ => panic!("Expected {:?}, got {:?}", $variant, $value),
            }
        };
    }

    let fluff = [0; 24]; // zeros to pad our magic test cases to satisfy the length requirements

    {
        let mut reader = vec![1u8, 2, 3];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, Eof);
    }

    {
        let mut reader = vec![1u8, 2, 3, 4];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, BadMagic);
    }

    {
        let mut reader = vec![0x95, 0x04, 0x12, 0xde];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let mut reader = vec![0xde, 0x12, 0x04, 0x95];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/1.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 1);
        assert_eq!(catalog.strings["this is context\x04Text"],
                   Message::new("Text", Some("this is context"), vec!["Tekstas", "Tekstai"]));
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/2.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 2);
        assert_eq!(catalog.strings["Image"],
                   Message::new("Image", None, vec!["Nuotrauka", "Nuotraukos"]));
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/invalid_utf8.mo");
        let err = parse_catalog(reader, ParseOptions::new()).unwrap_err();
        assert_variant!(err, DecodingError);
    }
}
<|endoftext|>


<commit_before>pub struct Parser<'a>
{
   stream: StrStream<'a>
}

pub type ParseError = String;

impl<'a> Parser<'a>
{
   pub fn new(input: &str) -> Parser
   {
      Parser {stream: StrStream::new(input)}
   }

   pub fn skip(&mut self, str: &str) -> Result<bool, ParseError>
   {
      if str.is_empty() {
         return Err("Couldn't skip empty str!".to_string());
      }

      self.push_pos();
      let mut str_stream = StrStream::new(str);
      while ! self.stream.eof() && ! str_stream.eof() {
         if self.stream.next_char() != str_stream.next_char() {
            self.pop_and_reset_pos();
            return Err(format!("Couldn't skip str '{}'!", str));
         }

         self.stream.take_char();
         str_stream.take_char();
      }

      self.pop_pos();
      Ok(true)
   }

   pub fn skip_while(&mut self, test: |char| -> bool)
   {
      while ! self.eof() && test(self.next_char()) {
         self.take_char();
      }
   }

   pub fn skip_whitespace(&mut self)
   {
      self.skip_while(|c| c.is_whitespace());
   }

   pub fn take_while(&mut self, test: |char| -> bool) -> Result<String, ParseError>
   {
      let mut string = String::new();
      while ! self.eof() {
         if ! test(self.next_char()) {
            return Ok(string);
         }

         string.push(self.take_char());
      }

      Ok(string)
   }

   pub fn take_uint(&mut self) -> Result<uint, ParseError>
   {
      self.push_pos();
      let mut digits = String::new();
      while ! self.eof() && self.next_char().is_digit() {
         digits.push(self.take_char());
      }

      match from_str::<uint>(digits.as_slice()) {
         Some(uint) => {
            self.pop_pos();
            Ok(uint)
         }

         None => {
            self.pop_and_reset_pos();
            Err("Couldn't take uint!".to_string())
         }
      }
   }

   pub fn take_till_eof(&mut self) -> Result<String, ParseError>
   {
      let mut string = String::new();
      while ! self.eof() {
         string.push(self.take_char());
      }

      Ok(string)
   }

   pub fn eof(&self) -> bool
   {
      self.stream.eof()
   }

   fn take_char(&mut self) -> char
   {
      self.stream.take_char()
   }

   fn next_char(&self) -> char
   {
      self.stream.next_char()
   }

   fn push_pos(&mut self)
   {
      self.stream.push_pos();
   }

   fn pop_pos(&mut self)
   {
      self.stream.pop_pos();
   }

   fn pop_and_reset_pos(&mut self)
   {
      self.stream.pop_and_reset_pos();
   }
}

struct StrStream<'a>
{
   pos      :  uint,
   input    :  &'a str,
   pos_stack:  Vec<uint>
}

impl<'a> StrStream<'a>
{
   fn new(input: &str) -> StrStream
   {
      StrStream {pos: 0u, input: input, pos_stack: Vec::new()}
   }

   fn eof(&self) -> bool
   {
      self.pos >= self.input.len()
   }

   fn take_char(&mut self) -> char
   {
      let range = self.input.char_range_at(self.pos);
      self.pos = range.next;
      return range.ch;
   }

   fn next_char(&self) -> char
   {
      self.input.char_at(self.pos)
   }

   fn push_pos(&mut self)
   {
      self.pos_stack.push(self.pos);
   }

   fn pop_pos(&mut self)
   {
      self.pos_stack.pop();
   }

   fn pop_and_reset_pos(&mut self)
   {
      self.pos_stack.pop().map(|p| self.pos = p);
   }
}
<commit_msg>Minor reformating<commit_after>pub struct Parser<'a>
{
   stream: StrStream<'a>
}

pub type ParseError = String;

impl<'a> Parser<'a>
{
   pub fn new(input: &str) -> Parser
   {
      Parser {stream: StrStream::new(input)}
   }

   pub fn skip(&mut self, str: &str) -> Result<bool, ParseError>
   {
      if str.is_empty() {
         return Err("Couldn't skip empty str!".to_string());
      }

      self.push_pos();
      let mut str_stream = StrStream::new(str);
      while ! self.stream.eof() && ! str_stream.eof() {
         if self.stream.next_char() != str_stream.next_char() {
            self.pop_and_reset_pos();
            return Err(format!("Couldn't skip str '{}'!", str));
         }

         self.stream.take_char();
         str_stream.take_char();
      }

      self.pop_pos();
      Ok(true)
   }

   pub fn skip_while(&mut self, test: |char| -> bool)
   {
      while ! self.eof() && test(self.next_char()) {
         self.take_char();
      }
   }

   pub fn skip_whitespace(&mut self)
   {
      self.skip_while(|c| c.is_whitespace());
   }

   pub fn take_while(&mut self, test: |char| -> bool) -> Result<String, ParseError>
   {
      let mut string = String::new();
      while ! self.eof() {
         if ! test(self.next_char()) {
            return Ok(string);
         }

         string.push(self.take_char());
      }

      Ok(string)
   }

   pub fn take_uint(&mut self) -> Result<uint, ParseError>
   {
      self.push_pos();
      let mut digits = String::new();
      while ! self.eof() && self.next_char().is_digit() {
         digits.push(self.take_char());
      }

      match from_str::<uint>(digits.as_slice()) {
         Some(uint) => {
            self.pop_pos();
            Ok(uint)
         }

         None => {
            self.pop_and_reset_pos();
            Err("Couldn't take uint!".to_string())
         }
      }
   }

   pub fn take_till_eof(&mut self) -> Result<String, ParseError>
   {
      let mut string = String::new();
      while ! self.eof() {
         string.push(self.take_char());
      }

      Ok(string)
   }

   pub fn eof(&self) -> bool { self.stream.eof() }

   fn take_char(&mut self) -> char { self.stream.take_char() }

   fn next_char(&self) -> char { self.stream.next_char() }

   fn push_pos(&mut self) { self.stream.push_pos(); }

   fn pop_pos(&mut self) { self.stream.pop_pos(); }

   fn pop_and_reset_pos(&mut self) { self.stream.pop_and_reset_pos(); }
}

struct StrStream<'a>
{
   pos      :  uint,
   input    :  &'a str,
   pos_stack:  Vec<uint>
}

impl<'a> StrStream<'a>
{
   fn new(input: &str) -> StrStream
   {
      StrStream {pos: 0u, input: input, pos_stack: Vec::new()}
   }

   fn eof(&self) -> bool { self.pos >= self.input.len() }

   fn take_char(&mut self) -> char
   {
      let range = self.input.char_range_at(self.pos);
      self.pos = range.next;
      return range.ch;
   }

   fn next_char(&self) -> char { self.input.char_at(self.pos) }

   fn push_pos(&mut self) { self.pos_stack.push(self.pos); }

   fn pop_pos(&mut self) { self.pos_stack.pop(); }

   fn pop_and_reset_pos(&mut self) { self.pos_stack.pop().map(|p| self.pos = p); }
}
<|endoftext|>


<commit_before>use std::str::from_utf8;
use nom::IResult;

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     & 'a str,
    pub mode:     & 'a str,
    pub uid:      u64,
    pub gid:      u64,
    pub size:     u64,
    pub mtime:    u64,
    pub chksum:   & 'a str,
    pub typeflag: char, /* TODO: enum */
    pub linkname: & 'a str,
    pub ustar:    Option<UStarHeader<'a>>
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    & 'a str,
    pub version:  & 'a str,
    pub uname:    & 'a str,
    pub gname:    & 'a str,
    pub devmajor: & 'a str,
    pub devminor: & 'a str,
    pub prefix:   & 'a str,
}

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: & 'a str
}

/* TODO: validation */
fn str_to_u64(s: &str, base: u64) -> u64 {
    let mut u = 0;
    let mut f = 1;

    for c in s.chars().rev().skip_while(|&c| c == '\0') {
        u += f * ((c as u64) - ('0' as u64));
        f *= base;
    }

    u
}

pub fn octal_to_u64(o: &str) -> u64 {
    str_to_u64(o, 8)
}

fn parse_ustar(i: &[u8]) -> IResult<&[u8], Option<UStarHeader>> {
    chain!(i,
        magic:    take_str!(6)  ~
        version:  take_str!(2)  ~
        uname:    take_str!(32) ~
        gname:    take_str!(32) ~
        devmajor: take_str!(8)  ~
        devminor: take_str!(8)  ~
        prefix:   take_str!(155),
        ||{
            match magic {
                "ustar" => Some(UStarHeader {
                    magic:    magic,
                    version:  version,
                    uname:    uname,
                    gname:    gname,
                    devmajor: devmajor,
                    devminor: devminor,
                    prefix:   prefix
                }),
                _ => None,
            }
        }
    )
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     take_str!(100) ~
        mode:     take_str!(8)   ~
        uid:      take_str!(8)   ~
        gid:      take_str!(8)   ~
        size:     take_str!(12)  ~
        mtime:    take_str!(12)  ~
        chksum:   take_str!(8)   ~
        typeflag: take!(1)       ~
        linkname: take_str!(100) ~
        ustar:    parse_ustar    ~
        take!(12), /* padding to 512 */
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      octal_to_u64(uid),
                gid:      octal_to_u64(gid),
                size:     octal_to_u64(size),
                mtime:    octal_to_u64(mtime), /* TODO: u64 */
                chksum:   chksum,
                typeflag: typeflag[0] as char,
                linkname: linkname,
                ustar:    ustar
            }
        }
    )
}

fn parse_contents(i: &[u8], size: u64) -> IResult<&[u8], &str> {
    let trailing = size % 512;
    let padding = match trailing {
        0 => 0,
        t => 512 - t
    };
    chain!(i,
        contents: take_str!(size as usize) ~
        take!(padding as usize),
        ||{
            contents
        }
    )
}

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header:   parse_header ~
        contents: apply!(parse_contents, header.size),
        ||{
            TarEntry {
                header: header,
                contents: contents
            }
        }
    )
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    many0!(i, parse_entry)
}

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

    #[test]
    fn octal_to_u64_test() {
        match octal_to_u64("756") {
            494 => {},
            o => panic!("octal_to_u64 failed, expected 494 but got {}", o)
        }
        match octal_to_u64("") {
            0 => {},
            o => panic!("octal_to_u64 failed, expected 0 but got {}", o)
        }
    }
}
<commit_msg>fix ustar<commit_after>use std::str::from_utf8;
use nom::IResult;

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     & 'a str,
    pub mode:     & 'a str,
    pub uid:      u64,
    pub gid:      u64,
    pub size:     u64,
    pub mtime:    u64,
    pub chksum:   & 'a str,
    pub typeflag: char, /* TODO: enum */
    pub linkname: & 'a str,
    pub ustar:    Option<UStarHeader<'a>>
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    & 'a str,
    pub version:  & 'a str,
    pub uname:    & 'a str,
    pub gname:    & 'a str,
    pub devmajor: & 'a str,
    pub devminor: & 'a str,
    pub prefix:   & 'a str,
}

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: & 'a str
}

/* TODO: validation */
fn str_to_u64(s: &str, base: u64) -> u64 {
    let mut u = 0;
    let mut f = 1;

    for c in s.chars().rev().skip_while(|&c| c == '\0') {
        u += f * ((c as u64) - ('0' as u64));
        f *= base;
    }

    u
}

pub fn octal_to_u64(o: &str) -> u64 {
    str_to_u64(o, 8)
}

fn parse_ustar(i: &[u8]) -> IResult<&[u8], Option<UStarHeader>> {
    chain!(i,
        magic:    take_str!(6)  ~
        version:  take_str!(2)  ~
        uname:    take_str!(32) ~
        gname:    take_str!(32) ~
        devmajor: take_str!(8)  ~
        devminor: take_str!(8)  ~
        prefix:   take_str!(155),
        ||{
            match magic {
                "ustar\0" => Some(UStarHeader {
                    magic:    magic,
                    version:  version,
                    uname:    uname,
                    gname:    gname,
                    devmajor: devmajor,
                    devminor: devminor,
                    prefix:   prefix
                }),
                _ => None,
            }
        }
    )
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     take_str!(100) ~
        mode:     take_str!(8)   ~
        uid:      take_str!(8)   ~
        gid:      take_str!(8)   ~
        size:     take_str!(12)  ~
        mtime:    take_str!(12)  ~
        chksum:   take_str!(8)   ~
        typeflag: take!(1)       ~
        linkname: take_str!(100) ~
        ustar:    parse_ustar    ~
        take!(12), /* padding to 512 */
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      octal_to_u64(uid),
                gid:      octal_to_u64(gid),
                size:     octal_to_u64(size),
                mtime:    octal_to_u64(mtime), /* TODO: u64 */
                chksum:   chksum,
                typeflag: typeflag[0] as char,
                linkname: linkname,
                ustar:    ustar
            }
        }
    )
}

fn parse_contents(i: &[u8], size: u64) -> IResult<&[u8], &str> {
    let trailing = size % 512;
    let padding = match trailing {
        0 => 0,
        t => 512 - t
    };
    chain!(i,
        contents: take_str!(size as usize) ~
        take!(padding as usize),
        ||{
            contents
        }
    )
}

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header:   parse_header ~
        contents: apply!(parse_contents, header.size),
        ||{
            TarEntry {
                header: header,
                contents: contents
            }
        }
    )
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    many0!(i, parse_entry)
}

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

    #[test]
    fn octal_to_u64_test() {
        match octal_to_u64("756") {
            494 => {},
            o => panic!("octal_to_u64 failed, expected 494 but got {}", o)
        }
        match octal_to_u64("") {
            0 => {},
            o => panic!("octal_to_u64 failed, expected 0 but got {}", o)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use libc::c_uint;
use std::ptr;
use ffi;
use glib::translate::{from_glib_none};
use glib::{to_bool, to_gboolean};

pub fn init() -> Result<(), ()> {
    unsafe {
	match to_bool(ffi::gtk_init_check(ptr::null(), ptr::null())) {
	    true => Ok(()),
	    false => Err(())
	}
    }
}

pub fn main() {
    unsafe {
        ffi::gtk_main();
    }
}

pub fn main_quit() {
    unsafe {
        ffi::gtk_main_quit();
    }
}

pub fn main_level() -> u32 {
    unsafe {
        ffi::gtk_main_level() as u32
    }
}

pub fn main_iteration() -> bool {
    unsafe { to_bool(ffi::gtk_main_iteration()) }
}

pub fn main_iteration_do(blocking: bool) -> bool {
    unsafe { to_bool(ffi::gtk_main_iteration_do(to_gboolean(blocking))) }
}

pub fn events_pending() -> bool {
    unsafe {
        to_bool(ffi::gtk_events_pending())
    }
}

pub fn get_major_version() -> u32 {
    unsafe {
        ffi::gtk_get_major_version() as u32
    }
}

pub fn get_minor_version() -> u32 {
    unsafe {
        ffi::gtk_get_minor_version() as u32
    }
}

pub fn get_micro_version() -> u32 {
    unsafe {
        ffi::gtk_get_micro_version() as u32
    }
}

pub fn get_binary_age() -> u32 {
    unsafe {
        ffi::gtk_get_binary_age() as u32
    }
}

pub fn get_interface_age() -> u32 {
    unsafe {
        ffi::gtk_get_interface_age() as u32
    }
}

pub fn check_version(required_major: u32, required_minor: u32, required_micro: u32) -> Option<String> {
    unsafe {
        from_glib_none(
            ffi::gtk_check_version(required_major as c_uint, required_minor as c_uint, required_micro as c_uint))
    }
 }
<commit_msg>Add comment to gtk::init() highlighting the difference in behaviour compared to gtk_init()<commit_after>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use libc::c_uint;
use std::ptr;
use ffi;
use glib::translate::{from_glib_none};
use glib::{to_bool, to_gboolean};

/// Call this function before using any other GTK+ functions.
/// Note that this function calls gtk_init_check() rather than gtk_init(),
/// so will not cause the program to terminate if GTK could not be initialized.
pub fn init() -> Result<(), ()> {
    unsafe {
	match to_bool(ffi::gtk_init_check(ptr::null(), ptr::null())) {
	    true => Ok(()),
	    false => Err(())
	}
    }
}

pub fn main() {
    unsafe {
        ffi::gtk_main();
    }
}

pub fn main_quit() {
    unsafe {
        ffi::gtk_main_quit();
    }
}

pub fn main_level() -> u32 {
    unsafe {
        ffi::gtk_main_level() as u32
    }
}

pub fn main_iteration() -> bool {
    unsafe { to_bool(ffi::gtk_main_iteration()) }
}

pub fn main_iteration_do(blocking: bool) -> bool {
    unsafe { to_bool(ffi::gtk_main_iteration_do(to_gboolean(blocking))) }
}

pub fn events_pending() -> bool {
    unsafe {
        to_bool(ffi::gtk_events_pending())
    }
}

pub fn get_major_version() -> u32 {
    unsafe {
        ffi::gtk_get_major_version() as u32
    }
}

pub fn get_minor_version() -> u32 {
    unsafe {
        ffi::gtk_get_minor_version() as u32
    }
}

pub fn get_micro_version() -> u32 {
    unsafe {
        ffi::gtk_get_micro_version() as u32
    }
}

pub fn get_binary_age() -> u32 {
    unsafe {
        ffi::gtk_get_binary_age() as u32
    }
}

pub fn get_interface_age() -> u32 {
    unsafe {
        ffi::gtk_get_interface_age() as u32
    }
}

pub fn check_version(required_major: u32, required_minor: u32, required_micro: u32) -> Option<String> {
    unsafe {
        from_glib_none(
            ffi::gtk_check_version(required_major as c_uint, required_minor as c_uint, required_micro as c_uint))
    }
 }
<|endoftext|>


<commit_before>use std::ptr::{Unique, self};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::marker::PhantomData;
use std::heap::{Alloc, Layout, Heap};
use std::sync::atomic::{AtomicUsize,AtomicU16};

use piece_move::BitMove;

pub type Key = u64;

// 2 bytes + 2 bytes + 1 Byte + 1 byte = ?6 Bytes
#[derive(Clone)]
pub struct Entry {
    pub partial_key: u16,
    pub best_move: BitMove, // What was the best move found here?
    pub score: i16, // What was the Score of this node?
    pub eval: i16, // What is the evaluation of this node
    pub depth: u8, // How deep was this Score Found?
    pub time_node_bound: NodeTypeTimeBound,
}

impl Entry {
    pub fn place(&mut self, key: Key, best_move: BitMove, score: i16, eval: i16, depth: u8, node_type: NodeType, time_bound: u8) {
        let partial_key = key.wrapping_shr(48) as u16;

        if partial_key != self.partial_key {
            self.best_move = best_move;
        }

        if partial_key != self.partial_key || node_type == NodeType::Exact {
            self.partial_key = partial_key;
            self.score = score;
            self.eval = eval;
            self.depth = depth;
            self.time_node_bound = NodeTypeTimeBound::create(node_type, time_bound);
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq)]
pub struct NodeTypeTimeBound {
    data: u8
}

impl NodeTypeTimeBound {
    pub fn create(node_type: NodeType, time_bound: u8) -> Self {
        NodeTypeTimeBound {
            data: time_bound + (node_type as u8)
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq)]
#[repr(u8)]
pub enum NodeType {
    NoBound = 0,
    LowerBound = 1,
    UpperBound = 2,
    Exact = 3,
}

pub const CLUSTER_SIZE: usize = 3;

pub struct Cluster {
    pub entry: [Entry; CLUSTER_SIZE],
    pub padding: [u8; 2],
}

pub struct TT {
    clusters: Unique<Cluster>,
    cap: usize,
    time_age: u8,
}

impl TT {
    pub fn new_round_up(size: usize) -> Self {
        TT::new(size.next_power_of_two())
    }

    pub fn new(size: usize) -> Self {
        assert_eq!(size.count_ones(), 1);
        assert!(size > 0);
        TT {
            clusters: alloc_room(size),
            cap: size,
            time_age: 0,
        }

    }

    pub fn resize_round_up(self, size: usize) {
        self.resize(size.next_power_of_two());
    }

    pub fn resize(&self, size: usize) {
        assert_eq!(size.count_ones(), 1);
        assert!(size > 0);
        self.de_alloc();
        self.re_alloc(size);
    }

    pub fn clear(&self) {
        self.resize(self.cap);
    }

    fn re_alloc(&self, size: usize) {
        unsafe {
            let clust_ptr: *mut Unique<Cluster> = mem::transmute::<&Unique<Cluster>,*mut Unique<Cluster>>(&self.clusters);
            *clust_ptr = alloc_room(size);
        }
    }

    pub fn new_search(&mut self) {
        self.time_age += 8;
    }

    pub fn time_age(&self) -> u8 {
        self.time_age
    }

    pub fn probe(&self, key: Key) -> (bool, *mut Entry) {
        unimplemented!()
    }

    pub fn first_entry(key: Key) -> *mut Entry {
        unimplemented!()
    }

    fn de_alloc(&self) {
        unsafe {
            Heap.dealloc(self.clusters.as_ptr() as *mut _,
                         Layout::array::<Cluster>(self.cap).unwrap());
        }
    }
}

impl Drop for TT {
    fn drop(&mut self) {
        self.de_alloc();
    }
}

fn alloc_room(size: usize) -> Unique<Cluster> {
    unsafe {
        let ptr = Heap.alloc_zeroed(Layout::array::<Cluster>(size).unwrap());

        let new_ptr = match ptr {
            Ok(ptr) => ptr,
            Err(err) => Heap.oom(err),
        };
        Unique::new(new_ptr as *mut Cluster).unwrap()
    }

}

<commit_msg>Forgot the lazy SMP, oops<commit_after>use std::ptr::{Unique, self};
use std::mem;
use std::ops::{Deref, DerefMut};
use std::marker::PhantomData;
use std::heap::{Alloc, Layout, Heap};
use std::sync::atomic::{AtomicUsize,AtomicU16};

use piece_move::BitMove;

pub type Key = u64;

// 2 bytes + 2 bytes + 1 Byte + 1 byte = ?6 Bytes
#[derive(Clone)]
pub struct Entry {
    pub partial_key: u16,
    pub best_move: BitMove, // What was the best move found here?
    pub score: i16, // What was the Score of this node?
    pub eval: i16, // What is the evaluation of this node
    pub depth: u8, // How deep was this Score Found?
    pub time_node_bound: NodeTypeTimeBound,
}

impl Entry {
    pub fn place(&mut self, key: Key, best_move: BitMove, score: i16, eval: i16, depth: u8, node_type: NodeType, time_bound: u8) {
        let partial_key = key.wrapping_shr(48) as u16;

        if partial_key != self.partial_key {
            self.best_move = best_move;
        }

        if partial_key != self.partial_key || node_type == NodeType::Exact {
            self.partial_key = partial_key;
            self.score = score;
            self.eval = eval;
            self.depth = depth;
            self.time_node_bound = NodeTypeTimeBound::create(node_type, time_bound);
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq)]
pub struct NodeTypeTimeBound {
    data: u8
}

impl NodeTypeTimeBound {
    pub fn create(node_type: NodeType, time_bound: u8) -> Self {
        NodeTypeTimeBound {
            data: time_bound + (node_type as u8)
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq)]
#[repr(u8)]
pub enum NodeType {
    NoBound = 0,
    LowerBound = 1,
    UpperBound = 2,
    Exact = 3,
}

pub const CLUSTER_SIZE: usize = 3;

pub struct Cluster {
    pub entry: [Entry; CLUSTER_SIZE],
    pub padding: [u8; 2],
}

pub struct TT {
    clusters: Unique<Cluster>,
    cap: usize,
    time_age: u8,
}

impl TT {
    pub fn new_round_up(size: usize) -> Self {
        TT::new(size.next_power_of_two())
    }

    pub fn new(size: usize) -> Self {
        assert_eq!(size.count_ones(), 1);
        assert!(size > 0);
        TT {
            clusters: alloc_room(size),
            cap: size,
            time_age: 0,
        }

    }

    pub fn resize_round_up(self, size: usize) {
        self.resize(size.next_power_of_two());
    }

    pub fn resize(&self, size: usize) {
        assert_eq!(size.count_ones(), 1);
        assert!(size > 0);
        self.de_alloc();
        self.re_alloc(size);
    }

    pub fn clear(&self) {
        self.resize(self.cap);
    }

    fn re_alloc(&self, size: usize) {
        unsafe {
            let clust_ptr: *mut Unique<Cluster> = mem::transmute::<&Unique<Cluster>,*mut Unique<Cluster>>(&self.clusters);
            *clust_ptr = alloc_room(size);
        }
    }

    pub fn new_search(&mut self) {
        self.time_age += 8;
    }

    pub fn time_age(&self) -> u8 {
        self.time_age
    }

    pub fn probe(&self, key: Key) -> (bool, *mut Entry) {
        unimplemented!()
    }

    pub fn first_entry(key: Key) -> *mut Entry {
        unimplemented!()
    }

    fn de_alloc(&self) {
        unsafe {
            Heap.dealloc(self.clusters.as_ptr() as *mut _,
                         Layout::array::<Cluster>(self.cap).unwrap());
        }
    }
}

impl Drop for TT {
    fn drop(&mut self) {
        self.de_alloc();
    }
}

fn alloc_room(size: usize) -> Unique<Cluster> {
    unsafe {
        let ptr = Heap.alloc_zeroed(Layout::array::<Cluster>(size).unwrap());

        let new_ptr = match ptr {
            Ok(ptr) => ptr,
            Err(err) => Heap.oom(err),
        };
        Unique::new(new_ptr as *mut Cluster).unwrap()
    }

}

<|endoftext|>