<commit_before>/* Decoder */

use cpu::Op8;
use cpu::Op8::*;
use cpu::Cond;
use cpu::ops::Cont;
use cpu::ops::Cont::*;
use cpu::ops::Instruction;
use cpu::ops::Instruction::*;
use cpu::registers::Reg8::*;
use cpu::registers::Reg16::*;
use cpu::IndirectAddr;

// TODO: add documentation for the macros
macro_rules! imm_type {
    (A   -> $i: ident) => { Ind(IndirectAddr::Imm8($i)) };
    (I   -> $i: ident) => { Imm($i) };
    (I16 -> $i: ident) => { $i };
    (A16 -> $i: ident) => { $i }
}

macro_rules! partial_type {
    (A)   => { Partial8  };
    (I)   => { Partial8  };
    (I16) => { Partial16 };
    (A16) => { Partial16 }
}

macro_rules! instr {
    ($mnem: ident) => {
        Done($mnem)
    };
    ($mnem: ident $t: ident#) => {
        partial_type!($t)(Box::new(|addr| $mnem(imm_type!($t -> addr))))
    };
    ($mnem: ident $op1: expr) => {
        Done($mnem($op1))
    };
    ($mnem: ident $t: ident#, $op2: expr) => {
        partial_type!($t)(Box::new(|addr| $mnem(imm_type!($t -> addr), $op2)))
    };
    ($mnem: ident $op1: expr, $t: ident#) => {
        partial_type!($t)(Box::new(|addr| $mnem($op1, imm_type!($t -> addr))))
    };
    ($mnem: ident $op1: expr, $op2: expr) => {
        Done($mnem($op1, $op2))
    };
}

// Auxiliary macro for decoding instructions of the form:
// | opcode(2) | imm_op(3) | op(3)
//
// These happen a lot in the CB-prefixed instructions
macro_rules! decode_cb_block {
    ($opcode: expr, $instr: ident) => ({
        const OP: u8 = 0x7;
        let op = to_operand($opcode & OP);
        let imm_op = ($opcode >> 3) & OP;
        $instr(imm_op, op)
    })
}

// Auxiliary macro for decoding instructions of the form:
// | opcode(4) | SWITCH_BIT(1) | op(3)
//
// Where the SWITCH_BIT decides which of the two instructions to call.
// These are relatively common, since operands are encoded in 3 bits (op),
// so single-operand instructions only use up 8 mappings.
// Since their opcodes are 4 bits, there are still 8 mappings, which are
// shared with another instruction.
macro_rules! decode_row {
    ($opcode: expr, $instr_set: ident, $instr_unset: ident) => ({
        const SWITCH_BIT: u8 = 0x4;
        let op = to_operand($opcode & 0x7 as u8);
        if $opcode & SWITCH_BIT > 0 {
            $instr_set(op)
        } else {
            $instr_unset(op)
        }
    })
}

fn to_operand(operand: u8) -> Op8 {
    match operand {
        0x0 => Reg(B),
        0x1 => Reg(C),
        0x2 => Reg(D),
        0x3 => Reg(E),
        0x4 => Reg(F),
        0x5 => Reg(L),
        0x6 => Ind(IndirectAddr::HL),
        0x7 => Reg(A),
        _   => panic!("Invalid operand")
    }
}

pub fn decode_cb(code: u8) -> Instruction {
    match code {
        0x00...0x0F => decode_row!(code, RRC, RLC),
        0x10...0x1F => decode_row!(code, RL, RR),
        0x20...0x2F => decode_row!(code, SLA, SRA),
        0x30...0x3F => decode_row!(code, SRL, SWAP),
        0x40...0x7F => decode_cb_block!(code, BIT),
        0x80...0xBF => decode_cb_block!(code, RES),
        0xC0...0xFF => decode_cb_block!(code, SET),
        _ => panic!("warning: Unknown opcode 0xCB{:02x}", code)
    }
}

pub fn decode(opcode: u8) -> Cont<Instruction> {
    match opcode {
        0x76 => instr!(HALT),

        // LD from register to register
        // | 0 1 | op2(3) | op1(3)
        0x40...0x7F => {
            let op1 = to_operand(opcode & 0x7);
            let op2 = to_operand((opcode >> 3) & 0x7);
            Done(LD(op2, op1))
        }

        // ADD and ADC
        // | 1 0 0 0 | CARRY_BIT(1) | operand(3)
        0x80...0x8F => Done(decode_row!(opcode, ADC, ADD)),

        // SUB and SBC
        // | 1 0 0 1 | CARRY_BIT(1) | operand(3)
        0x90...0x9F => Done(decode_row!(opcode, SBC, SUB)),

        // AND and XOR
        // | 1 0 1 0 | XOR_BIT(1) | operand(3)
        0xA0...0xAF => Done(decode_row!(opcode, XOR, AND)),

        // OR and CP
        // | 1 0 1 1 | XOR_BIT(1) | operand(3)
        0xB0...0xBF => Done(decode_row!(opcode, OR, CP)),

        // RST
        // | 1 1 | RST_TO(3) | 1 1 1
        0xC0...0xFF if (opcode & 0x7 == 0x7) => Done(RST(opcode & 0x38)),

        // 8-bit load
        0x06 => instr!(LD Reg(B), I#),

        0x0E => instr!(LD Reg(C), I#),
        0x16 => instr!(LD Reg(D), I#),
        0x1E => instr!(LD Reg(E), I#),
        0x26 => instr!(LD Reg(H), I#),
        0x2E => instr!(LD Reg(L), I#),
        0x3E => instr!(LD Reg(L), I#),
        0x36 => instr!(LD Ind(IndirectAddr::HL), I#),

        0x0A => instr!(LD Reg(A), Ind(IndirectAddr::BC)),
        0x1A => instr!(LD Reg(A), Ind(IndirectAddr::DE)),

        0x02 => instr!(LD Ind(IndirectAddr::BC), Reg(A)),
        0x12 => instr!(LD Ind(IndirectAddr::DE), Reg(A)),

        0xEA => instr!(LD A#, Reg(A)),
        0xFA => instr!(LD Reg(A), A#),

        0xF2 => instr!(LD Ind(IndirectAddr::C), Reg(A)),
        0xE2 => instr!(LD Reg(A), Ind(IndirectAddr::C)),

        0x3A => instr!(LDD Reg(A), Ind(IndirectAddr::HL)),
        0x32 => instr!(LDD Ind(IndirectAddr::HL), Reg(A)),
        0x2A => instr!(LDI Reg(A), Ind(IndirectAddr::HL)),
        0x22 => instr!(LDI Ind(IndirectAddr::HL), Reg(A)),

        0xE0 => instr!(LDH A#, Reg(A)),
        0xF0 => instr!(LDH Reg(A), A#),

        // 16-bit load
        0x01 => instr!(LD16 BC, I16#),
        0x11 => instr!(LD16 DE, I16#),
        0x21 => instr!(LD16 HL, I16#),
        0x31 => instr!(LD16 SP, I16#),

        0xF9 => instr!(LDSPHL),

        0xF8 => instr!(LDHL I#), // TODO: immediate should be signed!

        0x08 => instr!(LDSP A16#),

        0xF5 => instr!(PUSH AF),
        0xC5 => instr!(PUSH BC),
        0xD5 => instr!(PUSH DE),
        0xE5 => instr!(PUSH HL),

        0xF1 => instr!(POP AF),
        0xC1 => instr!(POP BC),
        0xD1 => instr!(POP DE),
        0xE1 => instr!(POP HL),

        0xC6 => instr!(ADD I#),
        0xCE => instr!(ADC I#),

        0xD6 => instr!(SUB I#),
        0xDE => instr!(SBC I#),

        0xE6 => instr!(AND I#),
        0xEE => instr!(XOR I#),

        0xF6 => instr!(OR I#),
        0xFE => instr!(CP I#),

        0x04 => instr!(INC Reg(B)),
        0x0C => instr!(INC Reg(C)),
        0x14 => instr!(INC Reg(D)),
        0x1C => instr!(INC Reg(E)),
        0x24 => instr!(INC Reg(F)),
        0x2C => instr!(INC Reg(L)),
        0x3C => instr!(INC Reg(A)),
        0x34 => instr!(INC Ind(IndirectAddr::HL)),

        0x05 => instr!(DEC Reg(B)),
        0x0D => instr!(DEC Reg(C)),
        0x15 => instr!(DEC Reg(D)),
        0x1D => instr!(DEC Reg(E)),
        0x25 => instr!(DEC Reg(F)),
        0x2D => instr!(DEC Reg(L)),
        0x3D => instr!(DEC Reg(A)),
        0x35 => instr!(DEC Ind(IndirectAddr::HL)),

        0x09 => instr!(ADDHL BC),
        0x19 => instr!(ADDHL DE),
        0x29 => instr!(ADDHL HL),
        0x39 => instr!(ADDHL SP),
        0xE8 => instr!(ADDSP I#),

        0x03 => instr!(INC16 BC),
        0x13 => instr!(INC16 DE),
        0x23 => instr!(INC16 HL),
        0x33 => instr!(INC16 SP),

        0x0B => instr!(DEC16 BC),
        0x1B => instr!(DEC16 DE),
        0x2B => instr!(DEC16 HL),
        0x3B => instr!(DEC16 SP),

        // misc
        0x27 => instr!(DAA),
        0x2F => instr!(CPL),
        0x3F => instr!(CCF),
        0x37 => instr!(SCF),
        0x00 => instr!(NOP),
        0x10 => instr!(STOP),
        0xF3 => instr!(DI),
        0xFB => instr!(EI),

        // rotates and shifts
        0x0F => instr!(RRCA),
        0x1f => instr!(RRA),
        0xCB => Partial8(Box::new(|cb| decode_cb(cb))),

        // control
        0xC3 => instr!(JP A#, Cond::None),
        0xC2 => instr!(JP A#, Cond::NZ),
        0xCA => instr!(JP A#, Cond::Z),
        0xD2 => instr!(JP A#, Cond::NC),
        0xDA => instr!(JP A#, Cond::C),
        0xE9 => instr!(JP Ind(IndirectAddr::HL), Cond::None),

        0x18 => instr!(JR A#, Cond::None),
        0x20 => instr!(JR A#, Cond::NZ),
        0x28 => instr!(JR A#, Cond::Z),
        0x30 => instr!(JR A#, Cond::NC),
        0x38 => instr!(JR A#, Cond::C),

        0xCD => instr!(CALL A#, Cond::None),
        0xC4 => instr!(CALL A#, Cond::NZ),
        0xCC => instr!(CALL A#, Cond::Z),
        0xD4 => instr!(CALL A#, Cond::NC),
        0xDC => instr!(CALL A#, Cond::C),

        0xC9 => instr!(RET Cond::None),
        0xC0 => instr!(RET Cond::NZ),
        0xC8 => instr!(RET Cond::Z),
        0xD0 => instr!(RET Cond::NC),
        0xD8 => instr!(RET Cond::C),

        0xD9 => instr!(RETI),
        0x07 => instr!(RLCA),
        0x17 => instr!(RLCA),

        // UNMAPPED:
        0xD3 => instr!(NOP),
        0xDB => instr!(NOP),
        0xDD => instr!(NOP),
        0xE3 => instr!(NOP),
        0xE4 => instr!(NOP),
        0xEB => instr!(NOP),
        0xEC => instr!(NOP),
        0xED => instr!(NOP),
        0xF4 => instr!(NOP),
        0xFC => instr!(NOP),
        0xFD => instr!(NOP),

        _ => panic!("warning: Unknown opcode 0x{:02x}", opcode)
    }
}
<commit_msg>Generalise 8 bit immediate loading<commit_after>/* Decoder */

use cpu::Op8;
use cpu::Op8::*;
use cpu::Cond;
use cpu::ops::Cont;
use cpu::ops::Cont::*;
use cpu::ops::Instruction;
use cpu::ops::Instruction::*;
use cpu::registers::Reg8::*;
use cpu::registers::Reg16::*;
use cpu::IndirectAddr;

// TODO: add documentation for the macros
macro_rules! imm_type {
    (A   -> $i: ident) => { Ind(IndirectAddr::Imm8($i)) };
    (I   -> $i: ident) => { Imm($i) };
    (I16 -> $i: ident) => { $i };
    (A16 -> $i: ident) => { $i }
}

macro_rules! partial_type {
    (A)   => { Partial8  };
    (I)   => { Partial8  };
    (I16) => { Partial16 };
    (A16) => { Partial16 }
}

macro_rules! instr {
    ($mnem: ident) => {
        Done($mnem)
    };
    ($mnem: ident $t: ident#) => {
        partial_type!($t)(Box::new(|addr| $mnem(imm_type!($t -> addr))))
    };
    ($mnem: ident $op1: expr) => {
        Done($mnem($op1))
    };
    ($mnem: ident $t: ident#, $op2: expr) => {
        partial_type!($t)(Box::new(|addr| $mnem(imm_type!($t -> addr), $op2)))
    };
    ($mnem: ident $op1: expr, $t: ident#) => {
        partial_type!($t)(Box::new(|addr| $mnem($op1, imm_type!($t -> addr))))
    };
    ($mnem: ident $op1: expr, $op2: expr) => {
        Done($mnem($op1, $op2))
    };
}

// Auxiliary macro for decoding instructions of the form:
// | opcode(2) | imm_op(3) | op(3)
//
// These happen a lot in the CB-prefixed instructions
macro_rules! decode_cb_block {
    ($opcode: expr, $instr: ident) => ({
        const OP: u8 = 0x7;
        let op = to_operand($opcode & OP);
        let imm_op = ($opcode >> 3) & OP;
        $instr(imm_op, op)
    })
}

// Auxiliary macro for decoding instructions of the form:
// | opcode(4) | SWITCH_BIT(1) | op(3)
//
// Where the SWITCH_BIT decides which of the two instructions to call.
// These are relatively common, since operands are encoded in 3 bits (op),
// so single-operand instructions only use up 8 mappings.
// Since their opcodes are 4 bits, there are still 8 mappings, which are
// shared with another instruction.
macro_rules! decode_row {
    ($opcode: expr, $instr_set: ident, $instr_unset: ident) => ({
        const SWITCH_BIT: u8 = 0x4;
        let op = to_operand($opcode & 0x7 as u8);
        if $opcode & SWITCH_BIT > 0 {
            $instr_set(op)
        } else {
            $instr_unset(op)
        }
    })
}

fn to_operand(operand: u8) -> Op8 {
    match operand {
        0x0 => Reg(B),
        0x1 => Reg(C),
        0x2 => Reg(D),
        0x3 => Reg(E),
        0x4 => Reg(F),
        0x5 => Reg(L),
        0x6 => Ind(IndirectAddr::HL),
        0x7 => Reg(A),
        _   => panic!("Invalid operand")
    }
}

pub fn decode_cb(code: u8) -> Instruction {
    match code {
        0x00...0x0F => decode_row!(code, RRC, RLC),
        0x10...0x1F => decode_row!(code, RL, RR),
        0x20...0x2F => decode_row!(code, SLA, SRA),
        0x30...0x3F => decode_row!(code, SRL, SWAP),
        0x40...0x7F => decode_cb_block!(code, BIT),
        0x80...0xBF => decode_cb_block!(code, RES),
        0xC0...0xFF => decode_cb_block!(code, SET),
        _ => panic!("warning: Unknown opcode 0xCB{:02x}", code)
    }
}

pub fn decode(opcode: u8) -> Cont<Instruction> {
    match opcode {
        0x76 => instr!(HALT),

        // LD from register to register
        // | 0 1 | op2(3) | op1(3)
        0x40...0x7F => {
            let op1 = to_operand(opcode & 0x7);
            let op2 = to_operand((opcode >> 3) & 0x7);
            Done(LD(op2, op1))
        }

        // ADD and ADC
        // | 1 0 0 0 | CARRY_BIT(1) | operand(3)
        0x80...0x8F => Done(decode_row!(opcode, ADC, ADD)),

        // SUB and SBC
        // | 1 0 0 1 | CARRY_BIT(1) | operand(3)
        0x90...0x9F => Done(decode_row!(opcode, SBC, SUB)),

        // AND and XOR
        // | 1 0 1 0 | XOR_BIT(1) | operand(3)
        0xA0...0xAF => Done(decode_row!(opcode, XOR, AND)),

        // OR and CP
        // | 1 0 1 1 | XOR_BIT(1) | operand(3)
        0xB0...0xBF => Done(decode_row!(opcode, OR, CP)),

        // RST
        // | 1 1 | RST_TO(3) | 1 1 1
        0xC0...0xFF if (opcode & 0x7 == 0x7) => Done(RST(opcode & 0x38)),

        // Load 8 bits
        // | 0 0 | DEST(3)   | 1 1 0
        0x06...0x3E if (opcode & 0x7 == 0x6) => {
            let op = (opcode >> 3) & 0x7;
            Partial8(Box::new(move |val| LD(to_operand(op), Imm(val))))
        },

        0x0A => instr!(LD Reg(A), Ind(IndirectAddr::BC)),
        0x1A => instr!(LD Reg(A), Ind(IndirectAddr::DE)),

        0x02 => instr!(LD Ind(IndirectAddr::BC), Reg(A)),
        0x12 => instr!(LD Ind(IndirectAddr::DE), Reg(A)),

        0xEA => instr!(LD A#, Reg(A)),
        0xFA => instr!(LD Reg(A), A#),

        0xF2 => instr!(LD Ind(IndirectAddr::C), Reg(A)),
        0xE2 => instr!(LD Reg(A), Ind(IndirectAddr::C)),

        0x3A => instr!(LDD Reg(A), Ind(IndirectAddr::HL)),
        0x32 => instr!(LDD Ind(IndirectAddr::HL), Reg(A)),
        0x2A => instr!(LDI Reg(A), Ind(IndirectAddr::HL)),
        0x22 => instr!(LDI Ind(IndirectAddr::HL), Reg(A)),

        0xE0 => instr!(LDH A#, Reg(A)),
        0xF0 => instr!(LDH Reg(A), A#),

        // 16-bit load
        0x01 => instr!(LD16 BC, I16#),
        0x11 => instr!(LD16 DE, I16#),
        0x21 => instr!(LD16 HL, I16#),
        0x31 => instr!(LD16 SP, I16#),

        0xF9 => instr!(LDSPHL),

        0xF8 => instr!(LDHL I#), // TODO: immediate should be signed!

        0x08 => instr!(LDSP A16#),

        0xF5 => instr!(PUSH AF),
        0xC5 => instr!(PUSH BC),
        0xD5 => instr!(PUSH DE),
        0xE5 => instr!(PUSH HL),

        0xF1 => instr!(POP AF),
        0xC1 => instr!(POP BC),
        0xD1 => instr!(POP DE),
        0xE1 => instr!(POP HL),

        0xC6 => instr!(ADD I#),
        0xCE => instr!(ADC I#),

        0xD6 => instr!(SUB I#),
        0xDE => instr!(SBC I#),

        0xE6 => instr!(AND I#),
        0xEE => instr!(XOR I#),

        0xF6 => instr!(OR I#),
        0xFE => instr!(CP I#),

        0x04 => instr!(INC Reg(B)),
        0x0C => instr!(INC Reg(C)),
        0x14 => instr!(INC Reg(D)),
        0x1C => instr!(INC Reg(E)),
        0x24 => instr!(INC Reg(F)),
        0x2C => instr!(INC Reg(L)),
        0x3C => instr!(INC Reg(A)),
        0x34 => instr!(INC Ind(IndirectAddr::HL)),

        0x05 => instr!(DEC Reg(B)),
        0x0D => instr!(DEC Reg(C)),
        0x15 => instr!(DEC Reg(D)),
        0x1D => instr!(DEC Reg(E)),
        0x25 => instr!(DEC Reg(F)),
        0x2D => instr!(DEC Reg(L)),
        0x3D => instr!(DEC Reg(A)),
        0x35 => instr!(DEC Ind(IndirectAddr::HL)),

        0x09 => instr!(ADDHL BC),
        0x19 => instr!(ADDHL DE),
        0x29 => instr!(ADDHL HL),
        0x39 => instr!(ADDHL SP),
        0xE8 => instr!(ADDSP I#),

        0x03 => instr!(INC16 BC),
        0x13 => instr!(INC16 DE),
        0x23 => instr!(INC16 HL),
        0x33 => instr!(INC16 SP),

        0x0B => instr!(DEC16 BC),
        0x1B => instr!(DEC16 DE),
        0x2B => instr!(DEC16 HL),
        0x3B => instr!(DEC16 SP),

        // misc
        0x27 => instr!(DAA),
        0x2F => instr!(CPL),
        0x3F => instr!(CCF),
        0x37 => instr!(SCF),
        0x00 => instr!(NOP),
        0x10 => instr!(STOP),
        0xF3 => instr!(DI),
        0xFB => instr!(EI),

        // rotates and shifts
        0x0F => instr!(RRCA),
        0x1f => instr!(RRA),
        0xCB => Partial8(Box::new(|cb| decode_cb(cb))),

        // control
        0xC3 => instr!(JP A#, Cond::None),
        0xC2 => instr!(JP A#, Cond::NZ),
        0xCA => instr!(JP A#, Cond::Z),
        0xD2 => instr!(JP A#, Cond::NC),
        0xDA => instr!(JP A#, Cond::C),
        0xE9 => instr!(JP Ind(IndirectAddr::HL), Cond::None),

        0x18 => instr!(JR A#, Cond::None),
        0x20 => instr!(JR A#, Cond::NZ),
        0x28 => instr!(JR A#, Cond::Z),
        0x30 => instr!(JR A#, Cond::NC),
        0x38 => instr!(JR A#, Cond::C),

        0xCD => instr!(CALL A#, Cond::None),
        0xC4 => instr!(CALL A#, Cond::NZ),
        0xCC => instr!(CALL A#, Cond::Z),
        0xD4 => instr!(CALL A#, Cond::NC),
        0xDC => instr!(CALL A#, Cond::C),

        0xC9 => instr!(RET Cond::None),
        0xC0 => instr!(RET Cond::NZ),
        0xC8 => instr!(RET Cond::Z),
        0xD0 => instr!(RET Cond::NC),
        0xD8 => instr!(RET Cond::C),

        0xD9 => instr!(RETI),
        0x07 => instr!(RLCA),
        0x17 => instr!(RLCA),

        // UNMAPPED:
        0xD3 => instr!(NOP),
        0xDB => instr!(NOP),
        0xDD => instr!(NOP),
        0xE3 => instr!(NOP),
        0xE4 => instr!(NOP),
        0xEB => instr!(NOP),
        0xEC => instr!(NOP),
        0xED => instr!(NOP),
        0xF4 => instr!(NOP),
        0xFC => instr!(NOP),
        0xFD => instr!(NOP),

        _ => panic!("warning: Unknown opcode 0x{:02x}", opcode)
    }
}
<|endoftext|>


<commit_before>use self::super::MAP;
use self::super::super::{http, Status};

pub fn close(ctn: u16) -> Status {
    // Do we know this CTN?
    if !MAP.lock().contains_key(&ctn) {
        error!("Card terminal has not been opened.");
        return Status::ErrInvalid;
    }

    let pn = MAP.lock().get(&ctn).unwrap().clone();
    let path = format!("ct_close/{}/{}", ctn, pn);
    let response = http::request(&path, None);
    match response {
        Err(why) => {
            error!("{}", why);
            Status::ErrHtsi
        }
        Ok(res) => match res.status {
            200 => handle_ok_status(res.body, ctn),
            _ => {
                error!("Request failed! Server response was not OK!");
                return Status::ErrHtsi;
            }
        },
    }
}

fn handle_ok_status(body: String, ctn: u16) -> Status {
    let status: Status = match body.parse::<Status>() {
        Ok(status) => status,
        _ => {
            error!("Unexpected server reponse body!");
            return Status::ErrHtsi;
        }
    };

    match status {
        Status::OK => {
            // Remove CTN
            MAP.lock().remove(&ctn);
            debug!("Card terminal opened.");
            status
        }
        _ => status,
    }
}

#[cfg(test)]
mod tests {

    use super::close;
    use super::super::MAP;
    use rand;
    use std::env;
    use test_server::{self, hyper};

    #[test]
    fn returns_err_htsi_if_no_server() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        MAP.lock().insert(ctn, pn);

        assert_eq!(-128, close(ctn))
    }

    #[test]
    fn returns_err_invalid_if_already_closed() {
        let ctn = rand::random::<u16>();

        assert_eq!(-1, close(ctn))
    }

    #[test]
    fn use_ctn_and_pn_in_request_path() {
        let server = test_server::serve(None);
        server.reply().status(hyper::BadRequest);
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        close(ctn);

        let (_method, uri, _version, _headers, _body) = server.request().unwrap().deconstruct();

        assert_eq!(format!("/ct_close/{}/{}", ctn, pn), uri.path());
    }

    #[test]
    fn returns_err_htsi_if_server_response_is_not_200() {
        let server = test_server::serve(None);
        server.reply().status(hyper::BadRequest);
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        assert_eq!(-128, close(ctn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));
    }

    #[test]
    fn returns_err_htsi_if_server_response_not_contains_status() {
        let server = test_server::serve(None);
        server.reply().status(hyper::Ok).body("hello world");
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        assert_eq!(-128, close(ctn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));
    }

    #[test]
    fn returns_response_status_from_server() {
        let server = test_server::serve(None);
        server.reply().status(hyper::Ok).body("-11");
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        assert_eq!(-11, close(ctn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));
    }

    #[test]
    fn return_ok_and_close_ctn_if_server_returns_ok() {
        let server = test_server::serve(None);
        server.reply().status(hyper::Ok).body("0");
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        assert_eq!(0, close(ctn));
        assert_eq!(false, MAP.lock().contains_key(&ctn));
    }
}
<commit_msg>fix logging message for closing terminal<commit_after>use self::super::MAP;
use self::super::super::{http, Status};

pub fn close(ctn: u16) -> Status {
    // Do we know this CTN?
    if !MAP.lock().contains_key(&ctn) {
        error!("Card terminal has not been opened.");
        return Status::ErrInvalid;
    }

    let pn = MAP.lock().get(&ctn).unwrap().clone();
    let path = format!("ct_close/{}/{}", ctn, pn);
    let response = http::request(&path, None);
    match response {
        Err(why) => {
            error!("{}", why);
            Status::ErrHtsi
        }
        Ok(res) => match res.status {
            200 => handle_ok_status(res.body, ctn),
            _ => {
                error!("Request failed! Server response was not OK!");
                return Status::ErrHtsi;
            }
        },
    }
}

fn handle_ok_status(body: String, ctn: u16) -> Status {
    let status: Status = match body.parse::<Status>() {
        Ok(status) => status,
        _ => {
            error!("Unexpected server reponse body!");
            return Status::ErrHtsi;
        }
    };

    match status {
        Status::OK => {
            // Remove CTN
            MAP.lock().remove(&ctn);
            debug!("Card terminal closed.");
            status
        }
        _ => status,
    }
}

#[cfg(test)]
mod tests {

    use super::close;
    use super::super::MAP;
    use rand;
    use std::env;
    use test_server::{self, hyper};

    #[test]
    fn returns_err_htsi_if_no_server() {
        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();

        MAP.lock().insert(ctn, pn);

        assert_eq!(-128, close(ctn))
    }

    #[test]
    fn returns_err_invalid_if_already_closed() {
        let ctn = rand::random::<u16>();

        assert_eq!(-1, close(ctn))
    }

    #[test]
    fn use_ctn_and_pn_in_request_path() {
        let server = test_server::serve(None);
        server.reply().status(hyper::BadRequest);
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        close(ctn);

        let (_method, uri, _version, _headers, _body) = server.request().unwrap().deconstruct();

        assert_eq!(format!("/ct_close/{}/{}", ctn, pn), uri.path());
    }

    #[test]
    fn returns_err_htsi_if_server_response_is_not_200() {
        let server = test_server::serve(None);
        server.reply().status(hyper::BadRequest);
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        assert_eq!(-128, close(ctn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));
    }

    #[test]
    fn returns_err_htsi_if_server_response_not_contains_status() {
        let server = test_server::serve(None);
        server.reply().status(hyper::Ok).body("hello world");
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        assert_eq!(-128, close(ctn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));
    }

    #[test]
    fn returns_response_status_from_server() {
        let server = test_server::serve(None);
        server.reply().status(hyper::Ok).body("-11");
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        assert_eq!(-11, close(ctn));
        assert_eq!(true, MAP.lock().contains_key(&ctn));
    }

    #[test]
    fn return_ok_and_close_ctn_if_server_returns_ok() {
        let server = test_server::serve(None);
        server.reply().status(hyper::Ok).body("0");
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let ctn = rand::random::<u16>();
        let pn = rand::random::<u16>();
        MAP.lock().insert(ctn, pn);

        assert_eq!(0, close(ctn));
        assert_eq!(false, MAP.lock().contains_key(&ctn));
    }
}
<|endoftext|>


<commit_before>#![crate_type="staticlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(arc_counts)]
#![feature(augmented_assignments)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(core_str_ext)]
#![feature(core_slice_ext)]
#![feature(fnbox)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(op_assign_traits)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
#![no_std]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

extern crate system;

use acpi::Acpi;

use alloc::boxed::Box;

use collections::string::{String, ToString};
use collections::vec::Vec;

use core::cell::UnsafeCell;
use core::{ptr, mem, usize};
use core::slice::SliceExt;

use common::event::{self, EVENT_KEY, EventOption};
use common::memory;
use common::paging::Page;
use common::time::Duration;

use drivers::pci;
use drivers::io::{Io, Pio};
use drivers::ps2::*;
use drivers::rtc::*;
use drivers::serial::*;

use env::Environment;

use graphics::display;

use scheduler::{Context, Regs, TSS};
use scheduler::context::context_switch;

use schemes::Url;
use schemes::context::*;
use schemes::debug::*;
use schemes::display::*;
use schemes::interrupt::*;
use schemes::memory::*;

use syscall::execute::execute;
use syscall::handle::*;

pub use system::externs::*;

/// Common std-like functionality
#[macro_use]
pub mod common;
#[macro_use]
pub mod macros;
/// Allocation
pub mod alloc_system;
/// ACPI
pub mod acpi;
/// Disk drivers
pub mod disk;
/// Various drivers
pub mod drivers;
/// Environment
pub mod env;
/// Filesystems
pub mod fs;
/// Various graphical methods
pub mod graphics;
/// Panic
pub mod panic;
/// Schemes
pub mod schemes;
/// Scheduling
pub mod scheduler;
/// Sync primatives
pub mod sync;
/// System calls
pub mod syscall;
/// USB input/output
pub mod usb;

pub static mut TSS_PTR: Option<&'static mut TSS> = None;
pub static mut ENV_PTR: Option<&'static mut Environment> = None;

pub fn env() -> &'static Environment {
    unsafe {
        match ENV_PTR {
            Some(&mut ref p) => p,
            None => unreachable!(),
        }
    }
}

/// Pit duration
static PIT_DURATION: Duration = Duration {
    secs: 0,
    nanos: 2250286,
};

/// Idle loop (active while idle)
unsafe fn idle_loop() {
    loop {
        asm!("cli" : : : : "intel", "volatile");

        let mut halt = true;

        for i in env().contexts.lock().iter().skip(1) {
            if i.interrupted {
                halt = false;
                break;
            }
        }

        if halt {
            asm!("sti" : : : : "intel", "volatile");
            asm!("hlt" : : : : "intel", "volatile");
        } else {
            asm!("sti" : : : : "intel", "volatile");
        }

        context_switch(false);
    }
}

/// Event poll loop
fn poll_loop() {
    loop {
        env().on_poll();

        unsafe { context_switch(false) };
    }
}

/// Event loop
fn event_loop() {
    {
        let mut console = env().console.lock();
        console.instant = false;
    }

    let mut cmd = String::new();
    loop {
        loop {
            let mut console = env().console.lock();
            match env().events.lock().pop_front() {
                Some(event) => {
                    if console.draw {
                        match event.to_option() {
                            EventOption::Key(key_event) => {
                                if key_event.pressed {
                                    match key_event.scancode {
                                        event::K_F2 => {
                                            console.draw = false;
                                        }
                                        event::K_BKSP => if !cmd.is_empty() {
                                            console.write(&[8]);
                                            cmd.pop();
                                        },
                                        _ => match key_event.character {
                                            '\0' => (),
                                            '\n' => {
                                                console.command = Some(cmd.clone());

                                                cmd.clear();
                                                console.write(&[10]);
                                            }
                                            _ => {
                                                cmd.push(key_event.character);
                                                console.write(&[key_event.character as u8]);
                                            }
                                        },
                                    }
                                }
                            }
                            _ => (),
                        }
                    } else {
                        if event.code == EVENT_KEY && event.b as u8 == event::K_F1 && event.c > 0 {
                            console.draw = true;
                            console.redraw = true;
                        } else {
                            // TODO: Magical orbital hack
                        }
                    }
                }
                None => break,
            }
        }

        {
            let mut console = env().console.lock();
            console.instant = false;
            if console.draw && console.redraw {
                console.redraw = false;
                console.display.flip();
            }
        }

        unsafe { context_switch(false) };
    }
}

static BSS_TEST_ZERO: usize = 0;
static BSS_TEST_NONZERO: usize = usize::MAX;

/// Initialize kernel
unsafe fn init(tss_data: usize) {

    // Test
    assume!(true);

    // Zero BSS, this initializes statics that are set to 0
    {
        extern {
            static mut __bss_start: u8;
            static mut __bss_end: u8;
        }

        let start_ptr = &mut __bss_start;
        let end_ptr = &mut __bss_end;

        if start_ptr as *const _ as usize <= end_ptr as *const _ as usize {
            let size = end_ptr as *const _ as usize - start_ptr as *const _ as usize;
            memset(start_ptr, 0, size);
        }

        assert_eq!(BSS_TEST_ZERO, 0);
        assert_eq!(BSS_TEST_NONZERO, usize::MAX);
    }

    // Setup paging, this allows for memory allocation
    Page::init();
    memory::cluster_init();
    // Unmap first page to catch null pointer errors (after reading memory map)
    Page::new(0).unmap();

    TSS_PTR = Some(&mut *(tss_data as *mut TSS));
    ENV_PTR = Some(&mut *Box::into_raw(Environment::new()));

    match ENV_PTR {
        Some(ref mut env) => {
            env.contexts.lock().push(Context::root());
            env.console.lock().draw = true;

            debug!("Redox {} bits\n", mem::size_of::<usize>() * 8);

            if let Some(acpi) = Acpi::new() {
                env.schemes.push(UnsafeCell::new(acpi));
            }

            *(env.clock_realtime.lock()) = Rtc::new().time();

            env.schemes.push(UnsafeCell::new(Ps2::new()));
            env.schemes.push(UnsafeCell::new(Serial::new(0x3F8, 0x4)));

            pci::pci_init(env);

            env.schemes.push(UnsafeCell::new(DebugScheme::new()));
            env.schemes.push(UnsafeCell::new(box DisplayScheme));
            env.schemes.push(UnsafeCell::new(box ContextScheme));
            env.schemes.push(UnsafeCell::new(box InterruptScheme));
            env.schemes.push(UnsafeCell::new(box MemoryScheme));

            Context::spawn("kpoll".to_string(),
            box move || {
                poll_loop();
            });

            Context::spawn("kevent".to_string(),
            box move || {
                event_loop();
            });

            env.contexts.lock().enabled = true;

            Context::spawn("kinit".to_string(),
            box move || {
                {
                    let wd_c = "file:/\0";
                    do_sys_chdir(wd_c.as_ptr());

                    let stdio_c = "debug:\0";
                    do_sys_open(stdio_c.as_ptr(), 0);
                    do_sys_open(stdio_c.as_ptr(), 0);
                    do_sys_open(stdio_c.as_ptr(), 0);
                }

                execute(Url::from_str("file:/apps/init/main.bin"), Vec::new());
                debug!("INIT: Failed to execute\n");

                loop {
                    context_switch(false);
                }
            });
        },
        None => unreachable!(),
    }
}

#[cold]
#[inline(never)]
#[no_mangle]
/// Take regs for kernel calls and exceptions
pub extern "cdecl" fn kernel(interrupt: usize, mut regs: &mut Regs) {
    macro_rules! exception_inner {
        ($name:expr) => ({
            {
                let contexts = ::env().contexts.lock();
                if let Some(context) = contexts.current() {
                    debugln!("PID {}: {}", context.pid, context.name);
                }
            }

            debugln!("  INT {:X}: {}", interrupt, $name);
            debugln!("    CS:  {:08X}    IP:  {:08X}    FLG: {:08X}", regs.cs, regs.ip, regs.flags);
            debugln!("    SS:  {:08X}    SP:  {:08X}    BP:  {:08X}", regs.ss, regs.sp, regs.bp);
            debugln!("    AX:  {:08X}    BX:  {:08X}    CX:  {:08X}    DX:  {:08X}", regs.ax, regs.bx, regs.cx, regs.dx);
            debugln!("    DI:  {:08X}    SI:  {:08X}", regs.di, regs.di);

            let cr0: usize;
            let cr2: usize;
            let cr3: usize;
            let cr4: usize;
            unsafe {
                asm!("mov $0, cr0" : "=r"(cr0) : : : "intel", "volatile");
                asm!("mov $0, cr2" : "=r"(cr2) : : : "intel", "volatile");
                asm!("mov $0, cr3" : "=r"(cr3) : : : "intel", "volatile");
                asm!("mov $0, cr4" : "=r"(cr4) : : : "intel", "volatile");
            }
            debugln!("    CR0: {:08X}    CR2: {:08X}    CR3: {:08X}    CR4: {:08X}", cr0, cr2, cr3, cr4);

            let sp = regs.sp as *const u32;
            for y in -15..16 {
                debug!("    {:>3}:", y * 8 * 4);
                for x in 0..8 {
                    debug!(" {:08X}", unsafe { ptr::read(sp.offset(-(x + y * 8))) });
                }
                debug!("\n");
            }
        })
    };

    macro_rules! exception {
        ($name:expr) => ({
            exception_inner!($name);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    macro_rules! exception_error {
        ($name:expr) => ({
            let error = regs.ip;
            regs.ip = regs.cs;
            regs.cs = regs.flags;
            regs.flags = regs.sp;
            regs.sp = regs.ss;
            regs.ss = 0;
            //regs.ss = regs.error;

            exception_inner!($name);
            debugln!("    ERR: {:08X}", error);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    if interrupt >= 0x20 && interrupt < 0x30 {
        if interrupt >= 0x28 {
            Pio::<u8>::new(0xA0).write(0x20);
        }

        Pio::<u8>::new(0x20).write(0x20);
    }

    //Do not catch init interrupt
    if interrupt < 0xFF {
        env().interrupts.lock()[interrupt as usize] += 1;
    }

    match interrupt {
        0x20 => {
            {
                let mut clock_monotonic = env().clock_monotonic.lock();
                *clock_monotonic = *clock_monotonic + PIT_DURATION;
            }
            {
                let mut clock_realtime = env().clock_realtime.lock();
                *clock_realtime = *clock_realtime + PIT_DURATION;
            }

            let switch = {
                let mut contexts = ::env().contexts.lock();
                if let Some(mut context) = contexts.current_mut() {
                    context.slices -= 1;
                    context.slice_total += 1;
                    context.slices == 0
                } else {
                    false
                }
            };

            if switch {
                unsafe { context_switch(true) };
            }
        }
        i @ 0x21 ... 0x2F => env().on_irq(i as u8 - 0x20),
        0x80 => if !syscall_handle(regs) {
            exception!("Unknown Syscall");
        },
        0xFF => {
            unsafe {
                init(regs.ax);
                idle_loop();
            }
        },
        0x0 => exception!("Divide by zero exception"),
        0x1 => exception!("Debug exception"),
        0x2 => exception!("Non-maskable interrupt"),
        0x3 => exception!("Breakpoint exception"),
        0x4 => exception!("Overflow exception"),
        0x5 => exception!("Bound range exceeded exception"),
        0x6 => exception!("Invalid opcode exception"),
        0x7 => exception!("Device not available exception"),
        0x8 => exception_error!("Double fault"),
        0x9 => exception!("Coprocessor Segment Overrun"), // legacy
        0xA => exception_error!("Invalid TSS exception"),
        0xB => exception_error!("Segment not present exception"),
        0xC => exception_error!("Stack-segment fault"),
        0xD => exception_error!("General protection fault"),
        0xE => exception_error!("Page fault"),
        0x10 => exception!("x87 floating-point exception"),
        0x11 => exception_error!("Alignment check exception"),
        0x12 => exception!("Machine check exception"),
        0x13 => exception!("SIMD floating-point exception"),
        0x14 => exception!("Virtualization exception"),
        0x1E => exception_error!("Security exception"),
        _ => exception!("Unknown Interrupt"),
    }
}

#[test]
fn get_slice_test() {
    let array = [1, 2, 3, 4, 5];
    assert_eq!(array.get_slice(2, None), array[2..]);
    assert_eq!(array.get_slice(2, array.len()), array[2..array.len()]);
    assert_eq!(array.get_slice(None, 2), array[..2]);
    assert_eq!(array.get_slice(0, 2), array[0..2]);
    assert_eq!(array.get_slice(1, array.len()), array[1..array.len()]);
    assert_eq!(array.get_slice(1, array.len() + 1), array[1..array.len()]);
    assert_eq!(array.get_slice(array.len(), array.len()),
               array[array.len()..array.len()]);
    assert_eq!(array.get_slice(array.len() + 2, array.len() + 2),
               array[array.len()..array.len()]);
}
<commit_msg>Format idle loop asm<commit_after>#![crate_type="staticlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(arc_counts)]
#![feature(augmented_assignments)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(core_str_ext)]
#![feature(core_slice_ext)]
#![feature(fnbox)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(op_assign_traits)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
#![no_std]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

extern crate system;

use acpi::Acpi;

use alloc::boxed::Box;

use collections::string::{String, ToString};
use collections::vec::Vec;

use core::cell::UnsafeCell;
use core::{ptr, mem, usize};
use core::slice::SliceExt;

use common::event::{self, EVENT_KEY, EventOption};
use common::memory;
use common::paging::Page;
use common::time::Duration;

use drivers::pci;
use drivers::io::{Io, Pio};
use drivers::ps2::*;
use drivers::rtc::*;
use drivers::serial::*;

use env::Environment;

use graphics::display;

use scheduler::{Context, Regs, TSS};
use scheduler::context::context_switch;

use schemes::Url;
use schemes::context::*;
use schemes::debug::*;
use schemes::display::*;
use schemes::interrupt::*;
use schemes::memory::*;

use syscall::execute::execute;
use syscall::handle::*;

pub use system::externs::*;

/// Common std-like functionality
#[macro_use]
pub mod common;
#[macro_use]
pub mod macros;
/// Allocation
pub mod alloc_system;
/// ACPI
pub mod acpi;
/// Disk drivers
pub mod disk;
/// Various drivers
pub mod drivers;
/// Environment
pub mod env;
/// Filesystems
pub mod fs;
/// Various graphical methods
pub mod graphics;
/// Panic
pub mod panic;
/// Schemes
pub mod schemes;
/// Scheduling
pub mod scheduler;
/// Sync primatives
pub mod sync;
/// System calls
pub mod syscall;
/// USB input/output
pub mod usb;

pub static mut TSS_PTR: Option<&'static mut TSS> = None;
pub static mut ENV_PTR: Option<&'static mut Environment> = None;

pub fn env() -> &'static Environment {
    unsafe {
        match ENV_PTR {
            Some(&mut ref p) => p,
            None => unreachable!(),
        }
    }
}

/// Pit duration
static PIT_DURATION: Duration = Duration {
    secs: 0,
    nanos: 2250286,
};

/// Idle loop (active while idle)
unsafe fn idle_loop() {
    loop {
        asm!("cli" : : : : "intel", "volatile");

        let mut halt = true;

        for i in env().contexts.lock().iter().skip(1) {
            if i.interrupted {
                halt = false;
                break;
            }
        }

        if halt {
            asm!("sti
                  hlt"
                  :
                  :
                  :
                  : "intel", "volatile");
        } else {
            asm!("sti"
                :
                :
                :
                : "intel", "volatile");
        }

        context_switch(false);
    }
}

/// Event poll loop
fn poll_loop() {
    loop {
        env().on_poll();

        unsafe { context_switch(false) };
    }
}

/// Event loop
fn event_loop() {
    {
        let mut console = env().console.lock();
        console.instant = false;
    }

    let mut cmd = String::new();
    loop {
        loop {
            let mut console = env().console.lock();
            match env().events.lock().pop_front() {
                Some(event) => {
                    if console.draw {
                        match event.to_option() {
                            EventOption::Key(key_event) => {
                                if key_event.pressed {
                                    match key_event.scancode {
                                        event::K_F2 => {
                                            console.draw = false;
                                        }
                                        event::K_BKSP => if !cmd.is_empty() {
                                            console.write(&[8]);
                                            cmd.pop();
                                        },
                                        _ => match key_event.character {
                                            '\0' => (),
                                            '\n' => {
                                                console.command = Some(cmd.clone());

                                                cmd.clear();
                                                console.write(&[10]);
                                            }
                                            _ => {
                                                cmd.push(key_event.character);
                                                console.write(&[key_event.character as u8]);
                                            }
                                        },
                                    }
                                }
                            }
                            _ => (),
                        }
                    } else {
                        if event.code == EVENT_KEY && event.b as u8 == event::K_F1 && event.c > 0 {
                            console.draw = true;
                            console.redraw = true;
                        } else {
                            // TODO: Magical orbital hack
                        }
                    }
                }
                None => break,
            }
        }

        {
            let mut console = env().console.lock();
            console.instant = false;
            if console.draw && console.redraw {
                console.redraw = false;
                console.display.flip();
            }
        }

        unsafe { context_switch(false) };
    }
}

static BSS_TEST_ZERO: usize = 0;
static BSS_TEST_NONZERO: usize = usize::MAX;

/// Initialize kernel
unsafe fn init(tss_data: usize) {

    // Test
    assume!(true);

    // Zero BSS, this initializes statics that are set to 0
    {
        extern {
            static mut __bss_start: u8;
            static mut __bss_end: u8;
        }

        let start_ptr = &mut __bss_start;
        let end_ptr = &mut __bss_end;

        if start_ptr as *const _ as usize <= end_ptr as *const _ as usize {
            let size = end_ptr as *const _ as usize - start_ptr as *const _ as usize;
            memset(start_ptr, 0, size);
        }

        assert_eq!(BSS_TEST_ZERO, 0);
        assert_eq!(BSS_TEST_NONZERO, usize::MAX);
    }

    // Setup paging, this allows for memory allocation
    Page::init();
    memory::cluster_init();
    // Unmap first page to catch null pointer errors (after reading memory map)
    Page::new(0).unmap();

    TSS_PTR = Some(&mut *(tss_data as *mut TSS));
    ENV_PTR = Some(&mut *Box::into_raw(Environment::new()));

    match ENV_PTR {
        Some(ref mut env) => {
            env.contexts.lock().push(Context::root());
            env.console.lock().draw = true;

            debug!("Redox {} bits\n", mem::size_of::<usize>() * 8);

            if let Some(acpi) = Acpi::new() {
                env.schemes.push(UnsafeCell::new(acpi));
            }

            *(env.clock_realtime.lock()) = Rtc::new().time();

            env.schemes.push(UnsafeCell::new(Ps2::new()));
            env.schemes.push(UnsafeCell::new(Serial::new(0x3F8, 0x4)));

            pci::pci_init(env);

            env.schemes.push(UnsafeCell::new(DebugScheme::new()));
            env.schemes.push(UnsafeCell::new(box DisplayScheme));
            env.schemes.push(UnsafeCell::new(box ContextScheme));
            env.schemes.push(UnsafeCell::new(box InterruptScheme));
            env.schemes.push(UnsafeCell::new(box MemoryScheme));

            Context::spawn("kpoll".to_string(),
            box move || {
                poll_loop();
            });

            Context::spawn("kevent".to_string(),
            box move || {
                event_loop();
            });

            env.contexts.lock().enabled = true;

            Context::spawn("kinit".to_string(),
            box move || {
                {
                    let wd_c = "file:/\0";
                    do_sys_chdir(wd_c.as_ptr());

                    let stdio_c = "debug:\0";
                    do_sys_open(stdio_c.as_ptr(), 0);
                    do_sys_open(stdio_c.as_ptr(), 0);
                    do_sys_open(stdio_c.as_ptr(), 0);
                }

                execute(Url::from_str("file:/apps/init/main.bin"), Vec::new());
                debug!("INIT: Failed to execute\n");

                loop {
                    context_switch(false);
                }
            });
        },
        None => unreachable!(),
    }
}

#[cold]
#[inline(never)]
#[no_mangle]
/// Take regs for kernel calls and exceptions
pub extern "cdecl" fn kernel(interrupt: usize, mut regs: &mut Regs) {
    macro_rules! exception_inner {
        ($name:expr) => ({
            {
                let contexts = ::env().contexts.lock();
                if let Some(context) = contexts.current() {
                    debugln!("PID {}: {}", context.pid, context.name);
                }
            }

            debugln!("  INT {:X}: {}", interrupt, $name);
            debugln!("    CS:  {:08X}    IP:  {:08X}    FLG: {:08X}", regs.cs, regs.ip, regs.flags);
            debugln!("    SS:  {:08X}    SP:  {:08X}    BP:  {:08X}", regs.ss, regs.sp, regs.bp);
            debugln!("    AX:  {:08X}    BX:  {:08X}    CX:  {:08X}    DX:  {:08X}", regs.ax, regs.bx, regs.cx, regs.dx);
            debugln!("    DI:  {:08X}    SI:  {:08X}", regs.di, regs.di);

            let cr0: usize;
            let cr2: usize;
            let cr3: usize;
            let cr4: usize;
            unsafe {
                asm!("mov $0, cr0" : "=r"(cr0) : : : "intel", "volatile");
                asm!("mov $0, cr2" : "=r"(cr2) : : : "intel", "volatile");
                asm!("mov $0, cr3" : "=r"(cr3) : : : "intel", "volatile");
                asm!("mov $0, cr4" : "=r"(cr4) : : : "intel", "volatile");
            }
            debugln!("    CR0: {:08X}    CR2: {:08X}    CR3: {:08X}    CR4: {:08X}", cr0, cr2, cr3, cr4);

            let sp = regs.sp as *const u32;
            for y in -15..16 {
                debug!("    {:>3}:", y * 8 * 4);
                for x in 0..8 {
                    debug!(" {:08X}", unsafe { ptr::read(sp.offset(-(x + y * 8))) });
                }
                debug!("\n");
            }
        })
    };

    macro_rules! exception {
        ($name:expr) => ({
            exception_inner!($name);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    macro_rules! exception_error {
        ($name:expr) => ({
            let error = regs.ip;
            regs.ip = regs.cs;
            regs.cs = regs.flags;
            regs.flags = regs.sp;
            regs.sp = regs.ss;
            regs.ss = 0;
            //regs.ss = regs.error;

            exception_inner!($name);
            debugln!("    ERR: {:08X}", error);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    if interrupt >= 0x20 && interrupt < 0x30 {
        if interrupt >= 0x28 {
            Pio::<u8>::new(0xA0).write(0x20);
        }

        Pio::<u8>::new(0x20).write(0x20);
    }

    //Do not catch init interrupt
    if interrupt < 0xFF {
        env().interrupts.lock()[interrupt as usize] += 1;
    }

    match interrupt {
        0x20 => {
            {
                let mut clock_monotonic = env().clock_monotonic.lock();
                *clock_monotonic = *clock_monotonic + PIT_DURATION;
            }
            {
                let mut clock_realtime = env().clock_realtime.lock();
                *clock_realtime = *clock_realtime + PIT_DURATION;
            }

            let switch = {
                let mut contexts = ::env().contexts.lock();
                if let Some(mut context) = contexts.current_mut() {
                    context.slices -= 1;
                    context.slice_total += 1;
                    context.slices == 0
                } else {
                    false
                }
            };

            if switch {
                unsafe { context_switch(true) };
            }
        }
        i @ 0x21 ... 0x2F => env().on_irq(i as u8 - 0x20),
        0x80 => if !syscall_handle(regs) {
            exception!("Unknown Syscall");
        },
        0xFF => {
            unsafe {
                init(regs.ax);
                idle_loop();
            }
        },
        0x0 => exception!("Divide by zero exception"),
        0x1 => exception!("Debug exception"),
        0x2 => exception!("Non-maskable interrupt"),
        0x3 => exception!("Breakpoint exception"),
        0x4 => exception!("Overflow exception"),
        0x5 => exception!("Bound range exceeded exception"),
        0x6 => exception!("Invalid opcode exception"),
        0x7 => exception!("Device not available exception"),
        0x8 => exception_error!("Double fault"),
        0x9 => exception!("Coprocessor Segment Overrun"), // legacy
        0xA => exception_error!("Invalid TSS exception"),
        0xB => exception_error!("Segment not present exception"),
        0xC => exception_error!("Stack-segment fault"),
        0xD => exception_error!("General protection fault"),
        0xE => exception_error!("Page fault"),
        0x10 => exception!("x87 floating-point exception"),
        0x11 => exception_error!("Alignment check exception"),
        0x12 => exception!("Machine check exception"),
        0x13 => exception!("SIMD floating-point exception"),
        0x14 => exception!("Virtualization exception"),
        0x1E => exception_error!("Security exception"),
        _ => exception!("Unknown Interrupt"),
    }
}

#[test]
fn get_slice_test() {
    let array = [1, 2, 3, 4, 5];
    assert_eq!(array.get_slice(2, None), array[2..]);
    assert_eq!(array.get_slice(2, array.len()), array[2..array.len()]);
    assert_eq!(array.get_slice(None, 2), array[..2]);
    assert_eq!(array.get_slice(0, 2), array[0..2]);
    assert_eq!(array.get_slice(1, array.len()), array[1..array.len()]);
    assert_eq!(array.get_slice(1, array.len() + 1), array[1..array.len()]);
    assert_eq!(array.get_slice(array.len(), array.len()),
               array[array.len()..array.len()]);
    assert_eq!(array.get_slice(array.len() + 2, array.len() + 2),
               array[array.len()..array.len()]);
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2020 Fabian Schuiki

use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{
    parse::{Parse, ParseStream},
    DeriveInput,
};

pub(crate) fn node(args: TokenStream, input: TokenStream) -> TokenStream {
    // Parse the input.
    let args = syn::parse_macro_input!(args as NodeConfig);
    let mut input = syn::parse_macro_input!(input as DeriveInput);

    // Extract the name of the node.
    let vis = input.vis.clone();
    let generics = input.generics.clone();
    let node_name = input.ident.clone();

    // Rename the node.
    let data_name = format_ident!("{}{}", node_name, "Data");
    input.ident = data_name.clone();

    // Generate the wrapper node.
    let mut output = proc_macro2::TokenStream::new();
    output.extend(quote! {
        #vis type #node_name #generics = Node<'a, #data_name #generics>;
    });

    // Emit the modified data.
    output.extend(quote! {
        #[derive(moore_derive::AcceptVisitor)]
        #input
    });

    // match &input.data {
    //     syn::Data::Struct(input) => println!("found struct {:?}", input),
    //     syn::Data::Enum(input) => println!("found enum {:?}", input),
    //     _ => panic!("unsupported item"),
    // }

    output.into()
}

struct NodeConfig {}

impl Parse for NodeConfig {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        Ok(NodeConfig {})
    }
}
<commit_msg>derive: Fix warnings<commit_after>// Copyright (c) 2016-2020 Fabian Schuiki

use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{
    parse::{Parse, ParseStream},
    DeriveInput,
};

pub(crate) fn node(args: TokenStream, input: TokenStream) -> TokenStream {
    // Parse the input.
    let _args = syn::parse_macro_input!(args as NodeConfig);
    let mut input = syn::parse_macro_input!(input as DeriveInput);

    // Extract the name of the node.
    let vis = input.vis.clone();
    let generics = input.generics.clone();
    let node_name = input.ident.clone();

    // Rename the node.
    let data_name = format_ident!("{}{}", node_name, "Data");
    input.ident = data_name.clone();

    // Generate the wrapper node.
    let mut output = proc_macro2::TokenStream::new();
    output.extend(quote! {
        #vis type #node_name #generics = Node<'a, #data_name #generics>;
    });

    // Emit the modified data.
    output.extend(quote! {
        #[derive(moore_derive::AcceptVisitor)]
        #input
    });

    // match &input.data {
    //     syn::Data::Struct(input) => println!("found struct {:?}", input),
    //     syn::Data::Enum(input) => println!("found enum {:?}", input),
    //     _ => panic!("unsupported item"),
    // }

    output.into()
}

struct NodeConfig {}

impl Parse for NodeConfig {
    fn parse(_input: ParseStream) -> syn::Result<Self> {
        Ok(NodeConfig {})
    }
}
<|endoftext|>


<commit_before>use std::ptr::null;
use std::str::raw;
use libc::{c_int, c_char, c_double};
use sync::mutex::{StaticMutex, MUTEX_INIT};

#[link(name="gdal")]
extern {
    fn OGRRegisterAll();
    fn OGROpen(pszName: *c_char, bUpdate: c_int, pahDriverList: *()) -> *();
    fn OGR_DS_GetLayerCount(hDS: *()) -> c_int;
    fn OGR_DS_Destroy(hDataSource: *());
    fn OGR_DS_GetLayer(hDS: *(), iLayer: c_int) -> *();
    fn OGR_L_GetNextFeature(hLayer: *()) -> *();
    fn OGR_F_GetFieldIndex(hFeat: *(), pszName: *c_char) -> c_int;
    fn OGR_F_GetFieldDefnRef(hFeat: *(), i: c_int) -> *();
    fn OGR_F_GetFieldAsString(hFeat: *(), iField: c_int) -> *c_char;
    fn OGR_F_GetFieldAsDouble(hFeat: *(), iField: c_int) -> c_double;
    fn OGR_F_GetGeometryRef(hFeat: *()) -> *();
    fn OGR_F_Destroy(hFeat: *());
    fn OGR_G_ExportToWkt(hGeom: *(), ppszSrcText: **c_char) -> c_int;
    fn OGR_Fld_GetType(hDefn: *()) -> c_int;
    fn OGRFree(ptr: *());
}

static OFTInteger:        c_int = 0;
static OFTIntegerList:    c_int = 1;
static OFTReal:           c_int = 2;
static OFTRealList:       c_int = 3;
static OFTString:         c_int = 4;
static OFTStringList:     c_int = 5;
static OFTWideString:     c_int = 6;
static OFTWideStringList: c_int = 7;
static OFTBinary:         c_int = 8;
static OFTDate:           c_int = 9;
static OFTTime:           c_int = 10;
static OFTDateTime:       c_int = 11;

static mut LOCK: StaticMutex = MUTEX_INIT;
static mut registered_drivers: bool = false;

fn register_drivers() {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            OGRRegisterAll();
            registered_drivers = true;
        }
    }
}

pub struct VectorDataset {
    c_dataset: *(),
}

impl VectorDataset {
    pub fn get_layer_count(&self) -> int {
        return unsafe { OGR_DS_GetLayerCount(self.c_dataset) } as int;
    }

    pub fn get_layer<'a>(&'a self, idx: int) -> Option<Layer<'a>> {
        let c_layer = unsafe { OGR_DS_GetLayer(self.c_dataset, idx as c_int) };
        return match c_layer.is_null() {
            true  => None,
            false => Some(Layer{vector_dataset: self, c_layer: c_layer}),
        };
    }
}

impl Drop for VectorDataset {
    fn drop(&mut self) {
        unsafe { OGR_DS_Destroy(self.c_dataset); }
    }
}

pub struct Layer<'a> {
    vector_dataset: &'a VectorDataset,
    c_layer: *(),
}

impl<'a> Layer<'a> {
    pub fn features<'a>(&'a self) -> FeatureIterator<'a> {
        return FeatureIterator{layer: self};
    }
}

pub struct FeatureIterator<'a> {
    layer: &'a Layer<'a>,
}

impl<'a> Iterator<Feature<'a>> for FeatureIterator<'a> {
    #[inline]
    fn next(&mut self) -> Option<Feature<'a>> {
        let c_feature = unsafe { OGR_L_GetNextFeature(self.layer.c_layer) };
        return match c_feature.is_null() {
            true  => None,
            false => Some(Feature{layer: self.layer, c_feature: c_feature}),
        };
    }
}

pub struct Feature<'a> {
    layer: &'a Layer<'a>,
    c_feature: *(),
}

impl<'a> Feature<'a> {
    pub fn get_field(&self, name: String) -> Option<FieldValue> {
        return name.with_c_str(|c_name| unsafe {
            let field_id = OGR_F_GetFieldIndex(self.c_feature, c_name);
            if field_id == -1 {
                return None;
            }
            let field_defn = OGR_F_GetFieldDefnRef(self.c_feature, field_id);
            let field_type = OGR_Fld_GetType(field_defn);
            return match field_type {
                OFTString => {
                    let rv = OGR_F_GetFieldAsString(self.c_feature, field_id);
                    return Some(StringValue(raw::from_c_str(rv)));
                },
                OFTReal => {
                    let rv = OGR_F_GetFieldAsDouble(self.c_feature, field_id);
                    return Some(F64Value(rv as f64));
                },
                _ => fail!("Unknown field type {}", field_type)
            }
        });
    }

    pub fn get_wkt(&self) -> String {
        unsafe {
            let c_geom = OGR_F_GetGeometryRef(self.c_feature);
            let c_wkt: *c_char = null();
            OGR_G_ExportToWkt(c_geom, &c_wkt);
            let wkt = raw::from_c_str(c_wkt);
            OGRFree(c_wkt as *());
            return wkt;
        }
    }
}

#[unsafe_destructor]
impl<'a> Drop for Feature<'a> {
    fn drop(&mut self) {
        unsafe { OGR_F_Destroy(self.c_feature); }
    }
}

pub fn open(path: &Path) -> Option<VectorDataset> {
    register_drivers();
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        return unsafe { OGROpen(c_filename, 0, null()) };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(VectorDataset{c_dataset: c_dataset}),
    };
}

pub enum FieldValue {
    StringValue(String),
    F64Value(f64),
}

impl FieldValue {
    pub fn as_string(self) -> String {
        match self { StringValue(rv) => rv, _ => fail!("not a string") }
    }

    pub fn as_f64(self) -> f64 {
        match self { F64Value(rv) => rv, _ => fail!("not an f64") }
    }
}

#[cfg(test)]
mod test {
    use std::os::getenv;
    use std::path::Path;
    use super::{Feature, open};

    fn fixture_path(name: &str) -> Path {
        let envvar = "RUST_GDAL_TEST_FIXTURES";
        let fixtures = match getenv(envvar) {
            Some(p) => Path::new(p),
            None => fail!("Environment variable {} not set", envvar)
        };
        let rv = fixtures.join(name);
        return rv;
    }

    fn assert_almost_eq(a: f64, b: f64) {
        let f: f64 = a / b;
        assert!(f < 1.00001);
        assert!(f > 0.99999);
    }

    #[test]
    fn test_layer_count() {
        let ds = open(&fixture_path("roads.geojson")).unwrap();
        assert_eq!(ds.get_layer_count(), 1);
    }

    #[test]
    fn test_iterate_features() {
        let ds = open(&fixture_path("roads.geojson")).unwrap();
        let layer = ds.get_layer(0).unwrap();
        let features: Vec<Feature> = layer.features().collect();
        assert_eq!(features.len(), 21);
    }

    #[test]
    fn test_get_string_field() {
        let ds = open(&fixture_path("roads.geojson")).unwrap();
        let layer = ds.get_layer(0).unwrap();
        let feature = layer.features().next().unwrap();
        assert_eq!(feature.get_field("highway".to_string()).unwrap().as_string(),
                   "footway".to_string());
        assert_eq!(
            layer.features()
                 .count(|f|
                    f.get_field("highway".to_string()).unwrap().as_string() ==
                    "residential".to_string()),
            2);
    }

    #[test]
    fn test_get_float_field() {
        let ds = open(&fixture_path("roads.geojson")).unwrap();
        let layer = ds.get_layer(0).unwrap();
        let feature = layer.features().next().unwrap();
        assert_almost_eq(feature.get_field("sort_key".to_string()).unwrap().as_f64(), -9.0);
    }

    #[test]
    fn test_get_missing_field() {
        let ds = open(&fixture_path("roads.geojson")).unwrap();
        let layer = ds.get_layer(0).unwrap();
        let feature = layer.features().next().unwrap();
        assert!(feature.get_field("no such field".to_string()).is_none());
    }

    #[test]
    fn test_get_wkt() {
        let ds = open(&fixture_path("roads.geojson")).unwrap();
        let layer = ds.get_layer(0).unwrap();
        let feature = layer.features().next().unwrap();
        let wkt = feature.get_wkt();
        assert_eq!(wkt, "LINESTRING (26.1019276 44.4302748,26.1019382 44.4303191,26.1020002 44.4304202)".to_string());
    }
}
<commit_msg>drop `get_` from function names<commit_after>use std::ptr::null;
use std::str::raw;
use libc::{c_int, c_char, c_double};
use sync::mutex::{StaticMutex, MUTEX_INIT};

#[link(name="gdal")]
extern {
    fn OGRRegisterAll();
    fn OGROpen(pszName: *c_char, bUpdate: c_int, pahDriverList: *()) -> *();
    fn OGR_DS_GetLayerCount(hDS: *()) -> c_int;
    fn OGR_DS_Destroy(hDataSource: *());
    fn OGR_DS_GetLayer(hDS: *(), iLayer: c_int) -> *();
    fn OGR_L_GetNextFeature(hLayer: *()) -> *();
    fn OGR_F_GetFieldIndex(hFeat: *(), pszName: *c_char) -> c_int;
    fn OGR_F_GetFieldDefnRef(hFeat: *(), i: c_int) -> *();
    fn OGR_F_GetFieldAsString(hFeat: *(), iField: c_int) -> *c_char;
    fn OGR_F_GetFieldAsDouble(hFeat: *(), iField: c_int) -> c_double;
    fn OGR_F_GetGeometryRef(hFeat: *()) -> *();
    fn OGR_F_Destroy(hFeat: *());
    fn OGR_G_ExportToWkt(hGeom: *(), ppszSrcText: **c_char) -> c_int;
    fn OGR_Fld_GetType(hDefn: *()) -> c_int;
    fn OGRFree(ptr: *());
}

static OFTInteger:        c_int = 0;
static OFTIntegerList:    c_int = 1;
static OFTReal:           c_int = 2;
static OFTRealList:       c_int = 3;
static OFTString:         c_int = 4;
static OFTStringList:     c_int = 5;
static OFTWideString:     c_int = 6;
static OFTWideStringList: c_int = 7;
static OFTBinary:         c_int = 8;
static OFTDate:           c_int = 9;
static OFTTime:           c_int = 10;
static OFTDateTime:       c_int = 11;

static mut LOCK: StaticMutex = MUTEX_INIT;
static mut registered_drivers: bool = false;

fn register_drivers() {
    unsafe {
        let _g = LOCK.lock();
        if ! registered_drivers {
            OGRRegisterAll();
            registered_drivers = true;
        }
    }
}

pub struct VectorDataset {
    c_dataset: *(),
}

impl VectorDataset {
    pub fn layer_count(&self) -> int {
        return unsafe { OGR_DS_GetLayerCount(self.c_dataset) } as int;
    }

    pub fn layer<'a>(&'a self, idx: int) -> Option<Layer<'a>> {
        let c_layer = unsafe { OGR_DS_GetLayer(self.c_dataset, idx as c_int) };
        return match c_layer.is_null() {
            true  => None,
            false => Some(Layer{vector_dataset: self, c_layer: c_layer}),
        };
    }
}

impl Drop for VectorDataset {
    fn drop(&mut self) {
        unsafe { OGR_DS_Destroy(self.c_dataset); }
    }
}

pub struct Layer<'a> {
    vector_dataset: &'a VectorDataset,
    c_layer: *(),
}

impl<'a> Layer<'a> {
    pub fn features<'a>(&'a self) -> FeatureIterator<'a> {
        return FeatureIterator{layer: self};
    }
}

pub struct FeatureIterator<'a> {
    layer: &'a Layer<'a>,
}

impl<'a> Iterator<Feature<'a>> for FeatureIterator<'a> {
    #[inline]
    fn next(&mut self) -> Option<Feature<'a>> {
        let c_feature = unsafe { OGR_L_GetNextFeature(self.layer.c_layer) };
        return match c_feature.is_null() {
            true  => None,
            false => Some(Feature{layer: self.layer, c_feature: c_feature}),
        };
    }
}

pub struct Feature<'a> {
    layer: &'a Layer<'a>,
    c_feature: *(),
}

impl<'a> Feature<'a> {
    pub fn field(&self, name: String) -> Option<FieldValue> {
        return name.with_c_str(|c_name| unsafe {
            let field_id = OGR_F_GetFieldIndex(self.c_feature, c_name);
            if field_id == -1 {
                return None;
            }
            let field_defn = OGR_F_GetFieldDefnRef(self.c_feature, field_id);
            let field_type = OGR_Fld_GetType(field_defn);
            return match field_type {
                OFTString => {
                    let rv = OGR_F_GetFieldAsString(self.c_feature, field_id);
                    return Some(StringValue(raw::from_c_str(rv)));
                },
                OFTReal => {
                    let rv = OGR_F_GetFieldAsDouble(self.c_feature, field_id);
                    return Some(F64Value(rv as f64));
                },
                _ => fail!("Unknown field type {}", field_type)
            }
        });
    }

    pub fn wkt(&self) -> String {
        unsafe {
            let c_geom = OGR_F_GetGeometryRef(self.c_feature);
            let c_wkt: *c_char = null();
            OGR_G_ExportToWkt(c_geom, &c_wkt);
            let wkt = raw::from_c_str(c_wkt);
            OGRFree(c_wkt as *());
            return wkt;
        }
    }
}

#[unsafe_destructor]
impl<'a> Drop for Feature<'a> {
    fn drop(&mut self) {
        unsafe { OGR_F_Destroy(self.c_feature); }
    }
}

pub fn open(path: &Path) -> Option<VectorDataset> {
    register_drivers();
    let filename = path.as_str().unwrap();
    let c_dataset = filename.with_c_str(|c_filename| {
        return unsafe { OGROpen(c_filename, 0, null()) };
    });
    return match c_dataset.is_null() {
        true  => None,
        false => Some(VectorDataset{c_dataset: c_dataset}),
    };
}

pub enum FieldValue {
    StringValue(String),
    F64Value(f64),
}

impl FieldValue {
    pub fn as_string(self) -> String {
        match self { StringValue(rv) => rv, _ => fail!("not a string") }
    }

    pub fn as_f64(self) -> f64 {
        match self { F64Value(rv) => rv, _ => fail!("not an f64") }
    }
}

#[cfg(test)]
mod test {
    use std::os::getenv;
    use std::path::Path;
    use super::{Feature, open};

    fn fixture_path(name: &str) -> Path {
        let envvar = "RUST_GDAL_TEST_FIXTURES";
        let fixtures = match getenv(envvar) {
            Some(p) => Path::new(p),
            None => fail!("Environment variable {} not set", envvar)
        };
        let rv = fixtures.join(name);
        return rv;
    }

    fn assert_almost_eq(a: f64, b: f64) {
        let f: f64 = a / b;
        assert!(f < 1.00001);
        assert!(f > 0.99999);
    }

    #[test]
    fn test_layer_count() {
        let ds = open(&fixture_path("roads.geojson")).unwrap();
        assert_eq!(ds.layer_count(), 1);
    }

    #[test]
    fn test_iterate_features() {
        let ds = open(&fixture_path("roads.geojson")).unwrap();
        let layer = ds.layer(0).unwrap();
        let features: Vec<Feature> = layer.features().collect();
        assert_eq!(features.len(), 21);
    }

    #[test]
    fn test_string_field() {
        let ds = open(&fixture_path("roads.geojson")).unwrap();
        let layer = ds.layer(0).unwrap();
        let feature = layer.features().next().unwrap();
        assert_eq!(feature.field("highway".to_string()).unwrap().as_string(),
                   "footway".to_string());
        assert_eq!(
            layer.features()
                 .count(|f|
                    f.field("highway".to_string()).unwrap().as_string() ==
                    "residential".to_string()),
            2);
    }

    #[test]
    fn test_float_field() {
        let ds = open(&fixture_path("roads.geojson")).unwrap();
        let layer = ds.layer(0).unwrap();
        let feature = layer.features().next().unwrap();
        assert_almost_eq(feature.field("sort_key".to_string()).unwrap().as_f64(), -9.0);
    }

    #[test]
    fn test_missing_field() {
        let ds = open(&fixture_path("roads.geojson")).unwrap();
        let layer = ds.layer(0).unwrap();
        let feature = layer.features().next().unwrap();
        assert!(feature.field("no such field".to_string()).is_none());
    }

    #[test]
    fn test_wkt() {
        let ds = open(&fixture_path("roads.geojson")).unwrap();
        let layer = ds.layer(0).unwrap();
        let feature = layer.features().next().unwrap();
        let wkt = feature.wkt();
        assert_eq!(wkt, "LINESTRING (26.1019276 44.4302748,26.1019382 44.4303191,26.1020002 44.4304202)".to_string());
    }
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2018 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate rustc_serialize;
extern crate tempdir;

use self::rustc_serialize::hex::FromHex;
use self::tempdir::TempDir;
use crate::libexecutor::block::{BlockBody, ClosedBlock, OpenBlock};
use crate::libexecutor::command;
use crate::libexecutor::executor::Executor;
use crate::state::State;
use crate::state_db::*;
use crate::types::header::OpenHeader;
use crate::types::transaction::SignedTransaction;
use cita_crypto::PrivKey;
use cita_types::traits::LowerHex;
use cita_types::{Address, U256};
use core::libchain::chain;
use crossbeam_channel::{Receiver, Sender};
use libproto::blockchain;
use std::env;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::path::Path;
use std::process::Command;
use std::sync::Arc;
use std::time::UNIX_EPOCH;
use util::AsMillis;

const CHAIN_CONFIG: &str = "chain.toml";
const SCRIPTS_DIR: &str = "../../scripts";

// pub fn get_temp_state() -> State<StateDB> {
//     let state_db = get_temp_state_db();
//     State::new(state_db, 0.into(), Default::default())
// }

// fn new_db() -> Arc<KeyValueDB> {
//     Arc::new(kvdb::in_memory(8))
// }

// pub fn get_temp_state_db() -> StateDB {
//     let db = new_db();
//     let journal_db = journaldb::new(db, journaldb::Algorithm::Archive, crate::db::COL_STATE);
//     StateDB::new(journal_db, 5 * 1024 * 1024)
// }

pub fn solc(name: &str, source: &str) -> (Vec<u8>, Vec<u8>) {
    // input and output of solc command
    let output_dir = TempDir::new("solc_output").unwrap().into_path();
    let contract_file = output_dir.join("contract.sol");

    let deploy_code_file = output_dir.join([name, ".bin"].join(""));
    let runtime_code_file = output_dir.join([name, ".bin-runtime"].join(""));

    // prepare contract file
    let mut file = File::create(contract_file.clone()).unwrap();
    let mut content = String::new();
    file.write_all(source.as_ref()).expect("failed to write");

    // execute solc command
    Command::new("solc")
        .arg(contract_file.clone())
        .arg("--bin")
        .arg("--bin-runtime")
        .arg("-o")
        .arg(output_dir)
        .output()
        .expect("failed to execute solc");

    // read deploy code
    File::open(deploy_code_file)
        .expect("failed to open deploy code file!")
        .read_to_string(&mut content)
        .expect("failed to read binary");
    let deploy_code = content.as_str().from_hex().unwrap();

    // read runtime code
    let mut content = String::new();
    File::open(runtime_code_file)
        .expect("failed to open deploy code file!")
        .read_to_string(&mut content)
        .expect("failed to read binary");
    let runtime_code = content.from_hex().unwrap();
    (deploy_code, runtime_code)
}

pub fn init_executor() -> Executor {
    let (_fsm_req_sender, fsm_req_receiver) = crossbeam_channel::unbounded();
    let (fsm_resp_sender, _fsm_resp_receiver) = crossbeam_channel::unbounded();
    let (_command_req_sender, command_req_receiver) = crossbeam_channel::bounded(0);
    let (command_resp_sender, _command_resp_receiver) = crossbeam_channel::bounded(0);
    init_executor2(
        fsm_req_receiver,
        fsm_resp_sender,
        command_req_receiver,
        command_resp_sender,
    )
}

pub fn init_executor2(
    fsm_req_receiver: Receiver<OpenBlock>,
    fsm_resp_sender: Sender<ClosedBlock>,
    command_req_receiver: Receiver<command::Command>,
    command_resp_sender: Sender<command::CommandResp>,
) -> Executor {
    // FIXME temp dir should be removed automatically, but at present it is not
    let tempdir = TempDir::new("init_executor").unwrap().into_path();
    let genesis_path = Path::new(SCRIPTS_DIR).join("config_tool/genesis/genesis.json");

    let mut data_path = tempdir.clone();
    data_path.push("data");
    env::set_var("DATA_PATH", data_path);
    let executor = Executor::init(
        genesis_path.to_str().unwrap(),
        "archive",
        5 * 1024 * 1024,
        tempdir.to_str().unwrap().to_string(),
        fsm_req_receiver,
        fsm_resp_sender,
        command_req_receiver,
        command_resp_sender,
        false,
    );
    executor
}

pub fn init_chain() -> Arc<chain::Chain> {
    unimplemented!()
    // let tempdir = TempDir::new("solc_output").unwrap().into_path();
    // let config = DatabaseConfig::with_columns(db::NUM_COLUMNS);
    // let db = Database::open(&config, &tempdir.to_str().unwrap()).unwrap();
    // let chain_config = chain::Config::new(CHAIN_CONFIG);
    // Arc::new(chain::Chain::init_chain(Arc::new(db), &chain_config))
}

pub fn create_block(
    executor: &Executor,
    to: Address,
    data: &Vec<u8>,
    nonce: (u32, u32),
    privkey: &PrivKey,
) -> OpenBlock {
    let mut block = OpenBlock::default();

    block.set_parent_hash(executor.get_current_hash());
    block.set_timestamp(AsMillis::as_millis(&UNIX_EPOCH.elapsed().unwrap()));
    block.set_number(executor.get_current_height() + 1);
    // header.proof= ?;

    let mut body = BlockBody::default();
    let mut txs = Vec::new();

    for i in nonce.0..nonce.1 {
        let mut tx = blockchain::Transaction::new();
        if to == Address::from(0) {
            tx.set_to(String::from(""));
        } else {
            tx.set_to(to.lower_hex());
        }
        tx.set_nonce(U256::from(i).lower_hex());
        tx.set_data(data.clone());
        tx.set_valid_until_block(100);
        tx.set_quota(1844674);

        let stx = tx.sign(*privkey);
        let new_tx = SignedTransaction::create(&stx).unwrap();
        txs.push(new_tx);
    }
    body.set_transactions(txs);
    block.set_body(body);
    block
}

pub fn generate_contract() -> Vec<u8> {
    let source = r#"
            pragma solidity ^0.4.8;
            contract ConstructSol {
                uint a;
                event LogCreate(address contractAddr);
                event A(uint);
                function ConstructSol(){
                    LogCreate(this);
                }
                function set(uint _a) {
                    a = _a;
                    A(a);
                }
                function get() returns (uint) {
                    return a;
                }
            }
        "#;
    let (data, _) = solc("ConstructSol", source);
    data
}

pub fn generate_block_header() -> OpenHeader {
    OpenHeader::default()
}

pub fn generate_block_body() -> BlockBody {
    let mut stx = SignedTransaction::default();
    use crate::types::transaction::SignedTransaction;
    stx.data = vec![1; 200];
    let transactions = vec![stx; 200];
    BlockBody { transactions }
}

pub fn generate_default_block() -> OpenBlock {
    let block_body = generate_block_body();
    let block_header = generate_block_header();
    OpenBlock {
        body: block_body,
        header: block_header,
    }
}
<commit_msg>[cita-executor] fix tests helpers<commit_after>// CITA
// Copyright 2016-2018 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate rustc_serialize;
extern crate tempdir;

use self::rustc_serialize::hex::FromHex;
use self::tempdir::TempDir;
use crate::libexecutor::block::{BlockBody, ClosedBlock, OpenBlock};
use crate::libexecutor::command;
use crate::libexecutor::executor::Executor;
use crate::types::header::OpenHeader;
use crate::types::transaction::SignedTransaction;
use cita_crypto::PrivKey;
use cita_types::traits::LowerHex;
use cita_types::{Address, U256};
use core::libchain::chain;
use crossbeam_channel::{Receiver, Sender};
use libproto::blockchain;
use std::env;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::path::Path;
use std::process::Command;
use std::time::UNIX_EPOCH;
use util::AsMillis;

use std::sync::Arc;

use cita_vm::{state::MemoryDB, state::State};

const CHAIN_CONFIG: &str = "chain.toml";
const SCRIPTS_DIR: &str = "../../scripts";

pub fn get_temp_state() -> State<MemoryDB> {
    let db = Arc::new(MemoryDB::new(false));
    State::new(db).unwrap()
}

pub fn solc(name: &str, source: &str) -> (Vec<u8>, Vec<u8>) {
    // input and output of solc command
    let output_dir = TempDir::new("solc_output").unwrap().into_path();
    let contract_file = output_dir.join("contract.sol");

    let deploy_code_file = output_dir.join([name, ".bin"].join(""));
    let runtime_code_file = output_dir.join([name, ".bin-runtime"].join(""));

    // prepare contract file
    let mut file = File::create(contract_file.clone()).unwrap();
    let mut content = String::new();
    file.write_all(source.as_ref()).expect("failed to write");

    // execute solc command
    Command::new("solc")
        .arg(contract_file.clone())
        .arg("--bin")
        .arg("--bin-runtime")
        .arg("-o")
        .arg(output_dir)
        .output()
        .expect("failed to execute solc");

    // read deploy code
    File::open(deploy_code_file)
        .expect("failed to open deploy code file!")
        .read_to_string(&mut content)
        .expect("failed to read binary");
    let deploy_code = content.as_str().from_hex().unwrap();

    // read runtime code
    let mut content = String::new();
    File::open(runtime_code_file)
        .expect("failed to open deploy code file!")
        .read_to_string(&mut content)
        .expect("failed to read binary");
    let runtime_code = content.from_hex().unwrap();
    (deploy_code, runtime_code)
}

pub fn init_executor() -> Executor {
    let (_fsm_req_sender, fsm_req_receiver) = crossbeam_channel::unbounded();
    let (fsm_resp_sender, _fsm_resp_receiver) = crossbeam_channel::unbounded();
    let (_command_req_sender, command_req_receiver) = crossbeam_channel::bounded(0);
    let (command_resp_sender, _command_resp_receiver) = crossbeam_channel::bounded(0);
    init_executor2(
        fsm_req_receiver,
        fsm_resp_sender,
        command_req_receiver,
        command_resp_sender,
    )
}

pub fn init_executor2(
    fsm_req_receiver: Receiver<OpenBlock>,
    fsm_resp_sender: Sender<ClosedBlock>,
    command_req_receiver: Receiver<command::Command>,
    command_resp_sender: Sender<command::CommandResp>,
) -> Executor {
    // FIXME temp dir should be removed automatically, but at present it is not
    let tempdir = TempDir::new("init_executor").unwrap().into_path();
    let genesis_path = Path::new(SCRIPTS_DIR).join("config_tool/genesis/genesis.json");

    let mut data_path = tempdir.clone();
    data_path.push("data");
    env::set_var("DATA_PATH", data_path);
    let executor = Executor::init(
        genesis_path.to_str().unwrap(),
        "archive".to_string(),
        fsm_req_receiver,
        fsm_resp_sender,
        command_req_receiver,
        command_resp_sender,
        false,
    );
    executor
}

pub fn init_chain() -> Arc<chain::Chain> {
    unimplemented!()
    // let tempdir = TempDir::new("solc_output").unwrap().into_path();
    // let config = DatabaseConfig::with_columns(db::NUM_COLUMNS);
    // let db = Database::open(&config, &tempdir.to_str().unwrap()).unwrap();
    // let chain_config = chain::Config::new(CHAIN_CONFIG);
    // Arc::new(chain::Chain::init_chain(Arc::new(db), &chain_config))
}

pub fn create_block(
    executor: &Executor,
    to: Address,
    data: &Vec<u8>,
    nonce: (u32, u32),
    privkey: &PrivKey,
) -> OpenBlock {
    let mut block = OpenBlock::default();

    block.set_parent_hash(executor.get_current_hash());
    block.set_timestamp(AsMillis::as_millis(&UNIX_EPOCH.elapsed().unwrap()));
    block.set_number(executor.get_current_height() + 1);
    // header.proof= ?;

    let mut body = BlockBody::default();
    let mut txs = Vec::new();

    for i in nonce.0..nonce.1 {
        let mut tx = blockchain::Transaction::new();
        if to == Address::from(0) {
            tx.set_to(String::from(""));
        } else {
            tx.set_to(to.lower_hex());
        }
        tx.set_nonce(U256::from(i).lower_hex());
        tx.set_data(data.clone());
        tx.set_valid_until_block(100);
        tx.set_quota(1844674);

        let stx = tx.sign(*privkey);
        let new_tx = SignedTransaction::create(&stx).unwrap();
        txs.push(new_tx);
    }
    body.set_transactions(txs);
    block.set_body(body);
    block
}

pub fn generate_contract() -> Vec<u8> {
    let source = r#"
            pragma solidity ^0.4.8;
            contract ConstructSol {
                uint a;
                event LogCreate(address contractAddr);
                event A(uint);
                function ConstructSol(){
                    LogCreate(this);
                }
                function set(uint _a) {
                    a = _a;
                    A(a);
                }
                function get() returns (uint) {
                    return a;
                }
            }
        "#;
    let (data, _) = solc("ConstructSol", source);
    data
}

pub fn generate_block_header() -> OpenHeader {
    OpenHeader::default()
}

pub fn generate_block_body() -> BlockBody {
    let mut stx = SignedTransaction::default();
    use crate::types::transaction::SignedTransaction;
    stx.data = vec![1; 200];
    let transactions = vec![stx; 200];
    BlockBody { transactions }
}

pub fn generate_default_block() -> OpenBlock {
    let block_body = generate_block_body();
    let block_header = generate_block_header();
    OpenBlock {
        body: block_body,
        header: block_header,
    }
}
<|endoftext|>


<commit_before>type Stack<T> = Vec<T>;

#[derive(Default)]
pub struct Interpreter<T> {
    data_stack: Stack<T>,
}

impl<T> Interpreter<T> {

    fn push(&mut self, value: T) {
        self.data_stack.push(value)
    }

    fn pop(&mut self) -> Option<T> {
        self.data_stack.pop()
    }
}

struct Word<'a, T> {
    entry: &'a Fn(&mut Interpreter<T>) -> (),
}

impl<'a, T> Word<'a, T> {
    fn eval_within(&self, i: &mut Interpreter<T>) {
        (self.entry)(i)
    }
}

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

    #[test]
    fn plus_word() {
        let mut interpreter = Interpreter::<i32>::default();
        let plus = Word {
            entry: &|i| {
                if let (Some(b), Some(a)) = (i.pop(), i.pop()) {
                    i.push(a + b)
                } else { panic!("Stack underflow") }
            }
        };
        interpreter.push(42);
        interpreter.push(51);
        plus.eval_within(&mut interpreter);
        assert_eq!(Some(93), interpreter.pop())
    }

    #[test]
    fn pops_nothing() {
        let mut interpreter = Interpreter::<i32>::default();
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_as_pushed() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_in_reverse_order() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        interpreter.push(51);
        assert_eq!(Some(51), interpreter.pop());
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }
}
<commit_msg>Extract word as a fixture, box word closure<commit_after>type Stack<T> = Vec<T>;

#[derive(Default)]
pub struct Interpreter<T> {
    data_stack: Stack<T>,
}

impl<T> Interpreter<T> {

    fn push(&mut self, value: T) {
        self.data_stack.push(value)
    }

    fn pop(&mut self) -> Option<T> {
        self.data_stack.pop()
    }
}

struct Word<T> {
    entry: Box<Fn(&mut Interpreter<T>) -> ()>,
}

impl<T> Word<T> {
    fn eval_within(&self, i: &mut Interpreter<T>) {
        (self.entry)(i)
    }
}

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

    fn fixture_plus() -> Word<i32> {
        Word {
            entry: Box::new(move |i| {
                if let (Some(b), Some(a)) = (i.pop(), i.pop()) {
                    i.push(a + b)
                } else { panic!("Stack underflow") }
            })
        }
    }

    #[test]
    fn plus_word() {
        let mut interpreter = Interpreter::<i32>::default();
        let plus = fixture_plus();
        interpreter.push(42);
        interpreter.push(51);
        plus.eval_within(&mut interpreter);
        assert_eq!(Some(93), interpreter.pop())
    }

    #[test]
    fn pops_nothing() {
        let mut interpreter = Interpreter::<i32>::default();
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_as_pushed() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_in_reverse_order() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        interpreter.push(51);
        assert_eq!(Some(51), interpreter.pop());
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }
}
<|endoftext|>