<commit_before>mod swig_foreign_types_map {
    #![swig_foreigner_type = "void"]
    #![swig_rust_type = "()"]
    #![swig_foreigner_type = "int8_t"]
    #![swig_rust_type = "i8"]
    #![swig_foreigner_type = "uint8_t"]
    #![swig_rust_type = "u8"]
    #![swig_foreigner_type = "int16_t"]
    #![swig_rust_type = "i16"]
    #![swig_foreigner_type = "uint16_t"]
    #![swig_rust_type = "u16"]
    #![swig_foreigner_type = "int32_t"]
    #![swig_rust_type = "i32"]
    #![swig_foreigner_type = "uint32_t"]
    #![swig_rust_type = "u32"]
    #![swig_foreigner_type = "int64_t"]
    #![swig_rust_type = "i64"]
    #![swig_foreigner_type = "uint64_t"]
    #![swig_rust_type = "u64"]
    #![swig_foreigner_type = "float"]
    #![swig_rust_type = "f32"]
    #![swig_foreigner_type = "double"]
    #![swig_rust_type = "f64"]
    #![swig_foreigner_type = "char"]
    #![swig_rust_type = "::std::os::raw::c_char"]
    #![swig_foreigner_type = "const char *"]
    #![swig_rust_type = "*const ::std::os::raw::c_char"]
    #![swig_foreigner_type = "struct RustStrView"]
    #![swig_rust_type = "RustStrView"]
    #![swig_foreigner_type = "struct RustVecBytes"]
    #![swig_rust_type = "RustVecBytes"]
}

#[allow(unused_macros)]
macro_rules! swig_c_str {
    ($lit:expr) => {
        concat!($lit, "\0").as_ptr()
            as *const ::std::os::raw::c_char
    }
}

#[allow(dead_code)]
trait SwigForeignClass {
    fn c_class_name() -> *const ::std::os::raw::c_char;
    fn box_object(x: Self) -> *mut ::std::os::raw::c_void;
}

#[allow(dead_code)]
#[swig_code = "let mut {to_var}: {to_var_type} = {from_var}.swig_into();"]
trait SwigInto<T> {
    fn swig_into(self) -> T;
}

#[allow(dead_code)]
#[swig_code = "let mut {to_var}: {to_var_type} = <{to_var_type}>::swig_from({from_var});"]
trait SwigFrom<T> {
    fn swig_from(T) -> Self;
}

#[allow(dead_code)]
#[swig_code = "let mut {to_var}: {to_var_type} = {from_var}.swig_deref();"]
trait SwigDeref {
    type Target: ?Sized;
    fn swig_deref(&self) -> &Self::Target;
}

#[allow(dead_code)]
#[swig_code = "let mut {to_var}: {to_var_type} = {from_var}.swig_deref_mut();"]
trait SwigDerefMut {
    type Target: ?Sized;
    fn swig_deref_mut(&mut self) -> &mut Self::Target;
}

impl SwigInto<bool> for ::std::os::raw::c_char {
    fn swig_into(self) -> bool {
        self != 0
    }
}

impl SwigFrom<bool> for ::std::os::raw::c_char {
    fn swig_from(x: bool) -> Self {
        if x {
            1
        } else {
            0
        }
    }
}

impl<'a> SwigInto<&'a ::std::ffi::CStr> for *const ::std::os::raw::c_char {
    fn swig_into(self) -> &'a ::std::ffi::CStr {
        assert!(!self.is_null());
        unsafe { ::std::ffi::CStr::from_ptr(self) }
    }
}

impl<'a> SwigDeref for &'a ::std::ffi::CStr {
    type Target = str;
    fn swig_deref(&self) -> &Self::Target {
        self.to_str().expect("wrong utf-8")
    }
}

#[allow(dead_code)]
#[repr(C)]
pub struct RustStrView {
    data: *const ::std::os::raw::c_char,
    len: u32,
}

impl<'a> SwigFrom<&'a str> for RustStrView {
    fn swig_from(s: &'a str) -> RustStrView {
        assert!((s.len() as u64) <= (::std::u32::MAX as u64));
        RustStrView {
            data: s.as_ptr() as *const ::std::os::raw::c_char,
            len: s.len() as u32,
        }
    }
}
impl<T> SwigDeref for Arc<Mutex<T>> {
    type Target = Mutex<T>;
    fn swig_deref(&self) -> &Mutex<T> {
        self
    }
}

impl<'a, T> SwigFrom<&'a Mutex<T>> for MutexGuard<'a, T> {
    fn swig_from(m: &'a Mutex<T>) -> MutexGuard<'a, T> {
        m.lock().unwrap()
    }
}

impl<'a, T> SwigDeref for MutexGuard<'a, T> {
    type Target = T;
    fn swig_deref(&self) -> &T {
        self
    }
}

impl<'a, T> SwigDerefMut for MutexGuard<'a, T> {
    type Target = T;
    fn swig_deref_mut(&mut self) -> &mut T {
        self
    }
}

impl<T> SwigDeref for Rc<T> {
    type Target = T;
    fn swig_deref(&self) -> &T {
        self
    }
}

impl<'a, T> SwigDeref for &'a Rc<T> {
    type Target = T;
    fn swig_deref(&self) -> &T {
        self
    }
}

impl<'a, T> SwigFrom<&'a RefCell<T>> for Ref<'a, T> {
    fn swig_from(m: &'a RefCell<T>) -> Ref<'a, T> {
        m.borrow()
    }
}

impl<'a, T> SwigFrom<&'a RefCell<T>> for RefMut<'a, T> {
    fn swig_from(m: &'a RefCell<T>) -> RefMut<'a, T> {
        m.borrow_mut()
    }
}

impl<'a, T> SwigDeref for Ref<'a, T> {
    type Target = T;
    fn swig_deref(&self) -> &T {
        self
    }
}

impl<'a, T> SwigDerefMut for RefMut<'a, T> {
    type Target = T;
    fn swig_deref_mut(&mut self) -> &mut T {
        self
    }
}

impl<T: SwigForeignClass> SwigDeref for T {
    type Target = T;
    fn swig_deref(&self) -> &T {
        self
    }
}

impl<T: SwigForeignClass> SwigDerefMut for T {
    type Target = T;
    fn swig_deref_mut(&mut self) -> &mut T {
        self
    }
}

#[swig_to_foreigner_hint = "T"]
impl<T: SwigForeignClass> SwigFrom<T> for *mut ::std::os::raw::c_void {
    fn swig_from(x: T) -> Self {
        <T>::box_object(x)
    }
}

#[allow(dead_code)]
#[repr(C)]
pub struct RustVecBytes {
    data: *const u8,
    len: u32,
    capacity: u32,
}

impl SwigFrom<Vec<u8>> for RustVecBytes {
    fn swig_from(mut v: Vec<u8>) -> RustVecBytes {
        let p = v.as_mut_ptr();
        let len = v.len();
        let cap = v.capacity();
        ::std::mem::forget(v);
        //todo check that u32 <-> usize safe, or may be use u64?
        RustVecBytes {
            data: p,
            len: len as u32,
            capacity: cap as u32,
        }
    }
}

#[allow(private_no_mangle_fns)]
#[no_mangle]
pub extern "C" fn rust_vec_bytes_free(v: RustVecBytes) {
    //todo check that u32 <-> usize safe, or may be use u64?
    let v = unsafe {
        Vec::from_raw_parts(v.data as *mut u8, v.len as usize, v.capacity as usize)
    };
    drop(v);
}
<commit_msg>c++ feature: add usize conversation<commit_after>mod swig_foreign_types_map {
    #![swig_foreigner_type = "void"]
    #![swig_rust_type = "()"]
    #![swig_foreigner_type = "int8_t"]
    #![swig_rust_type = "i8"]
    #![swig_foreigner_type = "uint8_t"]
    #![swig_rust_type = "u8"]
    #![swig_foreigner_type = "int16_t"]
    #![swig_rust_type = "i16"]
    #![swig_foreigner_type = "uint16_t"]
    #![swig_rust_type = "u16"]
    #![swig_foreigner_type = "int32_t"]
    #![swig_rust_type = "i32"]
    #![swig_foreigner_type = "uint32_t"]
    #![swig_rust_type = "u32"]
    #![swig_foreigner_type = "int64_t"]
    #![swig_rust_type = "i64"]
    #![swig_foreigner_type = "uint64_t"]
    #![swig_rust_type = "u64"]
    #![swig_foreigner_type = "uintptr_t"]
    #![swig_rust_type = "usize"]
    #![swig_foreigner_type = "float"]
    #![swig_rust_type = "f32"]
    #![swig_foreigner_type = "double"]
    #![swig_rust_type = "f64"]
    #![swig_foreigner_type = "char"]
    #![swig_rust_type = "::std::os::raw::c_char"]
    #![swig_foreigner_type = "const char *"]
    #![swig_rust_type = "*const ::std::os::raw::c_char"]
    #![swig_foreigner_type = "struct RustStrView"]
    #![swig_rust_type = "RustStrView"]
    #![swig_foreigner_type = "struct RustVecBytes"]
    #![swig_rust_type = "RustVecBytes"]
}

#[allow(unused_macros)]
macro_rules! swig_c_str {
    ($lit:expr) => {
        concat!($lit, "\0").as_ptr()
            as *const ::std::os::raw::c_char
    }
}

#[allow(dead_code)]
trait SwigForeignClass {
    fn c_class_name() -> *const ::std::os::raw::c_char;
    fn box_object(x: Self) -> *mut ::std::os::raw::c_void;
}

#[allow(dead_code)]
#[swig_code = "let mut {to_var}: {to_var_type} = {from_var}.swig_into();"]
trait SwigInto<T> {
    fn swig_into(self) -> T;
}

#[allow(dead_code)]
#[swig_code = "let mut {to_var}: {to_var_type} = <{to_var_type}>::swig_from({from_var});"]
trait SwigFrom<T> {
    fn swig_from(T) -> Self;
}

#[allow(dead_code)]
#[swig_code = "let mut {to_var}: {to_var_type} = {from_var}.swig_deref();"]
trait SwigDeref {
    type Target: ?Sized;
    fn swig_deref(&self) -> &Self::Target;
}

#[allow(dead_code)]
#[swig_code = "let mut {to_var}: {to_var_type} = {from_var}.swig_deref_mut();"]
trait SwigDerefMut {
    type Target: ?Sized;
    fn swig_deref_mut(&mut self) -> &mut Self::Target;
}

impl SwigInto<bool> for ::std::os::raw::c_char {
    fn swig_into(self) -> bool {
        self != 0
    }
}

impl SwigFrom<bool> for ::std::os::raw::c_char {
    fn swig_from(x: bool) -> Self {
        if x {
            1
        } else {
            0
        }
    }
}

impl<'a> SwigInto<&'a ::std::ffi::CStr> for *const ::std::os::raw::c_char {
    fn swig_into(self) -> &'a ::std::ffi::CStr {
        assert!(!self.is_null());
        unsafe { ::std::ffi::CStr::from_ptr(self) }
    }
}

impl<'a> SwigDeref for &'a ::std::ffi::CStr {
    type Target = str;
    fn swig_deref(&self) -> &Self::Target {
        self.to_str().expect("wrong utf-8")
    }
}

#[allow(dead_code)]
#[repr(C)]
pub struct RustStrView {
    data: *const ::std::os::raw::c_char,
    len: u32,
}

impl<'a> SwigFrom<&'a str> for RustStrView {
    fn swig_from(s: &'a str) -> RustStrView {
        assert!((s.len() as u64) <= (::std::u32::MAX as u64));
        RustStrView {
            data: s.as_ptr() as *const ::std::os::raw::c_char,
            len: s.len() as u32,
        }
    }
}
impl<T> SwigDeref for Arc<Mutex<T>> {
    type Target = Mutex<T>;
    fn swig_deref(&self) -> &Mutex<T> {
        self
    }
}

impl<'a, T> SwigFrom<&'a Mutex<T>> for MutexGuard<'a, T> {
    fn swig_from(m: &'a Mutex<T>) -> MutexGuard<'a, T> {
        m.lock().unwrap()
    }
}

impl<'a, T> SwigDeref for MutexGuard<'a, T> {
    type Target = T;
    fn swig_deref(&self) -> &T {
        self
    }
}

impl<'a, T> SwigDerefMut for MutexGuard<'a, T> {
    type Target = T;
    fn swig_deref_mut(&mut self) -> &mut T {
        self
    }
}

impl<T> SwigDeref for Rc<T> {
    type Target = T;
    fn swig_deref(&self) -> &T {
        self
    }
}

impl<'a, T> SwigDeref for &'a Rc<T> {
    type Target = T;
    fn swig_deref(&self) -> &T {
        self
    }
}

impl<'a, T> SwigFrom<&'a RefCell<T>> for Ref<'a, T> {
    fn swig_from(m: &'a RefCell<T>) -> Ref<'a, T> {
        m.borrow()
    }
}

impl<'a, T> SwigFrom<&'a RefCell<T>> for RefMut<'a, T> {
    fn swig_from(m: &'a RefCell<T>) -> RefMut<'a, T> {
        m.borrow_mut()
    }
}

impl<'a, T> SwigDeref for Ref<'a, T> {
    type Target = T;
    fn swig_deref(&self) -> &T {
        self
    }
}

impl<'a, T> SwigDerefMut for RefMut<'a, T> {
    type Target = T;
    fn swig_deref_mut(&mut self) -> &mut T {
        self
    }
}

impl<T: SwigForeignClass> SwigDeref for T {
    type Target = T;
    fn swig_deref(&self) -> &T {
        self
    }
}

impl<T: SwigForeignClass> SwigDerefMut for T {
    type Target = T;
    fn swig_deref_mut(&mut self) -> &mut T {
        self
    }
}

#[swig_to_foreigner_hint = "T"]
impl<T: SwigForeignClass> SwigFrom<T> for *mut ::std::os::raw::c_void {
    fn swig_from(x: T) -> Self {
        <T>::box_object(x)
    }
}

#[allow(dead_code)]
#[repr(C)]
pub struct RustVecBytes {
    data: *const u8,
    len: u32,
    capacity: u32,
}

impl SwigFrom<Vec<u8>> for RustVecBytes {
    fn swig_from(mut v: Vec<u8>) -> RustVecBytes {
        let p = v.as_mut_ptr();
        let len = v.len();
        let cap = v.capacity();
        ::std::mem::forget(v);
        //todo check that u32 <-> usize safe, or may be use u64?
        RustVecBytes {
            data: p,
            len: len as u32,
            capacity: cap as u32,
        }
    }
}

#[allow(private_no_mangle_fns)]
#[no_mangle]
pub extern "C" fn rust_vec_bytes_free(v: RustVecBytes) {
    //todo check that u32 <-> usize safe, or may be use u64?
    let v = unsafe {
        Vec::from_raw_parts(v.data as *mut u8, v.len as usize, v.capacity as usize)
    };
    drop(v);
}
<|endoftext|>


<commit_before>use std::{thread, time};
use std::env;
use std::io::prelude::*;
use std::fs::File;

/// Chipate Module
/// Rust emulation of the Chip-8
/// http://www.multigesturearticles/how-to-write-an-emulator-chip-8-interpreter/
#[allow(dead_code)]
pub struct Chipate {
    // Opcodes
    opcode: u16,

    // 4K Memory
    memory: [u8; 4096],
    // The systems memory map:
    // 0x000-0x1FF - Chip 8 interpreter (contains font set in emu)
    // 0x050-0x0A0 - Used for the built in 4x5 pixel font set (0-F)
    // 0x200-0xFFF - Program ROM and work RAM

    // Registers
    v: [u8; 16],

    // Index
    i: u16,

    // Program Counter
    pc: u16,

    gfx: [u8; 64 * 32],

    // Timers
    delay_timer: u8,
    sound_timer: u8,

    // Stack
    stack: [u8; 16],
    sp: u8,

    // Keypad
    key: [u8; 16],

    program: &'static str,
}

impl Chipate {
    pub fn init(&mut self) {
        debug!("Initialize Chip");
        // pc     = 0x200;  // Program counter starts at 0x200
        self.pc = 0x200;
        // opcode = 0;      // Reset current opcode
        self.opcode = 0x0;
        // I      = 0;      // Reset index register
        self.i = 0x0;
        // sp     = 0;      // Reset stack pointer
        self.sp = 0x0;

        // // Clear display
        // // Clear stack
        // // Clear registers V0-VF
        // // Clear memory

        // // Load fontset
        // for(int i = 0; i < 80; ++i)
        //     memory[i] = chip8_fontset[i];

        // // Reset timers
    }

    pub fn load_program(&mut self, program: &str) {
        debug!("Loading program {}", program);

        // We assume that we are in a valid directory.
        let mut p = env::current_dir().unwrap();
        p.push("programs");
        p.push(program);

        let mut f = File::open(p).expect("Unable to open file");
        let mut b = Vec::new();

        f.read_to_end(&mut b).expect("Unable to read file");

        for i in 0..b.len() {
            self.memory[i + 512] = b[i];
        }

    }

    pub fn emulate_cycle(&mut self) {
        debug!("Cycle Begin");

        self.fetch_opcode();
        self.decode_opcode();

        let one_second = time::Duration::from_millis(15);
        thread::sleep(one_second);

        debug!("Cycle End");
    }

    pub fn draw_screen(&mut self) {
        debug!("Drawing to Screen")
    }

    pub fn set_keys(&mut self) {
        debug!("Saving Key State")
    }

    // pub fn setup_testing_memory(&mut self) {
    //     debug!("Setting test memory");

    //     self.memory[self.pc as usize] = 0xA2;
    //     self.memory[(self.pc + 1) as usize] = 0xF0;

    //     debug!("Location: 0x{:X} data: 0x{:X}",
    //            self.pc,
    //            self.memory[self.pc as usize]);
    //     debug!("Location: 0x{:X} data: 0x{:X}",
    //            self.pc + 1,
    //            self.memory[(self.pc + 1) as usize]);
    // }

    pub fn fetch_opcode(&mut self) {
        let op_a = self.memory[self.pc as usize];
        self.opcode = op_a as u16;
        self.opcode = self.opcode << 8;
        // debug!("location: 0x{:X} data: 0x{:X}", self.pc, self.opcode);

        let op_b = self.memory[(self.pc + 1) as usize] as u16;
        // debug!("location: 0x{:X} data: 0x{:X}", self.pc, op_b);

        self.opcode = self.opcode | op_b;
        debug!("Opcode: 0x{:X}", self.opcode);
    }

    pub fn decode_opcode(&mut self) {
        let op = self.opcode & 0xF000;
        debug!("Decode: 0x{:X}", op);

        match op {
            0x2000 => self._2nnn_opcode(),
            0x6000 => self._6xnn_opcode(),
            0x7000 => self._7xnn_opcode(),
            0xA000 => self._annn_opcode(),
            _ => {
                // Using the catch all as a NOOP
                info!("Catch all: 0x{:X}", self.opcode);
                self.increase_pc();
            }
        }
    }

    pub fn increase_pc(&mut self) {
        self.pc += 2;
        debug!("Program Counter: 0x{:X}", self.pc);
    }

    /// 2NNN 	Flow 	*(0xNNN)() 	Calls subroutine at NNN.
    pub fn _2nnn_opcode(&mut self) {
        info!("2NNN: 0x{:X}", self.opcode);
        self.stack[self.sp as usize];
        self.sp += 1;
        self.pc = self.opcode & 0x0FFF;
    }

    /// 6XNN 	Const 	Vx = NN 	Sets VX to NN.
    pub fn _6xnn_opcode(&mut self) {
        info!("6XNN: 0x{:X}", self.opcode);
        let mut reg = self.opcode & 0x0F00;
        reg = reg >> 12;
        let data = self.opcode & 0x00FF;
        self.v[reg as usize] = data as u8;
        self.increase_pc();
    }

    /// 7XNN 	Const 	Vx += NN 	Adds NN to VX.
    pub fn _7xnn_opcode(&mut self) {
        info!("7XNN: 0x{:X}", self.opcode);
        let mut reg = self.opcode & 0x0F00;
        reg = reg >> 12;
        self.v[reg as usize] = (self.opcode & 0x00FF) as u8 + self.v[reg as usize] as u8;
    }

    /// ANNN 	MEM 	I = NNN 	Sets I to the address NNN.
    pub fn _annn_opcode(&mut self) {
        info!("ANNN: 0x{:X}", self.opcode);
        self.i = self.opcode & 0x0FFF;
        self.increase_pc();
    }

    pub fn new() -> Chipate {
        debug!("Creating New Chip");

        let chip = Chipate {
            opcode: 0,
            memory: [0; 4096],
            v: [0; 16],
            i: 0,
            pc: 0,
            gfx: [0; 64 * 32],
            delay_timer: 0,
            sound_timer: 0,
            stack: [0; 16],
            sp: 0,
            key: [0; 16],
            program: "",
        };

        return chip;
    }
}
<commit_msg>Added the remainder of the skel FXXX functions<commit_after>use std::{thread, time};
use std::env;
use std::io::prelude::*;
use std::fs::File;

/// Chipate Module
/// Rust emulation of the Chip-8
/// http://www.multigesturearticles/how-to-write-an-emulator-chip-8-interpreter/
#[allow(dead_code)]
pub struct Chipate {
    // Opcodes
    opcode: u16,

    // 4K Memory
    memory: [u8; 4096],
    // The systems memory map:
    // 0x000-0x1FF - Chip 8 interpreter (contains font set in emu)
    // 0x050-0x0A0 - Used for the built in 4x5 pixel font set (0-F)
    // 0x200-0xFFF - Program ROM and work RAM

    // Registers
    v: [u8; 16],

    // Index
    i: u16,

    // Program Counter
    pc: u16,

    gfx: [u8; 64 * 32],

    // Timers
    delay_timer: u8,
    sound_timer: u8,

    // Stack
    stack: [u8; 16],
    sp: u8,

    // Keypad
    key: [u8; 16],

    program: &'static str,
}

impl Chipate {
    pub fn init(&mut self) {
        debug!("Initialize Chip");
        // pc     = 0x200;  // Program counter starts at 0x200
        self.pc = 0x200;
        // opcode = 0;      // Reset current opcode
        self.opcode = 0x0;
        // I      = 0;      // Reset index register
        self.i = 0x0;
        // sp     = 0;      // Reset stack pointer
        self.sp = 0x0;

        // // Clear display
        // // Clear stack
        // // Clear registers V0-VF
        // // Clear memory

        // // Load fontset
        // for(int i = 0; i < 80; ++i)
        //     memory[i] = chip8_fontset[i];

        // // Reset timers
    }

    pub fn load_program(&mut self, program: &str) {
        debug!("Loading program {}", program);

        // We assume that we are in a valid directory.
        let mut p = env::current_dir().unwrap();
        p.push("programs");
        p.push(program);

        let mut f = File::open(p).expect("Unable to open file");
        let mut b = Vec::new();

        f.read_to_end(&mut b).expect("Unable to read file");

        for i in 0..b.len() {
            self.memory[i + 512] = b[i];
        }

    }

    pub fn emulate_cycle(&mut self) {
        debug!("Cycle Begin");

        self.fetch_opcode();
        self.decode_opcode();

        let one_second = time::Duration::from_millis(15);
        thread::sleep(one_second);

        debug!("Cycle End");
    }

    pub fn draw_screen(&mut self) {
        debug!("Drawing to Screen")
    }

    pub fn set_keys(&mut self) {
        debug!("Saving Key State")
    }

    // pub fn setup_testing_memory(&mut self) {
    //     debug!("Setting test memory");

    //     self.memory[self.pc as usize] = 0xA2;
    //     self.memory[(self.pc + 1) as usize] = 0xF0;

    //     debug!("Location: 0x{:X} data: 0x{:X}",
    //            self.pc,
    //            self.memory[self.pc as usize]);
    //     debug!("Location: 0x{:X} data: 0x{:X}",
    //            self.pc + 1,
    //            self.memory[(self.pc + 1) as usize]);
    // }

    pub fn fetch_opcode(&mut self) {
        let op_a = self.memory[self.pc as usize];
        self.opcode = op_a as u16;
        self.opcode = self.opcode << 8;
        // debug!("location: 0x{:X} data: 0x{:X}", self.pc, self.opcode);

        let op_b = self.memory[(self.pc + 1) as usize] as u16;
        // debug!("location: 0x{:X} data: 0x{:X}", self.pc, op_b);

        self.opcode = self.opcode | op_b;
        debug!("Opcode: 0x{:X}", self.opcode);
    }

    pub fn decode_opcode(&mut self) {
        let op = self.opcode & 0xF000;
        debug!("Decode: 0x{:X}", op);

        match op {
            0x2000 => self._2nnn_opcode(),
            0x6000 => self._6xnn_opcode(),
            0x7000 => self._7xnn_opcode(),
            0xA000 => self._annn_opcode(),
            _ => {
                // Using the catch all as a NOOP
                info!("Catch all: 0x{:X}", self.opcode);
                self.increase_pc();
            }
        }
    }

    pub fn increase_pc(&mut self) {
        self.pc += 2;
        debug!("Program Counter: 0x{:X}", self.pc);
    }

    /// 2NNN 	Flow 	*(0xNNN)() 	Calls subroutine at NNN.
    pub fn _2nnn_opcode(&mut self) {
        info!("2NNN: 0x{:X}", self.opcode);
        self.stack[self.sp as usize];
        self.sp += 1;
        self.pc = self.opcode & 0x0FFF;
    }

    /// 6XNN 	Const 	Vx = NN 	Sets VX to NN.
    pub fn _6xnn_opcode(&mut self) {
        info!("6XNN: 0x{:X}", self.opcode);
        let mut reg = self.opcode & 0x0F00;
        reg = reg >> 12;
        let data = self.opcode & 0x00FF;
        self.v[reg as usize] = data as u8;
        self.increase_pc();
    }

    /// 7XNN 	Const 	Vx += NN 	Adds NN to VX.
    pub fn _7xnn_opcode(&mut self) {
        info!("7XNN: 0x{:X}", self.opcode);
        let mut reg = self.opcode & 0x0F00;
        reg = reg >> 12;
        self.v[reg as usize] = (self.opcode & 0x00FF) as u8 + self.v[reg as usize] as u8;
    }

    /// ANNN 	MEM 	I = NNN 	Sets I to the address NNN.
    pub fn _annn_opcode(&mut self) {
        info!("ANNN: 0x{:X}", self.opcode);
        self.i = self.opcode & 0x0FFF;
        self.increase_pc();
    }

    /// FX07 	Timer 	Vx = get_delay() 	Sets VX to the value of the delay timer.
    pub fn _fx07_opcode(&mut self) {
        info!("FX07: 0x{:X}", self.opcode);
        self.increase_pc();
    }

    /// FX0A 	KeyOp 	Vx = get_key() 	A key press is awaited, and then stored in VX. (Blocking Operation. All instruction halted until next key event)
    pub fn _fx0a_opcode(&mut self) {
        info!("FX0A: 0x{:X}", self.opcode);
        self.increase_pc();
    }

    /// FX15 	Timer 	delay_timer(Vx) 	Sets the delay timer to VX.
    pub fn _fx15_opcode(&mut self) {
        info!("FX15: 0x{:X}", self.opcode);
        self.increase_pc();
    }

    /// FX18 	Sound 	sound_timer(Vx) 	Sets the sound timer to VX.
    pub fn _fx18_opcode(&mut self) {
        info!("FX18: 0x{:X}", self.opcode);
        self.increase_pc();
    }

    /// FX1E 	MEM 	I +=Vx 	Adds VX to I.[3]
    pub fn _fx1e_opcode(&mut self) {
        info!("FX1E: 0x{:X}", self.opcode);
        self.increase_pc();
    }

    /// FX29 	MEM 	I=sprite_addr[Vx] 	Sets I to the location of the sprite for the character in VX. Characters 0-F (in hexadecimal) are represented by a 4x5 font.
    pub fn _fx29_opcode(&mut self) {
        info!("FX29: 0x{:X}", self.opcode);
        self.increase_pc();
    }

    /// FX33 	BCD 	....  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 plus 1, and the least significant digit at I plus 2. (In other words, take the decimal representation of VX, place the hundreds digit in memory at location in I, the tens digit at location I+1, and the ones digit at location I+2.)
    pub fn _fx33_opcode(&mut self) {
        info!("FX33: 0x{:X}", self.opcode);
        self.increase_pc();
    }

    /// FX55 	MEM 	reg_dump(Vx,&I) 	Stores V0 to VX (including VX) in memory starting at address I.[4]
    pub fn _fx55_opcode(&mut self) {
        info!("FX55: 0x{:X}", self.opcode);
        self.increase_pc();
    }

    /// FX65 	MEM 	reg_load(Vx,&I) 	Fills V0 to VX (including VX) with values from memory starting at address I.[4]
    pub fn _fx65_opcode(&mut self) {
        info!("FX65: 0x{:X}", self.opcode);
        self.increase_pc();
    }

    pub fn _f_opcodes(&mut self) {
        let sub_op = self.opcode & 0x00FF;
        debug!("Decode: 0x{:X}", sub_op);

        match sub_op{
            0x0007 => self._fx07_opcode(),
            _ => {
                // Using the catch all as a NOOP
                info!("Catch all 0xFxxx: 0x{:X}", self.opcode);
                self.increase_pc();
            }
        }
    }

    pub fn new() -> Chipate {
        debug!("Creating New Chip");

        let chip = Chipate {
            opcode: 0,
            memory: [0; 4096],
            v: [0; 16],
            i: 0,
            pc: 0,
            gfx: [0; 64 * 32],
            delay_timer: 0,
            sound_timer: 0,
            stack: [0; 16],
            sp: 0,
            key: [0; 16],
            program: "",
        };

        return chip;
    }
}
<|endoftext|>


<commit_before>use {Errno, Error, Result, NixPath};
use fcntl::OFlag;
use libc::{self, c_void, size_t, off_t, mode_t};
use sys::stat::Mode;
use std::os::unix::io::RawFd;

pub use self::consts::*;

libc_bitflags!{
    pub flags ProtFlags: libc::c_int {
        PROT_NONE,
        PROT_READ,
        PROT_WRITE,
        PROT_EXEC,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        PROT_GROWSDOWN,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        PROT_GROWSUP,
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
mod consts {
    use libc::{self, c_int};

    libc_bitflags!{
        pub flags MapFlags: c_int {
            MAP_FILE,
            MAP_SHARED,
            MAP_PRIVATE,
            MAP_FIXED,
            MAP_ANON,
            MAP_ANONYMOUS,
            #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
            MAP_32BIT,
            MAP_GROWSDOWN,
            MAP_DENYWRITE,
            MAP_EXECUTABLE,
            MAP_LOCKED,
            MAP_NORESERVE,
            MAP_POPULATE,
            MAP_NONBLOCK,
            MAP_STACK,
            MAP_HUGETLB,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise  = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise  = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise  = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise  = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise  = 4; /* Don't need these pages.  */
    pub const MADV_REMOVE     : MmapAdvise  = 9; /* Remove these pages and resources.  */
    pub const MADV_DONTFORK   : MmapAdvise  = 10; /* Do not inherit across fork.  */
    pub const MADV_DOFORK     : MmapAdvise  = 11; /* Do inherit across fork.  */
    pub const MADV_MERGEABLE  : MmapAdvise  = 12; /* KSM may merge identical pages.  */
    pub const MADV_UNMERGEABLE: MmapAdvise  = 13; /* KSM may not merge identical pages.  */
    pub const MADV_HUGEPAGE   : MmapAdvise  = 14; /* Worth backing with hugepages.  */
    pub const MADV_NOHUGEPAGE : MmapAdvise  = 15; /* Not worth backing with hugepages.  */
    pub const MADV_DONTDUMP   : MmapAdvise  = 16; /* Explicity exclude from the core dump, overrides the coredump filter bits.  */
    pub const MADV_DODUMP     : MmapAdvise  = 17; /* Clear the MADV_DONTDUMP flag.  */
    pub const MADV_HWPOISON   : MmapAdvise  = 100; /* Poison a page for testing.  */

    libc_bitflags!{
        pub flags MsFlags: c_int {
            MS_ASYNC,
            MS_INVALIDATE,
            MS_SYNC,
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod consts {
    use libc::{self, c_int};

    libc_bitflags!{
        pub flags MapFlags: c_int {
            MAP_FILE,
            MAP_SHARED,
            MAP_PRIVATE,
            MAP_FIXED,
            MAP_ANON,
            MAP_NOCACHE,
            MAP_JIT,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_ZERO_WIRED_PAGES: MmapAdvise = 6; /* zero the wired pages that have not been unwired before the entry is deleted */
    pub const MADV_FREE_REUSABLE : MmapAdvise   = 7; /* pages can be reused (by anyone) */
    pub const MADV_FREE_REUSE : MmapAdvise      = 8; /* caller wants to reuse those pages */
    pub const MADV_CAN_REUSE : MmapAdvise       = 9;

    libc_bitflags!{
        pub flags MsFlags: c_int {
            MS_ASYNC, /* [MF|SIO] return immediately */
            MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            MS_KILLPAGES, /* invalidate pages, leave mapped */
            MS_DEACTIVATE, /* deactivate pages, leave mapped */
            MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd"))]
mod consts {
    use libc::{self, c_int};

    libc_bitflags!{
        pub flags MapFlags: c_int {
            MAP_FILE,
            MAP_SHARED,
            MAP_PRIVATE,
            MAP_FIXED,
            MAP_RENAME,
            MAP_NORESERVE,
            MAP_HASSEMAPHORE,
            #[cfg(not(any(target_os = "openbsd", target_os = "netbsd")))]
            MAP_STACK,
            #[cfg(target_os = "netbsd")]
            MAP_WIRED,
            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
            MAP_NOSYNC,
            MAP_ANON,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_NOSYNC     : MmapAdvise      = 6; /* try to avoid flushes to physical media*/
    pub const MADV_AUTOSYNC   : MmapAdvise      = 7; /* refert to default flushing strategy */
    pub const MADV_NOCORE     : MmapAdvise      = 8; /* do not include these pages in a core file */
    pub const MADV_CORE       : MmapAdvise      = 9; /* revert to including pages in a core file */
    #[cfg(not(target_os = "dragonfly"))]
    pub const MADV_PROTECT    : MmapAdvise      = 10; /* protect process from pageout kill */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_INVAL      : MmapAdvise      = 10; /* virt page tables have changed, inval pmap */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_SETMAP     : MmapAdvise      = 11; /* set page table directory page for map */

    bitflags!{
        pub flags MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC, /* [MF|SIO] return immediately */
            const MS_INVALIDATE = libc::MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_KILLPAGES  = 0x0004, /* invalidate pages, leave mapped */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_DEACTIVATE = 0x0004, /* deactivate pages, leave mapped */
            const MS_SYNC       = libc::MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize                 = -1;
}

mod ffi {
    use libc::{c_void, size_t, c_int, c_char, mode_t};

    pub use libc::{mmap, munmap};

    #[allow(improper_ctypes)]
    extern {
        pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int;
        pub fn shm_unlink(name: *const c_char) -> c_int;
        pub fn mlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn munlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn madvise (addr: *const c_void, len: size_t, advice: c_int) -> c_int;
        pub fn msync (addr: *const c_void, len: size_t, flags: c_int) -> c_int;
    }
}

pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(ffi::mlock(addr, length)).map(drop)
}

pub fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(unsafe { ffi::munlock(addr, length) }).map(drop)
}

/// Calls to mmap are inherently unsafe, so they must be made in an unsafe block. Typically
/// a higher-level abstraction will hide the unsafe interactions with the mmap'd region.
pub fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
    let ret = unsafe { ffi::mmap(addr, length, prot.bits(), flags.bits(), fd, offset) };

    if ret as isize == MAP_FAILED  {
        Err(Error::Sys(Errno::last()))
    } else {
        Ok(ret)
    }
}

pub fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
    Errno::result(unsafe { ffi::munmap(addr, len) }).map(drop)
}

pub fn madvise(addr: *const c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
    Errno::result(unsafe { ffi::madvise(addr, length, advise) }).map(drop)
}

pub fn msync(addr: *const c_void, length: size_t, flags: MsFlags) -> Result<()> {
    Errno::result(unsafe { ffi::msync(addr, length, flags.bits()) }).map(drop)
}

pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe {
            ffi::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as mode_t)
        }
    }));

    Errno::result(ret)
}

pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe { ffi::shm_unlink(cstr.as_ptr()) }
    }));

    Errno::result(ret).map(drop)
}
<commit_msg>Actually mark mmap and related functions as `unsafe`<commit_after>use {Errno, Error, Result, NixPath};
use fcntl::OFlag;
use libc::{self, c_void, size_t, off_t, mode_t};
use sys::stat::Mode;
use std::os::unix::io::RawFd;

pub use self::consts::*;

libc_bitflags!{
    pub flags ProtFlags: libc::c_int {
        PROT_NONE,
        PROT_READ,
        PROT_WRITE,
        PROT_EXEC,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        PROT_GROWSDOWN,
        #[cfg(any(target_os = "linux", target_os = "android"))]
        PROT_GROWSUP,
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
mod consts {
    use libc::{self, c_int};

    libc_bitflags!{
        pub flags MapFlags: c_int {
            MAP_FILE,
            MAP_SHARED,
            MAP_PRIVATE,
            MAP_FIXED,
            MAP_ANON,
            MAP_ANONYMOUS,
            #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
            MAP_32BIT,
            MAP_GROWSDOWN,
            MAP_DENYWRITE,
            MAP_EXECUTABLE,
            MAP_LOCKED,
            MAP_NORESERVE,
            MAP_POPULATE,
            MAP_NONBLOCK,
            MAP_STACK,
            MAP_HUGETLB,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise  = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise  = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise  = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise  = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise  = 4; /* Don't need these pages.  */
    pub const MADV_REMOVE     : MmapAdvise  = 9; /* Remove these pages and resources.  */
    pub const MADV_DONTFORK   : MmapAdvise  = 10; /* Do not inherit across fork.  */
    pub const MADV_DOFORK     : MmapAdvise  = 11; /* Do inherit across fork.  */
    pub const MADV_MERGEABLE  : MmapAdvise  = 12; /* KSM may merge identical pages.  */
    pub const MADV_UNMERGEABLE: MmapAdvise  = 13; /* KSM may not merge identical pages.  */
    pub const MADV_HUGEPAGE   : MmapAdvise  = 14; /* Worth backing with hugepages.  */
    pub const MADV_NOHUGEPAGE : MmapAdvise  = 15; /* Not worth backing with hugepages.  */
    pub const MADV_DONTDUMP   : MmapAdvise  = 16; /* Explicity exclude from the core dump, overrides the coredump filter bits.  */
    pub const MADV_DODUMP     : MmapAdvise  = 17; /* Clear the MADV_DONTDUMP flag.  */
    pub const MADV_HWPOISON   : MmapAdvise  = 100; /* Poison a page for testing.  */

    libc_bitflags!{
        pub flags MsFlags: c_int {
            MS_ASYNC,
            MS_INVALIDATE,
            MS_SYNC,
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod consts {
    use libc::{self, c_int};

    libc_bitflags!{
        pub flags MapFlags: c_int {
            MAP_FILE,
            MAP_SHARED,
            MAP_PRIVATE,
            MAP_FIXED,
            MAP_ANON,
            MAP_NOCACHE,
            MAP_JIT,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_ZERO_WIRED_PAGES: MmapAdvise = 6; /* zero the wired pages that have not been unwired before the entry is deleted */
    pub const MADV_FREE_REUSABLE : MmapAdvise   = 7; /* pages can be reused (by anyone) */
    pub const MADV_FREE_REUSE : MmapAdvise      = 8; /* caller wants to reuse those pages */
    pub const MADV_CAN_REUSE : MmapAdvise       = 9;

    libc_bitflags!{
        pub flags MsFlags: c_int {
            MS_ASYNC, /* [MF|SIO] return immediately */
            MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            MS_KILLPAGES, /* invalidate pages, leave mapped */
            MS_DEACTIVATE, /* deactivate pages, leave mapped */
            MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize               = -1;
}

#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd"))]
mod consts {
    use libc::{self, c_int};

    libc_bitflags!{
        pub flags MapFlags: c_int {
            MAP_FILE,
            MAP_SHARED,
            MAP_PRIVATE,
            MAP_FIXED,
            MAP_RENAME,
            MAP_NORESERVE,
            MAP_HASSEMAPHORE,
            #[cfg(not(any(target_os = "openbsd", target_os = "netbsd")))]
            MAP_STACK,
            #[cfg(target_os = "netbsd")]
            MAP_WIRED,
            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
            MAP_NOSYNC,
            MAP_ANON,
        }
    }

    pub type MmapAdvise = c_int;

    pub const MADV_NORMAL     : MmapAdvise      = 0; /* No further special treatment.  */
    pub const MADV_RANDOM     : MmapAdvise      = 1; /* Expect random page references.  */
    pub const MADV_SEQUENTIAL : MmapAdvise      = 2; /* Expect sequential page references.  */
    pub const MADV_WILLNEED   : MmapAdvise      = 3; /* Will need these pages.  */
    pub const MADV_DONTNEED   : MmapAdvise      = 4; /* Don't need these pages.  */
    pub const MADV_FREE       : MmapAdvise      = 5; /* pages unneeded, discard contents */
    pub const MADV_NOSYNC     : MmapAdvise      = 6; /* try to avoid flushes to physical media*/
    pub const MADV_AUTOSYNC   : MmapAdvise      = 7; /* refert to default flushing strategy */
    pub const MADV_NOCORE     : MmapAdvise      = 8; /* do not include these pages in a core file */
    pub const MADV_CORE       : MmapAdvise      = 9; /* revert to including pages in a core file */
    #[cfg(not(target_os = "dragonfly"))]
    pub const MADV_PROTECT    : MmapAdvise      = 10; /* protect process from pageout kill */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_INVAL      : MmapAdvise      = 10; /* virt page tables have changed, inval pmap */
    #[cfg(target_os = "dragonfly")]
    pub const MADV_SETMAP     : MmapAdvise      = 11; /* set page table directory page for map */

    bitflags!{
        pub flags MsFlags: c_int {
            const MS_ASYNC      = libc::MS_ASYNC, /* [MF|SIO] return immediately */
            const MS_INVALIDATE = libc::MS_INVALIDATE, /* [MF|SIO] invalidate all cached data */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_KILLPAGES  = 0x0004, /* invalidate pages, leave mapped */
            #[cfg(not(target_os = "dragonfly"))]
            const MS_DEACTIVATE = 0x0004, /* deactivate pages, leave mapped */
            const MS_SYNC       = libc::MS_SYNC, /* [MF|SIO] msync synchronously */
        }
    }

    pub const MAP_FAILED: isize                 = -1;
}

mod ffi {
    use libc::{c_void, size_t, c_int, c_char, mode_t};

    pub use libc::{mmap, munmap};

    #[allow(improper_ctypes)]
    extern {
        pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int;
        pub fn shm_unlink(name: *const c_char) -> c_int;
        pub fn mlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn munlock(addr: *const c_void, len: size_t) -> c_int;
        pub fn madvise (addr: *const c_void, len: size_t, advice: c_int) -> c_int;
        pub fn msync (addr: *const c_void, len: size_t, flags: c_int) -> c_int;
    }
}

pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(ffi::mlock(addr, length)).map(drop)
}

pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
    Errno::result(ffi::munlock(addr, length)).map(drop)
}

/// Calls to mmap are inherently unsafe, so they must be made in an unsafe block. Typically
/// a higher-level abstraction will hide the unsafe interactions with the mmap'd region.
pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
    let ret = ffi::mmap(addr, length, prot.bits(), flags.bits(), fd, offset);

    if ret as isize == MAP_FAILED  {
        Err(Error::Sys(Errno::last()))
    } else {
        Ok(ret)
    }
}

pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
    Errno::result(ffi::munmap(addr, len)).map(drop)
}

pub unsafe fn madvise(addr: *const c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
    Errno::result(ffi::madvise(addr, length, advise)).map(drop)
}

pub unsafe fn msync(addr: *const c_void, length: size_t, flags: MsFlags) -> Result<()> {
    Errno::result(ffi::msync(addr, length, flags.bits())).map(drop)
}

pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe {
            ffi::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as mode_t)
        }
    }));

    Errno::result(ret)
}

pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
    let ret = try!(name.with_nix_path(|cstr| {
        unsafe { ffi::shm_unlink(cstr.as_ptr()) }
    }));

    Errno::result(ret).map(drop)
}
<|endoftext|>


<commit_before>//! CLI tool to compile cretonne IL into native code.
//!
//! Reads IR files into Cretonne IL and compiles it.

use cton_reader::parse_functions;
use std::path::PathBuf;
use cretonne::Context;
use cretonne::settings::FlagsOrIsa;
use std::path::Path;
use utils::{pretty_error, read_to_string, parse_sets_and_isa};

pub fn run(
    files: Vec<String>,
    flag_print: bool,
    mut flag_set: Vec<String>,
    flag_isa: String,
) -> Result<(), String> {
    // Enable the verifier by default, since we're reading IL in from a
    // text file.
    flag_set.insert(0, "enable_verifier=1".to_string());

    let parsed = parse_sets_and_isa(flag_set, flag_isa)?;

    for filename in files {
        let path = Path::new(&filename);
        let name = String::from(path.as_os_str().to_string_lossy());
        handle_module(flag_print, path.to_path_buf(), name, parsed.as_fisa())?;
    }
    Ok(())
}

fn handle_module(
    flag_print: bool,
    path: PathBuf,
    name: String,
    fisa: FlagsOrIsa,
) -> Result<(), String> {
    let buffer = read_to_string(&path).map_err(
        |e| format!("{}: {}", name, e),
    )?;
    let items = parse_functions(&buffer).map_err(
        |e| format!("{}: {}", name, e),
    )?;
    for func in items.into_iter() {
        let mut context = Context::new();
        context.func = func;
        if let Some(isa) = fisa.isa {
            context.compile(isa).map_err(|err| {
                pretty_error(&context.func, fisa.isa, err)
            })?;
        } else {
            return Err(String::from("compilation requires a target isa"));
        }
        if flag_print {
            println!("{}", context.func.display(fisa.isa));
        }
    }
    Ok(())
}
<commit_msg>Make "cton-util compile" default to the isa specified in the test file.<commit_after>//! CLI tool to compile cretonne IL into native code.
//!
//! Reads IR files into Cretonne IL and compiles it.

use cton_reader::parse_test;
use std::path::PathBuf;
use cretonne::Context;
use cretonne::settings::FlagsOrIsa;
use std::path::Path;
use utils::{pretty_error, read_to_string, parse_sets_and_isa};

pub fn run(
    files: Vec<String>,
    flag_print: bool,
    mut flag_set: Vec<String>,
    flag_isa: String,
) -> Result<(), String> {
    // Enable the verifier by default, since we're reading IL in from a
    // text file.
    flag_set.insert(0, "enable_verifier=1".to_string());

    let parsed = parse_sets_and_isa(flag_set, flag_isa)?;

    for filename in files {
        let path = Path::new(&filename);
        let name = String::from(path.as_os_str().to_string_lossy());
        handle_module(flag_print, path.to_path_buf(), name, parsed.as_fisa())?;
    }
    Ok(())
}

fn handle_module(
    flag_print: bool,
    path: PathBuf,
    name: String,
    fisa: FlagsOrIsa,
) -> Result<(), String> {
    let buffer = read_to_string(&path).map_err(
        |e| format!("{}: {}", name, e),
    )?;
    let test_file = parse_test(&buffer).map_err(|e| format!("{}: {}", name, e))?;

    // If we have an isa from the command-line, use that. Otherwise if the
    // file contins a unique isa, use that.
    let isa = if let Some(isa) = fisa.isa {
        isa
    } else if let Some(isa) = test_file.isa_spec.unique_isa() {
        isa
    } else {
        return Err(String::from("compilation requires a target isa"));
    };

    for (func, _) in test_file.functions.into_iter() {
        let mut context = Context::new();
        context.func = func;
        context.compile(isa).map_err(|err| {
            pretty_error(&context.func, Some(isa), err)
        })?;
        if flag_print {
            println!("{}", context.func.display(isa));
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>use serde::Serialize;
use serde_json::value::{Value as Json, Map, to_value};

use pest::prelude::*;
use std::collections::{VecDeque, BTreeMap};

use grammar::{Rdp, Rule};
use error::RenderError;

static DEFAULT_VALUE: Json = Json::Null;

pub type Object = BTreeMap<String, Json>;

/// The context wrap data you render on your templates.
///
#[derive(Debug, Clone)]
pub struct Context {
    data: Json,
}

#[inline]
fn parse_json_visitor_inner<'a>(path_stack: &mut VecDeque<&'a str>,
                                path: &'a str)
                                -> Result<(), RenderError> {
    let path_in = StringInput::new(path);
    let mut parser = Rdp::new(path_in);

    let mut seg_stack: VecDeque<&Token<Rule>> = VecDeque::new();
    if parser.path() {
        for seg in parser.queue().iter() {
            match seg.rule {
                Rule::path_var | Rule::path_idx | Rule::path_key => {}
                Rule::path_up => {
                    path_stack.pop_back();
                    if let Some(p) = seg_stack.pop_back() {
                        // also pop array index like [1]
                        if p.rule == Rule::path_raw_id {
                            seg_stack.pop_back();
                        }
                    }
                }
                Rule::path_id |
                Rule::path_raw_id |
                Rule::path_num_id => {
                    seg_stack.push_back(seg);
                }
                _ => {}
            }
        }

        for i in seg_stack.iter() {
            let id = &path[i.start..i.end];
            path_stack.push_back(id);
        }
        Ok(())
    } else {
        Err(RenderError::new("Invalid JSON path"))
    }
}

#[inline]
fn parse_json_visitor<'a>(path_stack: &mut VecDeque<&'a str>,
                          base_path: &'a str,
                          path_context: &'a VecDeque<String>,
                          relative_path: &'a str)
                          -> Result<(), RenderError> {
    let path_in = StringInput::new(relative_path);
    let mut parser = Rdp::new(path_in);

    if parser.path() {
        let mut path_context_depth: i64 = -1;

        let mut iter = parser.queue().iter();
        loop {
            if let Some(sg) = iter.next() {
                if sg.rule == Rule::path_up {
                    path_context_depth += 1;
                } else {
                    break;
                }
            } else {
                break;
            }
        }

        if path_context_depth >= 0 {
            if let Some(context_base_path) = path_context.get(path_context_depth as usize) {
                parse_json_visitor_inner(path_stack, context_base_path)?;
            } else {
                parse_json_visitor_inner(path_stack, base_path)?;
            }
        } else {
            parse_json_visitor_inner(path_stack, base_path)?;
        }

        parse_json_visitor_inner(path_stack, relative_path)?;
        Ok(())
    } else {
        Err(RenderError::new("Invalid JSON path."))
    }

}

fn merge_json(base: &Json, addition: &Object) -> Json {
    let mut base_map = match base {
        &Json::Object(ref m) => m.clone(),
        _ => {
            let mut map = Map::new();
            map.insert("this".to_owned(), base.clone());
            map
        }
    };

    for (k, v) in addition.iter() {
        base_map.insert(k.clone(), v.clone());
    }

    Json::Object(base_map)
}

impl Context {
    /// Create a context with null data
    pub fn null() -> Context {
        Context { data: Json::Null }
    }

    /// Create a context with given data
    pub fn wraps<T: Serialize>(e: &T) -> Context {
        Context { data: to_json(e) }
    }

    /// Extend current context with another JSON object
    /// If current context is a JSON object, it's identical to a normal merge
    /// Otherwise, the current value will be stored in new JSON object with key `this`, and merged
    /// keys are also available.
    pub fn extend(&self, hash: &Object) -> Context {
        let new_data = merge_json(&self.data, hash);
        Context { data: new_data }
    }

    /// Navigate the context with base path and relative path
    /// Typically you will set base path to `RenderContext.get_path()`
    /// and set relative path to helper argument or so.
    ///
    /// If you want to navigate from top level, set the base path to `"."`
    pub fn navigate(&self,
                    base_path: &str,
                    path_context: &VecDeque<String>,
                    relative_path: &str)
                    -> Result<&Json, RenderError> {
        let mut path_stack: VecDeque<&str> = VecDeque::new();
        parse_json_visitor(&mut path_stack, base_path, path_context, relative_path)?;

        let paths: Vec<&str> = path_stack.iter().map(|x| *x).collect();
        let mut data: &Json = &self.data;
        for p in paths.iter() {
            if *p == "this" && data.as_object().and_then(|m| m.get("this")).is_none() {
                continue;
            }
            data = match *data {
                Json::Array(ref l) => {
                    p.parse::<usize>()
                        .and_then(|idx_u| Ok(l.get(idx_u).unwrap_or(&DEFAULT_VALUE)))
                        .unwrap_or(&DEFAULT_VALUE)
                }
                Json::Object(ref m) => m.get(*p).unwrap_or(&DEFAULT_VALUE),
                _ => &DEFAULT_VALUE,
            }
        }
        Ok(data)
    }

    pub fn data(&self) -> &Json {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut Json {
        &mut self.data
    }
}

/// Render Json data with default format
pub trait JsonRender {
    fn render(&self) -> String;
}

pub trait JsonTruthy {
    fn is_truthy(&self) -> bool;
}

impl JsonRender for Json {
    fn render(&self) -> String {
        match *self {
            Json::String(ref s) => s.to_string(),
            Json::Bool(i) => i.to_string(),
            Json::Number(ref n) => n.to_string(),
            Json::Null => "".to_owned(),
            Json::Array(ref a) => {
                let mut buf = String::new();
                buf.push('[');
                for i in a.iter() {
                    buf.push_str(i.render().as_ref());
                    buf.push_str(", ");
                }
                buf.push(']');
                buf
            }
            Json::Object(_) => "[object]".to_owned(),
        }
    }
}

pub fn to_json<T>(src: &T) -> Json
    where T: Serialize
{
    to_value(src).unwrap_or(Json::Null)
}

pub fn as_string(src: &Json) -> Option<&str> {
    src.as_str()
}

impl JsonTruthy for Json {
    fn is_truthy(&self) -> bool {
        match *self {
            Json::Bool(ref i) => *i,
            Json::Number(ref n) => n.as_f64().map(|f| f.is_normal()).unwrap_or(false),
            Json::Null => false,
            Json::String(ref i) => i.len() > 0,
            Json::Array(ref i) => i.len() > 0,
            Json::Object(ref i) => i.len() > 0,
        }
    }
}

#[cfg(test)]
mod test {
    use context::{self, JsonRender, Context};
    use std::collections::{VecDeque, BTreeMap};
    use serde_json::value::{Value as Json, Map};

    #[test]
    fn test_json_render() {
        let raw = "
Hello world
\n<p thing=\"hello\"
";
        let thing = Json::String(raw.to_string());

        assert_eq!(raw, thing.render());
    }

    #[derive(Serialize)]
    struct Address {
        city: String,
        country: String,
    }

    #[derive(Serialize)]
    struct Person {
        name: String,
        age: i16,
        addr: Address,
        titles: Vec<String>,
    }

    #[test]
    fn test_render() {
        let v = "hello";
        let ctx = Context::wraps(&v.to_string());
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "this")
                       .unwrap()
                       .render(),
                   v.to_string());
    }

    #[test]
    fn test_navigation() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let ctx = Context::wraps(&person);
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "./name/../addr/country")
                       .unwrap()
                       .render(),
                   "China".to_string());
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "addr.[country]")
                       .unwrap()
                       .render(),
                   "China".to_string());
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "addr.[\"country\"]")
                       .unwrap()
                       .render(),
                   "China".to_string());
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "addr.['country']")
                       .unwrap()
                       .render(),
                   "China".to_string());

        let v = true;
        let ctx2 = Context::wraps(&v);
        assert_eq!(ctx2.navigate(".", &VecDeque::new(), "this")
                       .unwrap()
                       .render(),
                   "true".to_string());

        assert_eq!(ctx.navigate(".", &VecDeque::new(), "titles[0]")
                       .unwrap()
                       .render(),
                   "programmer".to_string());
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "titles.[0]")
                       .unwrap()
                       .render(),
                   "programmer".to_string());

        assert_eq!(ctx.navigate(".", &VecDeque::new(), "titles[0]/../../age")
                       .unwrap()
                       .render(),
                   "27".to_string());
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "this.titles[0]/../../age")
                       .unwrap()
                       .render(),
                   "27".to_string());

    }

    #[test]
    fn test_this() {
        let mut map_with_this = Map::new();
        map_with_this.insert("this".to_string(), context::to_json(&"hello"));
        map_with_this.insert("age".to_string(), context::to_json(&5usize));
        let ctx1 = Context::wraps(&map_with_this);

        let mut map_without_this = Map::new();
        map_without_this.insert("age".to_string(), context::to_json(&4usize));
        let ctx2 = Context::wraps(&map_without_this);

        assert_eq!(ctx1.navigate(".", &VecDeque::new(), "this")
                       .unwrap()
                       .render(),
                   "hello".to_owned());
        assert_eq!(ctx2.navigate(".", &VecDeque::new(), "age")
                       .unwrap()
                       .render(),
                   "4".to_owned());
    }

    #[test]
    fn test_extend() {
        let mut map = Map::new();
        map.insert("age".to_string(), context::to_json(&4usize));
        let ctx1 = Context::wraps(&map);

        let s = "hello".to_owned();
        let ctx2 = Context::wraps(&s);

        let mut hash = BTreeMap::new();
        hash.insert("tag".to_owned(), context::to_json(&"h1"));

        let ctx_a1 = ctx1.extend(&hash);
        assert_eq!(ctx_a1
                       .navigate(".", &VecDeque::new(), "age")
                       .unwrap()
                       .render(),
                   "4".to_owned());
        assert_eq!(ctx_a1
                       .navigate(".", &VecDeque::new(), "tag")
                       .unwrap()
                       .render(),
                   "h1".to_owned());

        let ctx_a2 = ctx2.extend(&hash);
        assert_eq!(ctx_a2
                       .navigate(".", &VecDeque::new(), "this")
                       .unwrap()
                       .render(),
                   "hello".to_owned());
        assert_eq!(ctx_a2
                       .navigate(".", &VecDeque::new(), "tag")
                       .unwrap()
                       .render(),
                   "h1".to_owned());
    }

    #[test]
    fn test_key_name_with_this() {
        let m = btreemap!{
            "this_name".to_string() => "the_value".to_string()
        };
        let ctx = Context::wraps(&m);
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "this_name")
                       .unwrap()
                       .render(),
                   "the_value".to_string());
    }
}
<commit_msg>(fix) align context merge with handlebars.js<commit_after>use serde::Serialize;
use serde_json::value::{Value as Json, Map, to_value};

use pest::prelude::*;
use std::collections::{VecDeque, BTreeMap};

use grammar::{Rdp, Rule};
use error::RenderError;

static DEFAULT_VALUE: Json = Json::Null;

pub type Object = BTreeMap<String, Json>;

/// The context wrap data you render on your templates.
///
#[derive(Debug, Clone)]
pub struct Context {
    data: Json,
}

#[inline]
fn parse_json_visitor_inner<'a>(path_stack: &mut VecDeque<&'a str>,
                                path: &'a str)
                                -> Result<(), RenderError> {
    let path_in = StringInput::new(path);
    let mut parser = Rdp::new(path_in);

    let mut seg_stack: VecDeque<&Token<Rule>> = VecDeque::new();
    if parser.path() {
        for seg in parser.queue().iter() {
            match seg.rule {
                Rule::path_var | Rule::path_idx | Rule::path_key => {}
                Rule::path_up => {
                    path_stack.pop_back();
                    if let Some(p) = seg_stack.pop_back() {
                        // also pop array index like [1]
                        if p.rule == Rule::path_raw_id {
                            seg_stack.pop_back();
                        }
                    }
                }
                Rule::path_id |
                Rule::path_raw_id |
                Rule::path_num_id => {
                    seg_stack.push_back(seg);
                }
                _ => {}
            }
        }

        for i in seg_stack.iter() {
            let id = &path[i.start..i.end];
            path_stack.push_back(id);
        }
        Ok(())
    } else {
        Err(RenderError::new("Invalid JSON path"))
    }
}

#[inline]
fn parse_json_visitor<'a>(path_stack: &mut VecDeque<&'a str>,
                          base_path: &'a str,
                          path_context: &'a VecDeque<String>,
                          relative_path: &'a str)
                          -> Result<(), RenderError> {
    let path_in = StringInput::new(relative_path);
    let mut parser = Rdp::new(path_in);

    if parser.path() {
        let mut path_context_depth: i64 = -1;

        let mut iter = parser.queue().iter();
        loop {
            if let Some(sg) = iter.next() {
                if sg.rule == Rule::path_up {
                    path_context_depth += 1;
                } else {
                    break;
                }
            } else {
                break;
            }
        }

        if path_context_depth >= 0 {
            if let Some(context_base_path) = path_context.get(path_context_depth as usize) {
                parse_json_visitor_inner(path_stack, context_base_path)?;
            } else {
                parse_json_visitor_inner(path_stack, base_path)?;
            }
        } else {
            parse_json_visitor_inner(path_stack, base_path)?;
        }

        parse_json_visitor_inner(path_stack, relative_path)?;
        Ok(())
    } else {
        Err(RenderError::new("Invalid JSON path."))
    }

}

fn merge_json(base: &Json, addition: &Object) -> Json {
    let mut base_map = match base {
        &Json::Object(ref m) => m.clone(),
        _ => Map::new(),
    };

    for (k, v) in addition.iter() {
        base_map.insert(k.clone(), v.clone());
    }

    Json::Object(base_map)
}

impl Context {
    /// Create a context with null data
    pub fn null() -> Context {
        Context { data: Json::Null }
    }

    /// Create a context with given data
    pub fn wraps<T: Serialize>(e: &T) -> Context {
        Context { data: to_json(e) }
    }

    /// Extend current context with another JSON object
    /// If current context is a JSON object, it's identical to a normal merge
    /// Otherwise, the current value will be stored in new JSON object with key `this`, and merged
    /// keys are also available.
    pub fn extend(&self, hash: &Object) -> Context {
        let new_data = merge_json(&self.data, hash);
        Context { data: new_data }
    }

    /// Navigate the context with base path and relative path
    /// Typically you will set base path to `RenderContext.get_path()`
    /// and set relative path to helper argument or so.
    ///
    /// If you want to navigate from top level, set the base path to `"."`
    pub fn navigate(&self,
                    base_path: &str,
                    path_context: &VecDeque<String>,
                    relative_path: &str)
                    -> Result<&Json, RenderError> {
        let mut path_stack: VecDeque<&str> = VecDeque::new();
        parse_json_visitor(&mut path_stack, base_path, path_context, relative_path)?;

        let paths: Vec<&str> = path_stack.iter().map(|x| *x).collect();
        let mut data: &Json = &self.data;
        for p in paths.iter() {
            if *p == "this" {
                continue;
            }
            data = match *data {
                Json::Array(ref l) => {
                    p.parse::<usize>()
                        .and_then(|idx_u| Ok(l.get(idx_u).unwrap_or(&DEFAULT_VALUE)))
                        .unwrap_or(&DEFAULT_VALUE)
                }
                Json::Object(ref m) => m.get(*p).unwrap_or(&DEFAULT_VALUE),
                _ => &DEFAULT_VALUE,
            }
        }
        Ok(data)
    }

    pub fn data(&self) -> &Json {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut Json {
        &mut self.data
    }
}

/// Render Json data with default format
pub trait JsonRender {
    fn render(&self) -> String;
}

pub trait JsonTruthy {
    fn is_truthy(&self) -> bool;
}

impl JsonRender for Json {
    fn render(&self) -> String {
        match *self {
            Json::String(ref s) => s.to_string(),
            Json::Bool(i) => i.to_string(),
            Json::Number(ref n) => n.to_string(),
            Json::Null => "".to_owned(),
            Json::Array(ref a) => {
                let mut buf = String::new();
                buf.push('[');
                for i in a.iter() {
                    buf.push_str(i.render().as_ref());
                    buf.push_str(", ");
                }
                buf.push(']');
                buf
            }
            Json::Object(_) => "[object]".to_owned(),
        }
    }
}

pub fn to_json<T>(src: &T) -> Json
    where T: Serialize
{
    to_value(src).unwrap_or(Json::Null)
}

pub fn as_string(src: &Json) -> Option<&str> {
    src.as_str()
}

impl JsonTruthy for Json {
    fn is_truthy(&self) -> bool {
        match *self {
            Json::Bool(ref i) => *i,
            Json::Number(ref n) => n.as_f64().map(|f| f.is_normal()).unwrap_or(false),
            Json::Null => false,
            Json::String(ref i) => i.len() > 0,
            Json::Array(ref i) => i.len() > 0,
            Json::Object(ref i) => i.len() > 0,
        }
    }
}

#[cfg(test)]
mod test {
    use context::{self, JsonRender, Context};
    use std::collections::{VecDeque, BTreeMap};
    use serde_json::value::{Value as Json, Map};

    #[test]
    fn test_json_render() {
        let raw = "
Hello world
\n<p thing=\"hello\"
";
        let thing = Json::String(raw.to_string());

        assert_eq!(raw, thing.render());
    }

    #[derive(Serialize)]
    struct Address {
        city: String,
        country: String,
    }

    #[derive(Serialize)]
    struct Person {
        name: String,
        age: i16,
        addr: Address,
        titles: Vec<String>,
    }

    #[test]
    fn test_render() {
        let v = "hello";
        let ctx = Context::wraps(&v.to_string());
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "this")
                       .unwrap()
                       .render(),
                   v.to_string());
    }

    #[test]
    fn test_navigation() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let ctx = Context::wraps(&person);
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "./name/../addr/country")
                       .unwrap()
                       .render(),
                   "China".to_string());
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "addr.[country]")
                       .unwrap()
                       .render(),
                   "China".to_string());
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "addr.[\"country\"]")
                       .unwrap()
                       .render(),
                   "China".to_string());
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "addr.['country']")
                       .unwrap()
                       .render(),
                   "China".to_string());

        let v = true;
        let ctx2 = Context::wraps(&v);
        assert_eq!(ctx2.navigate(".", &VecDeque::new(), "this")
                       .unwrap()
                       .render(),
                   "true".to_string());

        assert_eq!(ctx.navigate(".", &VecDeque::new(), "titles[0]")
                       .unwrap()
                       .render(),
                   "programmer".to_string());
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "titles.[0]")
                       .unwrap()
                       .render(),
                   "programmer".to_string());

        assert_eq!(ctx.navigate(".", &VecDeque::new(), "titles[0]/../../age")
                       .unwrap()
                       .render(),
                   "27".to_string());
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "this.titles[0]/../../age")
                       .unwrap()
                       .render(),
                   "27".to_string());

    }

    #[test]
    fn test_this() {
        let mut map_with_this = Map::new();
        map_with_this.insert("this".to_string(), context::to_json(&"hello"));
        map_with_this.insert("age".to_string(), context::to_json(&5usize));
        let ctx1 = Context::wraps(&map_with_this);

        let mut map_without_this = Map::new();
        map_without_this.insert("age".to_string(), context::to_json(&4usize));
        let ctx2 = Context::wraps(&map_without_this);

        assert_eq!(ctx1.navigate(".", &VecDeque::new(), "this")
                       .unwrap()
                       .render(),
                   "[object]".to_owned());
        assert_eq!(ctx2.navigate(".", &VecDeque::new(), "age")
                       .unwrap()
                       .render(),
                   "4".to_owned());
    }

    #[test]
    fn test_extend() {
        let mut map = Map::new();
        map.insert("age".to_string(), context::to_json(&4usize));
        let ctx1 = Context::wraps(&map);

        let s = "hello".to_owned();
        let ctx2 = Context::wraps(&s);

        let mut hash = BTreeMap::new();
        hash.insert("tag".to_owned(), context::to_json(&"h1"));

        let ctx_a1 = ctx1.extend(&hash);
        assert_eq!(ctx_a1
                       .navigate(".", &VecDeque::new(), "age")
                       .unwrap()
                       .render(),
                   "4".to_owned());
        assert_eq!(ctx_a1
                       .navigate(".", &VecDeque::new(), "tag")
                       .unwrap()
                       .render(),
                   "h1".to_owned());

        let ctx_a2 = ctx2.extend(&hash);
        assert_eq!(ctx_a2
                       .navigate(".", &VecDeque::new(), "this")
                       .unwrap()
                       .render(),
                   "[object]".to_owned());
        assert_eq!(ctx_a2
                       .navigate(".", &VecDeque::new(), "tag")
                       .unwrap()
                       .render(),
                   "h1".to_owned());
    }

    #[test]
    fn test_key_name_with_this() {
        let m = btreemap!{
            "this_name".to_string() => "the_value".to_string()
        };
        let ctx = Context::wraps(&m);
        assert_eq!(ctx.navigate(".", &VecDeque::new(), "this_name")
                       .unwrap()
                       .render(),
                   "the_value".to_string());
    }
}
<|endoftext|>


<commit_before>use std::borrow::{Borrow, BorrowMut};
use gl;
use gl::types::*;
use ref_into::{RefInto, MutInto};
use types::{Color, Viewport, Capability, GLError};
use buffer::{BufferBinder, BufferBinderRef, BufferBinderMut};
use program::{ProgramBinder, ProgramAttrib};
use framebuffer::FramebufferBinder;
use renderbuffer::RenderbufferBinder;
use texture_units::TextureUnits;

pub type Context = ContextOf<BufferBinder,
                             FramebufferBinder,
                             ProgramBinder,
                             RenderbufferBinder,
                             TextureUnits>;

pub type ContextRef<'a> = ContextOf<&'a BufferBinder,
                                    &'a FramebufferBinder,
                                    &'a ProgramBinder,
                                    &'a RenderbufferBinder,
                                    &'a TextureUnits>;

pub type ContextMut<'a> = ContextOf<&'a mut BufferBinder,
                                    &'a mut FramebufferBinder,
                                    &'a mut ProgramBinder,
                                    &'a mut RenderbufferBinder,
                                    &'a mut TextureUnits>;

pub type ContextSubRef<'a> = ContextOf<BufferBinderRef<'a>,
                                       &'a FramebufferBinder,
                                       &'a ProgramBinder,
                                       &'a RenderbufferBinder,
                                       &'a TextureUnits>;

pub type ContextSubMut<'a> = ContextOf<BufferBinderMut<'a>,
                                       &'a mut FramebufferBinder,
                                       &'a mut ProgramBinder,
                                       &'a mut RenderbufferBinder,
                                       &'a mut TextureUnits>;

pub struct ContextOf {
    pub buffers: B,
    pub framebuffer: F,
    pub program: P,
    pub renderbuffer: R,
    pub tex_units: T
}

impl ContextOf {
    pub unsafe fn current_context() -> Context {
        ContextOf {
            buffers: BufferBinder::current(),
            framebuffer: FramebufferBinder,
            program: ProgramBinder,
            renderbuffer: RenderbufferBinder,
            tex_units: TextureUnits::current()
        }
    }

    pub fn clear_color(&mut self, color: Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn enable(&mut self, cap: Capability) {
        unsafe {
            gl::Enable(cap.gl_enum());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`cap` is not a valid OpenGL capability",
                _ => "Unknown error"
            }
        }
    }

    pub fn disable(&mut self, cap: Capability) {
        unsafe {
            gl::Disable(cap.gl_enum());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`cap` is not a valid OpenGL capability",
                _ => "Unknown error"
            }
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
            dbg_gl_error! {
                GLError::InvalidValue => "`index` is >= GL_MAX_VERTEX_ATTRIBS",
                _ => "Unknown error"
            }
        }
    }

    pub fn viewport(&self, viewport: Viewport) {
        unsafe {
            gl::Viewport(viewport.x as GLint,
                         viewport.y as GLint,
                         viewport.width as GLsizei,
                         viewport.height as GLsizei);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`width` or `height` is negative",
                _ => "Unknown error"
            }
        }
    }

    pub fn get_error() -> Option<GLError> {
        unsafe {
            match gl::GetError() {
                gl::INVALID_ENUM =>
                    Some(GLError::InvalidEnum),
                gl::INVALID_VALUE =>
                    Some(GLError::InvalidValue),
                gl::INVALID_OPERATION =>
                    Some(GLError::InvalidOperation),
                gl::INVALID_FRAMEBUFFER_OPERATION =>
                    Some(GLError::InvalidFramebufferOperation),
                gl::OUT_OF_MEMORY =>
                    Some(GLError::OutOfMemory),
                _ =>
                    None
            }
        }
    }

    pub fn borrowed<'a, BB = B, BF = F, BP = P, BR = R, BT = T>(&'a self)
        -> ContextOf<&'a BB, &'a BF, &'a BP, &'a BR, &'a BT>
        where B: Borrow<BB>,
              F: Borrow<BF>,
              P: Borrow<BP>,
              R: Borrow
,
              T: Borrow<BT>
    {
        ContextOf {
            buffers: self.buffers.borrow(),
            framebuffer: self.framebuffer.borrow(),
            program: self.program.borrow(),
            renderbuffer: self.renderbuffer.borrow(),
            tex_units: self.tex_units.borrow()
        }
    }

    pub fn borrowed_mut<'a, BB = B, BF = F, BP = P, BR = R, BT = T>
                       (&'a mut self)
        -> ContextOf<&'a mut BB,
                     &'a mut BF,
                     &'a mut BP,
                     &'a mut BR,
                     &'a mut BT>
        where B: BorrowMut<BB>,
              F: BorrowMut<BF>,
              P: BorrowMut<BP>,
              R: BorrowMut
,
              T: BorrowMut<BT>
    {
        ContextOf {
            buffers: self.buffers.borrow_mut(),
            framebuffer: self.framebuffer.borrow_mut(),
            program: self.program.borrow_mut(),
            renderbuffer: self.renderbuffer.borrow_mut(),
            tex_units: self.tex_units.borrow_mut()
        }
    }

    pub fn split_buffers(self)
        -> (B, ContextOf<(), F, P, R, T>)
    {
        (
            self.buffers,
            ContextOf {
                buffers: (),
                framebuffer: self.framebuffer,
                program: self.program,
                renderbuffer: self.renderbuffer,
                tex_units: self.tex_units
            }
        )
    }

    pub fn join_buffers<JB>(self, buffers: JB)
        -> ContextOf<JB, F, P, R, T>
    {
        ContextOf {
            buffers: buffers,
            framebuffer: self.framebuffer,
            program: self.program,
            renderbuffer: self.renderbuffer,
            tex_units: self.tex_units
        }
    }

    pub fn map_buffers<FN, BO>(self, f: FN) -> ContextOf<BO, F, P, R, T>
        where FN: FnOnce(B) -> BO
    {
        ContextOf {
            buffers: f(self.buffers),
            framebuffer: self.framebuffer,
            program: self.program,
            renderbuffer: self.renderbuffer,
            tex_units: self.tex_units
        }
    }

    pub fn split_framebuffer(self)
        -> (F, ContextOf)
    {
        (
            self.framebuffer,
            ContextOf {
                buffers: self.buffers,
                framebuffer: (),
                program: self.program,
                renderbuffer: self.renderbuffer,
                tex_units: self.tex_units
            }
        )
    }

    pub fn split_program(self)
        -> (P, ContextOf)
    {
        (
            self.program,
            ContextOf {
                buffers: self.buffers,
                framebuffer: self.framebuffer,
                program: (),
                renderbuffer: self.renderbuffer,
                tex_units: self.tex_units
            }
        )
    }

    pub fn split_renderbuffer(self)
        -> (R, ContextOf)
    {
        (
            self.renderbuffer,
            ContextOf {
                buffers: self.buffers,
                framebuffer: self.framebuffer,
                program: self.program,
                renderbuffer: (),
                tex_units: self.tex_units
            }
        )
    }

    pub fn split_tex_units(self)
        -> (T, ContextOf)
    {
        (
            self.tex_units,
            ContextOf {
                buffers: self.buffers,
                framebuffer: self.framebuffer,
                program: self.program,
                renderbuffer: self.renderbuffer,
                tex_units: ()
            }
        )
    }
}

impl<'a, B, F, P, R, T, BI, FI, PI, RI, TI>
    RefInto<'a, ContextOf<BI, FI, PI, RI, TI>>
    for ContextOf
    where B: RefInto<'a, BI>,
          F: RefInto<'a, FI>,
          P: RefInto<'a, PI>,
          R: RefInto<'a, RI>,
          T: RefInto<'a, TI>,
          BI: 'a, FI: 'a, PI: 'a, RI: 'a, TI: 'a
{
    fn ref_into(&'a self) -> ContextOf<BI, FI, PI, RI, TI> {
        ContextOf {
            buffers: self.buffers.ref_into(),
            framebuffer: self.framebuffer.ref_into(),
            program: self.program.ref_into(),
            renderbuffer: self.renderbuffer.ref_into(),
            tex_units: self.tex_units.ref_into()
        }
    }
}

impl<'a, B, F, P, R, T, BI, FI, PI, RI, TI>
    RefInto<'a, ContextOf<BI, FI, PI, RI, TI>>
    for &'a ContextOf
    where B: RefInto<'a, BI>,
          F: RefInto<'a, FI>,
          P: RefInto<'a, PI>,
          R: RefInto<'a, RI>,
          T: RefInto<'a, TI>,
          BI: 'a, FI: 'a, PI: 'a, RI: 'a, TI: 'a
{
    fn ref_into(&'a self) -> ContextOf<BI, FI, PI, RI, TI> {
        ContextOf {
            buffers: self.buffers.ref_into(),
            framebuffer: self.framebuffer.ref_into(),
            program: self.program.ref_into(),
            renderbuffer: self.renderbuffer.ref_into(),
            tex_units: self.tex_units.ref_into()
        }
    }
}

impl<'a, B, F, P, R, T, BI, FI, PI, RI, TI>
    MutInto<'a, ContextOf<BI, FI, PI, RI, TI>>
    for ContextOf
    where B: MutInto<'a, BI>,
          F: MutInto<'a, FI>,
          P: MutInto<'a, PI>,
          R: MutInto<'a, RI>,
          T: MutInto<'a, TI>,
          BI: 'a, FI: 'a, PI: 'a, RI: 'a, TI: 'a
{
    fn mut_into(&'a mut self) -> ContextOf<BI, FI, PI, RI, TI> {
        ContextOf {
            buffers: self.buffers.mut_into(),
            framebuffer: self.framebuffer.mut_into(),
            program: self.program.mut_into(),
            renderbuffer: self.renderbuffer.mut_into(),
            tex_units: self.tex_units.mut_into()
        }
    }
}

impl<'a, B, F, P, R, T, BI, FI, PI, RI, TI>
    MutInto<'a, ContextOf<BI, FI, PI, RI, TI>>
    for &'a ContextOf
    where B: RefInto<'a, BI>,
          F: RefInto<'a, FI>,
          P: RefInto<'a, PI>,
          R: RefInto<'a, RI>,
          T: RefInto<'a, TI>,
          BI: 'a, FI: 'a, PI: 'a, RI: 'a, TI: 'a
{
    fn mut_into(&'a mut self) -> ContextOf<BI, FI, PI, RI, TI> {
        ContextOf {
            buffers: self.buffers.ref_into(),
            framebuffer: self.framebuffer.ref_into(),
            program: self.program.ref_into(),
            renderbuffer: self.renderbuffer.ref_into(),
            tex_units: self.tex_units.ref_into()
        }
    }
}

impl<'a, B, F, P, R, T, BI, FI, PI, RI, TI>
    MutInto<'a, ContextOf<BI, FI, PI, RI, TI>>
    for &'a mut ContextOf
    where B: MutInto<'a, BI>,
          F: MutInto<'a, FI>,
          P: MutInto<'a, PI>,
          R: MutInto<'a, RI>,
          T: MutInto<'a, TI>,
          BI: 'a, FI: 'a, PI: 'a, RI: 'a, TI: 'a
{
    fn mut_into(&'a mut self) -> ContextOf<BI, FI, PI, RI, TI> {
        ContextOf {
            buffers: self.buffers.mut_into(),
            framebuffer: self.framebuffer.mut_into(),
            program: self.program.mut_into(),
            renderbuffer: self.renderbuffer.mut_into(),
            tex_units: self.tex_units.mut_into()
        }
    }
}

// HACK: Workaround for issue described here:
// https://www.reddit.com/r/rust/comments/339yj3/tuple_indexing_in_a_macro/cqiyv4n
#[macro_export]
macro_rules! _glitter_expr {
    ($x:expr) => ($x)
}

#[macro_export]
macro_rules! active_texture {
    ($gl:expr, $idx:tt) => {
        _glitter_expr!($gl.tex_units.$idx.active())
    }
}

#[macro_export]
macro_rules! active_texture_n {
    ($gl:expr, $idx:expr) => {
        $gl.tex_units.nth_unit($idx).active()
    }
}
<commit_msg>Add `ref_into()` and `mut_into()` methods on `ContextOf` directly<commit_after>use std::borrow::{Borrow, BorrowMut};
use gl;
use gl::types::*;
use ref_into::{RefInto, MutInto};
use types::{Color, Viewport, Capability, GLError};
use buffer::{BufferBinder, BufferBinderRef, BufferBinderMut};
use program::{ProgramBinder, ProgramAttrib};
use framebuffer::FramebufferBinder;
use renderbuffer::RenderbufferBinder;
use texture_units::TextureUnits;

pub type Context = ContextOf<BufferBinder,
                             FramebufferBinder,
                             ProgramBinder,
                             RenderbufferBinder,
                             TextureUnits>;

pub type ContextRef<'a> = ContextOf<&'a BufferBinder,
                                    &'a FramebufferBinder,
                                    &'a ProgramBinder,
                                    &'a RenderbufferBinder,
                                    &'a TextureUnits>;

pub type ContextMut<'a> = ContextOf<&'a mut BufferBinder,
                                    &'a mut FramebufferBinder,
                                    &'a mut ProgramBinder,
                                    &'a mut RenderbufferBinder,
                                    &'a mut TextureUnits>;

pub type ContextSubRef<'a> = ContextOf<BufferBinderRef<'a>,
                                       &'a FramebufferBinder,
                                       &'a ProgramBinder,
                                       &'a RenderbufferBinder,
                                       &'a TextureUnits>;

pub type ContextSubMut<'a> = ContextOf<BufferBinderMut<'a>,
                                       &'a mut FramebufferBinder,
                                       &'a mut ProgramBinder,
                                       &'a mut RenderbufferBinder,
                                       &'a mut TextureUnits>;

pub struct ContextOf {
    pub buffers: B,
    pub framebuffer: F,
    pub program: P,
    pub renderbuffer: R,
    pub tex_units: T
}

impl ContextOf {
    pub unsafe fn current_context() -> Context {
        ContextOf {
            buffers: BufferBinder::current(),
            framebuffer: FramebufferBinder,
            program: ProgramBinder,
            renderbuffer: RenderbufferBinder,
            tex_units: TextureUnits::current()
        }
    }

    pub fn clear_color(&mut self, color: Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn enable(&mut self, cap: Capability) {
        unsafe {
            gl::Enable(cap.gl_enum());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`cap` is not a valid OpenGL capability",
                _ => "Unknown error"
            }
        }
    }

    pub fn disable(&mut self, cap: Capability) {
        unsafe {
            gl::Disable(cap.gl_enum());
            dbg_gl_sanity_check! {
                GLError::InvalidEnum => "`cap` is not a valid OpenGL capability",
                _ => "Unknown error"
            }
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
            dbg_gl_error! {
                GLError::InvalidValue => "`index` is >= GL_MAX_VERTEX_ATTRIBS",
                _ => "Unknown error"
            }
        }
    }

    pub fn viewport(&self, viewport: Viewport) {
        unsafe {
            gl::Viewport(viewport.x as GLint,
                         viewport.y as GLint,
                         viewport.width as GLsizei,
                         viewport.height as GLsizei);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`width` or `height` is negative",
                _ => "Unknown error"
            }
        }
    }

    pub fn get_error() -> Option<GLError> {
        unsafe {
            match gl::GetError() {
                gl::INVALID_ENUM =>
                    Some(GLError::InvalidEnum),
                gl::INVALID_VALUE =>
                    Some(GLError::InvalidValue),
                gl::INVALID_OPERATION =>
                    Some(GLError::InvalidOperation),
                gl::INVALID_FRAMEBUFFER_OPERATION =>
                    Some(GLError::InvalidFramebufferOperation),
                gl::OUT_OF_MEMORY =>
                    Some(GLError::OutOfMemory),
                _ =>
                    None
            }
        }
    }

    pub fn borrowed<'a, BB = B, BF = F, BP = P, BR = R, BT = T>(&'a self)
        -> ContextOf<&'a BB, &'a BF, &'a BP, &'a BR, &'a BT>
        where B: Borrow<BB>,
              F: Borrow<BF>,
              P: Borrow<BP>,
              R: Borrow
,
              T: Borrow<BT>
    {
        ContextOf {
            buffers: self.buffers.borrow(),
            framebuffer: self.framebuffer.borrow(),
            program: self.program.borrow(),
            renderbuffer: self.renderbuffer.borrow(),
            tex_units: self.tex_units.borrow()
        }
    }

    pub fn borrowed_mut<'a, BB = B, BF = F, BP = P, BR = R, BT = T>
                       (&'a mut self)
        -> ContextOf<&'a mut BB,
                     &'a mut BF,
                     &'a mut BP,
                     &'a mut BR,
                     &'a mut BT>
        where B: BorrowMut<BB>,
              F: BorrowMut<BF>,
              P: BorrowMut<BP>,
              R: BorrowMut
,
              T: BorrowMut<BT>
    {
        ContextOf {
            buffers: self.buffers.borrow_mut(),
            framebuffer: self.framebuffer.borrow_mut(),
            program: self.program.borrow_mut(),
            renderbuffer: self.renderbuffer.borrow_mut(),
            tex_units: self.tex_units.borrow_mut()
        }
    }

    pub fn ref_into<'a,
                    BI = &'a B,
                    FI = &'a F,
                    PI = &'a P,
                    RI = &'a R,
                    TI = &'a T>
                   (&'a self)
        -> ContextOf<BI, FI, PI, RI, TI>
        where B: RefInto<'a, BI>,
              F: RefInto<'a, FI>,
              P: RefInto<'a, PI>,
              R: RefInto<'a, RI>,
              T: RefInto<'a, TI>
    {
        ContextOf {
            buffers: self.buffers.ref_into(),
            framebuffer: self.framebuffer.ref_into(),
            program: self.program.ref_into(),
            renderbuffer: self.renderbuffer.ref_into(),
            tex_units: self.tex_units.ref_into()
        }
    }

    pub fn mut_into<'a,
                    BI = &'a mut B,
                    FI = &'a mut F,
                    PI = &'a mut P,
                    RI = &'a mut R,
                    TI = &'a mut T>
                   (&'a mut self)
        -> ContextOf<BI, FI, PI, RI, TI>
        where B: MutInto<'a, BI>,
              F: MutInto<'a, FI>,
              P: MutInto<'a, PI>,
              R: MutInto<'a, RI>,
              T: MutInto<'a, TI>
    {
        ContextOf {
            buffers: self.buffers.mut_into(),
            framebuffer: self.framebuffer.mut_into(),
            program: self.program.mut_into(),
            renderbuffer: self.renderbuffer.mut_into(),
            tex_units: self.tex_units.mut_into()
        }
    }

    pub fn split_buffers(self)
        -> (B, ContextOf<(), F, P, R, T>)
    {
        (
            self.buffers,
            ContextOf {
                buffers: (),
                framebuffer: self.framebuffer,
                program: self.program,
                renderbuffer: self.renderbuffer,
                tex_units: self.tex_units
            }
        )
    }

    pub fn join_buffers<JB>(self, buffers: JB)
        -> ContextOf<JB, F, P, R, T>
    {
        ContextOf {
            buffers: buffers,
            framebuffer: self.framebuffer,
            program: self.program,
            renderbuffer: self.renderbuffer,
            tex_units: self.tex_units
        }
    }

    pub fn map_buffers<FN, BO>(self, f: FN) -> ContextOf<BO, F, P, R, T>
        where FN: FnOnce(B) -> BO
    {
        ContextOf {
            buffers: f(self.buffers),
            framebuffer: self.framebuffer,
            program: self.program,
            renderbuffer: self.renderbuffer,
            tex_units: self.tex_units
        }
    }

    pub fn split_framebuffer(self)
        -> (F, ContextOf)
    {
        (
            self.framebuffer,
            ContextOf {
                buffers: self.buffers,
                framebuffer: (),
                program: self.program,
                renderbuffer: self.renderbuffer,
                tex_units: self.tex_units
            }
        )
    }

    pub fn split_program(self)
        -> (P, ContextOf)
    {
        (
            self.program,
            ContextOf {
                buffers: self.buffers,
                framebuffer: self.framebuffer,
                program: (),
                renderbuffer: self.renderbuffer,
                tex_units: self.tex_units
            }
        )
    }

    pub fn split_renderbuffer(self)
        -> (R, ContextOf)
    {
        (
            self.renderbuffer,
            ContextOf {
                buffers: self.buffers,
                framebuffer: self.framebuffer,
                program: self.program,
                renderbuffer: (),
                tex_units: self.tex_units
            }
        )
    }

    pub fn split_tex_units(self)
        -> (T, ContextOf)
    {
        (
            self.tex_units,
            ContextOf {
                buffers: self.buffers,
                framebuffer: self.framebuffer,
                program: self.program,
                renderbuffer: self.renderbuffer,
                tex_units: ()
            }
        )
    }
}

impl<'a, B, F, P, R, T, BI, FI, PI, RI, TI>
    RefInto<'a, ContextOf<BI, FI, PI, RI, TI>>
    for ContextOf
    where B: RefInto<'a, BI>,
          F: RefInto<'a, FI>,
          P: RefInto<'a, PI>,
          R: RefInto<'a, RI>,
          T: RefInto<'a, TI>,
          BI: 'a, FI: 'a, PI: 'a, RI: 'a, TI: 'a
{
    fn ref_into(&'a self) -> ContextOf<BI, FI, PI, RI, TI> {
        ContextOf {
            buffers: self.buffers.ref_into(),
            framebuffer: self.framebuffer.ref_into(),
            program: self.program.ref_into(),
            renderbuffer: self.renderbuffer.ref_into(),
            tex_units: self.tex_units.ref_into()
        }
    }
}

impl<'a, B, F, P, R, T, BI, FI, PI, RI, TI>
    RefInto<'a, ContextOf<BI, FI, PI, RI, TI>>
    for &'a ContextOf
    where B: RefInto<'a, BI>,
          F: RefInto<'a, FI>,
          P: RefInto<'a, PI>,
          R: RefInto<'a, RI>,
          T: RefInto<'a, TI>,
          BI: 'a, FI: 'a, PI: 'a, RI: 'a, TI: 'a
{
    fn ref_into(&'a self) -> ContextOf<BI, FI, PI, RI, TI> {
        ContextOf {
            buffers: self.buffers.ref_into(),
            framebuffer: self.framebuffer.ref_into(),
            program: self.program.ref_into(),
            renderbuffer: self.renderbuffer.ref_into(),
            tex_units: self.tex_units.ref_into()
        }
    }
}

impl<'a, B, F, P, R, T, BI, FI, PI, RI, TI>
    MutInto<'a, ContextOf<BI, FI, PI, RI, TI>>
    for ContextOf
    where B: MutInto<'a, BI>,
          F: MutInto<'a, FI>,
          P: MutInto<'a, PI>,
          R: MutInto<'a, RI>,
          T: MutInto<'a, TI>,
          BI: 'a, FI: 'a, PI: 'a, RI: 'a, TI: 'a
{
    fn mut_into(&'a mut self) -> ContextOf<BI, FI, PI, RI, TI> {
        ContextOf {
            buffers: self.buffers.mut_into(),
            framebuffer: self.framebuffer.mut_into(),
            program: self.program.mut_into(),
            renderbuffer: self.renderbuffer.mut_into(),
            tex_units: self.tex_units.mut_into()
        }
    }
}

impl<'a, B, F, P, R, T, BI, FI, PI, RI, TI>
    MutInto<'a, ContextOf<BI, FI, PI, RI, TI>>
    for &'a ContextOf
    where B: RefInto<'a, BI>,
          F: RefInto<'a, FI>,
          P: RefInto<'a, PI>,
          R: RefInto<'a, RI>,
          T: RefInto<'a, TI>,
          BI: 'a, FI: 'a, PI: 'a, RI: 'a, TI: 'a
{
    fn mut_into(&'a mut self) -> ContextOf<BI, FI, PI, RI, TI> {
        ContextOf {
            buffers: self.buffers.ref_into(),
            framebuffer: self.framebuffer.ref_into(),
            program: self.program.ref_into(),
            renderbuffer: self.renderbuffer.ref_into(),
            tex_units: self.tex_units.ref_into()
        }
    }
}

impl<'a, B, F, P, R, T, BI, FI, PI, RI, TI>
    MutInto<'a, ContextOf<BI, FI, PI, RI, TI>>
    for &'a mut ContextOf
    where B: MutInto<'a, BI>,
          F: MutInto<'a, FI>,
          P: MutInto<'a, PI>,
          R: MutInto<'a, RI>,
          T: MutInto<'a, TI>,
          BI: 'a, FI: 'a, PI: 'a, RI: 'a, TI: 'a
{
    fn mut_into(&'a mut self) -> ContextOf<BI, FI, PI, RI, TI> {
        ContextOf {
            buffers: self.buffers.mut_into(),
            framebuffer: self.framebuffer.mut_into(),
            program: self.program.mut_into(),
            renderbuffer: self.renderbuffer.mut_into(),
            tex_units: self.tex_units.mut_into()
        }
    }
}

// HACK: Workaround for issue described here:
// https://www.reddit.com/r/rust/comments/339yj3/tuple_indexing_in_a_macro/cqiyv4n
#[macro_export]
macro_rules! _glitter_expr {
    ($x:expr) => ($x)
}

#[macro_export]
macro_rules! active_texture {
    ($gl:expr, $idx:tt) => {
        _glitter_expr!($gl.tex_units.$idx.active())
    }
}

#[macro_export]
macro_rules! active_texture_n {
    ($gl:expr, $idx:expr) => {
        $gl.tex_units.nth_unit($idx).active()
    }
}
<|endoftext|>