<commit_before>/// The focus on this file is to describe the data-structures
/// for IA-32e paging mode.
use core::fmt;
use core::mem::{size_of};

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

/// 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
}

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 {
    pub fn new(pdpt: PAddr, flags: PML4Entry) -> PML4Entry {
        assert!(pdpt % BASE_PAGE_SIZE == 0);
        PML4Entry { bits: pdpt | flags.bits }
    }

    pub fn get_address(&self) -> PAddr {
        self.bits & ADDRESS_MASK
    }
}

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

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 {
    pub fn new(pd: PAddr, flags: PDPTEntry) -> PDPTEntry {
        assert!(pd % BASE_PAGE_SIZE == 0);
        PDPTEntry { bits: pd | flags.bits }
    }

    pub fn get_address(&self) -> PAddr {
        self.bits & ADDRESS_MASK
    }
}

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

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 {
    pub fn new(pt: PAddr, flags: PDEntry) -> PDEntry {
        assert!(pt % BASE_PAGE_SIZE == 0);
        PDEntry { bits: pt | flags.bits }
    }

    pub fn get_address(&self) -> PAddr {
        self.bits & ADDRESS_MASK
    }
}

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

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 {
    pub fn new(page: PAddr, flags: PTEntry) -> PTEntry {
        assert!(page % BASE_PAGE_SIZE == 0);
        PTEntry{ bits: page | flags.bits }
    }

    pub fn get_address(&self) -> PAddr {
        self.bits & ADDRESS_MASK
    }
}

impl fmt::Debug for PTEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.bits)
    }
}
<commit_msg>Documentation for memory structures.<commit_after>/// The focus on this file is to describe the data-structures
/// for IA-32e paging mode.
use core::fmt;
use core::mem::{size_of};

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

/// 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)
    }
}
<|endoftext|>


<commit_before>use super::*;
use error::*;
use ffi::*;

#[derive(Debug, Clone)]
struct Alignment {
    in_: i32,
    out: i32,
}

impl Alignment {
    fn new<A: FFTW, B: FFTW>(in_: &[A], out: &[B]) -> Self {
        Self {
            in_: A::alignment_of(in_),
            out: B::alignment_of(out),
        }
    }
    fn check<A: FFTW, B: FFTW>(&self, in_: &[A], out: &[B]) -> Result<()> {
        if self.in_ != A::alignment_of(in_) || self.out != B::alignment_of(out) {
            Err(AlignmentMismatchError::new().into())
        } else {
            Ok(())
        }
    }
}

#[derive(Debug, Clone)]
struct Shape(Vec<i32>);

impl Shape {
    fn new(s: &[i32]) -> Self {
        Shape(s.to_vec())
    }
    fn check<A: FFTW, B: FFTW>(&self, in_: &[A], out: &[B]) -> Result<()> {
        let n = self.0.len();
        if in_.len() != n || out.len() != n {
            Err(SizeMismatchError::new().into())
        } else {
            Ok(())
        }
    }
}

#[derive(Debug)]
pub struct C2CPlan<C: FFTW> {
    plan: C::Plan,
    shape: Shape,
    sign: Sign,
    flag: FLAG,
    alignment: Alignment,
}

impl<C: FFTW> Drop for C2CPlan<C> {
    fn drop(&mut self) {
        C::destroy_plan(self.plan);
    }
}

impl<C: FFTW<Complex = C>> C2CPlan<C> {
    pub fn new(shape: &[i32], in_: &[C], out: &[C], sign: Sign, flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_c2c(&shape, in_, out, sign, flag)?,
            shape: Shape::new(shape),
            sign,
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn c2c(&mut self, in_: &[C], out: &mut [C]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_c2c(self.plan, in_, out);
        Ok(())
    }
}

#[derive(Debug)]
pub struct C2RPlan<C, R>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    plan: C::Plan,
    shape: Shape,
    flag: FLAG,
    alignment: Alignment,
}

impl<C, R> Drop for C2RPlan<C, R>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    fn drop(&mut self) {
        R::destroy_plan(self.plan);
    }
}

impl<C, R> C2RPlan<C, R>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    pub fn new(shape: &[i32], in_: &[C], out: &[R], flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_c2r(&shape, in_, out, flag)?,
            shape: Shape::new(shape),
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn c2r(&mut self, in_: &[C], out: &mut [R]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_c2r(self.plan, in_, out);
        Ok(())
    }
}

#[derive(Debug)]
pub struct R2CPlan<R, C>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    plan: C::Plan,
    shape: Shape,
    flag: FLAG,
    alignment: Alignment,
}

impl<R, C> Drop for R2CPlan<R, C>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    fn drop(&mut self) {
        R::destroy_plan(self.plan);
    }
}

impl<R, C> R2CPlan<R, C>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    pub fn new(shape: &[i32], in_: &[R], out: &[C], flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_r2c(&shape, in_, out, flag)?,
            shape: Shape::new(shape),
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn r2c(&mut self, in_: &[R], out: &mut [C]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_r2c(self.plan, in_, out);
        Ok(())
    }
}

pub type R2RKind = ffi::fftw_r2r_kind;

#[derive(Debug)]
pub struct R2RPlan<R: FFTW> {
    plan: R::Plan,
    shape: Shape,
    kind: Vec<R2RKind>,
    flag: FLAG,
    alignment: Alignment,
}

impl<R: FFTW> Drop for R2RPlan<R> {
    fn drop(&mut self) {
        R::destroy_plan(self.plan);
    }
}

impl<R: FFTW<Real = R>> R2RPlan<R> {
    pub fn new(shape: &[i32], in_: &[R], out: &[R], kinds: &[R2RKind], flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: R::plan_r2r(&shape, in_, out, kinds, flag)?,
            shape: Shape::new(shape),
            kind: kinds.to_vec(),
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn r2c(&mut self, in_: &[R], out: &mut [R]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        R::exec_r2r(self.plan, in_, out);
        Ok(())
    }
}

pub trait Plan: Sized {
    fn check_null(self) -> Result<Self>;
}

impl Plan for fftw_plan {
    fn check_null(self) -> Result<Self> {
        if self.is_null() {
            Err(InvalidPlanError::new().into())
        } else {
            Ok(self)
        }
    }
}

impl Plan for fftwf_plan {
    fn check_null(self) -> Result<Self> {
        if self.is_null() {
            Err(InvalidPlanError::new().into())
        } else {
            Ok(self)
        }
    }
}

/// Switch `fftw_*` and `fftwf_*`
pub trait FFTW {
    type Plan: Plan + Copy;
    type Real;
    type Complex;
    fn destroy_plan(Self::Plan);
    fn print_plan(Self::Plan);
    fn plan_c2c(shape: &[i32], in_: &[Self::Complex], out: &[Self::Complex], Sign, FLAG) -> Result<Self::Plan>;
    fn plan_c2r(shape: &[i32], in_: &[Self::Complex], out: &[Self::Real], FLAG) -> Result<Self::Plan>;
    fn plan_r2c(shape: &[i32], in_: &[Self::Real], out: &[Self::Complex], FLAG) -> Result<Self::Plan>;
    fn plan_r2r(shape: &[i32], in_: &[Self::Real], out: &[Self::Real], &[R2RKind], FLAG) -> Result<Self::Plan>;
    fn exec_c2c(p: Self::Plan, in_: &[Self::Complex], &mut [Self::Complex]);
    fn exec_c2r(p: Self::Plan, in_: &[Self::Complex], &mut [Self::Real]);
    fn exec_r2c(p: Self::Plan, in_: &[Self::Real], &mut [Self::Complex]);
    fn exec_r2r(p: Self::Plan, in_: &[Self::Real], &mut [Self::Real]);
    fn alignment_of<T>(&[T]) -> i32;
}

macro_rules! excall {
    ($call:expr) => {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe { $call }
    }
}

impl FFTW for c64 {
    type Plan = fftw_plan;
    type Real = f64;
    type Complex = c64;
    fn destroy_plan(p: Self::Plan) {
        excall!{ fftw_destroy_plan(p) };
    }
    fn print_plan(p: Self::Plan) {
        excall!{ fftw_print_plan(p) };
    }
    fn plan_c2c(
        shape: &[i32],
        in_: &[Self::Complex],
        out: &[Self::Complex],
        sign: Sign,
        flag: FLAG,
    ) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, sign, flag).check_null() }
    }
    fn plan_c2r(shape: &[i32], in_: &[Self::Complex], out: &[Self::Real], flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft_c2r(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, flag).check_null() }
    }
    fn plan_r2c(shape: &[i32], in_: &[Self::Real], out: &[Self::Complex], flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft_r2c(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, flag).check_null() }
    }
    fn plan_r2r(
        shape: &[i32],
        in_: &[Self::Real],
        out: &[Self::Real],
        kinds: &[R2RKind],
        flag: FLAG,
    ) -> Result<Self::Plan> {
        excall!{ fftw_plan_r2r(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, kinds.as_ptr() as *mut _, flag).check_null() }
    }
    fn exec_c2c(p: Self::Plan, in_: &[Self::Complex], out: &mut [Self::Complex]) {
        unsafe { fftw_execute_dft(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_c2r(p: Self::Plan, in_: &[Self::Complex], out: &mut [Self::Real]) {
        unsafe { fftw_execute_dft_c2r(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_r2c(p: Self::Plan, in_: &[Self::Real], out: &mut [Self::Complex]) {
        unsafe { fftw_execute_dft_r2c(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_r2r(p: Self::Plan, in_: &[Self::Real], out: &mut [Self::Real]) {
        unsafe { fftw_execute_r2r(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn alignment_of<T>(s: &[T]) -> i32 {
        unsafe { fftw_alignment_of(s.as_ptr() as *mut _) }
    }
}
<commit_msg>Impl FFTW for scalars<commit_after>use super::*;
use error::*;
use ffi::*;

#[derive(Debug, Clone)]
struct Alignment {
    in_: i32,
    out: i32,
}

impl Alignment {
    fn new<A: FFTW, B: FFTW>(in_: &[A], out: &[B]) -> Self {
        Self {
            in_: A::alignment_of(in_),
            out: B::alignment_of(out),
        }
    }
    fn check<A: FFTW, B: FFTW>(&self, in_: &[A], out: &[B]) -> Result<()> {
        if self.in_ != A::alignment_of(in_) || self.out != B::alignment_of(out) {
            Err(AlignmentMismatchError::new().into())
        } else {
            Ok(())
        }
    }
}

#[derive(Debug, Clone)]
struct Shape(Vec<i32>);

impl Shape {
    fn new(s: &[i32]) -> Self {
        Shape(s.to_vec())
    }
    fn check<A: FFTW, B: FFTW>(&self, in_: &[A], out: &[B]) -> Result<()> {
        let n = self.0.len();
        if in_.len() != n || out.len() != n {
            Err(SizeMismatchError::new().into())
        } else {
            Ok(())
        }
    }
}

#[derive(Debug)]
pub struct C2CPlan<C: FFTW> {
    plan: C::Plan,
    shape: Shape,
    sign: Sign,
    flag: FLAG,
    alignment: Alignment,
}

impl<C: FFTW> Drop for C2CPlan<C> {
    fn drop(&mut self) {
        C::destroy_plan(self.plan);
    }
}

impl<C: FFTW<Complex = C>> C2CPlan<C> {
    pub fn new(shape: &[i32], in_: &[C], out: &[C], sign: Sign, flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_c2c(&shape, in_, out, sign, flag)?,
            shape: Shape::new(shape),
            sign,
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn c2c(&mut self, in_: &[C], out: &mut [C]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_c2c(self.plan, in_, out);
        Ok(())
    }
}

#[derive(Debug)]
pub struct C2RPlan<C, R>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    plan: C::Plan,
    shape: Shape,
    flag: FLAG,
    alignment: Alignment,
}

impl<C, R> Drop for C2RPlan<C, R>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    fn drop(&mut self) {
        R::destroy_plan(self.plan);
    }
}

impl<C, R> C2RPlan<C, R>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    pub fn new(shape: &[i32], in_: &[C], out: &[R], flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_c2r(&shape, in_, out, flag)?,
            shape: Shape::new(shape),
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn c2r(&mut self, in_: &[C], out: &mut [R]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_c2r(self.plan, in_, out);
        Ok(())
    }
}

#[derive(Debug)]
pub struct R2CPlan<R, C>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    plan: C::Plan,
    shape: Shape,
    flag: FLAG,
    alignment: Alignment,
}

impl<R, C> Drop for R2CPlan<R, C>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    fn drop(&mut self) {
        R::destroy_plan(self.plan);
    }
}

impl<R, C> R2CPlan<R, C>
where
    C: FFTW<Real = R, Complex = C>,
    R: FFTW<Real = R, Complex = C, Plan = C::Plan>,
{
    pub fn new(shape: &[i32], in_: &[R], out: &[C], flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: C::plan_r2c(&shape, in_, out, flag)?,
            shape: Shape::new(shape),
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn r2c(&mut self, in_: &[R], out: &mut [C]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        C::exec_r2c(self.plan, in_, out);
        Ok(())
    }
}

pub type R2RKind = ffi::fftw_r2r_kind;

#[derive(Debug)]
pub struct R2RPlan<R: FFTW> {
    plan: R::Plan,
    shape: Shape,
    kind: Vec<R2RKind>,
    flag: FLAG,
    alignment: Alignment,
}

impl<R: FFTW> Drop for R2RPlan<R> {
    fn drop(&mut self) {
        R::destroy_plan(self.plan);
    }
}

impl<R: FFTW<Real = R>> R2RPlan<R> {
    pub fn new(shape: &[i32], in_: &[R], out: &[R], kinds: &[R2RKind], flag: FLAG) -> Result<Self> {
        Ok(Self {
            plan: R::plan_r2r(&shape, in_, out, kinds, flag)?,
            shape: Shape::new(shape),
            kind: kinds.to_vec(),
            flag,
            alignment: Alignment::new(in_, out),
        })
    }
    pub fn r2c(&mut self, in_: &[R], out: &mut [R]) -> Result<()> {
        self.alignment.check(in_, out)?;
        self.shape.check(in_, out)?;
        R::exec_r2r(self.plan, in_, out);
        Ok(())
    }
}

pub trait Plan: Sized {
    fn check_null(self) -> Result<Self>;
}

impl Plan for fftw_plan {
    fn check_null(self) -> Result<Self> {
        if self.is_null() {
            Err(InvalidPlanError::new().into())
        } else {
            Ok(self)
        }
    }
}

impl Plan for fftwf_plan {
    fn check_null(self) -> Result<Self> {
        if self.is_null() {
            Err(InvalidPlanError::new().into())
        } else {
            Ok(self)
        }
    }
}

/// Switch `fftw_*` and `fftwf_*`
pub trait FFTW {
    type Plan: Plan + Copy;
    type Real;
    type Complex;
    fn destroy_plan(Self::Plan);
    fn print_plan(Self::Plan);
    fn plan_c2c(shape: &[i32], in_: &[Self::Complex], out: &[Self::Complex], Sign, FLAG) -> Result<Self::Plan>;
    fn plan_c2r(shape: &[i32], in_: &[Self::Complex], out: &[Self::Real], FLAG) -> Result<Self::Plan>;
    fn plan_r2c(shape: &[i32], in_: &[Self::Real], out: &[Self::Complex], FLAG) -> Result<Self::Plan>;
    fn plan_r2r(shape: &[i32], in_: &[Self::Real], out: &[Self::Real], &[R2RKind], FLAG) -> Result<Self::Plan>;
    fn exec_c2c(p: Self::Plan, in_: &[Self::Complex], &mut [Self::Complex]);
    fn exec_c2r(p: Self::Plan, in_: &[Self::Complex], &mut [Self::Real]);
    fn exec_r2c(p: Self::Plan, in_: &[Self::Real], &mut [Self::Complex]);
    fn exec_r2r(p: Self::Plan, in_: &[Self::Real], &mut [Self::Real]);
    fn alignment_of<T>(&[T]) -> i32;
}

macro_rules! excall {
    ($call:expr) => {
        let _lock = FFTW_MUTEX.lock().expect("Cannot get lock");
        unsafe { $call }
    }
}

macro_rules! impl_fftw { ($scalar:ty) => {
impl FFTW for $scalar {
    type Real = f64;
    type Complex = c64;
    type Plan = fftw_plan;
    fn destroy_plan(p: Self::Plan) {
        excall!{ fftw_destroy_plan(p) };
    }
    fn print_plan(p: Self::Plan) {
        excall!{ fftw_print_plan(p) };
    }
    fn plan_c2c(shape: &[i32], in_: &[Self::Complex], out: &[Self::Complex], sign: Sign, flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, sign, flag).check_null() }
    }
    fn plan_c2r(shape: &[i32], in_: &[Self::Complex], out: &[Self::Real], flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft_c2r(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, flag).check_null() }
    }
    fn plan_r2c(shape: &[i32], in_: &[Self::Real], out: &[Self::Complex], flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftw_plan_dft_r2c(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, flag).check_null() }
    }
    fn plan_r2r(shape: &[i32], in_: &[Self::Real], out: &[Self::Real], kinds: &[R2RKind], flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftw_plan_r2r(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, kinds.as_ptr() as *mut _, flag).check_null() }
    }
    fn exec_c2c(p: Self::Plan, in_: &[Self::Complex], out: &mut [Self::Complex]) {
        unsafe { fftw_execute_dft(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_c2r(p: Self::Plan, in_: &[Self::Complex], out: &mut [Self::Real]) {
        unsafe { fftw_execute_dft_c2r(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_r2c(p: Self::Plan, in_: &[Self::Real], out: &mut [Self::Complex]) {
        unsafe { fftw_execute_dft_r2c(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_r2r(p: Self::Plan, in_: &[Self::Real], out: &mut [Self::Real]) {
        unsafe { fftw_execute_r2r(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn alignment_of<T>(s: &[T]) -> i32 {
        unsafe { fftw_alignment_of(s.as_ptr() as *mut _) }
    }
}
}} // impl_fftw

impl_fftw!(f64);
impl_fftw!(c64);

macro_rules! impl_fftwf { ($scalar:ty) => {
impl FFTW for $scalar {
    type Real = f32;
    type Complex = c32;
    type Plan = fftwf_plan;
    fn destroy_plan(p: Self::Plan) {
        excall!{ fftwf_destroy_plan(p) };
    }
    fn print_plan(p: Self::Plan) {
        excall!{ fftwf_print_plan(p) };
    }
    fn plan_c2c(shape: &[i32], in_: &[Self::Complex], out: &[Self::Complex], sign: Sign, flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftwf_plan_dft(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, sign, flag).check_null() }
    }
    fn plan_c2r(shape: &[i32], in_: &[Self::Complex], out: &[Self::Real], flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftwf_plan_dft_c2r(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, flag).check_null() }
    }
    fn plan_r2c(shape: &[i32], in_: &[Self::Real], out: &[Self::Complex], flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftwf_plan_dft_r2c(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, flag).check_null() }
    }
    fn plan_r2r(shape: &[i32], in_: &[Self::Real], out: &[Self::Real], kinds: &[R2RKind], flag: FLAG) -> Result<Self::Plan> {
        excall!{ fftwf_plan_r2r(shape.len() as i32, shape.as_ptr(), in_.as_ptr() as *mut _, out.as_ptr() as *mut _, kinds.as_ptr() as *mut _, flag).check_null() }
    }
    fn exec_c2c(p: Self::Plan, in_: &[Self::Complex], out: &mut [Self::Complex]) {
        unsafe { fftwf_execute_dft(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_c2r(p: Self::Plan, in_: &[Self::Complex], out: &mut [Self::Real]) {
        unsafe { fftwf_execute_dft_c2r(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_r2c(p: Self::Plan, in_: &[Self::Real], out: &mut [Self::Complex]) {
        unsafe { fftwf_execute_dft_r2c(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn exec_r2r(p: Self::Plan, in_: &[Self::Real], out: &mut [Self::Real]) {
        unsafe { fftwf_execute_r2r(p, in_.as_ptr() as *mut _, out.as_mut_ptr()) };
    }
    fn alignment_of<T>(s: &[T]) -> i32 {
        unsafe { fftwf_alignment_of(s.as_ptr() as *mut _) }
    }
}
}} // impl_fftwf

impl_fftwf!(f32);
impl_fftwf!(c32);
<|endoftext|>


<commit_before>use super::VirtualMachine;
use std::num::Wrapping;

pub fn jump_to_sys_routine(_vm: &mut VirtualMachine, _addr: usize) {
    // Do nothing
}

pub fn clear_display(vm: &mut VirtualMachine) {
    for px in vm.display.iter_mut() {
        *px = 0;
    }
}

pub fn ret_from_subroutine(vm: &mut VirtualMachine) {
    vm.pc = vm.stack[vm.sp as usize];
    vm.sp -= 1;
}

pub fn jump_addr(vm: &mut VirtualMachine, addr: u16) {
    vm.pc = addr;
}

pub fn call_subroutine(vm: &mut VirtualMachine, addr: usize) {
    vm.sp += 1;
    vm.stack[vm.sp as usize] = vm.pc;
    vm.pc = addr as u16;
}

pub fn skip_next_vx_eq(vm: &mut VirtualMachine, x: usize, to: u8) {
    if vm.v[x].0 == to {
        vm.pc += 2;
    }
}

pub fn skip_next_vx_ne(vm: &mut VirtualMachine, x: usize, to: u8) {
    if vm.v[x].0 != to {
        vm.pc += 2;
    }
}

pub fn skip_next_vx_eq_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    if vm.v[x] == vm.v[y] {
        vm.pc += 2;
    }
}

pub fn set_vx_byte(vm: &mut VirtualMachine, x: usize, byte: u8) {
    vm.v[x].0 = byte;
}

pub fn add_vx_byte(vm: &mut VirtualMachine, x: usize, byte: u8) {
    vm.v[x] = vm.v[x] + Wrapping(byte);
}

pub fn set_vx_to_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[x] = vm.v[y];
}

pub fn set_vx_to_vx_or_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[x] = vm.v[x] | vm.v[y];
}

pub fn set_vx_to_vx_and_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[x] = vm.v[x] & vm.v[y];
}

pub fn set_vx_to_vx_xor_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[x] = vm.v[x] ^ vm.v[y];
}

pub fn add_vx_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[0xF].0 = if vm.v[x].0 as u16 + vm.v[y].0 as u16 > 255 {
        1
    } else {
        0
    };
    vm.v[x] = vm.v[x] + vm.v[y];
}

pub fn sub_vx_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[0xF].0 = if vm.v[x] > vm.v[y] { 1 } else { 0 };
    vm.v[x] = vm.v[x] - vm.v[y];
}

pub fn subn_vx_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[0xF].0 = if vm.v[y] > vm.v[x] { 1 } else { 0 };
    vm.v[x] = vm.v[y] - vm.v[x];
}

pub fn set_vx_to_vy_shr_1(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[0xF].0 = nth_bit(vm.v[y].0, 7);
    vm.v[x] = vm.v[y] >> 1;
}

pub fn set_vx_to_vy_shl_1(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[0xF].0 = nth_bit(vm.v[y].0, 0);
    vm.v[x] = vm.v[y] << 1;
}

fn nth_bit(byte: u8, pos: usize) -> u8 {
    use bit_utils::BitInformation;
    if byte.has_x_bit(7 - pos) { 1 } else { 0 }
}

#[test]
fn test_nth_bit() {
    assert_eq!(nth_bit(0b10000000, 0), 1);
    for i in 1..8 {
        assert_eq!(nth_bit(0b10000000, i), 0);
    }
    assert_eq!(nth_bit(0b01000000, 1), 1);
    assert_eq!(nth_bit(0b00100000, 2), 1);
    assert_eq!(nth_bit(0b00010000, 3), 1);
    assert_eq!(nth_bit(0b00001000, 4), 1);
    assert_eq!(nth_bit(0b00000100, 5), 1);
    assert_eq!(nth_bit(0b00000010, 6), 1);
    assert_eq!(nth_bit(0b00000001, 7), 1);
}

pub fn skip_next_vx_ne_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    if vm.v[x] != vm.v[y] {
        vm.pc += 2;
    }
}

pub fn set_i(vm: &mut VirtualMachine, to: u16) {
    vm.i = to;
}

extern crate rand;

pub fn set_vx_rand_and(vm: &mut VirtualMachine, x: usize, to: u8) {
    use self::rand::Rng;
    let mut rgen = rand::thread_rng();
    vm.v[x].0 = rgen.gen::<u8>() & to;
}

pub fn display_sprite(vm: &mut VirtualMachine, vx: usize, vy: usize, n: usize) {
    use super::{DISPLAY_HEIGHT, DISPLAY_WIDTH};

    vm.v[0xF].0 = 0;

    for y in 0..n {
        let b = vm.ram[vm.i as usize + y];
        for x in 0..8 {
            let xx = x + vm.v[vx].0 as usize;
            let yy = y + vm.v[vy].0 as usize;

            if xx < DISPLAY_WIDTH && yy < DISPLAY_HEIGHT {
                let idx = yy * DISPLAY_WIDTH + xx;
                if b & (0b10000000 >> x) != 0 {
                    if vm.display[idx] == 1 {
                        vm.v[0xF].0 = 1;
                    }
                    vm.display[idx] ^= 1;
                }
            }
        }
    }

    vm.display_updated = true;
}

pub fn skip_next_key_vx_not_pressed(vm: &mut VirtualMachine, x: usize) {
    if !vm.keys[vm.v[x].0 as usize] {
        vm.pc += 2;
    }
}

pub fn skip_next_key_vx_pressed(vm: &mut VirtualMachine, x: usize) {
    if vm.keys[vm.v[x].0 as usize] {
        vm.pc += 2;
    }
}

pub fn set_vx_to_delay_timer(vm: &mut VirtualMachine, x: usize) {
    vm.v[x].0 = vm.delay_timer;
}

pub fn wait_for_keypress_store_in_vx(vm: &mut VirtualMachine, x: usize) {
    vm.keypress_wait.wait = true;
    vm.keypress_wait.vx = x;
}

pub fn set_delay_timer(vm: &mut VirtualMachine, x: usize) {
    vm.delay_timer = vm.v[x].0;
}

pub fn set_sound_timer(vm: &mut VirtualMachine, x: usize) {
    vm.sound_timer = vm.v[x].0;
}

pub fn add_vx_to_i(vm: &mut VirtualMachine, x: usize) {
    vm.i += vm.v[x].0 as u16;
}

pub fn set_i_to_loc_of_digit_vx(vm: &mut VirtualMachine, x: usize) {
    vm.i = (vm.v[x] * Wrapping(5)).0 as u16;
}

pub fn store_bcd_of_vx_to_i(vm: &mut VirtualMachine, x: usize) {
    let num = vm.v[x].0; // TODO: Should probably be wrapping
    let h = num / 100;
    let t = (num - h * 100) / 10;
    let o = num - h * 100 - t * 10;
    vm.ram[vm.i as usize] = h;
    vm.ram[vm.i as usize + 1] = t;
    vm.ram[vm.i as usize + 2] = o;
}

pub fn copy_v0_through_vx_to_mem(vm: &mut VirtualMachine, x: usize) {
    for pos in 0...x {
        vm.ram[(vm.i + pos as u16) as usize] = vm.v[pos as usize].0;
    }
    vm.i += (x + 1) as u16;
}

pub fn read_v0_through_vx_from_mem(vm: &mut VirtualMachine, x: usize) {
    for pos in 0...x {
        vm.v[pos as usize].0 = vm.ram[(vm.i + pos as u16) as usize];
    }
    vm.i += (x + 1) as u16;
}

#[test]
fn test_strore_bcd_of_vx_to_i() {
    let mut vm = VirtualMachine::new();
    vm.v[0].0 = 146;
    vm.i = 0;
    store_bcd_of_vx_to_i(&mut vm, 0);
    assert!(vm.ram[0] == 1);
    assert!(vm.ram[1] == 4);
    assert!(vm.ram[2] == 6);
}
<commit_msg>U FOKKIN WOT m8<commit_after>use super::VirtualMachine;
use std::num::Wrapping;

pub fn jump_to_sys_routine(_vm: &mut VirtualMachine, _addr: usize) {
    // Do nothing
}

pub fn clear_display(vm: &mut VirtualMachine) {
    for px in vm.display.iter_mut() {
        *px = 0;
    }
}

pub fn ret_from_subroutine(vm: &mut VirtualMachine) {
    vm.pc = vm.stack[vm.sp as usize];
    vm.sp -= 1;
}

pub fn jump_addr(vm: &mut VirtualMachine, addr: u16) {
    vm.pc = addr;
}

pub fn call_subroutine(vm: &mut VirtualMachine, addr: usize) {
    vm.sp += 1;
    vm.stack[vm.sp as usize] = vm.pc;
    vm.pc = addr as u16;
}

pub fn skip_next_vx_eq(vm: &mut VirtualMachine, x: usize, to: u8) {
    if vm.v[x].0 == to {
        vm.pc += 2;
    }
}

pub fn skip_next_vx_ne(vm: &mut VirtualMachine, x: usize, to: u8) {
    if vm.v[x].0 != to {
        vm.pc += 2;
    }
}

pub fn skip_next_vx_eq_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    if vm.v[x] == vm.v[y] {
        vm.pc += 2;
    }
}

pub fn set_vx_byte(vm: &mut VirtualMachine, x: usize, byte: u8) {
    vm.v[x].0 = byte;
}

pub fn add_vx_byte(vm: &mut VirtualMachine, x: usize, byte: u8) {
    vm.v[x] = vm.v[x] + Wrapping(byte);
}

pub fn set_vx_to_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[x] = vm.v[y];
}

pub fn set_vx_to_vx_or_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[x] = vm.v[x] | vm.v[y];
}

pub fn set_vx_to_vx_and_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[x] = vm.v[x] & vm.v[y];
}

pub fn set_vx_to_vx_xor_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[x] = vm.v[x] ^ vm.v[y];
}

pub fn add_vx_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[0xF].0 = if vm.v[x].0 as u16 + vm.v[y].0 as u16 > 255 {
        1
    } else {
        0
    };
    vm.v[x] = vm.v[x] + vm.v[y];
}

pub fn sub_vx_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[0xF].0 = if vm.v[x] > vm.v[y] { 1 } else { 0 };
    vm.v[x] = vm.v[x] - vm.v[y];
}

pub fn subn_vx_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[0xF].0 = if vm.v[y] > vm.v[x] { 1 } else { 0 };
    vm.v[x] = vm.v[y] - vm.v[x];
}

pub fn set_vx_to_vy_shr_1(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[0xF].0 = nth_bit(vm.v[y].0, 7);
    vm.v[x] = vm.v[y] >> 1;
}

pub fn set_vx_to_vy_shl_1(vm: &mut VirtualMachine, x: usize, y: usize) {
    vm.v[0xF].0 = nth_bit(vm.v[y].0, 0);
    vm.v[x] = vm.v[y] << 1;
}

fn nth_bit(byte: u8, pos: usize) -> u8 {
    use bit_utils::BitInformation;
    if byte.has_x_bit(7 - pos) {
        1
    } else {
        0
    }
}

#[test]
fn test_nth_bit() {
    assert_eq!(nth_bit(0b10000000, 0), 1);
    for i in 1..8 {
        assert_eq!(nth_bit(0b10000000, i), 0);
    }
    assert_eq!(nth_bit(0b01000000, 1), 1);
    assert_eq!(nth_bit(0b00100000, 2), 1);
    assert_eq!(nth_bit(0b00010000, 3), 1);
    assert_eq!(nth_bit(0b00001000, 4), 1);
    assert_eq!(nth_bit(0b00000100, 5), 1);
    assert_eq!(nth_bit(0b00000010, 6), 1);
    assert_eq!(nth_bit(0b00000001, 7), 1);
}

pub fn skip_next_vx_ne_vy(vm: &mut VirtualMachine, x: usize, y: usize) {
    if vm.v[x] != vm.v[y] {
        vm.pc += 2;
    }
}

pub fn set_i(vm: &mut VirtualMachine, to: u16) {
    vm.i = to;
}

extern crate rand;

pub fn set_vx_rand_and(vm: &mut VirtualMachine, x: usize, to: u8) {
    use self::rand::Rng;
    let mut rgen = rand::thread_rng();
    vm.v[x].0 = rgen.gen::<u8>() & to;
}

pub fn display_sprite(vm: &mut VirtualMachine, vx: usize, vy: usize, n: usize) {
    use super::{DISPLAY_HEIGHT, DISPLAY_WIDTH};

    vm.v[0xF].0 = 0;

    for y in 0..n {
        let b = vm.ram[vm.i as usize + y];
        for x in 0..8 {
            let xx = x + vm.v[vx].0 as usize;
            let yy = y + vm.v[vy].0 as usize;

            if xx < DISPLAY_WIDTH && yy < DISPLAY_HEIGHT {
                let idx = yy * DISPLAY_WIDTH + xx;
                if b & (0b10000000 >> x) != 0 {
                    if vm.display[idx] == 1 {
                        vm.v[0xF].0 = 1;
                    }
                    vm.display[idx] ^= 1;
                }
            }
        }
    }

    vm.display_updated = true;
}

pub fn skip_next_key_vx_not_pressed(vm: &mut VirtualMachine, x: usize) {
    if !vm.keys[vm.v[x].0 as usize] {
        vm.pc += 2;
    }
}

pub fn skip_next_key_vx_pressed(vm: &mut VirtualMachine, x: usize) {
    if vm.keys[vm.v[x].0 as usize] {
        vm.pc += 2;
    }
}

pub fn set_vx_to_delay_timer(vm: &mut VirtualMachine, x: usize) {
    vm.v[x].0 = vm.delay_timer;
}

pub fn wait_for_keypress_store_in_vx(vm: &mut VirtualMachine, x: usize) {
    vm.keypress_wait.wait = true;
    vm.keypress_wait.vx = x;
}

pub fn set_delay_timer(vm: &mut VirtualMachine, x: usize) {
    vm.delay_timer = vm.v[x].0;
}

pub fn set_sound_timer(vm: &mut VirtualMachine, x: usize) {
    vm.sound_timer = vm.v[x].0;
}

pub fn add_vx_to_i(vm: &mut VirtualMachine, x: usize) {
    vm.i += vm.v[x].0 as u16;
}

pub fn set_i_to_loc_of_digit_vx(vm: &mut VirtualMachine, x: usize) {
    vm.i = (vm.v[x] * Wrapping(5)).0 as u16;
}

pub fn store_bcd_of_vx_to_i(vm: &mut VirtualMachine, x: usize) {
    let num = vm.v[x].0; // TODO: Should probably be wrapping
    let h = num / 100;
    let t = (num - h * 100) / 10;
    let o = num - h * 100 - t * 10;
    vm.ram[vm.i as usize] = h;
    vm.ram[vm.i as usize + 1] = t;
    vm.ram[vm.i as usize + 2] = o;
}

pub fn copy_v0_through_vx_to_mem(vm: &mut VirtualMachine, x: usize) {
    for pos in 0...x {
        vm.ram[(vm.i + pos as u16) as usize] = vm.v[pos as usize].0;
    }
    vm.i += (x + 1) as u16;
}

pub fn read_v0_through_vx_from_mem(vm: &mut VirtualMachine, x: usize) {
    for pos in 0...x {
        vm.v[pos as usize].0 = vm.ram[(vm.i + pos as u16) as usize];
    }
    vm.i += (x + 1) as u16;
}

#[test]
fn test_strore_bcd_of_vx_to_i() {
    let mut vm = VirtualMachine::new();
    vm.v[0].0 = 146;
    vm.i = 0;
    store_bcd_of_vx_to_i(&mut vm, 0);
    assert!(vm.ram[0] == 1);
    assert!(vm.ram[1] == 4);
    assert!(vm.ram[2] == 6);
}
<|endoftext|>


<commit_before>//! Rust representations of docker json structures

use std::collections::HashMap;

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SearchResult {
  pub description: String,
  pub is_official: bool,
  pub is_trusted: bool,
  pub name: String,
  pub star_count: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Image {
  pub Created: u64,
  pub Id: String,
  pub ParentId: String,
  //pub Labels: ???,
  pub RepoTags: Vec<String>,
  pub RepoDigests: Option<Vec<String>>,
  pub Size: u64,
  pub VirtualSize: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ImageDetails {
  pub Architecture: String,
  pub Author: String,
  pub Comment: String,
  pub Config: Config,
  pub Created: String,
  pub DockerVersion: String,
  pub Id: String,
  pub Os: String,
  pub Parent: String,
  pub Size: u64,
  pub VirtualSize: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Container {
  pub Created: u64,
  pub Command: String,
  pub Id: String,
  pub Image: String,
  //pub Labels: ???,
  pub Names: Vec<String>,
  pub Ports: Vec<Port>,
  pub Status: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ContainerDetails {
  pub AppArmorProfile: String,
  pub Args: Vec<String>,
  pub Config: Config,
  pub Created: String,
  pub Driver: String,
  pub ExecDriver: String,
  //pub ExecIDs: ??
  pub HostConfig: HostConfig
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct HostConfig {
  pub CgroupParent: Option<String>,
  pub ContainerIDFile: String,
  pub CpuShares: Option<u64>,
  pub CpusetCpus: Option<String>,
  pub Memory: Option<u64>,
  pub MemorySwap: Option<u64>,
  pub NetworkMode: String,
  pub PidMode: Option<String>,
  //pub PortBindings: ???
  pub Privileged: bool,
  pub PublishAllPorts: bool,
  pub ReadonlyRootfs: Option<bool>
  //pub RestartPolicy: ???
  //pub SecurityOpt: Option<???>,
  //pub Ulimits: Option<???>
 // pub VolumesFrom: Option<??/>
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Config {
  AttachStderr: bool,
  AttachStdin: bool,
  AttachStdout: bool,
  Cmd: Vec<String>,
  CpuShares: u64,
  Cpuset: String,
  Domainname: String,
  Entrypoint: Option<Vec<String>>,
  Env: Vec<String>,
  //ExposedPorts
  Hostname: String,
  Image: String,
  //Labels:???
  MacAddress: String,
  Memory: u64,
  MemorySwap: u64,
  NetworkDisabled: bool,
  //OnBuild: Option<String>,
  OpenStdin: bool,
  //PortSpecs: ???,
  StdinOnce: bool,
  Tty: bool,
  User: String,
  //Volumes: ??,
  WorkingDir: String
}

impl Config {
  pub fn env(&self) -> HashMap<String, String> {
    let mut map = HashMap::new();
    for e in self.Env.clone() {
      let pair: Vec<&str> = e.split("=").collect();
      map.insert(pair[0].to_owned(), pair[1].to_owned());
    }
    map
  }
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Port {
  pub IP: Option<String>,
  pub PrivatePort: u64,
  pub PublicPort: Option<u64>,
  pub Type: String
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Stats {
  pub read: String,
  pub network: Network,
  pub memory_stats: MemoryStats,
  pub cpu_stats: CpuStats
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Network {
  pub rx_dropped: u64,
  pub rx_bytes: u64,
  pub rx_errors: u64,
  pub tx_packets: u64,
  pub tx_dropped: u64,
  pub rx_packets: u64,
  pub tx_errors: u64,
  pub tx_bytes: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MemoryStats {
  pub max_usage: u64,
  pub usage: u64,
  pub failcnt: u64,
  pub limit: u64,
  pub stats: MemoryStat
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MemoryStat {
  pub total_pgmajfault: u64,
  pub cache: u64,
  pub mapped_file: u64,
  pub total_inactive_file: u64,
  pub pgpgout: u64,
  pub rss: u64,
  pub total_mapped_file: u64,
  pub writeback: u64,
  pub unevictable: u64,
  pub pgpgin: u64,
  pub total_unevictable: u64,
  pub pgmajfault: u64,
  pub total_rss: u64,
  pub total_rss_huge: u64,
  pub total_writeback: u64,
  pub total_inactive_anon: u64,
  pub rss_huge: u64,
  pub hierarchical_memory_limit: u64,
  pub hierarchical_memsw_limit: u64,
  pub total_pgfault: u64,
  pub total_active_file: u64,
  pub active_anon: u64,
  pub total_active_anon: u64,
  pub total_pgpgout: u64,
  pub total_cache: u64,
  pub inactive_anon: u64,
  pub active_file: u64,
  pub pgfault: u64,
  pub inactive_file: u64,
  pub total_pgpgin: u64,
  pub swap: u64,
  pub total_swap: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct CpuStats {
  pub cpu_usage: CpuUsage,
  pub system_cpu_usage: u64,
  pub throttling_data: ThrottlingData
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct CpuUsage {
  pub percpu_usage: Vec<u64>,
  pub usage_in_usermode: u64,
  pub total_usage: u64,
  pub usage_in_kernelmode: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct ThrottlingData {
  pub periods: u64,
  pub throttled_periods: u64,
  pub throttled_time: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct BlkioStats {
  pub io_service_bytes_recursive: Vec<BlkioStat>,
  pub io_serviced_recursive: Vec<BlkioStat>,
  pub io_queue_recursive: Vec<BlkioStat>,
  pub io_service_time_recursive: Vec<BlkioStat>,
  pub io_wait_time_recursive: Vec<BlkioStat>,
  pub io_merged_recursive: Vec<BlkioStat>,
  pub io_time_recursive: Vec<BlkioStat>,
  pub sectors_recursive: Vec<BlkioStat>
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct BlkioStat {
  pub major: u64,
  pub minor: u64,
  pub op: String,
  pub value: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Change {
  pub Kind: u64,
  pub Path: String
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Top {
  pub Titles: Vec<String>,
  pub Processes: Vec<Vec<String>>
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Version {
  pub ApiVersion: String,
  pub Version: String,
  pub GitCommit: String,
  pub GoVersion: String
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Info {
  pub Containers: u64,
  pub Images: u64,
  pub Driver: String,
  pub DockerRootDir: String,
  pub DriverStatus: Vec<Vec<String>>,
  pub ExecutionDriver: String,
  pub ID: String,
  pub KernelVersion: String,
  //pub Labels: Option<???>,
  pub MemTotal: u64,
  pub MemoryLimit: u64,
  pub NCPU: u64,
  pub NEventsListener: u64,
  pub NGoroutines: u64,
  pub Name: String,
  pub OperatingSystem: String,
  //pub RegistryConfig:???
  pub SwapLimit: u64,
  pub SystemTime: Option<String>
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ContainerCreateInfo {
  pub Id: String,
  pub Warnings: Option<Vec<String>>
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct History {
  pub Id: String,
  pub Created: u64,
  pub CreatedBy: String
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Exit {
  pub StatusCode: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Event {
  pub status: String,
  pub id: String,
  pub from: String,
  pub time: u64
}

#[derive(Debug)]
pub enum Status {
  Untagged(String),
  Deleted(String)
}
<commit_msg>Config.{Cmd,Env} may potentially be null<commit_after>//! Rust representations of docker json structures

use std::collections::HashMap;

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SearchResult {
  pub description: String,
  pub is_official: bool,
  pub is_trusted: bool,
  pub name: String,
  pub star_count: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Image {
  pub Created: u64,
  pub Id: String,
  pub ParentId: String,
  //pub Labels: ???,
  pub RepoTags: Vec<String>,
  pub RepoDigests: Option<Vec<String>>,
  pub Size: u64,
  pub VirtualSize: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ImageDetails {
  pub Architecture: String,
  pub Author: String,
  pub Comment: String,
  pub Config: Config,
  pub Created: String,
  pub DockerVersion: String,
  pub Id: String,
  pub Os: String,
  pub Parent: String,
  pub Size: u64,
  pub VirtualSize: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Container {
  pub Created: u64,
  pub Command: String,
  pub Id: String,
  pub Image: String,
  //pub Labels: ???,
  pub Names: Vec<String>,
  pub Ports: Vec<Port>,
  pub Status: String,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ContainerDetails {
  pub AppArmorProfile: String,
  pub Args: Vec<String>,
  pub Config: Config,
  pub Created: String,
  pub Driver: String,
  pub ExecDriver: String,
  //pub ExecIDs: ??
  pub HostConfig: HostConfig
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct HostConfig {
  pub CgroupParent: Option<String>,
  pub ContainerIDFile: String,
  pub CpuShares: Option<u64>,
  pub CpusetCpus: Option<String>,
  pub Memory: Option<u64>,
  pub MemorySwap: Option<u64>,
  pub NetworkMode: String,
  pub PidMode: Option<String>,
  //pub PortBindings: ???
  pub Privileged: bool,
  pub PublishAllPorts: bool,
  pub ReadonlyRootfs: Option<bool>
  //pub RestartPolicy: ???
  //pub SecurityOpt: Option<???>,
  //pub Ulimits: Option<???>
 // pub VolumesFrom: Option<??/>
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Config {
  AttachStderr: bool,
  AttachStdin: bool,
  AttachStdout: bool,
  Cmd: Option<Vec<String>>,
  CpuShares: u64,
  Cpuset: String,
  Domainname: String,
  Entrypoint: Option<Vec<String>>,
  Env: Option<Vec<String>>,
  //ExposedPorts
  Hostname: String,
  Image: String,
  //Labels:???
  MacAddress: String,
  Memory: u64,
  MemorySwap: u64,
  NetworkDisabled: bool,
  //OnBuild: Option<String>,
  OpenStdin: bool,
  //PortSpecs: ???,
  StdinOnce: bool,
  Tty: bool,
  User: String,
  //Volumes: ??,
  WorkingDir: String
}

impl Config {
  pub fn env(&self) -> HashMap<String, String> {
    let mut map = HashMap::new();
    match self.Env {
      Some(ref vars) => {
        for e in vars {
          let pair: Vec<&str> = e.split("=").collect();
          map.insert(pair[0].to_owned(), pair[1].to_owned());
        }
      },
      _ => ()
    };
    map
  }
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Port {
  pub IP: Option<String>,
  pub PrivatePort: u64,
  pub PublicPort: Option<u64>,
  pub Type: String
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Stats {
  pub read: String,
  pub network: Network,
  pub memory_stats: MemoryStats,
  pub cpu_stats: CpuStats
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Network {
  pub rx_dropped: u64,
  pub rx_bytes: u64,
  pub rx_errors: u64,
  pub tx_packets: u64,
  pub tx_dropped: u64,
  pub rx_packets: u64,
  pub tx_errors: u64,
  pub tx_bytes: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MemoryStats {
  pub max_usage: u64,
  pub usage: u64,
  pub failcnt: u64,
  pub limit: u64,
  pub stats: MemoryStat
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct MemoryStat {
  pub total_pgmajfault: u64,
  pub cache: u64,
  pub mapped_file: u64,
  pub total_inactive_file: u64,
  pub pgpgout: u64,
  pub rss: u64,
  pub total_mapped_file: u64,
  pub writeback: u64,
  pub unevictable: u64,
  pub pgpgin: u64,
  pub total_unevictable: u64,
  pub pgmajfault: u64,
  pub total_rss: u64,
  pub total_rss_huge: u64,
  pub total_writeback: u64,
  pub total_inactive_anon: u64,
  pub rss_huge: u64,
  pub hierarchical_memory_limit: u64,
  pub hierarchical_memsw_limit: u64,
  pub total_pgfault: u64,
  pub total_active_file: u64,
  pub active_anon: u64,
  pub total_active_anon: u64,
  pub total_pgpgout: u64,
  pub total_cache: u64,
  pub inactive_anon: u64,
  pub active_file: u64,
  pub pgfault: u64,
  pub inactive_file: u64,
  pub total_pgpgin: u64,
  pub swap: u64,
  pub total_swap: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct CpuStats {
  pub cpu_usage: CpuUsage,
  pub system_cpu_usage: u64,
  pub throttling_data: ThrottlingData
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct CpuUsage {
  pub percpu_usage: Vec<u64>,
  pub usage_in_usermode: u64,
  pub total_usage: u64,
  pub usage_in_kernelmode: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct ThrottlingData {
  pub periods: u64,
  pub throttled_periods: u64,
  pub throttled_time: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct BlkioStats {
  pub io_service_bytes_recursive: Vec<BlkioStat>,
  pub io_serviced_recursive: Vec<BlkioStat>,
  pub io_queue_recursive: Vec<BlkioStat>,
  pub io_service_time_recursive: Vec<BlkioStat>,
  pub io_wait_time_recursive: Vec<BlkioStat>,
  pub io_merged_recursive: Vec<BlkioStat>,
  pub io_time_recursive: Vec<BlkioStat>,
  pub sectors_recursive: Vec<BlkioStat>
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct BlkioStat {
  pub major: u64,
  pub minor: u64,
  pub op: String,
  pub value: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Change {
  pub Kind: u64,
  pub Path: String
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Top {
  pub Titles: Vec<String>,
  pub Processes: Vec<Vec<String>>
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Version {
  pub ApiVersion: String,
  pub Version: String,
  pub GitCommit: String,
  pub GoVersion: String
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Info {
  pub Containers: u64,
  pub Images: u64,
  pub Driver: String,
  pub DockerRootDir: String,
  pub DriverStatus: Vec<Vec<String>>,
  pub ExecutionDriver: String,
  pub ID: String,
  pub KernelVersion: String,
  //pub Labels: Option<???>,
  pub MemTotal: u64,
  pub MemoryLimit: u64,
  pub NCPU: u64,
  pub NEventsListener: u64,
  pub NGoroutines: u64,
  pub Name: String,
  pub OperatingSystem: String,
  //pub RegistryConfig:???
  pub SwapLimit: u64,
  pub SystemTime: Option<String>
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct ContainerCreateInfo {
  pub Id: String,
  pub Warnings: Option<Vec<String>>
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct History {
  pub Id: String,
  pub Created: u64,
  pub CreatedBy: String
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
#[allow(non_snake_case)]
pub struct Exit {
  pub StatusCode: u64
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Event {
  pub status: String,
  pub id: String,
  pub from: String,
  pub time: u64
}

#[derive(Debug)]
pub enum Status {
  Untagged(String),
  Deleted(String)
}
<|endoftext|>


<commit_before>/// Utilities to write SDP offers and answers using Janus's SDP parsing machinery.

use super::ffi;
use super::glib;
use super::libc;
pub use ffi::sdp::janus_sdp_generate_answer as generate_answer;
use std::collections::HashMap;
use std::error::Error;
use std::ffi::{CStr, CString};
use std::ops::Deref;
use std::str;
use utils::GLibString;

pub type RawSdp = ffi::sdp::janus_sdp;
pub type RawMLine = ffi::sdp::janus_sdp_mline;
pub type RawAttribute = ffi::sdp::janus_sdp_attribute;
pub use ffi::sdp::janus_sdp_mtype as MediaType;
pub use ffi::sdp::janus_sdp_mdirection as MediaDirection;

/// SDP attributes which may refer to a specific RTP payload type.
static MEDIA_PAYLOAD_ATTRIBUTES: [&'static str; 3] = ["rtpmap", "fmtp", "rtcp-fb"];

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Available Janus audio codecs. See utils.c.
pub enum AudioCodec {
    Opus,
    Pcmu,
    Pcma,
    G722,
    Isac16,
    Isac32,
}

impl AudioCodec {
    pub fn to_str(&self) -> &'static str {
        self.to_cstr().to_str().unwrap()
    }
    pub fn to_cstr(&self) -> &'static CStr {
        unsafe {
            CStr::from_ptr(match *self {
                AudioCodec::Opus => cstr!("opus"),
                AudioCodec::Pcmu => cstr!("pcmu"),
                AudioCodec::Pcma => cstr!("pcma"),
                AudioCodec::G722 => cstr!("g722"),
                AudioCodec::Isac16 => cstr!("isac16"),
                AudioCodec::Isac32 => cstr!("isac32"),
            })
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Available Janus video codecs. See utils.c.
pub enum VideoCodec {
    Vp8,
    Vp9,
    H264,
}

impl VideoCodec {
    pub fn to_str(&self) -> &'static str {
        self.to_cstr().to_str().unwrap()
    }
    pub fn to_cstr(&self) -> &'static CStr {
        unsafe {
            CStr::from_ptr(match *self {
                VideoCodec::Vp8 => cstr!("vp8"),
                VideoCodec::Vp9 => cstr!("vp9"),
                VideoCodec::H264 => cstr!("h264"),
            })
        }
    }
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Parameters controlling SDP offer answering behavior. Used as keys in the parameter list
/// for janus_sdp_generate_answer. See sdp-utils.h in the Janus source for more details.
pub enum OfferAnswerParameters {
    /// Used to signal the end of the offer-answer parameter list.
    Done = 0,
    /// Whether to accept or reject audio.
    Audio = 1,
    /// Whether to accept or reject video.
    Video = 2,
    /// Whether to accept or reject data.
    Data = 3,
    /// The MediaDirection for the audio stream.
    AudioDirection = 4,
    /// The MediaDirection for the video stream.
    VideoDirection = 5,
    /// The AudioCodec for the audio stream.
    AudioCodec = 6,
    /// The VideoCodec for the video stream.
    VideoCodec = 7,
    /// The payload type for the audio stream.
    AudioPayloadType = 8,
    /// The payload type for the video stream.
    VideoPayloadType = 9,
    /// Whether to negotiate telephone events.
    AudioDtmf = 10,
    /// Whether to add RTCP-FB attributes.
    VideoRtcpfbDefaults = 11,
    /// Whether to add attributes for H.264 video.
    VideoH264Fmtp = 12,
}

#[derive(Debug)]
/// An SDP session description.
pub struct Sdp {
    pub ptr: *mut RawSdp, // annoyingly pub because of answer_sdp macro
}

impl Sdp {
    pub unsafe fn new(ptr: *mut RawSdp) -> Option<Self> {
        ptr.as_mut().map(|p| Self { ptr: p })
    }

    /// Parses an SDP offer string from a client into a structured SDP object.
    pub fn parse(offer: CString) -> Result<Self, Box<Error>> {
        let mut error_buffer = Vec::with_capacity(512);
        let error_ptr = error_buffer.as_mut_ptr() as *mut _;
        unsafe {
            let result = ffi::sdp::janus_sdp_parse(offer.as_ptr(), error_ptr, error_buffer.capacity());
            Sdp::new(result).ok_or_else(|| {
                error_buffer.set_len(libc::strlen(error_ptr));
                From::from(str::from_utf8(&error_buffer).expect("SDP error not valid UTF-8 :("))
            })
        }
    }

    /// Gets the payload type number for a codec in this SDP, or None if the codec isn't present.
    pub fn get_payload_type(&self, codec_name: &CStr) -> Option<i32> {
        unsafe {
            match ffi::sdp::janus_sdp_get_codec_pt(self.ptr, codec_name.as_ptr()) {
                err if err < 0 => None,
                n => Some(n),
            }
        }
    }

    /// Rewrites any references from one dynamically assigned payload type in this SDP to another dynamically assigned
    /// payload type.
    pub fn rewrite_payload_type(&mut self, from: i32, to: i32) {
        let from_pt_string = from.to_string();
        let to_pt_string = to.to_string();
        for (_media, m_lines) in self.get_mlines() {
            unsafe {
                for m_line in m_lines {
                    // 1. replace the payload type ID in this media line's payload type list
                    if !glib::g_list_find(m_line.ptypes, from as *const _).is_null() {
                        // payload type data in the list is cast to pointers
                        m_line.ptypes = glib::g_list_remove(m_line.ptypes, from as *const _);
                        m_line.ptypes = glib::g_list_prepend(m_line.ptypes, to as *mut _);
                    }
                    // 2. rewrite the values of attribute lines with the old payload type to have the new payload type
                    let mut attr_node = m_line.attributes;
                    while let Some(node) = attr_node.as_ref() {
                        let next = node.next; // we might delete this link, so grab next now!
                        let attr = (node.data as *const RawAttribute).as_ref().expect("Null data in SDP attribute node :(");
                        let name = CStr::from_ptr(attr.name).to_str().expect("Invalid attribute name in SDP :(");
                        if MEDIA_PAYLOAD_ATTRIBUTES.contains(&name) {
                            // each of the attributes with payload types in the values look like "$pt $stuff"
                            // where $stuff is specifying payload-type-specfic options; just rewrite $pt
                            let value = CStr::from_ptr(attr.value).to_str().expect("Invalid attribute value in SDP :(");
                            if value.starts_with(&from_pt_string) {
                                let new_val = value.replacen(&from_pt_string, &to_pt_string, 1);
                                let new_attr = ffi::sdp::janus_sdp_attribute_create(
                                    attr.name,
                                    CString::new(new_val).unwrap().as_ptr() // copied into the attribute
                                );
                                m_line.attributes = glib::g_list_prepend(m_line.attributes, new_attr as *mut _);
                                m_line.attributes = glib::g_list_delete_link(m_line.attributes, attr_node);
                            }
                        }
                        attr_node = next;
                    }
                }
            }
        }
    }

    /// Returns a map of all the SDP media lines per SDP media type.
    pub fn get_mlines(&self) -> HashMap<MediaType, Vec<&mut RawMLine>> {
        let mut result = HashMap::new();
        unsafe {
            let mut ml_node = (*self.ptr).m_lines;
            while let Some(node) = ml_node.as_ref() {
                let ml = (node.data as *mut RawMLine).as_mut().expect("Null data in SDP media node :(");
                result.entry(ml.type_).or_insert_with(Vec::new).push(ml);
                ml_node = node.next;
            }
            return result;
	}
    }

    /// Writes this SDP into a string.
    pub fn to_string(&self) -> GLibString {
        unsafe {
            let sdp = ffi::sdp::janus_sdp_write(self.ptr);
            GLibString::from_chars(sdp).expect("Mysterious error writing SDP to string :(")
        }
    }
}

impl Deref for Sdp {
    type Target = RawSdp;

    fn deref(&self) -> &RawSdp {
        unsafe { &*self.ptr }
    }
}

impl Drop for Sdp {
    fn drop(&mut self) {
        unsafe { ffi::sdp::janus_sdp_free(self.ptr) }
    }
}

unsafe impl Send for Sdp {}

#[macro_export]
/// Given an SDP offer from a client, generates an SDP answer.
/// (This has to be a macro because generate_answer is variadic.)
macro_rules! answer_sdp {
    ($sdp:expr $(, $param:expr, $value:expr),*) => {{
        unsafe {
            let result = $crate::sdp::generate_answer(
                $sdp.ptr,
                $($param, $value,)*
                $crate::sdp::OfferAnswerParameters::Done
            );
            $crate::sdp::Sdp::new(result).expect("Mysterious error generating SDP answer :(")
        }
    }}
}
<commit_msg>Allow trailing commas in answer_sdp!<commit_after>/// Utilities to write SDP offers and answers using Janus's SDP parsing machinery.

use super::ffi;
use super::glib;
use super::libc;
pub use ffi::sdp::janus_sdp_generate_answer as generate_answer;
use std::collections::HashMap;
use std::error::Error;
use std::ffi::{CStr, CString};
use std::ops::Deref;
use std::str;
use utils::GLibString;

pub type RawSdp = ffi::sdp::janus_sdp;
pub type RawMLine = ffi::sdp::janus_sdp_mline;
pub type RawAttribute = ffi::sdp::janus_sdp_attribute;
pub use ffi::sdp::janus_sdp_mtype as MediaType;
pub use ffi::sdp::janus_sdp_mdirection as MediaDirection;

/// SDP attributes which may refer to a specific RTP payload type.
static MEDIA_PAYLOAD_ATTRIBUTES: [&'static str; 3] = ["rtpmap", "fmtp", "rtcp-fb"];

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Available Janus audio codecs. See utils.c.
pub enum AudioCodec {
    Opus,
    Pcmu,
    Pcma,
    G722,
    Isac16,
    Isac32,
}

impl AudioCodec {
    pub fn to_str(&self) -> &'static str {
        self.to_cstr().to_str().unwrap()
    }
    pub fn to_cstr(&self) -> &'static CStr {
        unsafe {
            CStr::from_ptr(match *self {
                AudioCodec::Opus => cstr!("opus"),
                AudioCodec::Pcmu => cstr!("pcmu"),
                AudioCodec::Pcma => cstr!("pcma"),
                AudioCodec::G722 => cstr!("g722"),
                AudioCodec::Isac16 => cstr!("isac16"),
                AudioCodec::Isac32 => cstr!("isac32"),
            })
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Available Janus video codecs. See utils.c.
pub enum VideoCodec {
    Vp8,
    Vp9,
    H264,
}

impl VideoCodec {
    pub fn to_str(&self) -> &'static str {
        self.to_cstr().to_str().unwrap()
    }
    pub fn to_cstr(&self) -> &'static CStr {
        unsafe {
            CStr::from_ptr(match *self {
                VideoCodec::Vp8 => cstr!("vp8"),
                VideoCodec::Vp9 => cstr!("vp9"),
                VideoCodec::H264 => cstr!("h264"),
            })
        }
    }
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Parameters controlling SDP offer answering behavior. Used as keys in the parameter list
/// for janus_sdp_generate_answer. See sdp-utils.h in the Janus source for more details.
pub enum OfferAnswerParameters {
    /// Used to signal the end of the offer-answer parameter list.
    Done = 0,
    /// Whether to accept or reject audio.
    Audio = 1,
    /// Whether to accept or reject video.
    Video = 2,
    /// Whether to accept or reject data.
    Data = 3,
    /// The MediaDirection for the audio stream.
    AudioDirection = 4,
    /// The MediaDirection for the video stream.
    VideoDirection = 5,
    /// The AudioCodec for the audio stream.
    AudioCodec = 6,
    /// The VideoCodec for the video stream.
    VideoCodec = 7,
    /// The payload type for the audio stream.
    AudioPayloadType = 8,
    /// The payload type for the video stream.
    VideoPayloadType = 9,
    /// Whether to negotiate telephone events.
    AudioDtmf = 10,
    /// Whether to add RTCP-FB attributes.
    VideoRtcpfbDefaults = 11,
    /// Whether to add attributes for H.264 video.
    VideoH264Fmtp = 12,
}

#[derive(Debug)]
/// An SDP session description.
pub struct Sdp {
    pub ptr: *mut RawSdp, // annoyingly pub because of answer_sdp macro
}

impl Sdp {
    pub unsafe fn new(ptr: *mut RawSdp) -> Option<Self> {
        ptr.as_mut().map(|p| Self { ptr: p })
    }

    /// Parses an SDP offer string from a client into a structured SDP object.
    pub fn parse(offer: CString) -> Result<Self, Box<Error>> {
        let mut error_buffer = Vec::with_capacity(512);
        let error_ptr = error_buffer.as_mut_ptr() as *mut _;
        unsafe {
            let result = ffi::sdp::janus_sdp_parse(offer.as_ptr(), error_ptr, error_buffer.capacity());
            Sdp::new(result).ok_or_else(|| {
                error_buffer.set_len(libc::strlen(error_ptr));
                From::from(str::from_utf8(&error_buffer).expect("SDP error not valid UTF-8 :("))
            })
        }
    }

    /// Gets the payload type number for a codec in this SDP, or None if the codec isn't present.
    pub fn get_payload_type(&self, codec_name: &CStr) -> Option<i32> {
        unsafe {
            match ffi::sdp::janus_sdp_get_codec_pt(self.ptr, codec_name.as_ptr()) {
                err if err < 0 => None,
                n => Some(n),
            }
        }
    }

    /// Rewrites any references from one dynamically assigned payload type in this SDP to another dynamically assigned
    /// payload type.
    pub fn rewrite_payload_type(&mut self, from: i32, to: i32) {
        let from_pt_string = from.to_string();
        let to_pt_string = to.to_string();
        for (_media, m_lines) in self.get_mlines() {
            unsafe {
                for m_line in m_lines {
                    // 1. replace the payload type ID in this media line's payload type list
                    if !glib::g_list_find(m_line.ptypes, from as *const _).is_null() {
                        // payload type data in the list is cast to pointers
                        m_line.ptypes = glib::g_list_remove(m_line.ptypes, from as *const _);
                        m_line.ptypes = glib::g_list_prepend(m_line.ptypes, to as *mut _);
                    }
                    // 2. rewrite the values of attribute lines with the old payload type to have the new payload type
                    let mut attr_node = m_line.attributes;
                    while let Some(node) = attr_node.as_ref() {
                        let next = node.next; // we might delete this link, so grab next now!
                        let attr = (node.data as *const RawAttribute).as_ref().expect("Null data in SDP attribute node :(");
                        let name = CStr::from_ptr(attr.name).to_str().expect("Invalid attribute name in SDP :(");
                        if MEDIA_PAYLOAD_ATTRIBUTES.contains(&name) {
                            // each of the attributes with payload types in the values look like "$pt $stuff"
                            // where $stuff is specifying payload-type-specfic options; just rewrite $pt
                            let value = CStr::from_ptr(attr.value).to_str().expect("Invalid attribute value in SDP :(");
                            if value.starts_with(&from_pt_string) {
                                let new_val = value.replacen(&from_pt_string, &to_pt_string, 1);
                                let new_attr = ffi::sdp::janus_sdp_attribute_create(
                                    attr.name,
                                    CString::new(new_val).unwrap().as_ptr() // copied into the attribute
                                );
                                m_line.attributes = glib::g_list_prepend(m_line.attributes, new_attr as *mut _);
                                m_line.attributes = glib::g_list_delete_link(m_line.attributes, attr_node);
                            }
                        }
                        attr_node = next;
                    }
                }
            }
        }
    }

    /// Returns a map of all the SDP media lines per SDP media type.
    pub fn get_mlines(&self) -> HashMap<MediaType, Vec<&mut RawMLine>> {
        let mut result = HashMap::new();
        unsafe {
            let mut ml_node = (*self.ptr).m_lines;
            while let Some(node) = ml_node.as_ref() {
                let ml = (node.data as *mut RawMLine).as_mut().expect("Null data in SDP media node :(");
                result.entry(ml.type_).or_insert_with(Vec::new).push(ml);
                ml_node = node.next;
            }
            return result;
	}
    }

    /// Writes this SDP into a string.
    pub fn to_string(&self) -> GLibString {
        unsafe {
            let sdp = ffi::sdp::janus_sdp_write(self.ptr);
            GLibString::from_chars(sdp).expect("Mysterious error writing SDP to string :(")
        }
    }
}

impl Deref for Sdp {
    type Target = RawSdp;

    fn deref(&self) -> &RawSdp {
        unsafe { &*self.ptr }
    }
}

impl Drop for Sdp {
    fn drop(&mut self) {
        unsafe { ffi::sdp::janus_sdp_free(self.ptr) }
    }
}

unsafe impl Send for Sdp {}

#[macro_export]
/// Given an SDP offer from a client, generates an SDP answer.
/// (This has to be a macro because generate_answer is variadic.)
macro_rules! answer_sdp {
    ($sdp:expr $(, $param:expr, $value:expr)* $(,)*) => {{
        unsafe {
            let result = $crate::sdp::generate_answer(
                $sdp.ptr,
                $($param, $value,)*
                $crate::sdp::OfferAnswerParameters::Done
            );
            $crate::sdp::Sdp::new(result).expect("Mysterious error generating SDP answer :(")
        }
    }}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) the nom-lua contributors. All rights reserved.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation. This file is also subject
 * to the Linking exception provided in the LICENSE file that
 * accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */

use ast::ASTNode;
use ast::ASTNode::*;
use exp::{parse_prefixexp, parse_exp};
use name::parse_name;

// TODO: Should work, Needs tests
//named!(pub parse_varlist<ASTNode>, map!(map!(
//            map!(do_parse!(
//                   a: parse_var
//                >> b: many0!(preceded!(ws!(tag!(",")), parse_var))
//                >> ((a,b))
//            ), |(a, mut b): (_, Vec < ASTNode >) | { b.insert(0, a); b }),
//Box::new), ASTNode::VarList));

   /// indicates a correct parsing, the first field containing the rest of the unparsed data, the second field contains the parsed data
  //Done(I,O),
  /// contains a Err, an enum that can indicate an error code, a position in the input, and a pointer to another error, making a list of errors in the parsing tree
  //Error(Err<I,E>),
  /// Incomplete contains a Needed, an enum than can represent a known quantity of input data, or unknown
  //Incomplete(Needed)

use nom::IResult;
/*
pub fn parse_var(input: &[u8]) -> IResult<&[u8], ASTNode> {
    /// The function tries to parse a `Name`, if it succeds
    /// we attempt to match that with either [ `exp` ] or . `Name`
    /// if parsing of the Name fails we try the `prefixexp`

    let var = match parse_var(input) {
        IResult::Done(un, var) => Ok((un, var)),
        IResult::Incomplete(need) => { return IResult::Incomplete(need) },
        IResult::Error(err) => Err(err) ,
    };

    if let Ok(name_t) = var {
        match opt!(name_t.0, delimited!(ws!(tag!("[")), ws!(parse_exp), tag!("]"))) {
            IResult::Done(un, var) => {
                return IResult::Done(un, astb!(VarPrefixed, name_t.1, var.unwrap()))
            },
            IResult::Incomplete(need) => { return IResult::Incomplete(need) },
            _ => {},
        };

        match opt!(name_t.0, preceded!(ws!(tag!(".")), parse_name)) {
            IResult::Done(un, res) => {
                return IResult::Done(un, astb!(VarPrefixed, name_t.1, res.unwrap()))
            },
            IResult::Incomplete(need) => { return IResult::Incomplete(need) },
            _ => {},
        };

    }

    unimplemented!();
}
*/

named!(pub parse_var<ASTNode>, alt!(
    map!(do_parse!(
           name: parse_name
        >> r: opt!(alt!(complete!(delimited!(ws!(tag!("[")), ws!(parse_exp), tag!("]"))) |
                        complete!(preceded!(ws!(tag!(".")), parse_name))))
        >> ((name, r))
        ), |(name, r)| {
            if let Some(rest) = r {
                match rest {
                    ASTNode::Name(_) => {
                        return astb!(VarListAccess, astb!(PrefixExp, astb!(Var, name)), rest);
                    },
                    _ => {
                        return astb!(VarPrefixed, astb!(PrefixExp, astb!(Var, name)), rest);
                    },
                }
            }

            return astb!(Var, name);
        }
    ) |
    do_parse!(
           pe: parse_prefixexp
           // The ws!'s are this way, to not eat any whitespace
           // outside of the expression
        >> e: delimited!(ws!(tag!("[")), ws!(parse_exp), tag!("]"))
        >> (astb!(VarPrefixed, pe, e))) |
    do_parse!(
           pe: parse_prefixexp
        >> n: preceded!(ws!(tag!(".")), parse_name)
        >> (astb!(VarListAccess, pe, n)))
));

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

    ast_test!(parse_var_1, parse_var, "ayy", astb!(Var, ast!(Name, "ayy".into())));
    ast_test!(parse_var_2, parse_var, "ayy [ true ]",
              astb!(VarPrefixed,
                    astb!(PrefixExp, astb!(Var, ast!(Name, "ayy".into()))),
                    ast!(Bool, true)));
    ast_test!(parse_var_3, parse_var, "ayy.zxc",
              astb!(VarListAccess,
                    astb!(PrefixExp, astb!(Var, ast!(Name, "ayy".into()))),
                    ast!(Name, "zxc".into())));
}
<commit_msg>Add varlist<commit_after>/*
 * Copyright (c) the nom-lua contributors. All rights reserved.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation. This file is also subject
 * to the Linking exception provided in the LICENSE file that
 * accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */

use ast::ASTNode;
use ast::ASTNode::*;
use exp::{parse_prefixexp, parse_exp};
use name::parse_name;
use nom::IResult;

named!(pub parse_varlist<ASTNode>, map!(map!(
            map!(do_parse!(
                   a: parse_var
                >> b: many0!(preceded!(ws!(tag!(",")), parse_var))
                >> ((a,b))
            ), |(a, mut b): (_, Vec < ASTNode >) | { b.insert(0, a); b }),
Box::new), ASTNode::VarList));

named!(pub parse_var<ASTNode>, alt!(
    map!(do_parse!(
           name: parse_name
        >> r: opt!(alt!(complete!(delimited!(ws!(tag!("[")), ws!(parse_exp), tag!("]"))) |
                        complete!(preceded!(ws!(tag!(".")), parse_name))))
        >> ((name, r))
        ), |(name, r)| {
            if let Some(rest) = r {
                match rest {
                    ASTNode::Name(_) => {
                        return astb!(VarListAccess, astb!(PrefixExp, astb!(Var, name)), rest);
                    },
                    _ => {
                        return astb!(VarPrefixed, astb!(PrefixExp, astb!(Var, name)), rest);
                    },
                }
            }

            return astb!(Var, name);
        }
    ) |
    do_parse!(
           pe: parse_prefixexp
           // The ws!'s are this way, to not eat any whitespace
           // outside of the expression
        >> e: delimited!(ws!(tag!("[")), ws!(parse_exp), tag!("]"))
        >> (astb!(VarPrefixed, pe, e))) |
    do_parse!(
           pe: parse_prefixexp
        >> n: preceded!(ws!(tag!(".")), parse_name)
        >> (astb!(VarListAccess, pe, n)))
));

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

    ast_test!(parse_var_1, parse_var, "ayy", astb!(Var, ast!(Name, "ayy".into())));
    ast_test!(parse_var_2, parse_var, "ayy [ true ]",
              astb!(VarPrefixed,
                    astb!(PrefixExp, astb!(Var, ast!(Name, "ayy".into()))),
                    ast!(Bool, true)));
    ast_test!(parse_var_3, parse_var, "ayy.zxc",
              astb!(VarListAccess,
                    astb!(PrefixExp, astb!(Var, ast!(Name, "ayy".into()))),
                    ast!(Name, "zxc".into())));

    ast_test!(parse_varlist_1, parse_varlist, "xcz", astb!(VarList, vec![
        astb!(Var, ast!(Name, "xcz".into()))
    ]));
    ast_test!(parse_varlist_2, parse_varlist, "xcz , mcx", astb!(VarList, vec![
        astb!(Var, ast!(Name, "xcz".into())),
        astb!(Var, ast!(Name, "mcx".into()))
    ]));
    ast_test!(parse_varlist_3, parse_varlist, "lak , k, jd3", astb!(VarList, vec![
        astb!(Var, ast!(Name, "lak".into())),
        astb!(Var, ast!(Name, "k".into())),
        astb!(Var, ast!(Name, "jd3".into()))
    ]));
}
<|endoftext|>