<commit_before>use std::rand::random;
use graphics::Graphics;
/* CPU, Graphics and Memory core */

mod graphics;

//enum mode = {SCHIP, CHIP}; /* differentiate between CHIP and SCHIP modes */

static U12_MAX : u16 = 4096;
static FLAG : uint = 15;

struct CPU {
    registers : [u8, ..16], /* 16 8 bit general purpose registers */
    mem : [u8, .. 0xFFF], /* 4096bytes of memory */
    I : u16, /* 16 bit index register */
    pc: u16, /* Program counter */
    sp: uint, /* Stack Pointer */
    stack : [u16, ..16], /* 16 stack frames */
    sound_timer : u8,
    delay_timer : u8,
    hp_48_flags: [u16, ..8], /*SCHIP */
    opcode : u16,
    graphics :Graphics

}

fn dec_u12(val:u16) -> uint {
    ((val - 1) % U12_MAX) as uint
}

fn dec_u12_n(val:u16, n:u16) -> uint {
    ((val - n) % U12_MAX) as uint
}

fn inc_u12(val:u16) -> uint {
    ((val + 1) % U12_MAX) as uint
}

fn inc_u12_n(val:u16, n:u16) -> uint {
    ((val + n) % U12_MAX) as uint
}

/* returns 1 if true, 0 if false */
fn bool_to_int(b:bool) -> u8 {
    match b {
        true => 1,
        false => 0
    }
}

impl CPU {

    fn new(mut mem: Vec<u8>) -> CPU {
        let mut cpu = CPU { registers: [0u8, ..16],
              mem: [0u8, ..0xFFF],
              I: 0,
              pc: 0,
              sp: 1,
              stack : [0u16, ..16],
              sound_timer: 0,
              delay_timer: 0,
              hp_48_flags: [0u16, ..8],
              opcode : 0,
              graphics : Graphics::new()
       };

       /* Move values out of supplied vector and into
        * CPU mem */
       mem.reverse(); /* reverse vector first as poping off the end (O(1))
                         is much cheaper than shifting from the front (O(n)) */
       for val in cpu.mem.mut_iter() {
            *val = match mem.pop() {
                    Some(item) => item,
                    None => 0x0
            };
       }

       return cpu;
    }

    fn to_addr(dig1 :u8, dig2 :u8, dig :u8) -> u16 {
        ((dig1 << 8) | (dig2 << 4) | dig3) as u16
    }

    fn to_val(dig1 :u8, dig2 :u8) -> u8 {
        (dig1 << 4) | dig2
    }

    fn u16_to_hex_vec(hex :u16) => (u8, u8, u8, u8) {
         (hex & 0xF000) >> 12,  (hex & 0x0F00 >> 8),
         (hex & 0x00F0 >> 4, hex & 0x000F)
    }

    fn perform_cycle(&mut self) {

        opcode = u16_to_hex_vec(self.get_opcode());
        self.inc_pc();

        match opcode {
            (0x0, 0x0 ,0xE, 0x0) => self.clear_screen(),
            (0x0, 0x0, 0xE, 0xE) => self.ret(),
            (0x0, N1, N2, N3)  => {},
            (0x1, N1, N2, N3)  => self.jump(to_addr(N1, N2, N3)),
            (0x2, N1, N2, N3)  => self.call(to_addr(N1, N2, N3)),
            (0x3, X, N1, N2)  => self.skip_equals_reg_val(X, to_val(N1, N2)),
            (0x4, X, N, N)  => self.skip_not_equals_reg_val(X, to_val(N1, N2)),
            (0x5  X, Y, 0x0)  => self.skip_equals_regs(X, Y),
            (0x6  X, N1, N2)  => self.mov_reg_val(X, to_val(N1, N2)),
            (0x7, X, N1, N2)  => self.add_reg_val(X, to_val(N1, N2)),
            (0x8, X, Y, 0x0) => self.mov_regs(X, Y),
            (0x8, X, Y, 0x1) => self.or_regs(X, Y),
            (0x8, X, Y, 0x2) => self.and_regs(X, Y),
            (0x8, X, Y, 0x3) => self.xor_regs(X, Y),
            (0x8, X, Y, 0x4) => self.add_regs(X, Y),
            (0x8, X, Y, 0x5) => self.sub_regs(X, Y),
            (0x8, X, Y, 0x6) => self.shift_right(X, Y),
            (0x8, X, Y, 0x7) => self.sub_regs(Y, X),
            (0x8, X, Y, 0xE) => self.shift_left(X, Y),
            (0x9, X, Y, 0x0) => self.skip_not_equals_regs(X, Y),
            (0xA, N1, N2, N3) => self.set_i(to_addr(N1, N2, N3)),
            (0xB, N1, N2, N3) => self.jump_val_reg0(to_addr(N1, N2, N3)),
            (0xC, X, N1, N2) => self.rand(X, to_val(N1, N2)),
            (0xD, X, Y, N) => {},
            (0xE, X, 0x9, 0xE) => {},
            (0xE, X, 0xA, 0x1) => {},
            (0xF, X, 0x0, 0x7) => {},
            (0xF, X, 0x0, 0xA) => {},
            (0xF, X, 0x1, 0x5) => self.set_reg_delay(X),
            (0xF, X, 0x1, 0x8) => self.set_reg_sound(X),
            (0xF, X, 0x1, 0xE) => self.add_reg_index(X),
            (0xF, X, 0x2, 0x9) =>  {},
            (0xF, X, 0x3, 0x3) => self.binary_decimal(X),
            (0xF, X, 0x5, 0x5) => self.store_regs(X),
            (0xF, X, 0x6, 0x5) => self.load_regs(X)
        }
    }

    fn regs_op(&mut self, op: |u8, u8| -> u8) {
        let reg1 = self.get_reg_no_1();
        let reg2 = self.get_reg_no_1();

        self.registers[reg1] =
            op(self.registers[reg1], self.registers[reg2]);

    }

    fn regs_op_flags(&mut self, op: |u8, u8| -> u8, flag_val: |u8, u8| -> u8) {
        let reg1 = self.get_reg_no_1();
        let reg2 = self.get_reg_no_2();

        self.registers[FLAG] =
            flag_val(self.registers[reg1], self.registers[reg2]);

        self.registers[reg1] =
            flag_val(self.registers[reg1], self.registers[reg2]);
    }

    fn reg_val_op(&mut self, op: |u8, u8| -> u8) {
        let reg = self.get_reg_no_1();
        let val = self.get_val();

        self.registers[reg] = op(self.registers[reg], val)
   }

    fn reset(&mut self) {
        self.pc = 0x200;
        self.sp = 0;
    }

    fn pop(&mut self) -> u16 {
        let item = self.stack[self.sp];
        self.sp -= 1;
        return item;

    }

    fn push(&mut self, val:u16) {
        self.sp += 1;
        self.stack[self.sp] = val;
    }

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

    /* Jump to address at 0NNN */
    fn call(&mut self) {
        self.pc = self.opcode & 0xFFF;
    }

    /* Clear the screen */
    fn clear_screen(&mut self) {

    }

    /* Return from a subroutine */
    fn ret(&mut self) {
        self.pc = self.pop();
    }

    fn jump(&mut self, addr: u16) {
        self.pc = addr & 0xFFF;
    }

    /* Skip next instruction if register X is equal to NN */
    fn skip_equals_reg_val(&mut self, reg:u8, val:u8) {
        if self.registers[reg] == val {
            self.inc_pc();
        }

    }

    fn skip_not_equals_reg_val(&mut self, reg:u8, val:u8) {
        if self.registers[reg as uint] != val {
            self.inc_pc();
        }
    }

    fn skip_equals_regs(&mut self, reg1:u8, reg2:u8) {

        if self.registers[reg1 as uint] == self.registers[reg2 as uint] {
               self.inc_pc();
        }
    }

    fn skip_not_equals_regs(&mut self, reg1:u8, reg2:u8) {
        if self.registers[reg1 as uint] != self.registers[reg2 as uint] {
               self.inc_pc();
           }
    }

    fn mov_reg_val(&mut self, reg:u8, val:u8) {
        self.registers[reg as uint] = val;
    }

    fn add_reg_val(&mut self, reg:u8, val:u8) {
        self.registers[reg as uint] += val;
    }

    fn mov_regs(&mut self) {
        self.regs_op(|i, j| j);
    }

    fn or_regs(&mut self) {
        self.regs_op(|i, j| i | j);
    }

    fn and_regs(&mut self) {
        self.regs_op(|i, j| i & j);
    }

    fn xor_regs(&mut self) {
        self.regs_op(|i, j| i ^ j);
    }

    /* Add two regs, if overflow set flag register otherwise
     * unset flag register */
    fn add_regs(&mut self) {
        self.regs_op_flags(|reg1, reg2| reg1 + reg2,
                           |reg1, reg2| bool_to_int(0xFF - reg1 > reg2));
    }

    /* Sub reg2 from reg1, unset flag register if underflow,
     * set otherwise */
    fn sub_regs(&mut self) {
        self.regs_op_flags(|reg1, reg2| reg1 - reg2,
                           |reg1, reg2| bool_to_int(reg2 < reg1));

    }

    /* Sub reg1 from reg2, unset flag register if underflow,
     * set otherwise */
    fn sub_regs_inv(&mut self) {
        self.regs_op_flags(|reg1, reg2| reg2 - reg1,
                           |reg1, reg2| bool_to_int(reg1 < reg2));
    }

    /* Shift register left by 1, set flag register to most significant bit
     * before shifting */
    fn shift_left(&mut self) {
        self.regs_op_flags(|reg1, reg2| reg1 << 1, |reg1, reg2| reg1 & 0x80 >> 7);
    }

    /* Shift register right by 1, set flag register to least significant bit
     * before shifting */
    fn shift_right(&mut self) {
        self.regs_op_flags(|reg1, reg2| reg1 >> 1, |reg1, reg2| reg1 & 0x1);
    }

    /* Set index register to address in opcode */
    fn set_i(&mut self) {
        self.I = self.get_addr();
    }

    fn jump_val_reg0(&mut self) {
        self.pc = self.registers[0] as u16 + self.get_addr();
    }

    fn rand(&mut self) {
        self.reg_val_op( |reg, val| val & random::<u8>());
    }

    fn set_reg_delay(&mut self) {
        self.registers[self.get_reg_no_1()] = self.delay_timer;
    }

    fn set_reg_sound(&mut self) {
        self.registers[self.get_reg_no_1()] = self.sound_timer;
    }

    fn add_reg_index(&mut self) {
        let temp = self.I;
        self.I += self.registers[self.get_reg_no_1()] as u16;
        if (temp > self.I)  {
            self.registers[FLAG] = 1
        }
    }

    fn store_regs(&mut self) {
        let mut addr = self.I;
        for reg in self.registers.iter() {
            self.mem[addr as uint] = *reg;
            addr += 1;
        }
    }

    fn load_regs(&mut self) {
        let mut addr = self.I;
        for reg in self.registers.mut_iter() {
            *reg = self.mem[addr as uint];
            addr += 1;
        }
    }

    /*stores the Binary-coded decimal representation of VX, with the
     * most significant of three digits at the address in I, the middle digit
     * at I + 1, and the lsg at I + 2.*/
    fn binary_decimal(&mut self) {
        let val = self.registers[self.get_reg_no_1()];
        self.mem[self.I as uint] = val/100;
        self.mem[(self.I + 1) as uint] = (val % 100)/10;
        self.mem[(self.I + 2) as uint] = (val % 100)%10;

    }

}

fn main() {

    print!("yay");
}

<commit_msg>Fixed up core opcodes to take the correct args<commit_after>use std::rand::random;
use std::bool;
use graphics::Graphics;
/* CPU, Graphics and Memory core */

mod graphics;

//enum mode = {SCHIP, CHIP}; /* differentiate between CHIP and SCHIP modes */

static U12_MAX : u16 = 4096;
static FLAG : uint = 15;

struct CPU {
    registers : [u8, ..16], /* 16 8 bit general purpose registers */
    mem : [u8, .. 0xFFF], /* 4096bytes of memory */
    I : u16, /* 16 bit index register */
    pc: u16, /* Program counter */
    sp: uint, /* Stack Pointer */
    stack : [u16, ..16], /* 16 stack frames */
    sound_timer : u8,
    delay_timer : u8,
    hp_48_flags: [u16, ..8], /*SCHIP */
    opcode : u16,
    graphics :Graphics

}

impl CPU {

    fn new(mut mem: Vec<u8>) -> CPU {
        let mut cpu = CPU { registers: [0u8, ..16],
              mem: [0u8, ..0xFFF],
              I: 0,
              pc: 0x200,
              sp: 1,
              stack : [0u16, ..16],
              sound_timer: 0,
              delay_timer: 0,
              hp_48_flags: [0u16, ..8],
              opcode : 0,
              graphics : Graphics::new()
       };

       /* Move values out of supplied vector and into
        * CPU mem */
       mem.reverse(); /* reverse vector first as poping off the end (O(1))
                         is much cheaper than shifting from the front (O(n)) */
       for val in cpu.mem.mut_iter() {
            *val = match mem.pop() {
                    Some(item) => item,
                    None => 0x0
            };
       }

       return cpu;
    }

    fn to_addr(dig1 :u8, dig2 :u8, dig3 :u8) -> u16 {
        ((dig1 << 8) | (dig2 << 4) | dig3) as u16
    }

    fn to_val(dig1 :u8, dig2 :u8) -> u8 {
        (dig1 << 4) | dig2
    }

    fn u16_to_hex_vec(hex :u16) -> (u8, u8, u8, u8) {
         (((hex & 0xF000) >> 12) as u8,
          ((hex & 0x0F00) >> 8)  as u8,
          ((hex & 0x00F0) >> 4)  as u8,
           (hex & 0x000F)        as u8)
    }

    fn get_opcode(&self) -> u16 {
        (self.registers[self.pc as uint] << 4) as u16 |
        (self.registers[(self.pc + 1) as uint]) as u16
    }

    fn perform_cycle(&mut self) {

        let opcode = self.get_opcode();
        let opcode_v =  CPU::u16_to_hex_vec(opcode);
        self.inc_pc();

        match opcode_v {
            (0x0, 0x0 ,0xE, 0x0) => self.clear_screen(),
            (0x0, 0x0, 0xE, 0xE) => self.ret(),
            (0x0, N1, N2, N3) => {},
            (0x1, N1, N2, N3) => self.jump(CPU::to_addr(N1, N2, N3)),
            (0x2, N1, N2, N3) => self.call(CPU::to_addr(N1, N2, N3)),
            (0x3, X, N1, N2) => self.skip_equals_reg_val(X, CPU::to_val(N1, N2)),
            (0x4, X, N1, N2) => self.skip_not_equals_reg_val(X, CPU::to_val(N1, N2)),
            (0x5, X, Y, 0x0) => self.skip_equals_regs(X, Y),
            (0x6, X, N1, N2) => self.mov_reg_val(X, CPU::to_val(N1, N2)),
            (0x7, X, N1, N2) => self.add_reg_val(X, CPU::to_val(N1, N2)),
            (0x8, X, Y, 0x0) => self.mov_regs(X, Y),
            (0x8, X, Y, 0x1) => self.or_regs(X, Y),
            (0x8, X, Y, 0x2) => self.and_regs(X, Y),
            (0x8, X, Y, 0x3) => self.xor_regs(X, Y),
            (0x8, X, Y, 0x4) => self.add_regs(X, Y),
            (0x8, X, Y, 0x5) => self.sub_regs(X, Y),
            (0x8, X, _, 0x6) => self.shift_right(X),
            (0x8, X, Y, 0x7) => self.sub_regs(Y, X),
            (0x8, X, _, 0xE) => self.shift_left(X),
            (0x9, X, Y, 0x0) => self.skip_not_equals_regs(X, Y),
            (0xA, N1, N2, N3) => self.set_i(CPU::to_addr(N1, N2, N3)),
            (0xB, N1, N2, N3) => self.jump_val_reg0(CPU::to_addr(N1, N2, N3)),
            (0xC, X, N1, N2) => self.rand(X, CPU::to_val(N1, N2)),
            (0xD, X, Y, N) => {},
            (0xE, X, 0x9, 0xE) => {},
            (0xE, X, 0xA, 0x1) => {},
            (0xF, X, 0x0, 0x7) => {},
            (0xF, X, 0x0, 0xA) => {},
            (0xF, X, 0x1, 0x5) => self.set_reg_delay(X),
            (0xF, X, 0x1, 0x8) => self.set_reg_sound(X),
            (0xF, X, 0x1, 0xE) => self.add_reg_index(X),
            (0xF, X, 0x2, 0x9) =>  {},
            (0xF, X, 0x3, 0x3) => self.binary_decimal(X),
            (0xF, X, 0x5, 0x5) => self.store_regs(X),
            (0xF, X, 0x6, 0x5) => self.load_regs(X),
            _ => fail!("Unknown opcode {:x}",opcode)
        }
    }

    fn reset(&mut self) {
        self.pc = 0x200;
        self.sp = 0;
    }

    fn pop(&mut self) -> u16 {
        let item = self.stack[self.sp];
        self.sp -= 1;
        return item;

    }

    fn push(&mut self, val:u16) {
        self.sp += 1;
        self.stack[self.sp] = val;
    }

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

    /* Jump to address at 0NNN */
    fn call(&mut self, addr:u16) {
        self.pc = addr & 0xFFF;
    }

    /* Clear the screen */
    fn clear_screen(&mut self) {

    }

    /* Return from a subroutine */
    fn ret(&mut self) {
        self.pc = self.pop();
    }

    fn jump(&mut self, addr: u16) {
        self.pc = addr & 0xFFF;
    }

    /* Skip next instruction if register X is equal to NN */
    fn skip_equals_reg_val(&mut self, reg:u8, val:u8) {
        if self.registers[reg as uint] == val {
            self.inc_pc();
        }

    }

    fn skip_not_equals_reg_val(&mut self, reg:u8, val:u8) {
        if self.registers[reg as uint] != val {
            self.inc_pc();
        }
    }

    fn skip_equals_regs(&mut self, reg1:u8, reg2:u8) {

        if self.registers[reg1 as uint] == self.registers[reg2 as uint] {
               self.inc_pc();
        }
    }

    fn skip_not_equals_regs(&mut self, reg1:u8, reg2:u8) {
        if self.registers[reg1 as uint] != self.registers[reg2 as uint] {
               self.inc_pc();
           }
    }

    fn mov_reg_val(&mut self, reg:u8, val:u8) {
        self.registers[reg as uint] = val;
    }

    fn add_reg_val(&mut self, reg:u8, val:u8) {
        self.registers[reg as uint] += val;
    }

    fn mov_regs(&mut self, reg1:u8, reg2:u8) {
        self.registers[reg1 as uint] = self.registers[reg2 as uint];
    }

    fn or_regs(&mut self, reg1:u8, reg2:u8) {
       self.registers[reg1 as uint] |= self.registers[reg2 as uint];
    }

    fn and_regs(&mut self, reg1:u8, reg2:u8) {
        self.registers[reg1 as uint] |= self.registers[reg2 as uint];
    }

    fn xor_regs(&mut self, reg1:u8, reg2:u8) {
        self.registers[reg1 as uint] ^= self.registers[reg2 as uint];
    }

    /* Add two regs, if overflow set flag register otherwise
     * unset flag register */
    fn add_regs(&mut self, reg1:u8, reg2:u8) {
        self.registers[FLAG] =  bool::to_bit::<u8>(0xFF - reg1 > reg2);
        self.registers[reg1 as uint] += self.registers[reg2 as uint];
    }

    /* Sub reg2 from reg1, unset flag register if underflow,
     * set otherwise */
    fn sub_regs(&mut self, reg1:u8, reg2:u8) {
        self.registers[FLAG] = bool::to_bit::<u8>(reg2 < reg1);
        self.registers[reg1 as uint] -= self.registers[reg2 as uint];
    }

    /* Sub reg1 from reg2, unset flag register if underflow,
     * set otherwise */
    fn sub_regs_inv(&mut self, reg1:u8, reg2:u8) {
        self.registers[FLAG] = bool::to_bit::<u8>(reg1 < reg2);
        self.registers[reg2 as uint] -= self.registers[reg1 as uint];
    }

    /* Shift register left by 1, set flag register to most significant bit
     * before shifting */
    fn shift_left(&mut self, reg:u8) {
        self.registers[FLAG] = (self.registers[reg as uint] & 0x80) >> 7;
        self.registers[reg as uint] <<= 1;
    }

    /* Shift register right by 1, set flag register to least significant bit
     * before shifting */
    fn shift_right(&mut self, reg:u8) {
        self.registers[FLAG] = self.registers[reg as uint] & 0x1;
        self.registers[reg as uint] >>= 1;
    }

    /* Set index register to address in opcode */
    fn set_i(&mut self, addr:u16) {
        self.I = addr;
    }

    fn jump_val_reg0(&mut self, addr:u16) {
        self.pc = self.registers[0] as u16 + addr;
    }

    fn rand(&mut self, reg:u8, val:u8) {
        self.registers[reg as uint] = val & random::<u8>();
    }

    fn set_reg_delay(&mut self, reg:u8) {
        self.registers[reg as uint] = self.delay_timer;
    }

    fn set_reg_sound(&mut self, reg:u8) {
        self.registers[reg as uint] = self.sound_timer;
    }

    fn add_reg_index(&mut self, reg:u8) {
        self.registers[FLAG] =
            bool::to_bit::<u8>(0xFFF - (self.registers[reg as uint] as u16) < self.I);
        self.I += self.registers[reg as uint] as u16
    }

    fn store_regs(&mut self, reg:u8) {
        let mut addr = self.I;
        for reg in self.registers.iter() {
            self.mem[addr as uint] = *reg;
            addr += 1;
        }
    }

    fn load_regs(&mut self, reg:u8) {
        let mut addr = self.I;
        for reg in self.registers.mut_iter() {
            *reg = self.mem[addr as uint];
            addr += 1;
        }
    }

    /*stores the Binary-coded decimal representation of VX, with the
     * most significant of three digits at the address in I, the middle digit
     * at I + 1, and the lsg at I + 2.*/
    fn binary_decimal(&mut self, reg:u8) {
        let val = self.registers[reg as uint];
        self.mem[self.I as uint] = val/100;
        self.mem[(self.I + 1) as uint] = (val % 100)/10;
        self.mem[(self.I + 2) as uint] = (val % 100)%10;

    }

}

fn main() {

    print!("yay");
}

<|endoftext|>


<commit_before>// Copyright (C) 2014 The 6502-rs Developers
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. Neither the names of the copyright holders nor the names of any
//    contributors may be used to endorse or promote products derived from this
//    software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

use log;

use std;

use address::{AddressDiff};
use instruction;
use instruction::{DecodedInstr};
use memory::Memory;
use registers::{ Registers, Status, StatusArgs };
use registers::{ ps_negative, ps_overflow, ps_zero, ps_carry };

pub struct Machine {
    pub registers: Registers,
    pub memory:    Memory
}

impl Machine {
    pub fn new() -> Machine {
    	Machine{
    	    registers: Registers::new(),
    	    memory:    Memory::new()
    	}
    }

    pub fn reset(&mut self) {
    	*self = Machine::new();
    }

    pub fn fetch_next_and_decode(&mut self) -> Option<DecodedInstr> {
        let x: u8 = self.memory.get_byte(self.registers.program_counter);

        match instruction::OPCODES[x as uint] {
            Some((instr, am)) => {
                let extra_bytes = am.extra_bytes();
                let num_bytes = AddressDiff(1) + extra_bytes;

                let data_start = self.registers.program_counter
                               + AddressDiff(1);

                let slice = self.memory.get_slice(data_start, extra_bytes);
                let am_out = am.process(self, slice);

                // Increment program counter
                self.registers.program_counter =
                    self.registers.program_counter + num_bytes;

                Some((instr, am_out))
            }
            _ => None
        }
    }

    pub fn execute_instruction(&mut self, decoded_instr: DecodedInstr) {
        match decoded_instr {
            (instruction::ADC, instruction::UseImmediate(val)) => {
                log!(log::DEBUG, "add with carry immediate: {}", val);
                self.add_with_carry(val as i8);
            },
            (instruction::ADC, instruction::UseAddress(addr)) => {
                let val = self.memory.get_byte(addr) as i8;
                log!(log::DEBUG, "add with carry. address: {}. value: {}",
                                 addr, val);
                self.add_with_carry(val);
            },

            (instruction::LDA, instruction::UseImmediate(val)) => {
                log!(log::DEBUG, "load A immediate: {}", val);
                self.load_accumulator(val as i8);
            },
            (instruction::LDA, instruction::UseAddress(addr)) => {
                let val = self.memory.get_byte(addr);
                log!(log::DEBUG, "load A. address: {}. value: {}", addr, val);
                self.load_accumulator(val as i8);
            },

            (instruction::LDX, instruction::UseImmediate(val)) => {
                log!(log::DEBUG, "load X immediate: {}", val);
                self.load_x_register(val as i8);
            },
            (instruction::LDX, instruction::UseAddress(addr)) => {
                let val = self.memory.get_byte(addr);
                log!(log::DEBUG, "load X. address: {}. value: {}", addr, val);
                self.load_x_register(val as i8);
            },

            (instruction::LDY, instruction::UseImmediate(val)) => {
                log!(log::DEBUG, "load Y immediate: {}", val);
                self.load_y_register(val as i8);
            },
            (instruction::LDY, instruction::UseAddress(addr)) => {
                let val = self.memory.get_byte(addr);
                log!(log::DEBUG, "load Y. address: {}. value: {}", addr, val);
                self.load_y_register(val as i8);
            },

            (instruction::NOP, _) => {
                log!(log::DEBUG, "nop instr");
            },
            (_, _) => {
                log!(log::DEBUG, "attempting to execute unimplemented \
                                  instruction");
            },
        };
    }

    pub fn run(&mut self) {
        loop {
            if let Some(decoded_instr) = self.fetch_next_and_decode() {
                self.execute_instruction(decoded_instr);
            } else {
                break
            }
        }
    }

    fn load_register_with_flags(register: &mut i8,
                                status: &mut Status,
                                value: i8) {
        *register = value;

        let is_zero = value == 0;
        let is_negative = value < 0;

        status.set_with_mask(
            ps_zero | ps_negative,
            Status::new(StatusArgs { zero: is_zero,
                                     negative: is_negative,
                                     ..StatusArgs::none() } ));
    }

    pub fn load_x_register(&mut self, value: i8) {
        Machine::load_register_with_flags(&mut self.registers.index_x,
                                          &mut self.registers.status,
                                          value);
    }

    pub fn load_y_register(&mut self, value: i8) {
        Machine::load_register_with_flags(&mut self.registers.index_y,
                                          &mut self.registers.status,
                                          value);
    }

    pub fn load_accumulator(&mut self, value: i8) {
        Machine::load_register_with_flags(&mut self.registers.accumulator,
                                          &mut self.registers.status,
                                          value);
    }

    // TODO akeeton: Implement binary-coded decimal.
    pub fn add_with_carry(&mut self, value: i8) {
        let a_before: i8 = self.registers.accumulator;
        let c_before: i8 = self.registers.status.get_carry();
        let a_after: i8 = a_before + c_before + value;

        debug_assert_eq!(a_after as u8, a_before as u8 + c_before as u8
                                        + value as u8);

        let did_carry = (a_after as u8) < (a_before as u8);

        let did_overflow   =
        	   (a_before < 0 && value < 0 && a_after >= 0)
        	|| (a_before > 0 && value > 0 && a_after <= 0);

        let mask = ps_carry | ps_overflow;

        self.registers.status.set_with_mask(mask,
            Status::new(StatusArgs { carry: did_carry,
                                     overflow: did_overflow,
                                     ..StatusArgs::none() } ));

        self.load_accumulator(a_after);

        log!(log::DEBUG, "accumulator: {}", self.registers.accumulator);
    }
}

impl std::fmt::Show for Machine {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "Machine Dump:\n\nAccumulator: {}",
               self.registers.accumulator)
    }
}

#[test]
fn add_with_carry_test() {

    let mut machine = Machine::new();

    machine.add_with_carry(1);
    assert_eq!(machine.registers.accumulator, 1);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative), false);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    machine.add_with_carry(-1);
    assert_eq!(machine.registers.accumulator, 0);
    assert_eq!(machine.registers.status.contains(ps_carry),    true);
    assert_eq!(machine.registers.status.contains(ps_zero),     true);
    assert_eq!(machine.registers.status.contains(ps_negative), false);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    machine.add_with_carry(1);
    assert_eq!(machine.registers.accumulator, 2);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative), false);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    let mut machine = Machine::new();

    machine.add_with_carry(127);
    assert_eq!(machine.registers.accumulator, 127);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative), false);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    machine.add_with_carry(-127);
    assert_eq!(machine.registers.accumulator, 0);
    assert_eq!(machine.registers.status.contains(ps_carry),     true);
    assert_eq!(machine.registers.status.contains(ps_zero),      true);
    assert_eq!(machine.registers.status.contains(ps_negative), false);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    machine.registers.status.remove(ps_carry);
    machine.add_with_carry(-128);
    assert_eq!(machine.registers.accumulator, -128);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative),  true);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    machine.add_with_carry(127);
    assert_eq!(machine.registers.accumulator, -1);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative),  true);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    let mut machine = Machine::new();

    machine.add_with_carry(127);
    assert_eq!(machine.registers.accumulator, 127);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative), false);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    machine.add_with_carry(1);
    assert_eq!(machine.registers.accumulator, -128);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative),  true);
    assert_eq!(machine.registers.status.contains(ps_overflow),  true);
}
<commit_msg>DEX instruction and test<commit_after>// Copyright (C) 2014 The 6502-rs Developers
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 3. Neither the names of the copyright holders nor the names of any
//    contributors may be used to endorse or promote products derived from this
//    software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

use log;

use std;

use address::{AddressDiff};
use instruction;
use instruction::{DecodedInstr};
use memory::Memory;
use registers::{ Registers, Status, StatusArgs };
use registers::{ ps_negative, ps_overflow, ps_zero, ps_carry };

pub struct Machine {
    pub registers: Registers,
    pub memory:    Memory
}

impl Machine {
    pub fn new() -> Machine {
    	Machine{
    	    registers: Registers::new(),
    	    memory:    Memory::new()
    	}
    }

    pub fn reset(&mut self) {
    	*self = Machine::new();
    }

    pub fn fetch_next_and_decode(&mut self) -> Option<DecodedInstr> {
        let x: u8 = self.memory.get_byte(self.registers.program_counter);

        match instruction::OPCODES[x as uint] {
            Some((instr, am)) => {
                let extra_bytes = am.extra_bytes();
                let num_bytes = AddressDiff(1) + extra_bytes;

                let data_start = self.registers.program_counter
                               + AddressDiff(1);

                let slice = self.memory.get_slice(data_start, extra_bytes);
                let am_out = am.process(self, slice);

                // Increment program counter
                self.registers.program_counter =
                    self.registers.program_counter + num_bytes;

                Some((instr, am_out))
            }
            _ => None
        }
    }

    pub fn execute_instruction(&mut self, decoded_instr: DecodedInstr) {
        match decoded_instr {
            (instruction::ADC, instruction::UseImmediate(val)) => {
                log!(log::DEBUG, "add with carry immediate: {}", val);
                self.add_with_carry(val as i8);
            },
            (instruction::ADC, instruction::UseAddress(addr)) => {
                let val = self.memory.get_byte(addr) as i8;
                log!(log::DEBUG, "add with carry. address: {}. value: {}",
                                 addr, val);
                self.add_with_carry(val);
            },

            (instruction::DEX, instruction::UseImplied) => {
                self.dec_x();
            }

            (instruction::LDA, instruction::UseImmediate(val)) => {
                log!(log::DEBUG, "load A immediate: {}", val);
                self.load_accumulator(val as i8);
            },
            (instruction::LDA, instruction::UseAddress(addr)) => {
                let val = self.memory.get_byte(addr);
                log!(log::DEBUG, "load A. address: {}. value: {}", addr, val);
                self.load_accumulator(val as i8);
            },

            (instruction::LDX, instruction::UseImmediate(val)) => {
                log!(log::DEBUG, "load X immediate: {}", val);
                self.load_x_register(val as i8);
            },
            (instruction::LDX, instruction::UseAddress(addr)) => {
                let val = self.memory.get_byte(addr);
                log!(log::DEBUG, "load X. address: {}. value: {}", addr, val);
                self.load_x_register(val as i8);
            },

            (instruction::LDY, instruction::UseImmediate(val)) => {
                log!(log::DEBUG, "load Y immediate: {}", val);
                self.load_y_register(val as i8);
            },
            (instruction::LDY, instruction::UseAddress(addr)) => {
                let val = self.memory.get_byte(addr);
                log!(log::DEBUG, "load Y. address: {}. value: {}", addr, val);
                self.load_y_register(val as i8);
            },

            (instruction::NOP, _) => {
                log!(log::DEBUG, "nop instr");
            },
            (_, _) => {
                log!(log::DEBUG, "attempting to execute unimplemented \
                                  instruction");
            },
        };
    }

    pub fn run(&mut self) {
        loop {
            if let Some(decoded_instr) = self.fetch_next_and_decode() {
                self.execute_instruction(decoded_instr);
            } else {
                break
            }
        }
    }

    fn load_register_with_flags(register: &mut i8,
                                status: &mut Status,
                                value: i8) {
        *register = value;

        let is_zero = value == 0;
        let is_negative = value < 0;

        status.set_with_mask(
            ps_zero | ps_negative,
            Status::new(StatusArgs { zero: is_zero,
                                     negative: is_negative,
                                     ..StatusArgs::none() } ));
    }

    pub fn load_x_register(&mut self, value: i8) {
        Machine::load_register_with_flags(&mut self.registers.index_x,
                                          &mut self.registers.status,
                                          value);
    }

    pub fn load_y_register(&mut self, value: i8) {
        Machine::load_register_with_flags(&mut self.registers.index_y,
                                          &mut self.registers.status,
                                          value);
    }

    pub fn load_accumulator(&mut self, value: i8) {
        Machine::load_register_with_flags(&mut self.registers.accumulator,
                                          &mut self.registers.status,
                                          value);
    }

    // TODO akeeton: Implement binary-coded decimal.
    pub fn add_with_carry(&mut self, value: i8) {
        let a_before: i8 = self.registers.accumulator;
        let c_before: i8 = self.registers.status.get_carry();
        let a_after: i8 = a_before + c_before + value;

        debug_assert_eq!(a_after as u8, a_before as u8 + c_before as u8
                                        + value as u8);

        let did_carry = (a_after as u8) < (a_before as u8);

        let did_overflow   =
        	   (a_before < 0 && value < 0 && a_after >= 0)
        	|| (a_before > 0 && value > 0 && a_after <= 0);

        let mask = ps_carry | ps_overflow;

        self.registers.status.set_with_mask(mask,
            Status::new(StatusArgs { carry: did_carry,
                                     overflow: did_overflow,
                                     ..StatusArgs::none() } ));

        self.load_accumulator(a_after);

        log!(log::DEBUG, "accumulator: {}", self.registers.accumulator);
    }

    pub fn dec_x(&mut self) {
        let x_before = self.registers.index_x;
        let value = 1i8;
        let x_after = x_before - value;
        self.registers.index_x = x_before - 1;

        let is_negative = x_after < 0;
        let is_zero = x_after == 0;

        let mask = ps_negative | ps_zero;
        self.registers.status.set_with_mask(
            mask,
            Status::new(StatusArgs {
                negative: is_negative,
                zero: is_zero,
                    ..StatusArgs::none()
            })
        );
    }
}

impl std::fmt::Show for Machine {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "Machine Dump:\n\nAccumulator: {}",
               self.registers.accumulator)
    }
}

#[test]
fn add_with_carry_test() {

    let mut machine = Machine::new();

    machine.add_with_carry(1);
    assert_eq!(machine.registers.accumulator, 1);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative), false);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    machine.add_with_carry(-1);
    assert_eq!(machine.registers.accumulator, 0);
    assert_eq!(machine.registers.status.contains(ps_carry),    true);
    assert_eq!(machine.registers.status.contains(ps_zero),     true);
    assert_eq!(machine.registers.status.contains(ps_negative), false);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    machine.add_with_carry(1);
    assert_eq!(machine.registers.accumulator, 2);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative), false);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    let mut machine = Machine::new();

    machine.add_with_carry(127);
    assert_eq!(machine.registers.accumulator, 127);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative), false);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    machine.add_with_carry(-127);
    assert_eq!(machine.registers.accumulator, 0);
    assert_eq!(machine.registers.status.contains(ps_carry),     true);
    assert_eq!(machine.registers.status.contains(ps_zero),      true);
    assert_eq!(machine.registers.status.contains(ps_negative), false);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    machine.registers.status.remove(ps_carry);
    machine.add_with_carry(-128);
    assert_eq!(machine.registers.accumulator, -128);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative),  true);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    machine.add_with_carry(127);
    assert_eq!(machine.registers.accumulator, -1);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative),  true);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    let mut machine = Machine::new();

    machine.add_with_carry(127);
    assert_eq!(machine.registers.accumulator, 127);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative), false);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    machine.add_with_carry(1);
    assert_eq!(machine.registers.accumulator, -128);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative),  true);
    assert_eq!(machine.registers.status.contains(ps_overflow),  true);
}

#[test]
fn dec_x_test() {
    let mut machine = Machine::new();

    machine.dec_x();
    assert_eq!(machine.registers.index_x, -1);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative), true);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);

    machine.dec_x();
    assert_eq!(machine.registers.index_x, -2);
    assert_eq!(machine.registers.status.contains(ps_carry),    false);
    assert_eq!(machine.registers.status.contains(ps_zero),     false);
    assert_eq!(machine.registers.status.contains(ps_negative), true);
    assert_eq!(machine.registers.status.contains(ps_overflow), false);
}
<|endoftext|>


<commit_before>use llvm_sys::core::LLVMDisposeMessage;
use llvm_sys::execution_engine::{LLVMGetExecutionEngineTargetData, LLVMExecutionEngineRef, LLVMRunFunction, LLVMRunFunctionAsMain, LLVMDisposeExecutionEngine, LLVMGetFunctionAddress, LLVMAddModule, LLVMFindFunction, LLVMLinkInMCJIT, LLVMLinkInInterpreter, LLVMRemoveModule, LLVMGenericValueRef, LLVMFreeMachineCodeForFunction, LLVMAddGlobalMapping};

use module::Module;
use targets::TargetData;
use values::{AnyValue, AsValueRef, FunctionValue, GenericValue};

use std::rc::Rc;
use std::ffi::{CStr, CString};
use std::mem::{forget, uninitialized, zeroed};

#[derive(Debug, PartialEq, Eq)]
pub enum FunctionLookupError {
    JITNotEnabled,
    FunctionNotFound, // 404!
}

#[derive(PartialEq, Eq, Debug)]
pub struct ExecutionEngine {
    pub(crate) execution_engine: Rc<LLVMExecutionEngineRef>,
    target_data: Option<TargetData>,
    jit_mode: bool,
}

impl ExecutionEngine {
    pub(crate) fn new(execution_engine: Rc<LLVMExecutionEngineRef>, jit_mode: bool) -> ExecutionEngine {
        assert!(!execution_engine.is_null());

        // REVIEW: Will we have to do this for LLVMGetExecutionEngineTargetMachine too?
        let target_data = unsafe {
            LLVMGetExecutionEngineTargetData(*execution_engine)
        };

        ExecutionEngine {
            execution_engine: execution_engine,
            target_data: Some(TargetData::new(target_data)),
            jit_mode: jit_mode,
        }
    }

    pub fn link_in_mc_jit() {
        unsafe {
            LLVMLinkInMCJIT()
        }
    }

    pub fn link_in_interpreter() {
        unsafe {
            LLVMLinkInInterpreter();
        }
    }

    /// Maps the specified value to an address.
    ///
    /// # Example
    /// ```no_run
    /// use inkwell::targets::{InitializationConfig, Target};
    /// use inkwell::context::Context;
    /// use inkwell::OptimizationLevel;
    ///
    /// Target::initialize_native(&InitializationConfig::default()).unwrap();
    ///
    /// extern fn sumf(a: f64, b: f64) -> f64 {
    ///     a + b
    /// }
    ///
    /// let context = Context::create();
    /// let module = context.create_module("test");
    /// let builder = context.create_builder();
    ///
    /// let ft = context.f64_type();
    /// let fnt = ft.fn_type(&[], false);
    ///
    /// let f = module.add_function("test_fn", &fnt, None);
    /// let b = context.append_basic_block(&f, "entry");
    /// builder.position_at_end(&b);
    ///
    /// let extf = module.add_function("sumf", &ft.fn_type(&[ &ft, &ft ], false), None);
    ///
    /// let argf = ft.const_float(64.);
    /// let retv = builder.build_call(&extf, &[ &argf, &argf ], "retv", false).left().unwrap().into_float_value();
    ///
    /// builder.build_return(Some(&retv));
    ///
    /// let mut ee = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
    /// ee.add_global_mapping(&extf, sumf as usize);
    ///
    /// let result = unsafe { ee.run_function(&f, &[]) }.as_float(&ft);
    ///
    /// assert_eq!(result, 128.);
    /// ```
    pub fn add_global_mapping(&self, value: &AnyValue, addr: usize) {
        unsafe {
            LLVMAddGlobalMapping(*self.execution_engine, value.as_value_ref(), addr as *mut _)
        }
    }

    /// Adds a module to an `ExecutionEngine`.
    ///
    /// The method will be `Ok(())` if the module does not belong to an `ExecutionEngine` already and `Err(())` otherwise.
    ///
    /// ```rust,no_run
    /// use inkwell::targets::{InitializationConfig, Target};
    /// use inkwell::context::Context;
    /// use inkwell::OptimizationLevel;
    ///
    /// Target::initialize_native(&InitializationConfig::default()).unwrap();
    ///
    /// let context = Context::create();
    /// let module = context.create_module("test");
    /// let mut ee = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
    ///
    /// assert!(ee.add_module(&module).is_err());
    /// ```
    pub fn add_module(&self, module: &Module) -> Result<(), ()> {
        unsafe {
            LLVMAddModule(*self.execution_engine, module.module.get())
        }

        if module.owned_by_ee.borrow().is_some() {
            return Err(());
        }

        *module.owned_by_ee.borrow_mut() = Some(ExecutionEngine::new(self.execution_engine.clone(), self.jit_mode));

        Ok(())
    }

    pub fn remove_module(&self, module: &Module) -> Result<(), String> {
        match *module.owned_by_ee.borrow() {
            Some(ref ee) if *ee.execution_engine != *self.execution_engine => return Err("Module is not owned by this Execution Engine".into()),
            None => return Err("Module is not owned by an Execution Engine".into()),
            _ => ()
        }

        let mut new_module = unsafe { uninitialized() };
        let mut err_str = unsafe { zeroed() };

        let code = unsafe {
            LLVMRemoveModule(*self.execution_engine, module.module.get(), &mut new_module, &mut err_str)
        };

        if code == 1 {
            let rust_str = unsafe {
                let rust_str = CStr::from_ptr(err_str).to_string_lossy().into_owned();

                LLVMDisposeMessage(err_str);

                rust_str
            };

            return Err(rust_str);
        }

        module.module.set(new_module);
        *module.owned_by_ee.borrow_mut() = None;

        Ok(())
    }

    /// WARNING: The returned address *will* be invalid if the EE drops first
    /// Do not attempt to transmute it to a function if the ExecutionEngine is gone
    // TODOC: Initializing a target MUST occur before creating the EE or else it will not count
    // TODOC: Can still add functions after EE has been created
    pub fn get_function_address(&self, fn_name: &str) -> Result<u64, FunctionLookupError> {
        if !self.jit_mode {
            return Err(FunctionLookupError::JITNotEnabled);
        }

        let c_string = CString::new(fn_name).expect("Conversion to CString failed unexpectedly");

        let address = unsafe {
            LLVMGetFunctionAddress(*self.execution_engine, c_string.as_ptr())
        };

        // REVIEW: Can also return 0 if no targets are initialized.
        // One option might be to set a global to true if any at all of the targets have been
        // initialized (maybe we could figure out which config in particular is the trigger)
        // and if not return an "NoTargetsInitialized" error, instead of not found.
        if address == 0 {
            return Err(FunctionLookupError::FunctionNotFound);
        }

        Ok(address)
    }

    // REVIEW: Not sure if an EE's target data can change.. if so we might want to update the value
    // when making this call
    pub fn get_target_data(&self) -> &TargetData {
        self.target_data.as_ref().expect("TargetData should always exist until Drop")
    }

    // REVIEW: Can also find nothing if no targeting is initialized. Maybe best to
    // do have a global flag for anything initialized. Catch is that it must be initialized
    // before EE is created
    pub fn get_function_value(&self, fn_name: &str) -> Result<FunctionValue, FunctionLookupError> {
        if !self.jit_mode {
            return Err(FunctionLookupError::JITNotEnabled);
        }

        let c_string = CString::new(fn_name).expect("Conversion to CString failed unexpectedly");
        let mut function = unsafe { zeroed() };

        let code = unsafe {
            LLVMFindFunction(*self.execution_engine, c_string.as_ptr(), &mut function)
        };

        if code == 0 {
            return FunctionValue::new(function).ok_or(FunctionLookupError::FunctionNotFound)
        };

        Err(FunctionLookupError::FunctionNotFound)
    }

    // TODOC: Marked as unsafe because input function could very well do something unsafe. It's up to the caller
    // to ensure that doesn't happen by defining their function correctly.
    pub unsafe fn run_function(&self, function: &FunctionValue, args: &[&GenericValue]) -> GenericValue {
        let mut args: Vec<LLVMGenericValueRef> = args.iter()
                                                     .map(|val| val.generic_value)
                                                     .collect();

        let value = LLVMRunFunction(*self.execution_engine, function.as_value_ref(), args.len() as u32, args.as_mut_ptr()); // REVIEW: usize to u32 ok??

        GenericValue::new(value)
    }

    pub fn run_function_as_main(&self, function: &FunctionValue) {
        let args = vec![]; // TODO: Support argc, argv
        let env_p = vec![]; // REVIEW: No clue what this is

        unsafe {
            LLVMRunFunctionAsMain(*self.execution_engine, function.as_value_ref(), args.len() as u32, args.as_ptr(), env_p.as_ptr()); // REVIEW: usize to u32 cast ok??
        }
    }

    pub fn free_fn_machine_code(&self, function: &FunctionValue) {
        unsafe {
            LLVMFreeMachineCodeForFunction(*self.execution_engine, function.as_value_ref())
        }
    }
}

// Modules owned by the EE will be discarded by the EE so we don't
// want owned modules to drop.
impl Drop for ExecutionEngine {
    fn drop(&mut self) {
        forget(self.target_data.take().expect("TargetData should always exist until Drop"));

        if Rc::strong_count(&self.execution_engine) == 1 {
            unsafe {
                LLVMDisposeExecutionEngine(*self.execution_engine);
            }
        }
    }
}
<commit_msg>Replaced the get_function_addr with a get_function<commit_after>use llvm_sys::core::LLVMDisposeMessage;
use llvm_sys::execution_engine::{LLVMGetExecutionEngineTargetData, LLVMExecutionEngineRef, LLVMRunFunction, LLVMRunFunctionAsMain, LLVMDisposeExecutionEngine, LLVMGetFunctionAddress, LLVMAddModule, LLVMFindFunction, LLVMLinkInMCJIT, LLVMLinkInInterpreter, LLVMRemoveModule, LLVMGenericValueRef, LLVMFreeMachineCodeForFunction, LLVMAddGlobalMapping};

use module::Module;
use targets::TargetData;
use values::{AnyValue, AsValueRef, FunctionValue, GenericValue};

use std::rc::Rc;
use std::ops::Deref;
use std::ffi::{CStr, CString};
use std::mem::{forget, uninitialized, zeroed, transmute_copy, size_of};

#[derive(Debug, PartialEq, Eq)]
pub enum FunctionLookupError {
    JITNotEnabled,
    FunctionNotFound, // 404!
}

#[derive(PartialEq, Eq, Debug)]
pub struct ExecutionEngine {
    pub(crate) execution_engine: Rc<LLVMExecutionEngineRef>,
    target_data: Option<TargetData>,
    jit_mode: bool,
}

impl ExecutionEngine {
    pub(crate) fn new(execution_engine: Rc<LLVMExecutionEngineRef>, jit_mode: bool) -> ExecutionEngine {
        assert!(!execution_engine.is_null());

        // REVIEW: Will we have to do this for LLVMGetExecutionEngineTargetMachine too?
        let target_data = unsafe {
            LLVMGetExecutionEngineTargetData(*execution_engine)
        };

        ExecutionEngine {
            execution_engine: execution_engine,
            target_data: Some(TargetData::new(target_data)),
            jit_mode: jit_mode,
        }
    }

    pub fn link_in_mc_jit() {
        unsafe {
            LLVMLinkInMCJIT()
        }
    }

    pub fn link_in_interpreter() {
        unsafe {
            LLVMLinkInInterpreter();
        }
    }

    /// Maps the specified value to an address.
    ///
    /// # Example
    /// ```no_run
    /// use inkwell::targets::{InitializationConfig, Target};
    /// use inkwell::context::Context;
    /// use inkwell::OptimizationLevel;
    ///
    /// Target::initialize_native(&InitializationConfig::default()).unwrap();
    ///
    /// extern fn sumf(a: f64, b: f64) -> f64 {
    ///     a + b
    /// }
    ///
    /// let context = Context::create();
    /// let module = context.create_module("test");
    /// let builder = context.create_builder();
    ///
    /// let ft = context.f64_type();
    /// let fnt = ft.fn_type(&[], false);
    ///
    /// let f = module.add_function("test_fn", &fnt, None);
    /// let b = context.append_basic_block(&f, "entry");
    /// builder.position_at_end(&b);
    ///
    /// let extf = module.add_function("sumf", &ft.fn_type(&[ &ft, &ft ], false), None);
    ///
    /// let argf = ft.const_float(64.);
    /// let retv = builder.build_call(&extf, &[ &argf, &argf ], "retv", false).left().unwrap().into_float_value();
    ///
    /// builder.build_return(Some(&retv));
    ///
    /// let mut ee = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
    /// ee.add_global_mapping(&extf, sumf as usize);
    ///
    /// let result = unsafe { ee.run_function(&f, &[]) }.as_float(&ft);
    ///
    /// assert_eq!(result, 128.);
    /// ```
    pub fn add_global_mapping(&self, value: &AnyValue, addr: usize) {
        unsafe {
            LLVMAddGlobalMapping(*self.execution_engine, value.as_value_ref(), addr as *mut _)
        }
    }

    /// Adds a module to an `ExecutionEngine`.
    ///
    /// The method will be `Ok(())` if the module does not belong to an `ExecutionEngine` already and `Err(())` otherwise.
    ///
    /// ```rust,no_run
    /// use inkwell::targets::{InitializationConfig, Target};
    /// use inkwell::context::Context;
    /// use inkwell::OptimizationLevel;
    ///
    /// Target::initialize_native(&InitializationConfig::default()).unwrap();
    ///
    /// let context = Context::create();
    /// let module = context.create_module("test");
    /// let mut ee = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
    ///
    /// assert!(ee.add_module(&module).is_err());
    /// ```
    pub fn add_module(&self, module: &Module) -> Result<(), ()> {
        unsafe {
            LLVMAddModule(*self.execution_engine, module.module.get())
        }

        if module.owned_by_ee.borrow().is_some() {
            return Err(());
        }

        *module.owned_by_ee.borrow_mut() = Some(ExecutionEngine::new(self.execution_engine.clone(), self.jit_mode));

        Ok(())
    }

    pub fn remove_module(&self, module: &Module) -> Result<(), String> {
        match *module.owned_by_ee.borrow() {
            Some(ref ee) if *ee.execution_engine != *self.execution_engine => return Err("Module is not owned by this Execution Engine".into()),
            None => return Err("Module is not owned by an Execution Engine".into()),
            _ => ()
        }

        let mut new_module = unsafe { uninitialized() };
        let mut err_str = unsafe { zeroed() };

        let code = unsafe {
            LLVMRemoveModule(*self.execution_engine, module.module.get(), &mut new_module, &mut err_str)
        };

        if code == 1 {
            let rust_str = unsafe {
                let rust_str = CStr::from_ptr(err_str).to_string_lossy().into_owned();

                LLVMDisposeMessage(err_str);

                rust_str
            };

            return Err(rust_str);
        }

        module.module.set(new_module);
        *module.owned_by_ee.borrow_mut() = None;

        Ok(())
    }

    /// Try to load a function from the execution engine.
    ///
    /// If a target hasn't already been initialized, spurious "function not
    /// found" errors may be encountered.
    ///
    /// # Safety
    ///
    /// It is the caller's responsibility to ensure they call the function with
    /// the correct signature and calling convention.
    ///
    /// The `Symbol` wrapper ensures a function won't accidentally outlive the
    /// execution engine it came from, but adding functions after calling this
    /// method *may* invalidate the function pointer.
    pub unsafe fn get_function<F>(&self, fn_name: &str) -> Result<Symbol<F>, FunctionLookupError> {
        if !self.jit_mode {
            return Err(FunctionLookupError::JITNotEnabled);
        }

        let c_string = CString::new(fn_name).expect("Conversion to CString failed unexpectedly");

        let address = LLVMGetFunctionAddress(*self.execution_engine, c_string.as_ptr());

        // REVIEW: Can also return 0 if no targets are initialized.
        // One option might be to set a global to true if any at all of the targets have been
        // initialized (maybe we could figure out which config in particular is the trigger)
        // and if not return an "NoTargetsInitialized" error, instead of not found.
        if address == 0 {
            return Err(FunctionLookupError::FunctionNotFound);
        }

        assert_eq!(size_of::<F>(), size_of::<usize>(),
            "The type `F` must have the same size as a function pointer");

        Ok(Symbol {
            execution_engine: self.execution_engine.clone(),
            inner: transmute_copy(&address),
        })
    }

    // REVIEW: Not sure if an EE's target data can change.. if so we might want to update the value
    // when making this call
    pub fn get_target_data(&self) -> &TargetData {
        self.target_data.as_ref().expect("TargetData should always exist until Drop")
    }

    // REVIEW: Can also find nothing if no targeting is initialized. Maybe best to
    // do have a global flag for anything initialized. Catch is that it must be initialized
    // before EE is created
    pub fn get_function_value(&self, fn_name: &str) -> Result<FunctionValue, FunctionLookupError> {
        if !self.jit_mode {
            return Err(FunctionLookupError::JITNotEnabled);
        }

        let c_string = CString::new(fn_name).expect("Conversion to CString failed unexpectedly");
        let mut function = unsafe { zeroed() };

        let code = unsafe {
            LLVMFindFunction(*self.execution_engine, c_string.as_ptr(), &mut function)
        };

        if code == 0 {
            return FunctionValue::new(function).ok_or(FunctionLookupError::FunctionNotFound)
        };

        Err(FunctionLookupError::FunctionNotFound)
    }

    // TODOC: Marked as unsafe because input function could very well do something unsafe. It's up to the caller
    // to ensure that doesn't happen by defining their function correctly.
    pub unsafe fn run_function(&self, function: &FunctionValue, args: &[&GenericValue]) -> GenericValue {
        let mut args: Vec<LLVMGenericValueRef> = args.iter()
                                                     .map(|val| val.generic_value)
                                                     .collect();

        let value = LLVMRunFunction(*self.execution_engine, function.as_value_ref(), args.len() as u32, args.as_mut_ptr()); // REVIEW: usize to u32 ok??

        GenericValue::new(value)
    }

    pub fn run_function_as_main(&self, function: &FunctionValue) {
        let args = vec![]; // TODO: Support argc, argv
        let env_p = vec![]; // REVIEW: No clue what this is

        unsafe {
            LLVMRunFunctionAsMain(*self.execution_engine, function.as_value_ref(), args.len() as u32, args.as_ptr(), env_p.as_ptr()); // REVIEW: usize to u32 cast ok??
        }
    }

    pub fn free_fn_machine_code(&self, function: &FunctionValue) {
        unsafe {
            LLVMFreeMachineCodeForFunction(*self.execution_engine, function.as_value_ref())
        }
    }
}

/// A wrapper around a function pointer which ensures the symbol being pointed
/// to doesn't accidentally outlive its execution engine.
#[derive(Debug, Clone)]
pub struct Symbol<F> {
    pub(crate) execution_engine: Rc<LLVMExecutionEngineRef>,
    inner: F,
}

impl<F> Deref for Symbol<F> {
    type Target = F;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

// Modules owned by the EE will be discarded by the EE so we don't
// want owned modules to drop.
impl Drop for ExecutionEngine {
    fn drop(&mut self) {
        forget(self.target_data.take().expect("TargetData should always exist until Drop"));

        if Rc::strong_count(&self.execution_engine) == 1 {
            unsafe {
                LLVMDisposeExecutionEngine(*self.execution_engine);
            }
        }
    }
}
<|endoftext|>


<commit_before>use game::constants::PISTOL_AUDIO_PATH;
use rodio;
use rodio::Sink;
use specs;
use specs::WriteStorage;
use std::fs::File;
use std::io::BufReader;
use std::sync::mpsc;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Effects {
  PistolFire,
  None
}

pub struct AudioData {
  sink: Sink,
}

impl AudioData {
  pub fn new() -> AudioData {
    let endpoint = rodio::default_endpoint().unwrap();

    AudioData {
      sink: Sink::new(&endpoint),
    }
  }

  pub fn play_effect(&mut self) {
    let file = File::open(PISTOL_AUDIO_PATH).unwrap();
    let pistol_data = rodio::Decoder::new(BufReader::new(file)).unwrap();
    if self.sink.empty() {
      self.sink.append(pistol_data);
    }
  }
}

impl specs::Component for AudioData {
  type Storage = specs::VecStorage<AudioData>;
}

pub struct AudioSystem {
  effects: Effects,
  queue: mpsc::Receiver<Effects>
}

impl AudioSystem {
  pub fn new() -> (AudioSystem, mpsc::Sender<Effects>) {
    #[allow(deprecated)]
    let (tx, rx) = mpsc::channel();

    (AudioSystem {
      effects: Effects::None,
      queue: rx,
    }, tx)
  }
}

impl<'a> specs::System<'a> for AudioSystem {
  type SystemData = WriteStorage<'a, AudioData>;

  fn run(&mut self, mut audio_data: Self::SystemData) {
    use specs::Join;

    while let Ok(effect) = self.queue.try_recv() {
      match effect {
        Effects::PistolFire => self.effects = Effects::PistolFire,
        _ => self.effects = Effects::None,
      }
    }

    for audio in (&mut audio_data).join() {
      match self.effects {
        Effects::PistolFire => audio.play_effect(),
        _ => (),
      }
    }
  }
}
<commit_msg>Change pattern match to simpler if let syntax<commit_after>use game::constants::PISTOL_AUDIO_PATH;
use rodio;
use rodio::Sink;
use specs;
use specs::WriteStorage;
use std::fs::File;
use std::io::BufReader;
use std::sync::mpsc;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Effects {
  PistolFire,
  None
}

pub struct AudioData {
  sink: Sink,
}

impl AudioData {
  pub fn new() -> AudioData {
    let endpoint = rodio::default_endpoint().unwrap();

    AudioData {
      sink: Sink::new(&endpoint),
    }
  }

  pub fn play_effect(&mut self) {
    let file = File::open(PISTOL_AUDIO_PATH).unwrap();
    let pistol_data = rodio::Decoder::new(BufReader::new(file)).unwrap();
    if self.sink.empty() {
      self.sink.append(pistol_data);
    }
  }
}

impl specs::Component for AudioData {
  type Storage = specs::VecStorage<AudioData>;
}

pub struct AudioSystem {
  effects: Effects,
  queue: mpsc::Receiver<Effects>
}

impl AudioSystem {
  pub fn new() -> (AudioSystem, mpsc::Sender<Effects>) {
    #[allow(deprecated)]
    let (tx, rx) = mpsc::channel();

    (AudioSystem {
      effects: Effects::None,
      queue: rx,
    }, tx)
  }
}

impl<'a> specs::System<'a> for AudioSystem {
  type SystemData = WriteStorage<'a, AudioData>;

  fn run(&mut self, mut audio_data: Self::SystemData) {
    use specs::Join;

    while let Ok(effect) = self.queue.try_recv() {
      match effect {
        Effects::PistolFire => self.effects = Effects::PistolFire,
        _ => self.effects = Effects::None,
      }
    }

    for audio in (&mut audio_data).join() {
      if let Effects::PistolFire = self.effects { audio.play_effect() }
    }
  }
}
<|endoftext|>


<commit_before>#![crate_type="dylib"]
#![feature(plugin_registrar)]
#![feature(rustc_private)]
// basic syntax extension to calculate the factorial of 10
// at compile time for the compile-time calculation
// task (the task itself is in compile_time_calculation.rs)
extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::codemap::Span;
use syntax::parse;
use syntax::ast::TokenTree;
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder;  // trait for expr_usize
use rustc::plugin::Registry;

fn exp_factorial(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
        -> Box<MacResult + 'static> {
    // extract the argument and ensure there is only one and it's a usize
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_vec());

    // Try to parse a literal (doesn't need to be a number)
    let literal = match parser.parse_lit() {
		Ok(l) => l,
		Err(_) => {
			// span_err shows a compile time error to the user
			cx.span_err(sp, "fatal error");
			return DummyResult::any(sp);
		}
	};

    // Take the number of the literal (if it is a number)
    let n: u64 = match literal.node {
        ast::LitInt(x, _) => x,
         _              => {
            cx.span_err(sp, "Invalid literal (expected unsigned integer)");
            return DummyResult::any(sp);
        }
    };

    // calculating the factorial
    let result = (1..(n as usize)+1).fold(1, |accum, elem| accum * elem);

    MacEager::expr(cx.expr_usize(sp, result))
}

// here's where we register the macro with the name of factorial_10
// so that it can be invoked a with every other macro with a ! at the end
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("factorial", exp_factorial);
}
<commit_msg>indentation<commit_after>#![crate_type="dylib"]
#![feature(plugin_registrar)]
#![feature(rustc_private)]
// basic syntax extension to calculate the factorial of 10
// at compile time for the compile-time calculation
// task (the task itself is in compile_time_calculation.rs)
extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::codemap::Span;
use syntax::parse;
use syntax::ast::TokenTree;
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder;  // trait for expr_usize
use rustc::plugin::Registry;

fn exp_factorial(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
        -> Box<MacResult + 'static> {
    // extract the argument and ensure there is only one and it's a usize
    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_vec());

    // Try to parse a literal (doesn't need to be a number)
    let literal = match parser.parse_lit() {
        Ok(l) => l,
        Err(_) => {
            // span_err shows a compile time error to the user
            cx.span_err(sp, "fatal error");
            return DummyResult::any(sp);
        }
    };

    // Take the number of the literal (if it is a number)
    let n: u64 = match literal.node {
        ast::LitInt(x, _) => x,
         _              => {
            cx.span_err(sp, "Invalid literal (expected unsigned integer)");
            return DummyResult::any(sp);
        }
    };

    // calculating the factorial
    let result = (1..(n as usize)+1).fold(1, |accum, elem| accum * elem);

    MacEager::expr(cx.expr_usize(sp, result))
}

// here's where we register the macro with the name of factorial_10
// so that it can be invoked a with every other macro with a ! at the end
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("factorial", exp_factorial);
}
<|endoftext|>


<commit_before>use events::{Event, EventHandler};
use formatter::formatter::Formatter;
use std::io;

pub struct Simple<'a, Io: io::Write + 'a> {
    buf: &'a mut Io
}

impl<'a, T : io::Write> Simple<'a, T> {
    fn new<'b>(buf: &'b mut T) -> Simple<'b, T> {
        Simple { buf: buf }
    }
}

impl<'a, T : io::Write> EventHandler for Simple<'a, T> {
    fn trigger(&mut self, event: Event) {
        let _ = match event {
            Event::StartRunner => writeln!(self.buf, "Running tests..."),
            Event::FinishedRunner(result) => writeln!(
                self.buf,
                "test result: ok. {0} examples; {0} passed; 0 failed;",
                result.unwrap().total_tests
            )
        };
    }
}
impl<'a, T : io::Write> Formatter for Simple<'a, T> {}

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

    #[test]
    fn it_can_be_instanciated() {
        Simple::new(&mut vec!(1u8));
    }

    #[test]
    fn it_impl_formatter_trait() {
        let _ : &Formatter = &Simple::new(&mut vec!(1u8)) as &Formatter;
    }

    #[cfg(test)]
    mod event_start_runner {
        pub use super::*;
        use events::{Event, EventHandler};
        use std::str;

        #[test]
        fn it_display_that_tests_started() {
            let mut v = vec!();
            {
                let mut s = Simple::new(&mut v);
                s.trigger(Event::StartRunner);
            }

            assert_eq!("Running tests...\n", str::from_utf8(&v).unwrap());
        }
    }

    #[cfg(test)]
    mod event_finished_runner {
        pub use super::*;
        use events::{Event, EventHandler};
        use runner::TestReport;
        use std::str;

        fn make_report(succes: u32, errors: u32) -> Result<TestReport, TestReport> {
            let mut report = TestReport::default();
            report.success_count = succes;
            report.error_count = errors;
            report.total_tests = succes + errors;

            if errors != 0 {
                Err(report)
            } else {
                Ok(report)
            }
        }

        #[test]
        fn one_test() {
            let mut v = vec!();
            {
                let mut s = Simple::new(&mut v);
                s.trigger(Event::FinishedRunner(make_report(1, 0)))
            }

            assert_eq!("test result: ok. 1 examples; 1 passed; 0 failed;\n",
                       str::from_utf8(&v).unwrap())
        }

        #[test]
        fn multiple_ok() {
            let mut v = vec!();
            {
                let mut s = Simple::new(&mut v);
                s.trigger(Event::FinishedRunner(make_report(42, 0)))
            }

            assert_eq!("test result: ok. 42 examples; 42 passed; 0 failed;\n",
                       str::from_utf8(&v).unwrap())
        }
    }
}
<commit_msg>Refactor FinishedRunner tests + make advancements<commit_after>use events::{Event, EventHandler};
use formatter::formatter::Formatter;
use runner;
use std::io;

pub struct Simple<'a, Io: io::Write + 'a> {
    buf: &'a mut Io
}

impl<'a, T : io::Write> Simple<'a, T> {
    fn new<'b>(buf: &'b mut T) -> Simple<'b, T> {
        Simple { buf: buf }
    }

    fn write_summary(&mut self, result: runner::RunnerResult) -> Result<(), io::Error> {
        let (res, report) = match result {
            Ok(report) => ("ok", report),
            Err(report) => ("FAILED", report)
        };

        writeln!(
            self.buf,
            "test result: {}. {} examples; {} passed; {} failed;",
            res,
            report.total_tests,
            report.success_count,
            report.error_count
        )
    }
}

impl<'a, T : io::Write> EventHandler for Simple<'a, T> {
    fn trigger(&mut self, event: Event) {
        // FIXME: do something with the io::Error ?
        let _ = match event {
            Event::StartRunner => writeln!(self.buf, "Running tests..."),
            Event::FinishedRunner(result) => self.write_summary(result)
        };
    }
}
impl<'a, T : io::Write> Formatter for Simple<'a, T> {}

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

    #[test]
    fn it_can_be_instanciated() {
        Simple::new(&mut vec!(1u8));
    }

    #[test]
    fn it_impl_formatter_trait() {
        let _ : &Formatter = &Simple::new(&mut vec!(1u8)) as &Formatter;
    }

    #[cfg(test)]
    mod event_start_runner {
        pub use super::*;
        use events::{Event, EventHandler};
        use std::str;

        #[test]
        fn it_display_that_tests_started() {
            let mut v = vec!();
            {
                let mut s = Simple::new(&mut v);
                s.trigger(Event::StartRunner);
            }

            assert_eq!("Running tests...\n", str::from_utf8(&v).unwrap());
        }
    }

    #[cfg(test)]
    mod event_finished_runner {
        pub use super::*;
        use events::{Event, EventHandler};
        use runner::TestReport;
        use std::str;

        fn make_report(succes: u32, errors: u32) -> Result<TestReport, TestReport> {
            let mut report = TestReport::default();
            report.success_count = succes;
            report.error_count = errors;
            report.total_tests = succes + errors;

            if errors != 0 {
                Err(report)
            } else {
                Ok(report)
            }
        }

        macro_rules! test_and_compare_output {
            ($(
                $test_name:ident : (success: $succ:expr, errors: $err:expr) => $msg:expr
            ),+) => {

                $(
                    #[test]
                    fn $test_name() {
                        let mut v = vec!();
                        {
                            let mut s = Simple::new(&mut v);
                            s.trigger(Event::FinishedRunner(make_report($succ, $err)))
                        }

                        assert_eq!($msg, str::from_utf8(&v).unwrap())
                    }
                )+
            }
        }

        test_and_compare_output! {
            no_test_is_ok: (success: 0, errors: 0) =>
                "test result: ok. 0 examples; 0 passed; 0 failed;\n",
            one_test: (success: 1, errors: 0) =>
                "test result: ok. 1 examples; 1 passed; 0 failed;\n",
            multiple_ok: (success: 42, errors: 0) =>
                "test result: ok. 42 examples; 42 passed; 0 failed;\n",
            one_error: (success: 0, errors: 1) =>
              "test result: FAILED. 1 examples; 0 passed; 1 failed;\n",
            multiple_errors: (success: 0, errors: 37) =>
              "test result: FAILED. 37 examples; 0 passed; 37 failed;\n"
        }
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;

use std::env;
use std::io::{self, Write};
use std::thread;
use std::time::Duration;

use coreutils::extra::{OptionalExt};

const MAN_PAGE: &'static str = r#"NAME
    sleep - delay for a specified amount of time

SYNOPSIS
    sleep [-h | --help] NUMBER[SUFFIX]...

DESCRIPTION
    Pause the shell for NUMBER seconds. An optional SUFFIX may be applied, such as 's' for seconds (default), 'm' for minutes, 'h' for hours or 'd' for day. Given multiple arguments, it will pause for the amount of time specified by the sum of their values. This implementation supports floating point numbers as input.

EXAMPLE
    The following are three possible arguments with the same effect:

    sleep {90, 1.5m, 1m 30s}

OPTIONS
    -h
    --help
        display this help and exit

AUTHOR
    Written by Michael Murphy.
"#;

const MISSING_OPERAND: &'static str = "missing operand";
const HELP_INFO:       &'static str = "Try 'sleep --help' for more information.";

fn main() {
    let stdout     = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    let mut args   = env::args().skip(1);

    if let Some(arg) = args.next() {
        match arg.as_str() {
            "-h" | "--help" => {
                stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
            },
            _ => {
                thread::sleep(Duration::from_millis(argument_to_ms(&arg)));
                for argument in args {
                    thread::sleep(Duration::from_millis(argument_to_ms(&argument)));
                }
            }
        }
    } else {
        stderr.write(MISSING_OPERAND.as_bytes()).try(&mut stderr);
        stdout.write(HELP_INFO.as_bytes()).try(&mut stderr);
    }
}

/// Check if the argument uses a time suffix and convert the time accordingly.
fn argument_to_ms(argument: &str) -> u64 {
    // If the argument is a number, the duration is in seconds, so multiply it by 1000.
    if let Ok(number) = argument.parse::<f64>() {
        return (number * 1000f64) as u64;
    }

    let mut stderr = io::stderr();

    // Split the argument into two strings at the last character. The first string should be the
    // number while the second string should be the duration unit:
    // s = seconds; m = minutes; h = hours; d = days
    let (prefix, suffix) = argument.split_at(argument.len()-1);
    if let Ok(number) = prefix.parse::<f64>() {
        match suffix {
            "s" => (number * 1000f64) as u64,
            "m" => (number * 60000f64) as u64,
            "h" => (number * 3600000f64) as u64,
            "d" => (number * 86400000f64) as u64,
            _   => {
                let mut output = String::from("invalid time interval '");
                output.push_str(argument);
                output.push_str("\'\n");
                stderr.write(output.as_bytes()).try(&mut stderr);
                std::process::exit(1);
            }
        }
    } else {
        let mut output = String::from("invalid time interval '");
        output.push_str(argument);
        output.push_str("\'\n");
        stderr.write(output.as_bytes()).try(&mut stderr);
        std::process::exit(1);
    }
}
<commit_msg>Fix More Issues<commit_after>#![deny(warnings)]

extern crate coreutils;

use std::env;
use std::io::{self, Write};
use std::thread;
use std::time::Duration;

use coreutils::extra::{OptionalExt};

const MAN_PAGE: &'static str = r#"NAME
    sleep - delay for a specified amount of time

SYNOPSIS
    sleep [-h | --help] NUMBER[SUFFIX]...

DESCRIPTION
    Pause the shell for NUMBER seconds. An optional SUFFIX may be applied, such as 's' for seconds (default), 'm' for minutes, 'h' for hours or 'd' for day. Given multiple arguments, it will pause for the amount of time specified by the sum of their values. This implementation supports floating point numbers as input.

EXAMPLE
    The following are three possible arguments with the same effect:

    sleep {90, 1.5m, 1m 30s}

OPTIONS
    -h
    --help
        display this help and exit

AUTHOR
    Written by Michael Murphy.
"#;

const MISSING_OPERAND: &'static str = "missing operand";
const HELP_INFO:       &'static str = "Try 'sleep --help' for more information.";

fn main() {
    let stdout     = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    let mut args   = env::args().skip(1);

    if let Some(arg) = args.next() {
        match arg.as_str() {
            "-h" | "--help" => {
                stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
            },
            _ => {
                thread::sleep(Duration::from_millis(argument_to_ms(&arg)));
                for argument in args {
                    thread::sleep(Duration::from_millis(argument_to_ms(&argument)));
                }
            }
        }
    } else {
        stderr.write(MISSING_OPERAND.as_bytes()).try(&mut stderr);
        stdout.write(HELP_INFO.as_bytes()).try(&mut stderr);
    }
}

/// Check if the argument uses a time suffix and convert the time accordingly.
fn argument_to_ms(argument: &str) -> u64 {
    // If the argument is a number, the duration is in seconds, so multiply it by 1000.
    if let Ok(number) = argument.parse::<f64>() {
        return (number * 1000f64) as u64;
    }

    let mut stderr = io::stderr();

    // Split the argument into two strings at the last character. The first string should be the
    // number while the second string should be the duration unit:
    // s = seconds; m = minutes; h = hours; d = days
    let (prefix, suffix) = argument.split_at(argument.len()-1);
    if let Ok(number) = prefix.parse::<f64>() {
        match suffix {
            "s" => (number * 1000f64) as u64,
            "m" => (number * 60000f64) as u64,
            "h" => (number * 3600000f64) as u64,
            "d" => (number * 86400000f64) as u64,
            _   => {
                stderr.write(b"invalid time interval '").try(&mut stderr);
                stderr.write(argument.as_bytes()).try(&mut stderr);
                stderr.write(b"\'\n").try(&mut stderr);
                stderr.flush().try(&mut stderr);
                std::process::exit(1);
            }
        }
    } else {
        stderr.write(b"invalid time interval '").try(&mut stderr);
        stderr.write(argument.as_bytes()).try(&mut stderr);
        stderr.write(b"\'\n").try(&mut stderr);
        stderr.flush().try(&mut stderr);
        std::process::exit(1);
    }
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Matches
//!
//! These functions deal with establishing how much of a particular stream (or string) matches a particular pattern. The
//! most important function is `matches`, which takes a stream and a pattern and returns the number of characters from the
//! stream that matches the pattern. Use it like this:
//!
//! ```
//! # use ndfa::*;
//! # assert!(matches("abcabc", "abc".repeat_forever(1)) == Some(6));
//! # assert!(matches("abcabcabc", "abc".repeat_forever(1)).is_some());
//! # assert!(matches("abc", "abc").is_some());
//! # assert!(matches("def", "abc".repeat_forever(1)).is_none());
//! if matches("abcabc", "abc".repeat_forever(1)) == Some(6) { /* ... */ }
//! ```
//!
//! To determine if a string exactly matches a pattern, compare to the string length like this:
//!
//! ```
//! # use ndfa::*;
//! let input_string = "abcabc";
//! let pattern      = "abc".repeat_forever(1);
//!
//! if matches(input_string, pattern) == Some(input_string.len()) { }
//! # assert!(matches(input_string, "abc".repeat_forever(1)) == Some(input_string.len()));
//! ```
//!

use super::symbol_range_dfa::*;
use super::symbol_reader::*;
use super::pattern_matcher::*;
use super::prepare::*;

///
/// Runs a DFA against a symbol stream and returns its final state
///
/// This takes a DFA match action as an initial state (such as that returned by `SymbolRangeDfa::start()`) and runs it until it accepts
/// or rejects the pattern passed to it.
///
/// This call is useful for cases where there is more than one output symbol (as the output symbol that was matched can be retrieved)
/// or for working with pattern matchers other than the default one.
///
/// ```
/// # use ndfa::*;
/// let input_string = "abcabc";
/// let pattern      = "abc".repeat_forever(1);
/// let matcher      = pattern.prepare_to_match();
///
/// let match_result = match_pattern(matcher.start(), &mut input_string.read_symbols()); // == Accept(6, &true)
/// # assert!(match match_result { Accept(count, val) => count == 6 && val == &true, _ => false });
/// ```
///
pub fn match_pattern<'a, InputSymbol: Ord, OutputSymbol, State>(start_state: MatchAction<'a, OutputSymbol, State>, symbol_reader: &mut SymbolReader<InputSymbol>) -> MatchAction<'a, OutputSymbol, State>
where State: MatchingState<'a, InputSymbol, OutputSymbol> {
    let mut current_state = start_state;

    while let More(this_state) = current_state {
        let next_state =
            if let Some(next_char) = symbol_reader.next_symbol() {
                this_state.next(next_char)
            } else {
                this_state.finish()
            };

        current_state = next_state;
    }

    current_state
}

///
/// Runs a pattern matcher against a stream, and returns the number of characters matching if it accepted the stream
///
fn matches_symbol_range<InputSymbol: Ord, OutputSymbol: 'static>(dfa: &SymbolRangeDfa<InputSymbol, OutputSymbol>, symbol_reader: &mut SymbolReader<InputSymbol>) -> Option<usize> {
    // Run the DFA
    let final_state = match_pattern(dfa.start(), symbol_reader);

    if let Accept(count, _) = final_state {
        Some(count)
    } else {
        None
    }
}

///
/// Matches a source stream against a pattern
///
/// This is the basic pattern matcher. It matches against the left-hand side of the source, and if there is a string of any
/// length that can match the passed in pattern it will return the length of that string. Pattern matchers should be greedy,
/// so this will return the length of the longest string that can match the given pattern.
///
/// ```
/// # use ndfa::*;
/// matches("abc", "abc");                      // Returns Some(3)
/// matches("abcabc", "abc");                   // Also returns Some(3) as 'abc' matches the pattern
/// matches("abcabc", "abc".repeat_forever(0)); // Returns Some(6)
/// matches("ab", "abc");                       // Doesn't match: returns None
/// ```
///
pub fn matches<'a, Symbol, OutputSymbol, Prepare, Reader, Source>(source: Source, pattern: Prepare) -> Option<usize>
where   Prepare: PrepareToMatch<SymbolRangeDfa<Symbol, OutputSymbol>>
,       Reader: SymbolReader<Symbol>+'a
,       Source: SymbolSource<'a, Symbol, SymbolReader=Reader>
,       Symbol: Ord
,       OutputSymbol: 'static {
    let matcher    = pattern.prepare_to_match();
    let mut reader = source.read_symbols();

    matches_symbol_range(&matcher, &mut reader)
}

///
/// Matches a source stream against a prepared pattern
///
/// If it's necessary to match a pattern against a lot of different things, then preparing it by calling `pattern.prepare_to_match()`
/// will increase the performance of the matcher for every match after the first one. This call is otherwise identical to `matches`.
///
pub fn matches_prepared<'a, Symbol, OutputSymbol, Reader, Source>(source: Source, matcher: &SymbolRangeDfa<Symbol, OutputSymbol>) -> Option<usize>
where   Reader: SymbolReader<Symbol>+'a
,       Source: SymbolSource<'a, Symbol, SymbolReader=Reader>
,       Symbol: Ord
,       OutputSymbol: 'static {
    let mut reader = source.read_symbols();

    matches_symbol_range(&matcher, &mut reader)
}

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

    #[test]
    fn match_multiple_repeats() {
        assert!(matches("abcabc", "abc".repeat_forever(1)).is_some());
    }

    #[test]
    fn match_prepared() {
        let prepared = "abc".repeat_forever(1).prepare_to_match();

        assert!(matches_prepared("abcabc", &prepared) == Some(6));
        assert!(matches_prepared("abc", &prepared) == Some(3));
        assert!(matches_prepared("abcabcabc", &prepared) == Some(9));
    }

    #[test]
    fn match_single_repeat() {
        assert!(matches("abc", "abc".repeat_forever(1)).is_some());
    }

    #[test]
    fn match_with_zero_or_more() {
        assert!(matches("abc", "abc".repeat_forever(0)).is_some());
        assert!(matches("abcabc", "abc".repeat_forever(0)).is_some());
        assert!(matches("abcabcabc", "abc".repeat_forever(0)).is_some());
    }

    #[test]
    fn match_with_zero_or_more_following() {
        assert!(matches("abc", "abc".repeat_forever(0).append("def")).is_none());
        assert!(matches("abcabc", "abc".repeat_forever(0).append("def")).is_none());

        assert!(matches("abcdef", "abc".repeat_forever(0).append("def")).is_some());
        assert!(matches("abcabcdef", "abc".repeat_forever(0).append("def")).is_some());
    }

    #[test]
    fn match_limited_range() {
        assert!(matches("abc", "abc".repeat(2..4)).is_none());
        assert!(matches("abcabc", "abc".repeat(2..4)).is_some());
        assert!(matches("abcabcabc", "abc".repeat(2..4)) == Some(3*3));
        assert!(matches("abcabcabcabc", "abc".repeat(2..4)) == Some(3*3));
    }

    /* -- BROKEN
    #[test]
    fn match_zero_repeats() {
        assert!(matches("", "abc".repeat_forever(0)).is_some());
    }
    */
}
<commit_msg>Add example for matches_prepared<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Matches
//!
//! These functions deal with establishing how much of a particular stream (or string) matches a particular pattern. The
//! most important function is `matches`, which takes a stream and a pattern and returns the number of characters from the
//! stream that matches the pattern. Use it like this:
//!
//! ```
//! # use ndfa::*;
//! # assert!(matches("abcabc", "abc".repeat_forever(1)) == Some(6));
//! # assert!(matches("abcabcabc", "abc".repeat_forever(1)).is_some());
//! # assert!(matches("abc", "abc").is_some());
//! # assert!(matches("def", "abc".repeat_forever(1)).is_none());
//! if matches("abcabc", "abc".repeat_forever(1)) == Some(6) { /* ... */ }
//! ```
//!
//! To determine if a string exactly matches a pattern, compare to the string length like this:
//!
//! ```
//! # use ndfa::*;
//! let input_string = "abcabc";
//! let pattern      = "abc".repeat_forever(1);
//!
//! if matches(input_string, pattern) == Some(input_string.len()) { }
//! # assert!(matches(input_string, "abc".repeat_forever(1)) == Some(input_string.len()));
//! ```
//!

use super::symbol_range_dfa::*;
use super::symbol_reader::*;
use super::pattern_matcher::*;
use super::prepare::*;

///
/// Runs a DFA against a symbol stream and returns its final state
///
/// This takes a DFA match action as an initial state (such as that returned by `SymbolRangeDfa::start()`) and runs it until it accepts
/// or rejects the pattern passed to it.
///
/// This call is useful for cases where there is more than one output symbol (as the output symbol that was matched can be retrieved)
/// or for working with pattern matchers other than the default one.
///
/// ```
/// # use ndfa::*;
/// let input_string = "abcabc";
/// let pattern      = "abc".repeat_forever(1);
/// let matcher      = pattern.prepare_to_match();
///
/// let match_result = match_pattern(matcher.start(), &mut input_string.read_symbols()); // == Accept(6, &true)
/// # assert!(match match_result { Accept(count, val) => count == 6 && val == &true, _ => false });
/// ```
///
pub fn match_pattern<'a, InputSymbol: Ord, OutputSymbol, State>(start_state: MatchAction<'a, OutputSymbol, State>, symbol_reader: &mut SymbolReader<InputSymbol>) -> MatchAction<'a, OutputSymbol, State>
where State: MatchingState<'a, InputSymbol, OutputSymbol> {
    let mut current_state = start_state;

    while let More(this_state) = current_state {
        let next_state =
            if let Some(next_char) = symbol_reader.next_symbol() {
                this_state.next(next_char)
            } else {
                this_state.finish()
            };

        current_state = next_state;
    }

    current_state
}

///
/// Runs a pattern matcher against a stream, and returns the number of characters matching if it accepted the stream
///
fn matches_symbol_range<InputSymbol: Ord, OutputSymbol: 'static>(dfa: &SymbolRangeDfa<InputSymbol, OutputSymbol>, symbol_reader: &mut SymbolReader<InputSymbol>) -> Option<usize> {
    // Run the DFA
    let final_state = match_pattern(dfa.start(), symbol_reader);

    if let Accept(count, _) = final_state {
        Some(count)
    } else {
        None
    }
}

///
/// Matches a source stream against a pattern
///
/// This is the basic pattern matcher. It matches against the left-hand side of the source, and if there is a string of any
/// length that can match the passed in pattern it will return the length of that string. Pattern matchers should be greedy,
/// so this will return the length of the longest string that can match the given pattern.
///
/// ```
/// # use ndfa::*;
/// matches("abc", "abc");                      // Returns Some(3)
/// matches("abcabc", "abc");                   // Also returns Some(3) as 'abc' matches the pattern
/// matches("abcabc", "abc".repeat_forever(0)); // Returns Some(6)
/// matches("ab", "abc");                       // Doesn't match: returns None
/// ```
///
pub fn matches<'a, Symbol, OutputSymbol, Prepare, Reader, Source>(source: Source, pattern: Prepare) -> Option<usize>
where   Prepare: PrepareToMatch<SymbolRangeDfa<Symbol, OutputSymbol>>
,       Reader: SymbolReader<Symbol>+'a
,       Source: SymbolSource<'a, Symbol, SymbolReader=Reader>
,       Symbol: Ord
,       OutputSymbol: 'static {
    let matcher    = pattern.prepare_to_match();
    let mut reader = source.read_symbols();

    matches_symbol_range(&matcher, &mut reader)
}

///
/// Matches a source stream against a prepared pattern
///
/// If it's necessary to match a pattern against a lot of different things, then preparing it by calling `pattern.prepare_to_match()`
/// will increase the performance of the matcher for every match after the first one. This call is otherwise identical to `matches`.
///
/// ```
/// # use ndfa::*;
/// let prepared = "abc".repeat_forever(1).prepare_to_match();
///
/// matches_prepared("abcabc", &prepared);      // == Some(6));
/// matches_prepared("abc", &prepared);         // == Some(3));
/// matches_prepared("abcabcabc", &prepared);   // == Some(9));
/// ```
///
pub fn matches_prepared<'a, Symbol, OutputSymbol, Reader, Source>(source: Source, matcher: &SymbolRangeDfa<Symbol, OutputSymbol>) -> Option<usize>
where   Reader: SymbolReader<Symbol>+'a
,       Source: SymbolSource<'a, Symbol, SymbolReader=Reader>
,       Symbol: Ord
,       OutputSymbol: 'static {
    let mut reader = source.read_symbols();

    matches_symbol_range(&matcher, &mut reader)
}

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

    #[test]
    fn match_multiple_repeats() {
        assert!(matches("abcabc", "abc".repeat_forever(1)).is_some());
    }

    #[test]
    fn match_prepared() {
        let prepared = "abc".repeat_forever(1).prepare_to_match();

        assert!(matches_prepared("abcabc", &prepared) == Some(6));
        assert!(matches_prepared("abc", &prepared) == Some(3));
        assert!(matches_prepared("abcabcabc", &prepared) == Some(9));
    }

    #[test]
    fn match_single_repeat() {
        assert!(matches("abc", "abc".repeat_forever(1)).is_some());
    }

    #[test]
    fn match_with_zero_or_more() {
        assert!(matches("abc", "abc".repeat_forever(0)).is_some());
        assert!(matches("abcabc", "abc".repeat_forever(0)).is_some());
        assert!(matches("abcabcabc", "abc".repeat_forever(0)).is_some());
    }

    #[test]
    fn match_with_zero_or_more_following() {
        assert!(matches("abc", "abc".repeat_forever(0).append("def")).is_none());
        assert!(matches("abcabc", "abc".repeat_forever(0).append("def")).is_none());

        assert!(matches("abcdef", "abc".repeat_forever(0).append("def")).is_some());
        assert!(matches("abcabcdef", "abc".repeat_forever(0).append("def")).is_some());
    }

    #[test]
    fn match_limited_range() {
        assert!(matches("abc", "abc".repeat(2..4)).is_none());
        assert!(matches("abcabc", "abc".repeat(2..4)).is_some());
        assert!(matches("abcabcabc", "abc".repeat(2..4)) == Some(3*3));
        assert!(matches("abcabcabcabc", "abc".repeat(2..4)) == Some(3*3));
    }

    /* -- BROKEN
    #[test]
    fn match_zero_repeats() {
        assert!(matches("", "abc".repeat_forever(0)).is_some());
    }
    */
}
<|endoftext|>