<commit_before>use memory::MemSegment;
use cpu::CPU;

pub struct Disassembler<'a> {
    pc: u16,
    cpu: &'a mut CPU,
    bytes: Vec<u8>,
    unofficial: bool,
}

struct PartialInstruction {
    pattern: String,
}

impl PartialInstruction {
    fn finish(self, instr: &str) -> String {
        self.pattern.replace("$$$", instr).clone()
    }
}

pub struct Instruction {
    pub bytes: Vec<u8>,
    pub str: String,
    pub unofficial: bool,
}

impl<'a> Disassembler<'a> {
    pub fn new(cpu: &'a mut CPU) -> Disassembler {
        Disassembler {
            pc: cpu.regs.pc,
            cpu: cpu,
            bytes: vec![],
            unofficial: false,
        }
    }

    // Addressing modes
    fn immediate(&mut self) -> PartialInstruction {
        PartialInstruction { pattern: format!("$$$ #${:02X}", self.read_incr_pc()) }
    }
    fn absolute(&mut self) -> PartialInstruction {
        let arg = self.read_w_incr_pc();
        PartialInstruction { pattern: format!("$$$ ${:04X} = {:02X}", arg, self.cpu.mem.read(arg)) }
    }
    fn absolute_x(&mut self) -> PartialInstruction {
        let arg = self.read_w_incr_pc();
        let target = arg.wrapping_add(self.cpu.regs.x as u16);
        PartialInstruction {
            pattern: format!("$$$ ${:04X},X @ {:04X} = {:02X}",
                             arg,
                             target,
                             self.cpu.mem.read(target)),
        }
    }
    fn absolute_y(&mut self) -> PartialInstruction {
        let arg = self.read_w_incr_pc();
        let target = arg.wrapping_add(self.cpu.regs.y as u16);
        PartialInstruction {
            pattern: format!("$$$ ${:04X},Y @ {:04X} = {:02X}",
                             arg,
                             target,
                             self.cpu.mem.read(target)),
        }
    }
    fn zero_page(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        PartialInstruction {
            pattern: format!("$$$ ${:02X} = {:02X}", arg, self.cpu.mem.read(arg as u16)),
        }
    }
    fn zero_page_x(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let target = arg.wrapping_add(self.cpu.regs.x);
        PartialInstruction {
            pattern: format!("$$$ ${:02X},X @ {:02X} = {:02X}",
                             arg,
                             target,
                             self.cpu.mem.read(target as u16)),
        }
    }
    fn zero_page_y(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let target = arg.wrapping_add(self.cpu.regs.y);
        PartialInstruction {
            pattern: format!("$$$ ${:02X},Y @ {:02X} = {:02X}",
                             arg,
                             target,
                             self.cpu.mem.read(target as u16)),
        }
    }
    fn indirect_x(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let zp_idx = arg.wrapping_add(self.cpu.regs.x);
        let ptr = self.cpu.mem.read_w_zero_page(zp_idx);
        let target = self.cpu.mem.read(ptr);
        PartialInstruction {
            pattern: format!("$$$ (${:02X},X) @ {:02X} = {:04X} = {:02X}",
                             arg,
                             zp_idx,
                             ptr,
                             target),
        }
    }
    fn indirect_y(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let base_ptr = self.cpu.mem.read_w_zero_page(arg);
        let ptr = base_ptr.wrapping_add(self.cpu.regs.y as u16);
        let target = self.cpu.mem.read(ptr);
        PartialInstruction {
            pattern: format!("$$$ (${:02X}),Y = {:04X} @ {:04X} = {:02X}",
                             arg,
                             base_ptr,
                             ptr,
                             target),
        }
    }
    fn accumulator(&mut self) -> PartialInstruction {
        PartialInstruction { pattern: format!("$$$ A") }
    }

    // Instructions
    // Stores
    fn stx(&mut self, instr: PartialInstruction) -> String {
        instr.finish("STX")
    }
    fn sty(&mut self, instr: PartialInstruction) -> String {
        instr.finish("STY")
    }
    fn sta(&mut self, instr: PartialInstruction) -> String {
        instr.finish("STA")
    }

    // Loads
    fn ldx(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LDX")
    }
    fn lda(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LDA")
    }
    fn ldy(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LDY")
    }

    // Logic/Math Ops
    fn bit(&mut self, instr: PartialInstruction) -> String {
        instr.finish("BIT")
    }
    fn and(&mut self, instr: PartialInstruction) -> String {
        instr.finish("AND")
    }
    fn ora(&mut self, instr: PartialInstruction) -> String {
        instr.finish("ORA")
    }
    fn eor(&mut self, instr: PartialInstruction) -> String {
        instr.finish("EOR")
    }
    fn adc(&mut self, instr: PartialInstruction) -> String {
        instr.finish("ADC")
    }
    fn sbc(&mut self, instr: PartialInstruction) -> String {
        instr.finish("SBC")
    }
    fn cmp(&mut self, instr: PartialInstruction) -> String {
        instr.finish("CMP")
    }
    fn cpx(&mut self, instr: PartialInstruction) -> String {
        instr.finish("CPX")
    }
    fn cpy(&mut self, instr: PartialInstruction) -> String {
        instr.finish("CPY")
    }
    fn inc(&mut self, instr: PartialInstruction) -> String {
        instr.finish("INC")
    }
    fn iny(&mut self) -> String {
        "INY".to_string()
    }
    fn inx(&mut self) -> String {
        "INX".to_string()
    }
    fn dec(&mut self, instr: PartialInstruction) -> String {
        instr.finish("DEC")
    }
    fn dey(&mut self) -> String {
        "DEY".to_string()
    }
    fn dex(&mut self) -> String {
        "DEX".to_string()
    }
    fn lsr(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LSR")
    }
    fn asl(&mut self, instr: PartialInstruction) -> String {
        instr.finish("ASL")
    }
    fn ror(&mut self, instr: PartialInstruction) -> String {
        instr.finish("ROR")
    }
    fn rol(&mut self, instr: PartialInstruction) -> String {
        instr.finish("ROL")
    }

    // Jumps
    fn jmp(&mut self) -> String {
        format!("JMP ${:04X}", self.read_w_incr_pc())
    }
    fn jmpi(&mut self) -> String {
        let arg = self.read_w_incr_pc();
        format!("JMP (${:04X}) = {:04X}", arg, self.cpu.mem.read_w(arg))
    }
    fn jsr(&mut self) -> String {
        let arg = self.read_w_incr_pc();
        format!("JSR ${:04X}", arg)
    }
    fn rts(&mut self) -> String {
        "RTS".to_string()
    }
    fn rti(&mut self) -> String {
        "RTI".to_string()
    }
    fn brk(&mut self) -> String {
        "BRK".to_string()
    }

    // Branches
    fn bcs(&mut self) -> String {
        self.branch("BCS")
    }
    fn bcc(&mut self) -> String {
        self.branch("BCC")
    }
    fn beq(&mut self) -> String {
        self.branch("BEQ")
    }
    fn bne(&mut self) -> String {
        self.branch("BNE")
    }
    fn bvs(&mut self) -> String {
        self.branch("BVS")
    }
    fn bvc(&mut self) -> String {
        self.branch("BVC")
    }
    fn bmi(&mut self) -> String {
        self.branch("BMI")
    }
    fn bpl(&mut self) -> String {
        self.branch("BPL")
    }

    fn branch(&mut self, instr: &str) -> String {
        let arg = self.read_incr_pc();
        format!("{:3} ${:04X}", instr, self.relative_addr(arg))
    }

    // Stack
    fn plp(&mut self) -> String {
        "PLP".to_string()
    }
    fn php(&mut self) -> String {
        "PHP".to_string()
    }
    fn pla(&mut self) -> String {
        "PLA".to_string()
    }
    fn pha(&mut self) -> String {
        "PHA".to_string()
    }

    // Misc
    fn nop(&mut self) -> String {
        "NOP".to_string()
    }
    fn sec(&mut self) -> String {
        "SEC".to_string()
    }
    fn clc(&mut self) -> String {
        "CLC".to_string()
    }
    fn sei(&mut self) -> String {
        "SEI".to_string()
    }
    fn sed(&mut self) -> String {
        "SED".to_string()
    }
    fn cld(&mut self) -> String {
        "CLD".to_string()
    }
    fn clv(&mut self) -> String {
        "CLV".to_string()
    }
    fn tax(&mut self) -> String {
        "TAX".to_string()
    }
    fn tay(&mut self) -> String {
        "TAY".to_string()
    }
    fn tsx(&mut self) -> String {
        "TSX".to_string()
    }
    fn txa(&mut self) -> String {
        "TXA".to_string()
    }
    fn txs(&mut self) -> String {
        "TXS".to_string()
    }
    fn tya(&mut self) -> String {
        "TYA".to_string()
    }

    // Unofficial instructions
    fn u_nop(&mut self, instr: PartialInstruction) -> String {
        instr.finish("NOP")
    }
    fn lax(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LAX")
    }
    fn sax(&mut self, instr: PartialInstruction) -> String {
        instr.finish("SAX")
    }
    fn dcp(&mut self, instr: PartialInstruction) -> String {
        instr.finish("DCP")
    }
    fn isc(&mut self, instr: PartialInstruction) -> String {
        // Nintendulator calls this op ISB, so I'll use the same in the logs
        // at least for now
        instr.finish("ISB")
    }
    fn slo(&mut self, instr: PartialInstruction) -> String {
        instr.finish("SLO")
    }
    fn rla(&mut self, instr: PartialInstruction) -> String {
        instr.finish("RLA")
    }
    fn sre(&mut self, instr: PartialInstruction) -> String {
        instr.finish("SRE")
    }
    fn rra(&mut self, instr: PartialInstruction) -> String {
        instr.finish("RRA")
    }
    fn kil(&mut self) -> String {
        "KIL".to_string()
    }

    pub fn decode(mut self) -> Instruction {
        let opcode = self.read_incr_pc();
        let str: String = decode_opcode!(opcode, self);
        Instruction {
            bytes: self.bytes,
            str: str,
            unofficial: self.unofficial,
        }
    }

    fn unofficial(&mut self) {
        self.unofficial = true;
    }

    fn relative_addr(&self, disp: u8) -> u16 {
        let disp = (disp as i8) as i16; //We want to sign-extend here.
        let pc = self.pc as i16;
        pc.wrapping_add(disp) as u16
    }

    fn read_incr_pc(&mut self) -> u8 {
        let val: u8 = self.cpu.mem.read(self.pc);
        self.bytes.push(val);
        self.pc = self.pc.wrapping_add(1);
        val
    }

    fn read_w_incr_pc(&mut self) -> u16 {
        ((self.read_incr_pc() as u16) << 0) | ((self.read_incr_pc() as u16) << 8)
    }
}
<commit_msg>Prevent the disassembler from reading registers by returning 0xFF.<commit_after>use memory::MemSegment;
use cpu::CPU;

pub struct Disassembler<'a> {
    pc: u16,
    cpu: &'a mut CPU,
    bytes: Vec<u8>,
    unofficial: bool,
}

struct PartialInstruction {
    pattern: String,
}

impl PartialInstruction {
    fn finish(self, instr: &str) -> String {
        self.pattern.replace("$$$", instr).clone()
    }
}

pub struct Instruction {
    pub bytes: Vec<u8>,
    pub str: String,
    pub unofficial: bool,
}

impl<'a> Disassembler<'a> {
    pub fn new(cpu: &'a mut CPU) -> Disassembler {
        Disassembler {
            pc: cpu.regs.pc,
            cpu: cpu,
            bytes: vec![],
            unofficial: false,
        }
    }

    // Addressing modes
    fn immediate(&mut self) -> PartialInstruction {
        PartialInstruction { pattern: format!("$$$ #${:02X}", self.read_incr_pc()) }
    }
    fn absolute(&mut self) -> PartialInstruction {
        let arg = self.read_w_incr_pc();
        PartialInstruction { pattern: format!("$$$ ${:04X} = {:02X}", arg, self.read_safe(arg)) }
    }
    fn absolute_x(&mut self) -> PartialInstruction {
        let arg = self.read_w_incr_pc();
        let target = arg.wrapping_add(self.cpu.regs.x as u16);
        PartialInstruction {
            pattern: format!("$$$ ${:04X},X @ {:04X} = {:02X}",
                             arg,
                             target,
                             self.read_safe(target)),
        }
    }
    fn absolute_y(&mut self) -> PartialInstruction {
        let arg = self.read_w_incr_pc();
        let target = arg.wrapping_add(self.cpu.regs.y as u16);
        PartialInstruction {
            pattern: format!("$$$ ${:04X},Y @ {:04X} = {:02X}",
                             arg,
                             target,
                             self.read_safe(target)),
        }
    }
    fn zero_page(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        PartialInstruction {
            pattern: format!("$$$ ${:02X} = {:02X}", arg, self.read_safe(arg as u16)),
        }
    }
    fn zero_page_x(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let target = arg.wrapping_add(self.cpu.regs.x);
        PartialInstruction {
            pattern: format!("$$$ ${:02X},X @ {:02X} = {:02X}",
                             arg,
                             target,
                             self.read_safe(target as u16)),
        }
    }
    fn zero_page_y(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let target = arg.wrapping_add(self.cpu.regs.y);
        PartialInstruction {
            pattern: format!("$$$ ${:02X},Y @ {:02X} = {:02X}",
                             arg,
                             target,
                             self.read_safe(target as u16)),
        }
    }
    fn indirect_x(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let zp_idx = arg.wrapping_add(self.cpu.regs.x);
        let ptr = self.read_safe_w_zero_page(zp_idx);
        let target = self.read_safe(ptr);
        PartialInstruction {
            pattern: format!("$$$ (${:02X},X) @ {:02X} = {:04X} = {:02X}",
                             arg,
                             zp_idx,
                             ptr,
                             target),
        }
    }
    fn indirect_y(&mut self) -> PartialInstruction {
        let arg = self.read_incr_pc();
        let base_ptr = self.read_safe_w_zero_page(arg);
        let ptr = base_ptr.wrapping_add(self.cpu.regs.y as u16);
        let target = self.read_safe(ptr);
        PartialInstruction {
            pattern: format!("$$$ (${:02X}),Y = {:04X} @ {:04X} = {:02X}",
                             arg,
                             base_ptr,
                             ptr,
                             target),
        }
    }
    fn accumulator(&mut self) -> PartialInstruction {
        PartialInstruction { pattern: format!("$$$ A") }
    }

    // Instructions
    // Stores
    fn stx(&mut self, instr: PartialInstruction) -> String {
        instr.finish("STX")
    }
    fn sty(&mut self, instr: PartialInstruction) -> String {
        instr.finish("STY")
    }
    fn sta(&mut self, instr: PartialInstruction) -> String {
        instr.finish("STA")
    }

    // Loads
    fn ldx(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LDX")
    }
    fn lda(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LDA")
    }
    fn ldy(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LDY")
    }

    // Logic/Math Ops
    fn bit(&mut self, instr: PartialInstruction) -> String {
        instr.finish("BIT")
    }
    fn and(&mut self, instr: PartialInstruction) -> String {
        instr.finish("AND")
    }
    fn ora(&mut self, instr: PartialInstruction) -> String {
        instr.finish("ORA")
    }
    fn eor(&mut self, instr: PartialInstruction) -> String {
        instr.finish("EOR")
    }
    fn adc(&mut self, instr: PartialInstruction) -> String {
        instr.finish("ADC")
    }
    fn sbc(&mut self, instr: PartialInstruction) -> String {
        instr.finish("SBC")
    }
    fn cmp(&mut self, instr: PartialInstruction) -> String {
        instr.finish("CMP")
    }
    fn cpx(&mut self, instr: PartialInstruction) -> String {
        instr.finish("CPX")
    }
    fn cpy(&mut self, instr: PartialInstruction) -> String {
        instr.finish("CPY")
    }
    fn inc(&mut self, instr: PartialInstruction) -> String {
        instr.finish("INC")
    }
    fn iny(&mut self) -> String {
        "INY".to_string()
    }
    fn inx(&mut self) -> String {
        "INX".to_string()
    }
    fn dec(&mut self, instr: PartialInstruction) -> String {
        instr.finish("DEC")
    }
    fn dey(&mut self) -> String {
        "DEY".to_string()
    }
    fn dex(&mut self) -> String {
        "DEX".to_string()
    }
    fn lsr(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LSR")
    }
    fn asl(&mut self, instr: PartialInstruction) -> String {
        instr.finish("ASL")
    }
    fn ror(&mut self, instr: PartialInstruction) -> String {
        instr.finish("ROR")
    }
    fn rol(&mut self, instr: PartialInstruction) -> String {
        instr.finish("ROL")
    }

    // Jumps
    fn jmp(&mut self) -> String {
        format!("JMP ${:04X}", self.read_w_incr_pc())
    }
    fn jmpi(&mut self) -> String {
        let arg = self.read_w_incr_pc();
        format!("JMP (${:04X}) = {:04X}", arg, self.read_safe_w(arg))
    }
    fn jsr(&mut self) -> String {
        let arg = self.read_w_incr_pc();
        format!("JSR ${:04X}", arg)
    }
    fn rts(&mut self) -> String {
        "RTS".to_string()
    }
    fn rti(&mut self) -> String {
        "RTI".to_string()
    }
    fn brk(&mut self) -> String {
        "BRK".to_string()
    }

    // Branches
    fn bcs(&mut self) -> String {
        self.branch("BCS")
    }
    fn bcc(&mut self) -> String {
        self.branch("BCC")
    }
    fn beq(&mut self) -> String {
        self.branch("BEQ")
    }
    fn bne(&mut self) -> String {
        self.branch("BNE")
    }
    fn bvs(&mut self) -> String {
        self.branch("BVS")
    }
    fn bvc(&mut self) -> String {
        self.branch("BVC")
    }
    fn bmi(&mut self) -> String {
        self.branch("BMI")
    }
    fn bpl(&mut self) -> String {
        self.branch("BPL")
    }

    fn branch(&mut self, instr: &str) -> String {
        let arg = self.read_incr_pc();
        format!("{:3} ${:04X}", instr, self.relative_addr(arg))
    }

    // Stack
    fn plp(&mut self) -> String {
        "PLP".to_string()
    }
    fn php(&mut self) -> String {
        "PHP".to_string()
    }
    fn pla(&mut self) -> String {
        "PLA".to_string()
    }
    fn pha(&mut self) -> String {
        "PHA".to_string()
    }

    // Misc
    fn nop(&mut self) -> String {
        "NOP".to_string()
    }
    fn sec(&mut self) -> String {
        "SEC".to_string()
    }
    fn clc(&mut self) -> String {
        "CLC".to_string()
    }
    fn sei(&mut self) -> String {
        "SEI".to_string()
    }
    fn sed(&mut self) -> String {
        "SED".to_string()
    }
    fn cld(&mut self) -> String {
        "CLD".to_string()
    }
    fn clv(&mut self) -> String {
        "CLV".to_string()
    }
    fn tax(&mut self) -> String {
        "TAX".to_string()
    }
    fn tay(&mut self) -> String {
        "TAY".to_string()
    }
    fn tsx(&mut self) -> String {
        "TSX".to_string()
    }
    fn txa(&mut self) -> String {
        "TXA".to_string()
    }
    fn txs(&mut self) -> String {
        "TXS".to_string()
    }
    fn tya(&mut self) -> String {
        "TYA".to_string()
    }

    // Unofficial instructions
    fn u_nop(&mut self, instr: PartialInstruction) -> String {
        instr.finish("NOP")
    }
    fn lax(&mut self, instr: PartialInstruction) -> String {
        instr.finish("LAX")
    }
    fn sax(&mut self, instr: PartialInstruction) -> String {
        instr.finish("SAX")
    }
    fn dcp(&mut self, instr: PartialInstruction) -> String {
        instr.finish("DCP")
    }
    fn isc(&mut self, instr: PartialInstruction) -> String {
        // Nintendulator calls this op ISB, so I'll use the same in the logs
        // at least for now
        instr.finish("ISB")
    }
    fn slo(&mut self, instr: PartialInstruction) -> String {
        instr.finish("SLO")
    }
    fn rla(&mut self, instr: PartialInstruction) -> String {
        instr.finish("RLA")
    }
    fn sre(&mut self, instr: PartialInstruction) -> String {
        instr.finish("SRE")
    }
    fn rra(&mut self, instr: PartialInstruction) -> String {
        instr.finish("RRA")
    }
    fn kil(&mut self) -> String {
        "KIL".to_string()
    }

    pub fn decode(mut self) -> Instruction {
        let opcode = self.read_incr_pc();
        let str: String = decode_opcode!(opcode, self);
        Instruction {
            bytes: self.bytes,
            str: str,
            unofficial: self.unofficial,
        }
    }

    fn unofficial(&mut self) {
        self.unofficial = true;
    }

    fn relative_addr(&self, disp: u8) -> u16 {
        let disp = (disp as i8) as i16; //We want to sign-extend here.
        let pc = self.pc as i16;
        pc.wrapping_add(disp) as u16
    }

    fn read_incr_pc(&mut self) -> u8 {
        let pc = self.pc;
        let val: u8 = self.read_safe(pc);
        self.bytes.push(val);
        self.pc = self.pc.wrapping_add(1);
        val
    }

    fn read_w_incr_pc(&mut self) -> u16 {
        ((self.read_incr_pc() as u16) << 0) | ((self.read_incr_pc() as u16) << 8)
    }

    fn read_safe(&mut self, idx: u16) -> u8 {
        match idx {
            0x2000...0x3FFF => 0xFF,
            0x4000...0x401F => 0xFF,
            _ => self.cpu.mem.read(idx)
        }
    }
    fn read_safe_w(&mut self, idx: u16) -> u16 {
        let low = self.read_safe(idx) as u16;
        let high = self.read_safe(idx + 1) as u16;
        (high << 8) | low
    }

    fn read_safe_w_zero_page(&mut self, zp_idx: u8) -> u16 {
        let low = self.read_safe(zp_idx as u16) as u16;
        let high = self.read_safe(zp_idx.wrapping_add(1) as u16) as u16;
        (high << 8) | low
    }
}
<|endoftext|>


<commit_before>//! Representations of various client errors

use http;
use hyper::{self, StatusCode};
use serde_json::Error as SerdeError;
use std::{error::Error as StdError, fmt, io::Error as IoError, string::FromUtf8Error};

#[derive(Debug)]
pub enum Error {
    SerdeJsonError(SerdeError),
    Hyper(hyper::Error),
    Http(http::Error),
    IO(IoError),
    Encoding(FromUtf8Error),
    InvalidResponse(String),
    Fault { code: StatusCode, message: String },
    ConnectionNotUpgraded,
}

impl From<SerdeError> for Error {
    fn from(error: SerdeError) -> Error {
        Error::SerdeJsonError(error)
    }
}

impl From<hyper::Error> for Error {
    fn from(error: hyper::Error) -> Error {
        Error::Hyper(error)
    }
}

impl From<http::Error> for Error {
    fn from(error: http::Error) -> Error {
        Error::Http(error)
    }
}

impl From<IoError> for Error {
    fn from(error: IoError) -> Error {
        Error::IO(error)
    }
}

impl fmt::Display for Error {
    fn fmt(
        &self,
        f: &mut fmt::Formatter,
    ) -> fmt::Result {
        write!(f, "Docker Error: ")?;
        match self {
            Error::SerdeJsonError(ref err) => err.fmt(f),
            Error::Http(ref err) => err.fmt(f),
            Error::Hyper(ref err) => err.fmt(f),
            Error::IO(ref err) => err.fmt(f),
            Error::Encoding(ref err) => err.fmt(f),
            Error::InvalidResponse(ref cause) => {
                write!(f, "Response doesn't have the expected format: {}", cause)
            }
            Error::Fault { code, .. } => write!(f, "{}", code),
            Error::ConnectionNotUpgraded => write!(
                f,
                "expected the docker host to upgrade the HTTP connection but it did not"
            ),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        "Shiplift Error"
    }

    fn cause(&self) -> Option<&StdError> {
        match self {
            Error::SerdeJsonError(ref err) => Some(err),
            Error::Http(ref err) => Some(err),
            Error::IO(ref err) => Some(err),
            _ => None,
        }
    }
}
<commit_msg>fill in error details (#142)<commit_after>//! Representations of various client errors

use http;
use hyper::{self, StatusCode};
use serde_json::Error as SerdeError;
use std::{error::Error as StdError, fmt, io::Error as IoError, string::FromUtf8Error};

#[derive(Debug)]
pub enum Error {
    SerdeJsonError(SerdeError),
    Hyper(hyper::Error),
    Http(http::Error),
    IO(IoError),
    Encoding(FromUtf8Error),
    InvalidResponse(String),
    Fault { code: StatusCode, message: String },
    ConnectionNotUpgraded,
}

impl From<SerdeError> for Error {
    fn from(error: SerdeError) -> Error {
        Error::SerdeJsonError(error)
    }
}

impl From<hyper::Error> for Error {
    fn from(error: hyper::Error) -> Error {
        Error::Hyper(error)
    }
}

impl From<http::Error> for Error {
    fn from(error: http::Error) -> Error {
        Error::Http(error)
    }
}

impl From<IoError> for Error {
    fn from(error: IoError) -> Error {
        Error::IO(error)
    }
}

impl fmt::Display for Error {
    fn fmt(
        &self,
        f: &mut fmt::Formatter,
    ) -> fmt::Result {
        write!(f, "Docker Error: ")?;
        match self {
            Error::SerdeJsonError(ref err) => err.fmt(f),
            Error::Http(ref err) => err.fmt(f),
            Error::Hyper(ref err) => err.fmt(f),
            Error::IO(ref err) => err.fmt(f),
            Error::Encoding(ref err) => err.fmt(f),
            Error::InvalidResponse(ref cause) => {
                write!(f, "Response doesn't have the expected format: {}", cause)
            }
            Error::Fault { code, .. } => write!(f, "{}", code),
            Error::ConnectionNotUpgraded => write!(
                f,
                "expected the docker host to upgrade the HTTP connection but it did not"
            ),
        }
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        match self {
            Error::SerdeJsonError(e) => e.description(),
            Error::Hyper(e) => e.description(),
            Error::Http(e) => e.description(),
            Error::IO(e) => e.description(),
            Error::Encoding(e) => e.description(),
            Error::InvalidResponse(msg) => msg.as_str(),
            Error::Fault { message, .. } => message.as_str(),
            Error::ConnectionNotUpgraded => "connection not upgraded",
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match self {
            Error::SerdeJsonError(ref err) => Some(err),
            Error::Http(ref err) => Some(err),
            Error::IO(ref err) => Some(err),
            Error::Encoding(e) => Some(e),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>//! A simple adapter designe solely to print messages on the console.
//!
//! Useful for logging.

use foxbox_taxonomy::api::{ Error, InternalError, User };
use foxbox_taxonomy::channel::*;
use foxbox_taxonomy::manager::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::values::{ Value };

use std::collections::HashMap;
use std::sync::Arc;

static ADAPTER_NAME: &'static str = "Console adapter (built-in)";
static ADAPTER_VENDOR: &'static str = "team@link.mozilla.org";
static ADAPTER_VERSION: [u32;4] = [0, 0, 0, 0];

pub struct Console {
    setter_stdout_id: Id<Channel>
}

impl Console {
    pub fn id() -> Id<AdapterId> {
        Id::new("console@link.mozilla.org")
    }
    pub fn service_console_id() -> Id<ServiceId> {
        Id::new("service:console@link.mozilla.org")
    }
    pub fn setter_stdout_id() -> Id<Channel> {
        Id::new("setter:stdout@link.mozilla.org")
    }
}
impl Adapter for Console {
    fn id(&self) -> Id<AdapterId> {
        Self::id()
    }

    fn name(&self) -> &str {
        ADAPTER_NAME
    }

    fn vendor(&self) -> &str {
        ADAPTER_VENDOR
    }

    fn version(&self) -> &[u32;4] {
        &ADAPTER_VERSION
    }

    fn fetch_values(&self, mut set: Vec<Id<Channel>>, _: User) -> ResultMap<Id<Channel>, Option<Value>, Error> {
        set.drain(..).map(|id| {
            (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
        }).collect()
    }

    fn send_values(&self, mut values: HashMap<Id<Channel>, Value>, user: User) -> ResultMap<Id<Channel>, (), Error> {
        values.drain()
            .map(|(id, value)| {
                let result = {
                    if id == self.setter_stdout_id {
                        if let Value::String(s) = value {
                            info!("[console@link.mozilla.org] {} (user {:?})", s, user);
                        } else {
                            info!("[console@link.mozilla.org] {:?} (user {:?})", value, user);
                        }
                        Ok(())
                    } else {
                        Err(Error::InternalError(InternalError::NoSuchChannel(id.clone())))
                    }
                };
                (id, result)
            })
            .collect()
    }
}

impl Console {
    pub fn init(adapt: &Arc<AdapterManager>) -> Result<(), Error> {
        let service_console_id = Console::service_console_id();
        let setter_stdout_id = Console::setter_stdout_id();
        let adapter_id = Console::id();
        let console = Arc::new(Console {
            setter_stdout_id: setter_stdout_id.clone()
        });
        try!(adapt.add_adapter(console));
        let mut service = Service::empty(&service_console_id, &adapter_id);
        service.properties.insert("model".to_owned(), "Mozilla console v1".to_owned());
        try!(adapt.add_service(service));
        try!(adapt.add_channel(Channel {
            id: setter_stdout_id,
            service: service_console_id,
            adapter: adapter_id,
            ..LOG.clone()
        }));
        Ok(())
    }
}
<commit_msg>Console: Getting rid of centralized Value<commit_after>//! A simple adapter designe solely to print messages on the console.
//!
//! Useful for logging.

use foxbox_taxonomy::api::{ Error, InternalError, User };
use foxbox_taxonomy::channel::*;
use foxbox_taxonomy::manager::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::values::{ Value };

use std::collections::HashMap;
use std::sync::Arc;

static ADAPTER_NAME: &'static str = "Console adapter (built-in)";
static ADAPTER_VENDOR: &'static str = "team@link.mozilla.org";
static ADAPTER_VERSION: [u32;4] = [0, 0, 0, 0];

pub struct Console {
    setter_stdout_id: Id<Channel>
}

impl Console {
    pub fn id() -> Id<AdapterId> {
        Id::new("console@link.mozilla.org")
    }
    pub fn service_console_id() -> Id<ServiceId> {
        Id::new("service:console@link.mozilla.org")
    }
    pub fn setter_stdout_id() -> Id<Channel> {
        Id::new("setter:stdout@link.mozilla.org")
    }
}
impl Adapter for Console {
    fn id(&self) -> Id<AdapterId> {
        Self::id()
    }

    fn name(&self) -> &str {
        ADAPTER_NAME
    }

    fn vendor(&self) -> &str {
        ADAPTER_VENDOR
    }

    fn version(&self) -> &[u32;4] {
        &ADAPTER_VERSION
    }

    fn fetch_values(&self, mut set: Vec<Id<Channel>>, _: User) -> ResultMap<Id<Channel>, Option<Value>, Error> {
        set.drain(..).map(|id| {
            (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
        }).collect()
    }

    fn send_values(&self, mut values: HashMap<Id<Channel>, Value>, user: User) -> ResultMap<Id<Channel>, (), Error> {
        values.drain()
            .map(|(id, value)| {
                let result = {
                    if id == self.setter_stdout_id {
                        match value.cast::<String>() {
                            Err(err) => Err(err),
                            Ok(s) => {
                                info!("[console@link.mozilla.org] {} (user {:?})", s, user);
                                Ok(())
                            }
                        }
                    } else {
                        Err(Error::InternalError(InternalError::NoSuchChannel(id.clone())))
                    }
                };
                (id, result)
            })
            .collect()
    }
}

impl Console {
    pub fn init(adapt: &Arc<AdapterManager>) -> Result<(), Error> {
        let service_console_id = Console::service_console_id();
        let setter_stdout_id = Console::setter_stdout_id();
        let adapter_id = Console::id();
        let console = Arc::new(Console {
            setter_stdout_id: setter_stdout_id.clone()
        });
        try!(adapt.add_adapter(console));
        let mut service = Service::empty(&service_console_id, &adapter_id);
        service.properties.insert("model".to_owned(), "Mozilla console v1".to_owned());
        try!(adapt.add_service(service));
        try!(adapt.add_channel(Channel {
            id: setter_stdout_id,
            service: service_console_id,
            adapter: adapter_id,
            ..LOG.clone()
        }));
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::cmp::Ordering;

struct PhantomVertex;
struct PhantomFace;
struct PhantomEdge;
struct PhantomHalfedge;
pub type Vertex = BaseHandle<PhantomVertex>;
pub type Face = BaseHandle<PhantomFace>;
pub type Edge = BaseHandle<PhantomEdge>;
pub type Halfedge = BaseHandle<PhantomHalfedge>;

pub struct BaseHandle<A> {
    type_ : PhantomData<A>,
    index_ : Option<usize>,
}

impl<A> BaseHandle<A> {
    pub fn invalid() -> BaseHandle<A> {
        BaseHandle {
            type_ : PhantomData,
            index_ : None,
        }
    }

    pub fn new(idx : usize) -> BaseHandle<A> {
        BaseHandle {
            type_ : PhantomData,
            index_ : Some(idx),
        }
    }

    pub fn idx(&self) -> Option<usize> {
        self.index_
    }

    pub fn reset(&mut self) {
        self.index_ = None;
    }

    pub fn is_valid(&self) -> bool {
        self.index_.is_some()
    }
}

impl<A> Ord for BaseHandle<A> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.index_.cmp(&other.index_)
    }
}

impl<A> PartialOrd for BaseHandle<A> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.index_.cmp(&other.index_))
    }
}

impl<A> PartialEq for BaseHandle<A> {
    fn eq(&self, other: &Self) -> bool {
        self.index_ == other.index_
    }
}
impl<A> Eq for BaseHandle<A> { }

#[cfg(test)]
mod tests {
    use super::*;
    use std::cmp::Ordering;

    #[test]
    fn base_handle_invalid() {
        let handle : Vertex = Vertex::invalid();
        assert!(!handle.is_valid());
        assert!(handle.idx().is_none());
    }

    #[test]
    fn base_handle_idx() {
        let idx = 42;
        let handle : Vertex = Vertex::new(idx);
        assert!(handle.is_valid());

        assert!(handle.idx().is_some());
        assert!(handle.idx().unwrap() == idx);
    }

    #[test]
    fn base_handle_reset() {
        let idx = 42;
        let mut handle : Vertex = Vertex::new(idx);
        assert!(handle.is_valid());

        handle.reset();
        assert!(!handle.is_valid());
    }

    #[test]
    fn base_handle_cmp() {
        let idx1 = 42;
        let idx2 = 13;
        let h1 : Vertex = Vertex::new(idx1);
        let h2 : Vertex = Vertex::new(idx2);
        let h3 : Vertex = Vertex::new(idx1);

        assert!(h1!=h2);
        assert!(h1>h2);
        assert!(h2<h1);
        assert!(h1==h3);
        assert!(h1<=h3);
        assert_eq!(h2.cmp(&h1), Ordering::Less);
        assert_eq!(h1.cmp(&h2), Ordering::Greater);
        assert_eq!(h1.cmp(&h3), Ordering::Equal);
    }
}
<commit_msg>handle : rename the tests + Add Copy and Clone<commit_after>use std::marker::PhantomData;
use std::cmp::Ordering;

#[derive(Copy, Clone)]
struct PhantomVertex;
#[derive(Copy, Clone)]
struct PhantomFace;
#[derive(Copy, Clone)]
struct PhantomEdge;
#[derive(Copy, Clone)]
struct PhantomHalfedge;
pub type Vertex = BaseHandle<PhantomVertex>;
pub type Face = BaseHandle<PhantomFace>;
pub type Edge = BaseHandle<PhantomEdge>;
pub type Halfedge = BaseHandle<PhantomHalfedge>;

#[derive(Copy, Clone)]
pub struct BaseHandle<A> {
    type_ : PhantomData<A>,
    index_ : Option<usize>,
}

impl<A> BaseHandle<A> {
    pub fn invalid() -> BaseHandle<A> {
        BaseHandle {
            type_ : PhantomData,
            index_ : None,
        }
    }

    pub fn new(idx : usize) -> BaseHandle<A> {
        BaseHandle {
            type_ : PhantomData,
            index_ : Some(idx),
        }
    }

    pub fn idx(&self) -> Option<usize> {
        self.index_
    }

    pub fn reset(&mut self) {
        self.index_ = None;
    }

    pub fn is_valid(&self) -> bool {
        self.index_.is_some()
    }
}

impl<A> Ord for BaseHandle<A> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.index_.cmp(&other.index_)
    }
}

impl<A> PartialOrd for BaseHandle<A> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.index_.cmp(&other.index_))
    }
}

impl<A> PartialEq for BaseHandle<A> {
    fn eq(&self, other: &Self) -> bool {
        self.index_ == other.index_
    }
}
impl<A> Eq for BaseHandle<A> { }

#[cfg(test)]
mod tests {
    use super::*;
    use std::cmp::Ordering;

    #[test]
    fn invalid() {
        let handle = Vertex::invalid();
        assert!(!handle.is_valid());
        assert!(handle.idx().is_none());
    }

    #[test]
    fn idx() {
        let idx = 42;
        let handle = Vertex::new(idx);
        assert!(handle.is_valid());

        assert!(handle.idx().is_some());
        assert!(handle.idx().unwrap() == idx);
    }

    #[test]
    fn reset() {
        let idx = 42;
        let mut handle = Vertex::new(idx);
        assert!(handle.is_valid());

        handle.reset();
        assert!(!handle.is_valid());
    }

    #[test]
    fn cmp() {
        let idx1 = 42;
        let idx2 = 13;
        let h1 = Vertex::new(idx1);
        let h2 = Vertex::new(idx2);
        let h3 = Vertex::new(idx1);

        assert!(h1!=h2);
        assert!(h1>h2);
        assert!(h2<h1);
        assert!(h1==h3);
        assert!(h1<=h3);
        assert_eq!(h2.cmp(&h1), Ordering::Less);
        assert_eq!(h1.cmp(&h2), Ordering::Greater);
        assert_eq!(h1.cmp(&h3), Ordering::Equal);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 Jeffery Olson
//
// Licensed under the 3-Clause BSD License, see LICENSE.txt
// at the top-level of this repository.
// This file may not be copied, modified, or distributed
// except according to those terms.
use std::os::args;

fn run(_input: ~str) -> ~str {
    ~""
}

fn main() {
    let _args = args();
    println!("{}", run(~""));
}

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

    #[test]
    fn number_literal_evals_to_itself() {
        assert!(run(~"12") == ~"12");
    }
}
<commit_msg>impl pad_input()<commit_after>// Copyright 2013-2014 Jeffery Olson
//
// Licensed under the 3-Clause BSD License, see LICENSE.txt
// at the top-level of this repository.
// This file may not be copied, modified, or distributed
// except according to those terms.
use std::os::args;

// this is starting out as a straight port of Peter Norvig's
// lis.py (the first iteration) to Rust

fn main() {
    let _args = args();
    println!("{}", ~"");
}

fn pad_input(input: ~str) -> ~str {
    input.replace("(", " ( ").replace(")", " ) ")
}

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

    #[test]
    fn pad_input_should_insert_spaces_before_and_after_parens() {
        assert!(pad_input(~"(x 1 2 3)") == ~" ( x 1 2 3 ) ");
    }
}
<|endoftext|>


<commit_before>//! Implementation of the `import` macro.

use std::any::Any;
use std::sync::{Arc, RwLock, Mutex};
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::{Path, PathBuf};

use base::ast::{self, Expr, LiteralEnum, SpannedExpr};
use base::metadata::Metadata;
use base::pos;
use base::symbol::Symbol;
use vm::macros::{Macro, Error as MacroError};
use vm::thread::{Thread, ThreadInternal};
use vm::internal::Value;
use super::{filename_to_module, Compiler};
use base::types::TcIdent;
use base::fnv::FnvMap;

quick_error! {
    /// Error type for the import macro
    #[derive(Debug)]
    pub enum Error {
        /// The importer found a cyclic dependency when loading files
        CyclicDependency(module: String) {
            description("Cyclic dependency")
            display("Module '{}' occurs in a cyclic dependency", module)
        }
        /// Generic message error
        String(message: String) {
            description(message)
            display("{}", message)
        }
        /// The importer could not load the imported file
        IO(err: io::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
    }
}

macro_rules! std_libs {
    ($($file: expr),*) => {
        [$((concat!("std/", $file, ".glu"), include_str!(concat!("../std/", $file, ".glu")))),*]
    }
}
// Include the standard library distribution in the binary
static STD_LIBS: [(&'static str, &'static str); 8] = std_libs!("prelude",
                                                               "types",
                                                               "map",
                                                               "repl",
                                                               "string",
                                                               "state",
                                                               "test",
                                                               "writer");

pub trait Importer: Any + Clone + Sync + Send {
    fn import(&self, vm: &Thread, modulename: &str, input: &str) -> Result<(), MacroError>;
}

#[derive(Clone)]
pub struct DefaultImporter;
impl Importer for DefaultImporter {
    fn import(&self, vm: &Thread, modulename: &str, input: &str) -> Result<(), MacroError> {
        let mut compiler = Compiler::new().implicit_prelude(modulename != "std.types");
        try!(compiler.load_script(vm, &modulename, input));
        Ok(())
    }
}

#[derive(Clone)]
pub struct CheckImporter(pub Arc<Mutex<FnvMap<String, SpannedExpr<ast::TcIdent<Symbol>>>>>);
impl CheckImporter {
    pub fn new() -> CheckImporter {
        CheckImporter(Arc::new(Mutex::new(FnvMap::default())))
    }
}
impl Importer for CheckImporter {
    fn import(&self, vm: &Thread, modulename: &str, input: &str) -> Result<(), MacroError> {
        use compiler_pipeline::*;
        let mut compiler = Compiler::new().implicit_prelude(modulename != "std.types");
        let TypecheckValue(expr, typ) = try!(input.typecheck(&mut compiler, vm, modulename, input));
        self.0.lock().unwrap().insert(modulename.into(), expr);
        let metadata = Metadata::default();
        // Insert a global to ensure the globals type can be looked up
        try!(vm.global_env().set_global(Symbol::new(modulename), typ, metadata, Value::Int(0)));
        Ok(())
    }
}

/// Macro which rewrites occurances of `import "filename"` to a load of that file if it is not
/// already loaded and then a global access to the loaded module
pub struct Import<I = DefaultImporter> {
    visited: RwLock<Vec<String>>,
    paths: RwLock<Vec<PathBuf>>,
    pub importer: I,
}

impl<I> Import<I> {
    /// Creates a new import macro
    pub fn new(importer: I) -> Import<I> {
        Import {
            visited: RwLock::new(Vec::new()),
            paths: RwLock::new(vec![PathBuf::from(".")]),
            importer: importer,
        }
    }

    /// Adds a path to the list of paths which the importer uses to find files
    pub fn add_path<P: Into<PathBuf>>(&self, path: P) {
        self.paths.write().unwrap().push(path.into());
    }
}

impl<I> Macro for Import<I>
    where I: Importer
{
    fn expand(&self,
              vm: &Thread,
              arguments: &mut [SpannedExpr<TcIdent>])
              -> Result<SpannedExpr<TcIdent>, MacroError> {
        if arguments.len() != 1 {
            return Err(Error::String("Expected import to get 1 argument".into()).into());
        }
        match arguments[0].value {
            Expr::Literal(LiteralEnum::String(ref filename)) => {
                let modulename = filename_to_module(filename);
                let path = Path::new(&filename[..]);
                // Only load the script if it is not already loaded
                let name = Symbol::new(&*modulename);
                debug!("Import '{}' {:?}", modulename, self.visited);
                if !vm.global_env().global_exists(&modulename) {
                    if self.visited.read().unwrap().iter().any(|m| **m == **filename) {
                        return Err(Error::CyclicDependency(filename.clone()).into());
                    }
                    self.visited.write().unwrap().push(filename.clone());
                    let mut buffer = String::new();
                    let file_contents = match STD_LIBS.iter().find(|tup| tup.0 == filename) {
                        Some(tup) => tup.1,
                        None => {
                            let file = self.paths
                                .read()
                                .unwrap()
                                .iter()
                                .filter_map(|p| {
                                    let mut base = p.clone();
                                    base.push(path);
                                    match File::open(&base) {
                                        Ok(file) => Some(file),
                                        Err(_) => None,
                                    }
                                })
                                .next();
                            let mut file = try!(file.ok_or_else(|| {
                                Error::String(format!("Could not find file '{}'", filename))
                            }));
                            try!(file.read_to_string(&mut buffer));
                            &*buffer
                        }
                    };
                    // FIXME Remove this hack
                    self.visited.write().unwrap().pop();
                    try!(self.importer.import(vm, &modulename, file_contents));
                }
                // FIXME Does not handle shadowing
                Ok(pos::spanned(arguments[0].span,
                                Expr::Identifier(TcIdent::new(name))))
            }
            _ => return Err(Error::String("Expected a string literal to import".into()).into()),
        }
    }

    fn clone(&self) -> Box<Macro> {
        Box::new(Import {
            visited: RwLock::new(Vec::new()),
            paths: RwLock::new(self.paths.read().unwrap().clone()),
            importer: self.importer.clone(),
        })
    }
}
<commit_msg>fix: Make the paths of the import macro public again<commit_after>//! Implementation of the `import` macro.

use std::any::Any;
use std::sync::{Arc, RwLock, Mutex};
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::{Path, PathBuf};

use base::ast::{self, Expr, LiteralEnum, SpannedExpr};
use base::metadata::Metadata;
use base::pos;
use base::symbol::Symbol;
use vm::macros::{Macro, Error as MacroError};
use vm::thread::{Thread, ThreadInternal};
use vm::internal::Value;
use super::{filename_to_module, Compiler};
use base::types::TcIdent;
use base::fnv::FnvMap;

quick_error! {
    /// Error type for the import macro
    #[derive(Debug)]
    pub enum Error {
        /// The importer found a cyclic dependency when loading files
        CyclicDependency(module: String) {
            description("Cyclic dependency")
            display("Module '{}' occurs in a cyclic dependency", module)
        }
        /// Generic message error
        String(message: String) {
            description(message)
            display("{}", message)
        }
        /// The importer could not load the imported file
        IO(err: io::Error) {
            description(err.description())
            display("{}", err)
            from()
        }
    }
}

macro_rules! std_libs {
    ($($file: expr),*) => {
        [$((concat!("std/", $file, ".glu"), include_str!(concat!("../std/", $file, ".glu")))),*]
    }
}
// Include the standard library distribution in the binary
static STD_LIBS: [(&'static str, &'static str); 8] = std_libs!("prelude",
                                                               "types",
                                                               "map",
                                                               "repl",
                                                               "string",
                                                               "state",
                                                               "test",
                                                               "writer");

pub trait Importer: Any + Clone + Sync + Send {
    fn import(&self, vm: &Thread, modulename: &str, input: &str) -> Result<(), MacroError>;
}

#[derive(Clone)]
pub struct DefaultImporter;
impl Importer for DefaultImporter {
    fn import(&self, vm: &Thread, modulename: &str, input: &str) -> Result<(), MacroError> {
        let mut compiler = Compiler::new().implicit_prelude(modulename != "std.types");
        try!(compiler.load_script(vm, &modulename, input));
        Ok(())
    }
}

#[derive(Clone)]
pub struct CheckImporter(pub Arc<Mutex<FnvMap<String, SpannedExpr<ast::TcIdent<Symbol>>>>>);
impl CheckImporter {
    pub fn new() -> CheckImporter {
        CheckImporter(Arc::new(Mutex::new(FnvMap::default())))
    }
}
impl Importer for CheckImporter {
    fn import(&self, vm: &Thread, modulename: &str, input: &str) -> Result<(), MacroError> {
        use compiler_pipeline::*;
        let mut compiler = Compiler::new().implicit_prelude(modulename != "std.types");
        let TypecheckValue(expr, typ) = try!(input.typecheck(&mut compiler, vm, modulename, input));
        self.0.lock().unwrap().insert(modulename.into(), expr);
        let metadata = Metadata::default();
        // Insert a global to ensure the globals type can be looked up
        try!(vm.global_env().set_global(Symbol::new(modulename), typ, metadata, Value::Int(0)));
        Ok(())
    }
}

/// Macro which rewrites occurances of `import "filename"` to a load of that file if it is not
/// already loaded and then a global access to the loaded module
pub struct Import<I = DefaultImporter> {
    visited: RwLock<Vec<String>>,
    pub paths: RwLock<Vec<PathBuf>>,
    pub importer: I,
}

impl<I> Import<I> {
    /// Creates a new import macro
    pub fn new(importer: I) -> Import<I> {
        Import {
            visited: RwLock::new(Vec::new()),
            paths: RwLock::new(vec![PathBuf::from(".")]),
            importer: importer,
        }
    }

    /// Adds a path to the list of paths which the importer uses to find files
    pub fn add_path<P: Into<PathBuf>>(&self, path: P) {
        self.paths.write().unwrap().push(path.into());
    }
}

impl<I> Macro for Import<I>
    where I: Importer
{
    fn expand(&self,
              vm: &Thread,
              arguments: &mut [SpannedExpr<TcIdent>])
              -> Result<SpannedExpr<TcIdent>, MacroError> {
        if arguments.len() != 1 {
            return Err(Error::String("Expected import to get 1 argument".into()).into());
        }
        match arguments[0].value {
            Expr::Literal(LiteralEnum::String(ref filename)) => {
                let modulename = filename_to_module(filename);
                let path = Path::new(&filename[..]);
                // Only load the script if it is not already loaded
                let name = Symbol::new(&*modulename);
                debug!("Import '{}' {:?}", modulename, self.visited);
                if !vm.global_env().global_exists(&modulename) {
                    if self.visited.read().unwrap().iter().any(|m| **m == **filename) {
                        return Err(Error::CyclicDependency(filename.clone()).into());
                    }
                    self.visited.write().unwrap().push(filename.clone());
                    let mut buffer = String::new();
                    let file_contents = match STD_LIBS.iter().find(|tup| tup.0 == filename) {
                        Some(tup) => tup.1,
                        None => {
                            let file = self.paths
                                .read()
                                .unwrap()
                                .iter()
                                .filter_map(|p| {
                                    let mut base = p.clone();
                                    base.push(path);
                                    match File::open(&base) {
                                        Ok(file) => Some(file),
                                        Err(_) => None,
                                    }
                                })
                                .next();
                            let mut file = try!(file.ok_or_else(|| {
                                Error::String(format!("Could not find file '{}'", filename))
                            }));
                            try!(file.read_to_string(&mut buffer));
                            &*buffer
                        }
                    };
                    // FIXME Remove this hack
                    self.visited.write().unwrap().pop();
                    try!(self.importer.import(vm, &modulename, file_contents));
                }
                // FIXME Does not handle shadowing
                Ok(pos::spanned(arguments[0].span,
                                Expr::Identifier(TcIdent::new(name))))
            }
            _ => return Err(Error::String("Expected a string literal to import".into()).into()),
        }
    }

    fn clone(&self) -> Box<Macro> {
        Box::new(Import {
            visited: RwLock::new(Vec::new()),
            paths: RwLock::new(self.paths.read().unwrap().clone()),
            importer: self.importer.clone(),
        })
    }
}
<|endoftext|>


<commit_before>use screen::*;
use context::Context;
use resource_manager::Textures;
use graphics::Texture;
use piston_window::{self, PistonWindow};

pub struct Battle {
    empty_tile: Texture,
}

impl Battle {
    pub fn new(window: &PistonWindow, context: &mut Context) -> Self {
        Battle { empty_tile: context.resource_manager.load_texture(window, Textures::EmptyTile) }
    }
}

impl Screen for Battle {
    fn on_input(&mut self, input: &piston_window::Input, window: &PistonWindow, context: &mut Context) -> InputResults {
        use piston_window::{Input, Button, Key};

        let mut result = Vec::new();

        match input {
            &Input::Press(button) => {
                match button {
                    Button::Keyboard(Key::Escape) => {
                        result.push(InputResult::PushScreen(Box::new(MainMenu::new(&window, context))));
                    }
                    _ => {}
                }
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, _args: &piston_window::RenderArgs, window: &PistonWindow) {
        window.draw_2d(|context, graphics| {
            piston_window::clear([0.0, 0.0, 0.0, 1.0], graphics);
            piston_window::image(&self.a, context.transform, graphics);
        });
    }

    fn on_update(&mut self, _args: &piston_window::UpdateArgs) {}
}
<commit_msg>Tile name fix<commit_after>use screen::*;
use context::Context;
use resource_manager::Textures;
use graphics::Texture;
use piston_window::{self, PistonWindow};

pub struct Battle {
    empty_tile: Texture,
}

impl Battle {
    pub fn new(window: &PistonWindow, context: &mut Context) -> Self {
        Battle { empty_tile: context.resource_manager.load_texture(window, Textures::EmptyTile) }
    }
}

impl Screen for Battle {
    fn on_input(&mut self, input: &piston_window::Input, window: &PistonWindow, context: &mut Context) -> InputResults {
        use piston_window::{Input, Button, Key};

        let mut result = Vec::new();

        match input {
            &Input::Press(button) => {
                match button {
                    Button::Keyboard(Key::Escape) => {
                        result.push(InputResult::PushScreen(Box::new(MainMenu::new(&window, context))));
                    }
                    _ => {}
                }
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, _args: &piston_window::RenderArgs, window: &PistonWindow) {
        window.draw_2d(|context, graphics| {
            piston_window::clear([0.0, 0.0, 0.0, 1.0], graphics);
            piston_window::image(&self.empty_tile, context.transform, graphics);
        });
    }

    fn on_update(&mut self, _args: &piston_window::UpdateArgs) {}
}
<|endoftext|>


<commit_before>use url::Url;
use serde::de::{Deserialize, Deserializer, Error as DeserializeError};
use serde::ser::{Serialize, Serializer};

/// Unit struct which can be used to serialize a Url.
///
/// `#[serde(with = "UrlDef")]`
pub struct UrlDef;
impl UrlDef {
    pub fn deserialize<'de, D>(deserializer: D) -> Result<Url, D::Error>
            where D: Deserializer<'de> {
        <&str>::deserialize(deserializer).and_then(|s| {
            s.parse().map_err(|e| DeserializeError::custom(format!("invalid URL: {}", e)))
        })
    }

    pub fn serialize<S>(url: &Url, serializer: S) -> Result<S::Ok, S::Error>
            where S: Serializer {
        url.as_str().serialize(serializer)
    }
}
<commit_msg>Fix parsing JSON containing URLs with escaping<commit_after>use url::Url;
use serde::de::{Deserialize, Deserializer, Error as DeserializeError};
use serde::ser::{Serialize, Serializer};

/// Unit struct which can be used to serialize a Url.
///
/// `#[serde(with = "UrlDef")]`
pub struct UrlDef;
impl UrlDef {
    pub fn deserialize<'de, D>(deserializer: D) -> Result<Url, D::Error>
            where D: Deserializer<'de> {
        <String>::deserialize(deserializer).and_then(|s| {
            s.parse().map_err(|e| DeserializeError::custom(format!("invalid URL: {}", e)))
        })
    }

    pub fn serialize<S>(url: &Url, serializer: S) -> Result<S::Ok, S::Error>
            where S: Serializer {
        url.as_str().serialize(serializer)
    }
}
<|endoftext|>


<commit_before>//! Edit a `DataBase`.

use database::{write_database, DataBase};
use error::Result;
use ui::utils;
use ui::utils::{CommandList, CommandParser};

use std::error::Error;

#[derive(Clone, Copy, Debug)]
/// Editing commands.
enum Command {
    AddResidue,
    RemoveResidue,
    AddSubstrate,
    RemoveSubstrate,
    WriteToDisk,
    SetLocation,
    ShowDatabase,
    QuitAndSave,
    QuitWithoutSaving,
}

/// The main user menu.
pub fn user_menu(database: &mut DataBase) -> Result<&'static str> {
    let command_list: CommandList<Command> = vec![
        ("ra", Command::AddResidue, "Add a residue definition"),
        ("rr", Command::RemoveResidue, "Remove a residue definition"),
        ("sa", Command::AddSubstrate, "Add a substrate definition"),
        ("sr", Command::RemoveSubstrate, "Remove a substrate definition"),
        ("w", Command::WriteToDisk, "Write database to disk"),
        ("c", Command::SetLocation, "Change output location of database"),
        ("l", Command::ShowDatabase, "List database content"),
        ("f", Command::QuitAndSave, "Finish editing database"),
        ("a", Command::QuitWithoutSaving, "Abort editing and discard changes"),
    ];
    let commands = CommandParser::from_list(command_list);

    let path_backup = database.path.clone();
    let residues_backup = database.residue_defs.clone();
    let substrates_backup = database.substrate_defs.clone();

    println!("Editing the current database.\n");
    database.describe();
    println!("");

    loop {
        commands.print_menu();
        let input = utils::get_input_string("Selection")?;

        if let Some((cmd, tail)) = commands.get_selection_and_tail(&input) {
            match cmd {
                Command::AddResidue => {
                    match define_residue::user_menu() {
                        Ok(residue) => {
                            println!("Added residue '{}' to database.", residue.code);
                            database.residue_defs.push(residue);
                        },
                        Err(err) => println!("Could not create residue: {}", err.description()),
                    }
                },
                Command::RemoveResidue => {
                    match utils::remove_item(&mut database.residue_defs, &tail) {
                        Ok(i) => println!("Removed residue with index {} from database.", i),
                        Err(err) => println!("Could not remove residue: {}", err.description()),
                    }
                },
                Command::AddSubstrate => {
                    match define_substrate::user_menu(&database.residue_defs) {
                        Ok(substrate) => {
                            println!("Added substrate definition '{}' to database.",
                                     substrate.name);
                            database.substrate_defs.push(substrate);
                        },
                        Err(err) => println!("Could not create substrate: {}", err.description()),
                    }
                },
                Command::RemoveSubstrate => {
                    match utils::remove_item(&mut database.substrate_defs, &tail) {
                        Ok(i) => println!("Removed substrate with index {} from database.", i),
                        Err(err) => println!("Could not remove substrate: {}", err.description()),
                    }
                },
                Command::WriteToDisk => {
                    match write_database(&database) {
                        Ok(_) => println!("Wrote database to '{}'.",
                                          database.path.as_ref().unwrap().to_str().unwrap()),
                        Err(err) => println!("Could not write database: {}", err.description()),
                    }
                },
                Command::SetLocation => {
                    match database.set_path(&tail) {
                        Ok(_) => println!("Database path set to '{}'.",
                                          database.get_path_pretty()),
                        Err(err) => println!("Could not change database path: {}",
                                             err.description()),
                    }
                },
                Command::ShowDatabase => {
                    println!("");
                    database.describe();
                },
                Command::QuitAndSave => {
                    return Ok("Finished editing database.");
                },
                Command::QuitWithoutSaving => {
                    database.path = path_backup;
                    database.residue_defs = residues_backup;
                    database.substrate_defs = substrates_backup;

                    return Ok("Discarding changes to database.");
                },
            }
        } else {
            println!("Not a valid selection.");
        }

        println!("");
    }
}

mod define_residue {
    //! Define a new `ResidueBase`.

    use error::{GrafenCliError, Result, UIErrorKind};
    use ui::utils;
    use ui::utils::{CommandList, CommandParser};

    use grafen::system::{Atom, Coord, ResidueBase};
    use std::error::Error;

    #[derive(Clone, Copy, Debug)]
    enum ResidueCommand {
        SetName,
        AddAtom,
        RemoveAtom,
        SwapAtoms,
        ShowResidue,
        QuitAndSave,
        QuitWithoutSaving,
    }

    pub fn user_menu() -> Result<ResidueBase> {
        let command_list: CommandList<ResidueCommand> = vec![
            ("n", ResidueCommand::SetName, "Set residue name"),
            ("at", ResidueCommand::AddAtom, "Add atom to residue"),
            ("r", ResidueCommand::RemoveAtom, "Remove atom from residue"),
            ("s", ResidueCommand::SwapAtoms, "Swap two atoms in list"),
            ("l", ResidueCommand::ShowResidue, "List current residue data"),
            ("f", ResidueCommand::QuitAndSave, "Finish and add residue to list"),
            ("a", ResidueCommand::QuitWithoutSaving, "Abort and discard changes")
        ];
        let commands = CommandParser::from_list(command_list);

        println!("Creating a new residue.\n");

        let mut name = String::new();
        let mut atoms: Vec<Atom> = Vec::new();

        loop {
            commands.print_menu();
            let input = utils::get_input_string("Selection")?;
            println!("");

            if let Some((cmd, tail)) = commands.get_selection_and_tail(&input) {
                match cmd {
                    ResidueCommand::SetName => {
                        name = tail.to_uppercase().to_string();
                        println!("Set residue name to '{}'", &name);
                    },
                    ResidueCommand::AddAtom => {
                        match parse_string_for_atom(&tail) {
                            Ok(atom) => {
                                println!("Added atom '{}' to residue.", &atom.code);
                                atoms.push(atom);
                            },
                            Err(err) => println!("Could not add atom: {}", err.description()),
                        }

                    },
                    ResidueCommand::RemoveAtom => {
                        match utils::remove_item(&mut atoms, &tail) {
                            Ok(i) => println!("Removed atom with index {} from residue.", i),
                            Err(err) => println!("Could not remove atom: {}", err.description()),
                        }
                    },
                    ResidueCommand::SwapAtoms => {
                        match utils::swap_items(&mut atoms, &tail) {
                            Ok((i, j)) => println!("Swapped atoms at index {} with atom at {}.",
                                                   i, j),
                            Err(err) => println!("Could not swap atoms: {}", err.description()),
                        }
                    },
                    ResidueCommand::ShowResidue => {
                        describe_residue(&name, &atoms);
                    },
                    ResidueCommand::QuitAndSave => {
                        if name.is_empty() {
                            println!("Cannot add residue: No name is set");
                        } else if atoms.is_empty() {
                            println!("Cannot add residue: No atoms are set");
                        } else {
                            return Ok(ResidueBase {
                                code: name,
                                atoms: atoms,
                            });
                        }
                    }
                    ResidueCommand::QuitWithoutSaving => {
                        return Err(GrafenCliError::from(UIErrorKind::Abort));
                    },
                }
            } else {
                println!("Not a valid selection.");
            }

            println!("");
        }
    }

    fn parse_string_for_atom<'a>(input: &'a str) -> Result<Atom> {
        let mut iter = input.splitn(2, ' ');
        let name = iter.next().and_then(|s| {
                if s.is_empty() {
                    None
                } else {
                    Some(s)
                }
            })
            .ok_or(UIErrorKind::BadValue("No name was given".to_string()))?;

        let tail = iter.next().unwrap_or("");

        let coords = utils::parse_string(&tail)?;
        let &x = coords.get(0)
                       .ok_or(UIErrorKind::BadValue("3 positions are required".to_string()))?;
        let &y = coords.get(1)
                       .ok_or(UIErrorKind::BadValue("3 positions are required".to_string()))?;
        let &z = coords.get(2)
                       .ok_or(UIErrorKind::BadValue("3 positions are required".to_string()))?;

        Ok(Atom {
            code: name.to_uppercase().to_string(),
            position: Coord::new(x, y, z),
        })
    }

    fn describe_residue<'a>(name: &'a str, atoms: &[Atom]) {
        println!("Residue name: '{}'", name);
        println!("Atoms:");
        for (i, atom) in atoms.iter().enumerate() {
            let (x, y, z) = atom.position.to_tuple();
            println!("{:4}. {} at ({:.1}, {:.1}, {:.1})", i, atom.code, x, y, z);
        }
    }

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

        #[test]
        fn parse_atom_string() {
            let atom = Atom { code: "A1".to_string(), position: Coord::new(1.0, 2.0, 0.0) };
            assert_eq!(atom, parse_string_for_atom("A1 1 2 0").unwrap());
        }

        #[test]
        fn parse_atoms_without_name_or_some_values_is_error() {
            assert!(parse_string_for_atom("\t\n").is_err());
            assert!(parse_string_for_atom("\tname\n 1.0").is_err());
            assert!(parse_string_for_atom("\tname 1.0\t2.0").is_err());
            assert!(parse_string_for_atom("\tname 1.0 2.0 3").is_ok());
            assert!(parse_string_for_atom("\tname 1.0 2.0 a").is_err());
        }

        #[test]
        fn parse_atoms_sets_name_to_uppercase() {
            assert_eq!("AT1", parse_string_for_atom("at1 1 2 0").unwrap().code);
        }
    }
}

mod define_substrate {
    //! Define a new `SubstrateConfEntry`.

    use database::SubstrateConfEntry;
    use error::{GrafenCliError, Result};
    use ui::utils;

    use grafen::substrate::LatticeType;
    use grafen::system::ResidueBase;

    #[derive(Clone, Copy, Debug)]
    /// Available lattices to construct from. Each of these require
    /// a separate constructor since they have different qualities in
    /// their corresponding `LatticeType` unit.
    enum LatticeCommand {
        Triclinic,
        Hexagonal,
        PoissonDisc,
    }

    pub fn user_menu(residue_list: &Vec<ResidueBase>) -> Result<SubstrateConfEntry> {
        let name = utils::get_input_string("Substrate name")
            .and_then(|string| {
                if string.is_empty() {
                    Err(GrafenCliError::UIError("No name was entered".to_string()))
                } else {
                    Ok(string)
                }
            })
            .map_err(|err| GrafenCliError::from(err))?;
        println!("");

        let residue = select_residue(&residue_list)?;
        println!("");

        let lattice = select_lattice()?;
        println!("");

        let std_z = select_deviation_along_z()?;
        println!("");

        Ok(SubstrateConfEntry { name, lattice, residue, std_z })
    }

    fn select_residue(residue_list: &Vec<ResidueBase>) -> Result<ResidueBase> {
        println!("Available residues:");
        for (i, residue) in residue_list.iter().enumerate() {
            println!("{:4}. {}", i, residue.code);
        }
        println!("");

        let input = utils::get_input_string("Selection")?;
        let index = utils::parse_string_for_index(&input, &residue_list)?;

        Ok(residue_list[index].clone())
    }

    fn select_lattice() -> Result<LatticeType> {
        let lattice_list = vec![
            (LatticeCommand::Triclinic, "Triclinic lattice: two base vector lengths and an angle in-between"),
            (LatticeCommand::Hexagonal, "Hexagonal lattice: a honeycomb grid with a spacing"),
            (LatticeCommand::PoissonDisc, "Poisson disc: Randomly generated points with a density")
        ];

        println!("Available lattices:");
        for (i, lattice) in lattice_list.iter().enumerate() {
            println!("{:4}. {}", i, lattice.1);
        }
        println!("");

        let input = utils::get_input_string("Selection")?;
        let index = utils::parse_string_for_index(&input, &lattice_list)?;

        match lattice_list[index].0 {
            LatticeCommand::Triclinic => {
                println!("A triclinic lattice is constructed from two base ");
                println!("vectors of length a and b, separated by an angle γ.");
                println!("");

                let input = utils::get_input_string("Input length 'a'")?;
                let a = utils::parse_string_single(&input)?;
                let input = utils::get_input_string("Input length 'b'")?;
                let b = utils::parse_string_single(&input)?;
                let input = utils::get_input_string("Input angle 'γ'")?;
                let gamma = utils::parse_string_single(&input)?;

                Ok(LatticeType::Triclinic { a, b, gamma })
            },

            LatticeCommand::Hexagonal => {
                println!("A hexagonal lattice is a honeycomb grid with an input side length.");
                println!("");

                let input = utils::get_input_string("Input side length")?;
                let a = utils::parse_string_single(&input)?;

                Ok(LatticeType::Hexagonal { a })
            },

            LatticeCommand::PoissonDisc => {
                println!("A Poisson disc is a generated set of points with an even distribution.");
                println!("They are generated with an input density in points per area.");
                println!("");

                let input = utils::get_input_string("Input density")?;
                let density = utils::parse_string_single(&input)?;

                Ok(LatticeType::PoissonDisc { density })
            },
        }
    }

    fn select_deviation_along_z() -> Result<Option<f64>> {
        let query = "Distribute residue positions along z with this deviation (default: No)";
        let selection = utils::get_input_string(query)?;

        match utils::parse_string_single(&selection) {
            Ok(value) => Ok(Some(value)),
            _ => Ok(None),
        }
    }
}
<commit_msg>Fix double-quote enclosing when printing database path after setting<commit_after>//! Edit a `DataBase`.

use database::{write_database, DataBase};
use error::Result;
use ui::utils;
use ui::utils::{CommandList, CommandParser};

use std::error::Error;

#[derive(Clone, Copy, Debug)]
/// Editing commands.
enum Command {
    AddResidue,
    RemoveResidue,
    AddSubstrate,
    RemoveSubstrate,
    WriteToDisk,
    SetLocation,
    ShowDatabase,
    QuitAndSave,
    QuitWithoutSaving,
}

/// The main user menu.
pub fn user_menu(database: &mut DataBase) -> Result<&'static str> {
    let command_list: CommandList<Command> = vec![
        ("ra", Command::AddResidue, "Add a residue definition"),
        ("rr", Command::RemoveResidue, "Remove a residue definition"),
        ("sa", Command::AddSubstrate, "Add a substrate definition"),
        ("sr", Command::RemoveSubstrate, "Remove a substrate definition"),
        ("w", Command::WriteToDisk, "Write database to disk"),
        ("c", Command::SetLocation, "Change output location of database"),
        ("l", Command::ShowDatabase, "List database content"),
        ("f", Command::QuitAndSave, "Finish editing database"),
        ("a", Command::QuitWithoutSaving, "Abort editing and discard changes"),
    ];
    let commands = CommandParser::from_list(command_list);

    let path_backup = database.path.clone();
    let residues_backup = database.residue_defs.clone();
    let substrates_backup = database.substrate_defs.clone();

    println!("Editing the current database.\n");
    database.describe();
    println!("");

    loop {
        commands.print_menu();
        let input = utils::get_input_string("Selection")?;

        if let Some((cmd, tail)) = commands.get_selection_and_tail(&input) {
            match cmd {
                Command::AddResidue => {
                    match define_residue::user_menu() {
                        Ok(residue) => {
                            println!("Added residue '{}' to database.", residue.code);
                            database.residue_defs.push(residue);
                        },
                        Err(err) => println!("Could not create residue: {}", err.description()),
                    }
                },
                Command::RemoveResidue => {
                    match utils::remove_item(&mut database.residue_defs, &tail) {
                        Ok(i) => println!("Removed residue with index {} from database.", i),
                        Err(err) => println!("Could not remove residue: {}", err.description()),
                    }
                },
                Command::AddSubstrate => {
                    match define_substrate::user_menu(&database.residue_defs) {
                        Ok(substrate) => {
                            println!("Added substrate definition '{}' to database.",
                                     substrate.name);
                            database.substrate_defs.push(substrate);
                        },
                        Err(err) => println!("Could not create substrate: {}", err.description()),
                    }
                },
                Command::RemoveSubstrate => {
                    match utils::remove_item(&mut database.substrate_defs, &tail) {
                        Ok(i) => println!("Removed substrate with index {} from database.", i),
                        Err(err) => println!("Could not remove substrate: {}", err.description()),
                    }
                },
                Command::WriteToDisk => {
                    match write_database(&database) {
                        Ok(_) => println!("Wrote database to '{}'.",
                                          database.path.as_ref().unwrap().to_str().unwrap()),
                        Err(err) => println!("Could not write database: {}", err.description()),
                    }
                },
                Command::SetLocation => {
                    match database.set_path(&tail) {
                        Ok(_) => println!("Database path set to {}.",
                                          database.get_path_pretty()),
                        Err(err) => println!("Could not change database path: {}",
                                             err.description()),
                    }
                },
                Command::ShowDatabase => {
                    println!("");
                    database.describe();
                },
                Command::QuitAndSave => {
                    return Ok("Finished editing database.");
                },
                Command::QuitWithoutSaving => {
                    database.path = path_backup;
                    database.residue_defs = residues_backup;
                    database.substrate_defs = substrates_backup;

                    return Ok("Discarding changes to database.");
                },
            }
        } else {
            println!("Not a valid selection.");
        }

        println!("");
    }
}

mod define_residue {
    //! Define a new `ResidueBase`.

    use error::{GrafenCliError, Result, UIErrorKind};
    use ui::utils;
    use ui::utils::{CommandList, CommandParser};

    use grafen::system::{Atom, Coord, ResidueBase};
    use std::error::Error;

    #[derive(Clone, Copy, Debug)]
    enum ResidueCommand {
        SetName,
        AddAtom,
        RemoveAtom,
        SwapAtoms,
        ShowResidue,
        QuitAndSave,
        QuitWithoutSaving,
    }

    pub fn user_menu() -> Result<ResidueBase> {
        let command_list: CommandList<ResidueCommand> = vec![
            ("n", ResidueCommand::SetName, "Set residue name"),
            ("at", ResidueCommand::AddAtom, "Add atom to residue"),
            ("r", ResidueCommand::RemoveAtom, "Remove atom from residue"),
            ("s", ResidueCommand::SwapAtoms, "Swap two atoms in list"),
            ("l", ResidueCommand::ShowResidue, "List current residue data"),
            ("f", ResidueCommand::QuitAndSave, "Finish and add residue to list"),
            ("a", ResidueCommand::QuitWithoutSaving, "Abort and discard changes")
        ];
        let commands = CommandParser::from_list(command_list);

        println!("Creating a new residue.\n");

        let mut name = String::new();
        let mut atoms: Vec<Atom> = Vec::new();

        loop {
            commands.print_menu();
            let input = utils::get_input_string("Selection")?;
            println!("");

            if let Some((cmd, tail)) = commands.get_selection_and_tail(&input) {
                match cmd {
                    ResidueCommand::SetName => {
                        name = tail.to_uppercase().to_string();
                        println!("Set residue name to '{}'", &name);
                    },
                    ResidueCommand::AddAtom => {
                        match parse_string_for_atom(&tail) {
                            Ok(atom) => {
                                println!("Added atom '{}' to residue.", &atom.code);
                                atoms.push(atom);
                            },
                            Err(err) => println!("Could not add atom: {}", err.description()),
                        }

                    },
                    ResidueCommand::RemoveAtom => {
                        match utils::remove_item(&mut atoms, &tail) {
                            Ok(i) => println!("Removed atom with index {} from residue.", i),
                            Err(err) => println!("Could not remove atom: {}", err.description()),
                        }
                    },
                    ResidueCommand::SwapAtoms => {
                        match utils::swap_items(&mut atoms, &tail) {
                            Ok((i, j)) => println!("Swapped atoms at index {} with atom at {}.",
                                                   i, j),
                            Err(err) => println!("Could not swap atoms: {}", err.description()),
                        }
                    },
                    ResidueCommand::ShowResidue => {
                        describe_residue(&name, &atoms);
                    },
                    ResidueCommand::QuitAndSave => {
                        if name.is_empty() {
                            println!("Cannot add residue: No name is set");
                        } else if atoms.is_empty() {
                            println!("Cannot add residue: No atoms are set");
                        } else {
                            return Ok(ResidueBase {
                                code: name,
                                atoms: atoms,
                            });
                        }
                    }
                    ResidueCommand::QuitWithoutSaving => {
                        return Err(GrafenCliError::from(UIErrorKind::Abort));
                    },
                }
            } else {
                println!("Not a valid selection.");
            }

            println!("");
        }
    }

    fn parse_string_for_atom<'a>(input: &'a str) -> Result<Atom> {
        let mut iter = input.splitn(2, ' ');
        let name = iter.next().and_then(|s| {
                if s.is_empty() {
                    None
                } else {
                    Some(s)
                }
            })
            .ok_or(UIErrorKind::BadValue("No name was given".to_string()))?;

        let tail = iter.next().unwrap_or("");

        let coords = utils::parse_string(&tail)?;
        let &x = coords.get(0)
                       .ok_or(UIErrorKind::BadValue("3 positions are required".to_string()))?;
        let &y = coords.get(1)
                       .ok_or(UIErrorKind::BadValue("3 positions are required".to_string()))?;
        let &z = coords.get(2)
                       .ok_or(UIErrorKind::BadValue("3 positions are required".to_string()))?;

        Ok(Atom {
            code: name.to_uppercase().to_string(),
            position: Coord::new(x, y, z),
        })
    }

    fn describe_residue<'a>(name: &'a str, atoms: &[Atom]) {
        println!("Residue name: '{}'", name);
        println!("Atoms:");
        for (i, atom) in atoms.iter().enumerate() {
            let (x, y, z) = atom.position.to_tuple();
            println!("{:4}. {} at ({:.1}, {:.1}, {:.1})", i, atom.code, x, y, z);
        }
    }

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

        #[test]
        fn parse_atom_string() {
            let atom = Atom { code: "A1".to_string(), position: Coord::new(1.0, 2.0, 0.0) };
            assert_eq!(atom, parse_string_for_atom("A1 1 2 0").unwrap());
        }

        #[test]
        fn parse_atoms_without_name_or_some_values_is_error() {
            assert!(parse_string_for_atom("\t\n").is_err());
            assert!(parse_string_for_atom("\tname\n 1.0").is_err());
            assert!(parse_string_for_atom("\tname 1.0\t2.0").is_err());
            assert!(parse_string_for_atom("\tname 1.0 2.0 3").is_ok());
            assert!(parse_string_for_atom("\tname 1.0 2.0 a").is_err());
        }

        #[test]
        fn parse_atoms_sets_name_to_uppercase() {
            assert_eq!("AT1", parse_string_for_atom("at1 1 2 0").unwrap().code);
        }
    }
}

mod define_substrate {
    //! Define a new `SubstrateConfEntry`.

    use database::SubstrateConfEntry;
    use error::{GrafenCliError, Result};
    use ui::utils;

    use grafen::substrate::LatticeType;
    use grafen::system::ResidueBase;

    #[derive(Clone, Copy, Debug)]
    /// Available lattices to construct from. Each of these require
    /// a separate constructor since they have different qualities in
    /// their corresponding `LatticeType` unit.
    enum LatticeCommand {
        Triclinic,
        Hexagonal,
        PoissonDisc,
    }

    pub fn user_menu(residue_list: &Vec<ResidueBase>) -> Result<SubstrateConfEntry> {
        let name = utils::get_input_string("Substrate name")
            .and_then(|string| {
                if string.is_empty() {
                    Err(GrafenCliError::UIError("No name was entered".to_string()))
                } else {
                    Ok(string)
                }
            })
            .map_err(|err| GrafenCliError::from(err))?;
        println!("");

        let residue = select_residue(&residue_list)?;
        println!("");

        let lattice = select_lattice()?;
        println!("");

        let std_z = select_deviation_along_z()?;
        println!("");

        Ok(SubstrateConfEntry { name, lattice, residue, std_z })
    }

    fn select_residue(residue_list: &Vec<ResidueBase>) -> Result<ResidueBase> {
        println!("Available residues:");
        for (i, residue) in residue_list.iter().enumerate() {
            println!("{:4}. {}", i, residue.code);
        }
        println!("");

        let input = utils::get_input_string("Selection")?;
        let index = utils::parse_string_for_index(&input, &residue_list)?;

        Ok(residue_list[index].clone())
    }

    fn select_lattice() -> Result<LatticeType> {
        let lattice_list = vec![
            (LatticeCommand::Triclinic, "Triclinic lattice: two base vector lengths and an angle in-between"),
            (LatticeCommand::Hexagonal, "Hexagonal lattice: a honeycomb grid with a spacing"),
            (LatticeCommand::PoissonDisc, "Poisson disc: Randomly generated points with a density")
        ];

        println!("Available lattices:");
        for (i, lattice) in lattice_list.iter().enumerate() {
            println!("{:4}. {}", i, lattice.1);
        }
        println!("");

        let input = utils::get_input_string("Selection")?;
        let index = utils::parse_string_for_index(&input, &lattice_list)?;

        match lattice_list[index].0 {
            LatticeCommand::Triclinic => {
                println!("A triclinic lattice is constructed from two base ");
                println!("vectors of length a and b, separated by an angle γ.");
                println!("");

                let input = utils::get_input_string("Input length 'a'")?;
                let a = utils::parse_string_single(&input)?;
                let input = utils::get_input_string("Input length 'b'")?;
                let b = utils::parse_string_single(&input)?;
                let input = utils::get_input_string("Input angle 'γ'")?;
                let gamma = utils::parse_string_single(&input)?;

                Ok(LatticeType::Triclinic { a, b, gamma })
            },

            LatticeCommand::Hexagonal => {
                println!("A hexagonal lattice is a honeycomb grid with an input side length.");
                println!("");

                let input = utils::get_input_string("Input side length")?;
                let a = utils::parse_string_single(&input)?;

                Ok(LatticeType::Hexagonal { a })
            },

            LatticeCommand::PoissonDisc => {
                println!("A Poisson disc is a generated set of points with an even distribution.");
                println!("They are generated with an input density in points per area.");
                println!("");

                let input = utils::get_input_string("Input density")?;
                let density = utils::parse_string_single(&input)?;

                Ok(LatticeType::PoissonDisc { density })
            },
        }
    }

    fn select_deviation_along_z() -> Result<Option<f64>> {
        let query = "Distribute residue positions along z with this deviation (default: No)";
        let selection = utils::get_input_string(query)?;

        match utils::parse_string_single(&selection) {
            Ok(value) => Ok(Some(value)),
            _ => Ok(None),
        }
    }
}
<|endoftext|>


<commit_before>use serde::{Serialize, Serializer};
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::ffi::OsStr;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::path::Path;
use std::ptr;
use std::str;
use std::sync::Mutex;

pub fn leak(s: String) -> &'static str {
    Box::leak(s.into_boxed_str())
}

lazy_static::lazy_static! {
    static ref STRING_CACHE: Mutex<HashSet<&'static str>> = Mutex::new(HashSet::new());
}

#[derive(Clone, Copy)]
pub struct InternedString {
    inner: &'static str,
}

impl<'a> From<&'a str> for InternedString {
    fn from(item: &'a str) -> Self {
        InternedString::new(item)
    }
}

impl<'a> From<&'a String> for InternedString {
    fn from(item: &'a String) -> Self {
        InternedString::new(item)
    }
}

impl From<String> for InternedString {
    fn from(item: String) -> Self {
        InternedString::new(&item)
    }
}

impl PartialEq for InternedString {
    fn eq(&self, other: &InternedString) -> bool {
        ptr::eq(self.as_str(), other.as_str())
    }
}

impl PartialEq<str> for InternedString {
    fn eq(&self, other: &str) -> bool {
        *self == other
    }
}

impl<'a> PartialEq<&'a str> for InternedString {
    fn eq(&self, other: &&str) -> bool {
        **self == **other
    }
}

impl Eq for InternedString {}

impl InternedString {
    pub fn new(str: &str) -> InternedString {
        let mut cache = STRING_CACHE.lock().unwrap();
        let s = cache.get(str).cloned().unwrap_or_else(|| {
            let s = leak(str.to_string());
            cache.insert(s);
            s
        });

        InternedString { inner: s }
    }

    pub fn as_str(&self) -> &'static str {
        self.inner
    }
}

impl Deref for InternedString {
    type Target = str;

    fn deref(&self) -> &'static str {
        self.as_str()
    }
}

impl AsRef<str> for InternedString {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl AsRef<OsStr> for InternedString {
    fn as_ref(&self) -> &OsStr {
        self.as_str().as_ref()
    }
}

impl AsRef<Path> for InternedString {
    fn as_ref(&self) -> &Path {
        self.as_str().as_ref()
    }
}

impl Hash for InternedString {
    // N.B., we can't implement this as `identity(self).hash(state)`,
    // because we use this for on-disk fingerprints and so need
    // stability across Cargo invocations.
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.as_str().hash(state);
    }
}

impl Borrow<str> for InternedString {
    // If we implement Hash as `identity(self).hash(state)`,
    // then this will need to be removed.
    fn borrow(&self) -> &str {
        self.as_str()
    }
}

impl fmt::Debug for InternedString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(self.as_str(), f)
    }
}

impl fmt::Display for InternedString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self.as_str(), f)
    }
}

impl Ord for InternedString {
    fn cmp(&self, other: &InternedString) -> Ordering {
        self.as_str().cmp(other.as_str())
    }
}

impl PartialOrd for InternedString {
    fn partial_cmp(&self, other: &InternedString) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Serialize for InternedString {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.inner)
    }
}

struct InternedStringVisitor;

impl<'de> serde::Deserialize<'de> for InternedString {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_str(InternedStringVisitor)
    }
}

impl<'de> serde::de::Visitor<'de> for InternedStringVisitor {
    type Value = InternedString;

    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("an String like thing")
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(InternedString::new(v))
    }
}
<commit_msg>Make leak function private<commit_after>use serde::{Serialize, Serializer};
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::ffi::OsStr;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::path::Path;
use std::ptr;
use std::str;
use std::sync::Mutex;

fn leak(s: String) -> &'static str {
    Box::leak(s.into_boxed_str())
}

lazy_static::lazy_static! {
    static ref STRING_CACHE: Mutex<HashSet<&'static str>> = Mutex::new(HashSet::new());
}

#[derive(Clone, Copy)]
pub struct InternedString {
    inner: &'static str,
}

impl<'a> From<&'a str> for InternedString {
    fn from(item: &'a str) -> Self {
        InternedString::new(item)
    }
}

impl<'a> From<&'a String> for InternedString {
    fn from(item: &'a String) -> Self {
        InternedString::new(item)
    }
}

impl From<String> for InternedString {
    fn from(item: String) -> Self {
        InternedString::new(&item)
    }
}

impl PartialEq for InternedString {
    fn eq(&self, other: &InternedString) -> bool {
        ptr::eq(self.as_str(), other.as_str())
    }
}

impl PartialEq<str> for InternedString {
    fn eq(&self, other: &str) -> bool {
        *self == other
    }
}

impl<'a> PartialEq<&'a str> for InternedString {
    fn eq(&self, other: &&str) -> bool {
        **self == **other
    }
}

impl Eq for InternedString {}

impl InternedString {
    pub fn new(str: &str) -> InternedString {
        let mut cache = STRING_CACHE.lock().unwrap();
        let s = cache.get(str).cloned().unwrap_or_else(|| {
            let s = leak(str.to_string());
            cache.insert(s);
            s
        });

        InternedString { inner: s }
    }

    pub fn as_str(&self) -> &'static str {
        self.inner
    }
}

impl Deref for InternedString {
    type Target = str;

    fn deref(&self) -> &'static str {
        self.as_str()
    }
}

impl AsRef<str> for InternedString {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl AsRef<OsStr> for InternedString {
    fn as_ref(&self) -> &OsStr {
        self.as_str().as_ref()
    }
}

impl AsRef<Path> for InternedString {
    fn as_ref(&self) -> &Path {
        self.as_str().as_ref()
    }
}

impl Hash for InternedString {
    // N.B., we can't implement this as `identity(self).hash(state)`,
    // because we use this for on-disk fingerprints and so need
    // stability across Cargo invocations.
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.as_str().hash(state);
    }
}

impl Borrow<str> for InternedString {
    // If we implement Hash as `identity(self).hash(state)`,
    // then this will need to be removed.
    fn borrow(&self) -> &str {
        self.as_str()
    }
}

impl fmt::Debug for InternedString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(self.as_str(), f)
    }
}

impl fmt::Display for InternedString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self.as_str(), f)
    }
}

impl Ord for InternedString {
    fn cmp(&self, other: &InternedString) -> Ordering {
        self.as_str().cmp(other.as_str())
    }
}

impl PartialOrd for InternedString {
    fn partial_cmp(&self, other: &InternedString) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Serialize for InternedString {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.inner)
    }
}

struct InternedStringVisitor;

impl<'de> serde::Deserialize<'de> for InternedString {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_str(InternedStringVisitor)
    }
}

impl<'de> serde::de::Visitor<'de> for InternedStringVisitor {
    type Value = InternedString;

    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("an String like thing")
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(InternedString::new(v))
    }
}
<|endoftext|>