<commit_before>// Copyright 2016 Walter Kuppens.
//
// 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.

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use nes::cpu::CPU;
use nes::ppu::PPU;
use std::io::Cursor;

// Memory partition sizes (physical).
// TODO: Calculate based on ranges below.
pub const RAM_SIZE:                 usize = 0x800;
pub const PPU_CTRL_REGISTERS_SIZE:  usize = 0x8;
pub const MISC_CTRL_REGISTERS_SIZE: usize = 0x20;
pub const EXPANSION_ROM_SIZE:       usize = 0x1FE0;
pub const SRAM_SIZE:                usize = 0x2000;
pub const PRG_ROM_SIZE:             usize = 0x4000;

// Partitioned virtual memory map bounds.
pub const RAM_START_ADDR:                  usize = 0x0;
pub const RAM_END_ADDR:                    usize = 0x7FF;
pub const RAM_MIRROR_START:                usize = 0x800;
pub const RAM_MIRROR_END:                  usize = 0x1FFF;
pub const PPU_CTRL_REGISTERS_START:        usize = 0x2000;
pub const PPU_CTRL_REGISTERS_END:          usize = 0x2007;
pub const PPU_CTRL_REGISTERS_MIRROR_START: usize = 0x2008;
pub const PPU_CTRL_REGISTERS_MIRROR_END:   usize = 0x3FFF;
pub const MISC_CTRL_REGISTERS_START:       usize = 0x4000;
pub const MISC_CTRL_REGISTERS_END:         usize = 0x401F;
pub const EXPANSION_ROM_START:             usize = 0x4020;
pub const EXPANSION_ROM_END:               usize = 0x5FFF;
pub const SRAM_START:                      usize = 0x6000;
pub const SRAM_END:                        usize = 0x7FFF;
pub const PRG_ROM_1_START:                 usize = 0x8000;
pub const PRG_ROM_1_END:                   usize = 0xBFFF;
pub const PRG_ROM_2_START:                 usize = 0xC000;
pub const PRG_ROM_2_END:                   usize = 0xFFFF;

// Constants for additional structures.
pub const TRAINER_START: usize = 0x7000;
pub const TRAINER_SIZE:  usize = 512;

// Location of the first byte on the bottom of the stack. The stack starts on
// memory page 2 (0x100).
const STACK_OFFSET: usize = 0x100;

pub trait MemoryMapper {
    /// Map should map a given virtual address to either a physical address to
    /// host memory or to some control mechanism. How memory is mapped depends
    /// on the cartridge being used by the INES ROM.
    fn map(&mut self, addr: usize) -> (&mut [u8], usize, bool, bool);
}

pub trait Memory: MemoryMapper {
    /// Returns an instance of memory with all banks initialized.
    fn new() -> Self;

    /// Reads an unsigned 8-bit byte value located at the given virtual address.
    #[inline(always)]
    fn read_u8(&mut self, addr: usize) -> u8 {
        let (bank, idx, readable, _) = self.map(addr);
        if readable {
            bank[idx]
        } else {
            0
        }
    }

    /// Writes an unsigned 8-bit byte value to the given virtual address.
    #[inline(always)]
    fn write_u8(&mut self, addr: usize, val: u8) {
        let (bank, idx, _, writable) = self.map(addr);
        if writable {
            bank[idx] = val;
        }
    }

    /// Writes an unsigned 8-bit byte value to the given virtual address.
    #[inline(always)]
    fn write_u8_unrestricted(&mut self, addr: usize, val: u8) {
        let (bank, idx, _, _) = self.map(addr);
        bank[idx] = val;
    }

    /// Reads an unsigned 16-bit byte value at the given virtual address
    /// (little-endian).
    #[inline(always)]
    fn read_u16(&mut self, addr: usize) -> u16 {
        // Reads two bytes starting at the given address and parses them.
        let mut reader = Cursor::new(vec![
            self.read_u8(addr),
            self.read_u8(addr + 1)
        ]);
        reader.read_u16::<LittleEndian>().unwrap()
    }

    /// Reads an unsigned 16-bit byte value at the given virtual address
    /// (little-endian).
    #[inline(always)]
    fn read_u16_alt(&mut self, addr: usize) -> u16 {
        // Reads two bytes starting at the given address and parses them.
        let mut reader = Cursor::new(vec![
            self.read_u8(addr - 1),
            self.read_u8(addr)
        ]);
        reader.read_u16::<LittleEndian>().unwrap()
    }

    /// Reads an unsigned 16-bit byte value at the given virtual address
    /// (little-endian) where the MSB is read at page start if the LSB is at
    /// the end of a page. This exists to properly emulate a hardware bug in the
    /// 2A03 where indirect jumps cannot fetch addresses outside it's own page.
    #[inline(always)]
    fn read_u16_wrapped_msb(&mut self, addr: usize) -> u16 {
        let lsb = self.read_u8(addr);
        let msb = if addr & 0xFF == 0xFF {
            self.read_u8(addr - 0xFF)
        } else {
            self.read_u8(addr + 1)
        };

        // Reads two bytes starting at the given address and parses them.
        let mut reader = Cursor::new(vec![lsb, msb]);
        reader.read_u16::<LittleEndian>().unwrap()
    }

    /// Reads an unsigned 16-bit byte value at the given virtual address
    /// (little-endian) where the MSB is read at page start if the LSB is at
    /// the end of a page. This exists to properly emulate a hardware bug in the
    /// 2A03 where indirect jumps cannot fetch addresses outside it's own page.
    #[inline(always)]
    fn read_u16_wrapped_msb_alt(&mut self, addr: usize) -> u16 {
        let lsb = self.read_u8(addr - 1);
        let msb = if addr & 0xFF == 0xFF {
            self.read_u8(addr - 0xFF)
        } else {
            self.read_u8(addr)
        };

        // Reads two bytes starting at the given address and parses them.
        let mut reader = Cursor::new(vec![lsb, msb]);
        reader.read_u16::<LittleEndian>().unwrap()
    }

    /// Writes an unsigned 16-bit byte value to the given virtual address
    /// (little-endian)
    #[inline(always)]
    fn write_u16(&mut self, addr: usize, val: u16) {
        let mut writer = vec![];
        writer.write_u16::<LittleEndian>(val).unwrap();
        self.write_u8(addr, writer[0]);
        self.write_u8(addr + 1, writer[1]);
    }

    /// Writes an unsigned 16-bit byte value to the given virtual address
    /// (little-endian)
    #[inline(always)]
    fn write_u16_alt(&mut self, addr: usize, val: u16) {
        let mut writer = vec![];
        writer.write_u16::<LittleEndian>(val).unwrap();
        self.write_u8(addr - 1, writer[0]);
        self.write_u8(addr, writer[1]);
    }

    /// Dumps the contents of a slice starting at a given address.
    fn memdump(&mut self, addr: usize, buf: &[u8]) {
        for i in 0..buf.len() {
            self.write_u8_unrestricted(addr + i, buf[i]);
        }
    }

    // Utility functions for managing the stack.

    /// Pushes an 8-bit number onto the stack.
    fn stack_push_u8(&mut self, cpu: &mut CPU, value: u8) {
        self.write_u8(STACK_OFFSET + cpu.sp as usize, value);
        cpu.sp = cpu.sp.wrapping_sub(1);
    }

    /// Pops an 8-bit number off the stack.
    fn stack_pop_u8(&mut self, cpu: &mut CPU) -> u8 {
        cpu.sp = cpu.sp.wrapping_add(1);
        self.read_u8(STACK_OFFSET + cpu.sp as usize)
    }

    /// Pushes a 16-bit number (usually an address) onto the stack.
    fn stack_push_u16(&mut self, cpu: &mut CPU, value: u16) {
        self.write_u16_alt(STACK_OFFSET + cpu.sp as usize, value);
        cpu.sp = cpu.sp.wrapping_sub(2);
    }

    /// Pops a 16-bit number (usually an address) off the stack.
    fn stack_pop_u16(&mut self, cpu: &mut CPU) -> u16 {
        cpu.sp = cpu.sp.wrapping_add(2);
        self.read_u16_alt(STACK_OFFSET + cpu.sp as usize)
    }
}

/// Partitioned physical memory layout for CPU memory. These fields are not
/// meant to be accessed directly by the CPU implementation and are instead
/// accessed through a read function that handles memory mapping.
///
/// NOTE: Currently all memory is allocated on the stack. This may not work well
/// for systems with a small stack and slices should be boxed up.
pub struct NROMMapper {
    // 2kB of internal RAM which contains zero page, the stack, and general
    // purpose memory.
    ram: [u8; RAM_SIZE],

    // Contains PPU registers that allow the running application to communicate
    // with the PPU.
    ppu_ctrl_registers: [u8; PPU_CTRL_REGISTERS_SIZE],

    // Contains NES APU and I/O registers. Also allows use of APU and I/O
    // functionality that is normally disabled.
    misc_ctrl_registers: [u8; MISC_CTRL_REGISTERS_SIZE],

    expansion_rom: [u8; EXPANSION_ROM_SIZE],
    sram: [u8; SRAM_SIZE],

    // Read-only ROM which contains executable code and assets.
    prg_rom_1: [u8; PRG_ROM_SIZE],
    prg_rom_2: [u8; PRG_ROM_SIZE]
}

impl NROMMapper {
    /// Deals with the fact that different PPU I/O registers have different read
    /// and write access.
    ///
    /// TODO: Call PPU hooks.
    fn map_ppu_registers(&mut self, addr: usize) -> (&mut [u8], usize, bool, bool) {
        let registers = &mut self.ppu_ctrl_registers;
        match addr {
            0 => (registers, addr, false, true),
            1 => (registers, addr, false, true),
            2 => (registers, addr, true, false),
            3 => (registers, addr, false, true),
            4 => (registers, addr, true, true),
            5 => (registers, addr, false, true), // Twice
            6 => (registers, addr, false, true), // Twice
            7 => (registers, addr, true, true),
            _ => (registers, addr, true, true),
        }
    }
}

impl MemoryMapper for NROMMapper {
    /// Maps a given virtual address to a physical address internal to the
    /// emulator. Returns a memory buffer and index for physical memory access.
    fn map(&mut self, addr: usize) -> (&mut [u8], usize, bool, bool) {
        match addr {
            RAM_START_ADDR...RAM_END_ADDR =>
                (&mut self.ram, addr, true, true),
            RAM_MIRROR_START...RAM_MIRROR_END =>
                (&mut self.ram, addr % RAM_SIZE, true, true),
            PPU_CTRL_REGISTERS_START...PPU_CTRL_REGISTERS_END =>
                self.map_ppu_registers(addr - PPU_CTRL_REGISTERS_START),
            PPU_CTRL_REGISTERS_MIRROR_START...PPU_CTRL_REGISTERS_MIRROR_END =>
                self.map_ppu_registers((addr - PPU_CTRL_REGISTERS_START) % PPU_CTRL_REGISTERS_SIZE),
            MISC_CTRL_REGISTERS_START...MISC_CTRL_REGISTERS_END =>
                (&mut self.misc_ctrl_registers, addr - MISC_CTRL_REGISTERS_START, true, true),
            EXPANSION_ROM_START...EXPANSION_ROM_END =>
                (&mut self.expansion_rom, addr - EXPANSION_ROM_START, true, false),
            SRAM_START...SRAM_END =>
                (&mut self.sram, addr - SRAM_START, true, true),
            PRG_ROM_1_START...PRG_ROM_1_END =>
                (&mut self.prg_rom_1, addr - PRG_ROM_1_START, true, false),
            PRG_ROM_2_START...PRG_ROM_2_END =>
                (&mut self.prg_rom_2, addr - PRG_ROM_2_START, true, false),
            _ => { panic!("Unable to map virtual address {:#X} to any physical address", addr) }
        }
    }
}

impl Memory for NROMMapper {
    fn new() -> Self {
        NROMMapper {
            ram: [0; RAM_SIZE],
            ppu_ctrl_registers: [0; PPU_CTRL_REGISTERS_SIZE],
            misc_ctrl_registers: [0; MISC_CTRL_REGISTERS_SIZE],
            expansion_rom: [0; EXPANSION_ROM_SIZE],
            sram: [0; SRAM_SIZE],
            prg_rom_1: [0; PRG_ROM_SIZE],
            prg_rom_2: [0; PRG_ROM_SIZE],
        }
    }
}
<commit_msg>More work on PPU I/O registers<commit_after>// Copyright 2016 Walter Kuppens.
//
// 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.

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use nes::cpu::CPU;
use std::io::Cursor;

// Memory partition sizes (physical).
// TODO: Calculate based on ranges below.
pub const RAM_SIZE:                 usize = 0x800;
pub const PPU_CTRL_REGISTERS_SIZE:  usize = 0x8;
pub const MISC_CTRL_REGISTERS_SIZE: usize = 0x20;
pub const EXPANSION_ROM_SIZE:       usize = 0x1FE0;
pub const SRAM_SIZE:                usize = 0x2000;
pub const PRG_ROM_SIZE:             usize = 0x4000;

// Partitioned virtual memory map bounds.
pub const RAM_START_ADDR:                  usize = 0x0;
pub const RAM_END_ADDR:                    usize = 0x7FF;
pub const RAM_MIRROR_START:                usize = 0x800;
pub const RAM_MIRROR_END:                  usize = 0x1FFF;
pub const PPU_CTRL_REGISTERS_START:        usize = 0x2000;
pub const PPU_CTRL_REGISTERS_END:          usize = 0x2007;
pub const PPU_CTRL_REGISTERS_MIRROR_START: usize = 0x2008;
pub const PPU_CTRL_REGISTERS_MIRROR_END:   usize = 0x3FFF;
pub const MISC_CTRL_REGISTERS_START:       usize = 0x4000;
pub const MISC_CTRL_REGISTERS_END:         usize = 0x401F;
pub const EXPANSION_ROM_START:             usize = 0x4020;
pub const EXPANSION_ROM_END:               usize = 0x5FFF;
pub const SRAM_START:                      usize = 0x6000;
pub const SRAM_END:                        usize = 0x7FFF;
pub const PRG_ROM_1_START:                 usize = 0x8000;
pub const PRG_ROM_1_END:                   usize = 0xBFFF;
pub const PRG_ROM_2_START:                 usize = 0xC000;
pub const PRG_ROM_2_END:                   usize = 0xFFFF;

// Constants for additional structures.
pub const TRAINER_START: usize = 0x7000;
pub const TRAINER_SIZE:  usize = 512;

// Location of the first byte on the bottom of the stack. The stack starts on
// memory page 2 (0x100).
const STACK_OFFSET: usize = 0x100;

/// Possible states of PPU registers.
#[derive(Clone, Copy)]
pub enum PPURegisterStatus {
    Read,
    Written,
    WrittenTwice,
    Untouched,
}

pub trait MemoryMapper {
    /// Returns a slice of PPU registers.
    fn ppu_ctrl_registers(&mut self) -> &mut [u8];

    /// Returns a slice of each PPU register's status.
    fn ppu_ctrl_registers_status(&mut self) -> &mut [PPURegisterStatus];

    /// Map should map a given virtual address to either a physical address to
    /// host memory or to some control mechanism. How memory is mapped depends
    /// on the cartridge being used by the INES ROM.
    fn map(&mut self, addr: usize) -> (&mut [u8], usize, bool, bool);

    /// Deals with the fact that different PPU I/O registers have different read
    /// and write access.
    fn map_ppu_registers(&mut self, addr: usize) -> (&mut [u8], usize, bool, bool) {
        let registers = self.ppu_ctrl_registers();
        match addr {
            0 => (registers, addr, false, true),
            1 => (registers, addr, false, true),
            2 => (registers, addr, true, false),
            3 => (registers, addr, false, true),
            4 => (registers, addr, true, true),
            5 => (registers, addr, false, true), // Twice
            6 => (registers, addr, false, true), // Twice
            7 => (registers, addr, true, true),
            _ => (registers, addr, true, true),
        }
    }
}

pub trait Memory: MemoryMapper {
    /// Returns an instance of memory with all banks initialized.
    fn new() -> Self;

    /// Reads an unsigned 8-bit byte value located at the given virtual address.
    #[inline(always)]
    fn read_u8(&mut self, addr: usize) -> u8 {
        let (bank, idx, readable, _) = self.map(addr);
        if readable {
            bank[idx]
        } else {
            0
        }
    }

    /// Writes an unsigned 8-bit byte value to the given virtual address.
    #[inline(always)]
    fn write_u8(&mut self, addr: usize, val: u8) {
        let (bank, idx, _, writable) = self.map(addr);
        if writable {
            bank[idx] = val;
        }
    }

    /// Writes an unsigned 8-bit byte value to the given virtual address.
    #[inline(always)]
    fn write_u8_unrestricted(&mut self, addr: usize, val: u8) {
        let (bank, idx, _, _) = self.map(addr);
        bank[idx] = val;
    }

    /// Reads an unsigned 16-bit byte value at the given virtual address
    /// (little-endian).
    #[inline(always)]
    fn read_u16(&mut self, addr: usize) -> u16 {
        // Reads two bytes starting at the given address and parses them.
        let mut reader = Cursor::new(vec![
            self.read_u8(addr),
            self.read_u8(addr + 1)
        ]);
        reader.read_u16::<LittleEndian>().unwrap()
    }

    /// Reads an unsigned 16-bit byte value at the given virtual address
    /// (little-endian).
    #[inline(always)]
    fn read_u16_alt(&mut self, addr: usize) -> u16 {
        // Reads two bytes starting at the given address and parses them.
        let mut reader = Cursor::new(vec![
            self.read_u8(addr - 1),
            self.read_u8(addr)
        ]);
        reader.read_u16::<LittleEndian>().unwrap()
    }

    /// Reads an unsigned 16-bit byte value at the given virtual address
    /// (little-endian) where the MSB is read at page start if the LSB is at
    /// the end of a page. This exists to properly emulate a hardware bug in the
    /// 2A03 where indirect jumps cannot fetch addresses outside it's own page.
    #[inline(always)]
    fn read_u16_wrapped_msb(&mut self, addr: usize) -> u16 {
        let lsb = self.read_u8(addr);
        let msb = if addr & 0xFF == 0xFF {
            self.read_u8(addr - 0xFF)
        } else {
            self.read_u8(addr + 1)
        };

        // Reads two bytes starting at the given address and parses them.
        let mut reader = Cursor::new(vec![lsb, msb]);
        reader.read_u16::<LittleEndian>().unwrap()
    }

    /// Reads an unsigned 16-bit byte value at the given virtual address
    /// (little-endian) where the MSB is read at page start if the LSB is at
    /// the end of a page. This exists to properly emulate a hardware bug in the
    /// 2A03 where indirect jumps cannot fetch addresses outside it's own page.
    #[inline(always)]
    fn read_u16_wrapped_msb_alt(&mut self, addr: usize) -> u16 {
        let lsb = self.read_u8(addr - 1);
        let msb = if addr & 0xFF == 0xFF {
            self.read_u8(addr - 0xFF)
        } else {
            self.read_u8(addr)
        };

        // Reads two bytes starting at the given address and parses them.
        let mut reader = Cursor::new(vec![lsb, msb]);
        reader.read_u16::<LittleEndian>().unwrap()
    }

    /// Writes an unsigned 16-bit byte value to the given virtual address
    /// (little-endian)
    #[inline(always)]
    fn write_u16(&mut self, addr: usize, val: u16) {
        let mut writer = vec![];
        writer.write_u16::<LittleEndian>(val).unwrap();
        self.write_u8(addr, writer[0]);
        self.write_u8(addr + 1, writer[1]);
    }

    /// Writes an unsigned 16-bit byte value to the given virtual address
    /// (little-endian)
    #[inline(always)]
    fn write_u16_alt(&mut self, addr: usize, val: u16) {
        let mut writer = vec![];
        writer.write_u16::<LittleEndian>(val).unwrap();
        self.write_u8(addr - 1, writer[0]);
        self.write_u8(addr, writer[1]);
    }

    /// Dumps the contents of a slice starting at a given address.
    fn memdump(&mut self, addr: usize, buf: &[u8]) {
        for i in 0..buf.len() {
            self.write_u8_unrestricted(addr + i, buf[i]);
        }
    }

    // Utility functions for managing the stack.

    /// Pushes an 8-bit number onto the stack.
    fn stack_push_u8(&mut self, cpu: &mut CPU, value: u8) {
        self.write_u8(STACK_OFFSET + cpu.sp as usize, value);
        cpu.sp = cpu.sp.wrapping_sub(1);
    }

    /// Pops an 8-bit number off the stack.
    fn stack_pop_u8(&mut self, cpu: &mut CPU) -> u8 {
        cpu.sp = cpu.sp.wrapping_add(1);
        self.read_u8(STACK_OFFSET + cpu.sp as usize)
    }

    /// Pushes a 16-bit number (usually an address) onto the stack.
    fn stack_push_u16(&mut self, cpu: &mut CPU, value: u16) {
        self.write_u16_alt(STACK_OFFSET + cpu.sp as usize, value);
        cpu.sp = cpu.sp.wrapping_sub(2);
    }

    /// Pops a 16-bit number (usually an address) off the stack.
    fn stack_pop_u16(&mut self, cpu: &mut CPU) -> u16 {
        cpu.sp = cpu.sp.wrapping_add(2);
        self.read_u16_alt(STACK_OFFSET + cpu.sp as usize)
    }
}

/// Partitioned physical memory layout for CPU memory. These fields are not
/// meant to be accessed directly by the CPU implementation and are instead
/// accessed through a read function that handles memory mapping.
///
/// NOTE: Currently all memory is allocated on the stack. This may not work well
/// for systems with a small stack and slices should be boxed up.
pub struct NROMMapper {
    // 2kB of internal RAM which contains zero page, the stack, and general
    // purpose memory.
    ram: [u8; RAM_SIZE],

    // Contains PPU registers that allow the running application to communicate
    // with the PPU.
    ppu_ctrl_registers: [u8; PPU_CTRL_REGISTERS_SIZE],

    // Current read/write status of all PPU registers stored in memory.
    ppu_ctrl_registers_status: [PPURegisterStatus; PPU_CTRL_REGISTERS_SIZE],

    // TODO: Add ring buffer for double write registers.

    // Contains NES APU and I/O registers. Also allows use of APU and I/O
    // functionality that is normally disabled.
    misc_ctrl_registers: [u8; MISC_CTRL_REGISTERS_SIZE],

    expansion_rom: [u8; EXPANSION_ROM_SIZE],
    sram: [u8; SRAM_SIZE],

    // Read-only ROM which contains executable code and assets.
    prg_rom_1: [u8; PRG_ROM_SIZE],
    prg_rom_2: [u8; PRG_ROM_SIZE]
}

impl MemoryMapper for NROMMapper {
    /// Returns a slice of PPU registers.
    fn ppu_ctrl_registers(&mut self) -> &mut [u8] {
        &mut self.ppu_ctrl_registers
    }

    /// Returns a slice of each PPU register's status.
    fn ppu_ctrl_registers_status(&mut self) -> &mut [PPURegisterStatus] {
        &mut self.ppu_ctrl_registers_status
    }

    /// Maps a given virtual address to a physical address internal to the
    /// emulator. Returns a memory buffer and index for physical memory access.
    fn map(&mut self, addr: usize) -> (&mut [u8], usize, bool, bool) {
        match addr {
            RAM_START_ADDR...RAM_END_ADDR =>
                (&mut self.ram, addr, true, true),
            RAM_MIRROR_START...RAM_MIRROR_END =>
                (&mut self.ram, addr % RAM_SIZE, true, true),
            PPU_CTRL_REGISTERS_START...PPU_CTRL_REGISTERS_END =>
                self.map_ppu_registers(addr - PPU_CTRL_REGISTERS_START),
            PPU_CTRL_REGISTERS_MIRROR_START...PPU_CTRL_REGISTERS_MIRROR_END =>
                self.map_ppu_registers((addr - PPU_CTRL_REGISTERS_START) % PPU_CTRL_REGISTERS_SIZE),
            MISC_CTRL_REGISTERS_START...MISC_CTRL_REGISTERS_END =>
                (&mut self.misc_ctrl_registers, addr - MISC_CTRL_REGISTERS_START, true, true),
            EXPANSION_ROM_START...EXPANSION_ROM_END =>
                (&mut self.expansion_rom, addr - EXPANSION_ROM_START, true, false),
            SRAM_START...SRAM_END =>
                (&mut self.sram, addr - SRAM_START, true, true),
            PRG_ROM_1_START...PRG_ROM_1_END =>
                (&mut self.prg_rom_1, addr - PRG_ROM_1_START, true, false),
            PRG_ROM_2_START...PRG_ROM_2_END =>
                (&mut self.prg_rom_2, addr - PRG_ROM_2_START, true, false),
            _ => { panic!("Unable to map virtual address {:#X} to any physical address", addr) }
        }
    }
}

impl Memory for NROMMapper {
    fn new() -> Self {
        NROMMapper {
            ram: [0; RAM_SIZE],
            ppu_ctrl_registers: [0; PPU_CTRL_REGISTERS_SIZE],
            ppu_ctrl_registers_status: [PPURegisterStatus::Untouched; PPU_CTRL_REGISTERS_SIZE],
            misc_ctrl_registers: [0; MISC_CTRL_REGISTERS_SIZE],
            expansion_rom: [0; EXPANSION_ROM_SIZE],
            sram: [0; SRAM_SIZE],
            prg_rom_1: [0; PRG_ROM_SIZE],
            prg_rom_2: [0; PRG_ROM_SIZE],
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Delix Project Authors. See the AUTHORS file at the top level directory.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

extern crate delix;

#[allow(dead_code)] mod helper;

use std::thread;

use delix::node::{State, request};

#[test]
fn single_echo_from_local() {
    helper::set_up();

    let node = helper::build_node("127.0.0.1:3001", &[]);
    node.register("echo", Box::new(|request| Ok(request.to_vec())))
            .unwrap();

    thread::sleep_ms(100);
    helper::assert_node(&node, State::Discovering, 0);

    let response = node.request("echo", b"test message").unwrap();
    assert_eq!(b"test message".to_vec(), response);
}

#[test]
fn single_echo_from_remote() {
    helper::set_up();

    let node_one = helper::build_node("127.0.0.1:3011", &[]);
    node_one.register("echo", Box::new(|request| Ok(request.to_vec())))
            .unwrap();

    let node_two = helper::build_node("127.0.0.1:3012", &["127.0.0.1:3011"]);

    thread::sleep_ms(1000);
    helper::assert_node(&node_one, State::Joined, 1);
    helper::assert_node(&node_two, State::Joined, 1);

    let response = node_two.request("echo", b"test message").unwrap();
    assert_eq!(b"test message".to_vec(), response);
}

#[test]
fn multiple_echos_from_remote() {
    helper::set_up();

    let node_one = helper::build_node("127.0.0.1:3021", &[]);
    node_one.register("echo", Box::new(|request| Ok(request.to_vec())))
            .unwrap();

    let node_two = helper::build_node("127.0.0.1:3022", &["127.0.0.1:3021"]);

    thread::sleep_ms(1000);
    helper::assert_node(&node_one, State::Joined, 1);
    helper::assert_node(&node_two, State::Joined, 1);
    assert_eq!(1, node_one.service_count());
    assert_eq!(1, node_two.service_count());

    assert_eq!(b"test message one".to_vec(), node_two.request("echo", b"test message one").unwrap());
    assert_eq!(b"test message two".to_vec(), node_two.request("echo", b"test message two").unwrap());
}

#[test]
fn balanced_echos_from_two_remotes() {
    helper::set_up();

    let node_one = helper::build_node("127.0.0.1:3031", &[]);
    node_one.register("echo", Box::new(|_| {
        Err(request::Error::TestDuration(b"40".to_vec()))
    })).unwrap();

    let node_two = helper::build_node("127.0.0.1:3032", &["127.0.0.1:3031"]);
    node_two.register("echo", Box::new(|_| {
        Err(request::Error::TestDuration(b"100".to_vec()))
    })).unwrap();

    let node_three = helper::build_node("127.0.0.1:3033", &["127.0.0.1:3031"]);

    thread::sleep_ms(1000);
    helper::assert_node(&node_one, State::Joined, 2);
    helper::assert_node(&node_two, State::Joined, 2);
    helper::assert_node(&node_three, State::Joined, 2);
    assert_eq!(1, node_one.service_count());
    assert_eq!(1, node_two.service_count());
    assert_eq!(1, node_three.service_count());

    println!("--- round ---");

    // in the first round the balancer has no statistic, so every serivice gets a request in order.
    assert_eq!("40", String::from_utf8_lossy(&node_three.request("echo", b"").unwrap()));
    assert_eq!("100", String::from_utf8_lossy(&node_three.request("echo", b"").unwrap()));

    println!("--- round ---");

    // in the second round the balancer can access some respond time statistic, so this round
    // contains two requests to node one and one to node two.
    assert_eq!("40", String::from_utf8_lossy(&node_three.request("echo", b"").unwrap()));
    assert_eq!("40", String::from_utf8_lossy(&node_three.request("echo", b"").unwrap()));
    assert_eq!("100", String::from_utf8_lossy(&node_three.request("echo", b"").unwrap()));

    println!("--- round ---");

    // if a service deregisters in the middle of a round, the changes should be processed
    assert_eq!("40", String::from_utf8_lossy(&node_three.request("echo", b"").unwrap()));
    node_two.deregister("echo").unwrap();
    assert_eq!("40", String::from_utf8_lossy(&node_three.request("echo", b"").unwrap()));
    assert_eq!("40", String::from_utf8_lossy(&node_three.request("echo", b"").unwrap()));

    println!("--- round ---");
}
<commit_msg>restructured test<commit_after>// Copyright 2015 The Delix Project Authors. See the AUTHORS file at the top level directory.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

extern crate delix;

#[allow(dead_code)] mod helper;

use std::thread;

use delix::node::{State, request};

#[test]
fn single_echo_from_local() {
    helper::set_up();

    let node = helper::build_node("127.0.0.1:3001", &[]);
    node.register("echo", Box::new(|request| Ok(request.to_vec())))
            .unwrap();

    thread::sleep_ms(100);
    helper::assert_node(&node, State::Discovering, 0);

    let response = node.request("echo", b"test message").unwrap();
    assert_eq!(b"test message".to_vec(), response);
}

#[test]
fn single_echo_from_remote() {
    helper::set_up();

    let node_one = helper::build_node("127.0.0.1:3011", &[]);
    node_one.register("echo", Box::new(|request| Ok(request.to_vec())))
            .unwrap();

    let node_two = helper::build_node("127.0.0.1:3012", &["127.0.0.1:3011"]);

    thread::sleep_ms(1000);
    helper::assert_node(&node_one, State::Joined, 1);
    helper::assert_node(&node_two, State::Joined, 1);

    let response = node_two.request("echo", b"test message").unwrap();
    assert_eq!(b"test message".to_vec(), response);
}

#[test]
fn multiple_echos_from_remote() {
    helper::set_up();

    let node_one = helper::build_node("127.0.0.1:3021", &[]);
    node_one.register("echo", Box::new(|request| Ok(request.to_vec())))
            .unwrap();

    let node_two = helper::build_node("127.0.0.1:3022", &["127.0.0.1:3021"]);

    thread::sleep_ms(1000);
    helper::assert_node(&node_one, State::Joined, 1);
    helper::assert_node(&node_two, State::Joined, 1);
    assert_eq!(1, node_one.service_count());
    assert_eq!(1, node_two.service_count());

    assert_eq!(b"test message one".to_vec(), node_two.request("echo", b"test message one").unwrap());
    assert_eq!(b"test message two".to_vec(), node_two.request("echo", b"test message two").unwrap());
}

#[test]
fn balanced_echos_from_two_remotes() {
    helper::set_up();

    let node_one = helper::build_node("127.0.0.1:3031", &[]);

    let node_two = helper::build_node("127.0.0.1:3032", &["127.0.0.1:3031"]);
    node_two.register("echo", Box::new(|_| {
        Err(request::Error::TestDuration(b"40".to_vec()))
    })).unwrap();

    thread::sleep_ms(1000);
    helper::assert_node(&node_one, State::Joined, 1);
    helper::assert_node(&node_two, State::Joined, 1);

    let node_three = helper::build_node("127.0.0.1:3033", &["127.0.0.1:3031"]);
    node_three.register("echo", Box::new(|_| {
        Err(request::Error::TestDuration(b"100".to_vec()))
    })).unwrap();

    thread::sleep_ms(1000);
    helper::assert_node(&node_one, State::Joined, 2);
    helper::assert_node(&node_two, State::Joined, 2);
    helper::assert_node(&node_three, State::Joined, 2);
    assert_eq!(1, node_one.service_count());
    assert_eq!(1, node_two.service_count());
    assert_eq!(1, node_three.service_count());

    println!("--- round ---");

    // in the first round the balancer has no statistic, so every serivice gets a request in order.
    assert_eq!("40", String::from_utf8_lossy(&node_one.request("echo", b"").unwrap()));
    assert_eq!("100", String::from_utf8_lossy(&node_one.request("echo", b"").unwrap()));

    println!("--- round ---");

    // in the second round the balancer can access some respond time statistic, so this round
    // contains two requests to node one and one to node two.
    assert_eq!("40", String::from_utf8_lossy(&node_one.request("echo", b"").unwrap()));
    assert_eq!("40", String::from_utf8_lossy(&node_one.request("echo", b"").unwrap()));
    assert_eq!("100", String::from_utf8_lossy(&node_one.request("echo", b"").unwrap()));

    println!("--- round ---");

    // if a service deregisters in the middle of a round, the changes should be processed
    assert_eq!("40", String::from_utf8_lossy(&node_one.request("echo", b"").unwrap()));
    node_three.deregister("echo").unwrap();
    assert_eq!("40", String::from_utf8_lossy(&node_one.request("echo", b"").unwrap()));
    assert_eq!("40", String::from_utf8_lossy(&node_one.request("echo", b"").unwrap()));

    println!("--- round ---");
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate hamcrest;
extern crate cargo;

use std::collections::HashMap;

use hamcrest::{assert_that, equal_to, contains};

use cargo::core::source::{SourceId, GitReference};
use cargo::core::dependency::Kind::{self, Development};
use cargo::core::{Dependency, PackageId, Summary, Registry};
use cargo::util::{CargoResult, ToUrl};
use cargo::core::resolver::{self, Method};

fn resolve<R: Registry>(pkg: PackageId, deps: Vec<Dependency>,
                        registry: &mut R)
                        -> CargoResult<Vec<PackageId>> {
    let summary = Summary::new(pkg.clone(), deps, HashMap::new()).unwrap();
    let method = Method::Everything;
    Ok(resolver::resolve(&[(summary, method)], &[], registry)?.iter().map(|p| {
        p.clone()
    }).collect())
}

trait ToDep {
    fn to_dep(self) -> Dependency;
}

impl ToDep for &'static str {
    fn to_dep(self) -> Dependency {
        let url = "http://example.com".to_url().unwrap();
        let source_id = SourceId::for_registry(&url);
        Dependency::parse_no_deprecated(self, Some("1.0.0"), &source_id).unwrap()
    }
}

impl ToDep for Dependency {
    fn to_dep(self) -> Dependency {
        self
    }
}

trait ToPkgId {
    fn to_pkgid(&self) -> PackageId;
}

impl ToPkgId for &'static str {
    fn to_pkgid(&self) -> PackageId {
        PackageId::new(*self, "1.0.0", &registry_loc()).unwrap()
    }
}

impl ToPkgId for (&'static str, &'static str) {
    fn to_pkgid(&self) -> PackageId {
        let (name, vers) = *self;
        PackageId::new(name, vers, &registry_loc()).unwrap()
    }
}

macro_rules! pkg {
    ($pkgid:expr => [$($deps:expr),+]) => ({
        let d: Vec<Dependency> = vec![$($deps.to_dep()),+];

        Summary::new($pkgid.to_pkgid(), d, HashMap::new()).unwrap()
    });

    ($pkgid:expr) => (
        Summary::new($pkgid.to_pkgid(), Vec::new(), HashMap::new()).unwrap()
    )
}

fn registry_loc() -> SourceId {
    let remote = "http://example.com".to_url().unwrap();
    SourceId::for_registry(&remote)
}

fn pkg(name: &str) -> Summary {
    Summary::new(pkg_id(name), Vec::new(), HashMap::new()).unwrap()
}

fn pkg_id(name: &str) -> PackageId {
    PackageId::new(name, "1.0.0", &registry_loc()).unwrap()
}

fn pkg_id_loc(name: &str, loc: &str) -> PackageId {
    let remote = loc.to_url();
    let master = GitReference::Branch("master".to_string());
    let source_id = SourceId::for_git(&remote.unwrap(), master);

    PackageId::new(name, "1.0.0", &source_id).unwrap()
}

fn pkg_loc(name: &str, loc: &str) -> Summary {
    Summary::new(pkg_id_loc(name, loc), Vec::new(), HashMap::new()).unwrap()
}

fn dep(name: &str) -> Dependency { dep_req(name, "1.0.0") }
fn dep_req(name: &str, req: &str) -> Dependency {
    let url = "http://example.com".to_url().unwrap();
    let source_id = SourceId::for_registry(&url);
    Dependency::parse_no_deprecated(name, Some(req), &source_id).unwrap()
}

fn dep_loc(name: &str, location: &str) -> Dependency {
    let url = location.to_url().unwrap();
    let master = GitReference::Branch("master".to_string());
    let source_id = SourceId::for_git(&url, master);
    Dependency::parse_no_deprecated(name, Some("1.0.0"), &source_id).unwrap()
}
fn dep_kind(name: &str, kind: Kind) -> Dependency {
    dep(name).clone_inner().set_kind(kind).into_dependency()
}

fn registry(pkgs: Vec<Summary>) -> Vec<Summary> {
    pkgs
}

fn names<P: ToPkgId>(names: &[P]) -> Vec<PackageId> {
    names.iter().map(|name| name.to_pkgid()).collect()
}

fn loc_names(names: &[(&'static str, &'static str)]) -> Vec<PackageId> {
    names.iter()
        .map(|&(name, loc)| pkg_id_loc(name, loc)).collect()
}

#[test]
fn test_resolving_empty_dependency_list() {
    let res = resolve(pkg_id("root"), Vec::new(),
                      &mut registry(vec![])).unwrap();

    assert_that(&res, equal_to(&names(&["root"])));
}

#[test]
fn test_resolving_only_package() {
    let mut reg = registry(vec![pkg("foo")]);
    let res = resolve(pkg_id("root"), vec![dep("foo")], &mut reg);

    assert_that(&res.unwrap(), contains(names(&["root", "foo"])).exactly());
}

#[test]
fn test_resolving_one_dep() {
    let mut reg = registry(vec![pkg("foo"), pkg("bar")]);
    let res = resolve(pkg_id("root"), vec![dep("foo")], &mut reg);

    assert_that(&res.unwrap(), contains(names(&["root", "foo"])).exactly());
}

#[test]
fn test_resolving_multiple_deps() {
    let mut reg = registry(vec![pkg!("foo"), pkg!("bar"), pkg!("baz")]);
    let res = resolve(pkg_id("root"), vec![dep("foo"), dep("baz")],
                      &mut reg).unwrap();

    assert_that(&res, contains(names(&["root", "foo", "baz"])).exactly());
}

#[test]
fn test_resolving_transitive_deps() {
    let mut reg = registry(vec![pkg!("foo"), pkg!("bar" => ["foo"])]);
    let res = resolve(pkg_id("root"), vec![dep("bar")], &mut reg).unwrap();

    assert_that(&res, contains(names(&["root", "foo", "bar"])));
}

#[test]
fn test_resolving_common_transitive_deps() {
    let mut reg = registry(vec![pkg!("foo" => ["bar"]), pkg!("bar")]);
    let res = resolve(pkg_id("root"), vec![dep("foo"), dep("bar")],
                      &mut reg).unwrap();

    assert_that(&res, contains(names(&["root", "foo", "bar"])));
}

#[test]
fn test_resolving_with_same_name() {
    let list = vec![pkg_loc("foo", "http://first.example.com"),
                    pkg_loc("bar", "http://second.example.com")];

    let mut reg = registry(list);
    let res = resolve(pkg_id("root"),
                      vec![dep_loc("foo", "http://first.example.com"),
                           dep_loc("bar", "http://second.example.com")],
                      &mut reg);

    let mut names = loc_names(&[("foo", "http://first.example.com"),
                                ("bar", "http://second.example.com")]);

    names.push(pkg_id("root"));

    assert_that(&res.unwrap(), contains(names).exactly());
}

#[test]
fn test_resolving_with_dev_deps() {
    let mut reg = registry(vec![
        pkg!("foo" => ["bar", dep_kind("baz", Development)]),
        pkg!("baz" => ["bat", dep_kind("bam", Development)]),
        pkg!("bar"),
        pkg!("bat")
    ]);

    let res = resolve(pkg_id("root"),
                      vec![dep("foo"), dep_kind("baz", Development)],
                      &mut reg).unwrap();

    assert_that(&res, contains(names(&["root", "foo", "bar", "baz"])));
}

#[test]
fn resolving_with_many_versions() {
    let mut reg = registry(vec![
        pkg!(("foo", "1.0.1")),
        pkg!(("foo", "1.0.2")),
    ]);

    let res = resolve(pkg_id("root"), vec![dep("foo")], &mut reg).unwrap();

    assert_that(&res, contains(names(&[("root", "1.0.0"),
                                       ("foo", "1.0.2")])));
}

#[test]
fn resolving_with_specific_version() {
    let mut reg = registry(vec![
        pkg!(("foo", "1.0.1")),
        pkg!(("foo", "1.0.2")),
    ]);

    let res = resolve(pkg_id("root"), vec![dep_req("foo", "=1.0.1")],
                      &mut reg).unwrap();

    assert_that(&res, contains(names(&[("root", "1.0.0"),
                                       ("foo", "1.0.1")])));
}

#[test]
fn resolving_incompat_versions() {
    let mut reg = registry(vec![
        pkg!(("foo", "1.0.1")),
        pkg!(("foo", "1.0.2")),
        pkg!("bar" => [dep_req("foo", "=1.0.2")]),
    ]);

    assert!(resolve(pkg_id("root"), vec![
        dep_req("foo", "=1.0.1"),
        dep("bar"),
    ], &mut reg).is_err());
}

#[test]
fn resolving_backtrack() {
    let mut reg = registry(vec![
        pkg!(("foo", "1.0.2") => [dep("bar")]),
        pkg!(("foo", "1.0.1") => [dep("baz")]),
        pkg!("bar" => [dep_req("foo", "=2.0.2")]),
        pkg!("baz"),
    ]);

    let res = resolve(pkg_id("root"), vec![
        dep_req("foo", "^1"),
    ], &mut reg).unwrap();

    assert_that(&res, contains(names(&[("root", "1.0.0"),
                                       ("foo", "1.0.1"),
                                       ("baz", "1.0.0")])));
}

#[test]
fn resolving_allows_multiple_compatible_versions() {
    let mut reg = registry(vec![
        pkg!(("foo", "1.0.0")),
        pkg!(("foo", "2.0.0")),
        pkg!(("foo", "0.1.0")),
        pkg!(("foo", "0.2.0")),

        pkg!("bar" => ["d1", "d2", "d3", "d4"]),
        pkg!("d1" => [dep_req("foo", "1")]),
        pkg!("d2" => [dep_req("foo", "2")]),
        pkg!("d3" => [dep_req("foo", "0.1")]),
        pkg!("d4" => [dep_req("foo", "0.2")]),
    ]);

    let res = resolve(pkg_id("root"), vec![
        dep("bar"),
    ], &mut reg).unwrap();

    assert_that(&res, contains(names(&[("root", "1.0.0"),
                                       ("foo", "1.0.0"),
                                       ("foo", "2.0.0"),
                                       ("foo", "0.1.0"),
                                       ("foo", "0.2.0"),
                                       ("d1", "1.0.0"),
                                       ("d2", "1.0.0"),
                                       ("d3", "1.0.0"),
                                       ("d4", "1.0.0"),
                                       ("bar", "1.0.0")])));
}

#[test]
fn resolving_with_deep_backtracking() {
    let mut reg = registry(vec![
        pkg!(("foo", "1.0.1") => [dep_req("bar", "1")]),
        pkg!(("foo", "1.0.0") => [dep_req("bar", "2")]),

        pkg!(("bar", "1.0.0") => [dep_req("baz", "=1.0.2"),
                                  dep_req("other", "1")]),
        pkg!(("bar", "2.0.0") => [dep_req("baz", "=1.0.1")]),

        pkg!(("baz", "1.0.2") => [dep_req("other", "2")]),
        pkg!(("baz", "1.0.1")),

        pkg!(("dep_req", "1.0.0")),
        pkg!(("dep_req", "2.0.0")),
    ]);

    let res = resolve(pkg_id("root"), vec![
        dep_req("foo", "1"),
    ], &mut reg).unwrap();

    assert_that(&res, contains(names(&[("root", "1.0.0"),
                                       ("foo", "1.0.0"),
                                       ("bar", "2.0.0"),
                                       ("baz", "1.0.1")])));
}

#[test]
fn resolving_but_no_exists() {
    let mut reg = registry(vec![
    ]);

    let res = resolve(pkg_id("root"), vec![
        dep_req("foo", "1"),
    ], &mut reg);
    assert!(res.is_err());

    assert_eq!(res.err().unwrap().to_string(), "\
no matching package named `foo` found (required by `root`)
location searched: registry http://example.com/
version required: ^1\
");
}

#[test]
fn resolving_cycle() {
    let mut reg = registry(vec![
        pkg!("foo" => ["foo"]),
    ]);

    let _ = resolve(pkg_id("root"), vec![
        dep_req("foo", "1"),
    ], &mut reg);
}

#[test]
fn hard_equality() {
    extern crate env_logger;
    let mut reg = registry(vec![
        pkg!(("foo", "1.0.1")),
        pkg!(("foo", "1.0.0")),

        pkg!(("bar", "1.0.0") => [dep_req("foo", "1.0.0")]),
    ]);

    let res = resolve(pkg_id("root"), vec![
        dep_req("bar", "1"),
        dep_req("foo", "=1.0.0"),
    ], &mut reg).unwrap();

    assert_that(&res, contains(names(&[("root", "1.0.0"),
                                       ("foo", "1.0.0"),
                                       ("bar", "1.0.0")])));
}
<commit_msg>Test for issue #2064<commit_after>#![deny(warnings)]

extern crate hamcrest;
extern crate cargo;

use std::collections::HashMap;

use hamcrest::{assert_that, equal_to, contains, not};

use cargo::core::source::{SourceId, GitReference};
use cargo::core::dependency::Kind::{self, Development};
use cargo::core::{Dependency, PackageId, Summary, Registry};
use cargo::util::{CargoResult, ToUrl};
use cargo::core::resolver::{self, Method};

fn resolve<R: Registry>(pkg: PackageId, deps: Vec<Dependency>,
                        registry: &mut R)
                        -> CargoResult<Vec<PackageId>> {
    let summary = Summary::new(pkg.clone(), deps, HashMap::new()).unwrap();
    let method = Method::Everything;
    Ok(resolver::resolve(&[(summary, method)], &[], registry)?.iter().map(|p| {
        p.clone()
    }).collect())
}

trait ToDep {
    fn to_dep(self) -> Dependency;
}

impl ToDep for &'static str {
    fn to_dep(self) -> Dependency {
        let url = "http://example.com".to_url().unwrap();
        let source_id = SourceId::for_registry(&url);
        Dependency::parse_no_deprecated(self, Some("1.0.0"), &source_id).unwrap()
    }
}

impl ToDep for Dependency {
    fn to_dep(self) -> Dependency {
        self
    }
}

trait ToPkgId {
    fn to_pkgid(&self) -> PackageId;
}

impl ToPkgId for &'static str {
    fn to_pkgid(&self) -> PackageId {
        PackageId::new(*self, "1.0.0", &registry_loc()).unwrap()
    }
}

impl ToPkgId for (&'static str, &'static str) {
    fn to_pkgid(&self) -> PackageId {
        let (name, vers) = *self;
        PackageId::new(name, vers, &registry_loc()).unwrap()
    }
}

macro_rules! pkg {
    ($pkgid:expr => [$($deps:expr),+]) => ({
        let d: Vec<Dependency> = vec![$($deps.to_dep()),+];

        Summary::new($pkgid.to_pkgid(), d, HashMap::new()).unwrap()
    });

    ($pkgid:expr) => (
        Summary::new($pkgid.to_pkgid(), Vec::new(), HashMap::new()).unwrap()
    )
}

fn registry_loc() -> SourceId {
    let remote = "http://example.com".to_url().unwrap();
    SourceId::for_registry(&remote)
}

fn pkg(name: &str) -> Summary {
    Summary::new(pkg_id(name), Vec::new(), HashMap::new()).unwrap()
}

fn pkg_id(name: &str) -> PackageId {
    PackageId::new(name, "1.0.0", &registry_loc()).unwrap()
}

fn pkg_id_loc(name: &str, loc: &str) -> PackageId {
    let remote = loc.to_url();
    let master = GitReference::Branch("master".to_string());
    let source_id = SourceId::for_git(&remote.unwrap(), master);

    PackageId::new(name, "1.0.0", &source_id).unwrap()
}

fn pkg_loc(name: &str, loc: &str) -> Summary {
    Summary::new(pkg_id_loc(name, loc), Vec::new(), HashMap::new()).unwrap()
}

fn dep(name: &str) -> Dependency { dep_req(name, "1.0.0") }
fn dep_req(name: &str, req: &str) -> Dependency {
    let url = "http://example.com".to_url().unwrap();
    let source_id = SourceId::for_registry(&url);
    Dependency::parse_no_deprecated(name, Some(req), &source_id).unwrap()
}

fn dep_loc(name: &str, location: &str) -> Dependency {
    let url = location.to_url().unwrap();
    let master = GitReference::Branch("master".to_string());
    let source_id = SourceId::for_git(&url, master);
    Dependency::parse_no_deprecated(name, Some("1.0.0"), &source_id).unwrap()
}
fn dep_kind(name: &str, kind: Kind) -> Dependency {
    dep(name).clone_inner().set_kind(kind).into_dependency()
}

fn registry(pkgs: Vec<Summary>) -> Vec<Summary> {
    pkgs
}

fn names<P: ToPkgId>(names: &[P]) -> Vec<PackageId> {
    names.iter().map(|name| name.to_pkgid()).collect()
}

fn loc_names(names: &[(&'static str, &'static str)]) -> Vec<PackageId> {
    names.iter()
        .map(|&(name, loc)| pkg_id_loc(name, loc)).collect()
}

#[test]
fn test_resolving_empty_dependency_list() {
    let res = resolve(pkg_id("root"), Vec::new(),
                      &mut registry(vec![])).unwrap();

    assert_that(&res, equal_to(&names(&["root"])));
}

#[test]
fn test_resolving_only_package() {
    let mut reg = registry(vec![pkg("foo")]);
    let res = resolve(pkg_id("root"), vec![dep("foo")], &mut reg);

    assert_that(&res.unwrap(), contains(names(&["root", "foo"])).exactly());
}

#[test]
fn test_resolving_one_dep() {
    let mut reg = registry(vec![pkg("foo"), pkg("bar")]);
    let res = resolve(pkg_id("root"), vec![dep("foo")], &mut reg);

    assert_that(&res.unwrap(), contains(names(&["root", "foo"])).exactly());
}

#[test]
fn test_resolving_multiple_deps() {
    let mut reg = registry(vec![pkg!("foo"), pkg!("bar"), pkg!("baz")]);
    let res = resolve(pkg_id("root"), vec![dep("foo"), dep("baz")],
                      &mut reg).unwrap();

    assert_that(&res, contains(names(&["root", "foo", "baz"])).exactly());
}

#[test]
fn test_resolving_transitive_deps() {
    let mut reg = registry(vec![pkg!("foo"), pkg!("bar" => ["foo"])]);
    let res = resolve(pkg_id("root"), vec![dep("bar")], &mut reg).unwrap();

    assert_that(&res, contains(names(&["root", "foo", "bar"])));
}

#[test]
fn test_resolving_common_transitive_deps() {
    let mut reg = registry(vec![pkg!("foo" => ["bar"]), pkg!("bar")]);
    let res = resolve(pkg_id("root"), vec![dep("foo"), dep("bar")],
                      &mut reg).unwrap();

    assert_that(&res, contains(names(&["root", "foo", "bar"])));
}

#[test]
fn test_resolving_with_same_name() {
    let list = vec![pkg_loc("foo", "http://first.example.com"),
                    pkg_loc("bar", "http://second.example.com")];

    let mut reg = registry(list);
    let res = resolve(pkg_id("root"),
                      vec![dep_loc("foo", "http://first.example.com"),
                           dep_loc("bar", "http://second.example.com")],
                      &mut reg);

    let mut names = loc_names(&[("foo", "http://first.example.com"),
                                ("bar", "http://second.example.com")]);

    names.push(pkg_id("root"));

    assert_that(&res.unwrap(), contains(names).exactly());
}

#[test]
fn test_resolving_with_dev_deps() {
    let mut reg = registry(vec![
        pkg!("foo" => ["bar", dep_kind("baz", Development)]),
        pkg!("baz" => ["bat", dep_kind("bam", Development)]),
        pkg!("bar"),
        pkg!("bat")
    ]);

    let res = resolve(pkg_id("root"),
                      vec![dep("foo"), dep_kind("baz", Development)],
                      &mut reg).unwrap();

    assert_that(&res, contains(names(&["root", "foo", "bar", "baz"])));
}

#[test]
fn resolving_with_many_versions() {
    let mut reg = registry(vec![
        pkg!(("foo", "1.0.1")),
        pkg!(("foo", "1.0.2")),
    ]);

    let res = resolve(pkg_id("root"), vec![dep("foo")], &mut reg).unwrap();

    assert_that(&res, contains(names(&[("root", "1.0.0"),
                                       ("foo", "1.0.2")])));
}

#[test]
fn resolving_with_specific_version() {
    let mut reg = registry(vec![
        pkg!(("foo", "1.0.1")),
        pkg!(("foo", "1.0.2")),
    ]);

    let res = resolve(pkg_id("root"), vec![dep_req("foo", "=1.0.1")],
                      &mut reg).unwrap();

    assert_that(&res, contains(names(&[("root", "1.0.0"),
                                       ("foo", "1.0.1")])));
}

#[test]
fn test_resolving_maximum_version_with_transitive_deps() {
    let mut reg = registry(vec![
        pkg!(("util", "1.2.2")),
        pkg!(("util", "1.0.0")),
        pkg!(("util", "1.1.1")),
        pkg!("foo" => [dep_req("util", "1.0.0")]),
        pkg!("bar" => [dep_req("util", ">=1.0.1")]),
    ]);

    let res = resolve(pkg_id("root"), vec![dep_req("foo", "1.0.0"), dep_req("bar", "1.0.0")],
                      &mut reg).unwrap();

    assert_that(&res, contains(names(&[("root", "1.0.0"),
                                       ("foo", "1.0.0"),
                                       ("bar", "1.0.0"),
                                       ("util", "1.2.2")])));
    assert_that(&res, not(contains(names(&[("util", "1.0.1")]))));
    assert_that(&res, not(contains(names(&[("util", "1.1.1")]))));
}

#[test]
fn resolving_incompat_versions() {
    let mut reg = registry(vec![
        pkg!(("foo", "1.0.1")),
        pkg!(("foo", "1.0.2")),
        pkg!("bar" => [dep_req("foo", "=1.0.2")]),
    ]);

    assert!(resolve(pkg_id("root"), vec![
        dep_req("foo", "=1.0.1"),
        dep("bar"),
    ], &mut reg).is_err());
}

#[test]
fn resolving_backtrack() {
    let mut reg = registry(vec![
        pkg!(("foo", "1.0.2") => [dep("bar")]),
        pkg!(("foo", "1.0.1") => [dep("baz")]),
        pkg!("bar" => [dep_req("foo", "=2.0.2")]),
        pkg!("baz"),
    ]);

    let res = resolve(pkg_id("root"), vec![
        dep_req("foo", "^1"),
    ], &mut reg).unwrap();

    assert_that(&res, contains(names(&[("root", "1.0.0"),
                                       ("foo", "1.0.1"),
                                       ("baz", "1.0.0")])));
}

#[test]
fn resolving_allows_multiple_compatible_versions() {
    let mut reg = registry(vec![
        pkg!(("foo", "1.0.0")),
        pkg!(("foo", "2.0.0")),
        pkg!(("foo", "0.1.0")),
        pkg!(("foo", "0.2.0")),

        pkg!("bar" => ["d1", "d2", "d3", "d4"]),
        pkg!("d1" => [dep_req("foo", "1")]),
        pkg!("d2" => [dep_req("foo", "2")]),
        pkg!("d3" => [dep_req("foo", "0.1")]),
        pkg!("d4" => [dep_req("foo", "0.2")]),
    ]);

    let res = resolve(pkg_id("root"), vec![
        dep("bar"),
    ], &mut reg).unwrap();

    assert_that(&res, contains(names(&[("root", "1.0.0"),
                                       ("foo", "1.0.0"),
                                       ("foo", "2.0.0"),
                                       ("foo", "0.1.0"),
                                       ("foo", "0.2.0"),
                                       ("d1", "1.0.0"),
                                       ("d2", "1.0.0"),
                                       ("d3", "1.0.0"),
                                       ("d4", "1.0.0"),
                                       ("bar", "1.0.0")])));
}

#[test]
fn resolving_with_deep_backtracking() {
    let mut reg = registry(vec![
        pkg!(("foo", "1.0.1") => [dep_req("bar", "1")]),
        pkg!(("foo", "1.0.0") => [dep_req("bar", "2")]),

        pkg!(("bar", "1.0.0") => [dep_req("baz", "=1.0.2"),
                                  dep_req("other", "1")]),
        pkg!(("bar", "2.0.0") => [dep_req("baz", "=1.0.1")]),

        pkg!(("baz", "1.0.2") => [dep_req("other", "2")]),
        pkg!(("baz", "1.0.1")),

        pkg!(("dep_req", "1.0.0")),
        pkg!(("dep_req", "2.0.0")),
    ]);

    let res = resolve(pkg_id("root"), vec![
        dep_req("foo", "1"),
    ], &mut reg).unwrap();

    assert_that(&res, contains(names(&[("root", "1.0.0"),
                                       ("foo", "1.0.0"),
                                       ("bar", "2.0.0"),
                                       ("baz", "1.0.1")])));
}

#[test]
fn resolving_but_no_exists() {
    let mut reg = registry(vec![
    ]);

    let res = resolve(pkg_id("root"), vec![
        dep_req("foo", "1"),
    ], &mut reg);
    assert!(res.is_err());

    assert_eq!(res.err().unwrap().to_string(), "\
no matching package named `foo` found (required by `root`)
location searched: registry http://example.com/
version required: ^1\
");
}

#[test]
fn resolving_cycle() {
    let mut reg = registry(vec![
        pkg!("foo" => ["foo"]),
    ]);

    let _ = resolve(pkg_id("root"), vec![
        dep_req("foo", "1"),
    ], &mut reg);
}

#[test]
fn hard_equality() {
    extern crate env_logger;
    let mut reg = registry(vec![
        pkg!(("foo", "1.0.1")),
        pkg!(("foo", "1.0.0")),

        pkg!(("bar", "1.0.0") => [dep_req("foo", "1.0.0")]),
    ]);

    let res = resolve(pkg_id("root"), vec![
        dep_req("bar", "1"),
        dep_req("foo", "=1.0.0"),
    ], &mut reg).unwrap();

    assert_that(&res, contains(names(&[("root", "1.0.0"),
                                       ("foo", "1.0.0"),
                                       ("bar", "1.0.0")])));
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};

use ast::expressions;
use ast::lexer::tokens::{self, Keyword};
use ast::parser;
use ast::rules;
use ast::stack;

const DEBUG: bool = false;

macro_rules! make_op_table {
    ($lrec_prec: ident, $([$($lrec: expr), +]), +) => {
        let mut $lrec_prec = HashMap::new();

        let mut prec: usize = 0;
        $(
            $(
                $lrec_prec.insert($lrec, prec);
            )+
            prec = prec + 1;
            let _compiler_friend = prec;
        )+
    };
}

// binop ::=  ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘//’ | ‘^’ | ‘%’ |
//        ‘&’ | ‘~’ | ‘|’ | ‘>>’ | ‘<<’ | ‘..’ |
//        ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ |
//        and | or
#[derive(Debug)]
pub struct Binop(
    pub Keyword,
    pub Box<expressions::Expression>,
    pub Box<expressions::Expression>,
);
impl expressions::Expression for Binop {}

impl Binop {
    // parse_expression () return parse_expression_1 (parse_primary (), 0)
    pub fn rule(parser: &mut parser::Parser, stack: &mut stack::Stack) -> bool {
        if !rules::exp_prefix(parser, stack) {
            return false;
        }

        Binop::prec_rule(parser, stack, 0);
        true
    }

    // https://en.wikipedia.org/wiki/Operator-precedence_parser
    // parse_expression_1 (lhs, min_precedence)
    //     lookahead := peek next token
    //     while lookahead is a binary operator whose precedence is >= min_precedence
    //         op := lookahead
    //         advance to next token
    //         rhs := parse_primary ()
    //         lookahead := peek next token
    //         while lookahead is a binary operator whose precedence is greater
    //                  than op's, or a right-associative operator
    //                  whose precedence is equal to op's
    //             rhs := parse_expression_1 (rhs, lookahead's precedence)
    //             lookahead := peek next token
    //         lhs := the result of applying op with operands lhs and rhs
    //     return lhs
    pub fn prec_rule(
        parser: &mut parser::Parser,
        stack: &mut stack::Stack,
        precedence: usize,
    ) {
        // or
        // and
        // <     >     <=    >=    ~=    ==
        // |
        // ~
        // &
        // <<    >>
        // ..
        // +     -
        // *     /     //    %
        // ^
        make_op_table!(
            ops_prec_table,
            [Keyword::OR],
            [Keyword::AND],
            [
                Keyword::LESS,
                Keyword::LEQ,
                Keyword::GREATER,
                Keyword::GEQ,
                Keyword::EQ,
                Keyword::NEQ
            ],
            [Keyword::SOR],
            [Keyword::TILDA],
            [Keyword::SAND],
            [Keyword::SHRIGHT, Keyword::SHLEFT],
            [Keyword::DOT2],
            [Keyword::PLUS, Keyword::MINUS],
            [Keyword::MUL, Keyword::DIV, Keyword::MOD, Keyword::FLOORDIV],
            [Keyword::POW]
        );

        debug_parser!(
            "Entered precedence rule. Left: {:?}. Precedence: {}",
            stack.peek(),
            precedence
        );

        // lookahead := peek next token
        // while lookahead is a binary operator whose precedence is >= min_precedence
        while let Some(op) = parser.peek().and_then(|token| token.keyword()) {
            if !ops_prec_table.contains_key(&op) || ops_prec_table[&op] < precedence {
                return;
            }

            // op := lookahead
            // advance to next token
            parser.shift();

            // rhs := parse_primary ()
            if !rules::exp_prefix(parser, stack) {
                panic!(format!(
                    "Expecter expressiion after binary operator, got {:?}",
                    parser.peek()
                ))
            }

            // lookahead := peek next token
            while let Some(op2) = parser.peek().and_then(|token| token.keyword()) {
                // while lookahead is a binary operator whose precedence is greater
                // than op's, or a right-associative operator
                // whose precedence is equal to op's
                if !ops_prec_table.contains_key(&op2) || ops_prec_table[&op2] <= ops_prec_table[&op]
                {
                    break;
                }
                // rhs := parse_expression_1 (rhs, lookahead's precedence)
                // lookahead := peek next token
                Binop::prec_rule(parser, stack, ops_prec_table[&op2]);
            }
            let (right_expression, left_expression) = stack_unpack!(stack, single, single);

            // lhs := the result of applying op with operands lhs and rhs
            stack.push_single(Box::new(Binop(op, left_expression, right_expression)));
        }
    }
}

// unop ::= ‘-’ | not | ‘#’ | ‘~’
#[derive(Debug)]
pub struct Unop(pub Keyword, pub Box<expressions::Expression>);
impl expressions::Expression for Unop {}

impl Unop {
    pub fn rule(parser: &mut parser::Parser, stack: &mut stack::Stack) -> bool {
        let terminals: HashSet<Keyword> =
            vec![Keyword::MINUS, Keyword::NOT, Keyword::HASH, Keyword::TILDA]
                .into_iter()
                .collect();

        if let Some(token) = parser.peek().cloned() {
            if let Some(keyword) = token.keyword() {
                if !terminals.contains(&keyword) {
                    return false;
                }

                parser.shift();

                if rules::exp_prefix(parser, stack) {
                    let expression = stack.pop_single();

                    stack.push_single(Box::new(Unop(keyword, expression)));
                    return true;
                } else {
                    panic!(format!(
                        "Expecter expressiion after unary operator, got {:?}",
                        parser.peek()
                    ))
                }
            }
        }

        false
    }
}

#[derive(Debug)]
pub struct Noop;
impl expressions::Expression for Noop {}

impl Noop {
    make_keyword_rule![semi, (Keyword::SEMICOLONS, Noop)];
}
<commit_msg>Minor cleanup<commit_after>use std::collections::{HashMap, HashSet};

use ast::expressions;
use ast::lexer::tokens::{self, Keyword};
use ast::parser;
use ast::rules;
use ast::stack;

const DEBUG: bool = false;

macro_rules! make_op_table {
    ($lrec_prec: ident, $([$($lrec: expr), +]), +) => {
        let mut $lrec_prec = HashMap::new();

        let mut prec: usize = 0;
        $(
            $(
                $lrec_prec.insert($lrec, prec);
            )+
            prec = prec + 1;
            let _compiler_friend = prec;
        )+
    };
}

// binop ::=  ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘//’ | ‘^’ | ‘%’ |
//        ‘&’ | ‘~’ | ‘|’ | ‘>>’ | ‘<<’ | ‘..’ |
//        ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ |
//        and | or
#[derive(Debug)]
pub struct Binop(
    pub Keyword,
    pub Box<expressions::Expression>,
    pub Box<expressions::Expression>,
);
impl expressions::Expression for Binop {}

impl Binop {
    // parse_expression () return parse_expression_1 (parse_primary (), 0)
    pub fn rule(parser: &mut parser::Parser, stack: &mut stack::Stack) -> bool {
        if !rules::exp_prefix(parser, stack) {
            return false;
        }

        Binop::prec_rule(parser, stack, 0);
        true
    }

    // https://en.wikipedia.org/wiki/Operator-precedence_parser
    pub fn prec_rule(
        parser: &mut parser::Parser,
        stack: &mut stack::Stack,
        precedence: usize,
    ) {
        // or
        // and
        // <     >     <=    >=    ~=    ==
        // |
        // ~
        // &
        // <<    >>
        // ..
        // +     -
        // *     /     //    %
        // ^
        make_op_table!(
            ops_prec_table,
            [Keyword::OR],
            [Keyword::AND],
            [
                Keyword::LESS,
                Keyword::LEQ,
                Keyword::GREATER,
                Keyword::GEQ,
                Keyword::EQ,
                Keyword::NEQ
            ],
            [Keyword::SOR],
            [Keyword::TILDA],
            [Keyword::SAND],
            [Keyword::SHRIGHT, Keyword::SHLEFT],
            [Keyword::DOT2],
            [Keyword::PLUS, Keyword::MINUS],
            [Keyword::MUL, Keyword::DIV, Keyword::MOD, Keyword::FLOORDIV],
            [Keyword::POW]
        );

        debug_parser!(
            "Entered precedence rule. Left: {:?}. Precedence: {}",
            stack.peek(),
            precedence
        );

        // lookahead := peek next token
        // while lookahead is a binary operator whose precedence is >= min_precedence
        while let Some(op) = parser.peek().and_then(|token| token.keyword()) {
            if !ops_prec_table.contains_key(&op) || ops_prec_table[&op] < precedence {
                return;
            }

            // op := lookahead
            // advance to next token
            parser.shift();

            // rhs := parse_primary ()
            if !rules::exp_prefix(parser, stack) {
                panic!(format!(
                    "Expecter expressiion after binary operator, got {:?}",
                    parser.peek()
                ))
            }

            // lookahead := peek next token
            while let Some(op2) = parser.peek().and_then(|token| token.keyword()) {
                // while lookahead is a binary operator whose precedence is greater
                // than op's, or a right-associative operator
                // whose precedence is equal to op's
                if !ops_prec_table.contains_key(&op2) || ops_prec_table[&op2] <= ops_prec_table[&op]
                {
                    break;
                }
                // rhs := parse_expression_1 (rhs, lookahead's precedence)
                // lookahead := peek next token
                Binop::prec_rule(parser, stack, ops_prec_table[&op2]);
            }
            let (right_expression, left_expression) = stack_unpack!(stack, single, single);

            // lhs := the result of applying op with operands lhs and rhs
            stack.push_single(Box::new(Binop(op, left_expression, right_expression)));
        }
    }
}

// unop ::= ‘-’ | not | ‘#’ | ‘~’
#[derive(Debug)]
pub struct Unop(pub Keyword, pub Box<expressions::Expression>);
impl expressions::Expression for Unop {}

impl Unop {
    pub fn rule(parser: &mut parser::Parser, stack: &mut stack::Stack) -> bool {
        let terminals: HashSet<Keyword> =
            vec![Keyword::MINUS, Keyword::NOT, Keyword::HASH, Keyword::TILDA]
                .into_iter()
                .collect();

        if let Some(token) = parser.peek().cloned() {
            if let Some(keyword) = token.keyword() {
                if !terminals.contains(&keyword) {
                    return false;
                }

                parser.shift();

                if rules::exp_prefix(parser, stack) {
                    let expression = stack.pop_single();

                    stack.push_single(Box::new(Unop(keyword, expression)));
                    return true;
                } else {
                    panic!(format!(
                        "Expecter expressiion after unary operator, got {:?}",
                        parser.peek()
                    ))
                }
            }
        }

        false
    }
}

#[derive(Debug)]
pub struct Noop;
impl expressions::Expression for Noop {}

impl Noop {
    make_keyword_rule![semi, (Keyword::SEMICOLONS, Noop)];
}
<|endoftext|>


<commit_before>use super::NodeId;

///
/// Describes the possible behaviors of the `Tree::remove_node` method.
///
pub enum RemoveBehavior {
    ///
    /// All children will be dropped recursively.  In other words, the entire sub-tree of the `Node`
    /// being removed will be dropped from the tree.  Those `Node`s will no longer exist and
    /// cannot be accessed even if you have the `NodeId` the previously pointed to them.
    ///
    /// This means even without using `Clone` you might end up with copies of invalid `NodeId`s.
    /// Use this behavior with caution.
    ///
    /// ```
    /// use id_tree::*;
    ///
    /// let mut tree: Tree<i32> = Tree::new();
    /// let root_id = tree.set_root(Node::new(0));
    ///
    /// let child_id = tree.insert_with_parent(Node::new(1), &root_id).ok().unwrap();
    /// let grandchild_id = tree.insert_with_parent(Node::new(2), &child_id).ok().unwrap();
    ///
    /// let child = tree.remove_node(child_id, RemoveBehavior::DropChildren).ok().unwrap();
    ///
    /// assert!(tree.get(&grandchild_id).is_err());
    /// assert_eq!(tree.get(&root_id).unwrap().children().len(), 0);
    /// ```
    ///
    DropChildren,

    ///
    /// If the removed `Node` (let's call it `A`) has a parent, `A`'s parent will become the
    /// parent of `A`'s children.  This effectively just shifts them up one level in the `Tree`.
    ///
    /// If `A` doesn't have a parent, then this behaves exactly like
    /// `RemoveBehavior::OrphanChildren`.
    ///
    /// ```
    /// use id_tree::*;
    ///
    /// let mut tree: Tree<i32> = Tree::new();
    /// let root_id = tree.set_root(Node::new(0));
    ///
    /// let child_id = tree.insert_with_parent(Node::new(1), &root_id).ok().unwrap();
    /// let grandchild_id = tree.insert_with_parent(Node::new(2), &child_id).ok().unwrap();
    ///
    /// let child = tree.remove_node(child_id, RemoveBehavior::LiftChildren).ok().unwrap();
    ///
    /// assert!(tree.get(&grandchild_id).is_ok());
    /// assert!(tree.get(&root_id).unwrap().children().contains(&grandchild_id));
    /// ```
    ///
    LiftChildren,

    ///
    /// All children will have their parent references cleared.  This means nothing will point to
    /// them, but they will still exist in the tree.  Those `Node`s can still be accessed provided
    /// that you have the `NodeId` that points to them.
    ///
    /// ```
    /// use id_tree::*;
    ///
    /// let mut tree: Tree<i32> = Tree::new();
    /// let root_id = tree.set_root(Node::new(0));
    ///
    /// let child_id = tree.insert_with_parent(Node::new(1), &root_id).ok().unwrap();
    /// let grandchild_id = tree.insert_with_parent(Node::new(2), &child_id).ok().unwrap();
    ///
    /// let child = tree.remove_node(child_id, RemoveBehavior::OrphanChildren).ok().unwrap();
    ///
    /// assert!(tree.get(&grandchild_id).is_ok());
    /// assert_eq!(tree.get(&root_id).unwrap().children().len(), 0);
    /// ```
    ///
    OrphanChildren,
}

///
/// Describes the possible behaviors of the `Tree::move_node` method.
///
pub enum MoveBehavior<'a> {
    ///
    /// Sets the `Node` in question as the new root `Node`, leaving all children in their place (in
    /// other words, they will travel with the `Node` being moved).
    ///
    /// If there is already a root `Node` in place, it will be attached as the last child of the new
    /// root.
    ///
    /// ```
    /// use id_tree::*;
    ///
    /// let mut tree: Tree<i32> = Tree::new();
    /// let root_id = tree.set_root(Node::new(1));
    ///
    /// let child_id = tree.insert_with_parent(Node::new(2),  &root_id).ok().unwrap();
    /// let grandchild_id = tree.insert_with_parent(Node::new(3), &child_id).ok().unwrap();
    ///
    /// tree.move_node(&grandchild_id, MoveBehavior::ToRoot).unwrap();
    ///
    /// assert_eq!(tree.root_node_id(), Some(&grandchild_id));
    /// assert!(tree.get(&grandchild_id).unwrap().children().contains(&root_id));
    /// assert!(!tree.get(&child_id).unwrap().children().contains(&grandchild_id));
    /// ```
    ///
    ToRoot,

    ///
    /// Moves a `Node` inside the `Tree` to a new parent leaving all children in their place.
    ///
    /// If the new parent (let's call it `B`) is a descendant of the `Node` being moved (`A`), then
    /// the direct child of `A` on the path from `A` to `B` will be shifted upwards to take the
    /// place of its parent (`A`).  All other children of `A` will be left alone, meaning they will
    /// travel with it down the `Tree`.
    ///
    /// Please note that during the "shift-up" part of the above scenario, the `Node` being shifted
    /// up will always be added as the last child of its new parent.
    ///
    /// ```
    /// use id_tree::*;
    ///
    /// let mut tree: Tree<i32> = Tree::new();
    /// let root_id = tree.set_root(Node::new(1));
    ///
    /// let first_child_id = tree.insert_with_parent(Node::new(2),  &root_id).ok().unwrap();
    /// let second_child_id = tree.insert_with_parent(Node::new(3), &root_id).ok().unwrap();
    /// let grandchild_id = tree.insert_with_parent(Node::new(4), &first_child_id).ok().unwrap();
    ///
    /// tree.move_node(&grandchild_id, MoveBehavior::ToParent(&second_child_id)).unwrap();
    ///
    /// assert!(!tree.get(&first_child_id).unwrap().children().contains(&grandchild_id));
    /// assert!(tree.get(&second_child_id).unwrap().children().contains(&grandchild_id));
    /// ```
    ///
    ToParent(&'a NodeId),
}
<commit_msg>add InsertBehavior<commit_after>use super::NodeId;

///
/// Describes the possible behaviors of the `Tree::remove_node` method.
///
pub enum RemoveBehavior {
    ///
    /// All children will be dropped recursively.  In other words, the entire sub-tree of the `Node`
    /// being removed will be dropped from the tree.  Those `Node`s will no longer exist and
    /// cannot be accessed even if you have the `NodeId` the previously pointed to them.
    ///
    /// This means even without using `Clone` you might end up with copies of invalid `NodeId`s.
    /// Use this behavior with caution.
    ///
    /// ```
    /// use id_tree::*;
    ///
    /// let mut tree: Tree<i32> = Tree::new();
    /// let root_id = tree.set_root(Node::new(0));
    ///
    /// let child_id = tree.insert_with_parent(Node::new(1), &root_id).ok().unwrap();
    /// let grandchild_id = tree.insert_with_parent(Node::new(2), &child_id).ok().unwrap();
    ///
    /// let child = tree.remove_node(child_id, RemoveBehavior::DropChildren).ok().unwrap();
    ///
    /// assert!(tree.get(&grandchild_id).is_err());
    /// assert_eq!(tree.get(&root_id).unwrap().children().len(), 0);
    /// ```
    ///
    DropChildren,

    ///
    /// If the removed `Node` (let's call it `A`) has a parent, `A`'s parent will become the
    /// parent of `A`'s children.  This effectively just shifts them up one level in the `Tree`.
    ///
    /// If `A` doesn't have a parent, then this behaves exactly like
    /// `RemoveBehavior::OrphanChildren`.
    ///
    /// ```
    /// use id_tree::*;
    ///
    /// let mut tree: Tree<i32> = Tree::new();
    /// let root_id = tree.set_root(Node::new(0));
    ///
    /// let child_id = tree.insert_with_parent(Node::new(1), &root_id).ok().unwrap();
    /// let grandchild_id = tree.insert_with_parent(Node::new(2), &child_id).ok().unwrap();
    ///
    /// let child = tree.remove_node(child_id, RemoveBehavior::LiftChildren).ok().unwrap();
    ///
    /// assert!(tree.get(&grandchild_id).is_ok());
    /// assert!(tree.get(&root_id).unwrap().children().contains(&grandchild_id));
    /// ```
    ///
    LiftChildren,

    ///
    /// All children will have their parent references cleared.  This means nothing will point to
    /// them, but they will still exist in the tree.  Those `Node`s can still be accessed provided
    /// that you have the `NodeId` that points to them.
    ///
    /// ```
    /// use id_tree::*;
    ///
    /// let mut tree: Tree<i32> = Tree::new();
    /// let root_id = tree.set_root(Node::new(0));
    ///
    /// let child_id = tree.insert_with_parent(Node::new(1), &root_id).ok().unwrap();
    /// let grandchild_id = tree.insert_with_parent(Node::new(2), &child_id).ok().unwrap();
    ///
    /// let child = tree.remove_node(child_id, RemoveBehavior::OrphanChildren).ok().unwrap();
    ///
    /// assert!(tree.get(&grandchild_id).is_ok());
    /// assert_eq!(tree.get(&root_id).unwrap().children().len(), 0);
    /// ```
    ///
    OrphanChildren,
}

///
/// Describes the possible behaviors of the `Tree::move_node` method.
///
pub enum MoveBehavior<'a> {
    ///
    /// Sets the `Node` in question as the new root `Node`, leaving all children in their place (in
    /// other words, they will travel with the `Node` being moved).
    ///
    /// If there is already a root `Node` in place, it will be attached as the last child of the new
    /// root.
    ///
    /// ```
    /// use id_tree::*;
    ///
    /// let mut tree: Tree<i32> = Tree::new();
    /// let root_id = tree.set_root(Node::new(1));
    ///
    /// let child_id = tree.insert_with_parent(Node::new(2),  &root_id).ok().unwrap();
    /// let grandchild_id = tree.insert_with_parent(Node::new(3), &child_id).ok().unwrap();
    ///
    /// tree.move_node(&grandchild_id, MoveBehavior::ToRoot).unwrap();
    ///
    /// assert_eq!(tree.root_node_id(), Some(&grandchild_id));
    /// assert!(tree.get(&grandchild_id).unwrap().children().contains(&root_id));
    /// assert!(!tree.get(&child_id).unwrap().children().contains(&grandchild_id));
    /// ```
    ///
    ToRoot,

    ///
    /// Moves a `Node` inside the `Tree` to a new parent leaving all children in their place.
    ///
    /// If the new parent (let's call it `B`) is a descendant of the `Node` being moved (`A`), then
    /// the direct child of `A` on the path from `A` to `B` will be shifted upwards to take the
    /// place of its parent (`A`).  All other children of `A` will be left alone, meaning they will
    /// travel with it down the `Tree`.
    ///
    /// Please note that during the "shift-up" part of the above scenario, the `Node` being shifted
    /// up will always be added as the last child of its new parent.
    ///
    /// ```
    /// use id_tree::*;
    ///
    /// let mut tree: Tree<i32> = Tree::new();
    /// let root_id = tree.set_root(Node::new(1));
    ///
    /// let first_child_id = tree.insert_with_parent(Node::new(2),  &root_id).ok().unwrap();
    /// let second_child_id = tree.insert_with_parent(Node::new(3), &root_id).ok().unwrap();
    /// let grandchild_id = tree.insert_with_parent(Node::new(4), &first_child_id).ok().unwrap();
    ///
    /// tree.move_node(&grandchild_id, MoveBehavior::ToParent(&second_child_id)).unwrap();
    ///
    /// assert!(!tree.get(&first_child_id).unwrap().children().contains(&grandchild_id));
    /// assert!(tree.get(&second_child_id).unwrap().children().contains(&grandchild_id));
    /// ```
    ///
    ToParent(&'a NodeId),
}

///
/// Describes the possible behaviors of the `Tree::insert` method.
///
pub enum InsertBehavior<'a> {
    AsRoot,
    UnderNode(&'a NodeId),
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

extern crate brain;

use std::process;
use std::io::prelude::*;
use std::fs::File;
use std::path::{Path, PathBuf};

use clap::{Arg, App};

use brain::parser::{Program, ParseError};
use brain::operations::scope::ScopeStack;
use brain::codegen::Instructions;
use brain::optimizations::{OptimizationLevel, Optimize};
use brain::prelude;

macro_rules! exit_with_error(
    ($($arg:tt)*) => { {
        writeln!(&mut ::std::io::stderr(), $($arg)*)
            .expect("Failed while printing to stderr");
        process::exit(1);
    } }
);

fn main() {
    let args = App::new(crate_name!())
        .version(crate_version!())
        .version_short("v")
        .author(crate_authors!())
        .about(crate_description!())
        .arg(Arg::with_name("input-file")
            .help("The brain file to process")
            .value_name("file")
            .takes_value(true)
            .required(true)
        )
        .arg(Arg::with_name("output-file")
            .short("o")
            .help("Write output to <target>")
            .value_name("target")
            .takes_value(true)
        )
        .get_matches();

    let source_path = Path::new(args.value_of("input-file").unwrap());
    if !source_path.exists() || !source_path.is_file() {
        exit_with_error!("Not a valid file: '{}'", source_path.display());
    }

    let output_path = args.value_of("output-file").map_or_else(|| {
        let mut path = PathBuf::from(source_path.file_name().and_then(|s| s.to_str()).unwrap_or(""));
        path.set_extension("bf");
        path
    }, |s| PathBuf::from(s));

    let mut source_file = File::open(source_path).unwrap_or_else(|e| {
        exit_with_error!("Could not open source file: {}", e);
    });
    let mut source = String::new();
    source_file.read_to_string(&mut source).unwrap_or_else(|e| {
        exit_with_error!("Could not read source file: {}", e);
    });

    let generated_code: String = compile(source);
    println!("{:?}", generated_code);

    let mut output_file = File::create(output_path).unwrap_or_else(|e| {
        exit_with_error!("Could not create target file: {}", e);
    });
    output_file.write_all(generated_code.as_bytes()).and_then(|_| {
        // Write a newline because that's how a line is defined
        // http://stackoverflow.com/a/729795/551904
        output_file.write(&['\n' as u8])
    }).unwrap_or_else(|e| {
        exit_with_error!("Could not write target file: {}", e);
    });
}

/// Compile the provided source code to brainfuck
fn compile(source: String) -> String {
    let program: Program = source.parse().unwrap_or_else(|e: ParseError| {
        exit_with_error!("Syntax Error: {}", e);
    });

    let mut global_scope = ScopeStack::new();
    prelude::populate_scope(&mut global_scope);
    let operations = program.into_operations(&mut global_scope).unwrap_or_else(|error| {
        println!("{:?}", error);
        // Print the error properly
        unimplemented!();
    });
    println!("{:#?}", operations);

    let instructions: Instructions = operations.into();

    instructions.optimize(OptimizationLevel::L1).into()
}
<commit_msg>Replaced writeln to stderr with eprintln<commit_after>#[macro_use]
extern crate clap;

extern crate brain;

use std::process;
use std::io::prelude::*;
use std::fs::File;
use std::path::{Path, PathBuf};

use clap::{Arg, App};

use brain::parser::{Program, ParseError};
use brain::operations::scope::ScopeStack;
use brain::codegen::Instructions;
use brain::optimizations::{OptimizationLevel, Optimize};
use brain::prelude;

macro_rules! exit_with_error(
    ($($arg:tt)*) => { {
        eprintln!($($arg)*);
        process::exit(1);
    } }
);

fn main() {
    let args = App::new(crate_name!())
        .version(crate_version!())
        .version_short("v")
        .author(crate_authors!())
        .about(crate_description!())
        .arg(Arg::with_name("input-file")
            .help("The brain file to process")
            .value_name("file")
            .takes_value(true)
            .required(true)
        )
        .arg(Arg::with_name("output-file")
            .short("o")
            .help("Write output to <target>")
            .value_name("target")
            .takes_value(true)
        )
        .get_matches();

    let source_path = Path::new(args.value_of("input-file").unwrap());
    if !source_path.exists() || !source_path.is_file() {
        exit_with_error!("Not a valid file: '{}'", source_path.display());
    }

    let output_path = args.value_of("output-file").map_or_else(|| {
        let mut path = PathBuf::from(source_path.file_name().and_then(|s| s.to_str()).unwrap_or(""));
        path.set_extension("bf");
        path
    }, |s| PathBuf::from(s));

    let mut source_file = File::open(source_path).unwrap_or_else(|e| {
        exit_with_error!("Could not open source file: {}", e);
    });
    let mut source = String::new();
    source_file.read_to_string(&mut source).unwrap_or_else(|e| {
        exit_with_error!("Could not read source file: {}", e);
    });

    let generated_code: String = compile(source);
    println!("{:?}", generated_code);

    let mut output_file = File::create(output_path).unwrap_or_else(|e| {
        exit_with_error!("Could not create target file: {}", e);
    });
    output_file.write_all(generated_code.as_bytes()).and_then(|_| {
        // Write a newline because that's how a line is defined
        // http://stackoverflow.com/a/729795/551904
        output_file.write(&['\n' as u8])
    }).unwrap_or_else(|e| {
        exit_with_error!("Could not write target file: {}", e);
    });
}

/// Compile the provided source code to brainfuck
fn compile(source: String) -> String {
    let program: Program = source.parse().unwrap_or_else(|e: ParseError| {
        exit_with_error!("Syntax Error: {}", e);
    });

    let mut global_scope = ScopeStack::new();
    prelude::populate_scope(&mut global_scope);
    let operations = program.into_operations(&mut global_scope).unwrap_or_else(|error| {
        println!("{:?}", error);
        // Print the error properly
        unimplemented!();
    });
    println!("{:#?}", operations);

    let instructions: Instructions = operations.into();

    instructions.optimize(OptimizationLevel::L1).into()
}
<|endoftext|>


<commit_before>use proc_macro2::TokenStream;

use syn::DeriveInput;
use syn::spanned::Spanned;
use syn::parse::Error;
use quote::{quote, ToTokens as _};

use default_attr::{DefaultAttr, ConversionStrategy};
use util::find_only;

pub fn impl_my_derive(input: &DeriveInput) -> Result<TokenStream, Error> {
    let name = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let (default_expr, doc) = match input.data {
        syn::Data::Struct(ref body) => {
            let (body_assignment, doc) = default_body_tt(&body.fields)?;
            (quote! {
                #name #body_assignment
            }, format!("Return `{}{}`", name, doc))
        }
        syn::Data::Enum(ref body) => {
            let default_variant = find_only(body.variants.iter(), |variant| {
                if let Some(meta) = DefaultAttr::find_in_attributes(&variant.attrs)? {
                    if meta.code.is_none() {
                        Ok(true)
                    } else {
                        Err(Error::new(meta.code.span(), "Attribute #[default] on variants should have no value"))
                    }
                } else {
                    Ok(false)
                }
            })?.ok_or_else(|| Error::new(input.span(), "No default variant"))?;
            let default_variant_name = &default_variant.ident;
            let (body_assignment, doc) = default_body_tt(&default_variant.fields)?;
            (quote! {
                #name :: #default_variant_name #body_assignment
            }, format!("Return `{}::{}{}`", name, default_variant_name, doc))
        }
        syn::Data::Union(_) => {
            panic!()
        }
    };
    Ok(quote! {
        impl #impl_generics Default for #name #ty_generics #where_clause {
            #[doc = #doc]
            fn default() -> Self {
                #default_expr
            }
        }
    })
}

/// Return a token-tree for the default "body" - the part after the name that contains the values.
/// That is, the `{ ... }` part for structs, the `(...)` part for tuples, and nothing for units.
fn default_body_tt(body: &syn::Fields) -> Result<(TokenStream, String), Error> {
    let mut doc = String::new();
    use std::fmt::Write;
    let body_tt = match body {
        &syn::Fields::Named(ref fields) => {
            doc.push_str(" {");
            let result = {
                let field_assignments = fields.named.iter().map(|field| {
                    let field_name = field.ident.as_ref();
                    let (default_value, default_doc) = field_default_expr_and_doc(field)?;
                    write!(&mut doc, "\n    {}: {},", field_name.expect("field value in struct is empty"), default_doc).unwrap();
                    // let default_value = default_value.into_token_stream();
                    Ok(quote! { #field_name : #default_value })
                }).collect::<Result<Vec<_>, Error>>()?;
                quote!{
                    {
                        #( #field_assignments ),*
                    }
                }
            };
            if (&mut doc).ends_with(",") {
                doc.pop();
                doc.push('\n');
            };
            doc.push('}');
            result
        }
        &syn::Fields::Unnamed(ref fields) => {
            doc.push('(');
            let result = {
                let field_assignments = fields.unnamed.iter().map(|field| {
                    let (default_value, default_doc) = field_default_expr_and_doc(field)?;
                    write!(&mut doc, "{}, ", default_doc).unwrap();
                    Ok(default_value)
                }).collect::<Result<Vec<TokenStream>, Error>>()?;
                quote! {
                    (
                        #( #field_assignments ),*
                    )
                }
            };
            if (&mut doc).ends_with(", ") {
                doc.pop();
                doc.pop();
            };
            doc.push(')');
            result
        }
        &syn::Fields::Unit => quote!{},
    };
    Ok((body_tt, doc))
}

/// Return a default expression for a field based on it's `#[default = "..."]` attribute. Panic
/// if there is more than one, of if there is a `#[default]` attribute without value.
fn field_default_expr_and_doc(field: &syn::Field) -> Result<(TokenStream, String), Error> {
    if let Some(default_attr) = DefaultAttr::find_in_attributes(&field.attrs)? {
        let conversion_strategy = default_attr.conversion_strategy();
        let field_value = default_attr.code.ok_or_else(|| {
            Error::new(field.span(), "Expected #[default = ...] or #[default(...)]")})?;

        let field_value = match conversion_strategy {
            ConversionStrategy::NoConversion => field_value,
            ConversionStrategy::Into => quote!((#field_value).into()),
        };

        let field_doc = format!("{}", field_value);
        Ok((field_value, field_doc))
    } else {
        let field_type = field.ty.clone().into_token_stream();
        Ok((quote! {
            <#field_type as core::default::Default>::default()
        }, "Default::default()".to_owned()))
    }
}
<commit_msg>Fix Default trait naming<commit_after>use proc_macro2::TokenStream;

use syn::DeriveInput;
use syn::spanned::Spanned;
use syn::parse::Error;
use quote::{quote, ToTokens as _};

use default_attr::{DefaultAttr, ConversionStrategy};
use util::find_only;

pub fn impl_my_derive(input: &DeriveInput) -> Result<TokenStream, Error> {
    let name = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let (default_expr, doc) = match input.data {
        syn::Data::Struct(ref body) => {
            let (body_assignment, doc) = default_body_tt(&body.fields)?;
            (quote! {
                #name #body_assignment
            }, format!("Return `{}{}`", name, doc))
        }
        syn::Data::Enum(ref body) => {
            let default_variant = find_only(body.variants.iter(), |variant| {
                if let Some(meta) = DefaultAttr::find_in_attributes(&variant.attrs)? {
                    if meta.code.is_none() {
                        Ok(true)
                    } else {
                        Err(Error::new(meta.code.span(), "Attribute #[default] on variants should have no value"))
                    }
                } else {
                    Ok(false)
                }
            })?.ok_or_else(|| Error::new(input.span(), "No default variant"))?;
            let default_variant_name = &default_variant.ident;
            let (body_assignment, doc) = default_body_tt(&default_variant.fields)?;
            (quote! {
                #name :: #default_variant_name #body_assignment
            }, format!("Return `{}::{}{}`", name, default_variant_name, doc))
        }
        syn::Data::Union(_) => {
            panic!()
        }
    };
    Ok(quote! {
        impl #impl_generics Default for #name #ty_generics #where_clause {
            #[doc = #doc]
            fn default() -> Self {
                #default_expr
            }
        }
    })
}

/// Return a token-tree for the default "body" - the part after the name that contains the values.
/// That is, the `{ ... }` part for structs, the `(...)` part for tuples, and nothing for units.
fn default_body_tt(body: &syn::Fields) -> Result<(TokenStream, String), Error> {
    let mut doc = String::new();
    use std::fmt::Write;
    let body_tt = match body {
        &syn::Fields::Named(ref fields) => {
            doc.push_str(" {");
            let result = {
                let field_assignments = fields.named.iter().map(|field| {
                    let field_name = field.ident.as_ref();
                    let (default_value, default_doc) = field_default_expr_and_doc(field)?;
                    write!(&mut doc, "\n    {}: {},", field_name.expect("field value in struct is empty"), default_doc).unwrap();
                    // let default_value = default_value.into_token_stream();
                    Ok(quote! { #field_name : #default_value })
                }).collect::<Result<Vec<_>, Error>>()?;
                quote!{
                    {
                        #( #field_assignments ),*
                    }
                }
            };
            if (&mut doc).ends_with(",") {
                doc.pop();
                doc.push('\n');
            };
            doc.push('}');
            result
        }
        &syn::Fields::Unnamed(ref fields) => {
            doc.push('(');
            let result = {
                let field_assignments = fields.unnamed.iter().map(|field| {
                    let (default_value, default_doc) = field_default_expr_and_doc(field)?;
                    write!(&mut doc, "{}, ", default_doc).unwrap();
                    Ok(default_value)
                }).collect::<Result<Vec<TokenStream>, Error>>()?;
                quote! {
                    (
                        #( #field_assignments ),*
                    )
                }
            };
            if (&mut doc).ends_with(", ") {
                doc.pop();
                doc.pop();
            };
            doc.push(')');
            result
        }
        &syn::Fields::Unit => quote!{},
    };
    Ok((body_tt, doc))
}

/// Return a default expression for a field based on it's `#[default = "..."]` attribute. Panic
/// if there is more than one, of if there is a `#[default]` attribute without value.
fn field_default_expr_and_doc(field: &syn::Field) -> Result<(TokenStream, String), Error> {
    if let Some(default_attr) = DefaultAttr::find_in_attributes(&field.attrs)? {
        let conversion_strategy = default_attr.conversion_strategy();
        let field_value = default_attr.code.ok_or_else(|| {
            Error::new(field.span(), "Expected #[default = ...] or #[default(...)]")})?;

        let field_value = match conversion_strategy {
            ConversionStrategy::NoConversion => field_value,
            ConversionStrategy::Into => quote!((#field_value).into()),
        };

        let field_doc = format!("{}", field_value);
        Ok((field_value, field_doc))
    } else {
        let field_type = field.ty.clone().into_token_stream();
        Ok((quote! {
            <#field_type as Default>::default()
        }, "Default::default()".to_owned()))
    }
}
<|endoftext|>