<commit_before>use ::cpu::*;
use ::peripherals::Memory;
use self::output_registers::*;

use std::io::{stdin, stdout};
use std::io::Write;

use std::borrow::Cow;
use std::str::{self, FromStr};

use nom::{IResult, space, digit, hex_digit};

use std::rc::Rc;
use std::cell::RefCell;

#[derive(Debug, Clone, Copy)]
enum Command {
    Step(u16),
    Mem(u16),
    MemRng(u16, u16),
    Cont,
    Exit,
}

impl FromStr for Command {
    type Err = Cow<'static, str>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match command(s.as_bytes()) {
            IResult::Done(_, c) => Ok(c),
            err => Err(format!("Unable to parse command: {:?}", err).into()),
        }
    }
}

named!(
    command<Command>,
    do_parse!(
        c: alt_complete!(
            step |
            mem  |
            cont |
            exit) >>
        eof!() >>

        (c)
    )
);

named!(
    step<Command>,
    do_parse!(
        alt_complete!(tag!("step") | tag!("s")) >>
        count: opt!(complete!(preceded!(space, u16_parser))) >>

        (Command::Step(count.unwrap_or(1)))
    )
);

named!(
    mem<Command>,
    do_parse!(
        alt_complete!(tag!("mem") | tag!("m")) >>
        addrs: many_m_n!(1, 2, preceded!(space, u16_hex_parser)) >>

        (match addrs.len() {
            1 => Command::Mem(addrs[0]),
            2 => Command::MemRng(addrs[0], addrs[1]),
            _ => unreachable!(),
        })
    )
);

named!(
    cont<Command>,
    do_parse!(
        alt_complete!(tag!("cont") | tag!("c")) >>

        (Command::Cont)
    )
);

named!(
    exit<Command>,
    do_parse!(
        alt_complete!(tag!("exit") | tag!("e") | tag!("quit") | tag!("q")) >>

        (Command::Exit)
    )
);

named!(u16_parser<u16>,
    map_res!(
        map_res!(
            digit,
            str::from_utf8),
        FromStr::from_str));

named!(u16_hex_parser<u16>,
    do_parse!(
        opt!(tag!("0x")) >>
        number: map_res!(
            hex_digit,
            str::from_utf8) >>
        u16number: expr_res!(u16::from_str_radix(number, 16)) >>
        (u16number)
    )
);

pub mod output_registers {

    use ::cpu::{Reg8, Reg16};

    bitflags! {
        pub struct OutputRegisters: u32 {
            const ONONE = 0x00000000;

            const OA = 0x00000001;
            const OF = 0x00000002;
            const OB = 0x00000004;
            const OC = 0x00000008;
            const OD = 0x00000010;
            const OE = 0x00000020;
            const OH = 0x00000040;
            const OL = 0x00000080;

            const OA_ALT = 0x00000100;
            const OF_ALT = 0x00000200;
            const OB_ALT = 0x00000400;
            const OC_ALT = 0x00000800;
            const OD_ALT = 0x00001000;
            const OE_ALT = 0x00002000;
            const OH_ALT = 0x00004000;
            const OL_ALT = 0x00008000;

            const OIX = 0x00010000;
            const OIY = 0x00020000;
            const OSP = 0x00040000;
            const OPC = 0x00080000;
            const OWZ = 0x00100000;

            const OI = 0x00200000;
            const OR = 0x00400080;

            const OALL = 0xFFFFFFFF;
        }
    }

    impl From<Reg16> for OutputRegisters {
        fn from(r: Reg16) -> OutputRegisters {
            match r {
                Reg16::AF => OA | OF,
                Reg16::BC => OB | OC,
                Reg16::DE => OD | OE,
                Reg16::HL => OH | OL,
                Reg16::IR => OI | OR,
                Reg16::AF_ALT => OA_ALT | OF_ALT,
                Reg16::BC_ALT => OB_ALT | OC_ALT,
                Reg16::DE_ALT => OD_ALT | OE_ALT,
                Reg16::HL_ALT => OH_ALT | OL_ALT,
                Reg16::SP => OSP,
                Reg16::IX => OIX,
                Reg16::IY => OIY,
                Reg16::WZ => OWZ,
            }
        }
    }

    impl From<Reg8> for OutputRegisters {
        fn from(r: Reg8) -> OutputRegisters {
            match r {
                Reg8::A => OA,
                Reg8::B => OB,
                Reg8::C => OC,
                Reg8::D => OD,
                Reg8::E => OE,
                Reg8::H => OH,
                Reg8::L => OL,
                Reg8::I => OI,
                Reg8::R => OR,
                Reg8::A_ALT => OA_ALT,
                Reg8::B_ALT => OB_ALT,
                Reg8::C_ALT => OC_ALT,
                Reg8::D_ALT => OD_ALT,
                Reg8::E_ALT => OE_ALT,
                Reg8::H_ALT => OH_ALT,
                Reg8::L_ALT => OL_ALT,
                Reg8::F_ALT => OF_ALT,
                Reg8::IXL | Reg8::IXH => OIX,
                Reg8::IYL | Reg8::IYH => OIY,
            }
        }
    }
}

macro_rules! reg_str {
    ($regs: ident, $outreg: ident, $fmtstr: expr, $reg: expr, $nostr: expr) => {{
        if $regs.contains($outreg) {
            format!($fmtstr, $reg)
        } else {
            String::from($nostr)
        }
    }}
}

pub struct Debugger {
    cpu: Rc<RefCell<Cpu>>,
    memory: Rc<RefCell<Memory>>,
}

impl Debugger {
    pub fn new(cpu: Rc<RefCell<Cpu>>, memory: Rc<RefCell<Memory>>) -> Self {
        Debugger {
            cpu: cpu,
            memory: memory,
        }
    }

    fn output(&self, regs: OutputRegisters) -> String {
        format!(
            "                 -----------        -----------
             af: |{}|{}|   af': |{}|{}|   tcycles: {}    im: {}
             bc: |{}|{}|   bc': |{}|{}|         i: {}     iff1: {}
             de: |{}|{}|   de': |{}|{}|         r: {}     iff2: {}
             hl: |{}|{}|   hl': |{}|{}|
                 -----------        -----------
                 ----------         ------------
             ix: | {} |         | SZ_H_PNC |   0x0000: ROM {}
             iy: | {} |      f: |{}|   0x4000: ROM {}
             sp: | {} |         ------------   0x8000: ROM {}
             pc: | {} |                        0xC000: ROM {}
                 ----------",
            reg_str!(regs, OA    , " {:02X} ", self.cpu.borrow().read_reg8(Reg8::A)       , "    "      ),
            reg_str!(regs, OF    , " {:02X} ", self.cpu.borrow().get_flags().bits() as u8 , "    "      ),
            reg_str!(regs, OA_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::A_ALT)   , "    "      ),
            reg_str!(regs, OF_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::F_ALT)   , "    "      ),
            format!("{:05}", self.cpu.borrow().tcycles),
            format!("{}", self.cpu.borrow().get_im()),
            reg_str!(regs, OB    , " {:02X} ", self.cpu.borrow().read_reg8(Reg8::B)       , "    "      ),
            reg_str!(regs, OC    , " {:02X} ", self.cpu.borrow().read_reg8(Reg8::C)       , "    "      ),
            reg_str!(regs, OB_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::B_ALT)   , "    "      ),
            reg_str!(regs, OC_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::C_ALT)   , "    "      ),
            format!("{:02X}", self.cpu.borrow().read_reg8(Reg8::I)),
            format!("{}", if self.cpu.borrow().get_iff1() {1} else {0}),
            reg_str!(regs, OD    , " {:02X} ", self.cpu.borrow().read_reg8(Reg8::D)       , "    "      ),
            reg_str!(regs, OE    , " {:02X} ", self.cpu.borrow().read_reg8(Reg8::E)       , "    "      ),
            reg_str!(regs, OD_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::D_ALT)   , "    "      ),
            reg_str!(regs, OE_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::E_ALT)   , "    "      ),
            format!("{:02X}", self.cpu.borrow().read_reg8(Reg8::R)),
            format!("{}", if self.cpu.borrow().get_iff2() {1} else {0}),
            reg_str!(regs, OH    , " {:02X} ", self.cpu.borrow().read_reg8(Reg8::H)       , "    "      ),
            reg_str!(regs, OL    , " {:02X} ", self.cpu.borrow().read_reg8(Reg8::L)       , "    "      ),
            reg_str!(regs, OH_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::H_ALT)   , "    "      ),
            reg_str!(regs, OL_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::L_ALT)   , "    "      ),
            reg_str!(regs, OIX   , " {:04X} ", self.cpu.borrow().read_reg16(Reg16::IX)    , "      "    ),
            format!("{}", self.memory.borrow().get_0000_bank()),
            reg_str!(regs, OIY   , " {:04X} ", self.cpu.borrow().read_reg16(Reg16::IY)    , "      "    ),
            reg_str!(regs, OF    , " {:08b} ", self.cpu.borrow().get_flags().bits()       , "          "),
            format!("{}", self.memory.borrow().get_4000_bank()),
            reg_str!(regs, OSP   , " {:04X} ", self.cpu.borrow().read_reg16(Reg16::SP)    , "      "    ),
            format!("{}", self.memory.borrow().get_8000_bank()),
            format!(" {:04X} ", self.cpu.borrow().get_pc()),
            format!("{}", self.memory.borrow().get_c000_bank()))
    }

    fn peek_at_next_instruction(&self) -> &Instruction {
        let curr_pc = self.cpu.borrow().get_pc();

        let i0 = self.memory.borrow().read_word(curr_pc);
        let i1 = self.memory.borrow().read_word(curr_pc + 1);
        let i3 = self.memory.borrow().read_word(curr_pc + 3);

        match (i0, i1) {
            (0xDD, 0xCB) => INSTR_TABLE_DDCB[i3 as usize],
            (0xDD, _   ) => INSTR_TABLE_DD[i1 as usize],
            (0xFD, 0xCB) => INSTR_TABLE_FDCB[i3 as usize],
            (0xFD, _   ) => INSTR_TABLE_FD[i1 as usize],
            (0xCB, _   ) => INSTR_TABLE_CB[i1 as usize],
            (0xED, _   ) => INSTR_TABLE_ED[i1 as usize],
            (_   , _   ) => INSTR_TABLE[i0 as usize],
        }
    }

    pub fn run(&mut self) {
        loop {
            print!("z80> ");
            stdout().flush().unwrap();

            let mut input = String::new();
            stdin().read_line(&mut input).unwrap();
            let input: String = input.trim().into();

            match input.parse() {
                Ok(Command::Exit) => break,

                Ok(Command::Cont) => {
                    loop {
                        let (pre_regs, post_regs, instr_str) = {
                            let next_instr = self.peek_at_next_instruction();
                            let accessed_regs = next_instr.get_accessed_regs();
                            (accessed_regs.0,
                             accessed_regs.1,
                             next_instr.get_string(&self.cpu.borrow(), &self.memory.borrow()))
                        };
                        println!("{}", self.output(pre_regs));
                        println!("{}", instr_str);
                        self.cpu.borrow_mut().handle_interrupts();
                        self.cpu.borrow_mut().run_instruction();
                        println!("{}", self.output(post_regs));
                    }
                }

                Ok(Command::Step(count)) if count > 0 => {
                    for _ in 0..count {
                        let (pre_regs, post_regs, instr_str) = {
                            let next_instr = self.peek_at_next_instruction();
                            let accessed_regs = next_instr.get_accessed_regs();
                            (accessed_regs.0,
                             accessed_regs.1,
                             next_instr.get_string(&self.cpu.borrow(), &self.memory.borrow()))
                        };
                        println!("{}", self.output(pre_regs));
                        println!("{}", instr_str);
                        self.cpu.borrow_mut().handle_interrupts();
                        self.cpu.borrow_mut().run_instruction();
                        println!("{}", self.output(post_regs));
                    }
                }

                Ok(Command::MemRng(addrstart, addrend)) => {
                    let realaddrstart =
                        if addrstart % 16 == 0 {
                            addrstart
                        } else {
                            addrstart - (addrstart % 16)
                        };
                    let realaddrend =
                        if addrend % 16 == 0 {
                            addrend
                        } else {
                            addrend + (16 - (addrend % 16))
                        };
                    for addr in realaddrstart..realaddrend {
                        if addr % 16 == 0 {
                            println!();
                            print!("{:#06X}: ", addr);
                        }
                        print!("{:02X} ", self.memory.borrow().read_word(addr));
                    }
                    println!();
                }

                Ok(Command::Mem(addr)) => println!("{:#04X}", self.memory.borrow().read_word(addr)),

                _ => println!("Unknown command"),
            };
        }
    }
}
<commit_msg>Move macro inside function that uses it<commit_after>use ::cpu::*;
use ::peripherals::Memory;
use self::output_registers::*;

use std::io::{stdin, stdout};
use std::io::Write;

use std::borrow::Cow;
use std::str::{self, FromStr};

use nom::{IResult, space, digit, hex_digit};

use std::rc::Rc;
use std::cell::RefCell;

#[derive(Debug, Clone, Copy)]
enum Command {
    Step(u16),
    Mem(u16),
    MemRng(u16, u16),
    Cont,
    Exit,
}

impl FromStr for Command {
    type Err = Cow<'static, str>;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match command(s.as_bytes()) {
            IResult::Done(_, c) => Ok(c),
            err => Err(format!("Unable to parse command: {:?}", err).into()),
        }
    }
}

named!(
    command<Command>,
    do_parse!(
        c: alt_complete!(
            step |
            mem  |
            cont |
            exit) >>
        eof!() >>

        (c)
    )
);

named!(
    step<Command>,
    do_parse!(
        alt_complete!(tag!("step") | tag!("s")) >>
        count: opt!(complete!(preceded!(space, u16_parser))) >>

        (Command::Step(count.unwrap_or(1)))
    )
);

named!(
    mem<Command>,
    do_parse!(
        alt_complete!(tag!("mem") | tag!("m")) >>
        addrs: many_m_n!(1, 2, preceded!(space, u16_hex_parser)) >>

        (match addrs.len() {
            1 => Command::Mem(addrs[0]),
            2 => Command::MemRng(addrs[0], addrs[1]),
            _ => unreachable!(),
        })
    )
);

named!(
    cont<Command>,
    do_parse!(
        alt_complete!(tag!("cont") | tag!("c")) >>

        (Command::Cont)
    )
);

named!(
    exit<Command>,
    do_parse!(
        alt_complete!(tag!("exit") | tag!("e") | tag!("quit") | tag!("q")) >>

        (Command::Exit)
    )
);

named!(u16_parser<u16>,
    map_res!(
        map_res!(
            digit,
            str::from_utf8),
        FromStr::from_str));

named!(u16_hex_parser<u16>,
    do_parse!(
        opt!(tag!("0x")) >>
        number: map_res!(
            hex_digit,
            str::from_utf8) >>
        u16number: expr_res!(u16::from_str_radix(number, 16)) >>
        (u16number)
    )
);

pub mod output_registers {

    use ::cpu::{Reg8, Reg16};

    bitflags! {
        pub struct OutputRegisters: u32 {
            const ONONE = 0x00000000;

            const OA = 0x00000001;
            const OF = 0x00000002;
            const OB = 0x00000004;
            const OC = 0x00000008;
            const OD = 0x00000010;
            const OE = 0x00000020;
            const OH = 0x00000040;
            const OL = 0x00000080;

            const OA_ALT = 0x00000100;
            const OF_ALT = 0x00000200;
            const OB_ALT = 0x00000400;
            const OC_ALT = 0x00000800;
            const OD_ALT = 0x00001000;
            const OE_ALT = 0x00002000;
            const OH_ALT = 0x00004000;
            const OL_ALT = 0x00008000;

            const OIX = 0x00010000;
            const OIY = 0x00020000;
            const OSP = 0x00040000;
            const OPC = 0x00080000;
            const OWZ = 0x00100000;

            const OI = 0x00200000;
            const OR = 0x00400080;

            const OALL = 0xFFFFFFFF;
        }
    }

    impl From<Reg16> for OutputRegisters {
        fn from(r: Reg16) -> OutputRegisters {
            match r {
                Reg16::AF => OA | OF,
                Reg16::BC => OB | OC,
                Reg16::DE => OD | OE,
                Reg16::HL => OH | OL,
                Reg16::IR => OI | OR,
                Reg16::AF_ALT => OA_ALT | OF_ALT,
                Reg16::BC_ALT => OB_ALT | OC_ALT,
                Reg16::DE_ALT => OD_ALT | OE_ALT,
                Reg16::HL_ALT => OH_ALT | OL_ALT,
                Reg16::SP => OSP,
                Reg16::IX => OIX,
                Reg16::IY => OIY,
                Reg16::WZ => OWZ,
            }
        }
    }

    impl From<Reg8> for OutputRegisters {
        fn from(r: Reg8) -> OutputRegisters {
            match r {
                Reg8::A => OA,
                Reg8::B => OB,
                Reg8::C => OC,
                Reg8::D => OD,
                Reg8::E => OE,
                Reg8::H => OH,
                Reg8::L => OL,
                Reg8::I => OI,
                Reg8::R => OR,
                Reg8::A_ALT => OA_ALT,
                Reg8::B_ALT => OB_ALT,
                Reg8::C_ALT => OC_ALT,
                Reg8::D_ALT => OD_ALT,
                Reg8::E_ALT => OE_ALT,
                Reg8::H_ALT => OH_ALT,
                Reg8::L_ALT => OL_ALT,
                Reg8::F_ALT => OF_ALT,
                Reg8::IXL | Reg8::IXH => OIX,
                Reg8::IYL | Reg8::IYH => OIY,
            }
        }
    }
}

pub struct Debugger {
    cpu: Rc<RefCell<Cpu>>,
    memory: Rc<RefCell<Memory>>,
}

impl Debugger {
    pub fn new(cpu: Rc<RefCell<Cpu>>, memory: Rc<RefCell<Memory>>) -> Self {
        Debugger {
            cpu: cpu,
            memory: memory,
        }
    }

    fn output(&self, regs: OutputRegisters) -> String {
        macro_rules! reg_str {
            ($regs: ident, $outreg: ident, $fmtstr: expr, $reg: expr, $nostr: expr) => {{
                if $regs.contains($outreg) {
                    format!($fmtstr, $reg)
                } else {
                    String::from($nostr)
                }
            }}
        }

        format!(
            "                 -----------        -----------
             af: |{}|{}|   af': |{}|{}|   tcycles: {}    im: {}
             bc: |{}|{}|   bc': |{}|{}|         i: {}     iff1: {}
             de: |{}|{}|   de': |{}|{}|         r: {}     iff2: {}
             hl: |{}|{}|   hl': |{}|{}|
                 -----------        -----------
                 ----------         ------------
             ix: | {} |         | SZ_H_PNC |   0x0000: ROM {}
             iy: | {} |      f: |{}|   0x4000: ROM {}
             sp: | {} |         ------------   0x8000: ROM {}
             pc: | {} |                        0xC000: ROM {}
                 ----------",
            reg_str!(regs, OA    , " {:02X} ", self.cpu.borrow().read_reg8(Reg8::A)       , "    "      ),
            reg_str!(regs, OF    , " {:02X} ", self.cpu.borrow().get_flags().bits() as u8 , "    "      ),
            reg_str!(regs, OA_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::A_ALT)   , "    "      ),
            reg_str!(regs, OF_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::F_ALT)   , "    "      ),
            format!("{:05}", self.cpu.borrow().tcycles),
            format!("{}", self.cpu.borrow().get_im()),
            reg_str!(regs, OB    , " {:02X} ", self.cpu.borrow().read_reg8(Reg8::B)       , "    "      ),
            reg_str!(regs, OC    , " {:02X} ", self.cpu.borrow().read_reg8(Reg8::C)       , "    "      ),
            reg_str!(regs, OB_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::B_ALT)   , "    "      ),
            reg_str!(regs, OC_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::C_ALT)   , "    "      ),
            format!("{:02X}", self.cpu.borrow().read_reg8(Reg8::I)),
            format!("{}", if self.cpu.borrow().get_iff1() {1} else {0}),
            reg_str!(regs, OD    , " {:02X} ", self.cpu.borrow().read_reg8(Reg8::D)       , "    "      ),
            reg_str!(regs, OE    , " {:02X} ", self.cpu.borrow().read_reg8(Reg8::E)       , "    "      ),
            reg_str!(regs, OD_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::D_ALT)   , "    "      ),
            reg_str!(regs, OE_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::E_ALT)   , "    "      ),
            format!("{:02X}", self.cpu.borrow().read_reg8(Reg8::R)),
            format!("{}", if self.cpu.borrow().get_iff2() {1} else {0}),
            reg_str!(regs, OH    , " {:02X} ", self.cpu.borrow().read_reg8(Reg8::H)       , "    "      ),
            reg_str!(regs, OL    , " {:02X} ", self.cpu.borrow().read_reg8(Reg8::L)       , "    "      ),
            reg_str!(regs, OH_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::H_ALT)   , "    "      ),
            reg_str!(regs, OL_ALT, " {:02X} ", self.cpu.borrow().read_reg8(Reg8::L_ALT)   , "    "      ),
            reg_str!(regs, OIX   , " {:04X} ", self.cpu.borrow().read_reg16(Reg16::IX)    , "      "    ),
            format!("{}", self.memory.borrow().get_0000_bank()),
            reg_str!(regs, OIY   , " {:04X} ", self.cpu.borrow().read_reg16(Reg16::IY)    , "      "    ),
            reg_str!(regs, OF    , " {:08b} ", self.cpu.borrow().get_flags().bits()       , "          "),
            format!("{}", self.memory.borrow().get_4000_bank()),
            reg_str!(regs, OSP   , " {:04X} ", self.cpu.borrow().read_reg16(Reg16::SP)    , "      "    ),
            format!("{}", self.memory.borrow().get_8000_bank()),
            format!(" {:04X} ", self.cpu.borrow().get_pc()),
            format!("{}", self.memory.borrow().get_c000_bank()))
    }

    fn peek_at_next_instruction(&self) -> &Instruction {
        let curr_pc = self.cpu.borrow().get_pc();

        let i0 = self.memory.borrow().read_word(curr_pc);
        let i1 = self.memory.borrow().read_word(curr_pc + 1);
        let i3 = self.memory.borrow().read_word(curr_pc + 3);

        match (i0, i1) {
            (0xDD, 0xCB) => INSTR_TABLE_DDCB[i3 as usize],
            (0xDD, _   ) => INSTR_TABLE_DD[i1 as usize],
            (0xFD, 0xCB) => INSTR_TABLE_FDCB[i3 as usize],
            (0xFD, _   ) => INSTR_TABLE_FD[i1 as usize],
            (0xCB, _   ) => INSTR_TABLE_CB[i1 as usize],
            (0xED, _   ) => INSTR_TABLE_ED[i1 as usize],
            (_   , _   ) => INSTR_TABLE[i0 as usize],
        }
    }

    pub fn run(&mut self) {
        loop {
            print!("z80> ");
            stdout().flush().unwrap();

            let mut input = String::new();
            stdin().read_line(&mut input).unwrap();
            let input: String = input.trim().into();

            match input.parse() {
                Ok(Command::Exit) => break,

                Ok(Command::Cont) => {
                    loop {
                        let (pre_regs, post_regs, instr_str) = {
                            let next_instr = self.peek_at_next_instruction();
                            let accessed_regs = next_instr.get_accessed_regs();
                            (accessed_regs.0,
                             accessed_regs.1,
                             next_instr.get_string(&self.cpu.borrow(), &self.memory.borrow()))
                        };
                        println!("{}", self.output(pre_regs));
                        println!("{}", instr_str);
                        self.cpu.borrow_mut().handle_interrupts();
                        self.cpu.borrow_mut().run_instruction();
                        println!("{}", self.output(post_regs));
                    }
                }

                Ok(Command::Step(count)) if count > 0 => {
                    for _ in 0..count {
                        let (pre_regs, post_regs, instr_str) = {
                            let next_instr = self.peek_at_next_instruction();
                            let accessed_regs = next_instr.get_accessed_regs();
                            (accessed_regs.0,
                             accessed_regs.1,
                             next_instr.get_string(&self.cpu.borrow(), &self.memory.borrow()))
                        };
                        println!("{}", self.output(pre_regs));
                        println!("{}", instr_str);
                        self.cpu.borrow_mut().handle_interrupts();
                        self.cpu.borrow_mut().run_instruction();
                        println!("{}", self.output(post_regs));
                    }
                }

                Ok(Command::MemRng(addrstart, addrend)) => {
                    let realaddrstart =
                        if addrstart % 16 == 0 {
                            addrstart
                        } else {
                            addrstart - (addrstart % 16)
                        };
                    let realaddrend =
                        if addrend % 16 == 0 {
                            addrend
                        } else {
                            addrend + (16 - (addrend % 16))
                        };
                    for addr in realaddrstart..realaddrend {
                        if addr % 16 == 0 {
                            println!();
                            print!("{:#06X}: ", addr);
                        }
                        print!("{:02X} ", self.memory.borrow().read_word(addr));
                    }
                    println!();
                }

                Ok(Command::Mem(addr)) => println!("{:#04X}", self.memory.borrow().read_word(addr)),

                _ => println!("Unknown command"),
            };
        }
    }
}
<|endoftext|>


<commit_before>use base64;
use std::borrow::Cow;
use std::io::Write;
use xml_rs::name::Name;
use xml_rs::namespace::Namespace;
use xml_rs::writer::{EmitterConfig, Error as XmlWriterError, EventWriter, XmlEvent};

use events::{Event, Writer};
use Error;

impl From<XmlWriterError> for Error {
    fn from(err: XmlWriterError) -> Error {
        match err {
            XmlWriterError::Io(err) => Error::Io(err),
            _ => Error::InvalidData,
        }
    }
}

enum Element {
    Dictionary(DictionaryState),
    Array,
    Root,
}

enum DictionaryState {
    ExpectKey,
    ExpectValue,
}

pub struct XmlWriter<W: Write> {
    xml_writer: EventWriter<W>,
    stack: Vec<Element>,
    // Not very nice
    empty_namespace: Namespace,
}

impl<W: Write> XmlWriter<W> {
    pub fn new(writer: W) -> XmlWriter<W> {
        let config = EmitterConfig::new()
            .line_separator("\n")
            .indent_string("\t")
            .perform_indent(true)
            .write_document_declaration(false)
            .normalize_empty_elements(true)
            .cdata_to_characters(true)
            .keep_element_names_stack(false)
            .autopad_comments(true);

        XmlWriter {
            xml_writer: EventWriter::new_with_config(writer, config),
            stack: Vec::new(),
            empty_namespace: Namespace::empty(),
        }
    }

    fn write_element_and_value(&mut self, name: &str, value: &str) -> Result<(), Error> {
        self.start_element(name)?;
        self.write_value(value)?;
        self.end_element(name)?;
        Ok(())
    }

    fn start_element(&mut self, name: &str) -> Result<(), Error> {
        self.xml_writer.write(XmlEvent::StartElement {
            name: Name::local(name),
            attributes: Cow::Borrowed(&[]),
            namespace: Cow::Borrowed(&self.empty_namespace),
        })?;
        Ok(())
    }

    fn end_element(&mut self, name: &str) -> Result<(), Error> {
        self.xml_writer.write(XmlEvent::EndElement {
            name: Some(Name::local(name)),
        })?;
        Ok(())
    }

    fn write_value(&mut self, value: &str) -> Result<(), Error> {
        self.xml_writer.write(XmlEvent::Characters(value))?;
        Ok(())
    }

    fn maybe_end_plist(&mut self) -> Result<(), Error> {
        // If there are no more open tags then write the </plist> element
        if self.stack.len() == 1 {
            // We didn't tell the xml_writer about the <plist> tag so we'll skip telling it
            // about the </plist> tag as well.
            self.xml_writer.inner_mut().write(b"\n</plist>")?;
            if let Some(Element::Root) = self.stack.pop() {
            } else {
                return Err(Error::InvalidData);
            }
        }
        Ok(())
    }

    pub fn write(&mut self, event: &Event) -> Result<(), Error> {
        <Self as Writer>::write(self, event)
    }
}

impl<W: Write> Writer for XmlWriter<W> {
    fn write(&mut self, event: &Event) -> Result<(), Error> {
        match self.stack.pop() {
            Some(Element::Dictionary(DictionaryState::ExpectKey)) => {
                match *event {
                    Event::StringValue(ref value) => {
                        self.write_element_and_value("key", &*value)?;
                        self.stack
                            .push(Element::Dictionary(DictionaryState::ExpectValue));
                    }
                    Event::EndDictionary => {
                        self.end_element("dict")?;
                        // We might be closing the last tag here as well
                        self.maybe_end_plist()?;
                    }
                    _ => return Err(Error::InvalidData),
                };
                return Ok(());
            }
            Some(Element::Dictionary(DictionaryState::ExpectValue)) => self
                .stack
                .push(Element::Dictionary(DictionaryState::ExpectKey)),
            Some(other) => self.stack.push(other),
            None => {
                // Write prologue
                let prologue = r#"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
"#;
                self.xml_writer.inner_mut().write(prologue.as_bytes())?;

                self.stack.push(Element::Root);
            }
        }

        match *event {
            Event::StartArray(_) => {
                self.start_element("array")?;
                self.stack.push(Element::Array);
            }
            Event::EndArray => {
                self.end_element("array")?;
                if let Some(Element::Array) = self.stack.pop() {
                } else {
                    return Err(Error::InvalidData);
                }
            }

            Event::StartDictionary(_) => {
                self.start_element("dict")?;
                self.stack
                    .push(Element::Dictionary(DictionaryState::ExpectKey));
            }
            Event::EndDictionary => return Err(Error::InvalidData),

            Event::BooleanValue(true) => {
                self.start_element("true")?;
                self.end_element("true")?;
            }
            Event::BooleanValue(false) => {
                self.start_element("false")?;
                self.end_element("false")?;
            }
            Event::DataValue(ref value) => {
                let base64_data = base64::encode_config(&value, base64::MIME);
                self.write_element_and_value("data", &base64_data)?;
            }
            Event::DateValue(ref value) => {
                self.write_element_and_value("date", &value.to_rfc3339())?
            }
            Event::IntegerValue(ref value) => {
                self.write_element_and_value("integer", &value.to_string())?
            }
            Event::RealValue(ref value) => {
                self.write_element_and_value("real", &value.to_string())?
            }
            Event::StringValue(ref value) => self.write_element_and_value("string", &*value)?,
        };

        self.maybe_end_plist()?;

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use humantime::parse_rfc3339_weak;
    use std::io::Cursor;

    use super::*;
    use events::Event::*;

    #[test]
    fn streaming_parser() {
        let plist = &[
            StartDictionary(None),
            StringValue("Author".to_owned()),
            StringValue("William Shakespeare".to_owned()),
            StringValue("Lines".to_owned()),
            StartArray(None),
            StringValue("It is a tale told by an idiot,".to_owned()),
            StringValue("Full of sound and fury, signifying nothing.".to_owned()),
            EndArray,
            StringValue("Death".to_owned()),
            IntegerValue(1564),
            StringValue("Height".to_owned()),
            RealValue(1.60),
            StringValue("Data".to_owned()),
            DataValue(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]),
            StringValue("Birthdate".to_owned()),
            DateValue(parse_rfc3339_weak("1981-05-16 11:32:06").unwrap().into()),
            StringValue("Comment".to_owned()),
            StringValue("2 < 3".to_owned()), // make sure characters are escaped
            EndDictionary,
        ];

        let mut cursor = Cursor::new(Vec::new());

        {
            let mut plist_w = XmlWriter::new(&mut cursor);

            for item in plist {
                plist_w.write(item).unwrap();
            }
        }

        let comparison = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<dict>
\t<key>Author</key>
\t<string>William Shakespeare</string>
\t<key>Lines</key>
\t<array>
\t\t<string>It is a tale told by an idiot,</string>
\t\t<string>Full of sound and fury, signifying nothing.</string>
\t</array>
\t<key>Death</key>
\t<integer>1564</integer>
\t<key>Height</key>
\t<real>1.6</real>
\t<key>Data</key>
\t<data>AAAAvgAAAAMAAAAeAAAA</data>
\t<key>Birthdate</key>
\t<date>1981-05-16T11:32:06Z</date>
\t<key>Comment</key>
\t<string>2 < 3</string>
</dict>
</plist>";

        let s = String::from_utf8(cursor.into_inner()).unwrap();

        assert_eq!(s, comparison);
    }
}
<commit_msg>Use `write_all` instead of `write` to output xml prologue and trailer.<commit_after>use base64;
use std::borrow::Cow;
use std::io::Write;
use xml_rs::name::Name;
use xml_rs::namespace::Namespace;
use xml_rs::writer::{EmitterConfig, Error as XmlWriterError, EventWriter, XmlEvent};

use events::{Event, Writer};
use Error;

impl From<XmlWriterError> for Error {
    fn from(err: XmlWriterError) -> Error {
        match err {
            XmlWriterError::Io(err) => Error::Io(err),
            _ => Error::InvalidData,
        }
    }
}

enum Element {
    Dictionary(DictionaryState),
    Array,
    Root,
}

enum DictionaryState {
    ExpectKey,
    ExpectValue,
}

pub struct XmlWriter<W: Write> {
    xml_writer: EventWriter<W>,
    stack: Vec<Element>,
    // Not very nice
    empty_namespace: Namespace,
}

impl<W: Write> XmlWriter<W> {
    pub fn new(writer: W) -> XmlWriter<W> {
        let config = EmitterConfig::new()
            .line_separator("\n")
            .indent_string("\t")
            .perform_indent(true)
            .write_document_declaration(false)
            .normalize_empty_elements(true)
            .cdata_to_characters(true)
            .keep_element_names_stack(false)
            .autopad_comments(true);

        XmlWriter {
            xml_writer: EventWriter::new_with_config(writer, config),
            stack: Vec::new(),
            empty_namespace: Namespace::empty(),
        }
    }

    fn write_element_and_value(&mut self, name: &str, value: &str) -> Result<(), Error> {
        self.start_element(name)?;
        self.write_value(value)?;
        self.end_element(name)?;
        Ok(())
    }

    fn start_element(&mut self, name: &str) -> Result<(), Error> {
        self.xml_writer.write(XmlEvent::StartElement {
            name: Name::local(name),
            attributes: Cow::Borrowed(&[]),
            namespace: Cow::Borrowed(&self.empty_namespace),
        })?;
        Ok(())
    }

    fn end_element(&mut self, name: &str) -> Result<(), Error> {
        self.xml_writer.write(XmlEvent::EndElement {
            name: Some(Name::local(name)),
        })?;
        Ok(())
    }

    fn write_value(&mut self, value: &str) -> Result<(), Error> {
        self.xml_writer.write(XmlEvent::Characters(value))?;
        Ok(())
    }

    fn maybe_end_plist(&mut self) -> Result<(), Error> {
        // If there are no more open tags then write the </plist> element
        if self.stack.len() == 1 {
            // We didn't tell the xml_writer about the <plist> tag so we'll skip telling it
            // about the </plist> tag as well.
            self.xml_writer.inner_mut().write_all(b"\n</plist>")?;
            if let Some(Element::Root) = self.stack.pop() {
            } else {
                return Err(Error::InvalidData);
            }
        }
        Ok(())
    }

    pub fn write(&mut self, event: &Event) -> Result<(), Error> {
        <Self as Writer>::write(self, event)
    }
}

impl<W: Write> Writer for XmlWriter<W> {
    fn write(&mut self, event: &Event) -> Result<(), Error> {
        match self.stack.pop() {
            Some(Element::Dictionary(DictionaryState::ExpectKey)) => {
                match *event {
                    Event::StringValue(ref value) => {
                        self.write_element_and_value("key", &*value)?;
                        self.stack
                            .push(Element::Dictionary(DictionaryState::ExpectValue));
                    }
                    Event::EndDictionary => {
                        self.end_element("dict")?;
                        // We might be closing the last tag here as well
                        self.maybe_end_plist()?;
                    }
                    _ => return Err(Error::InvalidData),
                };
                return Ok(());
            }
            Some(Element::Dictionary(DictionaryState::ExpectValue)) => self
                .stack
                .push(Element::Dictionary(DictionaryState::ExpectKey)),
            Some(other) => self.stack.push(other),
            None => {
                // Write prologue
                let prologue = r#"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
"#;
                self.xml_writer.inner_mut().write_all(prologue.as_bytes())?;

                self.stack.push(Element::Root);
            }
        }

        match *event {
            Event::StartArray(_) => {
                self.start_element("array")?;
                self.stack.push(Element::Array);
            }
            Event::EndArray => {
                self.end_element("array")?;
                if let Some(Element::Array) = self.stack.pop() {
                } else {
                    return Err(Error::InvalidData);
                }
            }

            Event::StartDictionary(_) => {
                self.start_element("dict")?;
                self.stack
                    .push(Element::Dictionary(DictionaryState::ExpectKey));
            }
            Event::EndDictionary => return Err(Error::InvalidData),

            Event::BooleanValue(true) => {
                self.start_element("true")?;
                self.end_element("true")?;
            }
            Event::BooleanValue(false) => {
                self.start_element("false")?;
                self.end_element("false")?;
            }
            Event::DataValue(ref value) => {
                let base64_data = base64::encode_config(&value, base64::MIME);
                self.write_element_and_value("data", &base64_data)?;
            }
            Event::DateValue(ref value) => {
                self.write_element_and_value("date", &value.to_rfc3339())?
            }
            Event::IntegerValue(ref value) => {
                self.write_element_and_value("integer", &value.to_string())?
            }
            Event::RealValue(ref value) => {
                self.write_element_and_value("real", &value.to_string())?
            }
            Event::StringValue(ref value) => self.write_element_and_value("string", &*value)?,
        };

        self.maybe_end_plist()?;

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use humantime::parse_rfc3339_weak;
    use std::io::Cursor;

    use super::*;
    use events::Event::*;

    #[test]
    fn streaming_parser() {
        let plist = &[
            StartDictionary(None),
            StringValue("Author".to_owned()),
            StringValue("William Shakespeare".to_owned()),
            StringValue("Lines".to_owned()),
            StartArray(None),
            StringValue("It is a tale told by an idiot,".to_owned()),
            StringValue("Full of sound and fury, signifying nothing.".to_owned()),
            EndArray,
            StringValue("Death".to_owned()),
            IntegerValue(1564),
            StringValue("Height".to_owned()),
            RealValue(1.60),
            StringValue("Data".to_owned()),
            DataValue(vec![0, 0, 0, 190, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0]),
            StringValue("Birthdate".to_owned()),
            DateValue(parse_rfc3339_weak("1981-05-16 11:32:06").unwrap().into()),
            StringValue("Comment".to_owned()),
            StringValue("2 < 3".to_owned()), // make sure characters are escaped
            EndDictionary,
        ];

        let mut cursor = Cursor::new(Vec::new());

        {
            let mut plist_w = XmlWriter::new(&mut cursor);

            for item in plist {
                plist_w.write(item).unwrap();
            }
        }

        let comparison = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<dict>
\t<key>Author</key>
\t<string>William Shakespeare</string>
\t<key>Lines</key>
\t<array>
\t\t<string>It is a tale told by an idiot,</string>
\t\t<string>Full of sound and fury, signifying nothing.</string>
\t</array>
\t<key>Death</key>
\t<integer>1564</integer>
\t<key>Height</key>
\t<real>1.6</real>
\t<key>Data</key>
\t<data>AAAAvgAAAAMAAAAeAAAA</data>
\t<key>Birthdate</key>
\t<date>1981-05-16T11:32:06Z</date>
\t<key>Comment</key>
\t<string>2 < 3</string>
</dict>
</plist>";

        let s = String::from_utf8(cursor.into_inner()).unwrap();

        assert_eq!(s, comparison);
    }
}
<|endoftext|>


<commit_before>// Based on the original C++ farmhashcc.cc

// This file provides a 32-bit hash equivalent to CityHash32 (v1.1.1)
// and a 128-bit hash equivalent to CityHash128 (v1.1.1).  It also provides
// a seeded 32-bit hash function similar to CityHash32.

use platform::*;
use std::mem;

fn hash32_len_13_to_24(s: &[u8]) -> u32 {
    let len = s.len() as usize;
    let a = fetch32(&s[-4+(len>>1 as u64)..]);
    let b = fetch32(&s[4..]);
    let c = fetch32(&s[len-8..]);
    let d = fetch32(&s[len>>1..]);
    let e = fetch32(&s[0..]);
    let f = fetch32(&s[len-4..]);
    let h = len as u32;
    return fmix(mur(f, mur(e, mur(d, mur(c, mur(b, mur(a, h)))))));
}

fn hash32_len_0_to_4(s: &[u8]) -> u32 {
    let len = s.len() as usize;
    let mut b: u32 = 0;
    let mut c: u32 = 9;
    for i in 0..len {
        let v: u8 = s[i];
        b = b.wrapping_mul(C1) + v as u32;
        c ^= b;
    }
    return fmix(mur(b, mur(len as u32, c)));
}

fn hash32_len_5_to_12(s: &[u8]) -> u32 {
    let len = s.len() as usize;
    let mut a = len as u32;
    let mut b = len as u32 * 5;
    let mut c: u32 = 9;
    let d: u32 = b;

    a += fetch32(&s[0..]);
    b += fetch32(&s[len-4..]);
    c += fetch32(&s[((len >> 1) & 4)..]);
    return fmix(mur(c, mur(b, mur(a, d))));
}

pub fn hash32(mut s: &[u8]) -> u32 {
    let len = s.len() as usize;
    if len <= 24 {
        if len <= 12 {
            if len <= 4 {
                return hash32_len_0_to_4(s)
            }
            return hash32_len_5_to_12(s)
        }
        return hash32_len_13_to_24(s)
    }

    // len > 24
    let mut h = len as u32;
    let mut g = (len as u32).wrapping_mul(C1);
    let mut f = g;
    let a0 = rotate32(fetch32(&s[(len-4)..]).wrapping_mul(C1), 17) * C2;
    let a1 = rotate32(fetch32(&s[(len-8)..]).wrapping_mul(C1), 17) * C2;
    let a2 = rotate32(fetch32(&s[(len-16)..]).wrapping_mul(C1), 17) * C2;
    let a3 = rotate32(fetch32(&s[(len-12)..]).wrapping_mul(C1), 17) * C2;
    let a4 = rotate32(fetch32(&s[(len-20)..]).wrapping_mul(C1), 17) * C2;
    h ^= a0;
    h = rotate32(h, 19);
    h = (h*5).wrapping_add(0xe6546b64);
    h ^= a2;
    h = rotate32(h, 19);
    h = (h*5).wrapping_add(0xe6546b64);
    g ^= a1;
    g = rotate32(g, 19);
    g = (g*5).wrapping_add(0xe6546b64);
    g ^= a3;
    g = rotate32(g, 19);
    g = (g*5).wrapping_add(0xe6546b64);
    f += a4;
    f = rotate32(f, 19);
    f = (f*5).wrapping_add(0xe6546b64);

    let mut iters = ((len - 1) / 20) as u64;
    while iters > 0{
        let a0 = rotate32(fetch32(&s[..]).wrapping_mul(C1), 17).wrapping_mul(C2);
        let a1 = fetch32(&s[4..]);
        let a2 = rotate32(fetch32(&s[8..]).wrapping_mul(C1), 17).wrapping_mul(C2);
        let a3 = rotate32(fetch32(&s[12..]).wrapping_mul(C1), 17).wrapping_mul(C2);
        let a4 = fetch32(&s[16..]);
        h ^= a0;
        h = rotate32(h, 18);
        h = (h*5).wrapping_add(0xe6546b64);
        f += a1;
        f = rotate32(f, 19);
        f = f.wrapping_mul(C1);
        g += a2;
        g = rotate32(g, 18);
        g = (g*5).wrapping_add(0xe6546b64);
        h ^= a3 + a1;
        h = rotate32(h, 19);
        h = (h*5).wrapping_add(0xe6546b64);
        g ^= a4;
        g = bswap32(g) * 5;
        h += a4 * 5;
        h = bswap32(h);
        f += a0;
        //PERMUTE3(f, h, g) - swap(a,b);swap(b,c)
        mem::swap(&mut h, &mut f);

        mem::swap(&mut g, &mut f);
        s = &s[20..];
        iters-=1;
    }
    g = rotate32(g, 11).wrapping_mul(C1);
    g = rotate32(g, 17).wrapping_mul(C1);
    f = rotate32(f, 11).wrapping_mul(C1);
    f = rotate32(f, 17).wrapping_mul(C1);
    h = rotate32(h+g, 19);
    h = h*5 + 0xe6546b64;
    h = rotate32(h, 17).wrapping_mul(C1);
    h = rotate32(h+f, 19);
    h = h*5 + 0xe6546b64;
    h = rotate32(h, 17).wrapping_mul(C1);
    return h
}

// Return a 16-byte hash for 48 bytes.  Quick and dirty.
// Callers do best to use "random-looking" values for a and b.
// Note: C++ returned pair<uint64_t, uint64_t>
pub fn weak_hash_len_32_with_seeds(w: u64, x: u64, y:u64, z:u64, mut a:u64, mut b:u64) -> Uint128 {
    a = a.wrapping_add(w);
    b = rotate64(b.wrapping_add(a).wrapping_add(z), 21);
    let c = a;
    a = a.wrapping_add(x);
    a = a.wrapping_add(y);
    b = b.wrapping_add(rotate64(a, 44));
    return Uint128{first: a.wrapping_add(z), second:b.wrapping_add(c)};
}

// Return a 16-byte hash for s[0] ... s[31], a, and b.  Quick and dirty.
// Note: original C++ returned a pair<uint64_t, uint64_t>
pub fn weak_hash_len_32_with_seeds_bytes(s: &[u8], a:u64, b:u64) -> Uint128 {
    return weak_hash_len_32_with_seeds(fetch64(&s[0..8]),
        fetch64(&s[8..16]),
        fetch64(&s[16..24]),
        fetch64(&s[24..32]),
        a,
        b);
}
<commit_msg>Fix warning in hash32_len_13_to_24<commit_after>// Based on the original C++ farmhashcc.cc

// This file provides a 32-bit hash equivalent to CityHash32 (v1.1.1)
// and a 128-bit hash equivalent to CityHash128 (v1.1.1).  It also provides
// a seeded 32-bit hash function similar to CityHash32.

use platform::*;
use std::mem;

fn hash32_len_13_to_24(s: &[u8]) -> u32 {
    let len = s.len() as usize;
    let a = fetch32(&s[(len>>1 as u64) - 4..]);
    let b = fetch32(&s[4..]);
    let c = fetch32(&s[len-8..]);
    let d = fetch32(&s[len>>1..]);
    let e = fetch32(&s[0..]);
    let f = fetch32(&s[len-4..]);
    let h = len as u32;
    return fmix(mur(f, mur(e, mur(d, mur(c, mur(b, mur(a, h)))))));
}

fn hash32_len_0_to_4(s: &[u8]) -> u32 {
    let len = s.len() as usize;
    let mut b: u32 = 0;
    let mut c: u32 = 9;
    for i in 0..len {
        let v: u8 = s[i];
        b = b.wrapping_mul(C1) + v as u32;
        c ^= b;
    }
    return fmix(mur(b, mur(len as u32, c)));
}

fn hash32_len_5_to_12(s: &[u8]) -> u32 {
    let len = s.len() as usize;
    let mut a = len as u32;
    let mut b = len as u32 * 5;
    let mut c: u32 = 9;
    let d: u32 = b;

    a += fetch32(&s[0..]);
    b += fetch32(&s[len-4..]);
    c += fetch32(&s[((len >> 1) & 4)..]);
    return fmix(mur(c, mur(b, mur(a, d))));
}

pub fn hash32(mut s: &[u8]) -> u32 {
    let len = s.len() as usize;
    if len <= 24 {
        if len <= 12 {
            if len <= 4 {
                return hash32_len_0_to_4(s)
            }
            return hash32_len_5_to_12(s)
        }
        return hash32_len_13_to_24(s)
    }

    // len > 24
    let mut h = len as u32;
    let mut g = (len as u32).wrapping_mul(C1);
    let mut f = g;
    let a0 = rotate32(fetch32(&s[(len-4)..]).wrapping_mul(C1), 17) * C2;
    let a1 = rotate32(fetch32(&s[(len-8)..]).wrapping_mul(C1), 17) * C2;
    let a2 = rotate32(fetch32(&s[(len-16)..]).wrapping_mul(C1), 17) * C2;
    let a3 = rotate32(fetch32(&s[(len-12)..]).wrapping_mul(C1), 17) * C2;
    let a4 = rotate32(fetch32(&s[(len-20)..]).wrapping_mul(C1), 17) * C2;
    h ^= a0;
    h = rotate32(h, 19);
    h = (h*5).wrapping_add(0xe6546b64);
    h ^= a2;
    h = rotate32(h, 19);
    h = (h*5).wrapping_add(0xe6546b64);
    g ^= a1;
    g = rotate32(g, 19);
    g = (g*5).wrapping_add(0xe6546b64);
    g ^= a3;
    g = rotate32(g, 19);
    g = (g*5).wrapping_add(0xe6546b64);
    f += a4;
    f = rotate32(f, 19);
    f = (f*5).wrapping_add(0xe6546b64);

    let mut iters = ((len - 1) / 20) as u64;
    while iters > 0{
        let a0 = rotate32(fetch32(&s[..]).wrapping_mul(C1), 17).wrapping_mul(C2);
        let a1 = fetch32(&s[4..]);
        let a2 = rotate32(fetch32(&s[8..]).wrapping_mul(C1), 17).wrapping_mul(C2);
        let a3 = rotate32(fetch32(&s[12..]).wrapping_mul(C1), 17).wrapping_mul(C2);
        let a4 = fetch32(&s[16..]);
        h ^= a0;
        h = rotate32(h, 18);
        h = (h*5).wrapping_add(0xe6546b64);
        f += a1;
        f = rotate32(f, 19);
        f = f.wrapping_mul(C1);
        g += a2;
        g = rotate32(g, 18);
        g = (g*5).wrapping_add(0xe6546b64);
        h ^= a3 + a1;
        h = rotate32(h, 19);
        h = (h*5).wrapping_add(0xe6546b64);
        g ^= a4;
        g = bswap32(g) * 5;
        h += a4 * 5;
        h = bswap32(h);
        f += a0;
        //PERMUTE3(f, h, g) - swap(a,b);swap(b,c)
        mem::swap(&mut h, &mut f);

        mem::swap(&mut g, &mut f);
        s = &s[20..];
        iters-=1;
    }
    g = rotate32(g, 11).wrapping_mul(C1);
    g = rotate32(g, 17).wrapping_mul(C1);
    f = rotate32(f, 11).wrapping_mul(C1);
    f = rotate32(f, 17).wrapping_mul(C1);
    h = rotate32(h+g, 19);
    h = h*5 + 0xe6546b64;
    h = rotate32(h, 17).wrapping_mul(C1);
    h = rotate32(h+f, 19);
    h = h*5 + 0xe6546b64;
    h = rotate32(h, 17).wrapping_mul(C1);
    return h
}

// Return a 16-byte hash for 48 bytes.  Quick and dirty.
// Callers do best to use "random-looking" values for a and b.
// Note: C++ returned pair<uint64_t, uint64_t>
pub fn weak_hash_len_32_with_seeds(w: u64, x: u64, y:u64, z:u64, mut a:u64, mut b:u64) -> Uint128 {
    a = a.wrapping_add(w);
    b = rotate64(b.wrapping_add(a).wrapping_add(z), 21);
    let c = a;
    a = a.wrapping_add(x);
    a = a.wrapping_add(y);
    b = b.wrapping_add(rotate64(a, 44));
    return Uint128{first: a.wrapping_add(z), second:b.wrapping_add(c)};
}

// Return a 16-byte hash for s[0] ... s[31], a, and b.  Quick and dirty.
// Note: original C++ returned a pair<uint64_t, uint64_t>
pub fn weak_hash_len_32_with_seeds_bytes(s: &[u8], a:u64, b:u64) -> Uint128 {
    return weak_hash_len_32_with_seeds(fetch64(&s[0..8]),
        fetch64(&s[8..16]),
        fetch64(&s[16..24]),
        fetch64(&s[24..32]),
        a,
        b);
}
<|endoftext|>


<commit_before>//! Incremental BLOB I/O.
//!
//! Note that SQLite does not provide API-level access to change the size of a
//! BLOB; that must be performed through SQL statements.
//!
//! `Blob` conforms to `std::io::Read`, `std::io::Write`, and `std::io::Seek`,
//! so it plays nicely with other types that build on these (such as
//! `std::io::BufReader` and `std::io::BufWriter`). However, you must be
//! careful with the size of the blob. For example, when using a `BufWriter`,
//! the `BufWriter` will accept more data than the `Blob`
//! will allow, so make sure to call `flush` and check for errors. (See the
//! unit tests in this module for an example.)
//!
//! ## Example
//!
//! ```rust
//! use rusqlite::blob::ZeroBlob;
//! use rusqlite::{Connection, DatabaseName, Result, NO_PARAMS};
//! use std::io::{Read, Seek, SeekFrom, Write};
//!
//! fn main() -> Result<()> {
//!     let db = Connection::open_in_memory()?;
//!     db.execute_batch("CREATE TABLE test (content BLOB);")?;
//!     db.execute(
//!         "INSERT INTO test (content) VALUES (ZEROBLOB(10))",
//!         NO_PARAMS,
//!     )?;
//!
//!     let rowid = db.last_insert_rowid();
//!     let mut blob = db
//!         .blob_open(DatabaseName::Main, "test", "content", rowid, false)?;
//!
//!     // Make sure to test that the number of bytes written matches what you expect;
//!     // if you try to write too much, the data will be truncated to the size of the
//!     // BLOB.
//!     let bytes_written = blob.write(b"01234567")?;
//!     assert_eq!(bytes_written, 8);
//!
//!     // Same guidance - make sure you check the number of bytes read!
//!     blob.seek(SeekFrom::Start(0))?;
//!     let mut buf = [0u8; 20];
//!     let bytes_read = blob.read(&mut buf[..])?;
//!     assert_eq!(bytes_read, 10); // note we read 10 bytes because the blob has size 10
//!
//!     db.execute("INSERT INTO test (content) VALUES (?)", &[ZeroBlob(64)])?;
//!
//!     // given a new row ID, we can reopen the blob on that row
//!     let rowid = db.last_insert_rowid();
//!     blob.reopen(rowid)?;
//!
//!     assert_eq!(blob.size(), 64);
//!     Ok(())
//! }
//! ```
use std::cmp::min;
use std::io;
use std::ptr;

use super::ffi;
use super::types::{ToSql, ToSqlOutput};
use crate::{Connection, DatabaseName, Result};

/// Handle to an open BLOB.
pub struct Blob<'conn> {
    conn: &'conn Connection,
    blob: *mut ffi::sqlite3_blob,
    pos: i32,
}

impl Connection {
    /// Open a handle to the BLOB located in `row_id`, `column`, `table` in
    /// database `db`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `db`/`table`/`column` cannot be converted to a
    /// C-compatible string or if the underlying SQLite BLOB open call
    /// fails.
    pub fn blob_open<'a>(
        &'a self,
        db: DatabaseName<'_>,
        table: &str,
        column: &str,
        row_id: i64,
        read_only: bool,
    ) -> Result<Blob<'a>> {
        let mut c = self.db.borrow_mut();
        let mut blob = ptr::null_mut();
        let db = db.to_cstring()?;
        let table = super::str_to_cstring(table)?;
        let column = super::str_to_cstring(column)?;
        let rc = unsafe {
            ffi::sqlite3_blob_open(
                c.db(),
                db.as_ptr(),
                table.as_ptr(),
                column.as_ptr(),
                row_id,
                if read_only { 0 } else { 1 },
                &mut blob,
            )
        };
        c.decode_result(rc).map(|_| Blob {
            conn: self,
            blob,
            pos: 0,
        })
    }
}

impl Blob<'_> {
    /// Move a BLOB handle to a new row.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite BLOB reopen call fails.
    pub fn reopen(&mut self, row: i64) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_reopen(self.blob, row) };
        if rc != ffi::SQLITE_OK {
            return self.conn.decode_result(rc);
        }
        self.pos = 0;
        Ok(())
    }

    /// Return the size in bytes of the BLOB.
    pub fn size(&self) -> i32 {
        unsafe { ffi::sqlite3_blob_bytes(self.blob) }
    }

    /// Close a BLOB handle.
    ///
    /// Calling `close` explicitly is not required (the BLOB will be closed
    /// when the `Blob` is dropped), but it is available so you can get any
    /// errors that occur.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite close call fails.
    pub fn close(mut self) -> Result<()> {
        self.close_()
    }

    fn close_(&mut self) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_close(self.blob) };
        self.blob = ptr::null_mut();
        self.conn.decode_result(rc)
    }
}

impl io::Read for Blob<'_> {
    /// Read data from a BLOB incrementally. Will return Ok(0) if the end of
    /// the blob has been reached.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite read call fails.
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let max_allowed_len = (self.size() - self.pos) as usize;
        let n = min(buf.len(), max_allowed_len) as i32;
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe { ffi::sqlite3_blob_read(self.blob, buf.as_ptr() as *mut _, n, self.pos) };
        self.conn
            .decode_result(rc)
            .map(|_| {
                self.pos += n;
                n as usize
            })
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }
}

impl io::Write for Blob<'_> {
    /// Write data into a BLOB incrementally. Will return `Ok(0)` if the end of
    /// the blob has been reached; consider using `Write::write_all(buf)`
    /// if you want to get an error if the entirety of the buffer cannot be
    /// written.
    ///
    /// This function may only modify the contents of the BLOB; it is not
    /// possible to increase the size of a BLOB using this API.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite write call fails.
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let max_allowed_len = (self.size() - self.pos) as usize;
        let n = min(buf.len(), max_allowed_len) as i32;
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe { ffi::sqlite3_blob_write(self.blob, buf.as_ptr() as *mut _, n, self.pos) };
        self.conn
            .decode_result(rc)
            .map(|_| {
                self.pos += n;
                n as usize
            })
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl io::Seek for Blob<'_> {
    /// Seek to an offset, in bytes, in BLOB.
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        let pos = match pos {
            io::SeekFrom::Start(offset) => offset as i64,
            io::SeekFrom::Current(offset) => i64::from(self.pos) + offset,
            io::SeekFrom::End(offset) => i64::from(self.size()) + offset,
        };

        if pos < 0 {
            Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "invalid seek to negative position",
            ))
        } else if pos > i64::from(self.size()) {
            Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "invalid seek to position past end of blob",
            ))
        } else {
            self.pos = pos as i32;
            Ok(pos as u64)
        }
    }
}

#[allow(unused_must_use)]
impl Drop for Blob<'_> {
    fn drop(&mut self) {
        self.close_();
    }
}

/// BLOB of length N that is filled with zeroes.
///
/// Zeroblobs are intended to serve as placeholders for BLOBs whose content is
/// later written using incremental BLOB I/O routines.
///
/// A negative value for the zeroblob results in a zero-length BLOB.
#[derive(Copy, Clone)]
pub struct ZeroBlob(pub i32);

impl ToSql for ZeroBlob {
    fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
        let ZeroBlob(length) = *self;
        Ok(ToSqlOutput::ZeroBlob(length))
    }
}

#[cfg(test)]
mod test {
    use crate::{Connection, DatabaseName, Result};
    use std::io::{BufRead, BufReader, BufWriter, Read, Seek, SeekFrom, Write};

    fn db_with_test_blob() -> Result<(Connection, i64)> {
        let db = Connection::open_in_memory()?;
        let sql = "BEGIN;
                   CREATE TABLE test (content BLOB);
                   INSERT INTO test VALUES (ZEROBLOB(10));
                   END;";
        db.execute_batch(sql)?;
        let rowid = db.last_insert_rowid();
        Ok((db, rowid))
    }

    #[test]
    fn test_blob() {
        let (db, rowid) = db_with_test_blob().unwrap();

        let mut blob = db
            .blob_open(DatabaseName::Main, "test", "content", rowid, false)
            .unwrap();
        assert_eq!(4, blob.write(b"Clob").unwrap());
        assert_eq!(6, blob.write(b"567890xxxxxx").unwrap()); // cannot write past 10
        assert_eq!(0, blob.write(b"5678").unwrap()); // still cannot write past 10

        blob.reopen(rowid).unwrap();
        blob.close().unwrap();

        blob = db
            .blob_open(DatabaseName::Main, "test", "content", rowid, true)
            .unwrap();
        let mut bytes = [0u8; 5];
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"Clob5");
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"67890");
        assert_eq!(0, blob.read(&mut bytes[..]).unwrap());

        blob.seek(SeekFrom::Start(2)).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"ob567");

        // only first 4 bytes of `bytes` should be read into
        blob.seek(SeekFrom::Current(-1)).unwrap();
        assert_eq!(4, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"78907");

        blob.seek(SeekFrom::End(-6)).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"56789");

        blob.reopen(rowid).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"Clob5");

        // should not be able to seek negative or past end
        assert!(blob.seek(SeekFrom::Current(-20)).is_err());
        assert!(blob.seek(SeekFrom::End(0)).is_ok());
        assert!(blob.seek(SeekFrom::Current(1)).is_err());

        // write_all should detect when we return Ok(0) because there is no space left,
        // and return a write error
        blob.reopen(rowid).unwrap();
        assert!(blob.write_all(b"0123456789x").is_err());
    }

    #[test]
    fn test_blob_in_bufreader() {
        let (db, rowid) = db_with_test_blob().unwrap();

        let mut blob = db
            .blob_open(DatabaseName::Main, "test", "content", rowid, false)
            .unwrap();
        assert_eq!(8, blob.write(b"one\ntwo\n").unwrap());

        blob.reopen(rowid).unwrap();
        let mut reader = BufReader::new(blob);

        let mut line = String::new();
        assert_eq!(4, reader.read_line(&mut line).unwrap());
        assert_eq!("one\n", line);

        line.truncate(0);
        assert_eq!(4, reader.read_line(&mut line).unwrap());
        assert_eq!("two\n", line);

        line.truncate(0);
        assert_eq!(2, reader.read_line(&mut line).unwrap());
        assert_eq!("\0\0", line);
    }

    #[test]
    fn test_blob_in_bufwriter() {
        let (db, rowid) = db_with_test_blob().unwrap();

        {
            let blob = db
                .blob_open(DatabaseName::Main, "test", "content", rowid, false)
                .unwrap();
            let mut writer = BufWriter::new(blob);

            // trying to write too much and then flush should fail
            assert_eq!(8, writer.write(b"01234567").unwrap());
            assert_eq!(8, writer.write(b"01234567").unwrap());
            assert!(writer.flush().is_err());
        }

        {
            // ... but it should've written the first 10 bytes
            let mut blob = db
                .blob_open(DatabaseName::Main, "test", "content", rowid, false)
                .unwrap();
            let mut bytes = [0u8; 10];
            assert_eq!(10, blob.read(&mut bytes[..]).unwrap());
            assert_eq!(b"0123456701", &bytes);
        }

        {
            let blob = db
                .blob_open(DatabaseName::Main, "test", "content", rowid, false)
                .unwrap();
            let mut writer = BufWriter::new(blob);

            // trying to write_all too much should fail
            writer.write_all(b"aaaaaaaaaabbbbb").unwrap();
            assert!(writer.flush().is_err());
        }

        {
            // ... but it should've written the first 10 bytes
            let mut blob = db
                .blob_open(DatabaseName::Main, "test", "content", rowid, false)
                .unwrap();
            let mut bytes = [0u8; 10];
            assert_eq!(10, blob.read(&mut bytes[..]).unwrap());
            assert_eq!(b"aaaaaaaaaa", &bytes);
        }
    }
}
<commit_msg>Fix Blob example<commit_after>//! Incremental BLOB I/O.
//!
//! Note that SQLite does not provide API-level access to change the size of a
//! BLOB; that must be performed through SQL statements.
//!
//! `Blob` conforms to `std::io::Read`, `std::io::Write`, and `std::io::Seek`,
//! so it plays nicely with other types that build on these (such as
//! `std::io::BufReader` and `std::io::BufWriter`). However, you must be
//! careful with the size of the blob. For example, when using a `BufWriter`,
//! the `BufWriter` will accept more data than the `Blob`
//! will allow, so make sure to call `flush` and check for errors. (See the
//! unit tests in this module for an example.)
//!
//! ## Example
//!
//! ```rust
//! use rusqlite::blob::ZeroBlob;
//! use rusqlite::{Connection, DatabaseName, NO_PARAMS};
//! use std::error::Error;
//! use std::io::{Read, Seek, SeekFrom, Write};
//!
//! fn main() -> Result<(), Box<Error>> {
//!     let db = Connection::open_in_memory()?;
//!     db.execute_batch("CREATE TABLE test (content BLOB);")?;
//!     db.execute(
//!         "INSERT INTO test (content) VALUES (ZEROBLOB(10))",
//!         NO_PARAMS,
//!     )?;
//!
//!     let rowid = db.last_insert_rowid();
//!     let mut blob = db
//!         .blob_open(DatabaseName::Main, "test", "content", rowid, false)?;
//!
//!     // Make sure to test that the number of bytes written matches what you expect;
//!     // if you try to write too much, the data will be truncated to the size of the
//!     // BLOB.
//!     let bytes_written = blob.write(b"01234567")?;
//!     assert_eq!(bytes_written, 8);
//!
//!     // Same guidance - make sure you check the number of bytes read!
//!     blob.seek(SeekFrom::Start(0))?;
//!     let mut buf = [0u8; 20];
//!     let bytes_read = blob.read(&mut buf[..])?;
//!     assert_eq!(bytes_read, 10); // note we read 10 bytes because the blob has size 10
//!
//!     db.execute("INSERT INTO test (content) VALUES (?)", &[ZeroBlob(64)])?;
//!
//!     // given a new row ID, we can reopen the blob on that row
//!     let rowid = db.last_insert_rowid();
//!     blob.reopen(rowid)?;
//!
//!     assert_eq!(blob.size(), 64);
//!     Ok(())
//! }
//! ```
use std::cmp::min;
use std::io;
use std::ptr;

use super::ffi;
use super::types::{ToSql, ToSqlOutput};
use crate::{Connection, DatabaseName, Result};

/// Handle to an open BLOB.
pub struct Blob<'conn> {
    conn: &'conn Connection,
    blob: *mut ffi::sqlite3_blob,
    pos: i32,
}

impl Connection {
    /// Open a handle to the BLOB located in `row_id`, `column`, `table` in
    /// database `db`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `db`/`table`/`column` cannot be converted to a
    /// C-compatible string or if the underlying SQLite BLOB open call
    /// fails.
    pub fn blob_open<'a>(
        &'a self,
        db: DatabaseName<'_>,
        table: &str,
        column: &str,
        row_id: i64,
        read_only: bool,
    ) -> Result<Blob<'a>> {
        let mut c = self.db.borrow_mut();
        let mut blob = ptr::null_mut();
        let db = db.to_cstring()?;
        let table = super::str_to_cstring(table)?;
        let column = super::str_to_cstring(column)?;
        let rc = unsafe {
            ffi::sqlite3_blob_open(
                c.db(),
                db.as_ptr(),
                table.as_ptr(),
                column.as_ptr(),
                row_id,
                if read_only { 0 } else { 1 },
                &mut blob,
            )
        };
        c.decode_result(rc).map(|_| Blob {
            conn: self,
            blob,
            pos: 0,
        })
    }
}

impl Blob<'_> {
    /// Move a BLOB handle to a new row.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite BLOB reopen call fails.
    pub fn reopen(&mut self, row: i64) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_reopen(self.blob, row) };
        if rc != ffi::SQLITE_OK {
            return self.conn.decode_result(rc);
        }
        self.pos = 0;
        Ok(())
    }

    /// Return the size in bytes of the BLOB.
    pub fn size(&self) -> i32 {
        unsafe { ffi::sqlite3_blob_bytes(self.blob) }
    }

    /// Close a BLOB handle.
    ///
    /// Calling `close` explicitly is not required (the BLOB will be closed
    /// when the `Blob` is dropped), but it is available so you can get any
    /// errors that occur.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite close call fails.
    pub fn close(mut self) -> Result<()> {
        self.close_()
    }

    fn close_(&mut self) -> Result<()> {
        let rc = unsafe { ffi::sqlite3_blob_close(self.blob) };
        self.blob = ptr::null_mut();
        self.conn.decode_result(rc)
    }
}

impl io::Read for Blob<'_> {
    /// Read data from a BLOB incrementally. Will return Ok(0) if the end of
    /// the blob has been reached.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite read call fails.
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let max_allowed_len = (self.size() - self.pos) as usize;
        let n = min(buf.len(), max_allowed_len) as i32;
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe { ffi::sqlite3_blob_read(self.blob, buf.as_ptr() as *mut _, n, self.pos) };
        self.conn
            .decode_result(rc)
            .map(|_| {
                self.pos += n;
                n as usize
            })
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }
}

impl io::Write for Blob<'_> {
    /// Write data into a BLOB incrementally. Will return `Ok(0)` if the end of
    /// the blob has been reached; consider using `Write::write_all(buf)`
    /// if you want to get an error if the entirety of the buffer cannot be
    /// written.
    ///
    /// This function may only modify the contents of the BLOB; it is not
    /// possible to increase the size of a BLOB using this API.
    ///
    /// # Failure
    ///
    /// Will return `Err` if the underlying SQLite write call fails.
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let max_allowed_len = (self.size() - self.pos) as usize;
        let n = min(buf.len(), max_allowed_len) as i32;
        if n <= 0 {
            return Ok(0);
        }
        let rc = unsafe { ffi::sqlite3_blob_write(self.blob, buf.as_ptr() as *mut _, n, self.pos) };
        self.conn
            .decode_result(rc)
            .map(|_| {
                self.pos += n;
                n as usize
            })
            .map_err(|err| io::Error::new(io::ErrorKind::Other, err))
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl io::Seek for Blob<'_> {
    /// Seek to an offset, in bytes, in BLOB.
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        let pos = match pos {
            io::SeekFrom::Start(offset) => offset as i64,
            io::SeekFrom::Current(offset) => i64::from(self.pos) + offset,
            io::SeekFrom::End(offset) => i64::from(self.size()) + offset,
        };

        if pos < 0 {
            Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "invalid seek to negative position",
            ))
        } else if pos > i64::from(self.size()) {
            Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "invalid seek to position past end of blob",
            ))
        } else {
            self.pos = pos as i32;
            Ok(pos as u64)
        }
    }
}

#[allow(unused_must_use)]
impl Drop for Blob<'_> {
    fn drop(&mut self) {
        self.close_();
    }
}

/// BLOB of length N that is filled with zeroes.
///
/// Zeroblobs are intended to serve as placeholders for BLOBs whose content is
/// later written using incremental BLOB I/O routines.
///
/// A negative value for the zeroblob results in a zero-length BLOB.
#[derive(Copy, Clone)]
pub struct ZeroBlob(pub i32);

impl ToSql for ZeroBlob {
    fn to_sql(&self) -> Result<ToSqlOutput<'_>> {
        let ZeroBlob(length) = *self;
        Ok(ToSqlOutput::ZeroBlob(length))
    }
}

#[cfg(test)]
mod test {
    use crate::{Connection, DatabaseName, Result};
    use std::io::{BufRead, BufReader, BufWriter, Read, Seek, SeekFrom, Write};

    fn db_with_test_blob() -> Result<(Connection, i64)> {
        let db = Connection::open_in_memory()?;
        let sql = "BEGIN;
                   CREATE TABLE test (content BLOB);
                   INSERT INTO test VALUES (ZEROBLOB(10));
                   END;";
        db.execute_batch(sql)?;
        let rowid = db.last_insert_rowid();
        Ok((db, rowid))
    }

    #[test]
    fn test_blob() {
        let (db, rowid) = db_with_test_blob().unwrap();

        let mut blob = db
            .blob_open(DatabaseName::Main, "test", "content", rowid, false)
            .unwrap();
        assert_eq!(4, blob.write(b"Clob").unwrap());
        assert_eq!(6, blob.write(b"567890xxxxxx").unwrap()); // cannot write past 10
        assert_eq!(0, blob.write(b"5678").unwrap()); // still cannot write past 10

        blob.reopen(rowid).unwrap();
        blob.close().unwrap();

        blob = db
            .blob_open(DatabaseName::Main, "test", "content", rowid, true)
            .unwrap();
        let mut bytes = [0u8; 5];
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"Clob5");
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"67890");
        assert_eq!(0, blob.read(&mut bytes[..]).unwrap());

        blob.seek(SeekFrom::Start(2)).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"ob567");

        // only first 4 bytes of `bytes` should be read into
        blob.seek(SeekFrom::Current(-1)).unwrap();
        assert_eq!(4, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"78907");

        blob.seek(SeekFrom::End(-6)).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"56789");

        blob.reopen(rowid).unwrap();
        assert_eq!(5, blob.read(&mut bytes[..]).unwrap());
        assert_eq!(&bytes, b"Clob5");

        // should not be able to seek negative or past end
        assert!(blob.seek(SeekFrom::Current(-20)).is_err());
        assert!(blob.seek(SeekFrom::End(0)).is_ok());
        assert!(blob.seek(SeekFrom::Current(1)).is_err());

        // write_all should detect when we return Ok(0) because there is no space left,
        // and return a write error
        blob.reopen(rowid).unwrap();
        assert!(blob.write_all(b"0123456789x").is_err());
    }

    #[test]
    fn test_blob_in_bufreader() {
        let (db, rowid) = db_with_test_blob().unwrap();

        let mut blob = db
            .blob_open(DatabaseName::Main, "test", "content", rowid, false)
            .unwrap();
        assert_eq!(8, blob.write(b"one\ntwo\n").unwrap());

        blob.reopen(rowid).unwrap();
        let mut reader = BufReader::new(blob);

        let mut line = String::new();
        assert_eq!(4, reader.read_line(&mut line).unwrap());
        assert_eq!("one\n", line);

        line.truncate(0);
        assert_eq!(4, reader.read_line(&mut line).unwrap());
        assert_eq!("two\n", line);

        line.truncate(0);
        assert_eq!(2, reader.read_line(&mut line).unwrap());
        assert_eq!("\0\0", line);
    }

    #[test]
    fn test_blob_in_bufwriter() {
        let (db, rowid) = db_with_test_blob().unwrap();

        {
            let blob = db
                .blob_open(DatabaseName::Main, "test", "content", rowid, false)
                .unwrap();
            let mut writer = BufWriter::new(blob);

            // trying to write too much and then flush should fail
            assert_eq!(8, writer.write(b"01234567").unwrap());
            assert_eq!(8, writer.write(b"01234567").unwrap());
            assert!(writer.flush().is_err());
        }

        {
            // ... but it should've written the first 10 bytes
            let mut blob = db
                .blob_open(DatabaseName::Main, "test", "content", rowid, false)
                .unwrap();
            let mut bytes = [0u8; 10];
            assert_eq!(10, blob.read(&mut bytes[..]).unwrap());
            assert_eq!(b"0123456701", &bytes);
        }

        {
            let blob = db
                .blob_open(DatabaseName::Main, "test", "content", rowid, false)
                .unwrap();
            let mut writer = BufWriter::new(blob);

            // trying to write_all too much should fail
            writer.write_all(b"aaaaaaaaaabbbbb").unwrap();
            assert!(writer.flush().is_err());
        }

        {
            // ... but it should've written the first 10 bytes
            let mut blob = db
                .blob_open(DatabaseName::Main, "test", "content", rowid, false)
                .unwrap();
            let mut bytes = [0u8; 10];
            assert_eq!(10, blob.read(&mut bytes[..]).unwrap());
            assert_eq!(b"aaaaaaaaaa", &bytes);
        }
    }
}
<|endoftext|>


<commit_before>
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(unknown_features)]
#![feature(box_syntax)]

extern crate collections;

use std::collections::HashMap;

pub fn main() {
    let mut buggy_map: HashMap<uint, &uint> = HashMap::new();
    let x = box 1;
    buggy_map.insert(42, &*x);
}
<commit_msg>accommodate new scoping rules in test/run-pass.<commit_after>
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(unknown_features)]
#![feature(box_syntax)]

extern crate collections;

use std::collections::HashMap;

pub fn main() {
    let x;
    let mut buggy_map: HashMap<uint, &uint> = HashMap::new();
    x = box 1;
    buggy_map.insert(42, &*x);
}
<|endoftext|>


<commit_before>use super::{Expression, ExpressionError, Condition};
use asexp::Sexp;
use std::fmt::Debug;

/// A boolean condition evaluates to either `true` or `false`.
#[derive(Debug, Clone, PartialEq)]
pub enum Cond<E: Expression> {
    True,
    False,
    Not(Box<Cond<E>>),
    And(Box<Cond<E>>, Box<Cond<E>>),
    Or(Box<Cond<E>>, Box<Cond<E>>),

    /// If two expressions are equal
    Equal(Box<E>, Box<E>),

    Less(Box<E>, Box<E>),
    Greater(Box<E>, Box<E>),

    LessEqual(Box<E>, Box<E>),
    GreaterEqual(Box<E>, Box<E>),
}

impl<E: Expression> Condition for Cond<E> {
    type Expr = E;
    fn evaluate(&self,
                variables: &[<Self::Expr as Expression>::Element])
                -> Result<bool, ExpressionError> {
        Ok(match *self {
            Cond::True => true,
            Cond::False => false,
            Cond::Not(ref c) => !try!(c.evaluate(variables)),
            Cond::And(ref c1, ref c2) => {
                try!(c1.evaluate(variables)) && try!(c2.evaluate(variables))
            }
            Cond::Or(ref c1, ref c2) => {
                try!(c1.evaluate(variables)) || try!(c2.evaluate(variables))
            }
            Cond::Equal(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) == try!(e2.evaluate(variables))
            }
            Cond::Less(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) < try!(e2.evaluate(variables))
            }
            Cond::Greater(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) > try!(e2.evaluate(variables))
            }
            Cond::LessEqual(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) <= try!(e2.evaluate(variables))
            }
            Cond::GreaterEqual(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) >= try!(e2.evaluate(variables))
            }
        })
    }
}

impl<'a, E, T> Into<Sexp> for &'a Cond<E>
    where E: Expression<Element = T>,
          &'a E: Into<Sexp>,
          T: Debug + Copy + Clone + PartialEq + PartialOrd + Into<Sexp>
{
    fn into(self) -> Sexp {
        match self {
            &Cond::True => Sexp::from("true"),
            &Cond::False => Sexp::from("false"),
            &Cond::Not(ref a) => Sexp::from(("not", Into::<Sexp>::into(a.as_ref()))),
            &Cond::And(ref a, ref b) => {
                Sexp::from(("and",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &Cond::Or(ref a, ref b) => {
                Sexp::from(("or",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &Cond::Equal(ref a, ref b) => {
                Sexp::from(("==",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &Cond::Less(ref a, ref b) => {
                Sexp::from(("<",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &Cond::Greater(ref a, ref b) => {
                Sexp::from((">",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &Cond::LessEqual(ref a, ref b) => {
                Sexp::from(("<=",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &Cond::GreaterEqual(ref a, ref b) => {
                Sexp::from((">=",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    #[derive(Debug, Clone, PartialEq, PartialOrd)]
    struct ConstNum(f32);

    impl ::Expression for ConstNum {
        type Element = f32;
        fn evaluate(&self,
                    _variables: &[Self::Element])
                    -> Result<Self::Element, ::ExpressionError> {
            Ok(self.0)
        }
    }

    #[test]
    fn test_condition() {
        use Condition;
        use super::Cond;
        let no_vars: &[f32] = &[];

        let cond = Cond::Greater(box ConstNum(0.1), box ConstNum(0.2));
        assert_eq!(Ok(false), cond.evaluate(no_vars));

        let cond = Cond::Not(box Cond::Greater(box ConstNum(0.1), box ConstNum(0.2)));
        assert_eq!(Ok(true), cond.evaluate(no_vars));
    }
}
<commit_msg>Remove unneccessary trait bound.<commit_after>use super::{Expression, ExpressionError, Condition};
use asexp::Sexp;
use std::fmt::Debug;

/// A boolean condition evaluates to either `true` or `false`.
#[derive(Debug, Clone, PartialEq)]
pub enum Cond<E: Expression> {
    True,
    False,
    Not(Box<Cond<E>>),
    And(Box<Cond<E>>, Box<Cond<E>>),
    Or(Box<Cond<E>>, Box<Cond<E>>),

    /// If two expressions are equal
    Equal(Box<E>, Box<E>),

    Less(Box<E>, Box<E>),
    Greater(Box<E>, Box<E>),

    LessEqual(Box<E>, Box<E>),
    GreaterEqual(Box<E>, Box<E>),
}

impl<E: Expression> Condition for Cond<E> {
    type Expr = E;
    fn evaluate(&self,
                variables: &[<Self::Expr as Expression>::Element])
                -> Result<bool, ExpressionError> {
        Ok(match *self {
            Cond::True => true,
            Cond::False => false,
            Cond::Not(ref c) => !try!(c.evaluate(variables)),
            Cond::And(ref c1, ref c2) => {
                try!(c1.evaluate(variables)) && try!(c2.evaluate(variables))
            }
            Cond::Or(ref c1, ref c2) => {
                try!(c1.evaluate(variables)) || try!(c2.evaluate(variables))
            }
            Cond::Equal(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) == try!(e2.evaluate(variables))
            }
            Cond::Less(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) < try!(e2.evaluate(variables))
            }
            Cond::Greater(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) > try!(e2.evaluate(variables))
            }
            Cond::LessEqual(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) <= try!(e2.evaluate(variables))
            }
            Cond::GreaterEqual(ref e1, ref e2) => {
                try!(e1.evaluate(variables)) >= try!(e2.evaluate(variables))
            }
        })
    }
}

impl<'a, E, T> Into<Sexp> for &'a Cond<E>
    where E: Expression<Element = T>,
          &'a E: Into<Sexp>,
          T: Debug + Copy + Clone + PartialEq + PartialOrd
{
    fn into(self) -> Sexp {
        match self {
            &Cond::True => Sexp::from("true"),
            &Cond::False => Sexp::from("false"),
            &Cond::Not(ref a) => Sexp::from(("not", Into::<Sexp>::into(a.as_ref()))),
            &Cond::And(ref a, ref b) => {
                Sexp::from(("and",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &Cond::Or(ref a, ref b) => {
                Sexp::from(("or",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &Cond::Equal(ref a, ref b) => {
                Sexp::from(("==",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &Cond::Less(ref a, ref b) => {
                Sexp::from(("<",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &Cond::Greater(ref a, ref b) => {
                Sexp::from((">",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &Cond::LessEqual(ref a, ref b) => {
                Sexp::from(("<=",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
            &Cond::GreaterEqual(ref a, ref b) => {
                Sexp::from((">=",
                            Into::<Sexp>::into(a.as_ref()),
                            Into::<Sexp>::into(b.as_ref())))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    #[derive(Debug, Clone, PartialEq, PartialOrd)]
    struct ConstNum(f32);

    impl ::Expression for ConstNum {
        type Element = f32;
        fn evaluate(&self,
                    _variables: &[Self::Element])
                    -> Result<Self::Element, ::ExpressionError> {
            Ok(self.0)
        }
    }

    #[test]
    fn test_condition() {
        use Condition;
        use super::Cond;
        let no_vars: &[f32] = &[];

        let cond = Cond::Greater(box ConstNum(0.1), box ConstNum(0.2));
        assert_eq!(Ok(false), cond.evaluate(no_vars));

        let cond = Cond::Not(box Cond::Greater(box ConstNum(0.1), box ConstNum(0.2)));
        assert_eq!(Ok(true), cond.evaluate(no_vars));
    }
}
<|endoftext|>


<commit_before><commit_msg>x86_64: adding copy/clone derives...<commit_after><|endoftext|>


<commit_before>use std::any::{ Any, TypeId };
use std::ops::{ Deref, DerefMut };
use std::collections::HashMap;
use std::collections::hash_map::Entry;

pub trait Features {
    fn register(&mut Deps);
}

pub struct Deps {
    /// List of functions that constructs all childs for a type
    /// and returns value wrapped in Any that must live as long as the parent type.
    type_child_constructors: HashMap<
        TypeId,
        Vec<Box<
            Fn(&Deps, &mut Any) -> Option<Box<Any>> + Send + Sync
        >>
    >,
}

impl Deps {
    pub fn new() -> Deps {
        Deps {
            type_child_constructors: HashMap::new()
        }
    }

    /// Create dependencies for specified `obj` and return a wrapper `Scope` object.
    ///
    /// The wrapper `Scope` keeps ownership of all children together with parent object.
    pub fn create_for<P: Any>(&self, mut obj: P) -> Scope<P> {
        match self.type_child_constructors.get(&TypeId::of::<P>()) {
            // if there are type child constructors
            Some(list) => {
                // run each child constructor and receive list of objects that will be kept inside
                // the parent scope.
                let deps: Vec<_> = list.iter()
                    .filter_map(|any_constructor| any_constructor(&self, &mut obj))
                    .collect();

                Scope { obj: obj, childs: deps }
            },
            // if there are no type childs, wrap the type in scope anyways with empty child list.
            None => Scope { obj: obj, childs: vec![] },
        }
    }

    /// Register child constructor that will be invoked when the parent `P` type is
    /// created.
    pub fn register_child_constructor<P: Any>(
        &mut self,
        any_constructor: Box<Fn(&Deps, &mut Any) -> Option<Box<Any>> + Send + Sync>
    ) {
        match self.type_child_constructors.entry(TypeId::of::<P>()) {
            Entry::Occupied(mut list) => {
                list.get_mut().push(any_constructor);
            },
            Entry::Vacant(e) => {
                e.insert(vec![any_constructor]);
            },
        };
    }

    /// Register a bunch of features at once.
    pub fn with<F: Features>(&mut self) -> &mut Self {
        F::register(self);
        self
    }

    /// Single dependency on parent.
    pub fn on<P, C, F>(&mut self, constructor: F)
        where
            P: 'static + Any, C: 'static + Any,
            F: for<'r> Fn(&Deps, Parent<P>) -> C + 'static + Send + Sync
    {
        self.register_child_constructor::<P>(into_constructor_with_deps(constructor));
    }
}

fn into_constructor_with_deps<P, C, F>(constructor: F) -> Box<Fn(&Deps, &mut Any) -> Option<Box<Any>> + Send + Sync>
    where F: for<'r> Fn(&Deps, Parent<P>) -> C + 'static + Send + Sync, P: 'static + Any, C: 'static + Any
{
    Box::new(move |deps: &Deps, parent: &mut Any| -> Option<Box<Any>> {
        let concrete_parent = parent.downcast_mut::<P>().unwrap();
        let child = deps.create_for(constructor(deps, Parent::<P> { obj: concrete_parent }));
        Some(Box::new(child))
    })
}

#[derive(Debug)]
pub struct Parent<'a, T: 'a> {
    pub obj: &'a mut T,
}

impl<'a, T> Deref for Parent<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.obj
    }
}

impl<'a, T> DerefMut for Parent<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.obj
    }
}

#[derive(Debug)]
pub struct Scope<T> {
    pub obj: T,
    childs: Vec<Box<Any>>,
}

impl<T> Scope<T> {
    pub fn explode(self) -> T {
        self.obj
    }
}

impl<T> Deref for Scope<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.obj
    }
}

impl<T> DerefMut for Scope<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.obj
    }
}
<commit_msg>Add on_create hook.<commit_after>use std::any::{ Any, TypeId };
use std::ops::{ Deref, DerefMut };
use std::collections::HashMap;
use std::collections::hash_map::Entry;

pub trait Features {
    fn register(&mut Deps);
}

pub struct Deps {
    /// List of functions that constructs all childs for a type
    /// and returns value wrapped in Any that must live as long as the parent type.
    type_child_constructors: HashMap<
        TypeId,
        Vec<Box<
            Fn(&Deps, &mut Any) -> Option<Box<Any>> + Send + Sync
        >>
    >,
    type_scope_created: HashMap<
        TypeId,
        Vec<Box<
            Fn(&Deps, &mut Any) + Send + Sync
        >>
    >,
}

impl Deps {
    pub fn new() -> Deps {
        Deps {
            type_child_constructors: HashMap::new(),
            type_scope_created: HashMap::new(),
        }
    }

    /// Create dependencies for specified `obj` and return a wrapper `Scope` object.
    ///
    /// The wrapper `Scope` keeps ownership of all children together with parent object.
    pub fn create_for<P: Any>(&self, mut obj: P) -> Scope<P> {
        match self.type_child_constructors.get(&TypeId::of::<P>()) {
            // if there are type child constructors
            Some(list) => {
                // run each child constructor and receive list of objects that will be kept inside
                // the parent scope.
                let deps: Vec<_> = list.iter()
                    .filter_map(|any_constructor| any_constructor(&self, &mut obj))
                    .collect();

                if let Some(actions) = self.type_scope_created.get(&TypeId::of::<P>()) {
                    for action in actions {
                        action(&self, &mut obj);
                    }
                }

                Scope { obj: obj, childs: deps }
            },
            // if there are no type childs, wrap the type in scope anyways with empty child list.
            None => Scope { obj: obj, childs: vec![] },
        }
    }

    /// Register child constructor that will be invoked when the parent `P` type is
    /// created.
    pub fn register_child_constructor<P: Any>(
        &mut self,
        any_constructor: Box<Fn(&Deps, &mut Any) -> Option<Box<Any>> + Send + Sync>
    ) {
        match self.type_child_constructors.entry(TypeId::of::<P>()) {
            Entry::Occupied(mut list) => {
                list.get_mut().push(any_constructor);
            },
            Entry::Vacant(e) => {
                e.insert(vec![any_constructor]);
            },
        };
    }

    /// Register a bunch of features at once.
    pub fn with<F: Features>(&mut self) -> &mut Self {
        F::register(self);
        self
    }

    pub fn on_create<P, F>(&mut self, action: F)
        where
            P: 'static + Any,
            F: for<'r> Fn(&Deps, Parent<P>) + 'static + Send + Sync
    {
        match self.type_scope_created.entry(TypeId::of::<P>()) {
            Entry::Occupied(mut list) => {
                list.get_mut().push(into_action_with_deps(action));
            },
            Entry::Vacant(e) => {
                e.insert(vec![into_action_with_deps(action)]);
            },
        };
    }

    /// Single dependency on parent.
    pub fn on<P, C, F>(&mut self, constructor: F)
        where
            P: 'static + Any, C: 'static + Any,
            F: for<'r> Fn(&Deps, Parent<P>) -> C + 'static + Send + Sync
    {
        self.register_child_constructor::<P>(into_constructor_with_deps(constructor));
    }
}

fn into_action_with_deps<P, F>(action: F) -> Box<Fn(&Deps, &mut Any) + Send + Sync>
    where F: for<'r> Fn(&Deps, Parent<P>) + 'static + Send + Sync, P: 'static + Any
{
    Box::new(move |deps: &Deps, parent: &mut Any| {
        let concrete_parent = parent.downcast_mut::<P>().unwrap();
        action(deps, Parent::<P> { obj: concrete_parent })
    })
}

fn into_constructor_with_deps<P, C, F>(constructor: F) -> Box<Fn(&Deps, &mut Any) -> Option<Box<Any>> + Send + Sync>
    where F: for<'r> Fn(&Deps, Parent<P>) -> C + 'static + Send + Sync, P: 'static + Any, C: 'static + Any
{
    Box::new(move |deps: &Deps, parent: &mut Any| -> Option<Box<Any>> {
        let concrete_parent = parent.downcast_mut::<P>().unwrap();
        let child = deps.create_for(constructor(deps, Parent::<P> { obj: concrete_parent }));
        Some(Box::new(child))
    })
}

#[derive(Debug)]
pub struct Parent<'a, T: 'a> {
    pub obj: &'a mut T,
}

impl<'a, T> Deref for Parent<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.obj
    }
}

impl<'a, T> DerefMut for Parent<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.obj
    }
}

#[derive(Debug)]
pub struct Scope<T> {
    pub obj: T,
    childs: Vec<Box<Any>>,
}

impl<T> Scope<T> {
    pub fn explode(self) -> T {
        self.obj
    }
}

impl<T> Deref for Scope<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.obj
    }
}

impl<T> DerefMut for Scope<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.obj
    }
}
<|endoftext|>