<commit_before>//taken from https://github.com/gz/rust-x86   src/paging.rs
use core::fmt;

pub type PAddr = u64;
pub type VAddr = usize;

pub const BASE_PAGE_SIZE: u64 = 4096; // 4 KiB
pub const LARGE_PAGE_SIZE: u64 = 1024*1024*2; // 2 MiB
pub const HUGE_PAGE_SIZE: u64 = 1024*1024*1024; // 1 GiB
pub const CACHE_LINE_SIZE: usize = 64; // 64 Bytes

/// MAXPHYADDR, which is at most 52; (use CPUID for finding system value).
pub const MAXPHYADDR: u64 = 52;

/// Mask to find the physical address of an entry in a page-table.
const ADDRESS_MASK: u64 = ((1 << MAXPHYADDR) - 1) & !0xfff;

/// A PML4 table.
/// In practice this has only 4 entries but it still needs to be the size of a 4K page.
pub type PML4  = [PML4Entry; 512];

/// A page directory pointer table.
pub type PDPT  = [PDPTEntry; 512];

/// A page directory.
pub type PD    = [PDEntry; 512];

/// A page table.
pub type PT    = [PTEntry; 512];

/// Given virtual address calculate corresponding entry in PML4.
pub fn pml4_index(addr: VAddr) -> usize {
    (addr >> 39) & 0b111111111
}

/// Given virtual address calculate corresponding entry in PDPT.
#[inline]
pub fn pdpt_index(addr: VAddr) -> usize {
    (addr >> 30) & 0b111111111
}

/// Given virtual address calculate corresponding entry in PD.
#[inline]
pub fn pd_index(addr: VAddr) -> usize {
    (addr >> 21) & 0b111111111
}

/// Given virtual address calculate corresponding entry in PT.
#[inline]
pub fn pt_index(addr: VAddr) -> usize {
    (addr >> 12) & 0b111111111
}

/// PML4 Entry bits description.
bitflags! {
    flags PML4Entry: u64 {
        /// Present; must be 1 to reference a page-directory-pointer table
        const PML4_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 512-GByte region
        /// controlled by this entry (see Section 4.6)
        const PML4_RW      = 0b00000010,
        /// User/supervisor; if 0, user-mode accesses are not allowed
        /// to the 512-GByte region controlled by this entry.
        const PML4_US      = 0b00000100,
        /// Page-level write-through; indirectly determines the memory type used to
        /// access the page-directory-pointer table referenced by this entry.
        const PML4_PWT     = 0b00001000,
        /// Page-level cache disable; indirectly determines the memory type used to
        /// access the page-directory-pointer table referenced by this entry.
        const PML4_PCD     = 0b00010000,
        /// Accessed; indicates whether this entry has been used for linear-address translation.
        const PML4_A       = 0b00100000,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PML4_XD      = 1 << 63,
    }
}

impl PML4Entry {

    /// Creates a new PML4Entry.
    ///
    /// # Arguments
    ///
    ///  * `pdpt` - The physical address of the pdpt table.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(pdpt: PAddr, flags: PML4Entry) -> PML4Entry {
        assert!(pdpt % BASE_PAGE_SIZE == 0);
        PML4Entry { bits: pdpt | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PML4_P)
    }
}

impl fmt::Debug for PML4Entry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.bits)
    }
}

/// PDPT Entry bits description.
bitflags! {
    flags PDPTEntry: u64 {
        /// Present; must be 1 to map a 1-GByte page or reference a page directory.
        const PDPT_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 1-GByte region controlled by this entry
        const PDPT_RW      = 0b00000010,
        /// User/supervisor; user-mode accesses are not allowed to the 1-GByte region controlled by this entry.
        const PDPT_US      = 0b00000100,
        /// Page-level write-through.
        const PDPT_PWT     = 0b00001000,
        /// Page-level cache disable.
        const PDPT_PCD     = 0b00010000,
        /// Accessed; if PDPT_PS set indicates whether software has accessed the 1-GByte page
        /// else indicates whether this entry has been used for linear-address translation
        const PDPT_A       = 0b00100000,
        /// Dirty; if PDPT_PS indicates whether software has written to the 1-GByte page referenced by this entry.
        /// else ignored.
        const PDPT_D       = 0b01000000,
        /// Page size; if set this entry maps a 1-GByte page; otherwise, this entry references a page directory.
        /// if not PDPT_PS this is ignored.
        const PDPT_PS      = 0b10000000,
        /// Global; if PDPT_PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise
        /// if not PDPT_PS this is ignored.
        const PDPT_G       = 1<<8,
        /// Indirectly determines the memory type used to access the 1-GByte page referenced by this entry.
        const PDPT_PAT     = 1<<12,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PDPT_XD      = 1 << 63,
    }
}

impl PDPTEntry {

    /// Creates a new PDPTEntry.
    ///
    /// # Arguments
    ///
    ///  * `pd` - The physical address of the page directory.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(pd: PAddr, flags: PDPTEntry) -> PDPTEntry {
        assert!(pd % BASE_PAGE_SIZE == 0);
        PDPTEntry { bits: pd | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PDPT_P)
    }
}

impl fmt::Debug for PDPTEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.bits)
    }
}

/// PD Entry bits description.
bitflags! {
    flags PDEntry: u64 {
        /// Present; must be 1 to map a 2-MByte page or reference a page table.
        const PD_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 2-MByte region controlled by this entry
        const PD_RW      = 0b00000010,
        /// User/supervisor; user-mode accesses are not allowed to the 2-MByte region controlled by this entry.
        const PD_US      = 0b00000100,
        /// Page-level write-through.
        const PD_PWT     = 0b00001000,
        /// Page-level cache disable.
        const PD_PCD     = 0b00010000,
        /// Accessed; if PD_PS set indicates whether software has accessed the 2-MByte page
        /// else indicates whether this entry has been used for linear-address translation
        const PD_A       = 0b00100000,
        /// Dirty; if PD_PS indicates whether software has written to the 2-MByte page referenced by this entry.
        /// else ignored.
        const PD_D       = 0b01000000,
        /// Page size; if set this entry maps a 2-MByte page; otherwise, this entry references a page directory.
        const PD_PS      = 0b10000000,
        /// Global; if PD_PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise
        /// if not PD_PS this is ignored.
        const PD_G       = 1<<8,
        /// Indirectly determines the memory type used to access the 2-MByte page referenced by this entry.
        /// if not PD_PS this is ignored.
        const PD_PAT     = 1<<12,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PD_XD      = 1 << 63,
    }
}

impl PDEntry {

    /// Creates a new PDEntry.
    ///
    /// # Arguments
    ///
    ///  * `pt` - The physical address of the page table.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(pt: PAddr, flags: PDEntry) -> PDEntry {
        assert!(pt % BASE_PAGE_SIZE == 0);
        PDEntry { bits: pt | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PD_P)
    }
}

impl fmt::Debug for PDEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.bits)
    }
}

/// PT Entry bits description.
bitflags! {
    flags PTEntry: u64 {
        /// Present; must be 1 to map a 4-KByte page.
        const PT_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 4-KByte region controlled by this entry
        const PT_RW      = 0b00000010,
        /// User/supervisor; user-mode accesses are not allowed to the 4-KByte region controlled by this entry.
        const PT_US      = 0b00000100,
        /// Page-level write-through.
        const PT_PWT     = 0b00001000,
        /// Page-level cache disable.
        const PT_PCD     = 0b00010000,
        /// Accessed; indicates whether software has accessed the 4-KByte page
        const PT_A       = 0b00100000,
        /// Dirty; indicates whether software has written to the 4-KByte page referenced by this entry.
        const PT_D       = 0b01000000,
        /// Global; if CR4.PGE = 1, determines whether the translation is global (see Section 4.10); ignored otherwise
        const PT_G       = 1<<8,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PT_XD      = 1 << 63,
    }
}

impl PTEntry {

    /// Creates a new PTEntry.
    ///
    /// # Arguments
    ///
    ///  * `page` - The physical address of the backing 4 KiB page.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(page: PAddr, flags: PTEntry) -> PTEntry {
        assert!(page % BASE_PAGE_SIZE == 0);
        PTEntry{ bits: page | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PT_P)
    }
}

impl fmt::Debug for PTEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.bits)
    }
}
<commit_msg>changed to newer version of bitflags<commit_after>//taken from https://github.com/gz/rust-x86   src/paging.rs
use core::fmt;

pub type PAddr = u64;
pub type VAddr = usize;

pub const BASE_PAGE_SIZE: u64 = 1024 * 4; // 4 KiB
pub const LARGE_PAGE_SIZE: u64 = 1024 * 1024 * 2; // 2 MiB
pub const HUGE_PAGE_SIZE: u64 = 1024 * 1024 * 1024; // 1 GiB
pub const CACHE_LINE_SIZE: usize = 64; // 64 Bytes

/// MAXPHYADDR, which is at most 52; (use CPUID for finding system value).
pub const MAXPHYADDR: u64 = 52;

/// Mask to find the physical address of an entry in a page-table.
const ADDRESS_MASK: u64 = ((1 << MAXPHYADDR) - 1) & !0xfff;

/// A PML4 table.
/// In practice this has only 4 entries but it still needs to be the size of a 4K page.
pub type PML4  = [PML4Entry; 512];

/// A page directory pointer table.
pub type PDPT  = [PDPTEntry; 512];

/// A page directory.
pub type PD    = [PDEntry; 512];

/// A page table.
pub type PT    = [PTEntry; 512];

/// Given virtual address calculate corresponding entry in PML4.
pub fn pml4_index(addr: VAddr) -> usize {
    (addr >> 39) & 0b111111111
}

/// Given virtual address calculate corresponding entry in PDPT.
#[inline]
pub fn pdpt_index(addr: VAddr) -> usize {
    (addr >> 30) & 0b111111111
}

/// Given virtual address calculate corresponding entry in PD.
#[inline]
pub fn pd_index(addr: VAddr) -> usize {
    (addr >> 21) & 0b111111111
}

/// Given virtual address calculate corresponding entry in PT.
#[inline]
pub fn pt_index(addr: VAddr) -> usize {
    (addr >> 12) & 0b111111111
}

/// PML4 Entry bits description.
bitflags! {
    flags PML4Entry: u64 {
        /// Present; must be 1 to reference a page-directory-pointer table
        const PML4_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 512-GByte region
        /// controlled by this entry (see Section 4.6)
        const PML4_RW      = 0b00000010,
        /// User/supervisor; if 0, user-mode accesses are not allowed
        /// to the 512-GByte region controlled by this entry.
        const PML4_US      = 0b00000100,
        /// Page-level write-through; indirectly determines the memory type used to
        /// access the page-directory-pointer table referenced by this entry.
        const PML4_PWT     = 0b00001000,
        /// Page-level cache disable; indirectly determines the memory type used to
        /// access the page-directory-pointer table referenced by this entry.
        const PML4_PCD     = 0b00010000,
        /// Accessed; indicates whether this entry has been used for linear-address translation.
        const PML4_A       = 0b00100000,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PML4_XD      = 1 << 63,
    }
}

impl PML4Entry {

    /// Creates a new PML4Entry.
    ///
    /// # Arguments
    ///
    ///  * `pdpt` - The physical address of the pdpt table.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(pdpt: PAddr, flags: PML4Entry) -> PML4Entry {
        assert!(pdpt % BASE_PAGE_SIZE == 0);
        PML4Entry { bits: pdpt | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PML4_P)
    }
}

/// PDPT Entry bits description.
bitflags! {
    flags PDPTEntry: u64 {
        /// Present; must be 1 to map a 1-GByte page or reference a page directory.
        const PDPT_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 1-GByte region controlled by this entry
        const PDPT_RW      = 0b00000010,
        /// User/supervisor; user-mode accesses are not allowed to the 1-GByte region controlled by this entry.
        const PDPT_US      = 0b00000100,
        /// Page-level write-through.
        const PDPT_PWT     = 0b00001000,
        /// Page-level cache disable.
        const PDPT_PCD     = 0b00010000,
        /// Accessed; if PDPT_PS set indicates whether software has accessed the 1-GByte page
        /// else indicates whether this entry has been used for linear-address translation
        const PDPT_A       = 0b00100000,
        /// Dirty; if PDPT_PS indicates whether software has written to the 1-GByte page referenced by this entry.
        /// else ignored.
        const PDPT_D       = 0b01000000,
        /// Page size; if set this entry maps a 1-GByte page; otherwise, this entry references a page directory.
        /// if not PDPT_PS this is ignored.
        const PDPT_PS      = 0b10000000,
        /// Global; if PDPT_PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise
        /// if not PDPT_PS this is ignored.
        const PDPT_G       = 1<<8,
        /// Indirectly determines the memory type used to access the 1-GByte page referenced by this entry.
        const PDPT_PAT     = 1<<12,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PDPT_XD      = 1 << 63,
    }
}

impl PDPTEntry {

    /// Creates a new PDPTEntry.
    ///
    /// # Arguments
    ///
    ///  * `pd` - The physical address of the page directory.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(pd: PAddr, flags: PDPTEntry) -> PDPTEntry {
        assert!(pd % BASE_PAGE_SIZE == 0);
        PDPTEntry { bits: pd | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PDPT_P)
    }
}

/// PD Entry bits description.
bitflags! {
    flags PDEntry: u64 {
        /// Present; must be 1 to map a 2-MByte page or reference a page table.
        const PD_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 2-MByte region controlled by this entry
        const PD_RW      = 0b00000010,
        /// User/supervisor; user-mode accesses are not allowed to the 2-MByte region controlled by this entry.
        const PD_US      = 0b00000100,
        /// Page-level write-through.
        const PD_PWT     = 0b00001000,
        /// Page-level cache disable.
        const PD_PCD     = 0b00010000,
        /// Accessed; if PD_PS set indicates whether software has accessed the 2-MByte page
        /// else indicates whether this entry has been used for linear-address translation
        const PD_A       = 0b00100000,
        /// Dirty; if PD_PS indicates whether software has written to the 2-MByte page referenced by this entry.
        /// else ignored.
        const PD_D       = 0b01000000,
        /// Page size; if set this entry maps a 2-MByte page; otherwise, this entry references a page directory.
        const PD_PS      = 0b10000000,
        /// Global; if PD_PS && CR4.PGE = 1, determines whether the translation is global; ignored otherwise
        /// if not PD_PS this is ignored.
        const PD_G       = 1<<8,
        /// Indirectly determines the memory type used to access the 2-MByte page referenced by this entry.
        /// if not PD_PS this is ignored.
        const PD_PAT     = 1<<12,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PD_XD      = 1 << 63,
    }
}

impl PDEntry {

    /// Creates a new PDEntry.
    ///
    /// # Arguments
    ///
    ///  * `pt` - The physical address of the page table.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(pt: PAddr, flags: PDEntry) -> PDEntry {
        assert!(pt % BASE_PAGE_SIZE == 0);
        PDEntry { bits: pt | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PD_P)
    }
}

/// PT Entry bits description.
bitflags! {
    flags PTEntry: u64 {
        /// Present; must be 1 to map a 4-KByte page.
        const PT_P       = 0b00000001,
        /// Read/write; if 0, writes may not be allowed to the 4-KByte region controlled by this entry
        const PT_RW      = 0b00000010,
        /// User/supervisor; user-mode accesses are not allowed to the 4-KByte region controlled by this entry.
        const PT_US      = 0b00000100,
        /// Page-level write-through.
        const PT_PWT     = 0b00001000,
        /// Page-level cache disable.
        const PT_PCD     = 0b00010000,
        /// Accessed; indicates whether software has accessed the 4-KByte page
        const PT_A       = 0b00100000,
        /// Dirty; indicates whether software has written to the 4-KByte page referenced by this entry.
        const PT_D       = 0b01000000,
        /// Global; if CR4.PGE = 1, determines whether the translation is global (see Section 4.10); ignored otherwise
        const PT_G       = 1<<8,
        /// If IA32_EFER.NXE = 1, execute-disable
        /// If 1, instruction fetches are not allowed from the 512-GByte region.
        const PT_XD      = 1 << 63,
    }
}

impl PTEntry {

    /// Creates a new PTEntry.
    ///
    /// # Arguments
    ///
    ///  * `page` - The physical address of the backing 4 KiB page.
    ///  * `flags`- Additional flags for the entry.
    pub fn new(page: PAddr, flags: PTEntry) -> PTEntry {
        assert!(page % BASE_PAGE_SIZE == 0);
        PTEntry{ bits: page | flags.bits }
    }

    /// Retrieves the physical address in this entry.
    pub fn get_address(self) -> PAddr {
        self.bits & ADDRESS_MASK
    }

    /// Convenience function to check if the present bit is set.
    pub fn is_present(self) -> bool {
        self.contains(PT_P)
    }
}
<|endoftext|>


<commit_before>use bios_boot_device::{BIOSBootDeviceTag, BootDevice};
use boot_command_line::BootCommandLineTag;
use boot_loader_name::BootLoaderNameTag;
use memory_map::{MemoryMapTag, MemoryMapIter};
use tag::{TagType, Tag, TagIter};
use basic_memory_information::BasicMemoryInformationTag;
use end_tag;
use module::{ModuleIter};

pub unsafe fn load(multiboot_addr: u32) -> &'static MultiBootInfo  {
    let multiboot_info = MultiBootInfo::from_raw_parts(multiboot_addr);
    assert!(multiboot_info.has_valid_end_tag());
    multiboot_info
}

#[derive(Debug)]
#[repr(C)]
pub struct MultiBootInfo {
    total_size: u32,
    reserved: u32,      // Should always be 0.
    first_tag: Tag
}

impl MultiBootInfo {
    unsafe fn from_raw_parts(multiboot_addr: u32) -> &'static MultiBootInfo {
        &*(multiboot_addr as *const MultiBootInfo)
    }

    pub fn start_address(&self) -> usize {
        self as *const _ as usize
    }

    pub fn end_address(&self) -> usize {
        self.start_address() + self.total_size()
    }

    pub fn total_size(&self) -> usize {
        self.total_size as usize
    }

    pub fn mem_lower(&self) -> Option<usize> {
        self.cast_find_tag::<BasicMemoryInformationTag>(TagType::MemoryInformation)
            .map(|tag| { tag.mem_lower() })
    }

    pub fn mem_upper(&self) -> Option<usize> {
        self.cast_find_tag::<BasicMemoryInformationTag>(TagType::MemoryInformation)
            .map(|tag| { tag.mem_upper() })
    }

    pub fn bios_boot_device(&self) -> Option<BootDevice> {
        self.cast_find_tag::<BIOSBootDeviceTag>(TagType::BIOSBootDevice)
            .map(|tag| {
                BootDevice::new(tag.biosdev, tag.partition, tag.sub_partition)
            })
    }

    pub fn boot_cmd_line(&self) -> Option<&str> {
        self.cast_find_tag::<BootCommandLineTag>(TagType::BootCommandLine)
            .map(|tag| { tag.string() })
    }

    pub fn boot_loader_name(&self) -> Option<&str> {
        self.cast_find_tag::<BootLoaderNameTag>(TagType::BootCommandLine)
            .map(|tag| { tag.string() })
    }

    pub fn memory_map(&self) -> Option<MemoryMapIter> {
        self.cast_find_tag::<MemoryMapTag>(TagType::MemoryMap)
            .map(|tag| { tag.memory_regions() })
    }

    pub fn modules(&self) -> ModuleIter {
        ModuleIter::new(self.tags())
    }

    fn has_valid_end_tag(&self) -> bool {
        let end_tag_ptr = self.end_address() - end_tag::END_TAG_SIZE;
        let end_tag = unsafe {
            &*(end_tag_ptr as *const end_tag::EndTag)
        };

        end_tag.is_valid()
    }

    fn tags(&self) -> TagIter {
        TagIter::new(&self.first_tag)
    }

    fn find_tag(&self, tag_type: TagType) -> Option<&'static Tag> {
        self.tags().find(|tag| { tag.tag_type() == tag_type as usize })
    }

    fn cast_find_tag<T>(&self, tag_type: TagType) -> Option <&T> {
        self.find_tag(tag_type).map(|tag_ptr| {
            unsafe {
                tag_ptr.cast::<T>()
            }
        })
    }
}
<commit_msg>Minor refactoring<commit_after>use bios_boot_device::{BIOSBootDeviceTag, BootDevice};
use boot_command_line::BootCommandLineTag;
use boot_loader_name::BootLoaderNameTag;
use memory_map::{MemoryMapTag, MemoryMapIter};
use tag::{TagType, Tag, TagIter};
use basic_memory_information::BasicMemoryInformationTag;
use end_tag;
use module::{ModuleIter};

pub unsafe fn load(multiboot_addr: usize) -> &'static MultiBootInfo  {
    let multiboot_info = MultiBootInfo::from_raw_parts(multiboot_addr);
    assert!(multiboot_info.has_valid_end_tag());
    multiboot_info
}

#[derive(Debug)]
#[repr(C)]
pub struct MultiBootInfo {
    total_size: u32,
    reserved: u32,      // Should always be 0.
    first_tag: Tag
}

impl MultiBootInfo {
    unsafe fn from_raw_parts(multiboot_addr: usize) -> &'static MultiBootInfo {
        &*(multiboot_addr as *const MultiBootInfo)
    }

    pub fn start_address(&self) -> usize {
        self as *const _ as usize
    }

    pub fn end_address(&self) -> usize {
        self.start_address() + self.total_size()
    }

    pub fn total_size(&self) -> usize {
        self.total_size as usize
    }

    pub fn mem_lower(&self) -> Option<usize> {
        self.cast_find_tag::<BasicMemoryInformationTag>(TagType::MemoryInformation)
            .map(|tag| { tag.mem_lower() })
    }

    pub fn mem_upper(&self) -> Option<usize> {
        self.cast_find_tag::<BasicMemoryInformationTag>(TagType::MemoryInformation)
            .map(|tag| { tag.mem_upper() })
    }

    pub fn bios_boot_device(&self) -> Option<BootDevice> {
        self.cast_find_tag::<BIOSBootDeviceTag>(TagType::BIOSBootDevice)
            .map(|tag| {
                BootDevice::new(tag.biosdev, tag.partition, tag.sub_partition)
            })
    }

    pub fn boot_cmd_line(&self) -> Option<&str> {
        self.cast_find_tag::<BootCommandLineTag>(TagType::BootCommandLine)
            .map(|tag| { tag.string() })
    }

    pub fn boot_loader_name(&self) -> Option<&str> {
        self.cast_find_tag::<BootLoaderNameTag>(TagType::BootCommandLine)
            .map(|tag| { tag.string() })
    }

    pub fn memory_map(&self) -> Option<MemoryMapIter> {
        self.cast_find_tag::<MemoryMapTag>(TagType::MemoryMap)
            .map(|tag| { tag.memory_regions() })
    }

    pub fn modules(&self) -> ModuleIter {
        ModuleIter::new(self.tags())
    }

    fn has_valid_end_tag(&self) -> bool {
        let end_tag_ptr = self.end_address() - end_tag::END_TAG_SIZE;
        let end_tag = unsafe {
            &*(end_tag_ptr as *const end_tag::EndTag)
        };

        end_tag.is_valid()
    }

    fn tags(&self) -> TagIter {
        TagIter::new(&self.first_tag)
    }

    fn find_tag(&self, tag_type: TagType) -> Option<&'static Tag> {
        self.tags().find(|tag| { tag.tag_type() == tag_type as usize })
    }

    fn cast_find_tag<T>(&self, tag_type: TagType) -> Option <&T> {
        self.find_tag(tag_type).map(|tag_ptr| {
            unsafe {
                tag_ptr.cast::<T>()
            }
        })
    }
}
<|endoftext|>


<commit_before>//! Bindings to libgit2's raw git_strarray type

use std::ops::{Range,Deref};

use oid::Oid;
use raw;
use util::Binding;
use std::slice;

/// An oid array structure used by libgit2
///
/// Some apis return arrays of oids which originate from libgit2. This
/// wrapper type behaves a little like `Vec<&Oid>` but does so without copying
/// the underlying Oids until necessary.
pub struct OidArray {
    raw: raw::git_oidarray,
}

/// A forward iterator over the Oids of an array, casted to `&Oid`.
pub struct Iter<'a> {
    range: Range<usize>,
    arr: &'a OidArray,
}

/// A forward iterator over the bytes of n array.
pub struct IterBytes<'a> {
    range: Range<usize>,
    arr: &'a OidArray,
}

impl OidArray {
    /// Returns None if i is out of bounds.
    pub fn get(&self, i: usize) -> Option<Oid> {
        if i < self.raw.count as usize {
            Some(self[i])
        } else {
            None
        }
    }

    /// Returns None if `i` is out of bounds.
    pub fn get_bytes(&self, i: usize) -> Option<&[u8]> {
        if i < self.raw.count as usize {
            unsafe {
                let ptr = self.raw.ids.offset(i as isize) as *const _;
                Some(::opt_bytes(self, ptr).unwrap())
            }
        } else {
            None
        }
    }

    /// Returns an iterator over the Oids contained within this array.
    pub fn iter(&self) -> Iter {
        Iter { range: 0..self.len(), arr: self }
    }

    /// Returns an iterator over the strings contained within this array,
    /// yielding byte slices.
    pub fn iter_bytes(&self) -> IterBytes {
        IterBytes { range: 0..self.len(), arr: self }
    }

    /// Returns the number of strings in this array.
    pub fn len(&self) -> usize { self.raw.count as usize }
}

impl Deref for OidArray {
    type Target = [Oid];

    fn deref(&self) -> &[Oid] {
        unsafe {
            slice::from_raw_parts(self.raw.ids as *const Oid, self.raw.count as usize)
        }
    }
}

impl Binding for OidArray {
    type Raw = raw::git_oidarray;
    unsafe fn from_raw(raw: raw::git_oidarray) -> OidArray {
        OidArray { raw: raw }
    }
    fn raw(&self) -> raw::git_oidarray { self.raw }
}

impl<'a> Iterator for Iter<'a> {
    type Item = Oid;
    fn next(&mut self) -> Option<Oid> {
        self.range.next().and_then(|i| self.arr.get(i))
    }
    fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
}
impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<Oid> {
        self.range.next_back().and_then(|i| self.arr.get(i))
    }
}
impl<'a> ExactSizeIterator for Iter<'a> {}

impl<'a> Iterator for IterBytes<'a> {
    type Item = &'a [u8];
    fn next(&mut self) -> Option<&'a [u8]> {
        self.range.next().and_then(|i| self.arr.get_bytes(i))
    }
    fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
}
impl<'a> DoubleEndedIterator for IterBytes<'a> {
    fn next_back(&mut self) -> Option<&'a [u8]> {
        self.range.next_back().and_then(|i| self.arr.get_bytes(i))
    }
}
impl<'a> ExactSizeIterator for IterBytes<'a> {}

impl Drop for OidArray {
    fn drop(&mut self) {
        unsafe { raw::git_oidarray_free(&mut self.raw) }
    }
}
<commit_msg>remove bytes iterator and accessor since it's not currently used<commit_after>//! Bindings to libgit2's raw git_strarray type

use std::ops::{Range,Deref};

use oid::Oid;
use raw;
use util::Binding;
use std::slice;

/// An oid array structure used by libgit2
///
/// Some apis return arrays of oids which originate from libgit2. This
/// wrapper type behaves a little like `Vec<&Oid>` but does so without copying
/// the underlying Oids until necessary.
pub struct OidArray {
    raw: raw::git_oidarray,
}

/// A forward iterator over the Oids of an array, casted to `&Oid`.
pub struct Iter<'a> {
    range: Range<usize>,
    arr: &'a OidArray,
}

impl OidArray {
    /// Returns None if i is out of bounds.
    pub fn get(&self, i: usize) -> Option<Oid> {
        if i < self.raw.count as usize {
            Some(self[i])
        } else {
            None
        }
    }

    /// Returns an iterator over the Oids contained within this array.
    pub fn iter(&self) -> Iter {
        Iter { range: 0..self.len(), arr: self }
    }

    /// Returns the number of strings in this array.
    pub fn len(&self) -> usize { self.raw.count as usize }
}

impl Deref for OidArray {
    type Target = [Oid];

    fn deref(&self) -> &[Oid] {
        unsafe {
            slice::from_raw_parts(self.raw.ids as *const Oid, self.raw.count as usize)
        }
    }
}

impl Binding for OidArray {
    type Raw = raw::git_oidarray;
    unsafe fn from_raw(raw: raw::git_oidarray) -> OidArray {
        OidArray { raw: raw }
    }
    fn raw(&self) -> raw::git_oidarray { self.raw }
}

impl<'a> Iterator for Iter<'a> {
    type Item = Oid;
    fn next(&mut self) -> Option<Oid> {
        self.range.next().and_then(|i| self.arr.get(i))
    }
    fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
}
impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<Oid> {
        self.range.next_back().and_then(|i| self.arr.get(i))
    }
}
impl<'a> ExactSizeIterator for Iter<'a> {}

impl Drop for OidArray {
    fn drop(&mut self) {
        unsafe { raw::git_oidarray_free(&mut self.raw) }
    }
}
<|endoftext|>


<commit_before>use CHIP8_HEIGHT;
use CHIP8_WIDTH;
use CHIP8_RAM;

pub struct OutputState<'a> {
    pub vram: &'a [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    pub vram_changed: bool,
    pub beep: bool,
}

pub struct Processor {
    vram: [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    vram_changed: bool,
    ram: [u8; CHIP8_RAM],
    stack: [usize; 16],
    v: [u8; 16],
    i: usize,
    pc: usize,
    sp: usize,
    delay_timer: u8,
    sound_timer: u8,
}

impl Processor {
    pub fn new() -> Self {
        Processor {
            vram: [[0; CHIP8_WIDTH]; CHIP8_HEIGHT],
            vram_changed: false,
            ram: [0; CHIP8_RAM],
            stack: [0; 16],
            v: [0; 16],
            i: 0,
            pc: 0x200,
            sp: 0,
            delay_timer: 0,
            sound_timer: 0,
        }
    }

    pub fn tick(&mut self, keypad: &[bool; 16]) -> OutputState {
        self.vram_changed = false;
        let opcode = self.get_opcode();
        self.run_opcode(opcode);
        OutputState {
            vram: &self.vram,
            vram_changed: self.vram_changed,
            beep: self.sound_timer > 0,
        }
    }

    fn get_opcode(&self) -> u16 {
        (self.ram[self.pc] as u16) << 8 | (self.ram[self.pc + 1] as u16)
    }

    fn run_opcode(&mut self, opcode: u16) {

        let nibbles = (
            (opcode & 0xF000) >> 12 as u8,
            (opcode & 0x0F00) >> 8 as u8,
            (opcode & 0x00F0) >> 4 as u8,
            (opcode & 0x000F) as u8,
        );

        let nnn = opcode & 0x0FFF;
        let kk = (opcode & 0x00FF) as u8;
        let x = nibbles.2 as usize;
        let y = nibbles.1 as usize;
        let n = nibbles.0 as u8;

        match nibbles {
            (0x00, 0x00, 0x0e, 0x00) => self.op_00e0(),
            (0x00, 0x00, 0x0e, 0x0e) => self.op_00ee(),
            (0x01, _, _, _) => self.op_1nnn(nnn),
            (0x02, _, _, _) => self.op_2nnn(nnn),
            (0x03, _, _, _) => self.op_3xkk(x, kk),
            (0x04, _, _, _) => self.op_4xkk(x, kk),
            (0x05, _, _, 0x00) => self.op_5xy0(x, y),
            (0x06, _, _, _) => self.op_6xkk(x, kk),
            (0x07, _, _, _) => self.op_7xkk(x, kk),
            (0x08, _, _, 0x00) => self.op_8xy0(x, y),
            (0x08, _, _, 0x01) => self.op_8xy1(x, y),
            (0x08, _, _, 0x02) => self.op_8xy2(x, y),
            (0x08, _, _, 0x03) => self.op_8xy3(x, y),
            (0x08, _, _, 0x04) => self.op_8xy4(x, y),
            (0x08, _, _, 0x05) => self.op_8xy5(x, y),
            (0x08, _, _, 0x06) => self.op_8xy6(x, y),
            (0x08, _, _, 0x07) => self.op_8xy7(x, y),
            (0x08, _, _, 0x0e) => self.op_8xye(x, y),
            (0x09, _, _, 0x00) => self.op_9xy0(x, y),
            (0x0a, _, _, _) => self.op_annn(nnn),
            (0x0b, _, _, _) => self.op_bnnn(nnn),
            (0x0c, _, _, _) => self.op_cxkk(x, kk),
            (0x0d, _, _, _) => self.op_dxyn(x, y, n),
            (0x0e, _, 0x09, 0x0e) => self.op_ex9e(x),
            (0x0e, _, 0x0a, 0x01) => self.op_exa1(x),
            (0x0f, _, 0x00, 0x07) => self.op_fx07(x),
            (0x0f, _, 0x00, 0x0a) => self.op_fx0a(x),
            (0x0f, _, 0x01, 0x05) => self.op_fx15(x),
            (0x0f, _, 0x01, 0x08) => self.op_fx18(x),
            (0x0f, _, 0x01, 0x0e) => self.op_fx1e(x),
            (0x0f, _, 0x02, 0x09) => self.op_fx29(x),
            (0x0f, _, 0x03, 0x03) => self.op_fx33(x),
            (0x0f, _, 0x05, 0x05) => self.op_fx55(x),
            (0x0f, _, 0x06, 0x05) => self.op_fx65(x),
            _ => return,
        }

    }
    // CLS: Clear the display.
    fn op_00e0(&mut self) {
        for y in 0..CHIP8_HEIGHT {
            for x in 0..CHIP8_WIDTH {
                self.vram[y][x] = 0;
            }
        }
        self.vram_changed = true;
    }

    // RET:  Return from a subroutine.
    fn op_00ee(&mut self) {
        self.pc = self.stack[self.sp];
        self.sp -= 1;
    }

    // JP addr
    fn op_1nnn(&mut self, nnn: u16) {}
    // CALL addr
    fn op_2nnn(&mut self, nnn: u16) {}
    // SE Vx, byte
    fn op_3xkk(&mut self, x: usize, kk: u8) {}
    // SNE Vx, byte
    fn op_4xkk(&mut self, x: usize, kk: u8) {}
    // SE Vx, Vy
    fn op_5xy0(&mut self, x: usize, y: usize) {}
    // LD Vx, byte
    fn op_6xkk(&mut self, x: usize, kk: u8) {}
    // ADD Vx, byte
    fn op_7xkk(&mut self, x: usize, kk: u8) {}
    // LD Vx, Vy
    fn op_8xy0(&mut self, x: usize, y: usize) {}
    // OR Vx, Vy
    fn op_8xy1(&mut self, x: usize, y: usize) {}
    // AND Vx, Vy
    fn op_8xy2(&mut self, x: usize, y: usize) {}
    // XOR Vx, Vy
    fn op_8xy3(&mut self, x: usize, y: usize) {}
    // ADD Vx, Vy
    fn op_8xy4(&mut self, x: usize, y: usize) {}
    // SUB Vx, Vy
    fn op_8xy5(&mut self, x: usize, y: usize) {}
    // SHR Vx {, Vy}
    fn op_8xy6(&mut self, x: usize, y: usize) {}
    // SUBN Vx, Vy
    fn op_8xy7(&mut self, x: usize, y: usize) {}
    // SHL Vx {, Vy}
    fn op_8xye(&mut self, x: usize, y: usize) {}
    // SNE Vx, Vy
    fn op_9xy0(&mut self, x: usize, y: usize) {}
    // LD I, addr
    fn op_annn(&mut self, nnn: u16) {}
    // JP V0, addr
    fn op_bnnn(&mut self, nnn: u16) {}
    // RND Vx, byte
    fn op_cxkk(&mut self, x: usize, kk: u8) {}
    // DRW Vx, Vy, nibble
    fn op_dxyn(&mut self, x: usize, y: usize, n: u8) {}
    // SKP Vx
    fn op_ex9e(&mut self, x: usize) {}
    // SKNP Vx
    fn op_exa1(&mut self, x: usize) {}
    // LD Vx, DT
    fn op_fx07(&mut self, x: usize) {}
    // LD Vx, K
    fn op_fx0a(&mut self, x: usize) {}
    // LD DT, Vx
    fn op_fx15(&mut self, x: usize) {}
    // LD ST, Vx
    fn op_fx18(&mut self, x: usize) {}
    // ADD I, Vx
    fn op_fx1e(&mut self, x: usize) {}
    // LD F, Vx
    fn op_fx29(&mut self, x: usize) {}
    // LD B, Vx
    fn op_fx33(&mut self, x: usize) {}
    // LD [I], Vx
    fn op_fx55(&mut self, x: usize) {}
    // LD Vx, [I]
    fn op_fx65(&mut self, x: usize) {}
}

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

    #[test]
    fn test_initial_state() {
        let processor = Processor::new();
        assert_eq!(processor.sp, 0);
        assert_eq!(processor.stack, [0; 16]);
    }

    // CLS
    #[test]
    fn test_op_00e0() {
        let mut processor = Processor::new();
        processor.vram = [[128; CHIP8_WIDTH]; CHIP8_HEIGHT];
        processor.run_opcode(0x00e0);
        for y in 0..CHIP8_HEIGHT {
            for x in 0..CHIP8_WIDTH {
                assert_eq!(processor.vram[y][x], 0);
            }
        }
    }

    // RET
    #[test]
    fn test_op_00ee() {
        let mut processor = Processor::new();
        processor.sp = 5;
        processor.stack[5] = 0x6666;
        processor.run_opcode(0x00ee);
        assert_eq!(processor.sp, 4);
        assert_eq!(processor.pc, 0x6666);
    }

}
<commit_msg>dec sp before using<commit_after>use CHIP8_HEIGHT;
use CHIP8_WIDTH;
use CHIP8_RAM;

pub struct OutputState<'a> {
    pub vram: &'a [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    pub vram_changed: bool,
    pub beep: bool,
}

pub struct Processor {
    vram: [[u8; CHIP8_WIDTH]; CHIP8_HEIGHT],
    vram_changed: bool,
    ram: [u8; CHIP8_RAM],
    stack: [usize; 16],
    v: [u8; 16],
    i: usize,
    pc: usize,
    sp: usize,
    delay_timer: u8,
    sound_timer: u8,
}

impl Processor {
    pub fn new() -> Self {
        Processor {
            vram: [[0; CHIP8_WIDTH]; CHIP8_HEIGHT],
            vram_changed: false,
            ram: [0; CHIP8_RAM],
            stack: [0; 16],
            v: [0; 16],
            i: 0,
            pc: 0x200,
            sp: 0,
            delay_timer: 0,
            sound_timer: 0,
        }
    }

    pub fn tick(&mut self, keypad: &[bool; 16]) -> OutputState {
        self.vram_changed = false;
        let opcode = self.get_opcode();
        self.run_opcode(opcode);
        OutputState {
            vram: &self.vram,
            vram_changed: self.vram_changed,
            beep: self.sound_timer > 0,
        }
    }

    fn get_opcode(&self) -> u16 {
        (self.ram[self.pc] as u16) << 8 | (self.ram[self.pc + 1] as u16)
    }

    fn run_opcode(&mut self, opcode: u16) {

        let nibbles = (
            (opcode & 0xF000) >> 12 as u8,
            (opcode & 0x0F00) >> 8 as u8,
            (opcode & 0x00F0) >> 4 as u8,
            (opcode & 0x000F) as u8,
        );

        let nnn = opcode & 0x0FFF;
        let kk = (opcode & 0x00FF) as u8;
        let x = nibbles.2 as usize;
        let y = nibbles.1 as usize;
        let n = nibbles.0 as u8;

        match nibbles {
            (0x00, 0x00, 0x0e, 0x00) => self.op_00e0(),
            (0x00, 0x00, 0x0e, 0x0e) => self.op_00ee(),
            (0x01, _, _, _) => self.op_1nnn(nnn),
            (0x02, _, _, _) => self.op_2nnn(nnn),
            (0x03, _, _, _) => self.op_3xkk(x, kk),
            (0x04, _, _, _) => self.op_4xkk(x, kk),
            (0x05, _, _, 0x00) => self.op_5xy0(x, y),
            (0x06, _, _, _) => self.op_6xkk(x, kk),
            (0x07, _, _, _) => self.op_7xkk(x, kk),
            (0x08, _, _, 0x00) => self.op_8xy0(x, y),
            (0x08, _, _, 0x01) => self.op_8xy1(x, y),
            (0x08, _, _, 0x02) => self.op_8xy2(x, y),
            (0x08, _, _, 0x03) => self.op_8xy3(x, y),
            (0x08, _, _, 0x04) => self.op_8xy4(x, y),
            (0x08, _, _, 0x05) => self.op_8xy5(x, y),
            (0x08, _, _, 0x06) => self.op_8xy6(x, y),
            (0x08, _, _, 0x07) => self.op_8xy7(x, y),
            (0x08, _, _, 0x0e) => self.op_8xye(x, y),
            (0x09, _, _, 0x00) => self.op_9xy0(x, y),
            (0x0a, _, _, _) => self.op_annn(nnn),
            (0x0b, _, _, _) => self.op_bnnn(nnn),
            (0x0c, _, _, _) => self.op_cxkk(x, kk),
            (0x0d, _, _, _) => self.op_dxyn(x, y, n),
            (0x0e, _, 0x09, 0x0e) => self.op_ex9e(x),
            (0x0e, _, 0x0a, 0x01) => self.op_exa1(x),
            (0x0f, _, 0x00, 0x07) => self.op_fx07(x),
            (0x0f, _, 0x00, 0x0a) => self.op_fx0a(x),
            (0x0f, _, 0x01, 0x05) => self.op_fx15(x),
            (0x0f, _, 0x01, 0x08) => self.op_fx18(x),
            (0x0f, _, 0x01, 0x0e) => self.op_fx1e(x),
            (0x0f, _, 0x02, 0x09) => self.op_fx29(x),
            (0x0f, _, 0x03, 0x03) => self.op_fx33(x),
            (0x0f, _, 0x05, 0x05) => self.op_fx55(x),
            (0x0f, _, 0x06, 0x05) => self.op_fx65(x),
            _ => return,
        }

    }
    // CLS: Clear the display.
    fn op_00e0(&mut self) {
        for y in 0..CHIP8_HEIGHT {
            for x in 0..CHIP8_WIDTH {
                self.vram[y][x] = 0;
            }
        }
        self.vram_changed = true;
    }

    // RET:  Return from a subroutine.
    fn op_00ee(&mut self) {
        self.sp -= 1;
        self.pc = self.stack[self.sp];
    }

    // JP addr
    fn op_1nnn(&mut self, nnn: u16) {}
    // CALL addr
    fn op_2nnn(&mut self, nnn: u16) {}
    // SE Vx, byte
    fn op_3xkk(&mut self, x: usize, kk: u8) {}
    // SNE Vx, byte
    fn op_4xkk(&mut self, x: usize, kk: u8) {}
    // SE Vx, Vy
    fn op_5xy0(&mut self, x: usize, y: usize) {}
    // LD Vx, byte
    fn op_6xkk(&mut self, x: usize, kk: u8) {}
    // ADD Vx, byte
    fn op_7xkk(&mut self, x: usize, kk: u8) {}
    // LD Vx, Vy
    fn op_8xy0(&mut self, x: usize, y: usize) {}
    // OR Vx, Vy
    fn op_8xy1(&mut self, x: usize, y: usize) {}
    // AND Vx, Vy
    fn op_8xy2(&mut self, x: usize, y: usize) {}
    // XOR Vx, Vy
    fn op_8xy3(&mut self, x: usize, y: usize) {}
    // ADD Vx, Vy
    fn op_8xy4(&mut self, x: usize, y: usize) {}
    // SUB Vx, Vy
    fn op_8xy5(&mut self, x: usize, y: usize) {}
    // SHR Vx {, Vy}
    fn op_8xy6(&mut self, x: usize, y: usize) {}
    // SUBN Vx, Vy
    fn op_8xy7(&mut self, x: usize, y: usize) {}
    // SHL Vx {, Vy}
    fn op_8xye(&mut self, x: usize, y: usize) {}
    // SNE Vx, Vy
    fn op_9xy0(&mut self, x: usize, y: usize) {}
    // LD I, addr
    fn op_annn(&mut self, nnn: u16) {}
    // JP V0, addr
    fn op_bnnn(&mut self, nnn: u16) {}
    // RND Vx, byte
    fn op_cxkk(&mut self, x: usize, kk: u8) {}
    // DRW Vx, Vy, nibble
    fn op_dxyn(&mut self, x: usize, y: usize, n: u8) {}
    // SKP Vx
    fn op_ex9e(&mut self, x: usize) {}
    // SKNP Vx
    fn op_exa1(&mut self, x: usize) {}
    // LD Vx, DT
    fn op_fx07(&mut self, x: usize) {}
    // LD Vx, K
    fn op_fx0a(&mut self, x: usize) {}
    // LD DT, Vx
    fn op_fx15(&mut self, x: usize) {}
    // LD ST, Vx
    fn op_fx18(&mut self, x: usize) {}
    // ADD I, Vx
    fn op_fx1e(&mut self, x: usize) {}
    // LD F, Vx
    fn op_fx29(&mut self, x: usize) {}
    // LD B, Vx
    fn op_fx33(&mut self, x: usize) {}
    // LD [I], Vx
    fn op_fx55(&mut self, x: usize) {}
    // LD Vx, [I]
    fn op_fx65(&mut self, x: usize) {}
}

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

    #[test]
    fn test_initial_state() {
        let processor = Processor::new();
        assert_eq!(processor.sp, 0);
        assert_eq!(processor.stack, [0; 16]);
    }

    // CLS
    #[test]
    fn test_op_00e0() {
        let mut processor = Processor::new();
        processor.vram = [[128; CHIP8_WIDTH]; CHIP8_HEIGHT];
        processor.run_opcode(0x00e0);
        for y in 0..CHIP8_HEIGHT {
            for x in 0..CHIP8_WIDTH {
                assert_eq!(processor.vram[y][x], 0);
            }
        }
    }

    // RET
    #[test]
    fn test_op_00ee() {
        let mut processor = Processor::new();
        processor.sp = 5;
        processor.stack[5] = 0x6666;
        processor.run_opcode(0x00ee);
        assert_eq!(processor.sp, 4);
        assert_eq!(processor.pc, 0x6666);
    }

}
<|endoftext|>


<commit_before>use prolog::ast::*;
use prolog::codegen::*;
use prolog::debray_allocator::*;
use prolog::machine::*;

use termion::raw::IntoRawMode;
use termion::input::TermRead;
use termion::event::Key;

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

impl fmt::Display for Constant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Constant::Atom(ref atom) =>
                write!(f, "{}", atom),
            &Constant::EmptyList =>
                write!(f, "[]")
        }
    }
}

impl fmt::Display for FactInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &FactInstruction::GetConstant(Level::Shallow, ref constant, ref r) =>
                write!(f, "get_constant {}, A{}", constant, r.reg_num()),
            &FactInstruction::GetConstant(Level::Deep, ref constant, ref r) =>
                write!(f, "get_constant {}, {}", constant, r),
            &FactInstruction::GetList(Level::Shallow, ref r) =>
                write!(f, "get_list A{}", r.reg_num()),
            &FactInstruction::GetList(Level::Deep, ref r) =>
                write!(f, "get_list {}", r),
            &FactInstruction::GetStructure(Level::Deep, ref name, ref arity, ref r) =>
                write!(f, "get_structure {}/{}, {}", name, arity, r),
            &FactInstruction::GetStructure(Level::Shallow, ref name, ref arity, ref r) =>
                write!(f, "get_structure {}/{}, A{}", name, arity, r.reg_num()),
            &FactInstruction::GetValue(ref x, ref a) =>
                write!(f, "get_value {}, A{}", x, a),
            &FactInstruction::GetVariable(ref x, ref a) =>
                write!(f, "get_variable {}, A{}", x, a),
            &FactInstruction::UnifyConstant(ref constant) =>
                write!(f, "unify_constant {}", constant),
            &FactInstruction::UnifyVariable(ref r) =>
                write!(f, "unify_variable {}", r),
            &FactInstruction::UnifyLocalValue(ref r) =>
                write!(f, "unify_local_value {}", r),
            &FactInstruction::UnifyValue(ref r) =>
                write!(f, "unify_value {}", r),
            &FactInstruction::UnifyVoid(n) =>
                write!(f, "unify_void {}", n)
        }
    }
}

impl fmt::Display for QueryInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &QueryInstruction::GetVariable(ref x, ref a) =>
                write!(f, "get_variable {}, A{}", x, a),
            &QueryInstruction::PutConstant(Level::Shallow, ref constant, ref r) =>
                write!(f, "put_constant {}, A{}", constant, r.reg_num()),
            &QueryInstruction::PutConstant(Level::Deep, ref constant, ref r) =>
                write!(f, "put_constant {}, {}", constant, r),
            &QueryInstruction::PutList(Level::Shallow, ref r) =>
                write!(f, "put_list A{}", r.reg_num()),
            &QueryInstruction::PutList(Level::Deep, ref r) =>
                write!(f, "put_list {}", r),
            &QueryInstruction::PutStructure(Level::Deep, ref name, ref arity, ref r) =>
                write!(f, "put_structure {}/{}, {}", name, arity, r),
            &QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
                write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()),
            &QueryInstruction::PutUnsafeValue(y, a) =>
                write!(f, "put_unsafe_value Y{}, A{}", y, a),
            &QueryInstruction::PutValue(ref x, ref a) =>
                write!(f, "put_value {}, A{}", x, a),
            &QueryInstruction::PutVariable(ref x, ref a) =>
                write!(f, "put_variable {}, A{}", x, a),
            &QueryInstruction::SetConstant(ref constant) =>
                write!(f, "set_constant {}", constant),
            &QueryInstruction::SetLocalValue(ref r) =>
                write!(f, "set_local_value {}", r),
            &QueryInstruction::SetVariable(ref r) =>
                write!(f, "set_variable {}", r),
            &QueryInstruction::SetValue(ref r) =>
                write!(f, "set_value {}", r),
            &QueryInstruction::SetVoid(n) =>
                write!(f, "set_void {}", n)
        }
    }
}

impl fmt::Display for ControlInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ControlInstruction::Allocate(num_cells) =>
                write!(f, "allocate {}", num_cells),
            &ControlInstruction::Call(ref name, arity, pvs) =>
                write!(f, "call {}/{}, {}", name, arity, pvs),
            &ControlInstruction::Deallocate =>
                write!(f, "deallocate"),
            &ControlInstruction::Execute(ref name, arity) =>
                write!(f, "execute {}/{}", name, arity),
            &ControlInstruction::Proceed =>
                write!(f, "proceed")
        }
    }
}

impl fmt::Display for IndexedChoiceInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &IndexedChoiceInstruction::Try(offset) =>
                write!(f, "try {}", offset),
            &IndexedChoiceInstruction::Retry(offset) =>
                write!(f, "retry {}", offset),
            &IndexedChoiceInstruction::Trust(offset) =>
                write!(f, "trust {}", offset)
        }
    }
}

impl fmt::Display for ChoiceInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ChoiceInstruction::TryMeElse(offset) =>
                write!(f, "try_me_else {}", offset),
            &ChoiceInstruction::RetryMeElse(offset) =>
                write!(f, "retry_me_else {}", offset),
            &ChoiceInstruction::TrustMe =>
                write!(f, "trust_me")
        }
    }
}

impl fmt::Display for IndexingInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &IndexingInstruction::SwitchOnTerm(v, c, l, s) =>
                write!(f, "switch_on_term {}, {}, {}, {}", v, c, l, s),
            &IndexingInstruction::SwitchOnConstant(num_cs, _) =>
                write!(f, "switch_on_constant {}", num_cs),
            &IndexingInstruction::SwitchOnStructure(num_ss, _) =>
                write!(f, "switch_on_structure {}", num_ss)
        }
    }
}

impl fmt::Display for CutInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &CutInstruction::Cut(_) =>
                write!(f, "cut"),
            &CutInstruction::NeckCut(_) =>
                write!(f, "neck_cut"),
            &CutInstruction::GetLevel =>
                write!(f, "get_level")
        }
    }
}

impl fmt::Display for Level {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Level::Shallow => write!(f, "A"),
            &Level::Deep => write!(f, "X")
        }
    }
}

impl fmt::Display for VarReg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
            &VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
            &VarReg::ArgAndNorm(RegType::Perm(reg), arg) =>
                write!(f, "Y{} A{}", reg, arg),
            &VarReg::ArgAndNorm(RegType::Temp(reg), arg) =>
                write!(f, "X{} A{}", reg, arg)
        }
    }
}

impl fmt::Display for RegType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &RegType::Perm(val) => write!(f, "Y{}", val),
            &RegType::Temp(val) => write!(f, "X{}", val)
        }
    }
}

fn is_consistent(predicate: &Vec<PredicateClause>) -> bool {
    let name  = predicate.first().unwrap().name();
    let arity = predicate.first().unwrap().arity();

    for clause in predicate.iter().skip(1) {
        if !(name == clause.name() && arity == clause.arity()) {
            return false;
        }
    }

    true
}

#[allow(dead_code)]
pub fn print_code(code: &Code) {
    for clause in code {
        match clause {
            &Line::Fact(ref fact) =>
                for fact_instr in fact {
                    println!("{}", fact_instr);
                },
            &Line::Cut(ref cut) =>
                println!("{}", cut),
            &Line::Choice(ref choice) =>
                println!("{}", choice),
            &Line::Control(ref control) =>
                println!("{}", control),
            &Line::IndexedChoice(ref choice) =>
                println!("{}", choice),
            &Line::Indexing(ref indexing) =>
                println!("{}", indexing),
            &Line::Query(ref query) =>
                for query_instr in query {
                    println!("{}", query_instr);
                }
        }
    }
}

pub fn read() -> String {
    let _ = stdout().flush();

    let mut buffer = String::new();
    let mut result = String::new();

    let stdin = stdin();
    stdin.read_line(&mut buffer).unwrap();

    if &*buffer.trim() == ":{" {
        buffer.clear();

        stdin.read_line(&mut buffer).unwrap();

        while &*buffer.trim() != "}:" {
            result += buffer.as_str();
            buffer.clear();
            stdin.read_line(&mut buffer).unwrap();
        }
    } else {
        result = buffer;
    }

    result
}

pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'b>
{
    match tl {
        &TopLevel::Predicate(ref clauses) => {
            let mut cg = CodeGenerator::<DebrayAllocator>::new();

            if is_consistent(clauses) {
                let compiled_pred = cg.compile_predicate(clauses);
                wam.add_predicate(clauses, compiled_pred);

                EvalSession::EntrySuccess
            } else {
                let msg = r"Error: predicate is inconsistent.
Each predicate must have the same name and arity.";

                println!("{}", msg);
                EvalSession::EntryFailure
            }
        },
        &TopLevel::Fact(ref fact) => {
            let mut cg = CodeGenerator::<DebrayAllocator>::new();

            let compiled_fact = cg.compile_fact(fact);
            wam.add_fact(fact, compiled_fact);

            EvalSession::EntrySuccess
        },
        &TopLevel::Rule(ref rule) => {
            let mut cg = CodeGenerator::<DebrayAllocator>::new();

            let compiled_rule = cg.compile_rule(rule);
            wam.add_rule(rule, compiled_rule);

            EvalSession::EntrySuccess
        },
        &TopLevel::Query(ref query) => {
            let mut cg = CodeGenerator::<DebrayAllocator>::new();

            let compiled_query = cg.compile_query(query);
            wam.submit_query(compiled_query, cg.take_vars())
        }
    }
}

pub fn print(wam: &mut Machine, result: EvalSession) {
    match result {
        EvalSession::InitialQuerySuccess(alloc_locs, mut heap_locs) => {
            println!("true");

            if heap_locs.is_empty() {
                return;
            }

            loop {
                let mut result = EvalSession::QueryFailure;
                let bindings = wam.heap_view(&heap_locs);

                let stdin  = stdin();
                let mut stdout = stdout().into_raw_mode().unwrap();

                write!(stdout, "{}", bindings).unwrap();
                stdout.flush().unwrap();

                if !wam.or_stack_is_empty() {
                    stdout.flush().unwrap();

                    for c in stdin.keys() {
                        match c.unwrap() {
                            Key::Char(';') => {
                                write!(stdout, " ;\n\r").unwrap();
                                result = wam.continue_query(&alloc_locs, &mut heap_locs);
                                break;
                            },
                            Key::Char('.') => {
                                write!(stdout, " .\n\r").unwrap();
                                return;
                            },
                            _ => {}
                        }
                    }

                    if let &EvalSession::QueryFailure = &result {
                        write!(stdout, "false.\n\r").unwrap();
                        stdout.flush().unwrap();
                        return;
                    }
                } else {
                    break;
                }
            }

            write!(stdout(), ".\n").unwrap();
        },
        EvalSession::QueryFailure => println!("false."),
        _ => {}
    };
}
<commit_msg>add (non)-deterministic REPL demarcations<commit_after>use prolog::ast::*;
use prolog::codegen::*;
use prolog::debray_allocator::*;
use prolog::machine::*;

use termion::raw::IntoRawMode;
use termion::input::TermRead;
use termion::event::Key;

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

impl fmt::Display for Constant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Constant::Atom(ref atom) =>
                write!(f, "{}", atom),
            &Constant::EmptyList =>
                write!(f, "[]")
        }
    }
}

impl fmt::Display for FactInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &FactInstruction::GetConstant(Level::Shallow, ref constant, ref r) =>
                write!(f, "get_constant {}, A{}", constant, r.reg_num()),
            &FactInstruction::GetConstant(Level::Deep, ref constant, ref r) =>
                write!(f, "get_constant {}, {}", constant, r),
            &FactInstruction::GetList(Level::Shallow, ref r) =>
                write!(f, "get_list A{}", r.reg_num()),
            &FactInstruction::GetList(Level::Deep, ref r) =>
                write!(f, "get_list {}", r),
            &FactInstruction::GetStructure(Level::Deep, ref name, ref arity, ref r) =>
                write!(f, "get_structure {}/{}, {}", name, arity, r),
            &FactInstruction::GetStructure(Level::Shallow, ref name, ref arity, ref r) =>
                write!(f, "get_structure {}/{}, A{}", name, arity, r.reg_num()),
            &FactInstruction::GetValue(ref x, ref a) =>
                write!(f, "get_value {}, A{}", x, a),
            &FactInstruction::GetVariable(ref x, ref a) =>
                write!(f, "get_variable {}, A{}", x, a),
            &FactInstruction::UnifyConstant(ref constant) =>
                write!(f, "unify_constant {}", constant),
            &FactInstruction::UnifyVariable(ref r) =>
                write!(f, "unify_variable {}", r),
            &FactInstruction::UnifyLocalValue(ref r) =>
                write!(f, "unify_local_value {}", r),
            &FactInstruction::UnifyValue(ref r) =>
                write!(f, "unify_value {}", r),
            &FactInstruction::UnifyVoid(n) =>
                write!(f, "unify_void {}", n)
        }
    }
}

impl fmt::Display for QueryInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &QueryInstruction::GetVariable(ref x, ref a) =>
                write!(f, "get_variable {}, A{}", x, a),
            &QueryInstruction::PutConstant(Level::Shallow, ref constant, ref r) =>
                write!(f, "put_constant {}, A{}", constant, r.reg_num()),
            &QueryInstruction::PutConstant(Level::Deep, ref constant, ref r) =>
                write!(f, "put_constant {}, {}", constant, r),
            &QueryInstruction::PutList(Level::Shallow, ref r) =>
                write!(f, "put_list A{}", r.reg_num()),
            &QueryInstruction::PutList(Level::Deep, ref r) =>
                write!(f, "put_list {}", r),
            &QueryInstruction::PutStructure(Level::Deep, ref name, ref arity, ref r) =>
                write!(f, "put_structure {}/{}, {}", name, arity, r),
            &QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) =>
                write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()),
            &QueryInstruction::PutUnsafeValue(y, a) =>
                write!(f, "put_unsafe_value Y{}, A{}", y, a),
            &QueryInstruction::PutValue(ref x, ref a) =>
                write!(f, "put_value {}, A{}", x, a),
            &QueryInstruction::PutVariable(ref x, ref a) =>
                write!(f, "put_variable {}, A{}", x, a),
            &QueryInstruction::SetConstant(ref constant) =>
                write!(f, "set_constant {}", constant),
            &QueryInstruction::SetLocalValue(ref r) =>
                write!(f, "set_local_value {}", r),
            &QueryInstruction::SetVariable(ref r) =>
                write!(f, "set_variable {}", r),
            &QueryInstruction::SetValue(ref r) =>
                write!(f, "set_value {}", r),
            &QueryInstruction::SetVoid(n) =>
                write!(f, "set_void {}", n)
        }
    }
}

impl fmt::Display for ControlInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ControlInstruction::Allocate(num_cells) =>
                write!(f, "allocate {}", num_cells),
            &ControlInstruction::Call(ref name, arity, pvs) =>
                write!(f, "call {}/{}, {}", name, arity, pvs),
            &ControlInstruction::Deallocate =>
                write!(f, "deallocate"),
            &ControlInstruction::Execute(ref name, arity) =>
                write!(f, "execute {}/{}", name, arity),
            &ControlInstruction::Proceed =>
                write!(f, "proceed")
        }
    }
}

impl fmt::Display for IndexedChoiceInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &IndexedChoiceInstruction::Try(offset) =>
                write!(f, "try {}", offset),
            &IndexedChoiceInstruction::Retry(offset) =>
                write!(f, "retry {}", offset),
            &IndexedChoiceInstruction::Trust(offset) =>
                write!(f, "trust {}", offset)
        }
    }
}

impl fmt::Display for ChoiceInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ChoiceInstruction::TryMeElse(offset) =>
                write!(f, "try_me_else {}", offset),
            &ChoiceInstruction::RetryMeElse(offset) =>
                write!(f, "retry_me_else {}", offset),
            &ChoiceInstruction::TrustMe =>
                write!(f, "trust_me")
        }
    }
}

impl fmt::Display for IndexingInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &IndexingInstruction::SwitchOnTerm(v, c, l, s) =>
                write!(f, "switch_on_term {}, {}, {}, {}", v, c, l, s),
            &IndexingInstruction::SwitchOnConstant(num_cs, _) =>
                write!(f, "switch_on_constant {}", num_cs),
            &IndexingInstruction::SwitchOnStructure(num_ss, _) =>
                write!(f, "switch_on_structure {}", num_ss)
        }
    }
}

impl fmt::Display for CutInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &CutInstruction::Cut(_) =>
                write!(f, "cut"),
            &CutInstruction::NeckCut(_) =>
                write!(f, "neck_cut"),
            &CutInstruction::GetLevel =>
                write!(f, "get_level")
        }
    }
}

impl fmt::Display for Level {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Level::Shallow => write!(f, "A"),
            &Level::Deep => write!(f, "X")
        }
    }
}

impl fmt::Display for VarReg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
            &VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
            &VarReg::ArgAndNorm(RegType::Perm(reg), arg) =>
                write!(f, "Y{} A{}", reg, arg),
            &VarReg::ArgAndNorm(RegType::Temp(reg), arg) =>
                write!(f, "X{} A{}", reg, arg)
        }
    }
}

impl fmt::Display for RegType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &RegType::Perm(val) => write!(f, "Y{}", val),
            &RegType::Temp(val) => write!(f, "X{}", val)
        }
    }
}

fn is_consistent(predicate: &Vec<PredicateClause>) -> bool {
    let name  = predicate.first().unwrap().name();
    let arity = predicate.first().unwrap().arity();

    for clause in predicate.iter().skip(1) {
        if !(name == clause.name() && arity == clause.arity()) {
            return false;
        }
    }

    true
}

#[allow(dead_code)]
pub fn print_code(code: &Code) {
    for clause in code {
        match clause {
            &Line::Fact(ref fact) =>
                for fact_instr in fact {
                    println!("{}", fact_instr);
                },
            &Line::Cut(ref cut) =>
                println!("{}", cut),
            &Line::Choice(ref choice) =>
                println!("{}", choice),
            &Line::Control(ref control) =>
                println!("{}", control),
            &Line::IndexedChoice(ref choice) =>
                println!("{}", choice),
            &Line::Indexing(ref indexing) =>
                println!("{}", indexing),
            &Line::Query(ref query) =>
                for query_instr in query {
                    println!("{}", query_instr);
                }
        }
    }
}

pub fn read() -> String {
    let _ = stdout().flush();

    let mut buffer = String::new();
    let mut result = String::new();

    let stdin = stdin();
    stdin.read_line(&mut buffer).unwrap();

    if &*buffer.trim() == ":{" {
        buffer.clear();

        stdin.read_line(&mut buffer).unwrap();

        while &*buffer.trim() != "}:" {
            result += buffer.as_str();
            buffer.clear();
            stdin.read_line(&mut buffer).unwrap();
        }
    } else {
        result = buffer;
    }

    result
}

pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'b>
{
    match tl {
        &TopLevel::Predicate(ref clauses) => {
            let mut cg = CodeGenerator::<DebrayAllocator>::new();

            if is_consistent(clauses) {
                let compiled_pred = cg.compile_predicate(clauses);
                wam.add_predicate(clauses, compiled_pred);

                EvalSession::EntrySuccess
            } else {
                let msg = r"Error: predicate is inconsistent.
Each predicate must have the same name and arity.";

                println!("{}", msg);
                EvalSession::EntryFailure
            }
        },
        &TopLevel::Fact(ref fact) => {
            let mut cg = CodeGenerator::<DebrayAllocator>::new();

            let compiled_fact = cg.compile_fact(fact);
            wam.add_fact(fact, compiled_fact);

            EvalSession::EntrySuccess
        },
        &TopLevel::Rule(ref rule) => {
            let mut cg = CodeGenerator::<DebrayAllocator>::new();

            let compiled_rule = cg.compile_rule(rule);
            wam.add_rule(rule, compiled_rule);

            EvalSession::EntrySuccess
        },
        &TopLevel::Query(ref query) => {
            let mut cg = CodeGenerator::<DebrayAllocator>::new();

            let compiled_query = cg.compile_query(query);
            wam.submit_query(compiled_query, cg.take_vars())
        }
    }
}

pub fn print(wam: &mut Machine, result: EvalSession) {
    match result {
        EvalSession::InitialQuerySuccess(alloc_locs, mut heap_locs) => {
            print!("true");

            if !wam.or_stack_is_empty() {
                print!(" ");
            }

            println!(".");

            if heap_locs.is_empty() {
                return;
            }

            loop {
                let mut result = EvalSession::QueryFailure;
                let bindings = wam.heap_view(&heap_locs);

                let stdin  = stdin();
                let mut stdout = stdout().into_raw_mode().unwrap();

                write!(stdout, "{}", bindings).unwrap();
                stdout.flush().unwrap();

                if !wam.or_stack_is_empty() {
                    stdout.flush().unwrap();

                    for c in stdin.keys() {
                        match c.unwrap() {
                            Key::Char(';') => {
                                write!(stdout, " ;\n\r").unwrap();
                                result = wam.continue_query(&alloc_locs, &mut heap_locs);
                                break;
                            },
                            Key::Char('.') => {
                                write!(stdout, " .\n\r").unwrap();
                                return;
                            },
                            _ => {}
                        }
                    }

                    if let &EvalSession::QueryFailure = &result {
                        write!(stdout, "false.\n\r").unwrap();
                        stdout.flush().unwrap();
                        return;
                    }
                } else {
                    break;
                }
            }

            write!(stdout(), ".\n").unwrap();
        },
        EvalSession::QueryFailure => println!("false."),
        _ => {}
    };
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::collections::BTreeSet;
use std::fmt::{self, Display};
use parse::NextPrev;

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Range(pub char, pub char);

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.0, self.1)
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Set(BTreeSet<Range>);

impl fmt::Display for Set {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Set(ref set) = *self;
        let len = BTreeSet::len(set);

        for (count, s) in set.iter().enumerate() {
            if count < len - 1 { try!(write!(f, "{}, ", s)) }
            else { return write!(f, "{}", s) }
        }

        Ok(())
    }
}

impl Set {
    pub fn new() -> Self { Set(BTreeSet::new()) }
    pub fn insert(&mut self, value: Range) {
        let mut ret = BTreeSet::new();
        // value is a complete subset of one of the other ranges.
        let mut subset = false;

        // Borrowing self blocks later operation. Add a new scope.
        {   let Set(ref set) = *self;

            let Range(mut min_val, mut max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set adding old disjoint pieces and supersets back.
            // When partially overlapped, expand value to the union. At the
            // end, insert union after it has been fully expanded.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val < min && max_val >= min && max_val < max { max_val = max }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val > max { min_val = min }
                // value is entirely contained between min and max. Insert original
                // into new array because new is a subset.
                else if min_val >= min && max_val <= max {
                    ret.insert(Range(min, max));
                    subset = true;
                }
                // value is a superset to the current so don't add current.
                else if min_val < min && max_val > max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }

            // Insert value only when it's not a subset.
            if !subset { ret.insert(Range(min_val, max_val)); }
        }

        *self = Set(ret);
    }
    pub fn remove(&mut self, value: Range) {
        let mut ret = BTreeSet::new();

        // Borrowing self blocks later modification. Make a new scope to contain it.
        {   let Set(ref set) = *self;

            let Range(min_val, max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set inserting whatever doesn't intersect.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val <= min && max_val >= min && max_val < max { ret.insert(Range(max_val.next(), max)); }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val >= max { ret.insert(Range(min, min_val.prev())); }
                // value is entirely contained between min and max. Split set
                // into two pieces.
                else if min_val > min && max_val < max {
                    ret.insert(Range(min, min_val.prev()));
                    ret.insert(Range(max_val.next(), max));

                    // Current piece was a superset so value cannot be anywhere else.
                    break;
                // value is a superset to the current so don't add current.
                } else if min_val <= min && max_val >= max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }
        }

        *self = Set(ret)
    }
    pub fn union(&mut self, value: Self) {
        for x in value.0 { self.insert(x) }
    }
    // Intersection of `A` & `B` is `A - (A - B)`.
    pub fn intersection(&mut self, value: Self) {
        let mut diff = self.clone();
        diff.difference(value);

        self.difference(diff);
    }
    pub fn difference(&mut self, value: Self) {
        for x in value.0 { self.remove(x) }
    }
}

#[cfg(test)]
mod test {
    use super::{Range, Set};

    fn generate(vec: Vec<(char, char)>) -> Set {
        let mut set = Set::new();

        for (a, b) in vec {
            set.insert(Range(a, b));
        }

        set
    }
    #[test]
    fn insert_partial_overlap() {
        let set1 = generate(vec![('3', '5'), ('4', '6')]);
        let set2 = generate(vec![('3', '5'), ('1', '4')]);

        let other1 = generate(vec![('3', '6')]);
        let other2 = generate(vec![('1', '5')]);

        assert_eq!(other1, set1);
        assert_eq!(other2, set2);
    }
    #[test]
    fn insert_subset() {
        let set1 = generate(vec![('1', '5'), ('2', '3')]); // Complete overlap.
        let set2 = generate(vec![('1', '5'), ('1', '3')]); // Left is exact.
        let set3 = generate(vec![('1', '5'), ('2', '5')]); // Right is exact.
        let set4 = generate(vec![('1', '5'), ('1', '5')]); // Both are exact.

        let other = generate(vec![('1', '5')]);

        assert_eq!(set1, other);
        assert_eq!(set2, other);
        assert_eq!(set3, other);
        assert_eq!(set4, other);
    }
    #[test]
    fn insert_superset() {
        let set   = generate(vec![('3', '5'), ('2', '6')]);
        let other = generate(vec![('2', '6')]);

        assert_eq!(other, set);
    }
    #[test]
    #[should_panic]
    fn panic_on_decreasing_order() {
        generate(vec![('5', '3')]);
    }
    #[test]
    fn set_union() {
        let mut set1 = generate(vec![('1', '4'), ('5', '6')]);
        let set2 =     generate(vec![('0', '5'), ('8', '9')]);

        set1.union(set2);

        let other = generate(vec![('0', '6'), ('8', '9')]);
        assert_eq!(set1, other);
    }
    #[test]
    fn remove_partial_overlap() {
        let mut set1 = generate(vec![('5', '9')]);
        set1.remove(Range('3', '6')); // beginnings different.

        let mut set2 = generate(vec![('5', '9')]);
        set2.remove(Range('5', '6')); // beginnings same.

        let mut set3 = generate(vec![('2', '6')]);
        set3.remove(Range('5', '9')); // end different.

        let mut set4 = generate(vec![('2', '6')]);
        set4.remove(Range('5', '6')); // end same.

        let other12 = generate(vec![('7', '9')]);
        let other34 = generate(vec![('2', '4')]);

        assert_eq!(set1, other12);
        assert_eq!(set2, other12);
        assert_eq!(set3, other34);
        assert_eq!(set4, other34);
    }
    #[test]
    fn remove_subset() {
        let mut set = generate(vec![('1', '9')]);
        set.remove(Range('3', '6'));

        let other = generate(vec![('1', '2'), ('7', '9')]);

        assert_eq!(set, other);
    }
    #[test]
    fn remove_superset() {
        let mut set = generate(vec![('5', '6')]);
        set.remove(Range('3', '8'));

        let other = generate(vec![]);
        assert_eq!(set, other);
    }
    #[test]
    fn remove_disjoint() {
        let mut set = generate(vec![('2', '3')]);
        set.remove(Range('6', '8'));

        let other = generate(vec![('2', '3')]);
        assert_eq!(set, other);
    }
    #[test]
    fn set_difference() {
        let mut set1 = generate(vec![('2', '7')]);
        let set2     = generate(vec![('0', '1'),   // disjoint left
                                     ('1', '2'),   // partial overlap left
                                     ('4', '5'),   // subset
                                     ('7', '8'),   // partial overlap right
                                     ('9', '9')]); // disjoint right
        let mut letters1 = generate(vec![('c', 'e')]);
        let     letters2 = generate(vec![('a', 'g')]); // superset

        set1.difference(set2);
        letters1.difference(letters2);

        let other_set     = generate(vec![('3', '3'), ('6', '6')]);
        let other_letters = generate(vec![]);

        assert_eq!(set1, other_set);
        assert_eq!(letters1, other_letters);
    }
    #[test]
    fn set_intersection_partial_overlap() {
        let mut set_left  = generate(vec![('2', '7')]);
        let partial_left  = generate(vec![('0', '3')]);

        let mut set_right = generate(vec![('2', '7')]);
        let partial_right = generate(vec![('6', '8')]);

        set_left.intersection(partial_left);
        set_right.intersection(partial_right);

        let other_left  = generate(vec![('2', '3')]);
        let other_right = generate(vec![('6', '7')]);

        assert_eq!(set_left, other_left);
        assert_eq!(set_right, other_right);
    }
    #[test]
    fn set_intersection_subset() {
        let mut set_subset = generate(vec![('2', '7')]);
        let subset         = generate(vec![('3', '6')]);

        let mut set_left = generate(vec![('2', '7')]);
        let exact_left   = generate(vec![('2', '6')]);

        let mut set_right = generate(vec![('2', '7')]);
        let exact_right   = generate(vec![('3', '7')]);

        let mut set_both = generate(vec![('2', '7')]);
        let exact_both   = generate(vec![('2', '7')]);

        set_subset.intersection(subset);
        set_left.intersection(exact_left);
        set_right.intersection(exact_right);
        set_both.intersection(exact_both);

        let other_subset = generate(vec![('3', '6')]);
        let other_left   = generate(vec![('2', '6')]);
        let other_right  = generate(vec![('3', '7')]);
        let other_both   = generate(vec![('2', '7')]);

        assert_eq!(set_subset, other_subset);
        assert_eq!(set_left, other_left);
        assert_eq!(set_right, other_right);
        assert_eq!(set_both, other_both);
    }
    #[test]
    fn set_intersection_superset() {
        let mut set  = generate(vec![('2', '7')]);
        let superset = generate(vec![('1', '8')]);

        set.intersection(superset);

        let other = generate(vec![('2', '7')]);
        assert_eq!(set, other);
    }
    #[test]
    fn set_intersection_disjoint() {
        let mut set_low  = generate(vec![('3', '4')]);
        let mut set_high = generate(vec![('3', '4')]);
        let low  = generate(vec![('1', '2')]);
        let high = generate(vec![('5', '6')]);

        set_low.intersection(low);
        set_high.intersection(high);

        let other_low  = generate(vec![]);
        let other_high = generate(vec![]);

        assert_eq!(set_low, other_low);
        assert_eq!(set_high, other_high);
    }
}
<commit_msg>Add symmetric difference. Change set ops to borrow instead of taking by value.<commit_after>#![allow(dead_code)]

use std::collections::BTreeSet;
use std::fmt::{self, Display};
use parse::NextPrev;

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Range(pub char, pub char);

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.0, self.1)
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Set(BTreeSet<Range>);

impl fmt::Display for Set {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Set(ref set) = *self;
        let len = BTreeSet::len(set);

        for (count, s) in set.iter().enumerate() {
            if count < len - 1 { try!(write!(f, "{}, ", s)) }
            else { return write!(f, "{}", s) }
        }

        Ok(())
    }
}

impl Set {
    pub fn new() -> Self { Set(BTreeSet::new()) }
    pub fn insert(&mut self, value: Range) {
        let mut ret = BTreeSet::new();
        // value is a complete subset of one of the other ranges.
        let mut subset = false;

        // Borrowing self blocks later operation. Add a new scope.
        {   let Set(ref set) = *self;

            let Range(mut min_val, mut max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set adding old disjoint pieces and supersets back.
            // When partially overlapped, expand value to the union. At the
            // end, insert union after it has been fully expanded.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val < min && max_val >= min && max_val < max { max_val = max }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val > max { min_val = min }
                // value is entirely contained between min and max. Insert original
                // into new array because new is a subset.
                else if min_val >= min && max_val <= max {
                    ret.insert(Range(min, max));
                    subset = true;
                }
                // value is a superset to the current so don't add current.
                else if min_val < min && max_val > max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }

            // Insert value only when it's not a subset.
            if !subset { ret.insert(Range(min_val, max_val)); }
        }

        *self = Set(ret);
    }
    pub fn remove(&mut self, value: Range) {
        let mut ret = BTreeSet::new();

        // Borrowing self blocks later modification. Make a new scope to contain it.
        {   let Set(ref set) = *self;

            let Range(min_val, max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set inserting whatever doesn't intersect.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val <= min && max_val >= min && max_val < max { ret.insert(Range(max_val.next(), max)); }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val >= max { ret.insert(Range(min, min_val.prev())); }
                // value is entirely contained between min and max. Split set
                // into two pieces.
                else if min_val > min && max_val < max {
                    ret.insert(Range(min, min_val.prev()));
                    ret.insert(Range(max_val.next(), max));

                    // Current piece was a superset so value cannot be anywhere else.
                    break;
                // value is a superset to the current so don't add current.
                } else if min_val <= min && max_val >= max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }
        }

        *self = Set(ret)
    }
    // 123 + 345 = 12345.
    pub fn union(&self, value: &Self) -> Self {
        let mut ret = self.clone();

        // Loop over the btreeset of Range(char, char).
        for &x in &value.0 { ret.insert(x) }

        ret
    }
    // Intersection of `A` & `B` is `A - (A - B)`: 123 & 345 = 3.
    pub fn intersection(&self, value: &Self) -> Self {
        let diff = self.difference(value);

        self.difference(&diff)
    }
    // 123 - 345 = 12.
    pub fn difference(&self, value: &Self) -> Self {
        let mut ret = self.clone();

        for &x in &value.0 { ret.remove(x) }

        ret
    }
    // `A` ^ `B` is `(A + B) - (A & B)`: 123 ^ 345 = 1245.
    pub fn symmetric_difference(&self, value: &Self) -> Self {
        let union = self.union(value);
        let intersection = self.intersection(value);

        union.difference(&intersection)
    }
}

#[cfg(test)]
mod test {
    use super::{Range, Set};

    fn generate(vec: Vec<(char, char)>) -> Set {
        let mut set = Set::new();

        for (a, b) in vec {
            set.insert(Range(a, b));
        }

        set
    }
    #[test]
    fn insert_partial_overlap() {
        let set1 = generate(vec![('3', '5'), ('4', '6')]);
        let set2 = generate(vec![('3', '5'), ('1', '4')]);

        let other1 = generate(vec![('3', '6')]);
        let other2 = generate(vec![('1', '5')]);

        assert_eq!(other1, set1);
        assert_eq!(other2, set2);
    }
    #[test]
    fn insert_subset() {
        let set1 = generate(vec![('1', '5'), ('2', '3')]); // Complete overlap.
        let set2 = generate(vec![('1', '5'), ('1', '3')]); // Left is exact.
        let set3 = generate(vec![('1', '5'), ('2', '5')]); // Right is exact.
        let set4 = generate(vec![('1', '5'), ('1', '5')]); // Both are exact.

        let other = generate(vec![('1', '5')]);

        assert_eq!(set1, other);
        assert_eq!(set2, other);
        assert_eq!(set3, other);
        assert_eq!(set4, other);
    }
    #[test]
    fn insert_superset() {
        let set   = generate(vec![('3', '5'), ('2', '6')]);
        let other = generate(vec![('2', '6')]);

        assert_eq!(other, set);
    }
    #[test]
    #[should_panic]
    fn panic_on_decreasing_order() {
        generate(vec![('5', '3')]);
    }
    #[test]
    fn set_union() {
        let mut set1 = generate(vec![('1', '4'), ('5', '6')]);
        let set2 =     generate(vec![('0', '5'), ('8', '9')]);

        set1.union(set2);

        let other = generate(vec![('0', '6'), ('8', '9')]);
        assert_eq!(set1, other);
    }
    #[test]
    fn remove_partial_overlap() {
        let mut set1 = generate(vec![('5', '9')]);
        set1.remove(Range('3', '6')); // beginnings different.

        let mut set2 = generate(vec![('5', '9')]);
        set2.remove(Range('5', '6')); // beginnings same.

        let mut set3 = generate(vec![('2', '6')]);
        set3.remove(Range('5', '9')); // end different.

        let mut set4 = generate(vec![('2', '6')]);
        set4.remove(Range('5', '6')); // end same.

        let other12 = generate(vec![('7', '9')]);
        let other34 = generate(vec![('2', '4')]);

        assert_eq!(set1, other12);
        assert_eq!(set2, other12);
        assert_eq!(set3, other34);
        assert_eq!(set4, other34);
    }
    #[test]
    fn remove_subset() {
        let mut set = generate(vec![('1', '9')]);
        set.remove(Range('3', '6'));

        let other = generate(vec![('1', '2'), ('7', '9')]);

        assert_eq!(set, other);
    }
    #[test]
    fn remove_superset() {
        let mut set = generate(vec![('5', '6')]);
        set.remove(Range('3', '8'));

        let other = generate(vec![]);
        assert_eq!(set, other);
    }
    #[test]
    fn remove_disjoint() {
        let mut set = generate(vec![('2', '3')]);
        set.remove(Range('6', '8'));

        let other = generate(vec![('2', '3')]);
        assert_eq!(set, other);
    }
    #[test]
    fn set_difference() {
        let mut set1 = generate(vec![('2', '7')]);
        let set2     = generate(vec![('0', '1'),   // disjoint left
                                     ('1', '2'),   // partial overlap left
                                     ('4', '5'),   // subset
                                     ('7', '8'),   // partial overlap right
                                     ('9', '9')]); // disjoint right
        let mut letters1 = generate(vec![('c', 'e')]);
        let     letters2 = generate(vec![('a', 'g')]); // superset

        set1.difference(set2);
        letters1.difference(letters2);

        let other_set     = generate(vec![('3', '3'), ('6', '6')]);
        let other_letters = generate(vec![]);

        assert_eq!(set1, other_set);
        assert_eq!(letters1, other_letters);
    }
    #[test]
    fn set_intersection_partial_overlap() {
        let mut set_left  = generate(vec![('2', '7')]);
        let partial_left  = generate(vec![('0', '3')]);

        let mut set_right = generate(vec![('2', '7')]);
        let partial_right = generate(vec![('6', '8')]);

        set_left.intersection(partial_left);
        set_right.intersection(partial_right);

        let other_left  = generate(vec![('2', '3')]);
        let other_right = generate(vec![('6', '7')]);

        assert_eq!(set_left, other_left);
        assert_eq!(set_right, other_right);
    }
    #[test]
    fn set_intersection_subset() {
        let mut set_subset = generate(vec![('2', '7')]);
        let subset         = generate(vec![('3', '6')]);

        let mut set_left = generate(vec![('2', '7')]);
        let exact_left   = generate(vec![('2', '6')]);

        let mut set_right = generate(vec![('2', '7')]);
        let exact_right   = generate(vec![('3', '7')]);

        let mut set_both = generate(vec![('2', '7')]);
        let exact_both   = generate(vec![('2', '7')]);

        set_subset.intersection(subset);
        set_left.intersection(exact_left);
        set_right.intersection(exact_right);
        set_both.intersection(exact_both);

        let other_subset = generate(vec![('3', '6')]);
        let other_left   = generate(vec![('2', '6')]);
        let other_right  = generate(vec![('3', '7')]);
        let other_both   = generate(vec![('2', '7')]);

        assert_eq!(set_subset, other_subset);
        assert_eq!(set_left, other_left);
        assert_eq!(set_right, other_right);
        assert_eq!(set_both, other_both);
    }
    #[test]
    fn set_intersection_superset() {
        let mut set  = generate(vec![('2', '7')]);
        let superset = generate(vec![('1', '8')]);

        set.intersection(superset);

        let other = generate(vec![('2', '7')]);
        assert_eq!(set, other);
    }
    #[test]
    fn set_intersection_disjoint() {
        let mut set_low  = generate(vec![('3', '4')]);
        let mut set_high = generate(vec![('3', '4')]);
        let low  = generate(vec![('1', '2')]);
        let high = generate(vec![('5', '6')]);

        set_low.intersection(low);
        set_high.intersection(high);

        let other_low  = generate(vec![]);
        let other_high = generate(vec![]);

        assert_eq!(set_low, other_low);
        assert_eq!(set_high, other_high);
    }
}
<|endoftext|>