<commit_before>use super::super::interconnect::*;
use super::cp0;
use super::opcode::Opcode::*;
use super::opcode::SpecialOpcode::*;
use super::opcode::RegImmOpcode::*;
use super::instruction::Instruction;

use std::fmt;

const NUM_GPR: usize = 32;

enum SignExtendResult {
    Yes,
    No
}

enum WriteLink {
    Yes,
    No
}

pub struct Cpu {
    reg_gpr: [u64; NUM_GPR],
    reg_fpr: [f64; NUM_GPR],

    reg_pc: u64,

    reg_hi: u64,
    reg_lo: u64,

    reg_llbit: bool, // TODO: Enum type

    reg_fcr0: u32,
    reg_fcr31: u32,

    cp0: cp0::Cp0,

    delay_slot_pc: Option<u64>
}

impl Cpu {
    pub fn new() -> Cpu {
        Cpu {
            reg_gpr: [0; NUM_GPR],
            reg_fpr: [0.0; NUM_GPR],

            reg_pc: 0xffff_ffff_bfc0_0000, // TODO: Move to const

            reg_hi: 0,
            reg_lo: 0,

            reg_llbit: false,

            reg_fcr0: 0,
            reg_fcr31: 0,

            cp0: cp0::Cp0::default(),

            delay_slot_pc: None
        }
    }

    pub fn current_pc_virt(&self) -> u64 {
        self.delay_slot_pc.unwrap_or(self.reg_pc)
    }

    pub fn current_pc_phys(&self) -> u64 {
        self.virt_addr_to_phys_addr(self.current_pc_virt())
    }

    pub fn will_execute_from_delay_slot(&self) -> bool {
        self.delay_slot_pc.is_some()
    }

    pub fn step(&mut self, interconnect: &mut Interconnect) {
        if let Some(pc) = self.delay_slot_pc {
            let instr = self.read_instruction(interconnect, pc);
            self.execute_instruction(interconnect, instr);

            self.delay_slot_pc = None;
        } else {
            let instr = self.read_instruction(interconnect, self.reg_pc);

            self.reg_pc += 4;
            self.execute_instruction(interconnect, instr);
        }
    }

    fn read_instruction(&self, interconnect: &mut Interconnect, addr: u64) -> Instruction {
        Instruction(self.read_word(interconnect, addr))
    }

    fn execute_instruction(&mut self, interconnect: &mut Interconnect, instr: Instruction) {
        match instr.opcode() {
            Special => {
                match instr.special_op() {
                    Sll => self.reg_instr(instr, |_, rt, sa| rt << sa),
                    Srl => self.reg_instr(instr, |_, rt, sa| {
                        let rt = rt as u32;
                        (rt >> sa) as u64
                    }),

                    Sllv =>
                        self.reg_instr(instr, |rs, rt, _| {
                            // TODO: Check to see if this is actually sa
                            let shift = rs & 0b11111;
                            rt << shift
                        }),

                    Srlv =>
                        self.reg_instr(instr, |rs, rt, _| {
                            let rs = rs as u32;
                            let rt = rt as u32;
                            let shift = rs & 0b11111;
                            (rt >> shift) as u64
                        }),

                    Jr => {
                        let delay_slot_pc = self.reg_pc;

                        // Update PC before executing delay slot instruction
                        self.reg_pc = self.read_reg_gpr(instr.rs());

                        self.delay_slot_pc = Some(delay_slot_pc);
                    }

                    Multu => {
                        let rs = self.read_reg_gpr(instr.rs()) as u32;
                        let rt = self.read_reg_gpr(instr.rt()) as u32;

                        let res = (rs as u64) * (rt as u64);

                        // TODO: Undefined if last 2 instructions were
                        //  MFHI or MFLO
                        self.reg_lo = (res as i32) as u64;
                        self.reg_hi = ((res >> 32) as i32) as u64;
                    }

                    Mfhi => {
                        let value = self.reg_hi;
                        self.write_reg_gpr(instr.rd() as usize, value);
                    }
                    Mflo => {
                        let value = self.reg_lo;
                        self.write_reg_gpr(instr.rd() as usize, value);
                    }

                    Addu => self.reg_instr(instr, |rs, rt, _| rs.wrapping_add(rt)),
                    Subu => self.reg_instr(instr, |rs, rt, _| rs.wrapping_sub(rt)),

                    And => self.reg_instr(instr, |rs, rt, _| rs & rt),
                    Or => self.reg_instr(instr, |rs, rt, _| rs | rt),
                    Xor => self.reg_instr(instr, |rs, rt, _| rs ^ rt),

                    Sltu => self.reg_instr(instr, |rs, rt, _| if rs < rt { 1 } else { 0 })
                }
            }

            RegImm => {
                match instr.reg_imm_op() {
                    Bgezal => { self.branch(instr, WriteLink::Yes, |rs, _| (rs as i64) >= 0); }
                }
            }

            Addi =>
                self.imm_instr(instr, SignExtendResult::Yes, |rs, _, imm_sign_extended| {
                    // TODO: Handle overflow exception
                    rs + imm_sign_extended
                }),
            Addiu => self.imm_instr(instr, SignExtendResult::Yes, |rs, _, imm_sign_extended| rs.wrapping_add(imm_sign_extended)),

            Andi => self.imm_instr(instr, SignExtendResult::No, |rs, imm, _| rs & imm),
            Ori => self.imm_instr(instr, SignExtendResult::No, |rs, imm, _| rs | imm),

            Lui => self.imm_instr(instr, SignExtendResult::Yes, |_, imm, _| imm << 16),

            Mtc0 => {
                let data = self.read_reg_gpr(instr.rt());
                self.cp0.write_reg(instr.rd(), data);
            }

            Beq => { self.branch(instr, WriteLink::No, |rs, rt| rs == rt); },
            Bne => { self.branch(instr, WriteLink::No, |rs, rt| rs != rt); },

            Beql => self.branch_likely(instr, |rs, rt| rs == rt),
            Bnel => self.branch_likely(instr, |rs, rt| rs != rt),

            Lw => {
                let base = instr.rs();

                let sign_extended_offset = instr.offset_sign_extended();
                let virt_addr = self.read_reg_gpr(base).wrapping_add(sign_extended_offset);
                let mem = (self.read_word(interconnect, virt_addr) as i32) as u64;
                self.write_reg_gpr(instr.rt(), mem);
            },

            Sw => {
                let base = instr.rs();

                let sign_extended_offset = instr.offset_sign_extended();
                let virt_addr = self.read_reg_gpr(base).wrapping_add(sign_extended_offset);
                let mem = self.read_reg_gpr(instr.rt()) as u32;
                self.write_word(interconnect, virt_addr, mem);
            }
        }
    }

    fn imm_instr<F>(&mut self, instr: Instruction, sign_extend_result: SignExtendResult, f: F) where F: FnOnce(u64, u64, u64) -> u64 {
        let rs = self.read_reg_gpr(instr.rs());
        let imm = instr.imm() as u64;
        let imm_sign_extended = instr.imm_sign_extended();
        let value = f(rs, imm, imm_sign_extended);
        let sign_extended_value = (value as i32) as u64;
        let value = match sign_extend_result {
            SignExtendResult::Yes => sign_extended_value,
            _ => value
        };
        self.write_reg_gpr(instr.rt(), value);
    }

    fn reg_instr<F>(&mut self, instr: Instruction, f: F) where F: FnOnce(u64, u64, u32) -> u64 {
        let rs = self.read_reg_gpr(instr.rs());
        let rt = self.read_reg_gpr(instr.rt());
        let sa = instr.sa();
        let value = f(rs, rt, sa);
        let sign_extended_value = (value as i32) as u64;
        self.write_reg_gpr(instr.rd() as usize, sign_extended_value);
    }

    fn branch<F>(&mut self, instr: Instruction, write_link: WriteLink, f: F) -> bool where F: FnOnce(u64, u64) -> bool {
        let rs = self.read_reg_gpr(instr.rs());
        let rt = self.read_reg_gpr(instr.rt());
        let is_taken = f(rs, rt);

        let delay_slot_pc = self.reg_pc;

        if let WriteLink::Yes = write_link {
            let link_address = delay_slot_pc + 4;
            self.write_reg_gpr(31, link_address);
        }

        if is_taken {
            let sign_extended_offset = instr.offset_sign_extended() << 2;
            // Update PC before executing delay slot instruction
            self.reg_pc = self.reg_pc.wrapping_add(sign_extended_offset);

            self.delay_slot_pc = Some(delay_slot_pc);
        }

        is_taken
    }

    fn branch_likely<F>(&mut self, instr: Instruction, f: F) where F: FnOnce(u64, u64) -> bool {
        if !self.branch(instr, WriteLink::No, f) {
            // Skip over delay slot instruction when not branching
            self.reg_pc = self.reg_pc.wrapping_add(4);
        }
    }

    fn read_word(&self, interconnect: &mut Interconnect, virt_addr: u64) -> u32 {
        let phys_addr = self.virt_addr_to_phys_addr(virt_addr);
        interconnect.read_word(phys_addr as u32)
    }

    fn write_word(&mut self, interconnect: &mut Interconnect, virt_addr: u64, value: u32) {
        let phys_addr = self.virt_addr_to_phys_addr(virt_addr);
        interconnect.write_word(phys_addr as u32, value);
    }

    fn virt_addr_to_phys_addr(&self, virt_addr: u64) -> u64 {
        // See Table 5-3 in the VR4300 User's Manual
        let addr_bit_values = (virt_addr >> 29) & 0b111;

        if addr_bit_values == 0b101 {
            // kseg1
            virt_addr - 0xffff_ffff_a000_0000
        } else {
            // TODO
            panic!("Unrecognized virtual address: {:#x}", virt_addr);
        }
    }

    fn write_reg_gpr(&mut self, index: usize, value: u64) {
        if index != 0 {
            self.reg_gpr[index] = value;
        }
    }

    fn read_reg_gpr(&self, index: usize) -> u64 {
        match index {
            0 => 0,
            _ => self.reg_gpr[index]
        }
    }
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        const REGS_PER_LINE: usize = 2;
        const REG_NAMES: [&'static str; NUM_GPR] = [
        "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
        "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
        "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
        "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
        ];

        try!(write!(f,"\nCPU General Purpose Registers:"));
        for reg_num in 0..NUM_GPR {
            if (reg_num % REGS_PER_LINE) == 0 {
                try!(writeln!(f,""));
            }
            try!(write!(f,
                "{reg_name}/gpr{num:02}: {value:#018X} ",
                num = reg_num,
                reg_name = REG_NAMES[reg_num],
                value = self.reg_gpr[reg_num],
            ));
        }

        try!(write!(f,"\n\nCPU Floating Point Registers:"));
        for reg_num in 0..NUM_GPR {
            if (reg_num % REGS_PER_LINE) == 0 {
                try!(writeln!(f,""));
            }
            try!(write!(f,
                "fpr{num:02}: {value:21} ",
                num = reg_num,
                value = self.reg_fpr[reg_num],)
            );
        }

        try!(writeln!(f,"\n\nCPU Special Registers:"));
        try!(writeln!(f,
            "\
            reg_pc: {:#018X}\n\
            reg_hi: {:#018X}\n\
            reg_lo: {:#018X}\n\
            reg_llbit: {}\n\
            reg_fcr0:  {:#010X}\n\
            reg_fcr31: {:#010X}\n\
            ",
            self.reg_pc,
            self.reg_hi,
            self.reg_lo,
            self.reg_llbit,
            self.reg_fcr0,
            self.reg_fcr31
        ));

        writeln!(f, "{:#?}", self.cp0)
    }
}
<commit_msg>clear delay_slot_pc before executing the delay slot instruction<commit_after>use super::super::interconnect::*;
use super::cp0;
use super::opcode::Opcode::*;
use super::opcode::SpecialOpcode::*;
use super::opcode::RegImmOpcode::*;
use super::instruction::Instruction;

use std::fmt;

const NUM_GPR: usize = 32;

enum SignExtendResult {
    Yes,
    No
}

enum WriteLink {
    Yes,
    No
}

pub struct Cpu {
    reg_gpr: [u64; NUM_GPR],
    reg_fpr: [f64; NUM_GPR],

    reg_pc: u64,

    reg_hi: u64,
    reg_lo: u64,

    reg_llbit: bool, // TODO: Enum type

    reg_fcr0: u32,
    reg_fcr31: u32,

    cp0: cp0::Cp0,

    delay_slot_pc: Option<u64>
}

impl Cpu {
    pub fn new() -> Cpu {
        Cpu {
            reg_gpr: [0; NUM_GPR],
            reg_fpr: [0.0; NUM_GPR],

            reg_pc: 0xffff_ffff_bfc0_0000, // TODO: Move to const

            reg_hi: 0,
            reg_lo: 0,

            reg_llbit: false,

            reg_fcr0: 0,
            reg_fcr31: 0,

            cp0: cp0::Cp0::default(),

            delay_slot_pc: None
        }
    }

    pub fn current_pc_virt(&self) -> u64 {
        self.delay_slot_pc.unwrap_or(self.reg_pc)
    }

    pub fn current_pc_phys(&self) -> u64 {
        self.virt_addr_to_phys_addr(self.current_pc_virt())
    }

    pub fn will_execute_from_delay_slot(&self) -> bool {
        self.delay_slot_pc.is_some()
    }

    pub fn step(&mut self, interconnect: &mut Interconnect) {
        if let Some(pc) = self.delay_slot_pc {
            let instr = self.read_instruction(interconnect, pc);
            self.delay_slot_pc = None;

            self.execute_instruction(interconnect, instr);
        } else {
            let instr = self.read_instruction(interconnect, self.reg_pc);

            self.reg_pc += 4;
            self.execute_instruction(interconnect, instr);
        }
    }

    fn read_instruction(&self, interconnect: &mut Interconnect, addr: u64) -> Instruction {
        Instruction(self.read_word(interconnect, addr))
    }

    fn execute_instruction(&mut self, interconnect: &mut Interconnect, instr: Instruction) {
        match instr.opcode() {
            Special => {
                match instr.special_op() {
                    Sll => self.reg_instr(instr, |_, rt, sa| rt << sa),
                    Srl => self.reg_instr(instr, |_, rt, sa| {
                        let rt = rt as u32;
                        (rt >> sa) as u64
                    }),

                    Sllv =>
                        self.reg_instr(instr, |rs, rt, _| {
                            // TODO: Check to see if this is actually sa
                            let shift = rs & 0b11111;
                            rt << shift
                        }),

                    Srlv =>
                        self.reg_instr(instr, |rs, rt, _| {
                            let rs = rs as u32;
                            let rt = rt as u32;
                            let shift = rs & 0b11111;
                            (rt >> shift) as u64
                        }),

                    Jr => {
                        let delay_slot_pc = self.reg_pc;

                        // Update PC before executing delay slot instruction
                        self.reg_pc = self.read_reg_gpr(instr.rs());

                        self.delay_slot_pc = Some(delay_slot_pc);
                    }

                    Multu => {
                        let rs = self.read_reg_gpr(instr.rs()) as u32;
                        let rt = self.read_reg_gpr(instr.rt()) as u32;

                        let res = (rs as u64) * (rt as u64);

                        // TODO: Undefined if last 2 instructions were
                        //  MFHI or MFLO
                        self.reg_lo = (res as i32) as u64;
                        self.reg_hi = ((res >> 32) as i32) as u64;
                    }

                    Mfhi => {
                        let value = self.reg_hi;
                        self.write_reg_gpr(instr.rd() as usize, value);
                    }
                    Mflo => {
                        let value = self.reg_lo;
                        self.write_reg_gpr(instr.rd() as usize, value);
                    }

                    Addu => self.reg_instr(instr, |rs, rt, _| rs.wrapping_add(rt)),
                    Subu => self.reg_instr(instr, |rs, rt, _| rs.wrapping_sub(rt)),

                    And => self.reg_instr(instr, |rs, rt, _| rs & rt),
                    Or => self.reg_instr(instr, |rs, rt, _| rs | rt),
                    Xor => self.reg_instr(instr, |rs, rt, _| rs ^ rt),

                    Sltu => self.reg_instr(instr, |rs, rt, _| if rs < rt { 1 } else { 0 })
                }
            }

            RegImm => {
                match instr.reg_imm_op() {
                    Bgezal => { self.branch(instr, WriteLink::Yes, |rs, _| (rs as i64) >= 0); }
                }
            }

            Addi =>
                self.imm_instr(instr, SignExtendResult::Yes, |rs, _, imm_sign_extended| {
                    // TODO: Handle overflow exception
                    rs + imm_sign_extended
                }),
            Addiu => self.imm_instr(instr, SignExtendResult::Yes, |rs, _, imm_sign_extended| rs.wrapping_add(imm_sign_extended)),

            Andi => self.imm_instr(instr, SignExtendResult::No, |rs, imm, _| rs & imm),
            Ori => self.imm_instr(instr, SignExtendResult::No, |rs, imm, _| rs | imm),

            Lui => self.imm_instr(instr, SignExtendResult::Yes, |_, imm, _| imm << 16),

            Mtc0 => {
                let data = self.read_reg_gpr(instr.rt());
                self.cp0.write_reg(instr.rd(), data);
            }

            Beq => { self.branch(instr, WriteLink::No, |rs, rt| rs == rt); },
            Bne => { self.branch(instr, WriteLink::No, |rs, rt| rs != rt); },

            Beql => self.branch_likely(instr, |rs, rt| rs == rt),
            Bnel => self.branch_likely(instr, |rs, rt| rs != rt),

            Lw => {
                let base = instr.rs();

                let sign_extended_offset = instr.offset_sign_extended();
                let virt_addr = self.read_reg_gpr(base).wrapping_add(sign_extended_offset);
                let mem = (self.read_word(interconnect, virt_addr) as i32) as u64;
                self.write_reg_gpr(instr.rt(), mem);
            },

            Sw => {
                let base = instr.rs();

                let sign_extended_offset = instr.offset_sign_extended();
                let virt_addr = self.read_reg_gpr(base).wrapping_add(sign_extended_offset);
                let mem = self.read_reg_gpr(instr.rt()) as u32;
                self.write_word(interconnect, virt_addr, mem);
            }
        }
    }

    fn imm_instr<F>(&mut self, instr: Instruction, sign_extend_result: SignExtendResult, f: F) where F: FnOnce(u64, u64, u64) -> u64 {
        let rs = self.read_reg_gpr(instr.rs());
        let imm = instr.imm() as u64;
        let imm_sign_extended = instr.imm_sign_extended();
        let value = f(rs, imm, imm_sign_extended);
        let sign_extended_value = (value as i32) as u64;
        let value = match sign_extend_result {
            SignExtendResult::Yes => sign_extended_value,
            _ => value
        };
        self.write_reg_gpr(instr.rt(), value);
    }

    fn reg_instr<F>(&mut self, instr: Instruction, f: F) where F: FnOnce(u64, u64, u32) -> u64 {
        let rs = self.read_reg_gpr(instr.rs());
        let rt = self.read_reg_gpr(instr.rt());
        let sa = instr.sa();
        let value = f(rs, rt, sa);
        let sign_extended_value = (value as i32) as u64;
        self.write_reg_gpr(instr.rd() as usize, sign_extended_value);
    }

    fn branch<F>(&mut self, instr: Instruction, write_link: WriteLink, f: F) -> bool where F: FnOnce(u64, u64) -> bool {
        let rs = self.read_reg_gpr(instr.rs());
        let rt = self.read_reg_gpr(instr.rt());
        let is_taken = f(rs, rt);

        let delay_slot_pc = self.reg_pc;

        if let WriteLink::Yes = write_link {
            let link_address = delay_slot_pc + 4;
            self.write_reg_gpr(31, link_address);
        }

        if is_taken {
            let sign_extended_offset = instr.offset_sign_extended() << 2;
            // Update PC before executing delay slot instruction
            self.reg_pc = self.reg_pc.wrapping_add(sign_extended_offset);

            self.delay_slot_pc = Some(delay_slot_pc);
        }

        is_taken
    }

    fn branch_likely<F>(&mut self, instr: Instruction, f: F) where F: FnOnce(u64, u64) -> bool {
        if !self.branch(instr, WriteLink::No, f) {
            // Skip over delay slot instruction when not branching
            self.reg_pc = self.reg_pc.wrapping_add(4);
        }
    }

    fn read_word(&self, interconnect: &mut Interconnect, virt_addr: u64) -> u32 {
        let phys_addr = self.virt_addr_to_phys_addr(virt_addr);
        interconnect.read_word(phys_addr as u32)
    }

    fn write_word(&mut self, interconnect: &mut Interconnect, virt_addr: u64, value: u32) {
        let phys_addr = self.virt_addr_to_phys_addr(virt_addr);
        interconnect.write_word(phys_addr as u32, value);
    }

    fn virt_addr_to_phys_addr(&self, virt_addr: u64) -> u64 {
        // See Table 5-3 in the VR4300 User's Manual
        let addr_bit_values = (virt_addr >> 29) & 0b111;

        if addr_bit_values == 0b101 {
            // kseg1
            virt_addr - 0xffff_ffff_a000_0000
        } else {
            // TODO
            panic!("Unrecognized virtual address: {:#x}", virt_addr);
        }
    }

    fn write_reg_gpr(&mut self, index: usize, value: u64) {
        if index != 0 {
            self.reg_gpr[index] = value;
        }
    }

    fn read_reg_gpr(&self, index: usize) -> u64 {
        match index {
            0 => 0,
            _ => self.reg_gpr[index]
        }
    }
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        const REGS_PER_LINE: usize = 2;
        const REG_NAMES: [&'static str; NUM_GPR] = [
        "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
        "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
        "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
        "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
        ];

        try!(write!(f,"\nCPU General Purpose Registers:"));
        for reg_num in 0..NUM_GPR {
            if (reg_num % REGS_PER_LINE) == 0 {
                try!(writeln!(f,""));
            }
            try!(write!(f,
                "{reg_name}/gpr{num:02}: {value:#018X} ",
                num = reg_num,
                reg_name = REG_NAMES[reg_num],
                value = self.reg_gpr[reg_num],
            ));
        }

        try!(write!(f,"\n\nCPU Floating Point Registers:"));
        for reg_num in 0..NUM_GPR {
            if (reg_num % REGS_PER_LINE) == 0 {
                try!(writeln!(f,""));
            }
            try!(write!(f,
                "fpr{num:02}: {value:21} ",
                num = reg_num,
                value = self.reg_fpr[reg_num],)
            );
        }

        try!(writeln!(f,"\n\nCPU Special Registers:"));
        try!(writeln!(f,
            "\
            reg_pc: {:#018X}\n\
            reg_hi: {:#018X}\n\
            reg_lo: {:#018X}\n\
            reg_llbit: {}\n\
            reg_fcr0:  {:#010X}\n\
            reg_fcr31: {:#010X}\n\
            ",
            self.reg_pc,
            self.reg_hi,
            self.reg_lo,
            self.reg_llbit,
            self.reg_fcr0,
            self.reg_fcr31
        ));

        writeln!(f, "{:#?}", self.cp0)
    }
}
<|endoftext|>


<commit_before>//! Bindings to the Hypervisor Framework

use libc::*;

pub mod consts;

/// Hypervisor Framework return code
pub type hv_return_t = uint32_t;

/// Options for hv_vcpu_create()
pub type hv_vm_options_t = uint64_t;

// Creating and Destroying VM Instances
extern {
    /// Creates a VM instance for the current task
    pub fn hv_vm_create(flags: hv_vm_options_t) -> hv_return_t;

    /// Destroys the VM instance associated with the current task
    pub fn hv_vm_destroy() -> hv_return_t;
}

/// Type of a vCPU ID
pub type hv_vcpuid_t = c_uint;

// Creating and Managing vCPU Instances
extern {
    /// Creates a vCPU instance for the current thread
    pub fn hv_vcpu_create(vcpu: *mut hv_vcpuid_t, flags: hv_vm_options_t) -> hv_return_t;

    /// Executes a vCPU
    pub fn hv_vcpu_run(vcpu: hv_vcpuid_t) -> hv_return_t;

    /// Forces an immediate VMEXIT of a set of vCPUs of the VM
    pub fn hv_vcpu_interrupt(vcpu: *const hv_vcpuid_t, vcpu_count: c_uint) -> hv_return_t;

    /// Returns the cumulative execution time of a vCPU in nanoseconds
    pub fn hv_vcpu_get_exec_time(vcpu: hv_vcpuid_t, time: *mut uint64_t) -> hv_return_t;

    /// Forces flushing of cached vCPU state
    pub fn hv_vcpu_flush(vcpu: hv_vcpuid_t) -> hv_return_t;

    /// Invalidates the TLB of a vCPU
    pub fn hv_vcpu_invalidate_tlb(vcpu: hv_vcpuid_t) -> hv_return_t;

    /// Destroys the vCPU instance associated with the current thread
    pub fn hv_vcpu_destroy(vcpu: hv_vcpuid_t) -> hv_return_t;
}

/// x86 architectural register IDs
#[repr(C)]
pub enum hv_x86_reg_t {
	HV_X86_RIP,
	HV_X86_RFLAGS,
	HV_X86_RAX,
	HV_X86_RCX,
	HV_X86_RDX,
	HV_X86_RBX,
	HV_X86_RSI,
	HV_X86_RDI,
	HV_X86_RSP,
	HV_X86_RBP,
	HV_X86_R8,
	HV_X86_R9,
	HV_X86_R10,
	HV_X86_R11,
	HV_X86_R12,
	HV_X86_R13,
	HV_X86_R14,
	HV_X86_R15,
	HV_X86_CS,
	HV_X86_SS,
	HV_X86_DS,
	HV_X86_ES,
	HV_X86_FS,
	HV_X86_GS,
	HV_X86_IDT_BASE,
	HV_X86_IDT_LIMIT,
	HV_X86_GDT_BASE,
	HV_X86_GDT_LIMIT,
	HV_X86_LDTR,
	HV_X86_LDT_BASE,
	HV_X86_LDT_LIMIT,
	HV_X86_LDT_AR,
	HV_X86_TR,
	HV_X86_TSS_BASE,
	HV_X86_TSS_LIMIT,
	HV_X86_TSS_AR,
	HV_X86_CR0,
	HV_X86_CR1,
	HV_X86_CR2,
	HV_X86_CR3,
	HV_X86_CR4,
	HV_X86_DR0,
	HV_X86_DR1,
	HV_X86_DR2,
	HV_X86_DR3,
	HV_X86_DR4,
	HV_X86_DR5,
	HV_X86_DR6,
	HV_X86_DR7,
	HV_X86_TPR,
	HV_X86_XCR0,
	HV_X86_REGISTERS_MAX,
}

// Accessing Registers
extern {
    /// Returns the current value of an architectural x86 register
    /// of a vCPU
    pub fn hv_vcpu_read_register(vcpu: hv_vcpuid_t, reg: hv_x86_reg_t, value: *const uint64_t) -> hv_return_t;

    /// Sets the value of an architectural x86 register of a vCPU
    pub fn hv_vcpu_write_register(vcpu: hv_vcpuid_t, reg: hv_x86_reg_t, value: *mut uint64_t) -> hv_return_t;
}

// Accessing Floating Point (FP) State
extern {
    /// Returns the current architectural x86 floating point and
    /// SIMD state of a vCPU
    pub fn hv_vcpu_read_fpstate(vcpu: hv_vcpuid_t, buffer: *const c_void, size: size_t) -> hv_return_t;

    /// Sets the architectural x86 floating point and SIMD state of
    /// a vCPU
    pub fn hv_vcpu_write_fpstate(vcpu: hv_vcpuid_t, buffer: *mut c_void, size: size_t) -> hv_return_t;
}

// Accessing Machine Specific Registers (MSRs)
extern {
    /// Enables an MSR to be used natively by the VM
    pub fn hv_vcpu_enable_native_msr(vcpu: hv_vcpuid_t, msr: uint32_t, enable: bool) -> hv_return_t;

    /// Returns the current value of an MSR of a vCPU
    pub fn hv_vcpu_read_msr(vcpu: hv_vcpuid_t, msr: uint32_t, value: *const uint64_t) -> hv_return_t;

    /// Set the value of an MSR of a vCPU
    pub fn hv_vcpu_write_msr(vcpu: hv_vcpuid_t, msr: uint32_t, value: *mut uint64_t) -> hv_return_t;
}

// Managing Timestamp-Counters (TSC)
extern {
    /// Synchronizes guest Timestamp-Counters (TSC) across all vCPUs
    pub fn hv_vm_sync_tsc(tsc: uint64_t) -> hv_return_t;
}

/// Type of a user virtual address
pub type hv_uvaddr_t = *const c_void;

/// Guest physical memory region permissions for hv_vm_map()
/// and hv_vm_protect()
pub type hv_memory_flags_t = uint64_t;

/// Type of a guest physical address
pub type hv_gpaddr_t = uint64_t;

// Managing Memory Regions
extern {
    /// Maps a region in the virtual address space of the current
    /// task into the guest physical address space of the VM
    pub fn hv_vm_map(uva: hv_uvaddr_t, gpa: hv_gpaddr_t, size: size_t, flags: hv_memory_flags_t) -> hv_return_t;

    /// Unmaps a region in the guest physical address space of the VM
    pub fn hv_vm_unmap(gpa: hv_gpaddr_t, size: size_t) -> hv_return_t;

    /// Modifies the permissions of a region in the guest physical
    /// address space of the VM
    pub fn hv_vm_protect(gpa: hv_gpaddr_t, size: size_t, flags: hv_memory_flags_t) -> hv_return_t;
}

/// Enum type of VMX cabability fields
#[repr(C)]
pub enum hv_vmx_capability_t {
    /// Pin-based VMX capabilities
	HV_VMX_CAP_PINBASED                           = 0,
    /// Primary proc-based VMX capabilities
	HV_VMX_CAP_PROCBASED                          = 1,
    /// Secondary proc-based VMX capabilities
	HV_VMX_CAP_PROCBASED2                         = 2,
    /// VM-entry VMX capabilities
	HV_VMX_CAP_ENTRY                              = 3,
    /// VM-exit VMX capabilities
	HV_VMX_CAP_EXIT                               = 4,
    /// VMX preemption timer frequency
	HV_VMX_CAP_PREEMPTION_TIMER                   = 32
}

// Managing Virtual Machine Control Structure (VMCS)
extern {
    /// Returns the current value of a VMCS field of a vCPU
    pub fn hv_vmx_vcpu_read_vmcs(vcpu: hv_vcpuid_t, field: uint32_t, value: *const uint64_t) -> hv_return_t;

    /// Sets the value of a VMCS field of a vCPU
    pub fn hv_vmx_vcpu_write_vmcs(vcpu: hv_vcpuid_t, field: uint32_t, value: uint64_t) -> hv_return_t;

    /// Returns the VMX capabilities of the host processor
    pub fn hv_vmx_read_capability(field: hv_vmx_capability_t, value: *const uint64_t) -> hv_return_t;

    /// Sets the address of the guest APIC for a vCPU in the
    /// guest physical address space of the VM
    pub fn hv_vmx_vcpu_set_apic_address(vcpu: hv_vcpuid_t, gpa: hv_gpaddr_t) -> hv_return_t;
}
<commit_msg>Update function signatures in osx::ffi<commit_after>//! Bindings to the Hypervisor Framework

use libc::*;

pub mod consts;

/// Hypervisor Framework return code
pub type hv_return_t = uint32_t;

/// Options for hv_vcpu_create()
pub type hv_vm_options_t = uint64_t;

// Creating and Destroying VM Instances
extern {
    /// Creates a VM instance for the current task
    pub fn hv_vm_create(flags: hv_vm_options_t) -> hv_return_t;

    /// Destroys the VM instance associated with the current task
    pub fn hv_vm_destroy() -> hv_return_t;
}

/// Type of a vCPU ID
pub type hv_vcpuid_t = c_uint;

// Creating and Managing vCPU Instances
extern {
    /// Creates a vCPU instance for the current thread
    pub fn hv_vcpu_create(vcpu: *mut hv_vcpuid_t, flags: hv_vm_options_t) -> hv_return_t;

    /// Executes a vCPU
    pub fn hv_vcpu_run(vcpu: hv_vcpuid_t) -> hv_return_t;

    /// Forces an immediate VMEXIT of a set of vCPUs of the VM
    pub fn hv_vcpu_interrupt(vcpu: *const hv_vcpuid_t, vcpu_count: c_uint) -> hv_return_t;

    /// Returns the cumulative execution time of a vCPU in nanoseconds
    pub fn hv_vcpu_get_exec_time(vcpu: hv_vcpuid_t, time: *mut uint64_t) -> hv_return_t;

    /// Forces flushing of cached vCPU state
    pub fn hv_vcpu_flush(vcpu: hv_vcpuid_t) -> hv_return_t;

    /// Invalidates the TLB of a vCPU
    pub fn hv_vcpu_invalidate_tlb(vcpu: hv_vcpuid_t) -> hv_return_t;

    /// Destroys the vCPU instance associated with the current thread
    pub fn hv_vcpu_destroy(vcpu: hv_vcpuid_t) -> hv_return_t;
}

/// x86 architectural register IDs
#[repr(C)]
pub enum hv_x86_reg_t {
	HV_X86_RIP,
	HV_X86_RFLAGS,
	HV_X86_RAX,
	HV_X86_RCX,
	HV_X86_RDX,
	HV_X86_RBX,
	HV_X86_RSI,
	HV_X86_RDI,
	HV_X86_RSP,
	HV_X86_RBP,
	HV_X86_R8,
	HV_X86_R9,
	HV_X86_R10,
	HV_X86_R11,
	HV_X86_R12,
	HV_X86_R13,
	HV_X86_R14,
	HV_X86_R15,
	HV_X86_CS,
	HV_X86_SS,
	HV_X86_DS,
	HV_X86_ES,
	HV_X86_FS,
	HV_X86_GS,
	HV_X86_IDT_BASE,
	HV_X86_IDT_LIMIT,
	HV_X86_GDT_BASE,
	HV_X86_GDT_LIMIT,
	HV_X86_LDTR,
	HV_X86_LDT_BASE,
	HV_X86_LDT_LIMIT,
	HV_X86_LDT_AR,
	HV_X86_TR,
	HV_X86_TSS_BASE,
	HV_X86_TSS_LIMIT,
	HV_X86_TSS_AR,
	HV_X86_CR0,
	HV_X86_CR1,
	HV_X86_CR2,
	HV_X86_CR3,
	HV_X86_CR4,
	HV_X86_DR0,
	HV_X86_DR1,
	HV_X86_DR2,
	HV_X86_DR3,
	HV_X86_DR4,
	HV_X86_DR5,
	HV_X86_DR6,
	HV_X86_DR7,
	HV_X86_TPR,
	HV_X86_XCR0,
	HV_X86_REGISTERS_MAX,
}

// Accessing Registers
extern {
    /// Returns the current value of an architectural x86 register
    /// of a vCPU
    pub fn hv_vcpu_read_register(vcpu: hv_vcpuid_t, reg: hv_x86_reg_t, value: *mut uint64_t) -> hv_return_t;

    /// Sets the value of an architectural x86 register of a vCPU
    pub fn hv_vcpu_write_register(vcpu: hv_vcpuid_t, reg: hv_x86_reg_t, value: uint64_t) -> hv_return_t;
}

// Accessing Floating Point (FP) State
extern {
    /// Returns the current architectural x86 floating point and
    /// SIMD state of a vCPU
    pub fn hv_vcpu_read_fpstate(vcpu: hv_vcpuid_t, buffer: *mut c_void, size: size_t) -> hv_return_t;

    /// Sets the architectural x86 floating point and SIMD state of
    /// a vCPU
    pub fn hv_vcpu_write_fpstate(vcpu: hv_vcpuid_t, buffer: *const c_void, size: size_t) -> hv_return_t;
}

// Accessing Machine Specific Registers (MSRs)
extern {
    /// Enables an MSR to be used natively by the VM
    pub fn hv_vcpu_enable_native_msr(vcpu: hv_vcpuid_t, msr: uint32_t, enable: bool) -> hv_return_t;

    /// Returns the current value of an MSR of a vCPU
    pub fn hv_vcpu_read_msr(vcpu: hv_vcpuid_t, msr: uint32_t, value: *mut uint64_t) -> hv_return_t;

    /// Set the value of an MSR of a vCPU
    pub fn hv_vcpu_write_msr(vcpu: hv_vcpuid_t, msr: uint32_t, value: *const uint64_t) -> hv_return_t;
}

// Managing Timestamp-Counters (TSC)
extern {
    /// Synchronizes guest Timestamp-Counters (TSC) across all vCPUs
    pub fn hv_vm_sync_tsc(tsc: uint64_t) -> hv_return_t;
}

/// Type of a user virtual address
pub type hv_uvaddr_t = *const c_void;

/// Guest physical memory region permissions for hv_vm_map()
/// and hv_vm_protect()
pub type hv_memory_flags_t = uint64_t;

/// Type of a guest physical address
pub type hv_gpaddr_t = uint64_t;

// Managing Memory Regions
extern {
    /// Maps a region in the virtual address space of the current
    /// task into the guest physical address space of the VM
    pub fn hv_vm_map(uva: hv_uvaddr_t, gpa: hv_gpaddr_t, size: size_t, flags: hv_memory_flags_t) -> hv_return_t;

    /// Unmaps a region in the guest physical address space of the VM
    pub fn hv_vm_unmap(gpa: hv_gpaddr_t, size: size_t) -> hv_return_t;

    /// Modifies the permissions of a region in the guest physical
    /// address space of the VM
    pub fn hv_vm_protect(gpa: hv_gpaddr_t, size: size_t, flags: hv_memory_flags_t) -> hv_return_t;
}

/// Enum type of VMX cabability fields
#[repr(C)]
pub enum hv_vmx_capability_t {
    /// Pin-based VMX capabilities
	HV_VMX_CAP_PINBASED                           = 0,
    /// Primary proc-based VMX capabilities
	HV_VMX_CAP_PROCBASED                          = 1,
    /// Secondary proc-based VMX capabilities
	HV_VMX_CAP_PROCBASED2                         = 2,
    /// VM-entry VMX capabilities
	HV_VMX_CAP_ENTRY                              = 3,
    /// VM-exit VMX capabilities
	HV_VMX_CAP_EXIT                               = 4,
    /// VMX preemption timer frequency
	HV_VMX_CAP_PREEMPTION_TIMER                   = 32
}

// Managing Virtual Machine Control Structure (VMCS)
extern {
    /// Returns the current value of a VMCS field of a vCPU
    pub fn hv_vmx_vcpu_read_vmcs(vcpu: hv_vcpuid_t, field: uint32_t, value: *mut uint64_t) -> hv_return_t;

    /// Sets the value of a VMCS field of a vCPU
    pub fn hv_vmx_vcpu_write_vmcs(vcpu: hv_vcpuid_t, field: uint32_t, value: uint64_t) -> hv_return_t;

    /// Returns the VMX capabilities of the host processor
    pub fn hv_vmx_read_capability(field: hv_vmx_capability_t, value: *mut uint64_t) -> hv_return_t;

    /// Sets the address of the guest APIC for a vCPU in the
    /// guest physical address space of the VM
    pub fn hv_vmx_vcpu_set_apic_address(vcpu: hv_vcpuid_t, gpa: hv_gpaddr_t) -> hv_return_t;
}
<|endoftext|>


<commit_before>use std::io::{FileAccess, FileMode, Open, Read, Truncate};
use std::io::{ReadWrite};
use std::io::{SeekEnd, SeekSet};
use std::io::fs::File;
use std::mem::size_of;

static version: u8 = 1;

// some definitions from kissdb.h

struct Kissdb {
  hash_table_size : u64,
  key_size : u64,
  value_size : u64,
  hash_tables : ~[u64],
  f : std::io::fs::File
}

enum Error {
  ErrorIO,
  ErrorMalloc,
  InvalidParameters,
  CorruptDbFile
}

enum OpenMode {
  ReadOnly,
  RW,
  RWCreate,
  RWReplace
}

fn kissdb_hash(b :&[u8], len: u64) -> u64
{
    let mut hash : u64 = 5381;
    for i in range (0, len) {
        hash = ((hash << 5) + hash) + (b[i] as u64);
    }
    return hash
}

// either
// 1. use the c95 based alloc, realloc and free
// 2. use more rustic something
// maybe trying 2. gives me more knowledge
fn kissdb_open(
    path : &Path,
    orig_mode : OpenMode,
    mut hash_table_size : u64,
    mut key_size : u64,
    mut value_size : u64
    ) -> Option<~ Kissdb>
{
    let (mode, access) : (FileMode, FileAccess) =
        match orig_mode {
            ReadOnly =>  (Open, Read), // rb
            RW => (Open, ReadWrite), // r+b
            RWCreate =>  (Open, ReadWrite), // r+b
            RWReplace => (Truncate, ReadWrite) // w+b
        };
    let mut f_ : Option<File>
        = std::io::fs::File::open_mode(path, mode, access);

    if f_.is_none() {
        match (orig_mode) {
            RWCreate =>
            f_ = std::io::fs::File::open_mode(path, Truncate, ReadWrite), // w+b
            _ => f_ = f_
        }
    };

    match f_ {
        None => return None,
        Some (mut f) =>
        {let kissdb_header_size : u64 = ((size_of::<u64>() * 3) + 4) as u64;

         f.seek(0, SeekEnd);
         if (f.tell() < kissdb_header_size) {
             if hash_table_size > 0 && key_size > 0
                 && value_size >0
             {
                 f.seek(0, SeekSet);
                 let tmp2 : [u8, ..4] = ['K' as u8, 'd' as u8, 'R' as u8, version];
                 f.write(tmp2);
                 f.write_le_u64(hash_table_size);
                 f.write_le_u64(key_size);
                 f.write_le_u64(value_size);
                 f.flush();
             }
             else {
                 fail!()
             }
         }
         else {
             f.seek(0, SeekSet);
             let mut tmp2 : [u8, ..4] = [0,0,0,0];
             if f.read(tmp2) != Some(4) { fail! (); }
             if tmp2 != ['K' as u8, 'd' as u8, 'R' as u8, version] {fail! ();}
             hash_table_size = f.read_le_u64();
             key_size = f.read_le_u64();
             value_size = f.read_le_u64();
         }

         // let hash_table_size_bytes : uint = size_of::<u64>() * (hash_table_size + 1) as uint;
         // let mut httmp = std::vec::from_elem(hash_table_size_bytes, 0 as u8);
         //         let httmp = do std::at_vec::build::<u64>(None) |push| { for i in range(0, hash_table_size + 1)
//                  { push (0); }
        //};

         let mut num_hash_tables = 0;

         // should use at_vec, actually
         // no, std::vec is OK.  It has appends
         let mut hash_tables : ~[u64] = std::vec::from_elem(0, 0 as u64);
         let mut h : Option<~[u64]>;

         // do we do realloc in rust? with append, apparently.
         while({h = f.read_one_hash_table(hash_table_size); h.is_some()})
         {
             let httmp = h.unwrap();
             hash_tables = std::vec::append(hash_tables, httmp);
             num_hash_tables = num_hash_tables + 1;
             if (httmp[hash_table_size] > 0) {
                 f.seek(httmp[hash_table_size] as i64, SeekSet)
             }
             else {
                 break;
             }
         }

         // construct h somehow
         return Some(~Kissdb {hash_table_size : hash_table_size,
                         key_size : key_size,
                         value_size : value_size,
                         hash_tables : hash_tables,
                         f : f})
        }
    }
}

trait File2 {
    fn read_one_hash_table(&mut self, u64) -> Option<~[u64]>;
}

impl File2 for File {
fn read_one_hash_table(&mut self,
                       hash_table_size : u64) -> Option<~[u64]> {
    let bs = (hash_table_size + 1) as uint * size_of::<u64>();
    let mut buf = std::vec::from_elem(bs, 0 as u8);
    let mut result = std::vec::from_elem((hash_table_size + 1) as uint, 0 as u64);
    match self.read(buf) {
        None => None,
        Some(buf_size) if buf_size == bs => {
            let mut br = std::io::mem::BufReader::new(buf);
            for i in range(0, hash_table_size + 1) {
                result[i] = br.read_le_u64();
            }
            Some((result))
        },
        _ => None
    }
}
}

fn main()
{
}
<commit_msg>kissdb_close<commit_after>use std::io::{FileAccess, FileMode, Open, Read, Truncate};
use std::io::{ReadWrite};
use std::io::{SeekEnd, SeekSet};
use std::io::fs::File;
use std::mem::size_of;

static version: u8 = 1;

// some definitions from kissdb.h

struct Kissdb {
  hash_table_size : u64,
  key_size : u64,
  value_size : u64,
  hash_tables : ~[u64],
  f : std::io::fs::File
}

enum Error {
  ErrorIO,
  ErrorMalloc,
  InvalidParameters,
  CorruptDbFile
}

enum OpenMode {
  ReadOnly,
  RW,
  RWCreate,
  RWReplace
}

fn kissdb_hash(b :&[u8], len: u64) -> u64
{
    let mut hash : u64 = 5381;
    for i in range (0, len) {
        hash = ((hash << 5) + hash) + (b[i] as u64);
    }
    return hash
}

// either
// 1. use the c95 based alloc, realloc and free
// 2. use more rustic something
// maybe trying 2. gives me more knowledge
fn kissdb_open(
    path : &Path,
    orig_mode : OpenMode,
    mut hash_table_size : u64,
    mut key_size : u64,
    mut value_size : u64
    ) -> Option<~ Kissdb>
{
    let (mode, access) : (FileMode, FileAccess) =
        match orig_mode {
            ReadOnly =>  (Open, Read), // rb
            RW => (Open, ReadWrite), // r+b
            RWCreate =>  (Open, ReadWrite), // r+b
            RWReplace => (Truncate, ReadWrite) // w+b
        };
    let mut f_ : Option<File>
        = std::io::fs::File::open_mode(path, mode, access);

    if f_.is_none() {
        match (orig_mode) {
            RWCreate =>
            f_ = std::io::fs::File::open_mode(path, Truncate, ReadWrite), // w+b
            _ => f_ = f_
        }
    };

    match f_ {
        None => return None,
        Some (mut f) =>
        {let kissdb_header_size : u64 = ((size_of::<u64>() * 3) + 4) as u64;

         f.seek(0, SeekEnd);
         if (f.tell() < kissdb_header_size) {
             if hash_table_size > 0 && key_size > 0
                 && value_size >0
             {
                 f.seek(0, SeekSet);
                 let tmp2 : [u8, ..4] = ['K' as u8, 'd' as u8, 'R' as u8, version];
                 f.write(tmp2);
                 f.write_le_u64(hash_table_size);
                 f.write_le_u64(key_size);
                 f.write_le_u64(value_size);
                 f.flush();
             }
             else {
                 fail!()
             }
         }
         else {
             f.seek(0, SeekSet);
             let mut tmp2 : [u8, ..4] = [0,0,0,0];
             if f.read(tmp2) != Some(4) { fail! (); }
             if tmp2 != ['K' as u8, 'd' as u8, 'R' as u8, version] {fail! ();}
             hash_table_size = f.read_le_u64();
             key_size = f.read_le_u64();
             value_size = f.read_le_u64();
         }

         // let hash_table_size_bytes : uint = size_of::<u64>() * (hash_table_size + 1) as uint;
         // let mut httmp = std::vec::from_elem(hash_table_size_bytes, 0 as u8);
         //         let httmp = do std::at_vec::build::<u64>(None) |push| { for i in range(0, hash_table_size + 1)
//                  { push (0); }
        //};

         let mut num_hash_tables = 0;

         // should use at_vec, actually
         // no, std::vec is OK.  It has appends
         let mut hash_tables : ~[u64] = std::vec::from_elem(0, 0 as u64);
         let mut h : Option<~[u64]>;

         // do we do realloc in rust? with append, apparently.
         while({h = f.read_one_hash_table(hash_table_size); h.is_some()})
         {
             let httmp = h.unwrap();
             hash_tables = std::vec::append(hash_tables, httmp);
             num_hash_tables = num_hash_tables + 1;
             if (httmp[hash_table_size] > 0) {
                 f.seek(httmp[hash_table_size] as i64, SeekSet)
             }
             else {
                 break;
             }
         }

         // construct h somehow
         return Some(~Kissdb {hash_table_size : hash_table_size,
                         key_size : key_size,
                         value_size : value_size,
                         hash_tables : hash_tables,
                         f : f})
        }
    }
}

trait File2 {
    fn read_one_hash_table(&mut self, u64) -> Option<~[u64]>;
}

impl File2 for File {
        fn read_one_hash_table(&mut self,
                               hash_table_size : u64) -> Option<~[u64]> {
            let bs = (hash_table_size + 1) as uint * size_of::<u64>();
            let mut buf = std::vec::from_elem(bs, 0 as u8);
            let mut result = std::vec::from_elem((hash_table_size + 1) as uint, 0 as u64);
            match self.read(buf) {
                None => None,
                Some(buf_size) if buf_size == bs => {
                    let mut br = std::io::mem::BufReader::new(buf);
                    for i in range(0, hash_table_size + 1) {
                        result[i] = br.read_le_u64();
                    }
                    Some((result))
                },
                _ => None
            }
        }
}

fn kissdb_close(~db : ~Kissdb) {
}

fn main()
{
    let db = kissdb_open(&Path::new("test.db"), RWReplace, 1024, 8, size_of::<u64>() as u64);
    kissdb_close(db.unwrap());
}
<|endoftext|>


<commit_before>use std::io;

use tui::backend::Backend;
use tui::layout::{Constraint, Direction, Layout, Rect};
use tui::style::{Color, Modifier, Style};
use tui::widgets::canvas::{Canvas, Line, Map, MapResolution, Rectangle};
use tui::widgets::{
    Axis, BarChart, Block, Borders, Chart, Dataset, Gauge, List, Marker, Paragraph, Row,
    SelectableList, Sparkline, Table, Tabs, Text, Widget,
};
use tui::{Frame, Terminal};

use crate::demo::App;

pub fn draw<B: Backend>(terminal: &mut Terminal<B>, app: &App) -> Result<(), io::Error> {
    terminal.draw(|mut f| {
        let chunks = Layout::default()
            .constraints([Constraint::Length(3), Constraint::Min(0)].as_ref())
            .split(f.size());
        Tabs::default()
            .block(Block::default().borders(Borders::ALL).title(app.title))
            .titles(&app.tabs.titles)
            .style(Style::default().fg(Color::Green))
            .highlight_style(Style::default().fg(Color::Yellow))
            .select(app.tabs.index)
            .render(&mut f, chunks[0]);
        match app.tabs.index {
            0 => draw_first_tab(&mut f, &app, chunks[1]),
            1 => draw_second_tab(&mut f, &app, chunks[1]),
            _ => {}
        };
    })
}

fn draw_first_tab<B>(f: &mut Frame<B>, app: &App, area: Rect)
where
    B: Backend,
{
    let chunks = Layout::default()
        .constraints(
            [
                Constraint::Length(7),
                Constraint::Min(7),
                Constraint::Length(7),
            ]
            .as_ref(),
        )
        .split(area);
    draw_gauges(f, app, chunks[0]);
    draw_charts(f, app, chunks[1]);
    draw_text(f, chunks[2]);
}

fn draw_gauges<B>(f: &mut Frame<B>, app: &App, area: Rect)
where
    B: Backend,
{
    let chunks = Layout::default()
        .constraints([Constraint::Length(2), Constraint::Length(3)].as_ref())
        .margin(1)
        .split(area);
    Block::default()
        .borders(Borders::ALL)
        .title("Graphs")
        .render(f, area);
    Gauge::default()
        .block(Block::default().title("Gauge:"))
        .style(
            Style::default()
                .fg(Color::Magenta)
                .bg(Color::Black)
                .modifier(Modifier::ITALIC),
        )
        .label(&format!("{} / 100", app.progress))
        .percent(app.progress)
        .render(f, chunks[0]);
    Sparkline::default()
        .block(Block::default().title("Sparkline:"))
        .style(Style::default().fg(Color::Green))
        .data(&app.sparkline.points)
        .render(f, chunks[1]);
}

fn draw_charts<B>(f: &mut Frame<B>, app: &App, area: Rect)
where
    B: Backend,
{
    let constraints = if app.show_chart {
        vec![Constraint::Percentage(50), Constraint::Percentage(50)]
    } else {
        vec![Constraint::Percentage(100)]
    };
    let chunks = Layout::default()
        .constraints(constraints)
        .direction(Direction::Horizontal)
        .split(area);
    {
        let chunks = Layout::default()
            .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
            .split(chunks[0]);
        {
            let chunks = Layout::default()
                .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
                .direction(Direction::Horizontal)
                .split(chunks[0]);
            SelectableList::default()
                .block(Block::default().borders(Borders::ALL).title("List"))
                .items(&app.tasks.items)
                .select(Some(app.tasks.selected))
                .highlight_style(Style::default().fg(Color::Yellow).modifier(Modifier::BOLD))
                .highlight_symbol(">")
                .render(f, chunks[0]);
            let info_style = Style::default().fg(Color::White);
            let warning_style = Style::default().fg(Color::Yellow);
            let error_style = Style::default().fg(Color::Magenta);
            let critical_style = Style::default().fg(Color::Red);
            let events = app.logs.items.iter().map(|&(evt, level)| {
                Text::styled(
                    format!("{}: {}", level, evt),
                    match level {
                        "ERROR" => error_style,
                        "CRITICAL" => critical_style,
                        "WARNING" => warning_style,
                        _ => info_style,
                    },
                )
            });
            List::new(events)
                .block(Block::default().borders(Borders::ALL).title("List"))
                .render(f, chunks[1]);
        }
        BarChart::default()
            .block(Block::default().borders(Borders::ALL).title("Bar chart"))
            .data(&app.barchart)
            .bar_width(3)
            .bar_gap(2)
            .value_style(
                Style::default()
                    .fg(Color::Black)
                    .bg(Color::Green)
                    .modifier(Modifier::ITALIC),
            )
            .label_style(Style::default().fg(Color::Yellow))
            .style(Style::default().fg(Color::Green))
            .render(f, chunks[1]);
    }
    if app.show_chart {
        Chart::default()
            .block(
                Block::default()
                    .title("Chart")
                    .title_style(Style::default().fg(Color::Cyan).modifier(Modifier::BOLD))
                    .borders(Borders::ALL),
            )
            .x_axis(
                Axis::default()
                    .title("X Axis")
                    .style(Style::default().fg(Color::Gray))
                    .labels_style(Style::default().modifier(Modifier::ITALIC))
                    .bounds(app.signals.window)
                    .labels(&[
                        &format!("{}", app.signals.window[0]),
                        &format!("{}", (app.signals.window[0] + app.signals.window[1]) / 2.0),
                        &format!("{}", app.signals.window[1]),
                    ]),
            )
            .y_axis(
                Axis::default()
                    .title("Y Axis")
                    .style(Style::default().fg(Color::Gray))
                    .labels_style(Style::default().modifier(Modifier::ITALIC))
                    .bounds([-20.0, 20.0])
                    .labels(&["-20", "0", "20"]),
            )
            .datasets(&[
                Dataset::default()
                    .name("data2")
                    .marker(Marker::Dot)
                    .style(Style::default().fg(Color::Cyan))
                    .data(&app.signals.sin1.points),
                Dataset::default()
                    .name("data3")
                    .marker(Marker::Braille)
                    .style(Style::default().fg(Color::Yellow))
                    .data(&app.signals.sin2.points),
            ])
            .render(f, chunks[1]);
    }
}

fn draw_text<B>(f: &mut Frame<B>, area: Rect)
where
    B: Backend,
{
    let text = [
        Text::raw("This is a paragraph with several lines. You can change style your text the way you want.\n\nFox example: "),
        Text::styled("under", Style::default().fg(Color::Red)),
        Text::raw(" "),
        Text::styled("the", Style::default().fg(Color::Green)),
        Text::raw(" "),
        Text::styled("rainbow", Style::default().fg(Color::Blue)),
        Text::raw(".\nOh and if you didn't "),
        Text::styled("notice", Style::default().modifier(Modifier::ITALIC)),
        Text::raw(" you can "),
        Text::styled("automatically", Style::default().modifier(Modifier::BOLD)),
        Text::raw(" "),
        Text::styled("wrap", Style::default().modifier(Modifier::REVERSED)),
        Text::raw(" your "),
        Text::styled("text", Style::default().modifier(Modifier::UNDERLINED)),
        Text::raw(".\nOne more thing is that it should display unicode characters: 10€")
    ];
    Paragraph::new(text.iter())
        .block(
            Block::default()
                .borders(Borders::ALL)
                .title("Footer")
                .title_style(Style::default().fg(Color::Magenta).modifier(Modifier::BOLD)),
        )
        .wrap(true)
        .render(f, area);
}

fn draw_second_tab<B>(f: &mut Frame<B>, app: &App, area: Rect)
where
    B: Backend,
{
    let chunks = Layout::default()
        .constraints([Constraint::Percentage(30), Constraint::Percentage(70)].as_ref())
        .direction(Direction::Horizontal)
        .split(area);
    let up_style = Style::default().fg(Color::Green);
    let failure_style = Style::default().fg(Color::Red);
    let header = ["Server", "Location", "Status"];
    let rows = app.servers.iter().map(|s| {
        let style = if s.status == "Up" {
            up_style
        } else {
            failure_style
        };
        Row::StyledData(vec![s.name, s.location, s.status].into_iter(), style)
    });
    Table::new(header.into_iter(), rows)
        .block(Block::default().title("Servers").borders(Borders::ALL))
        .header_style(Style::default().fg(Color::Yellow))
        .widths(&[15, 15, 10])
        .render(f, chunks[0]);

    Canvas::default()
        .block(Block::default().title("World").borders(Borders::ALL))
        .paint(|ctx| {
            ctx.draw(&Map {
                color: Color::White,
                resolution: MapResolution::High,
            });
            ctx.layer();
            ctx.draw(&Rectangle {
                rect: Rect {
                    x: 0,
                    y: 30,
                    width: 10,
                    height: 10,
                },
                color: Color::Yellow,
            });
            for (i, s1) in app.servers.iter().enumerate() {
                for s2 in &app.servers[i + 1..] {
                    ctx.draw(&Line {
                        x1: s1.coords.1,
                        y1: s1.coords.0,
                        y2: s2.coords.0,
                        x2: s2.coords.1,
                        color: Color::Yellow,
                    });
                }
            }
            for server in &app.servers {
                let color = if server.status == "Up" {
                    Color::Green
                } else {
                    Color::Red
                };
                ctx.print(server.coords.1, server.coords.0, "X", color);
            }
        })
        .x_bounds([-180.0, 180.0])
        .y_bounds([-90.0, 90.0])
        .render(f, chunks[1]);
}
<commit_msg>Add modifiers in demo<commit_after>use std::io;

use tui::backend::Backend;
use tui::layout::{Constraint, Direction, Layout, Rect};
use tui::style::{Color, Modifier, Style};
use tui::widgets::canvas::{Canvas, Line, Map, MapResolution, Rectangle};
use tui::widgets::{
    Axis, BarChart, Block, Borders, Chart, Dataset, Gauge, List, Marker, Paragraph, Row,
    SelectableList, Sparkline, Table, Tabs, Text, Widget,
};
use tui::{Frame, Terminal};

use crate::demo::App;

pub fn draw<B: Backend>(terminal: &mut Terminal<B>, app: &App) -> Result<(), io::Error> {
    terminal.draw(|mut f| {
        let chunks = Layout::default()
            .constraints([Constraint::Length(3), Constraint::Min(0)].as_ref())
            .split(f.size());
        Tabs::default()
            .block(Block::default().borders(Borders::ALL).title(app.title))
            .titles(&app.tabs.titles)
            .style(Style::default().fg(Color::Green))
            .highlight_style(Style::default().fg(Color::Yellow))
            .select(app.tabs.index)
            .render(&mut f, chunks[0]);
        match app.tabs.index {
            0 => draw_first_tab(&mut f, &app, chunks[1]),
            1 => draw_second_tab(&mut f, &app, chunks[1]),
            _ => {}
        };
    })
}

fn draw_first_tab<B>(f: &mut Frame<B>, app: &App, area: Rect)
where
    B: Backend,
{
    let chunks = Layout::default()
        .constraints(
            [
                Constraint::Length(7),
                Constraint::Min(7),
                Constraint::Length(7),
            ]
            .as_ref(),
        )
        .split(area);
    draw_gauges(f, app, chunks[0]);
    draw_charts(f, app, chunks[1]);
    draw_text(f, chunks[2]);
}

fn draw_gauges<B>(f: &mut Frame<B>, app: &App, area: Rect)
where
    B: Backend,
{
    let chunks = Layout::default()
        .constraints([Constraint::Length(2), Constraint::Length(3)].as_ref())
        .margin(1)
        .split(area);
    Block::default()
        .borders(Borders::ALL)
        .title("Graphs")
        .render(f, area);
    Gauge::default()
        .block(Block::default().title("Gauge:"))
        .style(
            Style::default()
                .fg(Color::Magenta)
                .bg(Color::Black)
                .modifier(Modifier::ITALIC | Modifier::BOLD),
        )
        .label(&format!("{} / 100", app.progress))
        .percent(app.progress)
        .render(f, chunks[0]);
    Sparkline::default()
        .block(Block::default().title("Sparkline:"))
        .style(Style::default().fg(Color::Green))
        .data(&app.sparkline.points)
        .render(f, chunks[1]);
}

fn draw_charts<B>(f: &mut Frame<B>, app: &App, area: Rect)
where
    B: Backend,
{
    let constraints = if app.show_chart {
        vec![Constraint::Percentage(50), Constraint::Percentage(50)]
    } else {
        vec![Constraint::Percentage(100)]
    };
    let chunks = Layout::default()
        .constraints(constraints)
        .direction(Direction::Horizontal)
        .split(area);
    {
        let chunks = Layout::default()
            .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
            .split(chunks[0]);
        {
            let chunks = Layout::default()
                .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
                .direction(Direction::Horizontal)
                .split(chunks[0]);
            SelectableList::default()
                .block(Block::default().borders(Borders::ALL).title("List"))
                .items(&app.tasks.items)
                .select(Some(app.tasks.selected))
                .highlight_style(Style::default().fg(Color::Yellow).modifier(Modifier::BOLD))
                .highlight_symbol(">")
                .render(f, chunks[0]);
            let info_style = Style::default().fg(Color::White);
            let warning_style = Style::default().fg(Color::Yellow);
            let error_style = Style::default().fg(Color::Magenta);
            let critical_style = Style::default().fg(Color::Red);
            let events = app.logs.items.iter().map(|&(evt, level)| {
                Text::styled(
                    format!("{}: {}", level, evt),
                    match level {
                        "ERROR" => error_style,
                        "CRITICAL" => critical_style,
                        "WARNING" => warning_style,
                        _ => info_style,
                    },
                )
            });
            List::new(events)
                .block(Block::default().borders(Borders::ALL).title("List"))
                .render(f, chunks[1]);
        }
        BarChart::default()
            .block(Block::default().borders(Borders::ALL).title("Bar chart"))
            .data(&app.barchart)
            .bar_width(3)
            .bar_gap(2)
            .value_style(
                Style::default()
                    .fg(Color::Black)
                    .bg(Color::Green)
                    .modifier(Modifier::ITALIC),
            )
            .label_style(Style::default().fg(Color::Yellow))
            .style(Style::default().fg(Color::Green))
            .render(f, chunks[1]);
    }
    if app.show_chart {
        Chart::default()
            .block(
                Block::default()
                    .title("Chart")
                    .title_style(Style::default().fg(Color::Cyan).modifier(Modifier::BOLD))
                    .borders(Borders::ALL),
            )
            .x_axis(
                Axis::default()
                    .title("X Axis")
                    .style(Style::default().fg(Color::Gray))
                    .labels_style(Style::default().modifier(Modifier::ITALIC))
                    .bounds(app.signals.window)
                    .labels(&[
                        &format!("{}", app.signals.window[0]),
                        &format!("{}", (app.signals.window[0] + app.signals.window[1]) / 2.0),
                        &format!("{}", app.signals.window[1]),
                    ]),
            )
            .y_axis(
                Axis::default()
                    .title("Y Axis")
                    .style(Style::default().fg(Color::Gray))
                    .labels_style(Style::default().modifier(Modifier::ITALIC))
                    .bounds([-20.0, 20.0])
                    .labels(&["-20", "0", "20"]),
            )
            .datasets(&[
                Dataset::default()
                    .name("data2")
                    .marker(Marker::Dot)
                    .style(Style::default().fg(Color::Cyan))
                    .data(&app.signals.sin1.points),
                Dataset::default()
                    .name("data3")
                    .marker(Marker::Braille)
                    .style(Style::default().fg(Color::Yellow))
                    .data(&app.signals.sin2.points),
            ])
            .render(f, chunks[1]);
    }
}

fn draw_text<B>(f: &mut Frame<B>, area: Rect)
where
    B: Backend,
{
    let text = [
        Text::raw("This is a paragraph with several lines. You can change style your text the way you want.\n\nFox example: "),
        Text::styled("under", Style::default().fg(Color::Red)),
        Text::raw(" "),
        Text::styled("the", Style::default().fg(Color::Green)),
        Text::raw(" "),
        Text::styled("rainbow", Style::default().fg(Color::Blue)),
        Text::raw(".\nOh and if you didn't "),
        Text::styled("notice", Style::default().modifier(Modifier::ITALIC)),
        Text::raw(" you can "),
        Text::styled("automatically", Style::default().modifier(Modifier::BOLD)),
        Text::raw(" "),
        Text::styled("wrap", Style::default().modifier(Modifier::REVERSED)),
        Text::raw(" your "),
        Text::styled("text", Style::default().modifier(Modifier::UNDERLINED)),
        Text::raw(".\nOne more thing is that it should display unicode characters: 10€")
    ];
    Paragraph::new(text.iter())
        .block(
            Block::default()
                .borders(Borders::ALL)
                .title("Footer")
                .title_style(Style::default().fg(Color::Magenta).modifier(Modifier::BOLD)),
        )
        .wrap(true)
        .render(f, area);
}

fn draw_second_tab<B>(f: &mut Frame<B>, app: &App, area: Rect)
where
    B: Backend,
{
    let chunks = Layout::default()
        .constraints([Constraint::Percentage(30), Constraint::Percentage(70)].as_ref())
        .direction(Direction::Horizontal)
        .split(area);
    let up_style = Style::default().fg(Color::Green);
    let failure_style = Style::default()
        .fg(Color::Red)
        .modifier(Modifier::RAPID_BLINK | Modifier::CROSSED_OUT);
    let header = ["Server", "Location", "Status"];
    let rows = app.servers.iter().map(|s| {
        let style = if s.status == "Up" {
            up_style
        } else {
            failure_style
        };
        Row::StyledData(vec![s.name, s.location, s.status].into_iter(), style)
    });
    Table::new(header.into_iter(), rows)
        .block(Block::default().title("Servers").borders(Borders::ALL))
        .header_style(Style::default().fg(Color::Yellow))
        .widths(&[15, 15, 10])
        .render(f, chunks[0]);

    Canvas::default()
        .block(Block::default().title("World").borders(Borders::ALL))
        .paint(|ctx| {
            ctx.draw(&Map {
                color: Color::White,
                resolution: MapResolution::High,
            });
            ctx.layer();
            ctx.draw(&Rectangle {
                rect: Rect {
                    x: 0,
                    y: 30,
                    width: 10,
                    height: 10,
                },
                color: Color::Yellow,
            });
            for (i, s1) in app.servers.iter().enumerate() {
                for s2 in &app.servers[i + 1..] {
                    ctx.draw(&Line {
                        x1: s1.coords.1,
                        y1: s1.coords.0,
                        y2: s2.coords.0,
                        x2: s2.coords.1,
                        color: Color::Yellow,
                    });
                }
            }
            for server in &app.servers {
                let color = if server.status == "Up" {
                    Color::Green
                } else {
                    Color::Red
                };
                ctx.print(server.coords.1, server.coords.0, "X", color);
            }
        })
        .x_bounds([-180.0, 180.0])
        .y_bounds([-90.0, 90.0])
        .render(f, chunks[1]);
}
<|endoftext|>


<commit_before>use lapin_async::queue::Message;

use std::io;
use futures::{Async,Poll,Stream};
use tokio_io::{AsyncRead,AsyncWrite};
use std::sync::{Arc,Mutex};

use transport::*;

#[derive(Clone)]
pub struct Consumer<T> {
  pub transport:    Arc<Mutex<AMQPTransport<T>>>,
  pub channel_id:   u16,
  pub queue:        String,
  pub consumer_tag: String,
}

impl<T: AsyncRead+AsyncWrite+'static> Stream for Consumer<T> {
  type Item = Message;
  type Error = io::Error;

  fn poll(&mut self) -> Poll<Option<Message>, io::Error> {
    trace!("consumer[{}] poll", self.consumer_tag);
    if let Ok(mut transport) = self.transport.try_lock() {
      //FIXME: if the consumer closed, we should return Ok(Async::Ready(None))
      if let Some(message) = transport.conn.next_message(self.channel_id, &self.queue, &self.consumer_tag) {
        transport.upstream.poll();
        debug!("consumer[{}] ready", self.consumer_tag);
        Ok(Async::Ready(Some(message)))
      } else {
        transport.upstream.poll();
        trace!("consumer[{}] not ready", self.consumer_tag);
        Ok(Async::NotReady)
      }
    } else {
      //FIXME: return an error in case of mutex failure
      return Ok(Async::NotReady);
    }
  }
}

<commit_msg>remove some debug logs<commit_after>use lapin_async::queue::Message;

use std::io;
use futures::{Async,Poll,Stream};
use tokio_io::{AsyncRead,AsyncWrite};
use std::sync::{Arc,Mutex};

use transport::*;

#[derive(Clone)]
pub struct Consumer<T> {
  pub transport:    Arc<Mutex<AMQPTransport<T>>>,
  pub channel_id:   u16,
  pub queue:        String,
  pub consumer_tag: String,
}

impl<T: AsyncRead+AsyncWrite+'static> Stream for Consumer<T> {
  type Item = Message;
  type Error = io::Error;

  fn poll(&mut self) -> Poll<Option<Message>, io::Error> {
    //trace!("consumer[{}] poll", self.consumer_tag);
    if let Ok(mut transport) = self.transport.try_lock() {
      //FIXME: if the consumer closed, we should return Ok(Async::Ready(None))
      if let Some(message) = transport.conn.next_message(self.channel_id, &self.queue, &self.consumer_tag) {
        transport.upstream.poll();
        //debug!("consumer[{}] ready", self.consumer_tag);
        Ok(Async::Ready(Some(message)))
      } else {
        transport.upstream.poll();
        trace!("consumer[{}] not ready", self.consumer_tag);
        Ok(Async::NotReady)
      }
    } else {
      //FIXME: return an error in case of mutex failure
      return Ok(Async::NotReady);
    }
  }
}

<|endoftext|>


<commit_before>extern crate calx;
extern crate content;
extern crate world;

use calx::backend::{Key, Event};
use calx::backend::{WindowBuilder, Canvas, CanvasBuilder};
use content::TerrainType;
use world::Location;

pub fn main() {
    let window = WindowBuilder::new()
                     .set_title("Mapedit")
                     .build();

    let mut builder = CanvasBuilder::new();
    let mut ctx = builder.build(window);

    loop {
        for event in ctx.events().into_iter() {
            match event {
                Event::Quit => {
                    return;
                }
                _ => (),
            }
        }
        ctx.end_frame();
    }
}

pub struct EditState {
    center: Location,
    brush: TerrainType,
}

impl EditState {
    pub fn new() -> EditState {
        EditState {
            center: Location::new(0, 0),
            brush: TerrainType::Rock,
        }
    }
}
<commit_msg>Mapeditor shows scrollable map<commit_after>extern crate calx;
extern crate content;
extern crate world;
extern crate render;

use calx::backend::{Key, Event};
use calx::{Kernel, V2};
use calx::backend::{WindowBuilder, Canvas, CanvasUtil, CanvasBuilder};
use content::TerrainType;
use world::{World, Location};
use world::query;
use render::{chart_to_screen, cells_on_screen, render_terrain};
use render::{Angle, FLOOR_Z, BLOCK_Z};

fn draw_world(w: &World, ctx: &mut Canvas, center: Location) {
    for pt in cells_on_screen() {
        let screen_pos = chart_to_screen(pt);
        let loc = center + pt;

        let k = Kernel::new(|loc| query::terrain(w, loc), loc);
        render_terrain(&k, |img, angle, fore, back| {
            let z = match angle {
                Angle::Up => FLOOR_Z,
                _ => BLOCK_Z,
            };
            ctx.draw_image(img, screen_pos, z, fore, back)
        });
    }
}

pub fn main() {
    let window = WindowBuilder::new()
                     .set_title("Mapedit")
                     .build();

    let mut builder = CanvasBuilder::new();
    content::Brush::init(&mut builder);
    let mut ctx = builder.build(window);

    let mut state = EditState::new();

    loop {
        draw_world(&state.world, &mut ctx, state.center);

        for event in ctx.events().into_iter() {
            match event {
                Event::Quit => return,
                Event::KeyPress(Key::Escape) => return,

                Event::KeyPress(Key::W) => {
                    state.center = state.center + V2(-1, -1)
                }
                Event::KeyPress(Key::S) => {
                    state.center = state.center + V2(1, 1)
                }
                Event::KeyPress(Key::A) => {
                    state.center = state.center + V2(-1, 1)
                }
                Event::KeyPress(Key::D) => {
                    state.center = state.center + V2(1, -1)
                }

                _ => (),
            }
        }
        ctx.end_frame();
    }
}

pub struct EditState {
    world: World,
    center: Location,
    brush: TerrainType,
}

impl EditState {
    pub fn new() -> EditState {
        EditState {
            world: World::new(None),
            center: Location::new(0, 0),
            brush: TerrainType::Rock,
        }
    }
}
<|endoftext|>


<commit_before>use base_db::FileId;
use hir::{EnumVariant, Module, ModuleDef, Name};
use ide_db::{defs::Definition, search::Reference, RootDatabase};
use itertools::Itertools;
use rustc_hash::FxHashSet;
use syntax::{
    algo::find_node_at_offset,
    ast::{self, edit::IndentLevel, ArgListOwner, AstNode, NameOwner, VisibilityOwner},
    SourceFile, TextRange, TextSize,
};

use crate::{
    assist_context::AssistBuilder,
    utils::{insert_use, MergeBehaviour},
    AssistContext, AssistId, AssistKind, Assists,
};
use ast::make;
use insert_use::ImportScope;

// Assist: extract_struct_from_enum_variant
//
// Extracts a struct from enum variant.
//
// ```
// enum A { <|>One(u32, u32) }
// ```
// ->
// ```
// struct One(pub u32, pub u32);
//
// enum A { One(One) }
// ```
pub(crate) fn extract_struct_from_enum_variant(
    acc: &mut Assists,
    ctx: &AssistContext,
) -> Option<()> {
    let variant = ctx.find_node_at_offset::<ast::Variant>()?;
    let field_list = match variant.kind() {
        ast::StructKind::Tuple(field_list) => field_list,
        _ => return None,
    };
    let variant_name = variant.name()?.to_string();
    let variant_hir = ctx.sema.to_def(&variant)?;
    if existing_struct_def(ctx.db(), &variant_name, &variant_hir) {
        return None;
    }
    let enum_ast = variant.parent_enum();
    let visibility = enum_ast.visibility();
    let enum_hir = ctx.sema.to_def(&enum_ast)?;
    let variant_hir_name = variant_hir.name(ctx.db());
    let enum_module_def = ModuleDef::from(enum_hir);
    let current_module = enum_hir.module(ctx.db());
    let target = variant.syntax().text_range();
    acc.add(
        AssistId("extract_struct_from_enum_variant", AssistKind::RefactorRewrite),
        "Extract struct from enum variant",
        target,
        |builder| {
            let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir));
            let res = definition.usages(&ctx.sema).all();
            let start_offset = variant.parent_enum().syntax().text_range().start();
            let mut visited_modules_set = FxHashSet::default();
            visited_modules_set.insert(current_module);
            for reference in res {
                let source_file = ctx.sema.parse(reference.file_range.file_id);
                update_reference(
                    ctx,
                    builder,
                    reference,
                    &source_file,
                    &enum_module_def,
                    &variant_hir_name,
                    &mut visited_modules_set,
                );
            }
            extract_struct_def(
                builder,
                &enum_ast,
                &variant_name,
                &field_list.to_string(),
                start_offset,
                ctx.frange.file_id,
                &visibility,
            );
            let list_range = field_list.syntax().text_range();
            update_variant(builder, &variant_name, ctx.frange.file_id, list_range);
        },
    )
}

fn existing_struct_def(db: &RootDatabase, variant_name: &str, variant: &EnumVariant) -> bool {
    variant
        .parent_enum(db)
        .module(db)
        .scope(db, None)
        .into_iter()
        .any(|(name, _)| name.to_string() == variant_name.to_string())
}

fn insert_import(
    ctx: &AssistContext,
    builder: &mut AssistBuilder,
    path: &ast::PathExpr,
    module: &Module,
    enum_module_def: &ModuleDef,
    variant_hir_name: &Name,
) -> Option<()> {
    let db = ctx.db();
    let mod_path = module.find_use_path(db, enum_module_def.clone());
    if let Some(mut mod_path) = mod_path {
        mod_path.segments.pop();
        mod_path.segments.push(variant_hir_name.clone());
        let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?;
        let syntax = scope.as_syntax_node();

        let new_syntax = insert_use(
            &scope,
            make::path_from_text(&mod_path.to_string()),
            Some(MergeBehaviour::Full),
        );
        builder.replace(syntax.text_range(), new_syntax.to_string())
    }
    Some(())
}

// FIXME: this should use strongly-typed `make`, rather than string manipulation.
fn extract_struct_def(
    builder: &mut AssistBuilder,
    enum_: &ast::Enum,
    variant_name: &str,
    variant_list: &str,
    start_offset: TextSize,
    file_id: FileId,
    visibility: &Option<ast::Visibility>,
) -> Option<()> {
    let visibility_string = if let Some(visibility) = visibility {
        format!("{} ", visibility.to_string())
    } else {
        "".to_string()
    };
    let indent = IndentLevel::from_node(enum_.syntax());
    let struct_def = format!(
        r#"{}struct {}{};

{}"#,
        visibility_string,
        variant_name,
        list_with_visibility(variant_list),
        indent
    );
    builder.edit_file(file_id);
    builder.insert(start_offset, struct_def);
    Some(())
}

fn update_variant(
    builder: &mut AssistBuilder,
    variant_name: &str,
    file_id: FileId,
    list_range: TextRange,
) -> Option<()> {
    let inside_variant_range = TextRange::new(
        list_range.start().checked_add(TextSize::from(1))?,
        list_range.end().checked_sub(TextSize::from(1))?,
    );
    builder.edit_file(file_id);
    builder.replace(inside_variant_range, variant_name);
    Some(())
}

fn update_reference(
    ctx: &AssistContext,
    builder: &mut AssistBuilder,
    reference: Reference,
    source_file: &SourceFile,
    enum_module_def: &ModuleDef,
    variant_hir_name: &Name,
    visited_modules_set: &mut FxHashSet<Module>,
) -> Option<()> {
    let path_expr: ast::PathExpr = find_node_at_offset::<ast::PathExpr>(
        source_file.syntax(),
        reference.file_range.range.start(),
    )?;
    let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
    let list = call.arg_list()?;
    let segment = path_expr.path()?.segment()?;
    let module = ctx.sema.scope(&path_expr.syntax()).module()?;
    let list_range = list.syntax().text_range();
    let inside_list_range = TextRange::new(
        list_range.start().checked_add(TextSize::from(1))?,
        list_range.end().checked_sub(TextSize::from(1))?,
    );
    builder.edit_file(reference.file_range.file_id);
    if !visited_modules_set.contains(&module) {
        if insert_import(ctx, builder, &path_expr, &module, enum_module_def, variant_hir_name)
            .is_some()
        {
            visited_modules_set.insert(module);
        }
    }
    builder.replace(inside_list_range, format!("{}{}", segment, list));
    Some(())
}

fn list_with_visibility(list: &str) -> String {
    list.split(',')
        .map(|part| {
            let index = if part.chars().next().unwrap() == '(' { 1usize } else { 0 };
            let mut mod_part = part.trim().to_string();
            mod_part.insert_str(index, "pub ");
            mod_part
        })
        .join(", ")
}

#[cfg(test)]
mod tests {
    use crate::{
        tests::{check_assist, check_assist_not_applicable},
        utils::FamousDefs,
    };

    use super::*;

    #[test]
    fn test_extract_struct_several_fields() {
        check_assist(
            extract_struct_from_enum_variant,
            "enum A { <|>One(u32, u32) }",
            r#"struct One(pub u32, pub u32);

enum A { One(One) }"#,
        );
    }

    #[test]
    fn test_extract_struct_one_field() {
        check_assist(
            extract_struct_from_enum_variant,
            "enum A { <|>One(u32) }",
            r#"struct One(pub u32);

enum A { One(One) }"#,
        );
    }

    #[test]
    fn test_extract_struct_pub_visibility() {
        check_assist(
            extract_struct_from_enum_variant,
            "pub enum A { <|>One(u32, u32) }",
            r#"pub struct One(pub u32, pub u32);

pub enum A { One(One) }"#,
        );
    }

    #[test]
    fn test_extract_struct_with_complex_imports() {
        check_assist(
            extract_struct_from_enum_variant,
            r#"mod my_mod {
    fn another_fn() {
        let m = my_other_mod::MyEnum::MyField(1, 1);
    }

    pub mod my_other_mod {
        fn another_fn() {
            let m = MyEnum::MyField(1, 1);
        }

        pub enum MyEnum {
            <|>MyField(u8, u8),
        }
    }
}

fn another_fn() {
    let m = my_mod::my_other_mod::MyEnum::MyField(1, 1);
}"#,
            r#"use my_mod::my_other_mod::MyField;

mod my_mod {
    use my_other_mod::MyField;

    fn another_fn() {
        let m = my_other_mod::MyEnum::MyField(MyField(1, 1));
    }

    pub mod my_other_mod {
        fn another_fn() {
            let m = MyEnum::MyField(MyField(1, 1));
        }

        pub struct MyField(pub u8, pub u8);

        pub enum MyEnum {
            MyField(MyField),
        }
    }
}

fn another_fn() {
    let m = my_mod::my_other_mod::MyEnum::MyField(MyField(1, 1));
}"#,
        );
    }

    fn check_not_applicable(ra_fixture: &str) {
        let fixture =
            format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
        check_assist_not_applicable(extract_struct_from_enum_variant, &fixture)
    }

    #[test]
    fn test_extract_enum_not_applicable_for_element_with_no_fields() {
        check_not_applicable("enum A { <|>One }");
    }

    #[test]
    fn test_extract_enum_not_applicable_if_struct_exists() {
        check_not_applicable(
            r#"struct One;
        enum A { <|>One(u8) }"#,
        );
    }
}
<commit_msg>Disable insert_import in extract_struct_from_enum_variant until its fixed<commit_after>use base_db::FileId;
use hir::{EnumVariant, Module, ModuleDef, Name};
use ide_db::{defs::Definition, search::Reference, RootDatabase};
use itertools::Itertools;
use rustc_hash::FxHashSet;
use syntax::{
    algo::find_node_at_offset,
    ast::{self, edit::IndentLevel, ArgListOwner, AstNode, NameOwner, VisibilityOwner},
    SourceFile, TextRange, TextSize,
};

use crate::{
    assist_context::AssistBuilder,
    utils::{insert_use, MergeBehaviour},
    AssistContext, AssistId, AssistKind, Assists,
};
use ast::make;
use insert_use::ImportScope;

// Assist: extract_struct_from_enum_variant
//
// Extracts a struct from enum variant.
//
// ```
// enum A { <|>One(u32, u32) }
// ```
// ->
// ```
// struct One(pub u32, pub u32);
//
// enum A { One(One) }
// ```
pub(crate) fn extract_struct_from_enum_variant(
    acc: &mut Assists,
    ctx: &AssistContext,
) -> Option<()> {
    let variant = ctx.find_node_at_offset::<ast::Variant>()?;
    let field_list = match variant.kind() {
        ast::StructKind::Tuple(field_list) => field_list,
        _ => return None,
    };
    let variant_name = variant.name()?.to_string();
    let variant_hir = ctx.sema.to_def(&variant)?;
    if existing_struct_def(ctx.db(), &variant_name, &variant_hir) {
        return None;
    }
    let enum_ast = variant.parent_enum();
    let visibility = enum_ast.visibility();
    let enum_hir = ctx.sema.to_def(&enum_ast)?;
    let variant_hir_name = variant_hir.name(ctx.db());
    let enum_module_def = ModuleDef::from(enum_hir);
    let current_module = enum_hir.module(ctx.db());
    let target = variant.syntax().text_range();
    acc.add(
        AssistId("extract_struct_from_enum_variant", AssistKind::RefactorRewrite),
        "Extract struct from enum variant",
        target,
        |builder| {
            let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir));
            let res = definition.usages(&ctx.sema).all();
            let start_offset = variant.parent_enum().syntax().text_range().start();
            let mut visited_modules_set = FxHashSet::default();
            visited_modules_set.insert(current_module);
            for reference in res {
                let source_file = ctx.sema.parse(reference.file_range.file_id);
                update_reference(
                    ctx,
                    builder,
                    reference,
                    &source_file,
                    &enum_module_def,
                    &variant_hir_name,
                    &mut visited_modules_set,
                );
            }
            extract_struct_def(
                builder,
                &enum_ast,
                &variant_name,
                &field_list.to_string(),
                start_offset,
                ctx.frange.file_id,
                &visibility,
            );
            let list_range = field_list.syntax().text_range();
            update_variant(builder, &variant_name, ctx.frange.file_id, list_range);
        },
    )
}

fn existing_struct_def(db: &RootDatabase, variant_name: &str, variant: &EnumVariant) -> bool {
    variant
        .parent_enum(db)
        .module(db)
        .scope(db, None)
        .into_iter()
        .any(|(name, _)| name.to_string() == variant_name.to_string())
}

fn insert_import(
    ctx: &AssistContext,
    builder: &mut AssistBuilder,
    path: &ast::PathExpr,
    module: &Module,
    enum_module_def: &ModuleDef,
    variant_hir_name: &Name,
) -> Option<()> {
    let db = ctx.db();
    let mod_path = module.find_use_path(db, enum_module_def.clone());
    if let Some(mut mod_path) = mod_path {
        mod_path.segments.pop();
        mod_path.segments.push(variant_hir_name.clone());
        let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?;
        let syntax = scope.as_syntax_node();

        let new_syntax = insert_use(
            &scope,
            make::path_from_text(&mod_path.to_string()),
            Some(MergeBehaviour::Full),
        );
        // FIXME: this will currently panic as multiple imports will have overlapping text ranges
        builder.replace(syntax.text_range(), new_syntax.to_string())
    }
    Some(())
}

// FIXME: this should use strongly-typed `make`, rather than string manipulation.
fn extract_struct_def(
    builder: &mut AssistBuilder,
    enum_: &ast::Enum,
    variant_name: &str,
    variant_list: &str,
    start_offset: TextSize,
    file_id: FileId,
    visibility: &Option<ast::Visibility>,
) -> Option<()> {
    let visibility_string = if let Some(visibility) = visibility {
        format!("{} ", visibility.to_string())
    } else {
        "".to_string()
    };
    let indent = IndentLevel::from_node(enum_.syntax());
    let struct_def = format!(
        r#"{}struct {}{};

{}"#,
        visibility_string,
        variant_name,
        list_with_visibility(variant_list),
        indent
    );
    builder.edit_file(file_id);
    builder.insert(start_offset, struct_def);
    Some(())
}

fn update_variant(
    builder: &mut AssistBuilder,
    variant_name: &str,
    file_id: FileId,
    list_range: TextRange,
) -> Option<()> {
    let inside_variant_range = TextRange::new(
        list_range.start().checked_add(TextSize::from(1))?,
        list_range.end().checked_sub(TextSize::from(1))?,
    );
    builder.edit_file(file_id);
    builder.replace(inside_variant_range, variant_name);
    Some(())
}

fn update_reference(
    ctx: &AssistContext,
    builder: &mut AssistBuilder,
    reference: Reference,
    source_file: &SourceFile,
    enum_module_def: &ModuleDef,
    variant_hir_name: &Name,
    visited_modules_set: &mut FxHashSet<Module>,
) -> Option<()> {
    let path_expr: ast::PathExpr = find_node_at_offset::<ast::PathExpr>(
        source_file.syntax(),
        reference.file_range.range.start(),
    )?;
    let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
    let list = call.arg_list()?;
    let segment = path_expr.path()?.segment()?;
    let module = ctx.sema.scope(&path_expr.syntax()).module()?;
    let list_range = list.syntax().text_range();
    let inside_list_range = TextRange::new(
        list_range.start().checked_add(TextSize::from(1))?,
        list_range.end().checked_sub(TextSize::from(1))?,
    );
    builder.edit_file(reference.file_range.file_id);
    /* FIXME: this most likely requires AST-based editing, see `insert_import`
    if !visited_modules_set.contains(&module) {
        if insert_import(ctx, builder, &path_expr, &module, enum_module_def, variant_hir_name)
            .is_some()
        {
            visited_modules_set.insert(module);
        }
    }
    */
    builder.replace(inside_list_range, format!("{}{}", segment, list));
    Some(())
}

fn list_with_visibility(list: &str) -> String {
    list.split(',')
        .map(|part| {
            let index = if part.chars().next().unwrap() == '(' { 1usize } else { 0 };
            let mut mod_part = part.trim().to_string();
            mod_part.insert_str(index, "pub ");
            mod_part
        })
        .join(", ")
}

#[cfg(test)]
mod tests {
    use crate::{
        tests::{check_assist, check_assist_not_applicable},
        utils::FamousDefs,
    };

    use super::*;

    #[test]
    fn test_extract_struct_several_fields() {
        check_assist(
            extract_struct_from_enum_variant,
            "enum A { <|>One(u32, u32) }",
            r#"struct One(pub u32, pub u32);

enum A { One(One) }"#,
        );
    }

    #[test]
    fn test_extract_struct_one_field() {
        check_assist(
            extract_struct_from_enum_variant,
            "enum A { <|>One(u32) }",
            r#"struct One(pub u32);

enum A { One(One) }"#,
        );
    }

    #[test]
    fn test_extract_struct_pub_visibility() {
        check_assist(
            extract_struct_from_enum_variant,
            "pub enum A { <|>One(u32, u32) }",
            r#"pub struct One(pub u32, pub u32);

pub enum A { One(One) }"#,
        );
    }

    #[test]
    #[ignore] // FIXME: this currently panics if `insert_import` is used
    fn test_extract_struct_with_complex_imports() {
        check_assist(
            extract_struct_from_enum_variant,
            r#"mod my_mod {
    fn another_fn() {
        let m = my_other_mod::MyEnum::MyField(1, 1);
    }

    pub mod my_other_mod {
        fn another_fn() {
            let m = MyEnum::MyField(1, 1);
        }

        pub enum MyEnum {
            <|>MyField(u8, u8),
        }
    }
}

fn another_fn() {
    let m = my_mod::my_other_mod::MyEnum::MyField(1, 1);
}"#,
            r#"use my_mod::my_other_mod::MyField;

mod my_mod {
    use my_other_mod::MyField;

    fn another_fn() {
        let m = my_other_mod::MyEnum::MyField(MyField(1, 1));
    }

    pub mod my_other_mod {
        fn another_fn() {
            let m = MyEnum::MyField(MyField(1, 1));
        }

        pub struct MyField(pub u8, pub u8);

        pub enum MyEnum {
            MyField(MyField),
        }
    }
}

fn another_fn() {
    let m = my_mod::my_other_mod::MyEnum::MyField(MyField(1, 1));
}"#,
        );
    }

    fn check_not_applicable(ra_fixture: &str) {
        let fixture =
            format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
        check_assist_not_applicable(extract_struct_from_enum_variant, &fixture)
    }

    #[test]
    fn test_extract_enum_not_applicable_for_element_with_no_fields() {
        check_not_applicable("enum A { <|>One }");
    }

    #[test]
    fn test_extract_enum_not_applicable_if_struct_exists() {
        check_not_applicable(
            r#"struct One;
        enum A { <|>One(u8) }"#,
        );
    }
}
<|endoftext|>


<commit_before>extern crate test;

use std::old_io::fs::PathExtensions;
use std::os::getenv;
use std::old_io::File;
use self::test::Bencher;
use racer::codecleaner::code_chunks;
use racer::codeiter::iter_stmts;
use racer::scopes::{mask_comments, mask_sub_scopes};

fn get_rust_file_str(path: &[&str]) -> String {

    let mut src_path = match getenv("RUST_SRC_PATH") {
        Some(env) => { Path::new(&env[]) },
        None => panic!("Cannot find $RUST_SRC_PATH")
    };
    for &s in path.iter() { src_path.push(s); }

    File::open(&src_path).read_to_string().unwrap()
}

#[bench]
fn bench_code_chunks(b: &mut Bencher) {
    let src = &get_rust_file_str(&["libcollections", "bit.rs"])[];
    b.iter(|| {
        let chunks = code_chunks(src).collect::<Vec<_>>();
    });
}

#[bench]
fn bench_iter_stmts(b: &mut Bencher) {
    let src = &get_rust_file_str(&["libcollections", "bit.rs"])[];
    b.iter(|| {
        let chunks = iter_stmts(src).collect::<Vec<_>>();
    });
}

#[bench]
fn bench_mask_comments(b: &mut Bencher) {
    let src = &get_rust_file_str(&["libcollections", "bit.rs"])[];
    b.iter(|| {
        mask_comments(src);
    });
}

#[bench]
fn bench_mask_sub_scopes(b: &mut Bencher) {
    let src = &get_rust_file_str(&["libcollections", "bit.rs"])[];
    b.iter(|| {
        mask_sub_scopes(src);
    });
}

<commit_msg>Add black_boxes to benchs<commit_after>extern crate test;

use std::old_io::fs::PathExtensions;
use std::os::getenv;
use std::old_io::File;
use self::test::Bencher;
use racer::codecleaner::code_chunks;
use racer::codeiter::iter_stmts;
use racer::scopes::{mask_comments, mask_sub_scopes};

fn get_rust_file_str(path: &[&str]) -> String {

    let mut src_path = match getenv("RUST_SRC_PATH") {
        Some(env) => { Path::new(&env[]) },
        None => panic!("Cannot find $RUST_SRC_PATH")
    };
    for &s in path.iter() { src_path.push(s); }

    File::open(&src_path).read_to_string().unwrap()
}

#[bench]
fn bench_code_chunks(b: &mut Bencher) {
    let src = &get_rust_file_str(&["libcollections", "bit.rs"])[];
    b.iter(|| {
        test::black_box(code_chunks(src).collect::<Vec<_>>());
    });
}

#[bench]
fn bench_iter_stmts(b: &mut Bencher) {
    let src = &get_rust_file_str(&["libcollections", "bit.rs"])[];
    b.iter(|| {
        test::black_box(iter_stmts(src).collect::<Vec<_>>());
    });
}

#[bench]
fn bench_mask_comments(b: &mut Bencher) {
    let src = &get_rust_file_str(&["libcollections", "bit.rs"])[];
    b.iter(|| {
        test::black_box(mask_comments(src));
    });
}

#[bench]
fn bench_mask_sub_scopes(b: &mut Bencher) {
    let src = &get_rust_file_str(&["libcollections", "bit.rs"])[];
    b.iter(|| {
        test::black_box(mask_sub_scopes(src));
    });
}

<|endoftext|>