<commit_before>use std::fmt;

use byteorder::{ByteOrder, BigEndian};
use super::instruction::Instruction;
use super::mmu;
use super::machine_status::MachineStatus;
use super::super::memory;

const NUM_GPR: usize = 32;
const NUM_SPR: usize = 1023;
const NUM_SR : usize = 16;
const NUM_CR : usize = 8;

const XER : usize = 1;
const HID0: usize = 1008;

pub struct Cpu {
    pub memory: memory::Memory,
    pub mmu: mmu::Mmu,
    pub pc: u32,
    ctr: u32,
    gpr: [u32; NUM_GPR],
    spr: [u32; NUM_SPR], // ToDo phase out
    pub msr: MachineStatus,
    sr: [u32; NUM_SR],
    cr: [u8; NUM_CR],
    lr: u32
}

impl Cpu {
    pub fn new(memory: memory::Memory) -> Cpu {
        let msr = MachineStatus::default();

        // initial vector is (either 0x0000_0100 or 0xFFF0_0100) depending on MSR[IP]
        let pc = if msr.exception_prefix {
            0xFFF00100
        } else {
            0x00000100
        };

        Cpu {
            memory: memory,
            mmu: mmu::Mmu::new(),
            pc: pc,
            ctr: 0,
            gpr: [0; NUM_GPR],
            spr: [0; NUM_SPR],
            msr: msr,
            sr: [0; NUM_SR],
            cr: [0; NUM_CR],
            lr: 0
        }
    }

    pub fn run_instruction(&mut self) {
        let instr = self.read_instruction();

        println!("{:#x}:{:?}", instr.opcode(), self.gpr);

        match instr.opcode() {
            10 => self.cmpli(instr),
            14 => self.addi(instr),
            15 => self.addis(instr),
            16 => self.bcx(instr),
            18 => self.bx(instr),
            19 => {
                match instr.subopcode() {
                    150 => { // isync - instruction synchronize
                        // don't do anything
                    },
                    _ => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }
            },
            21 => self.rlwinm(instr),
            24 => { // ori - OR immediate
                self.gpr[instr.a()] = self.gpr[instr.s()] | instr.uimm();
            },
            31 => {

                match instr.subopcode() {
                     28 => self.andx(instr),
                     40 => self.subf(instr),
                     83 => self.mfmsr(instr),
                    146 => self.mtmsr(instr),
                    210 => self.mtsr(instr),
                    339 => self.mfspr(instr),
                    371 => self.mftb(instr),
                    467 => self.mtspr(instr),
                    _   => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }

            },
            32 => self.lwz(instr),
            36 => self.stw(instr),
            44 => self.sth(instr),
            _  => panic!("Unrecognized instruction {:#x} {:#b}", instr.0, instr.opcode())
        }

        self.pc += 4;
    }

    // FixMe: check if msr.exception_prefix (MSR[IP])
    fn read_instruction(&mut self) -> Instruction {
        let mut data = [0u8; 5];

        let addr = self.mmu.instr_address_translate(&self.msr, self.pc);

        self.memory.read(addr, &mut data);

        Instruction(BigEndian::read_u32(&data[0..]))
    }

    // complare logic immediate
    fn cmpli(&mut self, instr: Instruction) {
        let a = self.gpr[instr.a()];
        let b = instr.uimm();
        let mut c:u8;

        if a < b {
            c = 0b1000;
        } else if a > b {
            c = 0b0100;
        } else {
            c = 0b0010;
        }

        c |= self.spr[XER] as u8 & 0b1;

        self.cr[instr.crfd()] = c;
    }

    // add immediate
    fn addi(&mut self, instr: Instruction) {
        let a = instr.a();
        if a == 0 {
            self.gpr[instr.d()] = instr.uimm();
        } else {
            self.gpr[instr.d()] = self.gpr[a] + instr.uimm();
        }
    }

    // add immediate shifted
    fn addis(&mut self, instr: Instruction) {
        if instr.a() == 0 { // lis
            self.gpr[instr.d()] = instr.uimm() << 16;
        } else { // subis
            self.gpr[instr.d()] = self.gpr[instr.a()] + (instr.uimm() << 16);
        }
    }

    // ToDo: verify this is working
    fn bcx(&mut self, instr: Instruction) {
        let bo = instr.bo();

        let ctr_ok = if bon(bo, 2) == 0 {
            self.ctr.wrapping_sub(1); // FixMe: need wrapping :(

            if bon(bo, 3) != 0 {
                self.ctr == 0
            } else {
                self.ctr != 0
            }
        } else {
            true
        };

        let cond_ok = if bon(bo, 0) == 0 {
            (bon(bo, 1) == (self.cr[instr.bi()]))
        } else {
            true
        };

        if ctr_ok && cond_ok {
            if instr.aa() == 1 {
                self.pc = instr.bd() << 2;
            } else {
                self.pc = self.pc + (instr.bd() << 2);
            }

            if instr.lk() != 0 {
                self.lr = self.pc + 4;
            }
        }

    }

    // branch
    fn bx(&mut self, instr: Instruction) {
        if instr.aa() == 1 {
            self.pc = instr.li() << 2;
        } else {
            self.pc = self.pc + (instr.li() << 2);
        }

        if instr.lk() == 1 {
            self.lr = self.pc + 4;
        }
    }

    // rotate word immediate then AND with mask
    fn rlwinm(&mut self, instr: Instruction) {
        let r = self.gpr[instr.s()] << instr.sh();
        let m = mask(instr.mb(), instr.me());

        self.gpr[instr.a()] = r & m;
    }

    fn andx(&mut self, instr: Instruction) {
        self.gpr[instr.a()] = self.gpr[instr.d()] & self.gpr[instr.b()];

        // TODO: other registers altered
    }

    // subtract from
    fn subf(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.gpr[instr.a()] + self.gpr[instr.b()] + 1;

        // TODO: other registers altered
    }

    // move from machine state register
    fn mfmsr(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.msr.as_u32();

        // TODO: check privelege level
    }

    // move to machine state register
    fn mtmsr(&mut self, instr: Instruction) {
        self.msr = self.gpr[instr.s()].into();

        // TODO: check privelege level
    }

    // move to segment register
    fn mtsr(&mut self, instr: Instruction) {
        self.sr[instr.sr()] = self.gpr[instr.s()];

        // TODO: check privelege level -> supervisor level instruction
    }

    // move from special purpose register
    fn mfspr(&mut self, instr: Instruction) {
        let n = (instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111);

        self.gpr[instr.s()] = self.spr[n as usize];

        // TODO: check privelege level
    }

    // move from time base
    fn mftb(&mut self, instr: Instruction) {
        let n = (instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111);

        match n {
            268 => { // TBL
                println!("FIXME: mftb, get time base tbl");
            },
            269 => { // TBR
                println!("FIXME: mftb, get time base tbu");
            },
            _ => panic!("Unrecognized TBR {}", n) // FixMe: invoke error handler
        }
    }

    // move special purpose register
    fn mtspr(&mut self, instr: Instruction) {
        let n = ((instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111)) as usize;

        match n {
            8 => self.lr = self.gpr[instr.s()],
            9 => self.ctr = self.gpr[instr.s()],
            528 ... 543 => { // if IBAT or DBAT, write to MMU register
                self.mmu.write_bat_reg(n, self.gpr[instr.s()]);
                //panic!("FixMe: write to BAT registers");
            },
            _ => self.spr[n] = self.gpr[instr.s()]
        }

        // TODO: check privelege level
    }

    // load word and zero
    fn lwz(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.data_address_translate(&self.msr, ea);

        self.gpr[instr.d()] = self.memory.read_u32(addr);
    }

    // store word
    fn stw(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.data_address_translate(&self.msr, ea);

        self.memory.write_u32(addr, self.gpr[instr.s()]);
    }

    // store half word
    fn sth(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.data_address_translate(&self.msr, ea);

        self.memory.write_u16(addr, self.gpr[instr.s()] as u16);
    }
}

//((1 << (x - y +1)) - 1) << y
// FixMe: not sure if this is correct
// actually I think this might be backwards
fn mask(x: u8, y: u8) -> u32 {
    let mut mask:u32 = 0xFFFFFFFF >> y;

    if x >= 31 {
        mask ^= 0;
    } else {
        mask ^= 0xFFFFFFFF >> (x + 1);
    }

    if y > x {
        !mask
    } else {
        mask
    }
}

fn bon(bo: u8, n: u8) -> u8 {
    (bo >> (4-n)) & 1
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MSR: {:?} gpr: {:?}, sr: {:?}, cr:{:?}, HID0: {}", self.msr, self.gpr, self.sr, self.cr, self.spr[HID0])
    }
}
<commit_msg>implemented bclrx<commit_after>use std::fmt;

use byteorder::{ByteOrder, BigEndian};
use super::instruction::Instruction;
use super::mmu;
use super::machine_status::MachineStatus;
use super::super::memory;

const NUM_GPR: usize = 32;
const NUM_SPR: usize = 1023;
const NUM_SR : usize = 16;
const NUM_CR : usize = 8;

const XER : usize = 1;
const HID0: usize = 1008;

pub struct Cpu {
    pub memory: memory::Memory,
    pub mmu: mmu::Mmu,
    pub pc: u32,
    ctr: u32,
    gpr: [u32; NUM_GPR],
    spr: [u32; NUM_SPR], // ToDo phase out
    pub msr: MachineStatus,
    sr: [u32; NUM_SR],
    cr: [u8; NUM_CR],
    lr: u32
}

impl Cpu {
    pub fn new(memory: memory::Memory) -> Cpu {
        let msr = MachineStatus::default();

        // initial vector is (either 0x0000_0100 or 0xFFF0_0100) depending on MSR[IP]
        let pc = if msr.exception_prefix {
            0xFFF00100
        } else {
            0x00000100
        };

        Cpu {
            memory: memory,
            mmu: mmu::Mmu::new(),
            pc: pc,
            ctr: 0,
            gpr: [0; NUM_GPR],
            spr: [0; NUM_SPR],
            msr: msr,
            sr: [0; NUM_SR],
            cr: [0; NUM_CR],
            lr: 0
        }
    }

    pub fn run_instruction(&mut self) {
        let instr = self.read_instruction();

        println!("{:#x}:{:?}", instr.opcode(), self.gpr);

        match instr.opcode() {
            10 => self.cmpli(instr),
            14 => self.addi(instr),
            15 => self.addis(instr),
            16 => self.bcx(instr),
            18 => self.bx(instr),
            19 => {
                match instr.subopcode() {
                    16 => self.bclrx(instr),
                    150 => { // isync - instruction synchronize
                        // don't do anything
                    },
                    _ => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }
            },
            21 => self.rlwinm(instr),
            24 => { // ori - OR immediate
                self.gpr[instr.a()] = self.gpr[instr.s()] | instr.uimm();
            },
            31 => {

                match instr.subopcode() {
                     28 => self.andx(instr),
                     40 => self.subf(instr),
                     83 => self.mfmsr(instr),
                    146 => self.mtmsr(instr),
                    210 => self.mtsr(instr),
                    339 => self.mfspr(instr),
                    371 => self.mftb(instr),
                    467 => self.mtspr(instr),
                    _   => panic!("Unrecognized instruction subopcode {} {}", instr.opcode(), instr.subopcode())
                }

            },
            32 => self.lwz(instr),
            36 => self.stw(instr),
            44 => self.sth(instr),
            _  => panic!("Unrecognized instruction {:#x} {:#b}", instr.0, instr.opcode())
        }

        self.pc += 4;
    }

    // FixMe: check if msr.exception_prefix (MSR[IP])
    fn read_instruction(&mut self) -> Instruction {
        let mut data = [0u8; 5];

        let addr = self.mmu.instr_address_translate(&self.msr, self.pc);

        self.memory.read(addr, &mut data);

        Instruction(BigEndian::read_u32(&data[0..]))
    }

    // complare logic immediate
    fn cmpli(&mut self, instr: Instruction) {
        let a = self.gpr[instr.a()];
        let b = instr.uimm();
        let mut c:u8;

        if a < b {
            c = 0b1000;
        } else if a > b {
            c = 0b0100;
        } else {
            c = 0b0010;
        }

        c |= self.spr[XER] as u8 & 0b1;

        self.cr[instr.crfd()] = c;
    }

    // add immediate
    fn addi(&mut self, instr: Instruction) {
        let a = instr.a();
        if a == 0 {
            self.gpr[instr.d()] = instr.uimm();
        } else {
            self.gpr[instr.d()] = self.gpr[a] + instr.uimm();
        }
    }

    // add immediate shifted
    fn addis(&mut self, instr: Instruction) {
        if instr.a() == 0 { // lis
            self.gpr[instr.d()] = instr.uimm() << 16;
        } else { // subis
            self.gpr[instr.d()] = self.gpr[instr.a()] + (instr.uimm() << 16);
        }
    }

    // ToDo: verify this is working
    fn bcx(&mut self, instr: Instruction) {
        let bo = instr.bo();

        let ctr_ok = if bon(bo, 2) == 0 {
            self.ctr.wrapping_sub(1);

            if bon(bo, 3) != 0 {
                self.ctr == 0
            } else {
                self.ctr != 0
            }
        } else {
            true
        };

        let cond_ok = if bon(bo, 0) == 0 {
            (bon(bo, 1) == (self.cr[instr.bi()]))
        } else {
            true
        };

        if ctr_ok && cond_ok {
            if instr.aa() == 1 {
                self.pc = instr.bd() << 2;
            } else {
                self.pc = self.pc + (instr.bd() << 2);
            }

            if instr.lk() == 1 {
                self.lr = self.pc + 4;
            }
        }
    }

    // branch
    fn bx(&mut self, instr: Instruction) {
        if instr.aa() == 1 {
            self.pc = instr.li() << 2;
        } else {
            self.pc = self.pc + (instr.li() << 2);
        }

        if instr.lk() == 1 {
            self.lr = self.pc + 4;
        }
    }

    // branch conditional to link register
    fn bclrx(&mut self, instr: Instruction) {
        let bo = instr.bo();

        let ctr_ok = if bon(bo, 2) == 0 {
            self.ctr.wrapping_sub(1);

            if bon(bo, 3) != 0 {
                self.ctr == 0
            } else {
                self.ctr != 0
            }
        } else {
            true
        };

        let cond_ok = if bon(bo, 0) == 0 {
            (bon(bo, 1) == (self.cr[instr.bi()]))
        } else {
            true
        };

        if ctr_ok && cond_ok {
            self.pc = self.lr & 0b00;

            if instr.lk() == 1 {
                self.lr = self.pc + 4;
            }
        }
    }

    // rotate word immediate then AND with mask
    fn rlwinm(&mut self, instr: Instruction) {
        let r = self.gpr[instr.s()] << instr.sh();
        let m = mask(instr.mb(), instr.me());

        self.gpr[instr.a()] = r & m;
    }

    fn andx(&mut self, instr: Instruction) {
        self.gpr[instr.a()] = self.gpr[instr.d()] & self.gpr[instr.b()];

        // TODO: other registers altered
    }

    // subtract from
    fn subf(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.gpr[instr.a()] + self.gpr[instr.b()] + 1;

        // TODO: other registers altered
    }

    // move from machine state register
    fn mfmsr(&mut self, instr: Instruction) {
        self.gpr[instr.d()] = self.msr.as_u32();

        // TODO: check privelege level
    }

    // move to machine state register
    fn mtmsr(&mut self, instr: Instruction) {
        self.msr = self.gpr[instr.s()].into();

        // TODO: check privelege level
    }

    // move to segment register
    fn mtsr(&mut self, instr: Instruction) {
        self.sr[instr.sr()] = self.gpr[instr.s()];

        // TODO: check privelege level -> supervisor level instruction
    }

    // move from special purpose register
    fn mfspr(&mut self, instr: Instruction) {
        let n = ((instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111)) as usize;

        match n {
            8 => self.gpr[instr.s()] = self.lr,
            9 => self.gpr[instr.s()] = self.ctr,
            _ => {
                println!("FIXME: spr {} not implemented", n);
                self.gpr[instr.s()] = self.spr[n];
            }
        }

        // TODO: check privelege level
    }

    // move from time base
    fn mftb(&mut self, instr: Instruction) {
        let n = (instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111);

        match n {
            268 => { // TBL
                println!("FIXME: mftb, get time base tbl");
            },
            269 => { // TBR
                println!("FIXME: mftb, get time base tbu");
            },
            _ => panic!("Unrecognized TBR {}", n) // FixMe: invoke error handler
        }
    }

    // move special purpose register
    fn mtspr(&mut self, instr: Instruction) {
        let n = ((instr.spr_upper() << 5) | (instr.spr_lower() & 0b1_1111)) as usize;

        match n {
            8 => self.lr = self.gpr[instr.s()],
            9 => self.ctr = self.gpr[instr.s()],
            528 ... 543 => { // if IBAT or DBAT, write to MMU register
                self.mmu.write_bat_reg(n, self.gpr[instr.s()]);
                //panic!("FixMe: write to BAT registers");
            },
            _ => {
                println!("FIXME: mtspr {} not implemented", n);
                self.spr[n] = self.gpr[instr.s()];
            }
        }

        // TODO: check privelege level
    }

    // load word and zero
    fn lwz(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.data_address_translate(&self.msr, ea);

        self.gpr[instr.d()] = self.memory.read_u32(addr);
    }

    // store word
    fn stw(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.data_address_translate(&self.msr, ea);

        self.memory.write_u32(addr, self.gpr[instr.s()]);
    }

    // store half word
    fn sth(&mut self, instr: Instruction) {
        let ea = if instr.a() == 0 {
            instr.simm()
        } else {
            self.gpr[instr.a()] + instr.simm()
        };

        let addr = self.mmu.data_address_translate(&self.msr, ea);

        self.memory.write_u16(addr, self.gpr[instr.s()] as u16);
    }
}

//((1 << (x - y +1)) - 1) << y
// FixMe: not sure if this is correct
// actually I think this might be backwards
fn mask(x: u8, y: u8) -> u32 {
    let mut mask:u32 = 0xFFFFFFFF >> y;

    if x >= 31 {
        mask ^= 0;
    } else {
        mask ^= 0xFFFFFFFF >> (x + 1);
    }

    if y > x {
        !mask
    } else {
        mask
    }
}

fn bon(bo: u8, n: u8) -> u8 {
    (bo >> (4-n)) & 1
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MSR: {:?} gpr: {:?}, sr: {:?}, cr:{:?}, HID0: {}", self.msr, self.gpr, self.sr, self.cr, self.spr[HID0])
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

// This is more or less in the order it appears in the Lua manual, with the
// exception of constants, which appear scattered throughout the manual text.

// luaconf.h functions
pub use self::luaconf::lua_numtointeger;

// C API types
pub use self::lua::{
  lua_Alloc,
  lua_CFunction,
  lua_Ctx,
  lua_Debug,
  lua_Hook,
  lua_Integer,
  lua_KFunction,
  lua_Number,
  lua_Reader,
  lua_State,
  lua_Unsigned,
  lua_Writer
};

// C API functions
pub use self::lua::{
  lua_absindex,
  lua_arith,
  lua_atpanic,
  lua_call,
  lua_callk,
  lua_checkstack,
  lua_close,
  lua_compare,
  lua_concat,
  lua_copy,
  lua_createtable,
  lua_dump,
  lua_error,
  lua_gc,
  lua_getallocf,
  lua_getextraspace,
  lua_getfield,
  lua_getglobal,
  lua_gethook,
  lua_gethookcount,
  lua_gethookmask,
  lua_getinfo,
  lua_getlocal,
  lua_getmetatable,
  lua_getstack,
  lua_gettable,
  lua_gettop,
  lua_getupvalue,
  lua_getuservalue,
  lua_insert,
  lua_isboolean,
  lua_iscfunction,
  lua_isfunction,
  lua_isinteger,
  lua_islightuserdata,
  lua_isnil,
  lua_isnone,
  lua_isnoneornil,
  lua_isnumber,
  lua_isstring,
  lua_istable,
  lua_isthread,
  lua_isuserdata,
  lua_isyieldable,
  lua_len,
  lua_load,
  lua_newstate,
  lua_newtable,
  lua_newthread,
  lua_newuserdata,
  lua_next,
  lua_pcall,
  lua_pcallk,
  lua_pop,
  lua_pushboolean,
  lua_pushcclosure,
  lua_pushcfunction,
  lua_pushfstring,
  lua_pushglobaltable,
  lua_pushinteger,
  lua_pushlightuserdata,
  lua_pushliteral,
  lua_pushlstring,
  lua_pushnil,
  lua_pushnumber,
  lua_pushstring,
  lua_pushthread,
  lua_pushvalue,
  // omitted: lua_pushvfstring
  lua_rawequal,
  lua_rawget,
  lua_rawgeti,
  lua_rawgetp,
  lua_rawlen,
  lua_rawset,
  lua_rawseti,
  lua_rawsetp,
  lua_register,
  lua_remove,
  lua_replace,
  lua_resume,
  lua_rotate,
  lua_setallocf,
  lua_setfield,
  lua_setglobal,
  lua_sethook,
  lua_setlocal,
  lua_setmetatable,
  lua_settable,
  lua_settop,
  lua_setupvalue,
  lua_setuservalue,
  lua_status,
  lua_strtonum,
  lua_toboolean,
  lua_tocfunction,
  lua_tointeger,
  lua_tointegerx,
  lua_tolstring,
  lua_tonumber,
  lua_tonumberx,
  lua_topointer,
  lua_tostring,
  lua_tothread,
  lua_touserdata,
  lua_type,
  lua_typename,
  lua_upvalueid,
  lua_upvalueindex,
  lua_upvaluejoin,
  lua_version,
  lua_xmove,
  lua_yield,
  lua_yieldk
};

// auxiliary library types
pub use self::lauxlib::{
  luaL_Buffer,
  luaL_Reg,
  luaL_Stream
};

// auxiliary library functions
pub use self::lauxlib::{
  luaL_addchar,
  luaL_addlstring,
  luaL_addsize,
  luaL_addstring,
  luaL_addvalue,
  luaL_argcheck,
  luaL_argerror,
  luaL_buffinit,
  luaL_buffinitsize,
  luaL_callmeta,
  luaL_checkany,
  luaL_checkint,
  luaL_checkinteger,
  luaL_checklong,
  luaL_checklstring,
  luaL_checknumber,
  luaL_checkoption,
  luaL_checkstack,
  luaL_checkstring,
  luaL_checktype,
  luaL_checkudata,
  luaL_checkversion,
  luaL_dofile,
  luaL_dostring,
  luaL_error,
  luaL_execresult,
  luaL_fileresult,
  luaL_getmetafield,
  luaL_getmetatable,
  luaL_getsubtable,
  luaL_gsub,
  luaL_len,
  luaL_loadbuffer,
  luaL_loadbufferx,
  luaL_loadfile,
  luaL_loadfilex,
  luaL_loadstring,
  luaL_newlib,
  luaL_newlibtable,
  luaL_newmetatable,
  luaL_newstate,
  luaL_optint,
  luaL_optinteger,
  luaL_optlong,
  luaL_optlstring,
  luaL_optnumber,
  luaL_optstring,
  luaL_prepbuffer,
  luaL_prepbuffsize,
  luaL_pushresult,
  luaL_pushresultsize,
  luaL_ref,
  luaL_requiref,
  luaL_setfuncs,
  luaL_setmetatable,
  luaL_testudata,
  luaL_tolstring,
  luaL_traceback,
  luaL_typename,
  luaL_unref,
  luaL_where
};

// lualib.h functions
pub use self::lualib::{
  luaopen_base,
  luaopen_coroutine,
  luaopen_table,
  luaopen_io,
  luaopen_os,
  luaopen_string,
  luaopen_utf8,
  luaopen_bit32,
  luaopen_math,
  luaopen_debug,
  luaopen_package,

  luaL_openlibs
};

// constants from lua.h
pub use self::lua::{
  LUA_MULTRET,
  LUA_REGISTRYINDEX,

  LUA_RIDX_MAINTHREAD, LUA_RIDX_GLOBALS,

  LUA_OPADD, LUA_OPSUB, LUA_OPMUL, LUA_OPDIV, LUA_OPIDIV,
  LUA_OPMOD, LUA_OPPOW, LUA_OPUNM,
  LUA_OPBNOT, LUA_OPBAND, LUA_OPBOR, LUA_OPBXOR, LUA_OPSHL, LUA_OPSHR,
  LUA_OPEQ, LUA_OPLT, LUA_OPLE,

  LUA_OK, LUA_YIELD, LUA_ERRRUN, LUA_ERRSYNTAX, LUA_ERRMEM, LUA_ERRGCMM, LUA_ERRERR,

  LUA_TNONE, LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE,
  LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, LUA_TLIGHTUSERDATA,

  LUA_HOOKCALL, LUA_HOOKRET, LUA_HOOKTAILCALL, LUA_HOOKLINE, LUA_HOOKCOUNT,

  LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCCOUNTB,
  LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, LUA_GCISRUNNING
};

// constants from lauxlib.h
pub use self::lauxlib::{
  LUA_REFNIL, LUA_NOREF,
  LUA_ERRFILE,
  LUA_FILEHANDLE
};

// constants from lualib.h
pub use self::lualib::{
  LUA_COLIBNAME, LUA_TABLIBNAME, LUA_IOLIBNAME, LUA_OSLIBNAME, LUA_STRLIBNAME,
  LUA_UTF8LIBNAME, LUA_BITLIBNAME, LUA_MATHLIBNAME, LUA_DBLIBNAME, LUA_LOADLIBNAME
};

mod glue;
pub mod luaconf;
pub mod lua;
pub mod lauxlib;
pub mod lualib;

<commit_msg>Re-export hook mask constants<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

// This is more or less in the order it appears in the Lua manual, with the
// exception of constants, which appear scattered throughout the manual text.

// luaconf.h functions
pub use self::luaconf::lua_numtointeger;

// C API types
pub use self::lua::{
  lua_Alloc,
  lua_CFunction,
  lua_Ctx,
  lua_Debug,
  lua_Hook,
  lua_Integer,
  lua_KFunction,
  lua_Number,
  lua_Reader,
  lua_State,
  lua_Unsigned,
  lua_Writer
};

// C API functions
pub use self::lua::{
  lua_absindex,
  lua_arith,
  lua_atpanic,
  lua_call,
  lua_callk,
  lua_checkstack,
  lua_close,
  lua_compare,
  lua_concat,
  lua_copy,
  lua_createtable,
  lua_dump,
  lua_error,
  lua_gc,
  lua_getallocf,
  lua_getextraspace,
  lua_getfield,
  lua_getglobal,
  lua_gethook,
  lua_gethookcount,
  lua_gethookmask,
  lua_getinfo,
  lua_getlocal,
  lua_getmetatable,
  lua_getstack,
  lua_gettable,
  lua_gettop,
  lua_getupvalue,
  lua_getuservalue,
  lua_insert,
  lua_isboolean,
  lua_iscfunction,
  lua_isfunction,
  lua_isinteger,
  lua_islightuserdata,
  lua_isnil,
  lua_isnone,
  lua_isnoneornil,
  lua_isnumber,
  lua_isstring,
  lua_istable,
  lua_isthread,
  lua_isuserdata,
  lua_isyieldable,
  lua_len,
  lua_load,
  lua_newstate,
  lua_newtable,
  lua_newthread,
  lua_newuserdata,
  lua_next,
  lua_pcall,
  lua_pcallk,
  lua_pop,
  lua_pushboolean,
  lua_pushcclosure,
  lua_pushcfunction,
  lua_pushfstring,
  lua_pushglobaltable,
  lua_pushinteger,
  lua_pushlightuserdata,
  lua_pushliteral,
  lua_pushlstring,
  lua_pushnil,
  lua_pushnumber,
  lua_pushstring,
  lua_pushthread,
  lua_pushvalue,
  // omitted: lua_pushvfstring
  lua_rawequal,
  lua_rawget,
  lua_rawgeti,
  lua_rawgetp,
  lua_rawlen,
  lua_rawset,
  lua_rawseti,
  lua_rawsetp,
  lua_register,
  lua_remove,
  lua_replace,
  lua_resume,
  lua_rotate,
  lua_setallocf,
  lua_setfield,
  lua_setglobal,
  lua_sethook,
  lua_setlocal,
  lua_setmetatable,
  lua_settable,
  lua_settop,
  lua_setupvalue,
  lua_setuservalue,
  lua_status,
  lua_strtonum,
  lua_toboolean,
  lua_tocfunction,
  lua_tointeger,
  lua_tointegerx,
  lua_tolstring,
  lua_tonumber,
  lua_tonumberx,
  lua_topointer,
  lua_tostring,
  lua_tothread,
  lua_touserdata,
  lua_type,
  lua_typename,
  lua_upvalueid,
  lua_upvalueindex,
  lua_upvaluejoin,
  lua_version,
  lua_xmove,
  lua_yield,
  lua_yieldk
};

// auxiliary library types
pub use self::lauxlib::{
  luaL_Buffer,
  luaL_Reg,
  luaL_Stream
};

// auxiliary library functions
pub use self::lauxlib::{
  luaL_addchar,
  luaL_addlstring,
  luaL_addsize,
  luaL_addstring,
  luaL_addvalue,
  luaL_argcheck,
  luaL_argerror,
  luaL_buffinit,
  luaL_buffinitsize,
  luaL_callmeta,
  luaL_checkany,
  luaL_checkint,
  luaL_checkinteger,
  luaL_checklong,
  luaL_checklstring,
  luaL_checknumber,
  luaL_checkoption,
  luaL_checkstack,
  luaL_checkstring,
  luaL_checktype,
  luaL_checkudata,
  luaL_checkversion,
  luaL_dofile,
  luaL_dostring,
  luaL_error,
  luaL_execresult,
  luaL_fileresult,
  luaL_getmetafield,
  luaL_getmetatable,
  luaL_getsubtable,
  luaL_gsub,
  luaL_len,
  luaL_loadbuffer,
  luaL_loadbufferx,
  luaL_loadfile,
  luaL_loadfilex,
  luaL_loadstring,
  luaL_newlib,
  luaL_newlibtable,
  luaL_newmetatable,
  luaL_newstate,
  luaL_optint,
  luaL_optinteger,
  luaL_optlong,
  luaL_optlstring,
  luaL_optnumber,
  luaL_optstring,
  luaL_prepbuffer,
  luaL_prepbuffsize,
  luaL_pushresult,
  luaL_pushresultsize,
  luaL_ref,
  luaL_requiref,
  luaL_setfuncs,
  luaL_setmetatable,
  luaL_testudata,
  luaL_tolstring,
  luaL_traceback,
  luaL_typename,
  luaL_unref,
  luaL_where
};

// lualib.h functions
pub use self::lualib::{
  luaopen_base,
  luaopen_coroutine,
  luaopen_table,
  luaopen_io,
  luaopen_os,
  luaopen_string,
  luaopen_utf8,
  luaopen_bit32,
  luaopen_math,
  luaopen_debug,
  luaopen_package,

  luaL_openlibs
};

// constants from lua.h
pub use self::lua::{
  LUA_MULTRET,
  LUA_REGISTRYINDEX,

  LUA_RIDX_MAINTHREAD, LUA_RIDX_GLOBALS,

  LUA_OPADD, LUA_OPSUB, LUA_OPMUL, LUA_OPDIV, LUA_OPIDIV,
  LUA_OPMOD, LUA_OPPOW, LUA_OPUNM,
  LUA_OPBNOT, LUA_OPBAND, LUA_OPBOR, LUA_OPBXOR, LUA_OPSHL, LUA_OPSHR,
  LUA_OPEQ, LUA_OPLT, LUA_OPLE,

  LUA_OK, LUA_YIELD, LUA_ERRRUN, LUA_ERRSYNTAX, LUA_ERRMEM, LUA_ERRGCMM, LUA_ERRERR,

  LUA_TNONE, LUA_TNIL, LUA_TNUMBER, LUA_TBOOLEAN, LUA_TSTRING, LUA_TTABLE,
  LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, LUA_TLIGHTUSERDATA,

  LUA_HOOKCALL, LUA_HOOKRET, LUA_HOOKTAILCALL, LUA_HOOKLINE, LUA_HOOKCOUNT,
  LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE, LUA_MASKCOUNT,

  LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCCOUNTB,
  LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, LUA_GCISRUNNING
};

// constants from lauxlib.h
pub use self::lauxlib::{
  LUA_REFNIL, LUA_NOREF,
  LUA_ERRFILE,
  LUA_FILEHANDLE
};

// constants from lualib.h
pub use self::lualib::{
  LUA_COLIBNAME, LUA_TABLIBNAME, LUA_IOLIBNAME, LUA_OSLIBNAME, LUA_STRLIBNAME,
  LUA_UTF8LIBNAME, LUA_BITLIBNAME, LUA_MATHLIBNAME, LUA_DBLIBNAME, LUA_LOADLIBNAME
};

mod glue;
pub mod luaconf;
pub mod lua;
pub mod lauxlib;
pub mod lualib;

<|endoftext|>


<commit_before>/*
 This Source Code Form is subject to the terms of the Mozilla Public
 License, v. 2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

use rusqlite::{Connection, Row};

use crate::catalog::CatalogVersion;
use crate::content::Content;
use crate::fromdb::FromDb;
use crate::lrobject::{LrId, LrObject};

/// A folder define the container for `LibraryFiles`
/// They are all attached to a `RootFolder`
#[derive(Clone)]
pub struct Folder {
    id: LrId,
    uuid: String,
    /// Path from the `RootFolder`
    pub path_from_root: String,
    /// Id of the `RootFolder`
    pub root_folder: LrId,
    pub content: Option<Content>,
}

impl LrObject for Folder {
    fn id(&self) -> LrId {
        self.id
    }
    fn uuid(&self) -> &str {
        &self.uuid
    }
}

impl FromDb for Folder {
    fn read_from(_version: CatalogVersion, row: &Row) -> crate::Result<Self> {
        Ok(Folder {
            id: row.get(0)?,
            uuid: row.get(1)?,
            path_from_root: row.get(2)?,
            root_folder: row.get(3)?,
            content: None,
        })
    }
    fn read_db_tables(_version: CatalogVersion) -> &'static str {
        "AgLibraryFolder"
    }
    fn read_db_columns(_version: CatalogVersion) -> &'static str {
        "id_local,id_global,pathFromRoot,rootFolder"
    }
}

impl Folder {
    pub fn new(id: LrId, uuid: &str) -> Folder {
        Folder {
            id,
            uuid: String::from(uuid),
            path_from_root: String::from(""),
            root_folder: 0,
            content: None,
        }
    }
    pub fn read_content(&self, conn: &Connection) -> Content {
        Content::from_db(conn, "AgFolderContent", "containingFolder", self.id)
    }
}

/// Represent the ancestor of `Folder` and map to
/// an absolute path
#[derive(Clone)]
pub struct RootFolder {
    id: LrId,
    uuid: String,
    /// Absolute path of the `RootFolder`
    pub absolute_path: String,
    /// (User readable) name of the `RootFolder`
    pub name: String,
    /// Eventually if it is possible the path is relative
    /// to the catalog file.
    pub relative_path_from_catalog: Option<String>,
}

impl LrObject for RootFolder {
    fn id(&self) -> LrId {
        self.id
    }
    fn uuid(&self) -> &str {
        &self.uuid
    }
}

impl RootFolder {
    /// Create a new `RootFolder` with an id and uuid
    pub fn new(id: LrId, uuid: &str) -> RootFolder {
        RootFolder {
            id,
            uuid: String::from(uuid),
            absolute_path: String::from(""),
            name: String::from(""),
            relative_path_from_catalog: None,
        }
    }
}

impl FromDb for RootFolder {
    fn read_from(_version: CatalogVersion, row: &Row) -> crate::Result<Self> {
        Ok(RootFolder {
            id: row.get(0)?,
            uuid: row.get(1)?,
            absolute_path: row.get(2)?,
            name: row.get(3)?,
            relative_path_from_catalog: row.get(4).ok(),
        })
    }

    fn read_db_tables(_version: CatalogVersion) -> &'static str {
        "AgLibraryRootFolder"
    }

    fn read_db_columns(_version: CatalogVersion) -> &'static str {
        "id_local,id_global,absolutePath,name,relativePathFromCatalog"
    }
}

/// Represent the all the folders
#[derive(Clone, Default)]
pub struct Folders {
    /// The `RootFolder` list
    pub roots: Vec<RootFolder>,
    /// The `Folder` list
    pub folders: Vec<Folder>,
}

impl Folders {
    pub fn new() -> Folders {
        Folders::default()
    }

    /// Return `true` is it is empty
    pub fn is_empty(&self) -> bool {
        self.roots.is_empty() && self.folders.is_empty()
    }

    /// Add a `Folder`
    pub fn add_folder(&mut self, folder: Folder) {
        self.folders.push(folder);
    }

    /// Add a `RootFolder`
    pub fn add_root_folder(&mut self, root_folder: RootFolder) {
        self.roots.push(root_folder);
    }

    /// Append a vector of `Folder`
    pub fn append_folders(&mut self, mut folders: Vec<Folder>) {
        self.folders.append(&mut folders);
    }

    /// Append a vector of `RootFolder`
    pub fn append_root_folders(&mut self, mut root_folders: Vec<RootFolder>) {
        self.roots.append(&mut root_folders);
    }

    /// Return the eventual `RootFolder` with the id.
    fn find_root_folder(&self, id: LrId) -> Option<&RootFolder> {
        for root in &self.roots {
            if root.id() == id {
                return Some(root);
            }
        }
        None
    }

    /// Resolve the folder path by providing an absolute path
    /// This does not check if the path exist but merely combine
    /// the `RootFolder` absolute_path and the `Folder` relative path
    pub fn resolve_folder_path(&self, folder: &Folder) -> Option<String> {
        let root_folder = self.find_root_folder(folder.root_folder)?;
        let mut root_path = root_folder.absolute_path.clone();
        root_path += &folder.path_from_root;
        Some(root_path)
    }
}

#[cfg(test)]
#[test]
fn test_resolve_folder_path() {
    let mut folders = Folders::new();

    let mut rfolder = RootFolder::new(24, "toplevel");
    rfolder.absolute_path = String::from("/home/hub/Pictures");
    rfolder.name = String::from("Pictures");
    folders.add_root_folder(rfolder);

    let mut folder = Folder::new(42, "foobar");
    folder.root_folder = 24;
    folder.path_from_root = String::from("/2017/10");
    folders.add_folder(folder);

    let resolved = folders.resolve_folder_path(&folders.folders[0]);
    assert!(resolved.is_some());
    let resolved = resolved.unwrap();
    assert_eq!(resolved, "/home/hub/Pictures/2017/10");
}
<commit_msg>Folders::find_root_folder() is public<commit_after>/*
 This Source Code Form is subject to the terms of the Mozilla Public
 License, v. 2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

use rusqlite::{Connection, Row};

use crate::catalog::CatalogVersion;
use crate::content::Content;
use crate::fromdb::FromDb;
use crate::lrobject::{LrId, LrObject};

/// A folder define the container for `LibraryFiles`
/// They are all attached to a `RootFolder`
#[derive(Clone)]
pub struct Folder {
    id: LrId,
    uuid: String,
    /// Path from the `RootFolder`
    pub path_from_root: String,
    /// Id of the `RootFolder`
    pub root_folder: LrId,
    pub content: Option<Content>,
}

impl LrObject for Folder {
    fn id(&self) -> LrId {
        self.id
    }
    fn uuid(&self) -> &str {
        &self.uuid
    }
}

impl FromDb for Folder {
    fn read_from(_version: CatalogVersion, row: &Row) -> crate::Result<Self> {
        Ok(Folder {
            id: row.get(0)?,
            uuid: row.get(1)?,
            path_from_root: row.get(2)?,
            root_folder: row.get(3)?,
            content: None,
        })
    }
    fn read_db_tables(_version: CatalogVersion) -> &'static str {
        "AgLibraryFolder"
    }
    fn read_db_columns(_version: CatalogVersion) -> &'static str {
        "id_local,id_global,pathFromRoot,rootFolder"
    }
}

impl Folder {
    pub fn new(id: LrId, uuid: &str) -> Folder {
        Folder {
            id,
            uuid: String::from(uuid),
            path_from_root: String::from(""),
            root_folder: 0,
            content: None,
        }
    }
    pub fn read_content(&self, conn: &Connection) -> Content {
        Content::from_db(conn, "AgFolderContent", "containingFolder", self.id)
    }
}

/// Represent the ancestor of `Folder` and map to
/// an absolute path
#[derive(Clone)]
pub struct RootFolder {
    id: LrId,
    uuid: String,
    /// Absolute path of the `RootFolder`
    pub absolute_path: String,
    /// (User readable) name of the `RootFolder`
    pub name: String,
    /// Eventually if it is possible the path is relative
    /// to the catalog file.
    pub relative_path_from_catalog: Option<String>,
}

impl LrObject for RootFolder {
    fn id(&self) -> LrId {
        self.id
    }
    fn uuid(&self) -> &str {
        &self.uuid
    }
}

impl RootFolder {
    /// Create a new `RootFolder` with an id and uuid
    pub fn new(id: LrId, uuid: &str) -> RootFolder {
        RootFolder {
            id,
            uuid: String::from(uuid),
            absolute_path: String::from(""),
            name: String::from(""),
            relative_path_from_catalog: None,
        }
    }
}

impl FromDb for RootFolder {
    fn read_from(_version: CatalogVersion, row: &Row) -> crate::Result<Self> {
        Ok(RootFolder {
            id: row.get(0)?,
            uuid: row.get(1)?,
            absolute_path: row.get(2)?,
            name: row.get(3)?,
            relative_path_from_catalog: row.get(4).ok(),
        })
    }

    fn read_db_tables(_version: CatalogVersion) -> &'static str {
        "AgLibraryRootFolder"
    }

    fn read_db_columns(_version: CatalogVersion) -> &'static str {
        "id_local,id_global,absolutePath,name,relativePathFromCatalog"
    }
}

/// Represent the all the folders
#[derive(Clone, Default)]
pub struct Folders {
    /// The `RootFolder` list
    pub roots: Vec<RootFolder>,
    /// The `Folder` list
    pub folders: Vec<Folder>,
}

impl Folders {
    pub fn new() -> Folders {
        Folders::default()
    }

    /// Return `true` is it is empty
    pub fn is_empty(&self) -> bool {
        self.roots.is_empty() && self.folders.is_empty()
    }

    /// Add a `Folder`
    pub fn add_folder(&mut self, folder: Folder) {
        self.folders.push(folder);
    }

    /// Add a `RootFolder`
    pub fn add_root_folder(&mut self, root_folder: RootFolder) {
        self.roots.push(root_folder);
    }

    /// Append a vector of `Folder`
    pub fn append_folders(&mut self, mut folders: Vec<Folder>) {
        self.folders.append(&mut folders);
    }

    /// Append a vector of `RootFolder`
    pub fn append_root_folders(&mut self, mut root_folders: Vec<RootFolder>) {
        self.roots.append(&mut root_folders);
    }

    /// Return the eventual `RootFolder` with the id.
    pub fn find_root_folder(&self, id: LrId) -> Option<&RootFolder> {
        for root in &self.roots {
            if root.id() == id {
                return Some(root);
            }
        }
        None
    }

    /// Resolve the folder path by providing an absolute path
    /// This does not check if the path exist but merely combine
    /// the `RootFolder` absolute_path and the `Folder` relative path
    pub fn resolve_folder_path(&self, folder: &Folder) -> Option<String> {
        let root_folder = self.find_root_folder(folder.root_folder)?;
        let mut root_path = root_folder.absolute_path.clone();
        root_path += &folder.path_from_root;
        Some(root_path)
    }
}

#[cfg(test)]
#[test]
fn test_resolve_folder_path() {
    let mut folders = Folders::new();

    let mut rfolder = RootFolder::new(24, "toplevel");
    rfolder.absolute_path = String::from("/home/hub/Pictures");
    rfolder.name = String::from("Pictures");
    folders.add_root_folder(rfolder);

    let mut folder = Folder::new(42, "foobar");
    folder.root_folder = 24;
    folder.path_from_root = String::from("/2017/10");
    folders.add_folder(folder);

    let resolved = folders.resolve_folder_path(&folders.folders[0]);
    assert!(resolved.is_some());
    let resolved = resolved.unwrap();
    assert_eq!(resolved, "/home/hub/Pictures/2017/10");
}
<|endoftext|>


<commit_before>use engine::Game;
use gui::{Console, Colors, Key};
use util::units::{Direction, Point, Size};

#[deriving(PartialEq)]
pub enum State {
    Running,
    Exited
}

pub struct GUI<'a> {
    pub console: &'a mut (Console + 'a),
    game: Game,
    state: State,
}

impl<'a> GUI<'a> {
    pub fn new<T>(game: Game, console: &'a mut T) -> GUI where T: Console {
        GUI {
            game: game,
            console: console,
            state: State::Running,
        }
    }

    pub fn size(&self) -> Size {
        self.console.size()
    }

    pub fn run(&mut self) {
        while !self.console.window_closed() && !self.exited() {
            self.render();
            self.handle_input();
        }
    }

    fn handle_input(&mut self) {
        if let Some(key) = self.console.check_for_keypress() {
            match key {
                Key::Up => {
                    self.game.walk(Direction::Up);
                },
                Key::Down => {
                    self.game.walk(Direction::Down);
                },
                Key::Left => {
                    self.game.walk(Direction::Left);
                },
                Key::Right => {
                    self.game.walk(Direction::Right);
                },
                Key::Escape => {
                    self.state = State::Exited;
                },
            }
        }

    }

    fn render(&mut self) {
        self.console.clear();

        self.render_map();

        let repr = self.game.world.player.repr;
        let pos = self.game.world.player.pos;

        self.console.put_plain(pos, repr);

        self.console.flush();
    }

    fn render_map(&mut self) {
        let map = &(self.game.world.map);

        for (y, line) in map.tiles.iter().enumerate() {
            for (x, cell) in line.iter().enumerate() {
                self.console.put(Point::new(x as int, y as int), ' ', Colors::white, cell.b_color());
            }
        }
    }

    pub fn exited(&self) -> bool {
        self.state == State::Exited
    }
}
<commit_msg>Remove final instance of `deriving`<commit_after>use engine::Game;
use gui::{Console, Colors, Key};
use util::units::{Direction, Point, Size};

#[derive(PartialEq)]
pub enum State {
    Running,
    Exited
}

pub struct GUI<'a> {
    pub console: &'a mut (Console + 'a),
    game: Game,
    state: State,
}

impl<'a> GUI<'a> {
    pub fn new<T>(game: Game, console: &'a mut T) -> GUI where T: Console {
        GUI {
            game: game,
            console: console,
            state: State::Running,
        }
    }

    pub fn size(&self) -> Size {
        self.console.size()
    }

    pub fn run(&mut self) {
        while !self.console.window_closed() && !self.exited() {
            self.render();
            self.handle_input();
        }
    }

    fn handle_input(&mut self) {
        if let Some(key) = self.console.check_for_keypress() {
            match key {
                Key::Up => {
                    self.game.walk(Direction::Up);
                },
                Key::Down => {
                    self.game.walk(Direction::Down);
                },
                Key::Left => {
                    self.game.walk(Direction::Left);
                },
                Key::Right => {
                    self.game.walk(Direction::Right);
                },
                Key::Escape => {
                    self.state = State::Exited;
                },
            }
        }

    }

    fn render(&mut self) {
        self.console.clear();

        self.render_map();

        let repr = self.game.world.player.repr;
        let pos = self.game.world.player.pos;

        self.console.put_plain(pos, repr);

        self.console.flush();
    }

    fn render_map(&mut self) {
        let map = &(self.game.world.map);

        for (y, line) in map.tiles.iter().enumerate() {
            for (x, cell) in line.iter().enumerate() {
                self.console.put(Point::new(x as int, y as int), ' ', Colors::white, cell.b_color());
            }
        }
    }

    pub fn exited(&self) -> bool {
        self.state == State::Exited
    }
}
<|endoftext|>


<commit_before>use base::math::*;

pub fn convert(map: Vec<Vec<f32>>, scale: f32) -> Vec<Vec<(f32, f32, f32)>> {
    let mut normals: Vec<Vec<(f32, f32, f32)>> =
        vec![vec![(0.0,0.0,0.0); map[0].len() as usize]; map.len() as usize];
    let mut n: Vector3f = Vector3f::new(0.0, 0.0, 0.0);
    let mut arr;

    for i in 0..map.len() {
        for j in 0..map[0].len() {
            arr = neighbours(&map, (i as i32, j as i32));
            n.x = scale *
                  -(arr[8 as usize] - arr[6 as usize] + 2.0 * (arr[5 as usize] - arr[3 as usize]) +
                    arr[2 as usize] - arr[0 as usize]);
            n.y = scale *
                  -(arr[0 as usize] - arr[6 as usize] + 2.0 * (arr[1 as usize] - arr[7 as usize]) +
                    arr[2 as usize] - arr[8 as usize]);
            n.z = 1.0;
            n = n.normalize();
            normals[i as usize][j as usize] = (n.x, n.y, n.z);
        }
    }
    normals
}

fn neighbours(map: &Vec<Vec<f32>>, pos: (i32, i32)) -> [f32; 9] {
    let ref tmap = *map;
    let mut iter = 0;
    let mut arr: [f32; 9] = [0.0; 9];

    for p in 0..3 {
        for q in 0..3 {
            //        println!("{}{}", p, q);
            if tmap.get((pos.0 + p - 1) as usize).is_none() ||
               tmap[(pos.0 + p - 1) as usize].get((pos.1 + q - 1) as usize).is_none() {
                arr[iter] = tmap[pos.0 as usize][pos.1 as usize];
            } else {
                arr[iter] = tmap[(pos.0 + p - 1) as usize][(pos.1 + q - 1) as usize];
            }
            iter += 1;
        }
    }
    info!("{:?}", arr);
    arr
}
<commit_msg>take out info<commit_after>use base::math::*;

pub fn convert(map: Vec<Vec<f32>>, scale: f32) -> Vec<Vec<(f32, f32, f32)>> {
    let mut normals: Vec<Vec<(f32, f32, f32)>> =
        vec![vec![(0.0,0.0,0.0); map[0].len() as usize]; map.len() as usize];
    let mut n: Vector3f = Vector3f::new(0.0, 0.0, 0.0);
    let mut arr;

    for i in 0..map.len() {
        for j in 0..map[0].len() {
            arr = neighbours(&map, (i as i32, j as i32));
            n.x = scale *
                  -(arr[8 as usize] - arr[6 as usize] + 2.0 * (arr[5 as usize] - arr[3 as usize]) +
                    arr[2 as usize] - arr[0 as usize]);
            n.y = scale *
                  -(arr[0 as usize] - arr[6 as usize] + 2.0 * (arr[1 as usize] - arr[7 as usize]) +
                    arr[2 as usize] - arr[8 as usize]);
            n.z = 1.0;
            n = n.normalize();
            normals[i as usize][j as usize] = (n.x, n.y, n.z);
        }
    }
    normals
}

fn neighbours(map: &Vec<Vec<f32>>, pos: (i32, i32)) -> [f32; 9] {
    let ref tmap = *map;
    let mut iter = 0;
    let mut arr: [f32; 9] = [0.0; 9];

    for p in 0..3 {
        for q in 0..3 {
            // println!("{}{}", p, q);
            if tmap.get((pos.0 + p - 1) as usize).is_none() ||
               tmap[(pos.0 + p - 1) as usize].get((pos.1 + q - 1) as usize).is_none() {
                arr[iter] = tmap[pos.0 as usize][pos.1 as usize];
            } else {
                arr[iter] = tmap[(pos.0 + p - 1) as usize][(pos.1 + q - 1) as usize];
            }
            iter += 1;
        }
    }
    // info!("{:?}", arr);
    arr
}
<|endoftext|>


<commit_before><commit_msg>Rename io -> old_io<commit_after><|endoftext|>


<commit_before>use std::collections::HashMap;

use common::{Result, Id, Op2, Const};
use explicit;
use implicit;
use env;
use hindley_milner;

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Imm {
    Bool(bool),
    Int(i64),
    Var(Id),
    //    Fun(Id, Box<Expr>),
    //    Fix(Id, Box<Expr>),
    //    Star,
    //    V,
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Op {
    Op2(Op2, Box<Imm>, Box<Imm>),
    //    MkArray(Box<Imm>, Box<Imm>),
    //    GetArray(Box<Imm>, Box<Imm>),
    //    SetArray(Box<Imm>, Box<Imm>, Box<Imm>),
    Imm(Imm),
}
//    WellFormed(Imm), // Var-only

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Expr {
    //    If(Box<Imm>, Box<Imm>, Box<Imm>),
    //    App(Box<Imm>, Box<Imm>),
    Let(Id, Box<Expr>, Box<Expr>),
    Op(Op),
}

#[derive(PartialEq, Eq, Clone, Debug)]
struct ConvEnv {
    //env: HashMap<Id, explicit::Type>,
    next_id: i32,
}

impl ConvEnv {
    fn new() -> ConvEnv {
        ConvEnv {
            //env: HashMap::new(),
            next_id: 0,
        }
    }

    fn tmp(&self) -> (ConvEnv, Id) {
        let id = self.next_id;
        let c = ConvEnv{
            //env: self.env.clone(),
            next_id: self.next_id+1,
        };

        (c, format!("!tmp!{}", id))
    }
}

fn op(cenv: ConvEnv, e: &explicit::Expr) -> (ConvEnv, Op) {
    use typed::Expr as E;
    match *e {
        E::Const(Const::Bool(c)) => (cenv, Op::Imm(Imm::Bool(c))),
        E::Const(Const::Int(c)) => (cenv, Op::Imm(Imm::Int(c))),
        _ => {
            panic!("TODO: implement term for {:?}", e);
        }
    }
}

fn identity(cenv: ConvEnv, e: Expr) -> (ConvEnv, Expr) {
    (cenv, e)
}

fn imm(e: &Expr) -> Option<Imm> {
    if let &Expr::Op(Op::Imm(ref i)) = e {
        Some(i.clone())
    } else {
        None
    }
}

// 1:1 translation -- can't fail
fn expr(cenv: ConvEnv, e: &explicit::Expr, k: &Fn(ConvEnv, Expr) -> (ConvEnv, Expr)) -> (ConvEnv, Expr) {

    use self::Imm as I;
    use typed::Expr as E;
    use self::Op::*;
    use self::Expr::*;

    match *e {
        E::Const(_) => {
            let (cenv, eop) = op(cenv, e);
            k(cenv, Op(eop))
        }
        E::Op2(op, ref l, ref r) => {
            expr(cenv, l, &|cenv: ConvEnv, ll: Expr| -> (ConvEnv, Expr) {
                expr(cenv, r, &|cenv: ConvEnv, rr: Expr| -> (ConvEnv, Expr) {
                    let mut cenv = cenv;

                    // only allocate a let temporary for l or r if necessary
                    let (l_ref, l_bound) = match imm(&ll) {
                        Some(i) => (i, None),
                        None => {
                            let (l_cenv, l_tmp) = cenv.tmp();
                            cenv = l_cenv;
                            (I::Var(l_tmp.clone()), Some(l_tmp))
                        }
                    };
                    let (r_ref, r_bound) = match imm(&rr) {
                        Some(i) => (i, None),
                        None => {
                            let (r_cenv, r_tmp) = cenv.tmp();
                            cenv = r_cenv;
                            (I::Var(r_tmp.clone()), Some(r_tmp))
                        }
                    };

                    // value to pass to the continuation
                    let val = Op(Op2(op, box l_ref, box r_ref));

                    // our inner expression is whatever the
                    // continuation says it is.
                    let (cenv, mut result) = k(cenv, val);

                    if let Some(r_tmp) = r_bound {
                        result = Let(r_tmp, box rr, box result);
                    }
                    if let Some(l_tmp) = l_bound {
                        result = Let(l_tmp, box ll.clone(), box result);
                    }

                    (cenv, result)
                })
            })
        }
        E::Let(ref id, ref e1, ref e2) => {
            expr(cenv, e1, &|cenv: ConvEnv, e1l: Expr| -> (ConvEnv, Expr) {
                expr(cenv, e2, &|cenv: ConvEnv, e2l: Expr| -> (ConvEnv, Expr) {
                    let (cenv, inner) = k(cenv, e2l);
                    (cenv, Let(id.clone(), box e1l.clone(), box inner))
                })
            })
        }
        E::Var(ref x) => {
            k(cenv, Op(Imm(I::Var(x.clone()))))
        }
        _ => {
            panic!("TODO: implement expr for {:?}", e);
        }
    }
    // E::If(ref e1, ref e2, ref e3) => {
    //     let (n, e1, _) = convert(n, env, renamed, e1);
    //     let (n, e2, t) = convert(n, env, renamed, e2);
    //     let (n, e3, _) = convert(n, env, renamed, e3);
    //     (n, I::If(box e1, box e2, box e3), t)
    // }
    // E::Var(ref x) => {
    //     let αx = renamed.get(x).unwrap();
    //     (n, I::Var(αx.clone()), env.get(αx).unwrap().clone())
    // }
    // E::Let(ref id, ref e1, ref e2) => {
    //     let mut renamed = renamed.clone();
    //     let (n, αid) = (n+1, format!("{}!a{}", id, n));

    //     let (n, e1, t1) = convert(n, env, &renamed, e1);

    //     renamed.insert(id.clone(), αid.clone());
    //     env.insert(αid.clone(), t1);

    //     let (n, e2, t2) = convert(n, env, &renamed, e2);
    //     (n, I::Let(αid, box e1, box e2), t2)
    // }
    // E::Fun(ref id, ref t1, ref e) => {
    //     let mut renamed = renamed.clone();
    //     let (n, αid) = (n+1, format!("{}!a{}", id, n));

    //     renamed.insert(id.clone(), αid.clone());
    //     env.insert(αid.clone(), t1.clone());

    //     let (n, e, t2) = convert(n, env, &renamed, e);

    //     (n, I::Fun(αid, box e), Type::TFun(box t1.clone(), box t2))
    // }
    // E::Fix(ref id, ref t1, ref e) => {
    //     let mut renamed = renamed.clone();
    //     let (n, αid) = (n+1, format!("{}!a{}", id, n));

    //     renamed.insert(id.clone(), αid.clone());
    //     env.insert(αid.clone(), t1.clone());

    //     let (n, e, t2) = convert(n, env, &renamed, e);

    //     (n, I::Fix(αid, box e), t2)
    // }
    // E::App(ref e1, ref e2) => {
    //     let (n, e1, t1) = convert(n, env, renamed, e1);
    //     let (n, e2, _) = convert(n, env, renamed, e2);
    //     let t = match t1 {
    //         Type::TFun(_, t2) => *t2,
    //         _ => panic!("expected TFun, not {:?}", t1),
    //     };
    //     (n, I::App(box e1, box e2), t)
    // }
    // E::MkArray(ref sz, ref val) => {
    //     let (n, sz, _) = convert(n, env, renamed, sz);
    //     let (n, val, _) = convert(n, env, renamed, val);
    //     (n, I::MkArray(box sz, box val), Type::TIntArray)
    // }
    // E::GetArray(ref id, ref idx) => {
    //     let (n, id, _) = convert(n, env, renamed, id);
    //     let (n, idx, _) = convert(n, env, renamed, idx);
    //     (n, I::GetArray(box id, box idx), Type::TInt)
    // }
    // E::SetArray(ref id, ref idx, ref v) => {
    //     let (n, id, _) = convert(n, env, renamed, id);
    //     let (n, idx, _) = convert(n, env, renamed, idx);
    //     let (n, v, _) = convert(n, env, renamed, v);
    //     (n, I::SetArray(box id, box idx, box v), Type::TIntArray)
    // }
}

pub fn anf(implicit_expr: &implicit::Expr) -> Result<(Expr, HashMap<Id, explicit::Type>)> {

    let explicit_expr = hindley_milner::infer(implicit_expr)?;
    // alpha-renaming
    let (alpha_expr, env) = env::extract(&explicit_expr);

    // println!("α-implicit: {:?}\n", α_expr);
    // println!("Γ         : {:?}\n", env);

    let cenv = ConvEnv::new();
    let (_, expr) = expr(cenv, &alpha_expr, &identity);

    Ok((expr, env))
    // step 1 -- arithmatic + let bindings
    // step 2 -- conds + boolean vals
    // step 3 -- arrays
    // step 4 -- closures

    // (define (Value? M)
    //   (match M
    //     [`(quote ,_)         #t]
    //     [(? number?)         #t]
    //     [(? boolean?)        #t]
    //     [(? string?)         #t]
    //     [(? char?)           #t]
    //     [(? symbol?)         #t]
    //     [(or '+ '- '* '/ '=) #t]
    //     [else                #f]))

    // (define (normalize-term M) (normalize M (λ (x) x)))

    // (define (normalize M k)
    //   (match M
    //     [`(λ ,params ,body)
    //       (k `(λ ,params ,(normalize-term body)))]

    //     [`(let ([,x ,M1]) ,M2)
    //       (normalize M1 (λ (N1)
    //        `(let ([,x ,N1])
    //          ,(normalize M2 k))))]

    //     [`(if ,M1 ,M2 ,M3)
    //       (normalize-name M1 (λ (t)
    //        (k `(if ,t ,(normalize-term M2)
    //                   ,(normalize-term M3)))))]

    //     [`(,Fn . ,M*)
    //       (normalize-name Fn (λ (t)
    //        (normalize-name* M* (λ (t*)
    //         (k `(,t . ,t*))))))]

    //     [(? Value?)             (k M)]))

    // (define (normalize-name M k)
    //   (normalize M (λ (N)
    //     (if (Value? N) (k N)
    //         (let ([t (gensym)])
    //          `(let ([,t ,N]) ,(k t)))))))

    // (define (normalize-name* M* k)
    //   (if (null? M*)
    //       (k '())
    //       (normalize-name (car M*) (λ (t)
    //        (normalize-name* (cdr M*) (λ (t*)
    //         (k `(,t . ,t*))))))))

}

macro_rules! test_anf(
    ($s:expr, $ae:expr) => { {
        use implicit_parse;
        use tok::Tokenizer;
        use std;
        let s = $s;
        let tokenizer = Tokenizer::new(&s);
        let iexpr = match implicit_parse::parse_Program(&s, tokenizer) {
            Ok(iexpr) => iexpr,
            Err(e) => {
                die!("parse_Program({}): {:?}", $s, e);
            }
        };
        let anf_expr = match anf(&iexpr) {
            Ok((anf_expr, _)) => anf_expr,
            Err(e) => {
                die!("anf: {:?}", e);
            }
        };
        if anf_expr != $ae {
            die!("mismatch {:?} != {:?}", anf_expr, $ae);
        }
    } }
);

#[test]
fn anf_transforms() {
    use common::Op2 as O;
    use self::Imm as I;
    use self::Op::*;
    use self::Expr::*;

    test_anf!(
        "-22",
        Op(Imm(I::Int(-22))));

    test_anf!(
        "2+3",
        Op(Op2(O::Add, box I::Int(2), box I::Int(3))));

    test_anf!(
        "2+(3 - 2)",
        Let(String::from("!tmp!0"), box Op(Op2(O::Sub, box I::Int(3), box I::Int(2))),
            box Op(Op2(O::Add, box I::Int(2), box I::Var(String::from("!tmp!0"))))));

    test_anf!(
        "let x = 1 in x",
        Let(String::from("x!a1"), box Op(Imm(I::Int(1))),
            box Op(Imm(I::Var(String::from("x!a1"))))));
}
<commit_msg>lambdal: if<commit_after>use std::collections::HashMap;

use common::{Result, Id, Op2, Const};
use explicit;
use implicit;
use env;
use hindley_milner;

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Imm {
    Bool(bool),
    Int(i64),
    Var(Id),
    //    Fun(Id, Box<Expr>),
    //    Fix(Id, Box<Expr>),
    //    Star,
    //    V,
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Op {
    Op2(Op2, Box<Imm>, Box<Imm>),
    //    MkArray(Box<Imm>, Box<Imm>),
    //    GetArray(Box<Imm>, Box<Imm>),
    //    SetArray(Box<Imm>, Box<Imm>, Box<Imm>),
    Imm(Imm),
}
//    WellFormed(Imm), // Var-only

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Expr {
    If(Box<Imm>, Box<Expr>, Box<Expr>),
    //    App(Box<Imm>, Box<Imm>),
    Let(Id, Box<Expr>, Box<Expr>),
    Op(Op),
}

#[derive(PartialEq, Eq, Clone, Debug)]
struct ConvEnv {
    //env: HashMap<Id, explicit::Type>,
    next_id: i32,
}

impl ConvEnv {
    fn new() -> ConvEnv {
        ConvEnv {
            //env: HashMap::new(),
            next_id: 0,
        }
    }

    fn tmp(&self) -> (ConvEnv, Id) {
        let id = self.next_id;
        let c = ConvEnv{
            //env: self.env.clone(),
            next_id: self.next_id+1,
        };

        (c, format!("!tmp!{}", id))
    }
}

fn op(cenv: ConvEnv, e: &explicit::Expr) -> (ConvEnv, Op) {
    use typed::Expr as E;
    match *e {
        E::Const(Const::Bool(c)) => (cenv, Op::Imm(Imm::Bool(c))),
        E::Const(Const::Int(c)) => (cenv, Op::Imm(Imm::Int(c))),
        _ => {
            panic!("TODO: implement term for {:?}", e);
        }
    }
}

fn identity(cenv: ConvEnv, e: Expr) -> (ConvEnv, Expr) {
    (cenv, e)
}

fn imm(e: &Expr) -> Option<Imm> {
    if let &Expr::Op(Op::Imm(ref i)) = e {
        Some(i.clone())
    } else {
        None
    }
}

// fn getop(e: &Expr) -> Option<Op> {
//     if let &Expr::Op(ref o) = e {
//         Some(o.clone())
//     } else {
//         None
//     }
// }

// 1:1 translation -- can't fail
fn expr(cenv: ConvEnv, e: &explicit::Expr, k: &Fn(ConvEnv, Expr) -> (ConvEnv, Expr)) -> (ConvEnv, Expr) {

    use self::Imm as I;
    use typed::Expr as E;
    use self::Op::*;
    use self::Expr::*;

    match *e {
        E::Const(_) => {
            let (cenv, eop) = op(cenv, e);
            k(cenv, Op(eop))
        }
        E::Op2(op, ref l, ref r) => {
            expr(cenv, l, &|cenv: ConvEnv, ll: Expr| -> (ConvEnv, Expr) {
                expr(cenv, r, &|cenv: ConvEnv, rr: Expr| -> (ConvEnv, Expr) {
                    let mut cenv = cenv;

                    // only allocate a let temporary for l or r if necessary
                    let (l_ref, l_bound) = match imm(&ll) {
                        Some(i) => (i, None),
                        None => {
                            let (l_cenv, l_tmp) = cenv.tmp();
                            cenv = l_cenv;
                            (I::Var(l_tmp.clone()), Some(l_tmp))
                        }
                    };
                    let (r_ref, r_bound) = match imm(&rr) {
                        Some(i) => (i, None),
                        None => {
                            let (r_cenv, r_tmp) = cenv.tmp();
                            cenv = r_cenv;
                            (I::Var(r_tmp.clone()), Some(r_tmp))
                        }
                    };

                    // value to pass to the continuation
                    let val = Op(Op2(op, box l_ref, box r_ref));

                    // our inner expression is whatever the
                    // continuation says it is.
                    let (cenv, mut result) = k(cenv, val);

                    if let Some(r_tmp) = r_bound {
                        result = Let(r_tmp, box rr, box result);
                    }
                    if let Some(l_tmp) = l_bound {
                        result = Let(l_tmp, box ll.clone(), box result);
                    }

                    (cenv, result)
                })
            })
        }
        E::Let(ref id, ref e1, ref e2) => {
            expr(cenv, e1, &|cenv: ConvEnv, e1l: Expr| -> (ConvEnv, Expr) {
                expr(cenv, e2, &|cenv: ConvEnv, e2l: Expr| -> (ConvEnv, Expr) {
                    let (cenv, inner) = k(cenv, e2l);
                    (cenv, Let(id.clone(), box e1l.clone(), box inner))
                })
            })
        }
        E::Var(ref x) => {
            k(cenv, Op(Imm(I::Var(x.clone()))))
        }
        E::If(ref e1, ref e2, ref e3) => {
            expr(cenv, e1, &|cenv: ConvEnv, e1l: Expr| -> (ConvEnv, Expr) {
                let mut cenv = cenv;

                // only allocate a let temporary for cond if necessary
                let (cond_ref, cond_bound) = match imm(&e1l) {
                    Some(op) => (op, None),
                    None => {
                        let (cond_cenv, cond_tmp) = cenv.tmp();
                        cenv = cond_cenv;
                        (I::Var(cond_tmp.clone()), Some(cond_tmp))
                    }
                };

                let (cenv, l_true) = expr(cenv, e2, &identity);
                let (cenv, l_false) = expr(cenv, e3, &identity);

                // value to pass to the continuation
                let val = If(box cond_ref, box l_true, box l_false);

                // our inner expression is whatever the
                // continuation says it is.
                let (cenv, mut result) = k(cenv, val);

                if let Some(cond_tmp) = cond_bound {
                    result = Let(cond_tmp, box e1l, box result);
                }

                (cenv, result)
            })
        }
        _ => {
            panic!("TODO: implement expr for {:?}", e);
        }
    }
    // E::Fun(ref id, ref t1, ref e) => {
    //     let mut renamed = renamed.clone();
    //     let (n, αid) = (n+1, format!("{}!a{}", id, n));

    //     renamed.insert(id.clone(), αid.clone());
    //     env.insert(αid.clone(), t1.clone());

    //     let (n, e, t2) = convert(n, env, &renamed, e);

    //     (n, I::Fun(αid, box e), Type::TFun(box t1.clone(), box t2))
    // }
    // E::Fix(ref id, ref t1, ref e) => {
    //     let mut renamed = renamed.clone();
    //     let (n, αid) = (n+1, format!("{}!a{}", id, n));

    //     renamed.insert(id.clone(), αid.clone());
    //     env.insert(αid.clone(), t1.clone());

    //     let (n, e, t2) = convert(n, env, &renamed, e);

    //     (n, I::Fix(αid, box e), t2)
    // }
    // E::App(ref e1, ref e2) => {
    //     let (n, e1, t1) = convert(n, env, renamed, e1);
    //     let (n, e2, _) = convert(n, env, renamed, e2);
    //     let t = match t1 {
    //         Type::TFun(_, t2) => *t2,
    //         _ => panic!("expected TFun, not {:?}", t1),
    //     };
    //     (n, I::App(box e1, box e2), t)
    // }
    // E::MkArray(ref sz, ref val) => {
    //     let (n, sz, _) = convert(n, env, renamed, sz);
    //     let (n, val, _) = convert(n, env, renamed, val);
    //     (n, I::MkArray(box sz, box val), Type::TIntArray)
    // }
    // E::GetArray(ref id, ref idx) => {
    //     let (n, id, _) = convert(n, env, renamed, id);
    //     let (n, idx, _) = convert(n, env, renamed, idx);
    //     (n, I::GetArray(box id, box idx), Type::TInt)
    // }
    // E::SetArray(ref id, ref idx, ref v) => {
    //     let (n, id, _) = convert(n, env, renamed, id);
    //     let (n, idx, _) = convert(n, env, renamed, idx);
    //     let (n, v, _) = convert(n, env, renamed, v);
    //     (n, I::SetArray(box id, box idx, box v), Type::TIntArray)
    // }
}

pub fn anf(implicit_expr: &implicit::Expr) -> Result<(Expr, HashMap<Id, explicit::Type>)> {

    let explicit_expr = hindley_milner::infer(implicit_expr)?;
    // alpha-renaming
    let (alpha_expr, env) = env::extract(&explicit_expr);

    // println!("α-implicit: {:?}\n", α_expr);
    // println!("Γ         : {:?}\n", env);

    let cenv = ConvEnv::new();
    let (_, expr) = expr(cenv, &alpha_expr, &identity);

    Ok((expr, env))
    // step 1 -- arithmatic + let bindings
    // step 2 -- conds + boolean vals
    // step 3 -- arrays
    // step 4 -- closures

    // (define (Value? M)
    //   (match M
    //     [`(quote ,_)         #t]
    //     [(? number?)         #t]
    //     [(? boolean?)        #t]
    //     [(? string?)         #t]
    //     [(? char?)           #t]
    //     [(? symbol?)         #t]
    //     [(or '+ '- '* '/ '=) #t]
    //     [else                #f]))

    // (define (normalize-term M) (normalize M (λ (x) x)))

    // (define (normalize M k)
    //   (match M
    //     [`(λ ,params ,body)
    //       (k `(λ ,params ,(normalize-term body)))]

    //     [`(let ([,x ,M1]) ,M2)
    //       (normalize M1 (λ (N1)
    //        `(let ([,x ,N1])
    //          ,(normalize M2 k))))]

    //     [`(if ,M1 ,M2 ,M3)
    //       (normalize-name M1 (λ (t)
    //        (k `(if ,t ,(normalize-term M2)
    //                   ,(normalize-term M3)))))]

    //     [`(,Fn . ,M*)
    //       (normalize-name Fn (λ (t)
    //        (normalize-name* M* (λ (t*)
    //         (k `(,t . ,t*))))))]

    //     [(? Value?)             (k M)]))

    // (define (normalize-name M k)
    //   (normalize M (λ (N)
    //     (if (Value? N) (k N)
    //         (let ([t (gensym)])
    //          `(let ([,t ,N]) ,(k t)))))))

    // (define (normalize-name* M* k)
    //   (if (null? M*)
    //       (k '())
    //       (normalize-name (car M*) (λ (t)
    //        (normalize-name* (cdr M*) (λ (t*)
    //         (k `(,t . ,t*))))))))

}

macro_rules! test_anf(
    ($s:expr, $ae:expr) => { {
        use implicit_parse;
        use tok::Tokenizer;
        use std;
        let s = $s;
        let tokenizer = Tokenizer::new(&s);
        let iexpr = match implicit_parse::parse_Program(&s, tokenizer) {
            Ok(iexpr) => iexpr,
            Err(e) => {
                die!("parse_Program({}): {:?}", $s, e);
            }
        };
        let anf_expr = match anf(&iexpr) {
            Ok((anf_expr, _)) => anf_expr,
            Err(e) => {
                die!("anf: {:?}", e);
            }
        };
        if anf_expr != $ae {
            die!("mismatch {:?} != {:?}", anf_expr, $ae);
        }
    } }
);

#[test]
fn anf_transforms() {
    use common::Op2 as O;
    use self::Imm as I;
    use self::Op::*;
    use self::Expr::*;

    test_anf!(
        "-22",
        Op(Imm(I::Int(-22))));

    test_anf!(
        "2+3",
        Op(Op2(O::Add, box I::Int(2), box I::Int(3))));

    test_anf!(
        "2+(3 - 2)",
        Let(String::from("!tmp!0"), box Op(Op2(O::Sub, box I::Int(3), box I::Int(2))),
            box Op(Op2(O::Add, box I::Int(2), box I::Var(String::from("!tmp!0"))))));

    test_anf!(
        "2 + 3 - 2",
        Let(String::from("!tmp!0"), box Op(Op2(O::Add, box I::Int(2), box I::Int(3))),
            box Op(Op2(O::Sub, box I::Var(String::from("!tmp!0")), box I::Int(2)))));

    test_anf!(
        "let x = 1 in x",
        Let(String::from("x!a1"), box Op(Imm(I::Int(1))),
            box Op(Imm(I::Var(String::from("x!a1"))))));

    test_anf!(
        "let x = (if true then 1 else 2) in x",
        Let(String::from("x!a1"), box If(box I::Bool(true), box Op(Imm(I::Int(1))), box Op(Imm(I::Int(2)))),
            box Op(Imm(I::Var(String::from("x!a1"))))));
}
<|endoftext|>


<commit_before><commit_msg>Improve temporary db path generation on non-unix machines running with the no_metrics feature<commit_after><|endoftext|>


<commit_before>/// Check if input is a valid domain label
pub fn is_label(input: &str) -> bool {
    if input.is_empty() {
        return false;
    }
    let mut chars = input.chars();

    // it can start with an alphanumeric character
    let first = chars.next().unwrap();
    if !first.is_ascii_alphanumeric() {
        return false;
    }

    // then optionally be followed by any combination of
    // alphanumeric characters and dashes
    let last_index = input.len() - 2.min(input.len());
    for (index, c) in chars.enumerate() {
        // before finally ending with an alphanumeric character
        if !c.is_ascii_alphanumeric() && (index == last_index || c != '-') {
            return false;
        }
    }

    true
}

/// Check the local part of an email address (before @)
pub fn is_email_local(input: &str) -> bool {
    if input.is_empty() {
        return false;
    }

    let mut chars = input.chars();

    let first = chars.next().unwrap();

    let last_index = input.len() - 2.min(input.len());
    if first == ' '{
        return false;
    } else if first == '"' {
        // quoted
        if input.len() == 1 {
            return false;
        }
        for (index, c) in chars.enumerate() {
            if index == last_index {
                if c != '"' {
                    return false;
                }
            } else {
                if !is_combined(c) && !is_quoted(c) {
                    return false;
                }
            }
        }
    } else {
        // not quoted
        if first == '.' {
            return false;
        }
        for (index, c) in chars.enumerate() {
            if !is_combined(c) && (index == last_index || c != '.') {
                return false;
            }
        }
    }

    true
}

// these characters can be anywhere in the expresion
// [[:alnum:]!#$%&'*+/=?^_`{|}~-]
fn is_global(c: char) -> bool {
    c.is_ascii_alphanumeric()
        || c == '-'
        || c == '!'
        || c == '#'
        || c == '$'
        || c == '%'
        || c == '&'
        || c == '\''
        || c == '*'
        || c == '+'
        || c == '/'
        || c == '='
        || c == '?'
        || c == '^'
        || c == '_'
        || c == '`'
        || c == '{'
        || c == '|'
        || c == '}'
        || c == '~'
}
fn is_non_ascii(c: char) -> bool {
    c as u32 > 0x7f // non-ascii characters (can also be unquoted)
}
fn is_quoted(c: char) -> bool {
    // ["(),\\:;<>@\[\]. ]
    c == '"'
        || c == '.'
        || c == ' '
        || c == '('
        || c == ')'
        || c == ','
        || c == '\\'
        || c == ':'
        || c == ';'
        || c == '<'
        || c == '>'
        || c == '@'
        || c == '['
        || c == ']'
}
fn is_combined(c: char) -> bool {
    is_global(c) || is_non_ascii(c)
}

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

    #[test]
    fn is_label_correct() {
        for l in &["a", "ab", "a-b", "a--b", "0Z"] {
            assert!(is_label(l));
        }
    }

    #[test]
    fn is_label_incorrect() {
        for l in &["", "-", "a-", "-b", "$"] {
            assert!(!is_label(l));
        }
    }

    #[test]
    fn is_email_local_correct() {
        for l in &[
            "a",
            "ab",
            "a.b",
            "a\u{0080}",
            "$",
            "\"\"\"",
            "\"a b\"",
            "\" \"",
            "\"a<>@\"",
        ] {
            assert!(is_email_local(l));
        }
    }

    #[test]
    fn is_email_local_incorrect() {
        for l in &["", " a", "a ", "a.", ".b", "a\x7f", "\"", "\"a", "a\""] {
            assert!(!is_email_local(l));
        }
    }
}
<commit_msg>Replace unwrap with match<commit_after>/// Check if input is a valid domain label
pub fn is_label(input: &str) -> bool {
    let mut chars = input.chars();

    // we need at least one char
    let first = match chars.next() {
        None => {
            return false;
        }
        Some(c) => c,
    };

    // it can start with an alphanumeric character
    if !first.is_ascii_alphanumeric() {
        return false;
    }

    // then optionally be followed by any combination of
    // alphanumeric characters and dashes
    let last_index = input.len() - 2.min(input.len());
    for (index, c) in chars.enumerate() {
        // before finally ending with an alphanumeric character
        if !c.is_ascii_alphanumeric() && (index == last_index || c != '-') {
            return false;
        }
    }

    true
}

/// Check the local part of an email address (before @)
pub fn is_email_local(input: &str) -> bool {
    let mut chars = input.chars();

    // we need at least one char
    let first = match chars.next() {
        None => {
            return false;
        }
        Some(c) => c,
    };

    let last_index = input.len() - 2.min(input.len());
    if first == ' ' {
        return false;
    } else if first == '"' {
        // quoted
        if input.len() == 1 {
            return false;
        }
        for (index, c) in chars.enumerate() {
            if index == last_index {
                if c != '"' {
                    return false;
                }
            } else {
                if !is_combined(c) && !is_quoted(c) {
                    return false;
                }
            }
        }
    } else {
        // not quoted
        if first == '.' {
            return false;
        }
        for (index, c) in chars.enumerate() {
            if !is_combined(c) && (index == last_index || c != '.') {
                return false;
            }
        }
    }

    true
}

// these characters can be anywhere in the expresion
// [[:alnum:]!#$%&'*+/=?^_`{|}~-]
fn is_global(c: char) -> bool {
    c.is_ascii_alphanumeric()
        || c == '-'
        || c == '!'
        || c == '#'
        || c == '$'
        || c == '%'
        || c == '&'
        || c == '\''
        || c == '*'
        || c == '+'
        || c == '/'
        || c == '='
        || c == '?'
        || c == '^'
        || c == '_'
        || c == '`'
        || c == '{'
        || c == '|'
        || c == '}'
        || c == '~'
}
fn is_non_ascii(c: char) -> bool {
    c as u32 > 0x7f // non-ascii characters (can also be unquoted)
}
fn is_quoted(c: char) -> bool {
    // ["(),\\:;<>@\[\]. ]
    c == '"'
        || c == '.'
        || c == ' '
        || c == '('
        || c == ')'
        || c == ','
        || c == '\\'
        || c == ':'
        || c == ';'
        || c == '<'
        || c == '>'
        || c == '@'
        || c == '['
        || c == ']'
}
fn is_combined(c: char) -> bool {
    is_global(c) || is_non_ascii(c)
}

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

    #[test]
    fn is_label_correct() {
        for l in &["a", "ab", "a-b", "a--b", "0Z"] {
            assert!(is_label(l));
        }
    }

    #[test]
    fn is_label_incorrect() {
        for l in &["", "-", "a-", "-b", "$"] {
            assert!(!is_label(l));
        }
    }

    #[test]
    fn is_email_local_correct() {
        for l in &[
            "a",
            "ab",
            "a.b",
            "a\u{0080}",
            "$",
            "\"\"\"",
            "\"a b\"",
            "\" \"",
            "\"a<>@\"",
        ] {
            assert!(is_email_local(l));
        }
    }

    #[test]
    fn is_email_local_incorrect() {
        for l in &["", " a", "a ", "a.", ".b", "a\x7f", "\"", "\"a", "a\""] {
            assert!(!is_email_local(l));
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]

use std::io;
use std::process;

use libc;
use tokio;
use tokio_io::IoFuture;

use futures::stream::futures_unordered;
use futures::{self, Future, Stream};

use plugin::Plugin;
use relay::boxed_future;

#[cfg(unix)]
pub fn monitor_signal(plugins: Vec<Plugin>) -> impl Future<Item = (), Error = io::Error> + Send {
    use tokio_signal::unix::Signal;

    // Monitor SIGCHLD, triggered if subprocess (plugin) is exited.
    let fut1 = Signal::new(libc::SIGCHLD).and_then(|signal| {
                                                       signal.take(1)
                                                             .for_each(|_| -> Result<(), io::Error> {
                                                                           error!("Plugin exited unexpectly (SIGCHLD)");
                                                                           Ok(())
                                                                       })
                                                             .map(|_| libc::SIGCHLD)
                                                   })
                                         .map_err(|err| {
                                                      error!("Failed to monitor SIGCHLD, err: {:?}", err);
                                                      err
                                                  });

    // Monitor SIGTERM, triggered if shadowsocks is exited gracefully. (Kill by user).
    let fut2 = Signal::new(libc::SIGTERM).and_then(|sigterm| {
                                                       sigterm.take(1)
                                                              .for_each(|_| -> Result<(), io::Error> {
                                                                            info!("Received SIGTERM, exiting.");
                                                                            Ok(())
                                                                        })
                                                              .map(|_| libc::SIGTERM)
                                                   })
                                         .map_err(|err| {
                                                      error!("Failed to monitor SIGTERM, err: {:?}", err);
                                                      err
                                                  });

    // Monitor SIGINT, triggered by CTRL-C
    let fut3 = Signal::new(libc::SIGINT).and_then(|sigint| {
                                                      sigint.take(1)
                                                            .for_each(|_| -> Result<(), io::Error> {
                                                                          info!("Received SIGINT, exiting.");
                                                                          Ok(())
                                                                      })
                                                            .map(|_| libc::SIGINT)
                                                  })
                                        .map_err(|err| {
                                                     error!("Failed to monitor SIGINT, err: {:?}", err);
                                                     err
                                                 });

    // Join them all, if any of them is triggered, kill all subprocesses and exit.
    futures_unordered(vec![boxed_future(fut1), boxed_future(fut2), boxed_future(fut3)])
        .into_future()
        .then(move |r| {
                  // Something happened ... killing all subprocesses
                  info!("Killing {} plugin(s) and then ... Bye Bye :)", plugins.len());
                  drop(plugins);

                  match r {
                      Ok(..) => {
                          process::exit(0);
                      }
                      Err((err, ..)) => Err(err),
                  }
              })
}

#[cfg(windows)]
pub fn monitor_signal(plugins: Vec<Plugin>) -> impl Future<Item = (), Error = io::Error> + Send {
    // FIXME: How to handle SIGTERM equavalent in Windows?

    use tokio_signal::windows::Event;

    let fut1 = Event::ctrl_c().and_then(|ev| {
                                            ev.take(1).for_each(|_| -> Result<(), io::Error> {
                                                                    error!("Received Ctrl-C event");
                                                                    Ok(())
                                                                })
                                        })
                              .map_err(|err| {
                                           error!("Failed to monitor Ctrl-C event: {:?}", err);
                                           err
                                       });

    let fut2 = Event::ctrl_break().and_then(|ev| {
                                                ev.take(1).for_each(|_| -> Result<(), io::Error> {
                                                                        error!("Received Ctrl-Break event");
                                                                        Ok(())
                                                                    })
                                            })
                                  .map_err(|err| {
                                               error!("Failed to monitor Ctrl-Break event: {:?}", err);
                                               err
                                           });

    // Join them all, if any of them is triggered, kill all subprocesses and exit.
    futures_unordered(vec![boxed_future(fut1), boxed_future(fut2)])
        .into_future()
        .then(|r| {
            // Something happened ... killing all subprocesses
            info!("Killing {} plugin(s) and then ... Bye Bye :)", plugins.len());
            drop(plugins);
            match r {
                Ok(..) => {
                    process::exit(libc::EXIT_FAILURE);
                }
                Err((err, ..)) => Err(err)
            }
        })
}

#[cfg(not(any(windows, unix)))]
pub fn monitor_signal(plugins: Vec<Plugin>) -> impl Future<Item = (), Error = io::Error> + Send {
    // FIXME: What can I do ...
    // Blocks forever
    futures::empty::<(), ()>().and_then(|_| {
                                            drop(plugins);
                                        })
}
<commit_msg>Fixed bug, Event on windows will spawn tasks to current executor<commit_after>#![allow(unused_imports)]

use std::io;
use std::process;

use libc;
use tokio;
use tokio_io::IoFuture;

use futures::stream::futures_unordered;
use futures::{self, Future, Stream};

use plugin::Plugin;
use relay::boxed_future;

#[cfg(unix)]
pub fn monitor_signal(plugins: Vec<Plugin>) -> impl Future<Item = (), Error = io::Error> + Send {
    use tokio_signal::unix::Signal;

    // Monitor SIGCHLD, triggered if subprocess (plugin) is exited.
    let fut1 = Signal::new(libc::SIGCHLD).and_then(|signal| {
                                                       signal.take(1)
                                                             .for_each(|_| -> Result<(), io::Error> {
                                                                           error!("Plugin exited unexpectly (SIGCHLD)");
                                                                           Ok(())
                                                                       })
                                                             .map(|_| libc::SIGCHLD)
                                                   })
                                         .map_err(|err| {
                                                      error!("Failed to monitor SIGCHLD, err: {:?}", err);
                                                      err
                                                  });

    // Monitor SIGTERM, triggered if shadowsocks is exited gracefully. (Kill by user).
    let fut2 = Signal::new(libc::SIGTERM).and_then(|sigterm| {
                                                       sigterm.take(1)
                                                              .for_each(|_| -> Result<(), io::Error> {
                                                                            info!("Received SIGTERM, exiting.");
                                                                            Ok(())
                                                                        })
                                                              .map(|_| libc::SIGTERM)
                                                   })
                                         .map_err(|err| {
                                                      error!("Failed to monitor SIGTERM, err: {:?}", err);
                                                      err
                                                  });

    // Monitor SIGINT, triggered by CTRL-C
    let fut3 = Signal::new(libc::SIGINT).and_then(|sigint| {
                                                      sigint.take(1)
                                                            .for_each(|_| -> Result<(), io::Error> {
                                                                          info!("Received SIGINT, exiting.");
                                                                          Ok(())
                                                                      })
                                                            .map(|_| libc::SIGINT)
                                                  })
                                        .map_err(|err| {
                                                     error!("Failed to monitor SIGINT, err: {:?}", err);
                                                     err
                                                 });

    // Join them all, if any of them is triggered, kill all subprocesses and exit.
    futures_unordered(vec![boxed_future(fut1), boxed_future(fut2), boxed_future(fut3)])
        .into_future()
        .then(move |r| {
                  // Something happened ... killing all subprocesses
                  info!("Killing {} plugin(s) and then ... Bye Bye :)", plugins.len());
                  drop(plugins);

                  match r {
                      Ok(..) => {
                          process::exit(0);
                      }
                      Err((err, ..)) => Err(err),
                  }
              })
}

#[cfg(windows)]
pub fn monitor_signal(plugins: Vec<Plugin>) -> impl Future<Item = (), Error = io::Error> + Send {
    // FIXME: How to handle SIGTERM equavalent in Windows?

    use tokio_signal::windows::Event;

    // Must be wrapped with a future, because when `Event` is being created, it will spawn
    // a task into the current executor. So if there is no current running executor, thread
    // will panic.
    futures::lazy(|| {
        let fut1 = Event::ctrl_c().and_then(|ev| {
                                                ev.take(1).for_each(|_| -> Result<(), io::Error> {
                                                                        error!("Received Ctrl-C event");
                                                                        Ok(())
                                                                    })
                                            })
                                  .map_err(|err| {
                                               error!("Failed to monitor Ctrl-C event: {:?}", err);
                                               err
                                           });

        let fut2 = Event::ctrl_break().and_then(|ev| {
                                                    ev.take(1).for_each(|_| -> Result<(), io::Error> {
                                                                            error!("Received Ctrl-Break event");
                                                                            Ok(())
                                                                        })
                                                })
                                      .map_err(|err| {
                                                   error!("Failed to monitor Ctrl-Break event: {:?}", err);
                                                   err
                                               });

        // Join them all, if any of them is triggered, kill all subprocesses and exit.
        futures_unordered(vec![boxed_future(fut1), boxed_future(fut2)])
            .into_future()
            .then(|r| {
                // Something happened ... killing all subprocesses
                info!("Killing {} plugin(s) and then ... Bye Bye :)", plugins.len());
                drop(plugins);
                match r {
                    Ok(..) => {
                        process::exit(libc::EXIT_FAILURE);
                    }
                    Err((err, ..)) => Err(err)
                }
            })
    })
}

#[cfg(not(any(windows, unix)))]
pub fn monitor_signal(plugins: Vec<Plugin>) -> impl Future<Item = (), Error = io::Error> + Send {
    // FIXME: What can I do ...
    // Blocks forever
    futures::empty::<(), ()>().and_then(|_| {
                                            drop(plugins);
                                        })
}
<|endoftext|>