<commit_before>// The CPU
#![allow(non_snake_case)]
extern crate sdl2;
use c64::opcodes;
use c64::memory;
use c64::vic;
use c64::cia;
use std::cell::RefCell;
use std::rc::Rc;

use utils;

pub type CPUShared = Rc<RefCell<CPU>>;

// status flags for P register
pub enum StatusFlag
{
    Carry            = 1 << 0,
    Zero             = 1 << 1,
    InterruptDisable = 1 << 2,
    DecimalMode      = 1 << 3,
    Break            = 1 << 4,
    Unused           = 1 << 5,
    Overflow         = 1 << 6,
    Negative         = 1 << 7,
}

pub static NMI_VECTOR:   u16 = 0xFFFA;
pub static RESET_VECTOR: u16 = 0xFFFC;
pub static IRQ_VECTOR:   u16 = 0xFFFE;

pub struct CPU
{
    pub PC: u16, // program counter
    pub SP: u8,  // stack pointer
    pub P: u8,   // processor status
    pub A: u8,   // accumulator
    pub X: u8,   // index register
    pub Y: u8,   // index register
    pub mem_ref: Option<memory::MemShared>, // reference to shared system memory
    pub vic_ref: Option<vic::VICShared>,
    pub cia1_ref: Option<cia::CIAShared>,
    pub cia2_ref: Option<cia::CIAShared>,
    pub ba_low: bool,  // is BA low?
    pub cia_irq: bool,
    pub vic_irq: bool,
    wait_cycles: u8,
    nmi: bool,
    pub prev_PC: u16, // previous program counter - for debugging
    dfff_byte: u8,
    pub op_debugger: utils::OpDebugger
}

impl CPU
{
    pub fn new_shared() -> CPUShared
    {
        Rc::new(RefCell::new(CPU
        {
            PC: 0,
            SP: 0xFF,
            P: 0,
            A: 0,
            X: 0,
            Y: 0,
            mem_ref: None,
            vic_ref: None,
            cia1_ref: None,
            cia2_ref: None,
            ba_low: false,
            cia_irq: false,
            vic_irq: false,
            wait_cycles: 0,
            nmi: false,
            prev_PC: 0,
            dfff_byte: 0x55,
            op_debugger: utils::OpDebugger::new()
        }))
    }

    pub fn set_references(&mut self, memref: memory::MemShared, vicref: vic::VICShared, cia1ref: cia::CIAShared, cia2ref: cia::CIAShared)
    {
        self.mem_ref = Some(memref);
        self.vic_ref = Some(vicref);
        self.cia1_ref = Some(cia1ref);
        self.cia2_ref = Some(cia2ref);
    }

    pub fn set_status_flag(&mut self, flag: StatusFlag, value: bool)
    {
        if value { self.P |=   flag as u8;  }
        else     { self.P &= !(flag as u8); }
    }

    pub fn get_status_flag(&mut self, flag: StatusFlag) -> bool
    {
        self.P & flag as u8 != 0x00
    }

    // these flags will be set in tandem quite often
    pub fn set_zn_flags(&mut self, value: u8)
    {
        self.set_status_flag(StatusFlag::Zero, value == 0x00);
        self.set_status_flag(StatusFlag::Negative, (value as i8) < 0);
    }

    pub fn reset(&mut self)
    {
        // reset program counter
        let pc = self.read_word_le(RESET_VECTOR);
        self.PC = pc;
        self.SP = 0xFF;
        self.ba_low = false;
        self.cia_irq = false;
        self.vic_irq = false;
        self.nmi = false;
    }

    pub fn update(&mut self)
    {
        if self.ba_low { return }

        if self.process_nmi() { self.wait_cycles += 7; }
        else if self.process_irq() { self.wait_cycles += 7; }

        if self.wait_cycles == 0
        {
            let op = self.next_byte();
            self.wait_cycles += self.process_op(op);
        }
        else
        {
            self.wait_cycles -= 1;
        }
    }

    pub fn next_byte(&mut self) -> u8
    {
        let pc = self.PC;
        let op = self.read_byte(pc);
        self.PC += 1;
        op
    }

    pub fn next_word(&mut self) -> u16
    {
        let word = self.read_word_le(self.PC);
        self.PC += 2;
        word
    }

    // stack memory: $0100 - $01FF (256 byes)
    // TODO: some extra message if stack over/underflow occurs? (right now handled by Rust)
    pub fn push_byte(&mut self, value: u8)
    {
        self.SP -= 0x01;
        let newSP = (self.SP + 0x01) as u16;
        self.write_byte(0x0100 + newSP, value);
    }

    pub fn pop_byte(&mut self) -> u8
    {
        let addr = 0x0100 + (self.SP + 0x01) as u16;
        let value = self.read_byte(addr);
        self.SP += 0x01;
        value
    }

    pub fn push_word(&mut self, value: u16)
    {
        self.SP -= 0x02;
        self.write_word_le(0x0100 + (self.SP + 0x01) as u16, value);
    }

    pub fn pop_word(&mut self) -> u16
    {
        let value = self.read_word_le(0x0100 + (self.SP + 0x01) as u16);
        self.SP += 0x02;
        value
    }

    pub fn write_byte(&mut self, addr: u16, value: u8) -> bool
    {
        let mut on_vic_write: vic::VICCallbackAction = vic::VICCallbackAction::None;
        let mut on_cia_write: cia::CIACallbackAction = cia::CIACallbackAction::None;
        let mem_write_ok: bool;
        let io_enabled = as_ref!(self.mem_ref).io_on;

        match addr
        {
            // VIC-II address space
            0xD000...0xD3FF => {
                if io_enabled
                {
                    mem_write_ok = true;
                    as_mut!(self.vic_ref).write_register(addr, value, &mut on_vic_write);
                }
                else
                {
                    mem_write_ok = as_mut!(self.mem_ref).write_byte(addr, value);
                }
            },
            // color RAM address space
            0xD800...0xDBFF => {
                if io_enabled
                {
                    mem_write_ok = as_mut!(self.mem_ref).write_byte(addr, value & 0x0F);
                }
                else
                {
                    mem_write_ok = as_mut!(self.mem_ref).write_byte(addr, value);
                }
            },
            // CIA1 address space
            0xDC00...0xDCFF => {
                if io_enabled
                {
                    mem_write_ok = as_mut!(self.cia1_ref).write_register(addr, value, &mut on_cia_write);
                }
                else
                {
                    mem_write_ok = as_mut!(self.mem_ref).write_byte(addr, value);
                }
            },
            // CIA2 address space
            0xDD00...0xDDFF => {
                if io_enabled
                {
                    mem_write_ok = as_mut!(self.cia2_ref).write_register(addr, value, &mut on_cia_write);
                }
                else
                {
                    mem_write_ok = as_mut!(self.mem_ref).write_byte(addr, value);
                }
            },
            _ => mem_write_ok = as_mut!(self.mem_ref).write_byte(addr, value),
        }

        // on VIC register write perform necessary action on the CPU
        match on_vic_write
        {
            vic::VICCallbackAction::TriggerVICIrq => self.trigger_vic_irq(),
            vic::VICCallbackAction::ClearVICIrq   => self.clear_vic_irq(),
            _ => (),
        }

        match on_cia_write
        {
            cia::CIACallbackAction::TriggerCIAIRQ => self.trigger_cia_irq(),
            cia::CIACallbackAction::ClearCIAIRQ   => self.clear_cia_irq(),
            cia::CIACallbackAction::TriggerNMI    => self.trigger_nmi(),
            cia::CIACallbackAction::ClearNMI      => self.clear_nmi(),
            _ => (),
        }

        mem_write_ok
    }

    pub fn read_byte(&mut self, addr: u16) -> u8
    {
        let byte: u8;
        let mut on_cia_read: cia::CIACallbackAction = cia::CIACallbackAction::None;
        let io_enabled = as_ref!(self.mem_ref).io_on;
        match addr
        {
            // VIC-II address space
            0xD000...0xD3FF => {
                if io_enabled
                {
                    byte = as_mut!(self.vic_ref).read_register(addr);
                }
                else
                {
                    byte = as_mut!(self.mem_ref).read_byte(addr);
                }
            },
            // color RAM address space
            0xD800...0xDBFF => {
                if io_enabled
                {
                    byte = (as_ref!(self.mem_ref).read_byte(addr) & 0x0F) | (as_ref!(self.vic_ref).last_byte & 0xF0);
                }
                else
                {
                    byte = as_mut!(self.mem_ref).read_byte(addr);
                }
            },
            // CIA1 address space
            0xDC00...0xDCFF => {
                if io_enabled
                {
                    byte = as_mut!(self.cia1_ref).read_register(addr, &mut on_cia_read);
                }
                else
                {
                    byte = as_mut!(self.mem_ref).read_byte(addr);
                }
            },
            // CIA2 address space
            0xDD00...0xDDFF => {
                if io_enabled
                {
                    byte = as_mut!(self.cia2_ref).read_register(addr, &mut on_cia_read);
                }
                else
                {
                    byte = as_mut!(self.mem_ref).read_byte(addr);
                }
            },
            0xDF00...0xDF9F => {
                if io_enabled
                {
                    byte = as_ref!(self.vic_ref).last_byte;
                }
                else
                {
                    byte = as_mut!(self.mem_ref).read_byte(addr);
                }
            },
            0xDFFF => {
                if io_enabled
                {
                    self.dfff_byte = !self.dfff_byte;
                    byte = self.dfff_byte;
                }
                else
                {
                    byte = as_mut!(self.mem_ref).read_byte(addr);
                }
            },
            _ => byte = as_mut!(self.mem_ref).read_byte(addr)
        }

        match on_cia_read
        {
            cia::CIACallbackAction::TriggerCIAIRQ => self.trigger_cia_irq(),
            cia::CIACallbackAction::ClearCIAIRQ   => self.clear_cia_irq(),
            cia::CIACallbackAction::TriggerNMI    => self.trigger_nmi(),
            cia::CIACallbackAction::ClearNMI      => self.clear_nmi(),
            _ => (),
        }

        byte
    }

    pub fn read_word_le(&self, addr: u16) -> u16
    {
        as_ref!(self.mem_ref).read_word_le(addr)
    }

    pub fn write_word_le(&self, addr: u16, value: u16) -> bool
    {
        as_ref!(self.mem_ref).write_word_le(addr, value)
    }

    fn process_nmi(&mut self) -> bool
    {
        // 7 cycles
        if self.nmi
        {
            let curr_pc = self.PC;
            let curr_p = self.P;
            self.push_word(curr_pc);
            self.push_byte(curr_p);
            self.set_status_flag(StatusFlag::InterruptDisable, true);
            self.PC = as_ref!(self.mem_ref).read_word_le(NMI_VECTOR);
            self.nmi = false;
            true
        }
        else
        {
            false
        }
    }

    fn process_irq(&mut self) -> bool
    {
        // 7 cycles
        if (self.cia_irq || self.vic_irq) && !self.get_status_flag(StatusFlag::InterruptDisable)
        {
            self.set_status_flag(StatusFlag::Break, false);
            let curr_pc = self.PC;
            let curr_p = self.P;
            //println!("PC {} P {}", curr_pc, curr_p);
            self.push_word(curr_pc);
            self.push_byte(curr_p);
            self.set_status_flag(StatusFlag::InterruptDisable, true);
            self.PC = as_ref!(self.mem_ref).read_word_le(IRQ_VECTOR);
            self.cia_irq = false;
            self.vic_irq = false;
            true
        }
        else
        {
            false
        }
    }

    pub fn trigger_vic_irq(&mut self)
    {
        // TODO:
        //println!("VIC irq");
        self.vic_irq = true;
    }

    pub fn clear_vic_irq(&mut self)
    {
        // TODO
        self.vic_irq = false;
    }

    pub fn trigger_nmi(&mut self)
    {
        // TODO
        //println!("NMI irq");
        self.nmi = true;
    }

    pub fn clear_nmi(&mut self)
    {
        // TODO
        self.nmi = false;
    }

    pub fn trigger_cia_irq(&mut self)
    {
        // TODO
        //println!("CIA irq");
        self.cia_irq = true;
    }

    pub fn clear_cia_irq(&mut self)
    {
        // TODO
        self.cia_irq = false;
    }

    fn process_op(&mut self, opcode: u8) -> u8
    {
        //utils::debug_instruction(opcode, self);
        self.prev_PC = self.PC;
        match opcodes::get_instruction(opcode, self)
        {
            Some((instruction, num_cycles, addr_mode)) => {
                //utils::debug_instruction(opcode, Some((&instruction, num_cycles, &addr_mode)), self);
                instruction.run(&addr_mode, self);
                num_cycles
            },
            None => panic!("No instruction - this should never happen! (0x{:02X} at ${:04X})", opcode, self.PC)
        }
    }
}
<commit_msg>reduce num cycles (fetch already takes 1)<commit_after>// The CPU
#![allow(non_snake_case)]
extern crate sdl2;
use c64::opcodes;
use c64::memory;
use c64::vic;
use c64::cia;
use std::cell::RefCell;
use std::rc::Rc;

use utils;

pub type CPUShared = Rc<RefCell<CPU>>;

// status flags for P register
pub enum StatusFlag
{
    Carry            = 1 << 0,
    Zero             = 1 << 1,
    InterruptDisable = 1 << 2,
    DecimalMode      = 1 << 3,
    Break            = 1 << 4,
    Unused           = 1 << 5,
    Overflow         = 1 << 6,
    Negative         = 1 << 7,
}

pub static NMI_VECTOR:   u16 = 0xFFFA;
pub static RESET_VECTOR: u16 = 0xFFFC;
pub static IRQ_VECTOR:   u16 = 0xFFFE;

pub struct CPU
{
    pub PC: u16, // program counter
    pub SP: u8,  // stack pointer
    pub P: u8,   // processor status
    pub A: u8,   // accumulator
    pub X: u8,   // index register
    pub Y: u8,   // index register
    pub mem_ref: Option<memory::MemShared>, // reference to shared system memory
    pub vic_ref: Option<vic::VICShared>,
    pub cia1_ref: Option<cia::CIAShared>,
    pub cia2_ref: Option<cia::CIAShared>,
    pub ba_low: bool,  // is BA low?
    pub cia_irq: bool,
    pub vic_irq: bool,
    wait_cycles: u8,
    nmi: bool,
    pub prev_PC: u16, // previous program counter - for debugging
    dfff_byte: u8,
    pub op_debugger: utils::OpDebugger
}

impl CPU
{
    pub fn new_shared() -> CPUShared
    {
        Rc::new(RefCell::new(CPU
        {
            PC: 0,
            SP: 0xFF,
            P: 0,
            A: 0,
            X: 0,
            Y: 0,
            mem_ref: None,
            vic_ref: None,
            cia1_ref: None,
            cia2_ref: None,
            ba_low: false,
            cia_irq: false,
            vic_irq: false,
            wait_cycles: 0,
            nmi: false,
            prev_PC: 0,
            dfff_byte: 0x55,
            op_debugger: utils::OpDebugger::new()
        }))
    }

    pub fn set_references(&mut self, memref: memory::MemShared, vicref: vic::VICShared, cia1ref: cia::CIAShared, cia2ref: cia::CIAShared)
    {
        self.mem_ref = Some(memref);
        self.vic_ref = Some(vicref);
        self.cia1_ref = Some(cia1ref);
        self.cia2_ref = Some(cia2ref);
    }

    pub fn set_status_flag(&mut self, flag: StatusFlag, value: bool)
    {
        if value { self.P |=   flag as u8;  }
        else     { self.P &= !(flag as u8); }
    }

    pub fn get_status_flag(&mut self, flag: StatusFlag) -> bool
    {
        self.P & flag as u8 != 0x00
    }

    // these flags will be set in tandem quite often
    pub fn set_zn_flags(&mut self, value: u8)
    {
        self.set_status_flag(StatusFlag::Zero, value == 0x00);
        self.set_status_flag(StatusFlag::Negative, (value as i8) < 0);
    }

    pub fn reset(&mut self)
    {
        // reset program counter
        let pc = self.read_word_le(RESET_VECTOR);
        self.PC = pc;
        self.SP = 0xFF;
        self.ba_low = false;
        self.cia_irq = false;
        self.vic_irq = false;
        self.nmi = false;
    }

    pub fn update(&mut self)
    {
        if self.process_nmi() { self.wait_cycles += 7; }
        else if self.process_irq() { self.wait_cycles += 7; }

        if !self.ba_low {
            if self.wait_cycles == 0
            {
                let op = self.next_byte();
                self.wait_cycles += self.process_op(op);
            }
        }

        if self.wait_cycles > 0
        {
            self.wait_cycles -= 1;
        }
    }

    pub fn next_byte(&mut self) -> u8
    {
        let pc = self.PC;
        let op = self.read_byte(pc);
        self.PC += 1;
        op
    }

    pub fn next_word(&mut self) -> u16
    {
        let word = self.read_word_le(self.PC);
        self.PC += 2;
        word
    }

    // stack memory: $0100 - $01FF (256 byes)
    // TODO: some extra message if stack over/underflow occurs? (right now handled by Rust)
    pub fn push_byte(&mut self, value: u8)
    {
        self.SP -= 0x01;
        let newSP = (self.SP + 0x01) as u16;
        self.write_byte(0x0100 + newSP, value);
    }

    pub fn pop_byte(&mut self) -> u8
    {
        let addr = 0x0100 + (self.SP + 0x01) as u16;
        let value = self.read_byte(addr);
        self.SP += 0x01;
        value
    }

    pub fn push_word(&mut self, value: u16)
    {
        self.SP -= 0x02;
        self.write_word_le(0x0100 + (self.SP + 0x01) as u16, value);
    }

    pub fn pop_word(&mut self) -> u16
    {
        let value = self.read_word_le(0x0100 + (self.SP + 0x01) as u16);
        self.SP += 0x02;
        value
    }

    pub fn write_byte(&mut self, addr: u16, value: u8) -> bool
    {
        let mut on_vic_write: vic::VICCallbackAction = vic::VICCallbackAction::None;
        let mut on_cia_write: cia::CIACallbackAction = cia::CIACallbackAction::None;
        let mem_write_ok: bool;
        let io_enabled = as_ref!(self.mem_ref).io_on;

        match addr
        {
            // VIC-II address space
            0xD000...0xD3FF => {
                if io_enabled
                {
                    mem_write_ok = true;
                    as_mut!(self.vic_ref).write_register(addr, value, &mut on_vic_write);
                }
                else
                {
                    mem_write_ok = as_mut!(self.mem_ref).write_byte(addr, value);
                }
            },
            // color RAM address space
            0xD800...0xDBFF => {
                if io_enabled
                {
                    mem_write_ok = as_mut!(self.mem_ref).write_byte(addr, value & 0x0F);
                }
                else
                {
                    mem_write_ok = as_mut!(self.mem_ref).write_byte(addr, value);
                }
            },
            // CIA1 address space
            0xDC00...0xDCFF => {
                if io_enabled
                {
                    mem_write_ok = as_mut!(self.cia1_ref).write_register(addr, value, &mut on_cia_write);
                }
                else
                {
                    mem_write_ok = as_mut!(self.mem_ref).write_byte(addr, value);
                }
            },
            // CIA2 address space
            0xDD00...0xDDFF => {
                if io_enabled
                {
                    mem_write_ok = as_mut!(self.cia2_ref).write_register(addr, value, &mut on_cia_write);
                }
                else
                {
                    mem_write_ok = as_mut!(self.mem_ref).write_byte(addr, value);
                }
            },
            _ => mem_write_ok = as_mut!(self.mem_ref).write_byte(addr, value),
        }

        // on VIC register write perform necessary action on the CPU
        match on_vic_write
        {
            vic::VICCallbackAction::TriggerVICIrq => self.trigger_vic_irq(),
            vic::VICCallbackAction::ClearVICIrq   => self.clear_vic_irq(),
            _ => (),
        }

        match on_cia_write
        {
            cia::CIACallbackAction::TriggerCIAIRQ => self.trigger_cia_irq(),
            cia::CIACallbackAction::ClearCIAIRQ   => self.clear_cia_irq(),
            cia::CIACallbackAction::TriggerNMI    => self.trigger_nmi(),
            cia::CIACallbackAction::ClearNMI      => self.clear_nmi(),
            _ => (),
        }

        mem_write_ok
    }

    pub fn read_byte(&mut self, addr: u16) -> u8
    {
        let byte: u8;
        let mut on_cia_read: cia::CIACallbackAction = cia::CIACallbackAction::None;
        let io_enabled = as_ref!(self.mem_ref).io_on;
        match addr
        {
            // VIC-II address space
            0xD000...0xD3FF => {
                if io_enabled
                {
                    byte = as_mut!(self.vic_ref).read_register(addr);
                }
                else
                {
                    byte = as_mut!(self.mem_ref).read_byte(addr);
                }
            },
            // color RAM address space
            0xD800...0xDBFF => {
                if io_enabled
                {
                    byte = (as_ref!(self.mem_ref).read_byte(addr) & 0x0F) | (as_ref!(self.vic_ref).last_byte & 0xF0);
                }
                else
                {
                    byte = as_mut!(self.mem_ref).read_byte(addr);
                }
            },
            // CIA1 address space
            0xDC00...0xDCFF => {
                if io_enabled
                {
                    byte = as_mut!(self.cia1_ref).read_register(addr, &mut on_cia_read);
                }
                else
                {
                    byte = as_mut!(self.mem_ref).read_byte(addr);
                }
            },
            // CIA2 address space
            0xDD00...0xDDFF => {
                if io_enabled
                {
                    byte = as_mut!(self.cia2_ref).read_register(addr, &mut on_cia_read);
                }
                else
                {
                    byte = as_mut!(self.mem_ref).read_byte(addr);
                }
            },
            0xDF00...0xDF9F => {
                if io_enabled
                {
                    byte = as_ref!(self.vic_ref).last_byte;
                }
                else
                {
                    byte = as_mut!(self.mem_ref).read_byte(addr);
                }
            },
            0xDFFF => {
                if io_enabled
                {
                    self.dfff_byte = !self.dfff_byte;
                    byte = self.dfff_byte;
                }
                else
                {
                    byte = as_mut!(self.mem_ref).read_byte(addr);
                }
            },
            _ => byte = as_mut!(self.mem_ref).read_byte(addr)
        }

        match on_cia_read
        {
            cia::CIACallbackAction::TriggerCIAIRQ => self.trigger_cia_irq(),
            cia::CIACallbackAction::ClearCIAIRQ   => self.clear_cia_irq(),
            cia::CIACallbackAction::TriggerNMI    => self.trigger_nmi(),
            cia::CIACallbackAction::ClearNMI      => self.clear_nmi(),
            _ => (),
        }

        byte
    }

    pub fn read_word_le(&self, addr: u16) -> u16
    {
        as_ref!(self.mem_ref).read_word_le(addr)
    }

    pub fn write_word_le(&self, addr: u16, value: u16) -> bool
    {
        as_ref!(self.mem_ref).write_word_le(addr, value)
    }

    fn process_nmi(&mut self) -> bool
    {
        // 7 cycles
        if self.nmi
        {
            let curr_pc = self.PC;
            let curr_p = self.P;
            self.push_word(curr_pc);
            self.push_byte(curr_p);
            self.set_status_flag(StatusFlag::InterruptDisable, true);
            self.PC = as_ref!(self.mem_ref).read_word_le(NMI_VECTOR);
            self.nmi = false;
            true
        }
        else
        {
            false
        }
    }

    fn process_irq(&mut self) -> bool
    {
        // 7 cycles
        if (self.cia_irq || self.vic_irq) && !self.get_status_flag(StatusFlag::InterruptDisable)
        {
            self.set_status_flag(StatusFlag::Break, false);
            let curr_pc = self.PC;
            let curr_p = self.P;
            //println!("PC {} P {}", curr_pc, curr_p);
            self.push_word(curr_pc);
            self.push_byte(curr_p);
            self.set_status_flag(StatusFlag::InterruptDisable, true);
            self.PC = as_ref!(self.mem_ref).read_word_le(IRQ_VECTOR);
            self.cia_irq = false;
            self.vic_irq = false;
            true
        }
        else
        {
            false
        }
    }

    pub fn trigger_vic_irq(&mut self)
    {
        // TODO:
        //println!("VIC irq");
        self.vic_irq = true;
    }

    pub fn clear_vic_irq(&mut self)
    {
        // TODO
        self.vic_irq = false;
    }

    pub fn trigger_nmi(&mut self)
    {
        // TODO
        //println!("NMI irq");
        self.nmi = true;
    }

    pub fn clear_nmi(&mut self)
    {
        // TODO
        self.nmi = false;
    }

    pub fn trigger_cia_irq(&mut self)
    {
        // TODO
        //println!("CIA irq");
        self.cia_irq = true;
    }

    pub fn clear_cia_irq(&mut self)
    {
        // TODO
        self.cia_irq = false;
    }

    fn process_op(&mut self, opcode: u8) -> u8
    {
        //utils::debug_instruction(opcode, self);
        self.prev_PC = self.PC;
        match opcodes::get_instruction(opcode, self)
        {
            Some((instruction, num_cycles, addr_mode)) => {
                //utils::debug_instruction(opcode, Some((&instruction, num_cycles, &addr_mode)), self);
                instruction.run(&addr_mode, self);
                num_cycles
            },
            None => panic!("No instruction - this should never happen! (0x{:02X} at ${:04X})", opcode, self.PC)
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::{mpsc, Arc};
use std::fmt::Debug;
use std::io;
use std::sync::atomic::{AtomicUsize, Ordering};
use user_event::UserEvent;

#[cfg(any(target_os = "linux", target_os = "android"))]
use epoll::KernelRegistrar;

#[cfg(any(target_os = "bitrig", target_os = "dragonfly",
          target_os = "freebsd", target_os = "ios", target_os = "macos",
          target_os = "netbsd", target_os = "openbsd"))]
pub use kqueue::KernelRegistrar;

pub fn channel<T: Debug>(mut registrar: KernelRegistrar) -> io::Result<(Sender<T>, Receiver<T>)> {
    let (tx, rx) = mpsc::channel();
    let pending = Arc::new(AtomicUsize::new(0));
    let user_event = try!(registrar.register_user_event().map_err(|e| io::Error::from(e)));

    let tx = Sender {
        tx: tx,
        user_event: user_event.clone(),
        pending: pending.clone()
    };

    let rx = Receiver {
        rx: rx,
        user_event: user_event,
        pending: pending,
        registrar: registrar
    };

    Ok((tx, rx))
}

pub fn sync_channel<T: Debug>(mut registrar: KernelRegistrar,
                              bound: usize) -> io::Result<(SyncSender<T>, Receiver<T>)> {
    let (tx, rx) = mpsc::sync_channel(bound);
    let pending = Arc::new(AtomicUsize::new(0));
    let user_event = try!(registrar.register_user_event().map_err(|e| io::Error::from(e)));

    let tx = SyncSender {
        tx: tx,
        user_event: user_event.clone(),
        pending: pending.clone()
    };

    let rx = Receiver {
        rx: rx,
        user_event: user_event,
        pending: pending,
        registrar: registrar
    };

    Ok((tx, rx))
}

#[derive(Debug, Clone)]
pub struct Sender<T: Debug> {
    tx: mpsc::Sender<T>,
    user_event: UserEvent,
    pending: Arc<AtomicUsize>
}

impl<T: Debug> Sender<T> {
    pub fn send(&self, msg: T) -> Result<(), ChannelError<T>> {
        try!(self.tx.send(msg));
        if self.pending.fetch_add(1, Ordering::SeqCst) == 0 {
            // Notify the kernel poller that a read is ready
            try!(self.user_event.trigger());
        }
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub struct SyncSender<T: Debug> {
    tx: mpsc::SyncSender<T>,
    user_event: UserEvent,
    pending: Arc<AtomicUsize>
}

impl<T: Debug> SyncSender<T> {
    pub fn send(&self, msg: T) -> Result<(), ChannelError<T>> {
        try!(self.tx.send(msg));
        if self.pending.fetch_add(1, Ordering::SeqCst) == 0 {
            // Notify the kernel poller that a read is ready
            try!(self.user_event.trigger());
        }
        Ok(())
    }

    pub fn try_send(&self, msg: T) -> Result<(), ChannelError<T>> {
        try!(self.tx.try_send(msg));
        if self.pending.fetch_add(1, Ordering::SeqCst) == 0 {
            // Notify the kernel poller that a read is ready
            try!(self.user_event.trigger());
        }
        Ok(())
    }
}

pub struct Receiver<T: Debug> {
    rx: mpsc::Receiver<T>,
    user_event: UserEvent,
    pending: Arc<AtomicUsize>,
    registrar: KernelRegistrar
}

impl<T: Debug> Receiver<T> {
    pub fn try_recv(&self) -> Result<T, ChannelError<T>> {
        if self.pending.load(Ordering::SeqCst) == 0 {
            // Clear the kernel event and prepare for edge triggering
            try!(self.user_event.clear());

            // Try one last check to prevent a race condition where the sender puts a value on the
            // channel and writes the event after our pending.load check, but before we did the
            // read. If we just did a read this would result in a value remaining on the channel and
            // a poller that would never wake up.
            if self.pending.load(Ordering::SeqCst) == 0 {
                return Err(ChannelError::TryRecvError(mpsc::TryRecvError::Empty));
            }
            // We still have pending events, re-activate the user event so the poller will wakeup
            try!(self.user_event.trigger());
        }

        self.pending.fetch_sub(1, Ordering::SeqCst);
        self.rx.try_recv().map_err(|e| ChannelError::from(e))
    }

    pub fn get_id(&self) -> usize {
        self.user_event.id
    }
}

impl<T: Debug> Drop for Receiver<T> {
    fn drop(&mut self) {
        // Don't leak file descriptors. Note that the tx side will never get notified that the rx
        // side is gone, so senders can leak. However, any attempt to send from a sender will show
        // the receiver to be disconnected, so they can be cleaned up then, or ahead of time if it's
        // known that the channel is going away.
        let _ = self.registrar.deregister_user_event(self.user_event.clone());
    }
}

#[derive(Debug)]
pub enum ChannelError<T: Debug> {
    SendError(mpsc::SendError<T>),
    TrySendError(mpsc::TrySendError<T>),
    TryRecvError(mpsc::TryRecvError),
    Io(io::Error)
}

impl<T: Debug> From<io::Error> for ChannelError<T> {
    fn from(e: io::Error) -> ChannelError<T> {
        ChannelError::Io(e)
    }
}

impl<T: Debug> From<mpsc::SendError<T>> for ChannelError<T> {
    fn from(e: mpsc::SendError<T>) -> ChannelError<T> {
        ChannelError::SendError(e)
    }
}

impl<T: Debug> From<mpsc::TrySendError<T>> for ChannelError<T> {
    fn from(e: mpsc::TrySendError<T>) -> ChannelError<T> {
        ChannelError::TrySendError(e)
    }
}

impl<T: Debug> From<mpsc::TryRecvError> for ChannelError<T> {
    fn from(e: mpsc::TryRecvError) -> ChannelError<T> {
        ChannelError::TryRecvError(e)
    }
}

<commit_msg>Remove uneccessary Debug bounds from channel types<commit_after>use std::sync::{mpsc, Arc};
use std::io;
use std::sync::atomic::{AtomicUsize, Ordering};
use user_event::UserEvent;

#[cfg(any(target_os = "linux", target_os = "android"))]
use epoll::KernelRegistrar;

#[cfg(any(target_os = "bitrig", target_os = "dragonfly",
          target_os = "freebsd", target_os = "ios", target_os = "macos",
          target_os = "netbsd", target_os = "openbsd"))]
pub use kqueue::KernelRegistrar;

pub fn channel<T>(mut registrar: KernelRegistrar) -> io::Result<(Sender<T>, Receiver<T>)> {
    let (tx, rx) = mpsc::channel();
    let pending = Arc::new(AtomicUsize::new(0));
    let user_event = try!(registrar.register_user_event().map_err(|e| io::Error::from(e)));

    let tx = Sender {
        tx: tx,
        user_event: user_event.clone(),
        pending: pending.clone()
    };

    let rx = Receiver {
        rx: rx,
        user_event: user_event,
        pending: pending,
        registrar: registrar
    };

    Ok((tx, rx))
}

pub fn sync_channel<T>(mut registrar: KernelRegistrar,
                              bound: usize) -> io::Result<(SyncSender<T>, Receiver<T>)> {
    let (tx, rx) = mpsc::sync_channel(bound);
    let pending = Arc::new(AtomicUsize::new(0));
    let user_event = try!(registrar.register_user_event().map_err(|e| io::Error::from(e)));

    let tx = SyncSender {
        tx: tx,
        user_event: user_event.clone(),
        pending: pending.clone()
    };

    let rx = Receiver {
        rx: rx,
        user_event: user_event,
        pending: pending,
        registrar: registrar
    };

    Ok((tx, rx))
}

#[derive(Debug, Clone)]
pub struct Sender<T> {
    tx: mpsc::Sender<T>,
    user_event: UserEvent,
    pending: Arc<AtomicUsize>
}

impl<T> Sender<T> {
    pub fn send(&self, msg: T) -> Result<(), ChannelError<T>> {
        try!(self.tx.send(msg));
        if self.pending.fetch_add(1, Ordering::SeqCst) == 0 {
            // Notify the kernel poller that a read is ready
            try!(self.user_event.trigger());
        }
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub struct SyncSender<T> {
    tx: mpsc::SyncSender<T>,
    user_event: UserEvent,
    pending: Arc<AtomicUsize>
}

impl<T> SyncSender<T> {
    pub fn send(&self, msg: T) -> Result<(), ChannelError<T>> {
        try!(self.tx.send(msg));
        if self.pending.fetch_add(1, Ordering::SeqCst) == 0 {
            // Notify the kernel poller that a read is ready
            try!(self.user_event.trigger());
        }
        Ok(())
    }

    pub fn try_send(&self, msg: T) -> Result<(), ChannelError<T>> {
        try!(self.tx.try_send(msg));
        if self.pending.fetch_add(1, Ordering::SeqCst) == 0 {
            // Notify the kernel poller that a read is ready
            try!(self.user_event.trigger());
        }
        Ok(())
    }
}

pub struct Receiver<T> {
    rx: mpsc::Receiver<T>,
    user_event: UserEvent,
    pending: Arc<AtomicUsize>,
    registrar: KernelRegistrar
}

impl<T> Receiver<T> {
    pub fn try_recv(&self) -> Result<T, ChannelError<T>> {
        if self.pending.load(Ordering::SeqCst) == 0 {
            // Clear the kernel event and prepare for edge triggering
            try!(self.user_event.clear());

            // Try one last check to prevent a race condition where the sender puts a value on the
            // channel and writes the event after our pending.load check, but before we did the
            // read. If we just did a read this would result in a value remaining on the channel and
            // a poller that would never wake up.
            if self.pending.load(Ordering::SeqCst) == 0 {
                return Err(ChannelError::TryRecvError(mpsc::TryRecvError::Empty));
            }
            // We still have pending events, re-activate the user event so the poller will wakeup
            try!(self.user_event.trigger());
        }

        self.pending.fetch_sub(1, Ordering::SeqCst);
        self.rx.try_recv().map_err(|e| ChannelError::from(e))
    }

    pub fn get_id(&self) -> usize {
        self.user_event.id
    }
}

impl<T> Drop for Receiver<T> {
    fn drop(&mut self) {
        // Don't leak file descriptors. Note that the tx side will never get notified that the rx
        // side is gone, so senders can leak. However, any attempt to send from a sender will show
        // the receiver to be disconnected, so they can be cleaned up then, or ahead of time if it's
        // known that the channel is going away.
        let _ = self.registrar.deregister_user_event(self.user_event.clone());
    }
}

#[derive(Debug)]
pub enum ChannelError<T> {
    SendError(mpsc::SendError<T>),
    TrySendError(mpsc::TrySendError<T>),
    TryRecvError(mpsc::TryRecvError),
    Io(io::Error)
}

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

impl<T> From<mpsc::SendError<T>> for ChannelError<T> {
    fn from(e: mpsc::SendError<T>) -> ChannelError<T> {
        ChannelError::SendError(e)
    }
}

impl<T> From<mpsc::TrySendError<T>> for ChannelError<T> {
    fn from(e: mpsc::TrySendError<T>) -> ChannelError<T> {
        ChannelError::TrySendError(e)
    }
}

impl<T> From<mpsc::TryRecvError> for ChannelError<T> {
    fn from(e: mpsc::TryRecvError) -> ChannelError<T> {
        ChannelError::TryRecvError(e)
    }
}

<|endoftext|>


<commit_before>use std::sync::Arc;

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

use std::collections::{BTreeMap, VecDeque};

use pest::Parser;
use pest::iterators::Pair;
use grammar::{HandlebarsParser, Rule};
use error::RenderError;

pub type Object = BTreeMap<String, Json>;

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

#[inline]
fn parse_json_visitor_inner<'a>(
    path_stack: &mut VecDeque<&'a str>,
    path: &'a str,
) -> Result<(), RenderError> {
    let parsed_path = HandlebarsParser::parse(Rule::path, path)
        .map(|p| p.flatten())
        .map_err(|_| RenderError::new("Invalid JSON path"))?;

    let mut seg_stack: VecDeque<Pair<Rule>> = VecDeque::new();
    for seg in parsed_path {
        if seg.as_str() == "@root" {
            seg_stack.clear();
            path_stack.clear();
            continue;
        }

        match seg.as_rule() {
            Rule::path_up => {
                path_stack.pop_back();
                if let Some(p) = seg_stack.pop_back() {
                    // also pop array index like [1]
                    if p.as_rule() == Rule::path_raw_id {
                        seg_stack.pop_back();
                    }
                }
            }
            Rule::path_id | Rule::path_raw_id => {
                seg_stack.push_back(seg);
            }
            _ => {}
        }
    }

    for i in seg_stack.into_iter() {
        let span = i.into_span();
        path_stack.push_back(&path[span.start()..span.end()]);
    }
    Ok(())
}

#[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 mut parser = HandlebarsParser::parse(Rule::path, relative_path)
        .map(|p| p.flatten())
        .map_err(|_| RenderError::new("Invalid JSON path."))?;

    let mut path_context_depth: i64 = -1;

    loop {
        if let Some(sg) = parser.next() {
            if sg.as_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(())
}

pub 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: Arc::new(Json::Null),
        }
    }

    /// Create a context with given data
    pub fn wraps<T: Serialize>(e: &T) -> Result<Context, RenderError> {
        to_value(e)
            .map_err(RenderError::from)
            .map(|d| Context { data: Arc::new(d) })
    }

    /// 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<Option<&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: Option<&Json> = Some(self.data.as_ref());
        for p in paths.iter() {
            if *p == "this" {
                continue;
            }
            data = match data {
                Some(&Json::Array(ref l)) => p.parse::<usize>()
                    .map_err(|e| RenderError::with(e))
                    .map(|idx_u| l.get(idx_u))?,
                Some(&Json::Object(ref m)) => m.get(*p),
                Some(_) => None,
                None => break,
            }
        }
        Ok(data)
    }

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

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

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

    #[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()).unwrap();
        assert_eq!(
            ctx.navigate(".", &VecDeque::new(), "this")
                .unwrap()
                .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).unwrap();
        assert_eq!(
            ctx.navigate(".", &VecDeque::new(), "./name/../addr/country")
                .unwrap()
                .unwrap()
                .render(),
            "China".to_string()
        );
        assert_eq!(
            ctx.navigate(".", &VecDeque::new(), "addr.[country]")
                .unwrap()
                .unwrap()
                .render(),
            "China".to_string()
        );

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

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

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

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

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

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

    #[test]
    fn test_merge_json() {
        let map = json!({ "age": 4 });
        let s = "hello".to_owned();
        let hash = btreemap!{
            "tag".to_owned() => value::to_json(&"h1")
        };

        let ctx_a1 = Context::wraps(&context::merge_json(&map, &hash)).unwrap();
        assert_eq!(
            ctx_a1
                .navigate(".", &VecDeque::new(), "age")
                .unwrap()
                .unwrap()
                .render(),
            "4".to_owned()
        );
        assert_eq!(
            ctx_a1
                .navigate(".", &VecDeque::new(), "tag")
                .unwrap()
                .unwrap()
                .render(),
            "h1".to_owned()
        );

        let ctx_a2 = Context::wraps(&context::merge_json(&value::to_json(&s), &hash)).unwrap();
        assert_eq!(
            ctx_a2
                .navigate(".", &VecDeque::new(), "this")
                .unwrap()
                .unwrap()
                .render(),
            "[object]".to_owned()
        );
        assert_eq!(
            ctx_a2
                .navigate(".", &VecDeque::new(), "tag")
                .unwrap()
                .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).unwrap();
        assert_eq!(
            ctx.navigate(".", &VecDeque::new(), "this_name")
                .unwrap()
                .unwrap()
                .render(),
            "the_value".to_string()
        );
    }

    use serde::{Serialize, Serializer};
    use serde::ser::Error as SerdeError;

    struct UnserializableType {}

    impl Serialize for UnserializableType {
        fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            Err(SerdeError::custom("test"))
        }
    }

    #[test]
    fn test_serialize_error() {
        let d = UnserializableType {};
        assert!(Context::wraps(&d).is_err());
    }

    #[test]
    fn test_root() {
        let m = json!({
            "a" : {
                "b" : {
                    "c" : {
                        "d" : 1
                    }
                }
            },
            "b": 2
        });
        let ctx = Context::wraps(&m).unwrap();
        assert_eq!(
            ctx.navigate("a/b", &VecDeque::new(), "@root/b")
                .unwrap()
                .unwrap()
                .render(),
            "2".to_string()
        );
    }
}
<commit_msg>(feat) remove unneeded arc<commit_after>use serde::Serialize;
use serde_json::value::{to_value, Map, Value as Json};

use std::collections::{BTreeMap, VecDeque};

use pest::Parser;
use pest::iterators::Pair;
use grammar::{HandlebarsParser, Rule};
use error::RenderError;

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 parsed_path = HandlebarsParser::parse(Rule::path, path)
        .map(|p| p.flatten())
        .map_err(|_| RenderError::new("Invalid JSON path"))?;

    let mut seg_stack: VecDeque<Pair<Rule>> = VecDeque::new();
    for seg in parsed_path {
        if seg.as_str() == "@root" {
            seg_stack.clear();
            path_stack.clear();
            continue;
        }

        match seg.as_rule() {
            Rule::path_up => {
                path_stack.pop_back();
                if let Some(p) = seg_stack.pop_back() {
                    // also pop array index like [1]
                    if p.as_rule() == Rule::path_raw_id {
                        seg_stack.pop_back();
                    }
                }
            }
            Rule::path_id | Rule::path_raw_id => {
                seg_stack.push_back(seg);
            }
            _ => {}
        }
    }

    for i in seg_stack.into_iter() {
        let span = i.into_span();
        path_stack.push_back(&path[span.start()..span.end()]);
    }
    Ok(())
}

#[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 mut parser = HandlebarsParser::parse(Rule::path, relative_path)
        .map(|p| p.flatten())
        .map_err(|_| RenderError::new("Invalid JSON path."))?;

    let mut path_context_depth: i64 = -1;

    loop {
        if let Some(sg) = parser.next() {
            if sg.as_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(())
}

pub 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) -> Result<Context, RenderError> {
        to_value(e)
            .map_err(RenderError::from)
            .map(|d| Context { data: d })
    }

    /// 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<Option<&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: Option<&Json> = Some(&self.data);
        for p in paths.iter() {
            if *p == "this" {
                continue;
            }
            data = match data {
                Some(&Json::Array(ref l)) => p.parse::<usize>()
                    .map_err(|e| RenderError::with(e))
                    .map(|idx_u| l.get(idx_u))?,
                Some(&Json::Object(ref m)) => m.get(*p),
                Some(_) => None,
                None => break,
            }
        }
        Ok(data)
    }

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

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

    #[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()).unwrap();
        assert_eq!(
            ctx.navigate(".", &VecDeque::new(), "this")
                .unwrap()
                .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).unwrap();
        assert_eq!(
            ctx.navigate(".", &VecDeque::new(), "./name/../addr/country")
                .unwrap()
                .unwrap()
                .render(),
            "China".to_string()
        );
        assert_eq!(
            ctx.navigate(".", &VecDeque::new(), "addr.[country]")
                .unwrap()
                .unwrap()
                .render(),
            "China".to_string()
        );

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

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

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

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

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

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

    #[test]
    fn test_merge_json() {
        let map = json!({ "age": 4 });
        let s = "hello".to_owned();
        let hash = btreemap!{
            "tag".to_owned() => value::to_json(&"h1")
        };

        let ctx_a1 = Context::wraps(&context::merge_json(&map, &hash)).unwrap();
        assert_eq!(
            ctx_a1
                .navigate(".", &VecDeque::new(), "age")
                .unwrap()
                .unwrap()
                .render(),
            "4".to_owned()
        );
        assert_eq!(
            ctx_a1
                .navigate(".", &VecDeque::new(), "tag")
                .unwrap()
                .unwrap()
                .render(),
            "h1".to_owned()
        );

        let ctx_a2 = Context::wraps(&context::merge_json(&value::to_json(&s), &hash)).unwrap();
        assert_eq!(
            ctx_a2
                .navigate(".", &VecDeque::new(), "this")
                .unwrap()
                .unwrap()
                .render(),
            "[object]".to_owned()
        );
        assert_eq!(
            ctx_a2
                .navigate(".", &VecDeque::new(), "tag")
                .unwrap()
                .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).unwrap();
        assert_eq!(
            ctx.navigate(".", &VecDeque::new(), "this_name")
                .unwrap()
                .unwrap()
                .render(),
            "the_value".to_string()
        );
    }

    use serde::{Serialize, Serializer};
    use serde::ser::Error as SerdeError;

    struct UnserializableType {}

    impl Serialize for UnserializableType {
        fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            Err(SerdeError::custom("test"))
        }
    }

    #[test]
    fn test_serialize_error() {
        let d = UnserializableType {};
        assert!(Context::wraps(&d).is_err());
    }

    #[test]
    fn test_root() {
        let m = json!({
            "a" : {
                "b" : {
                    "c" : {
                        "d" : 1
                    }
                }
            },
            "b": 2
        });
        let ctx = Context::wraps(&m).unwrap();
        assert_eq!(
            ctx.navigate("a/b", &VecDeque::new(), "@root/b")
                .unwrap()
                .unwrap()
                .render(),
            "2".to_string()
        );
    }
}
<|endoftext|>


<commit_before>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::File;
use std::path::posix::Path;
use editor;
use root;

#[cfg(test)] use std::finally::Finally;
#[cfg(test)] use test_helper::{random_name,cleanup_file};

static TEMPLATE: &'static str = include_str!("creator/template.toml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = match root::muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        true  => Path::new(format!("{}/.{}/", root::homedir_string(), &DEFAULT_MUXED_DIR.to_string())),
        false => root::create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}.toml", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path);

        match editor::default_editor_set() {
            true  => editor::open_project_file(path),
            false => println!("Default editor is not set. Please define $EDITOR in your ~/.bashrc or similar file.")
        }
    } else {
        println!("Project already exists.");
    }
}

/// Copy and create the new project file from a template.
fn create_project_file(path: &Path) {
    let filename = path.filename().unwrap().to_string();
    match File::create(path).write(modified_template(TEMPLATE, filename.as_slice()).as_bytes()) {
        Ok(())  => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }
}

fn modified_template(template: &str, project_name: &str) -> String {
    template.replace("{file_name}", project_name)
}

#[test]
fn populates_template_values() {
    let value = modified_template(TEMPLATE, "muxed project");
    let result = value.as_slice().contains("muxed project");
    assert!(result);
}

#[test]
fn replaces_template_values() {
    let value = modified_template(TEMPLATE, "muxed project");
    let result = !value.as_slice().contains("{file_name}");
    assert!(result);
}

#[test]
fn creates_project_file() {
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), random_name()));
    create_project_file(path);
    assert!(path.exists());

    cleanup_file(path);
}

#[test]
fn errors_when_creating_project_file() {
    //assert!(false);
}

#[test]
fn create_copies_the_template_file() {
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), random_name()));
    let filename = path.filename().unwrap().to_string();
    create_project_file(path);
    let data = File::open(path).read_to_end().unwrap();
    let template_expectation = modified_template(TEMPLATE, filename.as_slice());
    assert_eq!(data.as_slice(), template_expectation.as_bytes());

    cleanup_file(path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());

    cleanup_file(path);
}
<commit_msg>Make a function to handle finding the project name from the path.<commit_after>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::File;
use std::path::posix::Path;
use editor;
use root;

#[cfg(test)] use std::finally::Finally;
#[cfg(test)] use test_helper::{random_name,cleanup_file};

static TEMPLATE: &'static str = include_str!("creator/template.toml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = match root::muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        true  => Path::new(format!("{}/.{}/", root::homedir_string(), &DEFAULT_MUXED_DIR.to_string())),
        false => root::create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}.toml", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path);

        match editor::default_editor_set() {
            true  => editor::open_project_file(path),
            false => println!("Default editor is not set. Please define $EDITOR in your ~/.bashrc or similar file.")
        }
    } else {
        println!("Project already exists.");
    }
}

/// Copy and create the new project file from a template.
fn create_project_file(path: &Path) {
    let filename = project_filename(path);
    match File::create(path).write(modified_template(TEMPLATE, filename.as_slice()).as_bytes()) {
        Ok(())  => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }
}

fn modified_template(template: &str, project_name: &str) -> String {
    template.replace("{file_name}", project_name)
}

fn project_filename(path: &Path) -> String {
    String::from_utf8(path.filename().unwrap().to_vec()).unwrap().replace(".toml", "")
}

#[test]
fn populates_template_values() {
    let value = modified_template(TEMPLATE, "muxed project");
    let result = value.as_slice().contains("muxed project");
    assert!(result);
}

#[test]
fn replaces_template_values() {
    let value = modified_template(TEMPLATE, "muxed project");
    let result = !value.as_slice().contains("{file_name}");
    assert!(result);
}

#[test]
fn creates_project_file() {
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), random_name()));
    create_project_file(path);
    assert!(path.exists());

    cleanup_file(path);
}

#[test]
fn errors_when_creating_project_file() {
    //assert!(false);
}

#[test]
fn create_copies_the_template_file() {
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), random_name()));
    let filename = project_filename(path);
    create_project_file(path);
    let data = File::open(path).read_to_end().unwrap();
    let template_expectation = modified_template(TEMPLATE, filename.as_slice());
    assert_eq!(data.as_slice(), template_expectation.as_bytes());

    cleanup_file(path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}.toml", root::homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());

    cleanup_file(path);
}
<|endoftext|>


<commit_before>use super::scope::{CowScope};
use super::CompileError;
use super::parser::{Parser, TokenStream};
use super::expr::Expression;
use super::function::Function;
use super::lexer::{Token, Symbol};
use super::identifier::{Identifier, IdMap};
use std::collections::VecMap;
use std::borrow::Cow;

/// Represents a function call written in synthizer
#[derive(Debug, Clone)]
pub struct FunctionCall {
	pub func: Identifier, // the function the call refers to as a scope id
	args: VecMap<Expression>,
}
impl<'a> Parser<'a> for FunctionCall {
	/// Parse a function call from a token stream. Scope is used to find function definitions
	fn parse(tokens: TokenStream<'a>, scope: CowScope<'a>) -> Result<FunctionCall, CompileError> {
		let mut tokens = tokens;
		let mut args = VecMap::new();

		// Opening bracket
		try!(expect!(tokens.next(), Token::Symbol(Symbol::LeftBracket), "expected `[`, got `{}`"));

		// Function name
		let fn_ident = try!(expect_value!(tokens.next(),
			Token::Ident, "expected function name, got `{}`"));

		// Parse arguments
		'outer: loop {
			let token = tokens.next();
			if let Ok(_) = expect!(token, Token::Symbol(Symbol::RightBracket)) {
				// Got closing paren, end of list
				break;
			} else {
				// Argument name
				let arg_ident = try!(expect_value!(token, Token::Ident, "expected `]` or argument name, got `{}`"));

				// Equals
				try!(expect!(tokens.next(), Token::Symbol(Symbol::Equals), "expected `=`, got `{}`"));

				// Mark the position of the start of the expression so we can later extract a slice
				let expr_start = tokens.pos();

				loop {
					let token = tokens.next();

					// Adds all the tokens we have scanned so far in the inner loop to the args
					// list
					let mut write_arg = || -> Result<(), CompileError> {
						let slice = tokens.slice(expr_start, tokens.pos() - 1);
						let expr = try!(Parser::parse(slice, scope.clone()));
						match args.get(&arg_ident) {
							Some(_) => {
								return Err(CompileError::new(format!("argument {} has already been defined", arg_ident)));
							}
							None => {
								args.insert(arg_ident, expr);
							}
						}
						Ok(())
					};

					match token.map(|x| x.token) {
						// Advance to next argument
						Some(Token::Symbol(Symbol::Comma)) => {
							try!(write_arg());
							break;
						}

						// End of function call
						Some(Token::Symbol(Symbol::RightBracket)) => {
							try!(write_arg());
							break 'outer;
						}

						// We need to handle nested parens so we can include parens in the argument
						// expressions
						Some(Token::Symbol(Symbol::LeftBracket)) => {
							//TODO borrowing issues with the closure above, need to rewrite it out.
							//tokens = try!(parser::match_paren(tokens, Token::Symbol(Symbol::LeftBracket), Token::Symbol(Symbol::RightBracket)));
						}

						None => {
							return Err(CompileError::new_static("Expected expression, got EOF"));
						}

						_ => { }
					}
				}
			}
		}

		Ok(FunctionCall {
			func: fn_ident,
			args: args,
		})
	}
}

impl Function for FunctionCall {
	fn call(&self, scope: CowScope, idmap: &IdMap) -> Result<f32, CompileError> {
		let mut inner = scope.clone().into_owned();
		match scope.get_func(self.func) {
			Some(f) => {
				for (n, a) in self.args.iter() {
					inner.set_var(n, try!(a.call(scope.clone(), idmap)));
				}
				f.call(Cow::Owned(inner), idmap)
			}
			None => panic!("internal error: function id is invalid!"),
		}
	}
}
<commit_msg>Add an nice interface to function calls<commit_after>use super::scope::{CowScope};
use super::CompileError;
use super::parser::{Parser, TokenStream};
use super::expr::Expression;
use super::function::Function;
use super::lexer::{Token, Symbol};
use super::identifier::{Identifier, IdMap};
use std::collections::VecMap;
use std::borrow::Cow;

/// Represents a function call written in synthizer
#[derive(Debug, Clone)]
pub struct FunctionCall {
	func: Option<Identifier>, // the function the call refers to as a scope id
	args: VecMap<Expression>,
}

impl FunctionCall {
    pub fn new() -> FunctionCall {
        FunctionCall {
            func: None,
            args: VecMap::new(),
        }
    }

    pub fn set_func(&mut self, ident: Identifier) {
        self.func = Some(ident);
    }

    pub fn func(&self) -> Identifier {
        self.func.expect("this function call is not complete! (no function was attached)")
    }

    /// If the argument is already defined, returns the expression it is set to.
    pub fn add_arg(&mut self, ident: Identifier, expr: Expression) -> Option<Expression> {
        self.args.insert(ident, expr)
    }

    pub fn arg(&mut self, ident: Identifier) -> Option<&mut Expression> {
        self.args.get_mut(&ident)
    }
}

impl<'a> Parser<'a> for FunctionCall {
	/// Parse a function call from a token stream. Scope is used to find function definitions
	fn parse(tokens: TokenStream<'a>, scope: CowScope<'a>) -> Result<FunctionCall, CompileError> {
		let mut tokens = tokens;
        let mut call = FunctionCall::new();

		// Opening bracket
		try!(expect!(tokens.next(), Token::Symbol(Symbol::LeftBracket), "expected `[`, got `{}`"));

		// Function name
		call.set_func(try!(expect_value!(tokens.next(),
			Token::Ident, "expected function name, got `{}`")));

		// Parse arguments
		'outer: loop {
			let token = tokens.next();
			if let Ok(_) = expect!(token, Token::Symbol(Symbol::RightBracket)) {
				// Got closing paren, end of list
				break;
			} else {
				// Argument name
				let arg_ident = try!(expect_value!(token, Token::Ident, "expected `]` or argument name, got `{}`"));

				// Equals
				try!(expect!(tokens.next(), Token::Symbol(Symbol::Equals), "expected `=`, got `{}`"));

				// Mark the position of the start of the expression so we can later extract a slice
				let expr_start = tokens.pos();

				loop {
					let token = tokens.next();

					// Adds all the tokens we have scanned so far in the inner loop to the args
					// list
					let mut write_arg = || -> Result<(), CompileError> {
						let slice = tokens.slice(expr_start, tokens.pos() - 1);
						let expr = try!(Parser::parse(slice, scope.clone()));
						match call.add_arg(arg_ident, expr) {
							Some(x) => {
								return Err(CompileError::new(format!("argument {} has already been defined as {:?}", arg_ident, x)));
							}
							None => { }
						}
						Ok(())
					};

					match token.map(|x| x.token) {
						// Advance to next argument
						Some(Token::Symbol(Symbol::Comma)) => {
							try!(write_arg());
							break;
						}

						// End of function call
						Some(Token::Symbol(Symbol::RightBracket)) => {
							try!(write_arg());
							break 'outer;
						}

						// We need to handle nested parens so we can include parens in the argument
						// expressions
						Some(Token::Symbol(Symbol::LeftBracket)) => {
							//TODO borrowing issues with the closure above, need to rewrite it out.
							//tokens = try!(parser::match_paren(tokens, Token::Symbol(Symbol::LeftBracket), Token::Symbol(Symbol::RightBracket)));
						}

						None => {
							return Err(CompileError::new_static("Expected expression, got EOF"));
						}

						_ => { }
					}
				}
			}
		}

		Ok(call)
	}
}

impl Function for FunctionCall {
	fn call(&self, scope: CowScope, idmap: &IdMap) -> Result<f32, CompileError> {
		let mut inner = scope.clone().into_owned();
		match scope.get_func(self.func()) {
			Some(f) => {
				for (n, a) in self.args.iter() {
					inner.set_var(n, try!(a.call(scope.clone(), idmap)));
				}
				f.call(Cow::Owned(inner), idmap)
			}
			None => panic!("internal error: function id is invalid!"),
		}
	}
}
<|endoftext|>


<commit_before>/*!
Functionality for declaring Objective-C classes.

Classes can be declared using the `ClassDecl` struct. Instance variables and
methods can then be added before the class is ultimately registered.

# Example

The following example demonstrates declaring a class named `MyNumber` that has
one ivar, a `u32` named `_number` and a `number` method that returns it:

```
# #[macro_use] extern crate objc;
# use objc::declare::ClassDecl;
# use objc::runtime::{Class, Object, Sel};
# fn main() {
let superclass = Class::get("NSObject").unwrap();
let mut decl = ClassDecl::new(superclass, "MyNumber").unwrap();

// Add an instance variable
decl.add_ivar::<u32>("_number");

// Add an ObjC method for getting the number
extern fn my_number_get(this: &Object, _cmd: Sel) -> u32 {
    unsafe { *this.get_ivar("_number") }
}
unsafe {
    decl.add_method(sel!(number),
        my_number_get as extern fn(&Object, Sel) -> u32);
}

decl.register();
# }
```
*/

use std::ffi::CString;
use std::fmt;
use std::mem;
use libc::size_t;

use {Encode, Encoding, Message};
use runtime::{Class, Imp, NO, Object, Sel, self};

/// An error returned from `IntoMethodImp::into_imp` to indicate that a
/// selector and function accept unequal numbers of arguments.
#[derive(Clone, PartialEq, Debug)]
pub struct UnequalArgsError {
    sel_args: usize,
    fn_args: usize,
}

impl fmt::Display for UnequalArgsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Selector accepts {} arguments, but function accepts {}",
            self.sel_args, self.fn_args)
    }
}

/// Types that can be used as the implementation of an Objective-C method.
pub trait IntoMethodImp {
    /// The callee type of the method.
    type Callee: Message;
    /// The return type of the method.
    type Ret: Encode;

    /// Returns the type encodings of Self's arguments.
    fn argument_encodings() -> Box<[Encoding]>;

    /// Consumes self to create a method implementation for the given selector.
    ///
    /// Returns an error if self and the selector do not accept the same number
    /// of arguments.
    fn into_imp(self, sel: Sel) -> Result<Imp, UnequalArgsError>;
}

macro_rules! count_idents {
    () => (0);
    ($a:ident) => (1);
    ($a:ident, $($b:ident),+) => (1 + count_idents!($($b),*));
}

macro_rules! method_decl_impl {
    (-$s:ident, $sp:ty, $($t:ident),*) => (
        impl<$s, R $(, $t)*> IntoMethodImp for extern fn($sp, Sel $(, $t)*) -> R
                where $s: Message, R: Encode $(, $t: Encode)* {
            type Callee = $s;
            type Ret = R;

            fn argument_encodings() -> Box<[Encoding]> {
                Box::new([
                    <*mut Object>::encode(),
                    Sel::encode(),
                    $($t::encode()),*
                ])
            }

            fn into_imp(self, sel: Sel) -> Result<Imp, UnequalArgsError> {
                // Add 2 to the arguments for self and _cmd
                let fn_args = 2 + count_idents!($($t),*);
                let sel_args = 2 + sel.name().chars().filter(|&c| c == ':').count();
                if sel_args == fn_args {
                    unsafe { Ok(mem::transmute(self)) }
                } else {
                    Err(UnequalArgsError { sel_args: sel_args, fn_args: fn_args })
                }
            }
        }
    );
    ($($t:ident),*) => (
        method_decl_impl!(-T, &T, $($t),*);
        method_decl_impl!(-T, &mut T, $($t),*);
    );
}

method_decl_impl!();
method_decl_impl!(A);
method_decl_impl!(A, B);
method_decl_impl!(A, B, C);
method_decl_impl!(A, B, C, D);
method_decl_impl!(A, B, C, D, E);
method_decl_impl!(A, B, C, D, E, F);
method_decl_impl!(A, B, C, D, E, F, G);
method_decl_impl!(A, B, C, D, E, F, G, H);
method_decl_impl!(A, B, C, D, E, F, G, H, I);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J, K);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J, K, L);

fn method_type_encoding<F>() -> CString where F: IntoMethodImp {
    let mut types = F::Ret::encode().as_str().to_string();
    types.extend(F::argument_encodings().iter().map(|e| e.as_str()));
    CString::new(types).unwrap()
}

/// A type for declaring a new class and adding new methods and ivars to it
/// before registering it.
pub struct ClassDecl {
    cls: *mut Class,
}

impl ClassDecl {
    /// Constructs a `ClassDecl` with the given superclass and name.
    /// Returns `None` if the class couldn't be allocated.
    pub fn new(superclass: &Class, name: &str) -> Option<ClassDecl> {
        let name = CString::new(name).unwrap();
        let cls = unsafe {
            runtime::objc_allocateClassPair(superclass, name.as_ptr(), 0)
        };
        if cls.is_null() {
            None
        } else {
            Some(ClassDecl { cls: cls })
        }
    }

    /// Adds a method with the given name and implementation to self.
    /// Panics if the method wasn't sucessfully added
    /// or if the selector and function take different numbers of arguments.
    /// Unsafe because the caller must ensure that the types match those that
    /// are expected when the method is invoked from Objective-C.
    pub unsafe fn add_method<F>(&mut self, sel: Sel, func: F)
            where F: IntoMethodImp<Callee=Object> {
        let types = method_type_encoding::<F>();
        let imp = match func.into_imp(sel) {
            Ok(imp) => imp,
            Err(err) => panic!("{}", err),
        };

        let success = runtime::class_addMethod(self.cls, sel, imp,
            types.as_ptr());
        assert!(success != NO, "Failed to add method {:?}", sel);
    }

    /// Adds a class method with the given name and implementation to self.
    /// Panics if the method wasn't sucessfully added
    /// or if the selector and function take different numbers of arguments.
    /// Unsafe because the caller must ensure that the types match those that
    /// are expected when the method is invoked from Objective-C.
    pub unsafe fn add_class_method<F>(&mut self, sel: Sel, func: F)
            where F: IntoMethodImp<Callee=Class> {
        let types = method_type_encoding::<F>();
        let imp = match func.into_imp(sel) {
            Ok(imp) => imp,
            Err(err) => panic!("{}", err),
        };

        let cls_obj = self.cls as *const Object;
        let metaclass = runtime::object_getClass(cls_obj) as *mut Class;
        let success = runtime::class_addMethod(metaclass, sel, imp,
            types.as_ptr());
        assert!(success != NO, "Failed to add class method {:?}", sel);
    }

    /// Adds an ivar with type `T` and the provided name to self.
    /// Panics if the ivar wasn't successfully added.
    pub fn add_ivar<T>(&mut self, name: &str) where T: Encode {
        let c_name = CString::new(name).unwrap();
        let encoding = CString::new(T::encode().as_str()).unwrap();
        let size = mem::size_of::<T>() as size_t;
        let align = mem::align_of::<T>() as u8;
        let success = unsafe {
            runtime::class_addIvar(self.cls, c_name.as_ptr(), size, align,
                encoding.as_ptr())
        };
        assert!(success != NO, "Failed to add ivar {}", name);
    }

    /// Registers self, consuming it and returning a reference to the
    /// newly registered `Class`.
    pub fn register(self) -> &'static Class {
        unsafe {
            let cls = self.cls;
            runtime::objc_registerClassPair(cls);
            // Forget self otherwise the class will be disposed in drop
            mem::forget(self);
            &*cls
        }
    }
}

impl Drop for ClassDecl {
    fn drop(&mut self) {
        unsafe {
            runtime::objc_disposeClassPair(self.cls);
        }
    }
}

#[cfg(test)]
mod tests {
    use runtime::{Object, Sel};
    use test_utils;
    use super::IntoMethodImp;

    #[test]
    fn test_custom_class() {
        // Registering the custom class is in test_utils
        let obj = test_utils::custom_object();
        unsafe {
            let _: () = msg_send![obj, setFoo:13u32];
            let result: u32 = msg_send![obj, foo];
            assert!(result == 13);
        }
    }

    #[test]
    fn test_class_method() {
        let cls = test_utils::custom_class();
        unsafe {
            let result: u32 = msg_send![cls, classFoo];
            assert!(result == 7);
        }
    }

    #[test]
    fn test_mismatched_args() {
        extern fn wrong_num_args_method(_obj: &Object, _cmd: Sel, _a: i32) { }

        let sel = sel!(doSomethingWithFoo:bar:);
        let f: extern fn(&Object, Sel, i32) = wrong_num_args_method;
        let imp = f.into_imp(sel);
        assert!(imp.is_err());
    }
}
<commit_msg>Implement Error for UnequalArgsError.<commit_after>/*!
Functionality for declaring Objective-C classes.

Classes can be declared using the `ClassDecl` struct. Instance variables and
methods can then be added before the class is ultimately registered.

# Example

The following example demonstrates declaring a class named `MyNumber` that has
one ivar, a `u32` named `_number` and a `number` method that returns it:

```
# #[macro_use] extern crate objc;
# use objc::declare::ClassDecl;
# use objc::runtime::{Class, Object, Sel};
# fn main() {
let superclass = Class::get("NSObject").unwrap();
let mut decl = ClassDecl::new(superclass, "MyNumber").unwrap();

// Add an instance variable
decl.add_ivar::<u32>("_number");

// Add an ObjC method for getting the number
extern fn my_number_get(this: &Object, _cmd: Sel) -> u32 {
    unsafe { *this.get_ivar("_number") }
}
unsafe {
    decl.add_method(sel!(number),
        my_number_get as extern fn(&Object, Sel) -> u32);
}

decl.register();
# }
```
*/

use std::error::Error;
use std::ffi::CString;
use std::fmt;
use std::mem;
use libc::size_t;

use {Encode, Encoding, Message};
use runtime::{Class, Imp, NO, Object, Sel, self};

/// An error returned from `IntoMethodImp::into_imp` to indicate that a
/// selector and function accept unequal numbers of arguments.
#[derive(Clone, PartialEq, Debug)]
pub struct UnequalArgsError {
    sel_args: usize,
    fn_args: usize,
}

impl fmt::Display for UnequalArgsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Selector accepts {} arguments, but function accepts {}",
            self.sel_args, self.fn_args)
    }
}

impl Error for UnequalArgsError {
    fn description(&self) -> &str {
        "Selector and function accept unequal numbers of arguments"
    }
}

/// Types that can be used as the implementation of an Objective-C method.
pub trait IntoMethodImp {
    /// The callee type of the method.
    type Callee: Message;
    /// The return type of the method.
    type Ret: Encode;

    /// Returns the type encodings of Self's arguments.
    fn argument_encodings() -> Box<[Encoding]>;

    /// Consumes self to create a method implementation for the given selector.
    ///
    /// Returns an error if self and the selector do not accept the same number
    /// of arguments.
    fn into_imp(self, sel: Sel) -> Result<Imp, UnequalArgsError>;
}

macro_rules! count_idents {
    () => (0);
    ($a:ident) => (1);
    ($a:ident, $($b:ident),+) => (1 + count_idents!($($b),*));
}

macro_rules! method_decl_impl {
    (-$s:ident, $sp:ty, $($t:ident),*) => (
        impl<$s, R $(, $t)*> IntoMethodImp for extern fn($sp, Sel $(, $t)*) -> R
                where $s: Message, R: Encode $(, $t: Encode)* {
            type Callee = $s;
            type Ret = R;

            fn argument_encodings() -> Box<[Encoding]> {
                Box::new([
                    <*mut Object>::encode(),
                    Sel::encode(),
                    $($t::encode()),*
                ])
            }

            fn into_imp(self, sel: Sel) -> Result<Imp, UnequalArgsError> {
                // Add 2 to the arguments for self and _cmd
                let fn_args = 2 + count_idents!($($t),*);
                let sel_args = 2 + sel.name().chars().filter(|&c| c == ':').count();
                if sel_args == fn_args {
                    unsafe { Ok(mem::transmute(self)) }
                } else {
                    Err(UnequalArgsError { sel_args: sel_args, fn_args: fn_args })
                }
            }
        }
    );
    ($($t:ident),*) => (
        method_decl_impl!(-T, &T, $($t),*);
        method_decl_impl!(-T, &mut T, $($t),*);
    );
}

method_decl_impl!();
method_decl_impl!(A);
method_decl_impl!(A, B);
method_decl_impl!(A, B, C);
method_decl_impl!(A, B, C, D);
method_decl_impl!(A, B, C, D, E);
method_decl_impl!(A, B, C, D, E, F);
method_decl_impl!(A, B, C, D, E, F, G);
method_decl_impl!(A, B, C, D, E, F, G, H);
method_decl_impl!(A, B, C, D, E, F, G, H, I);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J, K);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J, K, L);

fn method_type_encoding<F>() -> CString where F: IntoMethodImp {
    let mut types = F::Ret::encode().as_str().to_string();
    types.extend(F::argument_encodings().iter().map(|e| e.as_str()));
    CString::new(types).unwrap()
}

/// A type for declaring a new class and adding new methods and ivars to it
/// before registering it.
pub struct ClassDecl {
    cls: *mut Class,
}

impl ClassDecl {
    /// Constructs a `ClassDecl` with the given superclass and name.
    /// Returns `None` if the class couldn't be allocated.
    pub fn new(superclass: &Class, name: &str) -> Option<ClassDecl> {
        let name = CString::new(name).unwrap();
        let cls = unsafe {
            runtime::objc_allocateClassPair(superclass, name.as_ptr(), 0)
        };
        if cls.is_null() {
            None
        } else {
            Some(ClassDecl { cls: cls })
        }
    }

    /// Adds a method with the given name and implementation to self.
    /// Panics if the method wasn't sucessfully added
    /// or if the selector and function take different numbers of arguments.
    /// Unsafe because the caller must ensure that the types match those that
    /// are expected when the method is invoked from Objective-C.
    pub unsafe fn add_method<F>(&mut self, sel: Sel, func: F)
            where F: IntoMethodImp<Callee=Object> {
        let types = method_type_encoding::<F>();
        let imp = match func.into_imp(sel) {
            Ok(imp) => imp,
            Err(err) => panic!("{}", err),
        };

        let success = runtime::class_addMethod(self.cls, sel, imp,
            types.as_ptr());
        assert!(success != NO, "Failed to add method {:?}", sel);
    }

    /// Adds a class method with the given name and implementation to self.
    /// Panics if the method wasn't sucessfully added
    /// or if the selector and function take different numbers of arguments.
    /// Unsafe because the caller must ensure that the types match those that
    /// are expected when the method is invoked from Objective-C.
    pub unsafe fn add_class_method<F>(&mut self, sel: Sel, func: F)
            where F: IntoMethodImp<Callee=Class> {
        let types = method_type_encoding::<F>();
        let imp = match func.into_imp(sel) {
            Ok(imp) => imp,
            Err(err) => panic!("{}", err),
        };

        let cls_obj = self.cls as *const Object;
        let metaclass = runtime::object_getClass(cls_obj) as *mut Class;
        let success = runtime::class_addMethod(metaclass, sel, imp,
            types.as_ptr());
        assert!(success != NO, "Failed to add class method {:?}", sel);
    }

    /// Adds an ivar with type `T` and the provided name to self.
    /// Panics if the ivar wasn't successfully added.
    pub fn add_ivar<T>(&mut self, name: &str) where T: Encode {
        let c_name = CString::new(name).unwrap();
        let encoding = CString::new(T::encode().as_str()).unwrap();
        let size = mem::size_of::<T>() as size_t;
        let align = mem::align_of::<T>() as u8;
        let success = unsafe {
            runtime::class_addIvar(self.cls, c_name.as_ptr(), size, align,
                encoding.as_ptr())
        };
        assert!(success != NO, "Failed to add ivar {}", name);
    }

    /// Registers self, consuming it and returning a reference to the
    /// newly registered `Class`.
    pub fn register(self) -> &'static Class {
        unsafe {
            let cls = self.cls;
            runtime::objc_registerClassPair(cls);
            // Forget self otherwise the class will be disposed in drop
            mem::forget(self);
            &*cls
        }
    }
}

impl Drop for ClassDecl {
    fn drop(&mut self) {
        unsafe {
            runtime::objc_disposeClassPair(self.cls);
        }
    }
}

#[cfg(test)]
mod tests {
    use runtime::{Object, Sel};
    use test_utils;
    use super::IntoMethodImp;

    #[test]
    fn test_custom_class() {
        // Registering the custom class is in test_utils
        let obj = test_utils::custom_object();
        unsafe {
            let _: () = msg_send![obj, setFoo:13u32];
            let result: u32 = msg_send![obj, foo];
            assert!(result == 13);
        }
    }

    #[test]
    fn test_class_method() {
        let cls = test_utils::custom_class();
        unsafe {
            let result: u32 = msg_send![cls, classFoo];
            assert!(result == 7);
        }
    }

    #[test]
    fn test_mismatched_args() {
        extern fn wrong_num_args_method(_obj: &Object, _cmd: Sel, _a: i32) { }

        let sel = sel!(doSomethingWithFoo:bar:);
        let f: extern fn(&Object, Sel, i32) = wrong_num_args_method;
        let imp = f.into_imp(sel);
        assert!(imp.is_err());
    }
}
<|endoftext|>


<commit_before>use crate::mir::operand::OperandRef;
use crate::traits::*;
use rustc_index::vec::Idx;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{ConstValue, ErrorHandled};
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::{self, Ty};
use rustc_span::source_map::Span;
use rustc_target::abi::Abi;

use super::FunctionCx;

impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
    pub fn eval_mir_constant_to_operand(
        &mut self,
        bx: &mut Bx,
        constant: &mir::Constant<'tcx>,
    ) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
        match constant.literal.val {
            // Special case unevaluated statics, because statics have an identity and thus should
            // use `get_static` to get at their id.
            // FIXME(oli-obk): can we unify this somehow, maybe by making const eval of statics
            // always produce `&STATIC`. This may also simplify how const eval works with statics.
            ty::ConstKind::Unevaluated(def_id, substs, None) if self.cx.tcx().is_static(def_id) => {
                assert!(substs.is_empty(), "we don't support generic statics yet");
                let static_ = bx.get_static(def_id);
                // we treat operands referring to statics as if they were `&STATIC` instead
                let ptr_ty = self.cx.tcx().mk_mut_ptr(self.monomorphize(&constant.literal.ty));
                let layout = bx.layout_of(ptr_ty);
                Ok(OperandRef::from_immediate_or_packed_pair(bx, static_, layout))
            }
            _ => {
                let val = self.eval_mir_constant(constant)?;
                let ty = self.monomorphize(&constant.literal.ty);
                Ok(OperandRef::from_const(bx, val, ty))
            }
        }
    }

    pub fn eval_mir_constant(
        &mut self,
        constant: &mir::Constant<'tcx>,
    ) -> Result<ConstValue<'tcx>, ErrorHandled> {
        match self.monomorphize(&constant.literal).val {
            ty::ConstKind::Unevaluated(def_id, substs, promoted) => self
                .cx
                .tcx()
                .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None)
                .map_err(|err| {
                    if promoted.is_none() {
                        self.cx
                            .tcx()
                            .sess
                            .span_err(constant.span, "erroneous constant encountered");
                    }
                    err
                }),
            ty::ConstKind::Value(value) => Ok(value),
            err => span_bug!(
                constant.span,
                "encountered bad ConstKind after monomorphizing: {:?}",
                err
            ),
        }
    }

    /// process constant containing SIMD shuffle indices
    pub fn simd_shuffle_indices(
        &mut self,
        bx: &Bx,
        span: Span,
        ty: Ty<'tcx>,
        constant: Result<ConstValue<'tcx>, ErrorHandled>,
    ) -> (Bx::Value, Ty<'tcx>) {
        constant
            .map(|val| {
                let field_ty = ty.builtin_index().unwrap();
                let fields = match ty.kind {
                    ty::Array(_, n) => n.eval_usize(bx.tcx(), ty::ParamEnv::reveal_all()),
                    _ => bug!("invalid simd shuffle type: {}", ty),
                };
                let c = ty::Const::from_value(bx.tcx(), val, ty);
                let values: Vec<_> = (0..fields)
                    .map(|field| {
                        let field = bx.tcx().const_field(
                            ty::ParamEnv::reveal_all().and((&c, mir::Field::new(field as usize))),
                        );
                        if let Some(prim) = field.try_to_scalar() {
                            let layout = bx.layout_of(field_ty);
                            let scalar = match layout.abi {
                                Abi::Scalar(ref x) => x,
                                _ => bug!("from_const: invalid ByVal layout: {:#?}", layout),
                            };
                            bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout))
                        } else {
                            bug!("simd shuffle field {:?}", field)
                        }
                    })
                    .collect();
                let llval = bx.const_struct(&values, false);
                (llval, c.ty)
            })
            .unwrap_or_else(|_| {
                bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time");
                // We've errored, so we don't have to produce working code.
                let ty = self.monomorphize(&ty);
                let llty = bx.backend_type(bx.layout_of(ty));
                (bx.const_undef(llty), ty)
            })
    }
}
<commit_msg>Rollup merge of #71747 - spastorino:safety-scheme-around-consts-cleanup, r=oli-obk<commit_after>use crate::mir::operand::OperandRef;
use crate::traits::*;
use rustc_index::vec::Idx;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{ConstValue, ErrorHandled};
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::{self, Ty};
use rustc_span::source_map::Span;
use rustc_target::abi::Abi;

use super::FunctionCx;

impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
    pub fn eval_mir_constant_to_operand(
        &mut self,
        bx: &mut Bx,
        constant: &mir::Constant<'tcx>,
    ) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
        let val = self.eval_mir_constant(constant)?;
        let ty = self.monomorphize(&constant.literal.ty);
        Ok(OperandRef::from_const(bx, val, ty))
    }

    pub fn eval_mir_constant(
        &mut self,
        constant: &mir::Constant<'tcx>,
    ) -> Result<ConstValue<'tcx>, ErrorHandled> {
        match self.monomorphize(&constant.literal).val {
            ty::ConstKind::Unevaluated(def_id, substs, promoted) => self
                .cx
                .tcx()
                .const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None)
                .map_err(|err| {
                    if promoted.is_none() {
                        self.cx
                            .tcx()
                            .sess
                            .span_err(constant.span, "erroneous constant encountered");
                    }
                    err
                }),
            ty::ConstKind::Value(value) => Ok(value),
            err => span_bug!(
                constant.span,
                "encountered bad ConstKind after monomorphizing: {:?}",
                err
            ),
        }
    }

    /// process constant containing SIMD shuffle indices
    pub fn simd_shuffle_indices(
        &mut self,
        bx: &Bx,
        span: Span,
        ty: Ty<'tcx>,
        constant: Result<ConstValue<'tcx>, ErrorHandled>,
    ) -> (Bx::Value, Ty<'tcx>) {
        constant
            .map(|val| {
                let field_ty = ty.builtin_index().unwrap();
                let fields = match ty.kind {
                    ty::Array(_, n) => n.eval_usize(bx.tcx(), ty::ParamEnv::reveal_all()),
                    _ => bug!("invalid simd shuffle type: {}", ty),
                };
                let c = ty::Const::from_value(bx.tcx(), val, ty);
                let values: Vec<_> = (0..fields)
                    .map(|field| {
                        let field = bx.tcx().const_field(
                            ty::ParamEnv::reveal_all().and((&c, mir::Field::new(field as usize))),
                        );
                        if let Some(prim) = field.try_to_scalar() {
                            let layout = bx.layout_of(field_ty);
                            let scalar = match layout.abi {
                                Abi::Scalar(ref x) => x,
                                _ => bug!("from_const: invalid ByVal layout: {:#?}", layout),
                            };
                            bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout))
                        } else {
                            bug!("simd shuffle field {:?}", field)
                        }
                    })
                    .collect();
                let llval = bx.const_struct(&values, false);
                (llval, c.ty)
            })
            .unwrap_or_else(|_| {
                bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time");
                // We've errored, so we don't have to produce working code.
                let ty = self.monomorphize(&ty);
                let llty = bx.backend_type(bx.layout_of(ty));
                (bx.const_undef(llty), ty)
            })
    }
}
<|endoftext|>