<commit_before>/*
Copyright (c) 2016 Saurav Sachidanand

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/*!
This is a Rust library that enables hardware-accelerated execution of
virtual machines on OS X.

It binds to the `Hypervisor` framework on OS X, and exposes a safe Rust
interface through the `hypervisor` module, and an unsafe foreign function
interface through the `hypervisor::ffi` module.

To use this library, you need

* OS X Yosemite (10.10), or newer

* an Intel processor with the VT-x feature set that includes Extended Page
Tables (EPT) and Unrestricted Mode. To verify this, run and expect the following
in your Terminal:

  ```shell
  $ sysctl kern.hv_support
  kern.hv_support: 1
  ```
!*/

extern crate libc;
extern crate core;

#[allow(non_camel_case_types)]
pub mod ffi;
pub mod consts;

use self::core::fmt;
use libc::*;

use self::ffi::*;

/// Error returned after every call
pub enum Error {
    /// Success
    Success,
    /// Error
    Error,
    /// Busy
    Busy,
    /// Bad argument
    BadArg,
    /// No resources
    NoRes,
    /// No device
    NoDev,
    /// Unsupported
    Unsupp
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Success => write!(f, "Success"),
            Error::Error   => write!(f, "Error"),
            Error::Busy    => write!(f, "Busy"),
            Error::BadArg  => write!(f, "Bad argument"),
            Error::NoRes   => write!(f, "No resources"),
            Error::NoDev   => write!(f, "No device"),
            Error::Unsupp  => write!(f, "Unsupported"),
        }
    }
}

// Returns an Error for a hv_return_t
fn match_error_code(code: hv_return_t) -> Error {
    match code {
        HV_SUCCESS      => Error::Success,
        HV_BUSY         => Error::Busy,
        HV_BAD_ARGUMENT => Error::BadArg,
        HV_NO_RESOURCES => Error::NoRes,
        HV_NO_DEVICE    => Error::NoDev,
        HV_UNSUPPORTED  => Error::Unsupp,
        _               => Error::Error
    }
}

/// Creates a VM instance for the current Mach task
pub fn create_vm() -> Error {
    match_error_code(unsafe {
        hv_vm_create(HV_VM_DEFAULT)
    })
}

/// Destroys the VM instance associated with the current Mach task
pub fn destory_vm() -> Error {
    match_error_code(unsafe {
        hv_vm_destroy()
    })
}

/// Guest physical memory region permissions
pub enum MemPerm {
    /// Read
    Read,
    /// Write (implies read)
    Write,
    /// Execute
    Exec,
    /// Execute and write (implies read)
    ExecAndWrite,
    /// Execute and read
    ExecAndRead
}

#[allow(non_snake_case)]
#[inline(always)]
fn match_MemPerm(mem_perm: &MemPerm) -> uint64_t {
    match mem_perm {
        &MemPerm::Read         => HV_MEMORY_READ,
        &MemPerm::Write        => HV_MEMORY_WRITE | HV_MEMORY_READ,
        &MemPerm::Exec         => HV_MEMORY_EXEC,
        &MemPerm::ExecAndWrite => HV_MEMORY_EXEC | HV_MEMORY_WRITE | HV_MEMORY_READ,
        &MemPerm::ExecAndRead  => HV_MEMORY_EXEC | HV_MEMORY_READ,
    }
}

/// Maps a region in the virtual address space of the current Mach task into the guest physical
/// address space of the virutal machine
pub fn map_mem(mem: &[u8], gpa: u64, mem_perm: &MemPerm) -> Error {
    match_error_code(unsafe {
        hv_vm_map(
            mem.as_ptr() as *const c_void, gpa as hv_gpaddr_t, mem.len() as size_t,
            match_MemPerm(mem_perm)
        )
    })
}

/// Unmaps a region in the guest physical address space of the virutal machine
pub fn unmap_mem(gpa: u64, size: usize) -> Error {
    match_error_code(unsafe {
        hv_vm_unmap(gpa as hv_gpaddr_t, size as size_t)
    })
}

/// Modifies the permissions of a region in the guest physical address space of the virtual
/// machine
pub fn protect_mem(gpa: u64, size: usize, mem_perm: &MemPerm) -> Error {
    match_error_code(unsafe {
        hv_vm_protect(gpa as hv_gpaddr_t, size as size_t, match_MemPerm(mem_perm))
    })
}

/// Synchronizes the guest Timestamp-Counters (TSC) across all vCPUs
///
/// * `tsc` Guest TSC value
pub fn sync_tsc(tsc: u64) -> Error {
    match_error_code(unsafe {
        hv_vm_sync_tsc(tsc as uint64_t)
    })
}

/// Forces an immediate VMEXIT of a set of vCPUs
///
/// * `vcpu_ids` Array of vCPU IDs
pub fn interrupt_vcpus(vcpu_ids: &[u32]) -> Error {
    match_error_code(unsafe {
        hv_vcpu_interrupt(vcpu_ids.as_ptr(), vcpu_ids.len() as c_uint)
    })
}

/// Virtual CPU
#[allow(non_camel_case_types)]
pub struct vCPU {
    /// Virtual CPU ID
    pub id: u32
}

/// x86 architectural register
#[allow(non_camel_case_types)]
#[derive(Clone)]
#[repr(C)]
pub enum x86Reg {
	RIP,
	RFLAGS,
	RAX,
	RCX,
	RDX,
	RBX,
	RSI,
	RDI,
	RSP,
	RBP,
	R8,
	R9,
	R10,
	R11,
	R12,
	R13,
	R14,
	R15,
	CS,
	SS,
	DS,
	ES,
	FS,
	GS,
	IDT_BASE,
	IDT_LIMIT,
	GDT_BASE,
	GDT_LIMIT,
	LDTR,
	LDT_BASE,
	LDT_LIMIT,
	LDT_AR,
	TR,
	TSS_BASE,
	TSS_LIMIT,
	TSS_AR,
	CR0,
	CR1,
	CR2,
	CR3,
	CR4,
	DR0,
	DR1,
	DR2,
	DR3,
	DR4,
	DR5,
	DR6,
	DR7,
	TPR,
	XCR0,
	REGISTERS_MAX,
}

impl vCPU {

    /// Creates a vCPU instance for the current thread
    pub fn new() -> Result<vCPU, Error> {
        let mut vcpuid: hv_vcpuid_t = 0;

        let error = match_error_code(unsafe {
            hv_vcpu_create(&mut vcpuid, HV_VCPU_DEFAULT)
        });

        match error {
            Error::Success => Ok(vCPU {
                id: vcpuid as u32
            }),
            _ => Err(error)
        }
    }

    /// Destroys the vCPU instance associated with the current thread
    pub fn destory(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_destroy(self.id as hv_vcpuid_t)
        })
    }

    /// Executes the vCPU
    pub fn run(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_run(self.id as hv_vcpuid_t)
        })
    }

    /// Forces an immediate VMEXIT of the vCPU
    pub fn interrupt(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_interrupt(&(self.id), 1 as c_uint)
        })
    }

    /// Returns the cumulative execution time of the vCPU in nanoseconds
    pub fn exec_time(&self) -> Result<u64, Error> {
        let mut exec_time: uint64_t = 0;

        let error = match_error_code(unsafe {
            hv_vcpu_get_exec_time(self.id, &mut exec_time)
        });

        match error {
            Error::Success => Ok(exec_time as u64),
            _ => Err(error)
        }
    }

    /// Forces flushing of cached vCPU state
    pub fn flush(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_flush(self.id as hv_vcpuid_t)
        })
    }

    /// Invalidates the translation lookaside buffer (TLB) of the vCPU
    pub fn invalidate_tlb(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_invalidate_tlb(self.id as hv_vcpuid_t)
        })
    }

    /// Enables an MSR to be used natively by the VM
    pub fn enable_native_msr(&self, msr: u32, enable: bool) -> Error {
        match_error_code(unsafe {
            hv_vcpu_enable_native_msr(self.id as hv_vcpuid_t, msr as uint32_t, enable)
        })
    }

    /// Returns the current value of an MSR of the vCPU
    pub fn read_msr(&self, msr: u32) -> Result<u64, Error> {
        let mut value: uint64_t = 0;

        let error = match_error_code(unsafe {
            hv_vcpu_read_msr(self.id as hv_vcpuid_t, msr as uint32_t, &mut value)
        });

        match error {
            Error::Success => Ok(value as u64),
            _ => Err(error)
        }
    }

    /// Set the value of an MSR of the vCPU
    pub fn write_msr(&self, msr: u32, value: u64) -> Error {
        match_error_code(unsafe {
            hv_vcpu_write_msr(self.id as hv_vcpuid_t, msr as uint32_t, &(value as uint64_t))
        })
    }

    /// Returns the current value of an architectural x86 register
    /// of the vCPU
    pub fn read_register(&self, reg: &x86Reg) -> Result<u64, Error> {
        let mut value: uint64_t = 0;

        let error = match_error_code(unsafe {
            hv_vcpu_read_register(self.id as hv_vcpuid_t, (*reg).clone(), &mut value)
        });

        match error {
            Error::Success => Ok(value as u64),
            _ => Err(error)
        }
    }

    /// Sets the value of an architectural x86 register of the vCPU
    pub fn write_register(&self, reg: &x86Reg, value: u64) -> Error {
        match_error_code(unsafe {
            hv_vcpu_write_register(self.id as hv_vcpuid_t, (*reg).clone(), value as uint64_t)
        })
    }

    /// Returns the current value of a VMCS field of the vCPU
    pub fn read_vmcs(&self, field: u32) -> Result<u64, Error> {
        let mut value: uint64_t = 0;

        let error = match_error_code(unsafe {
            hv_vmx_vcpu_read_vmcs(self.id as hv_vcpuid_t, field as uint32_t, &mut value)
        });

        match error {
            Error::Success => Ok(value as u64),
            _ => Err(error)
        }
    }

    /// Sets the value of a VMCS field of the vCPU
    pub fn write_vmcs(&self, field: u32, value: u64) -> Error {
        match_error_code(unsafe {
            hv_vmx_vcpu_write_vmcs(self.id as hv_vcpuid_t, field as uint32_t, value as uint64_t)
        })
    }

    /// Sets the address of the guest APIC for the vCPU in the
    /// guest physical address space of the VM
    pub fn set_apic_addr(&self, gpa: u64) -> Error {
        match_error_code(unsafe {
            hv_vmx_vcpu_set_apic_address(self.id as hv_vcpuid_t, gpa as uint64_t)
        })
    }

    /// Reads the current architectural x86 floating point and SIMD state of the vCPU
    pub fn read_fpstate(&self, buffer: &mut [u8]) -> Error {
        match_error_code(unsafe {
            hv_vcpu_read_fpstate(self.id as hv_vcpuid_t, buffer.as_mut_ptr() as *mut c_void,
            buffer.len() as size_t)
        })
    }

    /// Sets the architectural x86 floating point and SIMD state of the vCPU
    pub fn write_fpstate(&self, buffer: &[u8]) -> Error {
        match_error_code(unsafe {
            hv_vcpu_write_fpstate(self.id as hv_vcpuid_t, buffer.as_ptr() as *const c_void,
            buffer.len() as size_t)
        })
    }

}

impl fmt::Debug for vCPU {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "vCPU ID: {}", (*self).id)
    }
}

/// VMX cabability
#[allow(non_camel_case_types)]
#[derive(Clone)]
#[repr(C)]
pub enum VMXCap {
    /// Pin-based VMX capabilities
    PINBASED                                     = 0,
    /// Primary proc-based VMX capabilities
    PROCBASED                                    = 1,
    /// Secondary proc-based VMX capabilities
    PROCBASED2                                   = 2,
    /// VM-entry VMX capabilities
    ENTRY                                        = 3,
    /// VM-exit VMX capabilities
    EXIT                                         = 4,
    /// VMX preemption timer frequency
    PREEMPTION_TIMER                             = 32,
}

/// Reads a VMX capability of the host processor
pub fn read_vmx_cap(vmx_cap: &VMXCap) -> Result<u64, Error> {
    let mut value: uint64_t = 0;

    let error = match_error_code(unsafe {
        hv_vmx_read_capability((*vmx_cap).clone(), &mut value)
    });

    match error {
        Error::Success => Ok(value as u64),
        _ => Err(error)
    }
}
<commit_msg>Update documentation comments for hypervisor module<commit_after>/*
Copyright (c) 2016 Saurav Sachidanand

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/*!
This is a Rust library that taps into functionality that enables
hardware-accelerated execution of virtual machines on OS X.

It binds to the `Hypervisor` framework on OS X, and exposes a safe Rust
interface through the `hypervisor` module, and an unsafe foreign function
interface through the `hypervisor::ffi` module.

To use this library, you need

* OS X Yosemite (10.10), or newer

* an Intel processor with the VT-x feature set that includes Extended Page
Tables (EPT) and Unrestricted Mode. To verify this, run and expect the following
in your Terminal:

  ```shell
  $ sysctl kern.hv_support
  kern.hv_support: 1
  ```
!*/

extern crate libc;
extern crate core;

#[allow(non_camel_case_types)]
pub mod ffi;
pub mod consts;

use self::core::fmt;
use libc::*;

use self::ffi::*;

/// Error returned after every call
pub enum Error {
    /// Success
    Success,
    /// Error
    Error,
    /// Busy
    Busy,
    /// Bad argument
    BadArg,
    /// No resources
    NoRes,
    /// No device
    NoDev,
    /// Unsupported
    Unsupp
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Success => write!(f, "Success"),
            Error::Error   => write!(f, "Error"),
            Error::Busy    => write!(f, "Busy"),
            Error::BadArg  => write!(f, "Bad argument"),
            Error::NoRes   => write!(f, "No resources"),
            Error::NoDev   => write!(f, "No device"),
            Error::Unsupp  => write!(f, "Unsupported"),
        }
    }
}

// Returns an Error for a hv_return_t
fn match_error_code(code: hv_return_t) -> Error {
    match code {
        HV_SUCCESS      => Error::Success,
        HV_BUSY         => Error::Busy,
        HV_BAD_ARGUMENT => Error::BadArg,
        HV_NO_RESOURCES => Error::NoRes,
        HV_NO_DEVICE    => Error::NoDev,
        HV_UNSUPPORTED  => Error::Unsupp,
        _               => Error::Error
    }
}

/// Creates a VM instance for the current Mach task
pub fn create_vm() -> Error {
    match_error_code(unsafe {
        hv_vm_create(HV_VM_DEFAULT)
    })
}

/// Destroys the VM instance associated with the current Mach task
pub fn destory_vm() -> Error {
    match_error_code(unsafe {
        hv_vm_destroy()
    })
}

/// Guest physical memory region permissions
pub enum MemPerm {
    /// Read
    Read,
    /// Write (implies read)
    Write,
    /// Execute
    Exec,
    /// Execute and write (implies read)
    ExecAndWrite,
    /// Execute and read
    ExecAndRead
}

#[allow(non_snake_case)]
#[inline(always)]
fn match_MemPerm(mem_perm: &MemPerm) -> uint64_t {
    match mem_perm {
        &MemPerm::Read         => HV_MEMORY_READ,
        &MemPerm::Write        => HV_MEMORY_WRITE | HV_MEMORY_READ,
        &MemPerm::Exec         => HV_MEMORY_EXEC,
        &MemPerm::ExecAndWrite => HV_MEMORY_EXEC | HV_MEMORY_WRITE | HV_MEMORY_READ,
        &MemPerm::ExecAndRead  => HV_MEMORY_EXEC | HV_MEMORY_READ,
    }
}

/// Maps a region in the virtual address space of the current Mach task into the guest physical
/// address space of the virutal machine
pub fn map_mem(mem: &[u8], gpa: u64, mem_perm: &MemPerm) -> Error {
    match_error_code(unsafe {
        hv_vm_map(
            mem.as_ptr() as *const c_void, gpa as hv_gpaddr_t, mem.len() as size_t,
            match_MemPerm(mem_perm)
        )
    })
}

/// Unmaps a region in the guest physical address space of the virutal machine
pub fn unmap_mem(gpa: u64, size: usize) -> Error {
    match_error_code(unsafe {
        hv_vm_unmap(gpa as hv_gpaddr_t, size as size_t)
    })
}

/// Modifies the permissions of a region in the guest physical address space of the virtual
/// machine
pub fn protect_mem(gpa: u64, size: usize, mem_perm: &MemPerm) -> Error {
    match_error_code(unsafe {
        hv_vm_protect(gpa as hv_gpaddr_t, size as size_t, match_MemPerm(mem_perm))
    })
}

/// Synchronizes the guest Timestamp-Counters (TSC) across all vCPUs
///
/// * `tsc` Guest TSC value
pub fn sync_tsc(tsc: u64) -> Error {
    match_error_code(unsafe {
        hv_vm_sync_tsc(tsc as uint64_t)
    })
}

/// Forces an immediate VMEXIT of a set of vCPUs
///
/// * `vcpu_ids` Array of vCPU IDs
pub fn interrupt_vcpus(vcpu_ids: &[u32]) -> Error {
    match_error_code(unsafe {
        hv_vcpu_interrupt(vcpu_ids.as_ptr(), vcpu_ids.len() as c_uint)
    })
}

/// Virtual CPU
#[allow(non_camel_case_types)]
pub struct vCPU {
    /// Virtual CPU ID
    pub id: u32
}

/// x86 architectural register
#[allow(non_camel_case_types)]
#[derive(Clone)]
#[repr(C)]
pub enum x86Reg {
	RIP,
	RFLAGS,
	RAX,
	RCX,
	RDX,
	RBX,
	RSI,
	RDI,
	RSP,
	RBP,
	R8,
	R9,
	R10,
	R11,
	R12,
	R13,
	R14,
	R15,
	CS,
	SS,
	DS,
	ES,
	FS,
	GS,
	IDT_BASE,
	IDT_LIMIT,
	GDT_BASE,
	GDT_LIMIT,
	LDTR,
	LDT_BASE,
	LDT_LIMIT,
	LDT_AR,
	TR,
	TSS_BASE,
	TSS_LIMIT,
	TSS_AR,
	CR0,
	CR1,
	CR2,
	CR3,
	CR4,
	DR0,
	DR1,
	DR2,
	DR3,
	DR4,
	DR5,
	DR6,
	DR7,
	TPR,
	XCR0,
	REGISTERS_MAX,
}

impl vCPU {

    /// Creates a vCPU instance for the current thread
    pub fn new() -> Result<vCPU, Error> {
        let mut vcpuid: hv_vcpuid_t = 0;

        let error = match_error_code(unsafe {
            hv_vcpu_create(&mut vcpuid, HV_VCPU_DEFAULT)
        });

        match error {
            Error::Success => Ok(vCPU {
                id: vcpuid as u32
            }),
            _ => Err(error)
        }
    }

    /// Destroys the vCPU instance associated with the current thread
    pub fn destory(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_destroy(self.id as hv_vcpuid_t)
        })
    }

    /// Executes the vCPU
    pub fn run(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_run(self.id as hv_vcpuid_t)
        })
    }

    /// Forces an immediate VMEXIT of the vCPU
    pub fn interrupt(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_interrupt(&(self.id), 1 as c_uint)
        })
    }

    /// Returns the cumulative execution time of the vCPU in nanoseconds
    pub fn exec_time(&self) -> Result<u64, Error> {
        let mut exec_time: uint64_t = 0;

        let error = match_error_code(unsafe {
            hv_vcpu_get_exec_time(self.id, &mut exec_time)
        });

        match error {
            Error::Success => Ok(exec_time as u64),
            _ => Err(error)
        }
    }

    /// Forces flushing of cached vCPU state
    pub fn flush(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_flush(self.id as hv_vcpuid_t)
        })
    }

    /// Invalidates the translation lookaside buffer (TLB) of the vCPU
    pub fn invalidate_tlb(&self) -> Error {
        match_error_code(unsafe {
            hv_vcpu_invalidate_tlb(self.id as hv_vcpuid_t)
        })
    }

    /// Enables an MSR to be used natively by the VM
    pub fn enable_native_msr(&self, msr: u32, enable: bool) -> Error {
        match_error_code(unsafe {
            hv_vcpu_enable_native_msr(self.id as hv_vcpuid_t, msr as uint32_t, enable)
        })
    }

    /// Returns the current value of an MSR of the vCPU
    pub fn read_msr(&self, msr: u32) -> Result<u64, Error> {
        let mut value: uint64_t = 0;

        let error = match_error_code(unsafe {
            hv_vcpu_read_msr(self.id as hv_vcpuid_t, msr as uint32_t, &mut value)
        });

        match error {
            Error::Success => Ok(value as u64),
            _ => Err(error)
        }
    }

    /// Set the value of an MSR of the vCPU
    pub fn write_msr(&self, msr: u32, value: u64) -> Error {
        match_error_code(unsafe {
            hv_vcpu_write_msr(self.id as hv_vcpuid_t, msr as uint32_t, &(value as uint64_t))
        })
    }

    /// Returns the current value of an architectural x86 register
    /// of the vCPU
    pub fn read_register(&self, reg: &x86Reg) -> Result<u64, Error> {
        let mut value: uint64_t = 0;

        let error = match_error_code(unsafe {
            hv_vcpu_read_register(self.id as hv_vcpuid_t, (*reg).clone(), &mut value)
        });

        match error {
            Error::Success => Ok(value as u64),
            _ => Err(error)
        }
    }

    /// Sets the value of an architectural x86 register of the vCPU
    pub fn write_register(&self, reg: &x86Reg, value: u64) -> Error {
        match_error_code(unsafe {
            hv_vcpu_write_register(self.id as hv_vcpuid_t, (*reg).clone(), value as uint64_t)
        })
    }

    /// Returns the current value of a VMCS field of the vCPU
    pub fn read_vmcs(&self, field: u32) -> Result<u64, Error> {
        let mut value: uint64_t = 0;

        let error = match_error_code(unsafe {
            hv_vmx_vcpu_read_vmcs(self.id as hv_vcpuid_t, field as uint32_t, &mut value)
        });

        match error {
            Error::Success => Ok(value as u64),
            _ => Err(error)
        }
    }

    /// Sets the value of a VMCS field of the vCPU
    pub fn write_vmcs(&self, field: u32, value: u64) -> Error {
        match_error_code(unsafe {
            hv_vmx_vcpu_write_vmcs(self.id as hv_vcpuid_t, field as uint32_t, value as uint64_t)
        })
    }

    /// Sets the address of the guest APIC for the vCPU in the
    /// guest physical address space of the VM
    pub fn set_apic_addr(&self, gpa: u64) -> Error {
        match_error_code(unsafe {
            hv_vmx_vcpu_set_apic_address(self.id as hv_vcpuid_t, gpa as uint64_t)
        })
    }

    /// Reads the current architectural x86 floating point and SIMD state of the vCPU
    pub fn read_fpstate(&self, buffer: &mut [u8]) -> Error {
        match_error_code(unsafe {
            hv_vcpu_read_fpstate(self.id as hv_vcpuid_t, buffer.as_mut_ptr() as *mut c_void,
            buffer.len() as size_t)
        })
    }

    /// Sets the architectural x86 floating point and SIMD state of the vCPU
    pub fn write_fpstate(&self, buffer: &[u8]) -> Error {
        match_error_code(unsafe {
            hv_vcpu_write_fpstate(self.id as hv_vcpuid_t, buffer.as_ptr() as *const c_void,
            buffer.len() as size_t)
        })
    }

}

impl fmt::Debug for vCPU {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "vCPU ID: {}", (*self).id)
    }
}

/// VMX cabability
#[allow(non_camel_case_types)]
#[derive(Clone)]
#[repr(C)]
pub enum VMXCap {
    /// Pin-based VMX capabilities
    PINBASED                                     = 0,
    /// Primary proc-based VMX capabilities
    PROCBASED                                    = 1,
    /// Secondary proc-based VMX capabilities
    PROCBASED2                                   = 2,
    /// VM-entry VMX capabilities
    ENTRY                                        = 3,
    /// VM-exit VMX capabilities
    EXIT                                         = 4,
    /// VMX preemption timer frequency
    PREEMPTION_TIMER                             = 32,
}

/// Reads a VMX capability of the host processor
pub fn read_vmx_cap(vmx_cap: &VMXCap) -> Result<u64, Error> {
    let mut value: uint64_t = 0;

    let error = match_error_code(unsafe {
        hv_vmx_read_capability((*vmx_cap).clone(), &mut value)
    });

    match error {
        Error::Success => Ok(value as u64),
        _ => Err(error)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

//! # Canteen
//!
//! ## Description
//!
//! A pure Rust clone of [Flask](http://flask.pocoo.org), a simple but powerful Python
//! web framework.
//!
//! ## Example
//!
//! The principle behind Canteen is simple -- handler functions are defined as simple
//! Rust functions that take a `Request` and return a `Response`. Handlers are then attached
//! to one or more routes and HTTP methods/verbs. Routes are specified using a simple
//! syntax that lets you define variables within them; variables that can then be
//! extracted to perform various operations. Currently, the following variable types can
//! be used:
//!
//! - `<str:name>` will match anything inside a path segment, returns a `String`
//! - `<int:name>` will return a signed integer (`i32`) from a path segment
//!   - ex: `cnt.add_route("/api/foo/<int:foo_id>", &[Method::Get], my_handler)` will match
//!   `"/api/foo/123"` but not `"/api/foo/123.34"` or `"/api/foo/bar"`
//! - `<uint:name>` will return an unsigned integer (`u32`)
//! - `<float:name>` does the same thing as the `int` parameter definition, but matches numbers
//! with decimal points and returns an `f32`
//! - `<path:name>` will greedily take all path data contained, returns a `String`
//!   - ex: `cnt.add_route("/static/<path:name>", &[Method::Get], utils::static_file)` will
//!   serve anything in the `/static/` directory as a file
//!
//! ```rust
//! extern crate canteen;
//!
//! use canteen::{Canteen, Request, Response, Method};
//! use canteen::utils;
//!
//! fn hello_handler(req: &Request) -> Response {
//!     let mut res = Response::new();
//!
//!     res.set_status(200);
//!     res.set_content_type("text/plain");
//!     res.append("Hello, world!");
//!
//!     res
//! }
//!
//! fn double_handler(req: &Request) -> Response {
//!     let to_dbl: i32 = req.get("to_dbl");
//!
//!     /* simpler response generation syntax */
//!     utils::make_response(format!("{}", to_dbl * 2), "text/plain", 200)
//! }
//!
//! fn main() {
//!     let mut cnt = Canteen::new(("127.0.0.1", 8080));
//!
//!     // set the default route handler to show a 404 message
//!     cnt.set_default(utils::err_404);
//!
//!     // respond to requests to / with "Hello, world!"
//!     cnt.add_route("/", &[Method::Get], hello_handler);
//!
//!     // pull a variable from the path and do something with it
//!     cnt.add_route("/double/<int:to_dbl>", &[Method::Get], double_handler);
//!
//!     // serve raw files from the /static/ directory
//!     cnt.add_route("/static/<path:path>", &[Method::Get], utils::static_file);
//!
//!     /* cnt.run() */;
//! }
//! ```

extern crate mio;
extern crate regex;
extern crate chrono;
extern crate rustc_serialize;
extern crate threadpool;

pub mod utils;
pub mod route;
pub mod request;
pub mod response;

use std::io::Result;
use std::io::prelude::*;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use std::collections::HashSet;

use threadpool::ThreadPool;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;
use mio::*;

pub use request::*;
pub use response::*;

struct Client {
    sock:   TcpStream,
    token:  Token,
    events: EventSet,
    i_buf:  Vec<u8>,
    o_buf:  Vec<u8>,
}

impl Client {
    fn new(sock: TcpStream, token: Token) -> Client {
        Client {
            sock:   sock,
            token:  token,
            events: EventSet::hup(),
            i_buf:  Vec::with_capacity(2048),
            o_buf:  Vec::with_capacity(2048),
        }
    }

    fn receive(&mut self) -> Result<bool> {
        let mut buf: Vec<u8> = Vec::with_capacity(2048);

        match self.sock.try_read_buf(&mut buf) {
            Ok(size)  => {
                match size {
                    Some(_) => {
                        self.events.remove(EventSet::readable());
                        self.events.insert(EventSet::writable());
                        self.i_buf.extend(buf);
                        return Ok(true);
                    },
                    None    => {
                        return Ok(false);
                    },
                }
            },
            Err(e)  => {
                panic!("failed to read from socket! <token: {:?}> <error: {:?}>", self.token, e);
            },
        }

        Ok(false)
    }

    // write the client's output buffer to the socket.
    //
    // the following return values mean:
    //  - Ok(true):  we can close the connection
    //  - Ok(false): keep listening for writeable event and continue next time
    //  - Err(e):    something dun fucked up
    fn send(&mut self) -> Result<bool> {
        if self.o_buf.len() == 0 {
            return Ok(false);
        }

        while self.o_buf.len() > 0 {
            match self.sock.write(&self.o_buf.as_slice()) {
                Ok(sz)  => {
                    if sz == self.o_buf.len() {
                        // we did it!
                        self.events.remove(EventSet::writable());
                        break;
                    } else {
                        // keep going
                        self.o_buf = self.o_buf.split_off(sz);
                    }
                },
                Err(e)  => {
                    panic!("failed to write to socket! <token: {:?}> <error: {:?}>", self.token, e);
                }
            }
        }

        Ok(true)
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        self.events.insert(EventSet::readable());

        evl.register(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.reregister(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to re-register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }
}

/// The primary struct provided by the library. The aim is to have a similar
/// interface to Flask, the Python microframework.
pub struct Canteen {
    routes:  HashMap<route::RouteDef, route::Route>,
    rcache:  HashMap<route::RouteDef, route::RouteDef>,
    server:  TcpListener,
    token:   Token,
    conns:   Slab<Client>,
    default: fn(&Request) -> Response,
    tpool:   ThreadPool,
}

impl Handler for Canteen {
    type Timeout = ();
    type Message = (Token, Vec<u8>);

    fn ready(&mut self, evl: &mut EventLoop<Canteen>, token: Token, events: EventSet) {
        if events.is_error() || events.is_hup() {
            self.reset_connection(token);
            return;
        }

        if events.is_readable() {
            if self.token == token {
                self.accept(evl);
            } else {
                self.readable(evl, token)
                    .and_then(|_| self.get_client(token)
                                      .reregister(evl))
                    .unwrap_or_else(|e| {
                        panic!("read event failed! <token: {:?}> <error: {:?}>", token, e);
                    });
            }

            return;
        }

        if events.is_writable() {
            match self.get_client(token).send() {
                Ok(true)    => { self.reset_connection(token); },
                Ok(false)   => { let _ = self.get_client(token).reregister(evl); },
                Err(_)      => { panic!("something really bad happened!"); },
            }
        }
    }

    fn notify(&mut self, evl: &mut EventLoop<Canteen>, msg: (Token, Vec<u8>)) {
        let (token, output) = msg;
        let mut client = self.get_client(token);

        client.o_buf.extend(output);
        let _ = client.reregister(evl);
    }
}

impl Canteen {
    /// Creates a new Canteen instance.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    ///
    /// let cnt = Canteen::new(("127.0.0.1", 8081));
    /// ```
    pub fn new<A: ToSocketAddrs>(addr: A) -> Canteen {
        Canteen {
            routes:  HashMap::new(),
            rcache:  HashMap::new(),
            server:  TcpListener::bind(&addr.to_socket_addrs().unwrap().next().unwrap()).unwrap(),
            token:   Token(1),
            conns:   Slab::new_starting_at(Token(2), 2048),
            default: utils::err_404,
            tpool:   ThreadPool::new(255),
        }
    }

    /// Adds a new route definition to be handled by Canteen.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::{Canteen, Request, Response, Method};
    /// use canteen::utils;
    ///
    /// fn handler(_: &Request) -> Response {
    ///     utils::make_response("<b>Hello, world!</b>", "text/html", 200)
    /// }
    ///
    /// fn main() {
    ///     let mut cnt = Canteen::new(("127.0.0.1", 8082));
    ///     cnt.add_route("/hello", &[Method::Get], handler);
    /// }
    /// ```
    pub fn add_route(&mut self, path: &str, mlist: &[Method],
                     handler: fn(&Request) -> Response) -> &mut Canteen {
        let mut methods: HashSet<Method> = HashSet::new();

        // make them unique
        for m in mlist {
            methods.insert(*m);
        }

        for m in methods {
            let rd = route::RouteDef {
                pathdef:    String::from(path),
                method:     m,
            };

            if self.routes.contains_key(&rd) {
                panic!("a route handler for {} has already been defined!", path);
            }

            self.routes.insert(rd, route::Route::new(&path, m, handler));
        }

        self
    }

    /// Defines a default route for undefined paths.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    /// use canteen::utils;
    ///
    /// let mut cnt = Canteen::new(("127.0.0.1", 8083));
    /// cnt.set_default(utils::err_404);
    /// ```
    pub fn set_default(&mut self, handler: fn(&Request) -> Response) {
        self.default = handler;
    }

    fn get_client<'a>(&'a mut self, token: Token) -> &'a mut Client {
        match self.conns.get_mut(token) {
            None    => { panic!("it's gone!"); },
            Some(c) => c,
        }
    }

    fn accept(&mut self, evl: &mut EventLoop<Canteen>) {
        let (sock, _) = match self.server.accept() {
            Ok(s)   => {
                match s {
                    Some(sock)  => sock,
                    None        => {
                        panic!("failed to accept new connection!");
                    }
                }
            },
            Err(e)  => {
                panic!("failed to accept new connection! <error: {:?}>", e);
            },
        };

        match self.conns.insert_with(|token| Client::new(sock, token)) {
            Some(token) => {
                match self.get_client(token).register(evl) {
                    Ok(_)   => {},
                    Err(e)  => {
                        panic!("failed to register client! <token: {:?}> <error: {:?}>", token, e);
                    },
                }
            },
            None        => {
                panic!("failed to add client connection!");
            },
        }

        self.reregister(evl);
    }

    fn handle_request(&mut self, token: Token, tx: Sender<(Token, Vec<u8>)>, rqstr: &str) {
        let mut req = Request::from_str(&rqstr);
        let resolved = route::RouteDef { pathdef: req.path.clone(), method: req.method };
        let mut handler: fn(&Request) -> Response = self.default;

        if self.rcache.contains_key(&resolved) {
            let ref route = self.routes[&self.rcache[&resolved]];

            handler = route.handler;
            req.params = route.parse(&req.path);
        } else {
            for (path, route) in &self.routes {
                match (route).is_match(&req) {
                    true  => {
                        handler = route.handler;
                        req.params = route.parse(&req.path);
                        self.rcache.insert(resolved, (*path).clone());
                        break;
                    },
                    false => continue,
                }
            }
        }

        self.tpool.execute(move || {
            let _ = tx.send((token, handler(&req).gen_output()));
        });
    }

    fn readable(&mut self, evl: &mut EventLoop<Canteen>, token: Token) -> Result<bool> {
        match self.get_client(token).receive() {
            Ok(true)    => {
                let buf = self.get_client(token).i_buf.clone();
                let rqstr = String::from_utf8(buf).unwrap();
                self.handle_request(token, evl.channel(), &rqstr);
            },
            Ok(false)   => {},
            Err(e)      => {
                panic!("message wasn't actually readable! <error: {:?}>", e);
            },
        };

        Ok(true)
    }

    fn reset_connection(&mut self, token: Token) {
        // kill the connection
        self.conns.remove(token);
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.register(&self.server, self.token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) {
        match evl.reregister(&self.server, self.token,
                             EventSet::readable(),
                             PollOpt::edge() | PollOpt::oneshot()) {
            Ok(_)   => {},
            Err(e)  => {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           }
        };
    }

    /// Creates the listener and starts a Canteen server's event loop.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    ///
    /// let cnt = Canteen::new(("127.0.0.1", 8084));
    /// /* cnt.run(); */
    /// ```
    pub fn run(&mut self) {
        let mut evl = EventLoop::new().unwrap();
        self.register(&mut evl).ok();
        evl.run(self).unwrap();
    }
}
<commit_msg>remove needless token check<commit_after>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

//! # Canteen
//!
//! ## Description
//!
//! A pure Rust clone of [Flask](http://flask.pocoo.org), a simple but powerful Python
//! web framework.
//!
//! ## Example
//!
//! The principle behind Canteen is simple -- handler functions are defined as simple
//! Rust functions that take a `Request` and return a `Response`. Handlers are then attached
//! to one or more routes and HTTP methods/verbs. Routes are specified using a simple
//! syntax that lets you define variables within them; variables that can then be
//! extracted to perform various operations. Currently, the following variable types can
//! be used:
//!
//! - `<str:name>` will match anything inside a path segment, returns a `String`
//! - `<int:name>` will return a signed integer (`i32`) from a path segment
//!   - ex: `cnt.add_route("/api/foo/<int:foo_id>", &[Method::Get], my_handler)` will match
//!   `"/api/foo/123"` but not `"/api/foo/123.34"` or `"/api/foo/bar"`
//! - `<uint:name>` will return an unsigned integer (`u32`)
//! - `<float:name>` does the same thing as the `int` parameter definition, but matches numbers
//! with decimal points and returns an `f32`
//! - `<path:name>` will greedily take all path data contained, returns a `String`
//!   - ex: `cnt.add_route("/static/<path:name>", &[Method::Get], utils::static_file)` will
//!   serve anything in the `/static/` directory as a file
//!
//! ```rust
//! extern crate canteen;
//!
//! use canteen::{Canteen, Request, Response, Method};
//! use canteen::utils;
//!
//! fn hello_handler(req: &Request) -> Response {
//!     let mut res = Response::new();
//!
//!     res.set_status(200);
//!     res.set_content_type("text/plain");
//!     res.append("Hello, world!");
//!
//!     res
//! }
//!
//! fn double_handler(req: &Request) -> Response {
//!     let to_dbl: i32 = req.get("to_dbl");
//!
//!     /* simpler response generation syntax */
//!     utils::make_response(format!("{}", to_dbl * 2), "text/plain", 200)
//! }
//!
//! fn main() {
//!     let mut cnt = Canteen::new(("127.0.0.1", 8080));
//!
//!     // set the default route handler to show a 404 message
//!     cnt.set_default(utils::err_404);
//!
//!     // respond to requests to / with "Hello, world!"
//!     cnt.add_route("/", &[Method::Get], hello_handler);
//!
//!     // pull a variable from the path and do something with it
//!     cnt.add_route("/double/<int:to_dbl>", &[Method::Get], double_handler);
//!
//!     // serve raw files from the /static/ directory
//!     cnt.add_route("/static/<path:path>", &[Method::Get], utils::static_file);
//!
//!     /* cnt.run() */;
//! }
//! ```

extern crate mio;
extern crate regex;
extern crate chrono;
extern crate rustc_serialize;
extern crate threadpool;

pub mod utils;
pub mod route;
pub mod request;
pub mod response;

use std::io::Result;
use std::io::prelude::*;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use std::collections::HashSet;

use threadpool::ThreadPool;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;
use mio::*;

pub use request::*;
pub use response::*;

struct Client {
    sock:   TcpStream,
    token:  Token,
    events: EventSet,
    i_buf:  Vec<u8>,
    o_buf:  Vec<u8>,
}

impl Client {
    fn new(sock: TcpStream, token: Token) -> Client {
        Client {
            sock:   sock,
            token:  token,
            events: EventSet::hup(),
            i_buf:  Vec::with_capacity(2048),
            o_buf:  Vec::with_capacity(2048),
        }
    }

    fn receive(&mut self) -> Result<bool> {
        let mut buf: Vec<u8> = Vec::with_capacity(2048);

        match self.sock.try_read_buf(&mut buf) {
            Ok(size)  => {
                match size {
                    Some(_) => {
                        self.events.remove(EventSet::readable());
                        self.events.insert(EventSet::writable());
                        self.i_buf.extend(buf);
                        return Ok(true);
                    },
                    None    => {
                        return Ok(false);
                    },
                }
            },
            Err(e)  => {
                panic!("failed to read from socket! <token: {:?}> <error: {:?}>", self.token, e);
            },
        }

        Ok(false)
    }

    // write the client's output buffer to the socket.
    //
    // the following return values mean:
    //  - Ok(true):  we can close the connection
    //  - Ok(false): keep listening for writeable event and continue next time
    //  - Err(e):    something dun fucked up
    fn send(&mut self) -> Result<bool> {
        if self.o_buf.len() == 0 {
            return Ok(false);
        }

        while self.o_buf.len() > 0 {
            match self.sock.write(&self.o_buf.as_slice()) {
                Ok(sz)  => {
                    if sz == self.o_buf.len() {
                        // we did it!
                        self.events.remove(EventSet::writable());
                        break;
                    } else {
                        // keep going
                        self.o_buf = self.o_buf.split_off(sz);
                    }
                },
                Err(e)  => {
                    panic!("failed to write to socket! <token: {:?}> <error: {:?}>", self.token, e);
                }
            }
        }

        Ok(true)
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        self.events.insert(EventSet::readable());

        evl.register(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.reregister(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to re-register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }
}

/// The primary struct provided by the library. The aim is to have a similar
/// interface to Flask, the Python microframework.
pub struct Canteen {
    routes:  HashMap<route::RouteDef, route::Route>,
    rcache:  HashMap<route::RouteDef, route::RouteDef>,
    server:  TcpListener,
    token:   Token,
    conns:   Slab<Client>,
    default: fn(&Request) -> Response,
    tpool:   ThreadPool,
}

impl Handler for Canteen {
    type Timeout = ();
    type Message = (Token, Vec<u8>);

    fn ready(&mut self, evl: &mut EventLoop<Canteen>, token: Token, events: EventSet) {
        if events.is_error() || events.is_hup() {
            self.reset_connection(token);
            return;
        }

        if events.is_readable() {
            if self.token == token {
                self.accept(evl);
            } else {
                self.readable(evl, token)
                    .and_then(|_| self.get_client(token)
                                      .reregister(evl))
                    .unwrap_or_else(|e| {
                        panic!("read event failed! <token: {:?}> <error: {:?}>", token, e);
                    });
            }

            return;
        }

        if events.is_writable() {
            match self.get_client(token).send() {
                Ok(true)    => { self.reset_connection(token); },
                Ok(false)   => { let _ = self.get_client(token).reregister(evl); },
                Err(_)      => { panic!("something really bad happened!"); },
            }
        }
    }

    fn notify(&mut self, evl: &mut EventLoop<Canteen>, msg: (Token, Vec<u8>)) {
        let (token, output) = msg;
        let mut client = self.get_client(token);

        client.o_buf.extend(output);
        let _ = client.reregister(evl);
    }
}

impl Canteen {
    /// Creates a new Canteen instance.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    ///
    /// let cnt = Canteen::new(("127.0.0.1", 8081));
    /// ```
    pub fn new<A: ToSocketAddrs>(addr: A) -> Canteen {
        Canteen {
            routes:  HashMap::new(),
            rcache:  HashMap::new(),
            server:  TcpListener::bind(&addr.to_socket_addrs().unwrap().next().unwrap()).unwrap(),
            token:   Token(1),
            conns:   Slab::new_starting_at(Token(2), 2048),
            default: utils::err_404,
            tpool:   ThreadPool::new(255),
        }
    }

    /// Adds a new route definition to be handled by Canteen.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::{Canteen, Request, Response, Method};
    /// use canteen::utils;
    ///
    /// fn handler(_: &Request) -> Response {
    ///     utils::make_response("<b>Hello, world!</b>", "text/html", 200)
    /// }
    ///
    /// fn main() {
    ///     let mut cnt = Canteen::new(("127.0.0.1", 8082));
    ///     cnt.add_route("/hello", &[Method::Get], handler);
    /// }
    /// ```
    pub fn add_route(&mut self, path: &str, mlist: &[Method],
                     handler: fn(&Request) -> Response) -> &mut Canteen {
        let mut methods: HashSet<Method> = HashSet::new();

        // make them unique
        for m in mlist {
            methods.insert(*m);
        }

        for m in methods {
            let rd = route::RouteDef {
                pathdef:    String::from(path),
                method:     m,
            };

            if self.routes.contains_key(&rd) {
                panic!("a route handler for {} has already been defined!", path);
            }

            self.routes.insert(rd, route::Route::new(&path, m, handler));
        }

        self
    }

    /// Defines a default route for undefined paths.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    /// use canteen::utils;
    ///
    /// let mut cnt = Canteen::new(("127.0.0.1", 8083));
    /// cnt.set_default(utils::err_404);
    /// ```
    pub fn set_default(&mut self, handler: fn(&Request) -> Response) {
        self.default = handler;
    }

    fn get_client<'a>(&'a mut self, token: Token) -> &'a mut Client {
        &mut self.conns[token]
    }

    fn accept(&mut self, evl: &mut EventLoop<Canteen>) {
        let (sock, _) = match self.server.accept() {
            Ok(s)   => {
                match s {
                    Some(sock)  => sock,
                    None        => {
                        panic!("failed to accept new connection!");
                    }
                }
            },
            Err(e)  => {
                panic!("failed to accept new connection! <error: {:?}>", e);
            },
        };

        match self.conns.insert_with(|token| Client::new(sock, token)) {
            Some(token) => {
                match self.get_client(token).register(evl) {
                    Ok(_)   => {},
                    Err(e)  => {
                        panic!("failed to register client! <token: {:?}> <error: {:?}>", token, e);
                    },
                }
            },
            None        => {
                panic!("failed to add client connection!");
            },
        }

        self.reregister(evl);
    }

    fn handle_request(&mut self, token: Token, tx: Sender<(Token, Vec<u8>)>, rqstr: &str) {
        let mut req = Request::from_str(&rqstr);
        let resolved = route::RouteDef { pathdef: req.path.clone(), method: req.method };
        let mut handler: fn(&Request) -> Response = self.default;

        if self.rcache.contains_key(&resolved) {
            let ref route = self.routes[&self.rcache[&resolved]];

            handler = route.handler;
            req.params = route.parse(&req.path);
        } else {
            for (path, route) in &self.routes {
                match (route).is_match(&req) {
                    true  => {
                        handler = route.handler;
                        req.params = route.parse(&req.path);
                        self.rcache.insert(resolved, (*path).clone());
                        break;
                    },
                    false => continue,
                }
            }
        }

        self.tpool.execute(move || {
            let _ = tx.send((token, handler(&req).gen_output()));
        });
    }

    fn readable(&mut self, evl: &mut EventLoop<Canteen>, token: Token) -> Result<bool> {
        match self.get_client(token).receive() {
            Ok(true)    => {
                let buf = self.get_client(token).i_buf.clone();
                let rqstr = String::from_utf8(buf).unwrap();
                self.handle_request(token, evl.channel(), &rqstr);
            },
            Ok(false)   => {},
            Err(e)      => {
                panic!("message wasn't actually readable! <error: {:?}>", e);
            },
        };

        Ok(true)
    }

    fn reset_connection(&mut self, token: Token) {
        // kill the connection
        self.conns.remove(token);
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.register(&self.server, self.token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) {
        match evl.reregister(&self.server, self.token,
                             EventSet::readable(),
                             PollOpt::edge() | PollOpt::oneshot()) {
            Ok(_)   => {},
            Err(e)  => {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           }
        };
    }

    /// Creates the listener and starts a Canteen server's event loop.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    ///
    /// let cnt = Canteen::new(("127.0.0.1", 8084));
    /// /* cnt.run(); */
    /// ```
    pub fn run(&mut self) {
        let mut evl = EventLoop::new().unwrap();
        self.register(&mut evl).ok();
        evl.run(self).unwrap();
    }
}
<|endoftext|>


<commit_before>use std::ops::Deref;

/// Dirty wraps a value of type T with functions similiar to that of a Read/Write
/// lock but simply sets a dirty flag on write(), reset on clear().
/// Use read() or deref (*dirty_variable) to access the inner value.
pub struct Dirty<T> {
    value: T,
    dirty: bool,
}

impl<T> Dirty<T> {
    /// Create a new Dirty.
    pub fn new(val: T) -> Dirty<T> {
        Dirty {
            value: val,
            dirty: true,
        }
    }

    /// Returns true if dirty, false otherwise.
    #[allow(dead_code)]
    pub fn dirty(&self) -> bool {
        self.dirty
    }

    /// Writable value return, sets the dirty flag.
    pub fn write(&mut self) -> &mut T {
        self.dirty = true;
        &mut self.value
    }

    /// Read the value.
    pub fn read(&self) -> &T {
        &self.value
    }

    /// Clears the dirty flag.
    pub fn clear(&mut self) {
        self.dirty = false;
    }

    /// Read the value only if modified since last read.
    #[allow(dead_code)]
    pub fn read_dirty(&self) -> Option<&T> {
        match self.dirty {
            true => {
                Some(&self.value)
            },
            false => None,
        }
    }
}

impl<T> Deref for Dirty<T>{
    type Target = T;
    fn deref(&self) -> &T {
        &self.value
    }
}

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

    #[test]
    fn new_dirty() {
        let dirty = Dirty::new(0);
        assert!(dirty.dirty() == true);
    }

    #[test]
    fn read_doesnt_clears_flag() {
        let dirty = Dirty::new(0);
        assert!(dirty.dirty() == true);
        assert!(*dirty.read() == 0);
        assert!(dirty.dirty() == true);
    }

    #[test]
    fn write_sets_flag() {
        let mut dirty = Dirty::new(0);
        assert!(*dirty.read() == 0);
        dirty.clear();
        assert!(dirty.dirty() == false);
        *dirty.write() += 1;
        assert!(dirty.dirty() == true);
    }

    #[test]
    fn read_dirty() {
        let mut dirty = Dirty::new(0);
        assert!(dirty.read_dirty().is_some());
		dirty.clear();
        assert!(dirty.dirty() == false);
        assert!(dirty.read_dirty() == None);
        assert!(dirty.dirty() == false);
        *dirty.write() += 1;
        assert!(dirty.dirty() == true);
        assert!(dirty.read_dirty().is_some());
		dirty.clear();
        assert!(dirty.dirty() == false);
        assert!(dirty.read_dirty() == None);
    }

    #[test]
    fn access_inner_deref() {
        let dirty = Dirty::new(0);
        assert!(*dirty == 0);
    }
}
<commit_msg>Added default implementation for T has default<commit_after>use std::ops::Deref;

/// Dirty wraps a value of type T with functions similiar to that of a Read/Write
/// lock but simply sets a dirty flag on write(), reset on clear().
/// Use read() or deref (*dirty_variable) to access the inner value.
pub struct Dirty<T> {
    value: T,
    dirty: bool,
}

impl<T> Dirty<T> {
    /// Create a new Dirty.
    pub fn new(val: T) -> Dirty<T> {
        Dirty {
            value: val,
            dirty: true,
        }
    }

    /// Returns true if dirty, false otherwise.
    #[allow(dead_code)]
    pub fn dirty(&self) -> bool {
        self.dirty
    }

    /// Writable value return, sets the dirty flag.
    pub fn write(&mut self) -> &mut T {
        self.dirty = true;
        &mut self.value
    }

    /// Read the value.
    pub fn read(&self) -> &T {
        &self.value
    }

    /// Clears the dirty flag.
    pub fn clear(&mut self) {
        self.dirty = false;
    }

    /// Read the value only if modified since last read.
    #[allow(dead_code)]
    pub fn read_dirty(&self) -> Option<&T> {
        match self.dirty {
            true => {
                Some(&self.value)
            },
            false => None,
        }
    }
}

impl<T> Deref for Dirty<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.value
    }
}

impl<T> Default for Dirty<T> where T: Default {
    fn default() -> Self {
        Dirty::new(T::default())
    }
}

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

    #[test]
    fn new_dirty() {
        let dirty = Dirty::new(0);
        assert!(dirty.dirty() == true);
    }

    #[test]
    fn read_doesnt_clears_flag() {
        let dirty = Dirty::new(0);
        assert!(dirty.dirty() == true);
        assert!(*dirty.read() == 0);
        assert!(dirty.dirty() == true);
    }

    #[test]
    fn write_sets_flag() {
        let mut dirty = Dirty::new(0);
        assert!(*dirty.read() == 0);
        dirty.clear();
        assert!(dirty.dirty() == false);
        *dirty.write() += 1;
        assert!(dirty.dirty() == true);
    }

    #[test]
    fn read_dirty() {
        let mut dirty = Dirty::new(0);
        assert!(dirty.read_dirty().is_some());
		dirty.clear();
        assert!(dirty.dirty() == false);
        assert!(dirty.read_dirty() == None);
        assert!(dirty.dirty() == false);
        *dirty.write() += 1;
        assert!(dirty.dirty() == true);
        assert!(dirty.read_dirty().is_some());
		dirty.clear();
        assert!(dirty.dirty() == false);
        assert!(dirty.read_dirty() == None);
    }

    #[test]
    fn access_inner_deref() {
        let dirty = Dirty::new(0);
        assert!(*dirty == 0);
    }

    #[test]
    fn default_value() {
        let dirty = Dirty::<i32>::default();
        assert!(*dirty == 0);
    }
}
<|endoftext|>


<commit_before>#![feature(backtrace)]

mod as_error;
mod exception;
mod context;

#[doc(inline)]
/// Annotations a function that "throws" a Result.
///
/// Inside functions tagged with `throws`, you can use `?` and the `throw!` macro to return errors,
/// but you don't need to wrap the successful return values in `Ok`.
///
/// `throws` can optionally take a type as an argument, which will be the error type returned by
/// this function. By default, the function will throw `Exception`.
pub use fehler_macros::throws;

#[doc(inline)]
/// Derive for the Error trait.
///
/// If the type contains a `Backtrace`, it will generate the `backtrace` method to find it.
///
/// If this wraps a different, underlying error, you can tag that field with `#[error::source]`,
/// which will generate the `cause` and `source` methods correctly.
pub use fehler_macros::Error;

pub use crate::as_error::AsError;
pub use crate::exception::{Exception, Errors};
pub use crate::context::Context;

/// Throw an error.
///
/// This macro is equivalent to `Err($err)?`.
#[macro_export]
macro_rules! throw {
    ($err:expr)   => (return std::result::Result::Err(std::convert::From::from($err)))
}

/// Construct an ad-hoc exception from a string.
///
/// This evaluates to an `Exception`. It can take either just a string, or a format string with
/// arguments. It also can take any custom type which implements `Debug` and `Display`.
#[macro_export]
macro_rules! error {
    ($e:expr)   => { $crate::Exception::new_adhoc($e) };
    ($($arg:tt)*) => { $crate::Exception::new_adhoc(format!($($arg)*)) };
}
<commit_msg>Drop the dependency on a macros crate<commit_after>#![feature(backtrace)]

mod as_error;
mod exception;
mod context;

pub use crate::as_error::AsError;
pub use crate::exception::{Exception, Errors};
pub use crate::context::Context;

/// Throw an error.
///
/// This macro is equivalent to `Err($err)?`.
#[macro_export]
macro_rules! throw {
    ($err:expr)   => (return std::result::Result::Err(std::convert::From::from($err)))
}

/// Construct an ad-hoc exception from a string.
///
/// This evaluates to an `Exception`. It can take either just a string, or a format string with
/// arguments. It also can take any custom type which implements `Debug` and `Display`.
#[macro_export]
macro_rules! error {
    ($e:expr)   => { $crate::Exception::new_adhoc($e) };
    ($($arg:tt)*) => { $crate::Exception::new_adhoc(format!($($arg)*)) };
}
<|endoftext|>


<commit_before>//extern crate libc;
//
//use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t};
//use std::mem;
//use std::ptr;

#[link(name = "isl")]
extern {
    fn isl_ctx_alloc() -> Box<Ctx>;
}

// safe wrapper
fn getCtx() -> Box<Ctx>  {
    unsafe { isl_ctx_alloc() }
}

//isl_ctx *ctx = isl_ctx_alloc();

#[repr(C)]
#[derive(Clone, Copy)]
// TODO align with isl/include/isl/isl_ctx_private.h
struct Ctx {
    ref_: i32,
}

#[test]
fn it_works() {
    // see https://github.com/rust-lang/rust/issues/20204
    //let ctx = getCtx();
    unsafe {
        let ctx = isl_ctx_alloc();
    }
}
<commit_msg>rust je_arena_dalloc_bin_locked problem.<commit_after>//extern crate libc;
//
//use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t};
//use std::mem;
//use std::ptr;

#[link(name = "isl")]
extern {
    fn isl_ctx_alloc() -> Box<Ctx>;
}

// safe wrapper
fn getCtx() -> Box<Ctx>  {
    unsafe { isl_ctx_alloc() }
}

//isl_ctx *ctx = isl_ctx_alloc();

#[repr(C)]
#[derive(Clone, Copy)]
// TODO align with isl/include/isl/isl_ctx_private.h
struct Ctx {
    ref_: i32,
}

#[test]
fn it_works() {
    // see https://github.com/rust-lang/rust/issues/20204
    // rust je_arena_dalloc_bin_locked
    //let ctx = getCtx();
    unsafe {
        let ctx = isl_ctx_alloc();
    }
}
<|endoftext|>


<commit_before>pub mod board;

use board::Board;

use std::i32;
use std::ops::Neg;
use std::marker::PhantomData;

#[derive(Copy,Clone,Debug)]
pub enum Team
{
    Enemy,
    Ally,
}

impl Team
{
    pub fn other_team(self) -> Team
    {
        match self
        {
            Team::Enemy => Team::Ally,
            Team::Ally => Team::Enemy,
        }
    }
}

#[derive(PartialEq,Eq,PartialOrd,Ord,Copy,Clone,Debug,Hash)]
pub enum Score
{
    Lose,
    Heuristic(i32),
    Win,
}

impl Neg for Score
{
    type Output = Self;
    fn neg(self) -> Self
    {
        match self
        {
            Score::Win => Score::Lose,
            Score::Lose => Score::Win,
            Score::Heuristic(val) => Score::Heuristic(-val),
        }
    }
}

#[derive(Clone,Debug,PartialEq,Eq)]
pub struct MoveStats<M>
{
    pub mv: Option<M>,
    pub score: Score,
    pub turns: u32,
    pub nodes_visited: u64,
}

#[derive(Clone,Debug)]
pub struct Minimax<B: Board>
{
    /* TODO: Some sort of caching */
    phantom: PhantomData<B>,
}

impl<B: Board> Minimax<B>
{
    pub fn new() -> Minimax<B>
    {
        Minimax
        {
            phantom: PhantomData,
        }
    }

    /// Minimax driver function.
    ///
    /// `turn` is the current player.
    pub fn minimax(&mut self, board: &B, turn: Team, plies: u32) -> MoveStats<B::Move>
    {
        let mut optimal_move = match turn
        {
            Team::Ally =>
                self.max(board, plies, Score::Lose, Score::Win),
            Team::Enemy =>
                self.min(board, plies, Score::Lose, Score::Win),
        };
        optimal_move.nodes_visited += 1;
        optimal_move
    }

    /// Generates best move for ally
    fn max(&mut self, board: &B, plies: u32, mut alpha: Score, beta: Score) -> MoveStats<B::Move>
    {
        let moves = board.gen_ally_moves();

        /* Fail state if you can't move */
        if moves.len() == 0
        {
            return MoveStats
            {
                mv: None,
                score: Score::Lose,
                turns: 0,
                nodes_visited: 0,
            };
        }

        /* If you cannot proceed further */
        if plies == 0 || board.is_game_over()
        {
            return MoveStats
            {
                mv: None,
                score: board.score(),
                turns: 0,
                nodes_visited: 0,
            }
        }

        let mut best = MoveStats {
            mv: None,
            score: Score::Lose,
            turns: 0,
            nodes_visited: 0,
        };

        for mv in moves
        {

            /* Make a clone of the board so we don't break this one */
            let mut board_clone = board.clone();
            board_clone.do_move(&mv);

            /* Find enemy's best move */
            let enemy_move = self.min(&board_clone, plies - 1, alpha, beta);

            /* TODO: Try to postpone losing */
            if best.mv.is_none() || (enemy_move.score, -(enemy_move.turns as i32)) > (best.score, -(best.turns as i32))
            {
                best.mv = Some(mv);
                best.score = enemy_move.score;
                best.turns = enemy_move.turns + 1;
            }

            best.nodes_visited += enemy_move.nodes_visited + 1;

            /* Set α and break on β ≤ α */
            if best.score > alpha
            {
                alpha = enemy_move.score;
            }
            if alpha >= beta
            {
                break;
            }
        }
        best
    }

    /// Generates best move for enemy
    fn min(&mut self, board: &B, plies: u32, alpha: Score, mut beta: Score) -> MoveStats<B::Move>
    {
        let moves = board.gen_enemy_moves();

        /* Fail state if you can't move */
        if moves.len() == 0
        {
            return MoveStats
            {
                mv: None,
                /* If enemy can't move, we win. */
                score: Score::Win,
                turns: 0,
                nodes_visited: 0,
            };
        }

        /* If you cannot proceed further */
        if plies == 0 || board.is_game_over()
        {
            return MoveStats
            {
                mv: None,
                score: board.score(),
                turns: 0,
                nodes_visited: 0,
            }
        }

        let mut best = MoveStats {
            mv: None,
            /* Technically doesn't matter, but for consistancy's sake */
            score: Score::Win,
            turns: 0,
            nodes_visited: 0,
        };

        for mv in moves
        {
            /* Make a clone of the board so we don't break this one */
            let mut board_clone = board.clone();
            board_clone.do_move(&mv);

            /* Find ally's best move */
            let ally_move = self.max(&board_clone, plies - 1, alpha, beta);

            /* TODO: Try to postpone losing */
            if best.mv.is_none() || (ally_move.score, -(ally_move.turns as i32)) < (best.score, -(best.turns as i32))
            {
                best.mv = Some(mv);
                best.score = ally_move.score;
                best.turns = ally_move.turns + 1;
            }

            best.nodes_visited += ally_move.nodes_visited + 1;

            /* Set β and break on β ≤ α */
            if best.score < beta
            {
                beta = ally_move.score;
            }
            if alpha >= beta
            {
                break;
            }
        }
        best
    }
}

#[cfg(test)]
mod tests
{
    use super::{Team, Score, Minimax, MoveStats};
    use board::Board;

    #[derive(PartialEq,Eq,Debug)]
    struct SimpleMove(usize);
    #[derive(Clone,PartialEq,Eq,Hash,Debug)]
    enum SimpleBoard
    {
        Node(Vec<SimpleBoard>),
        Leaf(Score),
    }

    /* These aren't really efficient, but they
     * work for testing.
     */
    impl Board for SimpleBoard
    {
        type Move = SimpleMove;

        fn gen_ally_moves(&self) -> Vec<Self::Move>
        {
            match *self
            {
                SimpleBoard::Node(ref v) =>
                    (0..v.len()).map(|u| SimpleMove(u)).collect(),
                SimpleBoard::Leaf(_) =>
                    /* Trick the algorithm into thinking
                     * we still have moves left
                     */
                    vec![SimpleMove(1)],
            }
        }

        fn gen_enemy_moves(&self) -> Vec<Self::Move>
        {
            match *self
            {
                SimpleBoard::Node(ref v) =>
                    (0..v.len()).map(|u| SimpleMove(u)).collect(),
                SimpleBoard::Leaf(_) =>
                    /* Trick the algorithm into thinking
                     * we still have moves left
                     */
                    vec![SimpleMove(1)],
            }
        }

        fn do_move(&mut self, mv: &Self::Move)
        {
            let child = match *self
            {
                SimpleBoard::Node(ref v) =>
                    Some(v[mv.0].clone()),
                SimpleBoard::Leaf(_) =>
                    None,
            };

            if let Some(c) = child
            {
                *self = c;
            }
        }

        fn score(&self) -> Score
        {
            match *self
            {
                SimpleBoard::Node(_) =>
                    unreachable!(),
                SimpleBoard::Leaf(s) =>
                    s,
            }
        }

        fn is_game_over(&self) -> bool
        {
            match *self
            {
                SimpleBoard::Node(_) =>
                    false,
                SimpleBoard::Leaf(_) =>
                    true,
            }
        }
    }

    #[test]
    fn test_score_ord()
    {
        assert!(Score::Win > Score::Heuristic(0));
        assert!(Score::Heuristic(0) > Score::Lose);
        assert!(Score::Win > Score::Lose);
        assert!(Score::Heuristic(100) > Score::Heuristic(0));
        assert!(Score::Heuristic(0) > Score::Heuristic(-100));
        assert!(Score::Win == Score::Win);
        assert!(Score::Lose == Score::Lose);
        assert!(Score::Heuristic(0) == Score::Heuristic(0));
    }

    #[test]
    fn test_minimax()
    {
        let mut minimax = Minimax::new();
        let game1 =
        SimpleBoard::Node(vec![
            SimpleBoard::Node(vec![
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(5)),
                        SimpleBoard::Leaf(Score::Heuristic(6)),
                    ]),
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(7)),
                        SimpleBoard::Leaf(Score::Heuristic(4)),
                        SimpleBoard::Leaf(Score::Heuristic(5)),
                    ]),
                ]),
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(3)),
                    ]),
                ]),
            ]),
            SimpleBoard::Node(vec![
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(6)),
                    ]),
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(6)),
                        SimpleBoard::Leaf(Score::Heuristic(9)),
                    ]),
                ]),
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(7)),
                    ]),
                ]),
            ]),
            SimpleBoard::Node(vec![
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(5)),
                    ]),
                ]),
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(9)),
                        SimpleBoard::Leaf(Score::Heuristic(8)),
                    ]),
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(6)),
                    ]),
                ]),
            ]),
        ]);
        let game2 =
        SimpleBoard::Node(vec![
            SimpleBoard::Node(vec![
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(12)),
                        SimpleBoard::Leaf(Score::Heuristic(10)),
                    ]),
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(-18)),
                        SimpleBoard::Leaf(Score::Heuristic(-7)),
                    ]),
                ]),
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(6)),
                        SimpleBoard::Leaf(Score::Heuristic(-17)),
                    ]),
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(-3)),
                        SimpleBoard::Leaf(Score::Heuristic(6)),
                    ]),
                ]),
            ]),
            SimpleBoard::Node(vec![
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(-19)),
                        SimpleBoard::Leaf(Score::Heuristic(-16)),
                    ]),
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(-4)),
                        SimpleBoard::Leaf(Score::Heuristic(-6)),
                    ]),
                ]),
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(-1)),
                        SimpleBoard::Leaf(Score::Heuristic(6)),
                    ]),
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(9)),
                        SimpleBoard::Leaf(Score::Heuristic(15)),
                    ]),
                ]),
            ]),
        ]);

        println!();
        println!("Game 1");
        assert_eq!(game1.gen_ally_moves(), vec![SimpleMove(0), SimpleMove(1), SimpleMove(2)]);
        let move_stats1 = minimax.minimax(&game1, Team::Ally, 4);
        let optimal_move1 = MoveStats {
            mv: Some(SimpleMove(1)),
            score: Score::Heuristic(6),
            turns: 4,
            nodes_visited: 25,
        };
        assert_eq!(move_stats1, optimal_move1);

        println!();
        println!("Game 2");
        assert_eq!(game2.gen_ally_moves(), vec![SimpleMove(0), SimpleMove(1)]);
        let move_stats2 = minimax.minimax(&game2, Team::Ally, 4);
        let optimal_move2 = MoveStats {
            mv: Some(SimpleMove(0)),
            score: Score::Heuristic(-3),
            turns: 4,
            nodes_visited: 21,
        };
        assert_eq!(move_stats2, optimal_move2);
    }
}
<commit_msg>minimax: remove trait bound on struct<commit_after>pub mod board;

use board::Board;

use std::i32;
use std::ops::Neg;
use std::marker::PhantomData;

#[derive(Copy,Clone,Debug)]
pub enum Team
{
    Enemy,
    Ally,
}

impl Team
{
    pub fn other_team(self) -> Team
    {
        match self
        {
            Team::Enemy => Team::Ally,
            Team::Ally => Team::Enemy,
        }
    }
}

#[derive(PartialEq,Eq,PartialOrd,Ord,Copy,Clone,Debug,Hash)]
pub enum Score
{
    Lose,
    Heuristic(i32),
    Win,
}

impl Neg for Score
{
    type Output = Self;
    fn neg(self) -> Self
    {
        match self
        {
            Score::Win => Score::Lose,
            Score::Lose => Score::Win,
            Score::Heuristic(val) => Score::Heuristic(-val),
        }
    }
}

#[derive(Clone,Debug,PartialEq,Eq)]
pub struct MoveStats<M>
{
    pub mv: Option<M>,
    pub score: Score,
    pub turns: u32,
    pub nodes_visited: u64,
}

#[derive(Clone,Debug)]
pub struct Minimax<B>
{
    /* TODO: Some sort of caching */
    phantom: PhantomData<B>,
}

impl<B: Board> Minimax<B>
{
    pub fn new() -> Minimax<B>
    {
        Minimax
        {
            phantom: PhantomData,
        }
    }

    /// Minimax driver function.
    ///
    /// `turn` is the current player.
    pub fn minimax(&mut self, board: &B, turn: Team, plies: u32) -> MoveStats<B::Move>
    {
        let mut optimal_move = match turn
        {
            Team::Ally =>
                self.max(board, plies, Score::Lose, Score::Win),
            Team::Enemy =>
                self.min(board, plies, Score::Lose, Score::Win),
        };
        optimal_move.nodes_visited += 1;
        optimal_move
    }

    /// Generates best move for ally
    fn max(&mut self, board: &B, plies: u32, mut alpha: Score, beta: Score) -> MoveStats<B::Move>
    {
        let moves = board.gen_ally_moves();

        /* Fail state if you can't move */
        if moves.len() == 0
        {
            return MoveStats
            {
                mv: None,
                score: Score::Lose,
                turns: 0,
                nodes_visited: 0,
            };
        }

        /* If you cannot proceed further */
        if plies == 0 || board.is_game_over()
        {
            return MoveStats
            {
                mv: None,
                score: board.score(),
                turns: 0,
                nodes_visited: 0,
            }
        }

        let mut best = MoveStats {
            mv: None,
            score: Score::Lose,
            turns: 0,
            nodes_visited: 0,
        };

        for mv in moves
        {

            /* Make a clone of the board so we don't break this one */
            let mut board_clone = board.clone();
            board_clone.do_move(&mv);

            /* Find enemy's best move */
            let enemy_move = self.min(&board_clone, plies - 1, alpha, beta);

            /* TODO: Try to postpone losing */
            if best.mv.is_none() || (enemy_move.score, -(enemy_move.turns as i32)) > (best.score, -(best.turns as i32))
            {
                best.mv = Some(mv);
                best.score = enemy_move.score;
                best.turns = enemy_move.turns + 1;
            }

            best.nodes_visited += enemy_move.nodes_visited + 1;

            /* Set α and break on β ≤ α */
            if best.score > alpha
            {
                alpha = enemy_move.score;
            }
            if alpha >= beta
            {
                break;
            }
        }
        best
    }

    /// Generates best move for enemy
    fn min(&mut self, board: &B, plies: u32, alpha: Score, mut beta: Score) -> MoveStats<B::Move>
    {
        let moves = board.gen_enemy_moves();

        /* Fail state if you can't move */
        if moves.len() == 0
        {
            return MoveStats
            {
                mv: None,
                /* If enemy can't move, we win. */
                score: Score::Win,
                turns: 0,
                nodes_visited: 0,
            };
        }

        /* If you cannot proceed further */
        if plies == 0 || board.is_game_over()
        {
            return MoveStats
            {
                mv: None,
                score: board.score(),
                turns: 0,
                nodes_visited: 0,
            }
        }

        let mut best = MoveStats {
            mv: None,
            /* Technically doesn't matter, but for consistancy's sake */
            score: Score::Win,
            turns: 0,
            nodes_visited: 0,
        };

        for mv in moves
        {
            /* Make a clone of the board so we don't break this one */
            let mut board_clone = board.clone();
            board_clone.do_move(&mv);

            /* Find ally's best move */
            let ally_move = self.max(&board_clone, plies - 1, alpha, beta);

            /* TODO: Try to postpone losing */
            if best.mv.is_none() || (ally_move.score, -(ally_move.turns as i32)) < (best.score, -(best.turns as i32))
            {
                best.mv = Some(mv);
                best.score = ally_move.score;
                best.turns = ally_move.turns + 1;
            }

            best.nodes_visited += ally_move.nodes_visited + 1;

            /* Set β and break on β ≤ α */
            if best.score < beta
            {
                beta = ally_move.score;
            }
            if alpha >= beta
            {
                break;
            }
        }
        best
    }
}

#[cfg(test)]
mod tests
{
    use super::{Team, Score, Minimax, MoveStats};
    use board::Board;

    #[derive(PartialEq,Eq,Debug)]
    struct SimpleMove(usize);
    #[derive(Clone,PartialEq,Eq,Hash,Debug)]
    enum SimpleBoard
    {
        Node(Vec<SimpleBoard>),
        Leaf(Score),
    }

    /* These aren't really efficient, but they
     * work for testing.
     */
    impl Board for SimpleBoard
    {
        type Move = SimpleMove;

        fn gen_ally_moves(&self) -> Vec<Self::Move>
        {
            match *self
            {
                SimpleBoard::Node(ref v) =>
                    (0..v.len()).map(|u| SimpleMove(u)).collect(),
                SimpleBoard::Leaf(_) =>
                    /* Trick the algorithm into thinking
                     * we still have moves left
                     */
                    vec![SimpleMove(1)],
            }
        }

        fn gen_enemy_moves(&self) -> Vec<Self::Move>
        {
            match *self
            {
                SimpleBoard::Node(ref v) =>
                    (0..v.len()).map(|u| SimpleMove(u)).collect(),
                SimpleBoard::Leaf(_) =>
                    /* Trick the algorithm into thinking
                     * we still have moves left
                     */
                    vec![SimpleMove(1)],
            }
        }

        fn do_move(&mut self, mv: &Self::Move)
        {
            let child = match *self
            {
                SimpleBoard::Node(ref v) =>
                    Some(v[mv.0].clone()),
                SimpleBoard::Leaf(_) =>
                    None,
            };

            if let Some(c) = child
            {
                *self = c;
            }
        }

        fn score(&self) -> Score
        {
            match *self
            {
                SimpleBoard::Node(_) =>
                    unreachable!(),
                SimpleBoard::Leaf(s) =>
                    s,
            }
        }

        fn is_game_over(&self) -> bool
        {
            match *self
            {
                SimpleBoard::Node(_) =>
                    false,
                SimpleBoard::Leaf(_) =>
                    true,
            }
        }
    }

    #[test]
    fn test_score_ord()
    {
        assert!(Score::Win > Score::Heuristic(0));
        assert!(Score::Heuristic(0) > Score::Lose);
        assert!(Score::Win > Score::Lose);
        assert!(Score::Heuristic(100) > Score::Heuristic(0));
        assert!(Score::Heuristic(0) > Score::Heuristic(-100));
        assert!(Score::Win == Score::Win);
        assert!(Score::Lose == Score::Lose);
        assert!(Score::Heuristic(0) == Score::Heuristic(0));
    }

    #[test]
    fn test_minimax()
    {
        let mut minimax = Minimax::new();
        let game1 =
        SimpleBoard::Node(vec![
            SimpleBoard::Node(vec![
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(5)),
                        SimpleBoard::Leaf(Score::Heuristic(6)),
                    ]),
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(7)),
                        SimpleBoard::Leaf(Score::Heuristic(4)),
                        SimpleBoard::Leaf(Score::Heuristic(5)),
                    ]),
                ]),
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(3)),
                    ]),
                ]),
            ]),
            SimpleBoard::Node(vec![
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(6)),
                    ]),
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(6)),
                        SimpleBoard::Leaf(Score::Heuristic(9)),
                    ]),
                ]),
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(7)),
                    ]),
                ]),
            ]),
            SimpleBoard::Node(vec![
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(5)),
                    ]),
                ]),
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(9)),
                        SimpleBoard::Leaf(Score::Heuristic(8)),
                    ]),
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(6)),
                    ]),
                ]),
            ]),
        ]);
        let game2 =
        SimpleBoard::Node(vec![
            SimpleBoard::Node(vec![
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(12)),
                        SimpleBoard::Leaf(Score::Heuristic(10)),
                    ]),
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(-18)),
                        SimpleBoard::Leaf(Score::Heuristic(-7)),
                    ]),
                ]),
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(6)),
                        SimpleBoard::Leaf(Score::Heuristic(-17)),
                    ]),
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(-3)),
                        SimpleBoard::Leaf(Score::Heuristic(6)),
                    ]),
                ]),
            ]),
            SimpleBoard::Node(vec![
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(-19)),
                        SimpleBoard::Leaf(Score::Heuristic(-16)),
                    ]),
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(-4)),
                        SimpleBoard::Leaf(Score::Heuristic(-6)),
                    ]),
                ]),
                SimpleBoard::Node(vec![
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(-1)),
                        SimpleBoard::Leaf(Score::Heuristic(6)),
                    ]),
                    SimpleBoard::Node(vec![
                        SimpleBoard::Leaf(Score::Heuristic(9)),
                        SimpleBoard::Leaf(Score::Heuristic(15)),
                    ]),
                ]),
            ]),
        ]);

        println!();
        println!("Game 1");
        assert_eq!(game1.gen_ally_moves(), vec![SimpleMove(0), SimpleMove(1), SimpleMove(2)]);
        let move_stats1 = minimax.minimax(&game1, Team::Ally, 4);
        let optimal_move1 = MoveStats {
            mv: Some(SimpleMove(1)),
            score: Score::Heuristic(6),
            turns: 4,
            nodes_visited: 25,
        };
        assert_eq!(move_stats1, optimal_move1);

        println!();
        println!("Game 2");
        assert_eq!(game2.gen_ally_moves(), vec![SimpleMove(0), SimpleMove(1)]);
        let move_stats2 = minimax.minimax(&game2, Team::Ally, 4);
        let optimal_move2 = MoveStats {
            mv: Some(SimpleMove(0)),
            score: Score::Heuristic(-3),
            turns: 4,
            nodes_visited: 21,
        };
        assert_eq!(move_stats2, optimal_move2);
    }
}
<|endoftext|>


<commit_before>#![feature(associated_types)]

use std::ascii::AsciiExt;

use tokenizer::{PeekableTokens, Token, Tokens};
use types::FromTokens;
use types::linestring::LineString;
use types::point::Point;

mod tokenizer;
mod types;

pub enum WktItem {
    Point(Point),
    LineString(LineString),
}

impl WktItem {
    fn from_word_and_tokens(word: &str, tokens: &mut PeekableTokens)-> Result<Self, &'static str> {
        match word {
            "POINT" => {
                let x: Result<Point, _> = FromTokens::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "LINESTRING" => {
                let x: Result<LineString, _> = FromTokens::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            _ => Err("Invalid type encountered"),
        }
    }
}

pub struct Wkt {
    items: Vec<WktItem>
}

impl Wkt {
    fn new() -> Self {
        Wkt {items: vec![]}
    }

    fn add_item(&mut self, item: WktItem) {
        self.items.push(item);
    }

    fn from_str(wkt_str: &str) -> Result<Self, &'static str> {
        let tokens = Tokens::from_str(wkt_str);
        Wkt::from_tokens(tokens)
    }

    fn from_tokens(tokens: Tokens) -> Result<Self, &'static str> {
        let mut wkt = Wkt::new();
        let mut tokens = tokens.peekable();
        let word = match tokens.next() {
            Some(Token::Word(word)) => {
                if !word.is_ascii() {
                    return Err("Encountered non-ascii word");
                }
                word.to_ascii_uppercase()
            },
            None => return Ok(wkt),
            _ => return Err("Invalid WKT format"),
        };
        match WktItem::from_word_and_tokens(word.as_slice(), &mut tokens) {
            Ok(item) => wkt.add_item(item),
            Err(s) => return Err(s),
        }
        Ok(wkt)
    }
}

#[test]
fn empty_string() {
    let wkt = Wkt::from_str("").ok().unwrap();
    assert_eq!(0, wkt.items.len());
}

#[test]
fn basic_point() {
    let mut wkt = Wkt::from_str("POINT (10 -20)").ok().unwrap();
    assert_eq!(1, wkt.items.len());
    let point = match wkt.items.pop().unwrap() {
        WktItem::Point(point) => point,
        _ => unreachable!(),
    };
    assert_eq!(10.0, point.coord.x);
    assert_eq!(-20.0, point.coord.y);
    assert_eq!(None, point.coord.z);
    assert_eq!(None, point.coord.m);
}

#[test]
fn basic_linestring() {
    let mut wkt = Wkt::from_str("LINESTRING (10 -20, -0 -0.5)").ok().unwrap();
    assert_eq!(1, wkt.items.len());
    let linestring = match wkt.items.pop().unwrap() {
        WktItem::LineString(linestring) => linestring,
        _ => unreachable!(),
    };
    assert_eq!(2, linestring.coords.len());

    assert_eq!(10.0, linestring.coords[0].x);
    assert_eq!(-20.0, linestring.coords[0].y);
    assert_eq!(None, linestring.coords[0].z);
    assert_eq!(None, linestring.coords[0].m);

    assert_eq!(0.0, linestring.coords[1].x);
    assert_eq!(-0.5, linestring.coords[1].y);
    assert_eq!(None, linestring.coords[1].z);
    assert_eq!(None, linestring.coords[1].m);
}

#[test]
fn invalid_points() {
    Wkt::from_str("POINT ()").err().unwrap();
    Wkt::from_str("POINT (10)").err().unwrap();
    Wkt::from_str("POINT 10").err().unwrap();
    Wkt::from_str("POINT (10 -20 40)").err().unwrap();
}
<commit_msg>Create test module<commit_after>#![feature(associated_types)]

use std::ascii::AsciiExt;

use tokenizer::{PeekableTokens, Token, Tokens};
use types::FromTokens;
use types::linestring::LineString;
use types::point::Point;

mod tokenizer;
mod types;

pub enum WktItem {
    Point(Point),
    LineString(LineString),
}

impl WktItem {
    fn from_word_and_tokens(word: &str, tokens: &mut PeekableTokens)-> Result<Self, &'static str> {
        match word {
            "POINT" => {
                let x: Result<Point, _> = FromTokens::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            "LINESTRING" => {
                let x: Result<LineString, _> = FromTokens::from_tokens_with_parens(tokens);
                x.map(|y| y.as_item())
            },
            _ => Err("Invalid type encountered"),
        }
    }
}

pub struct Wkt {
    items: Vec<WktItem>
}

impl Wkt {
    fn new() -> Self {
        Wkt {items: vec![]}
    }

    fn add_item(&mut self, item: WktItem) {
        self.items.push(item);
    }

    fn from_str(wkt_str: &str) -> Result<Self, &'static str> {
        let tokens = Tokens::from_str(wkt_str);
        Wkt::from_tokens(tokens)
    }

    fn from_tokens(tokens: Tokens) -> Result<Self, &'static str> {
        let mut wkt = Wkt::new();
        let mut tokens = tokens.peekable();
        let word = match tokens.next() {
            Some(Token::Word(word)) => {
                if !word.is_ascii() {
                    return Err("Encountered non-ascii word");
                }
                word.to_ascii_uppercase()
            },
            None => return Ok(wkt),
            _ => return Err("Invalid WKT format"),
        };
        match WktItem::from_word_and_tokens(word.as_slice(), &mut tokens) {
            Ok(item) => wkt.add_item(item),
            Err(s) => return Err(s),
        }
        Ok(wkt)
    }
}

#[cfg(test)]
mod tests {
    use super::{Wkt, WktItem};

    #[test]
    fn empty_string() {
        let wkt = Wkt::from_str("").ok().unwrap();
        assert_eq!(0, wkt.items.len());
    }

    #[test]
    fn basic_point() {
        let mut wkt = Wkt::from_str("POINT (10 -20)").ok().unwrap();
        assert_eq!(1, wkt.items.len());
        let point = match wkt.items.pop().unwrap() {
            WktItem::Point(point) => point,
            _ => unreachable!(),
        };
        assert_eq!(10.0, point.coord.x);
        assert_eq!(-20.0, point.coord.y);
        assert_eq!(None, point.coord.z);
        assert_eq!(None, point.coord.m);
    }

    #[test]
    fn basic_linestring() {
        let mut wkt = Wkt::from_str("LINESTRING (10 -20, -0 -0.5)").ok().unwrap();
        assert_eq!(1, wkt.items.len());
        let linestring = match wkt.items.pop().unwrap() {
            WktItem::LineString(linestring) => linestring,
            _ => unreachable!(),
        };
        assert_eq!(2, linestring.coords.len());

        assert_eq!(10.0, linestring.coords[0].x);
        assert_eq!(-20.0, linestring.coords[0].y);
        assert_eq!(None, linestring.coords[0].z);
        assert_eq!(None, linestring.coords[0].m);

        assert_eq!(0.0, linestring.coords[1].x);
        assert_eq!(-0.5, linestring.coords[1].y);
        assert_eq!(None, linestring.coords[1].z);
        assert_eq!(None, linestring.coords[1].m);
    }

    #[test]
    fn invalid_points() {
        Wkt::from_str("POINT ()").err().unwrap();
        Wkt::from_str("POINT (10)").err().unwrap();
        Wkt::from_str("POINT 10").err().unwrap();
        Wkt::from_str("POINT (10 -20 40)").err().unwrap();
    }
}
<|endoftext|>