<commit_before>/* kernel::cstr.rs */
#[allow(unused_imports)];
use core::*;
use core::str::*;
use core::option::{Some, Option, None}; // Match statement
use core::iter::Iterator;
use kernel::*;
use super::super::platform::*;
use kernel::memory::Allocator;

pub static DEFAULT_STRLEN: uint = 256;

pub static mut count:uint = 0;

pub struct cstr {
    p: *mut u8,
    p_cstr_i: uint,
    size: uint
}

impl cstr {
    pub fn new() -> cstr {
        unsafe {
            cstr::news(DEFAULT_STRLEN)
        }
    }

    pub unsafe fn news(size: uint) -> cstr {
        // Sometimes this doesn't allocate enough memory and gets stuck...
        let (z, w) = heap.alloc(size);
        let (x, y) = heap.alloc(size);
        let this = cstr {
            p: x,
            p_cstr_i: 0,
            size: y
        };
        *(((this.p as uint)) as *mut char) = '\0';
        this
    }

    pub fn from_str(s: &str) -> cstr {
        let mut this = cstr::new();
        for c in slice::iter(as_bytes(s)) {
            this.add_u8(*c);
        };
        this
    }

    pub fn map_u8(&mut self, f: |u8|) {
        self.map(|c: char| {
            f(c as u8)
        });
    }

    pub fn map(&self, f: |char|) {
        let mut i = 0;
        while i < self.len() && self.get_char(i) != '\0' {
            f(self.get_char(i));
            i += 1;
        }
    }

    pub unsafe fn join(&self, other: cstr) -> cstr {
        let mut len = DEFAULT_STRLEN;
        while len < self.len() + other.len() {
            len += DEFAULT_STRLEN;
        }
        let mut new = cstr::news(len);
        self.map(|c| { new.add_char(c); } );
        other.map(|c| { new.add_char(c); } );
        new
    }

    pub unsafe fn trim(&mut self) -> cstr {
        let mut new = cstr::new();
        if self.len() == 0 || self.size > new.size {
            return new;
        }
        // Kill beginning whitespace.
        let mut beginwhite = true;
        let mut i = 0;
        while i < self.len() {
            let c = self.get_char(i);
            let iswhite = (c == (' ') || c == ('\n'));
            if !iswhite || !beginwhite {
                beginwhite = false;
                new.add_char(c);
            }
            i += 1;
        }
        // Kill trailing whitespace.
        i = self.len();
        let mut endwhite = true;
        while (endwhite && i > 0) {
            let c = self.get_char(i);
            let iswhite = (c == (' ') || c == ('\n'));
            if !iswhite {
                endwhite = false;
            }
            else {
                new.delete_char();
            }
            i -= 1;
        }
        return new;
    }

    pub unsafe fn clone(&mut self) -> cstr {
        let mut ind: uint = 0;
        let mut s = cstr::news(self.size);
        loop {
            if (self.len() == 0 || ind == self.len()) {
                return s;
            }
            s.add_u8(self.get_char(ind) as u8);
            ind += 1;
            if (ind == self.size) {
                return s;
            }
        }
    }

    #[allow(dead_code)]
    pub fn len(&self) -> uint {
        self.p_cstr_i
    }

    // HELP THIS DOESN'T WORK THERE IS NO GARBAGE COLLECTION!!!
    // -- TODO: exchange_malloc, exchange_free
    #[allow(dead_code)]
    pub unsafe fn destroy(&self) {
        heap.free(self.p);
    }

    pub fn get_char(&self, idx: uint) -> char {
        if idx > self.len() || idx > self.size || self.p_cstr_i > self.size {
            return '\0';
        }
        unsafe {
            *(((self.p as uint) + idx) as *char)
        }
    }

    pub fn add_char(&mut self, c: char) -> bool {
        self.add_u8(c as u8)
    }

    pub fn add_u8(&mut self, x: u8) -> bool {
        if (self.p_cstr_i >= self.size || self.size > DEFAULT_STRLEN) {
            return false;
        }
        unsafe {
            *(((self.p as uint) + self.p_cstr_i) as *mut u8) = x;
            self.p_cstr_i += 1;
            *(((self.p as uint) + self.p_cstr_i) as *mut char) = '\0';
        }
        true
    }

    pub unsafe fn delete_char(&mut self) -> bool {
        if (self.p_cstr_i == 0) {
            return false;
        }
        self.p_cstr_i -= 1;
        *(((self.p as uint)+self.p_cstr_i) as *mut char) = '\0';
        true
    }

    pub unsafe fn reset(&mut self) {
        self.p_cstr_i = 0;
        *(self.p as *mut char) = '\0';
    }

    #[allow(dead_code)]
    pub unsafe fn eq(&self, other: &cstr) -> bool {
        if (self.len() != other.len()) { return false; }
        else {
            let mut x = 0;
            let mut selfp: uint = self.p as uint;
            let mut otherp: uint = other.p as uint;
            while x < self.len() {
                if (*(selfp as *char) != *(otherp as *char)) { return false; }
                selfp += 1;
                otherp += 1;
                x += 1;
            }
            true
        }
    }

    pub unsafe fn streq(&self, other: &str) -> bool {
        let mut selfp: uint = self.p as uint;
        for c in slice::iter(as_bytes(other)) {
            if( *c != *(selfp as *u8) ) {
                return false;
            }
            selfp += 1;
        };
        *(selfp as *char) == '\0'
    }

    pub unsafe fn getarg(&self, delim: char, mut k: uint) -> Option<cstr> {
        let mut ind: uint = 0;
        let mut found = k == 0;
        let mut selfp: uint = self.p as uint;
        let mut s = cstr::new();
        loop {
            if (self.len() == 0) {
                return None;
            }
            if (*(selfp as *char) == '\0') {
                // End of string
                if (found) { return Some(s); }
                else { return None; }
            };
            if (*(selfp as *u8) == delim as u8) {
                if (found) { return Some(s); }
                k -= 1;
            };
            if (found) {
                s.add_u8(*(selfp as *u8));
            };
            found = k == 0;
            selfp += 1;
            ind += 1;
            if (ind == self.size) {
                return None;
            }
        }
    }
    #[allow(dead_code)]
    pub unsafe fn split(&self, delim: char) -> (cstr, cstr) {
        let mut i = 0;
        let mut beg = cstr::new();
        let mut end = cstr::new();
        let mut found = false;
        while i < self.len() && self.get_char(i) != '\0' {
            if (!found && self.get_char(i) as u8 == delim as u8) {
                found = true;
            }
            else if (!found) {
                beg.add_char(self.get_char(i));
            }
            else {
                end.add_char(self.get_char(i));
            };
            i += 1;
        }
        (beg, end)
    }
}
<commit_msg>kill getarg()<commit_after>/* kernel::cstr.rs */
#[allow(unused_imports)];
use core::*;
use core::str::*;
use core::option::{Some, Option, None}; // Match statement
use core::iter::Iterator;
use kernel::*;
use super::super::platform::*;
use kernel::memory::Allocator;

pub static DEFAULT_STRLEN: uint = 256;

pub static mut count:uint = 0;

pub struct cstr {
    p: *mut u8,
    p_cstr_i: uint,
    size: uint
}

impl cstr {
    pub fn new() -> cstr {
        unsafe {
            cstr::news(DEFAULT_STRLEN)
        }
    }

    pub unsafe fn news(size: uint) -> cstr {
        // Sometimes this doesn't allocate enough memory and gets stuck...
        let (z, w) = heap.alloc(size);
        let (x, y) = heap.alloc(size);
        let this = cstr {
            p: x,
            p_cstr_i: 0,
            size: y
        };
        *(((this.p as uint)) as *mut char) = '\0';
        this
    }

    pub fn from_str(s: &str) -> cstr {
        let mut this = cstr::new();
        for c in slice::iter(as_bytes(s)) {
            this.add_u8(*c);
        };
        this
    }

    pub fn map_u8(&mut self, f: |u8|) {
        self.map(|c: char| {
            f(c as u8)
        });
    }

    pub fn map(&self, f: |char|) {
        let mut i = 0;
        while i < self.len() && self.get_char(i) != '\0' {
            f(self.get_char(i));
            i += 1;
        }
    }

    pub unsafe fn join(&self, other: cstr) -> cstr {
        let mut len = DEFAULT_STRLEN;
        while len < self.len() + other.len() {
            len += DEFAULT_STRLEN;
        }
        let mut new = cstr::news(len);
        self.map(|c| { new.add_char(c); } );
        other.map(|c| { new.add_char(c); } );
        new
    }

    pub unsafe fn trim(&mut self) -> cstr {
        let mut new = cstr::new();
        if self.len() == 0 || self.size > new.size {
            return new;
        }
        // Kill beginning whitespace.
        let mut beginwhite = true;
        let mut i = 0;
        while i < self.len() {
            let c = self.get_char(i);
            let iswhite = (c == (' ') || c == ('\n'));
            if !iswhite || !beginwhite {
                beginwhite = false;
                new.add_char(c);
            }
            i += 1;
        }
        // Kill trailing whitespace.
        i = self.len();
        let mut endwhite = true;
        while (endwhite && i > 0) {
            let c = self.get_char(i);
            let iswhite = (c == (' ') || c == ('\n'));
            if !iswhite {
                endwhite = false;
            }
            else {
                new.delete_char();
            }
            i -= 1;
        }
        return new;
    }

    pub unsafe fn clone(&mut self) -> cstr {
        let mut ind: uint = 0;
        let mut s = cstr::news(self.size);
        loop {
            if (self.len() == 0 || ind == self.len()) {
                return s;
            }
            s.add_u8(self.get_char(ind) as u8);
            ind += 1;
            if (ind == self.size) {
                return s;
            }
        }
    }

    #[allow(dead_code)]
    pub fn len(&self) -> uint {
        self.p_cstr_i
    }

    // HELP THIS DOESN'T WORK THERE IS NO GARBAGE COLLECTION!!!
    // -- TODO: exchange_malloc, exchange_free
    #[allow(dead_code)]
    pub unsafe fn destroy(&self) {
        heap.free(self.p);
    }

    pub fn get_char(&self, idx: uint) -> char {
        if idx > self.len() || idx > self.size || self.p_cstr_i > self.size {
            return '\0';
        }
        unsafe {
            *(((self.p as uint) + idx) as *char)
        }
    }

    pub fn add_char(&mut self, c: char) -> bool {
        self.add_u8(c as u8)
    }

    pub fn add_u8(&mut self, x: u8) -> bool {
        if (self.p_cstr_i >= self.size || self.size > DEFAULT_STRLEN) {
            return false;
        }
        unsafe {
            *(((self.p as uint) + self.p_cstr_i) as *mut u8) = x;
            self.p_cstr_i += 1;
            *(((self.p as uint) + self.p_cstr_i) as *mut char) = '\0';
        }
        true
    }

    pub unsafe fn delete_char(&mut self) -> bool {
        if (self.p_cstr_i == 0) {
            return false;
        }
        self.p_cstr_i -= 1;
        *(((self.p as uint)+self.p_cstr_i) as *mut char) = '\0';
        true
    }

    pub unsafe fn reset(&mut self) {
        self.p_cstr_i = 0;
        *(self.p as *mut char) = '\0';
    }

    #[allow(dead_code)]
    pub unsafe fn eq(&self, other: &cstr) -> bool {
        if (self.len() != other.len()) { return false; }
        else {
            let mut x = 0;
            let mut selfp: uint = self.p as uint;
            let mut otherp: uint = other.p as uint;
            while x < self.len() {
                if (*(selfp as *char) != *(otherp as *char)) { return false; }
                selfp += 1;
                otherp += 1;
                x += 1;
            }
            true
        }
    }

    pub unsafe fn streq(&self, other: &str) -> bool {
        let mut selfp: uint = self.p as uint;
        for c in slice::iter(as_bytes(other)) {
            if( *c != *(selfp as *u8) ) {
                return false;
            }
            selfp += 1;
        };
        *(selfp as *char) == '\0'
    }

    #[allow(dead_code)]
    pub unsafe fn split(&self, delim: char) -> (cstr, cstr) {
        let mut i = 0;
        let mut beg = cstr::new();
        let mut end = cstr::new();
        let mut found = false;
        while i < self.len() && self.get_char(i) != '\0' {
            if (!found && self.get_char(i) as u8 == delim as u8) {
                found = true;
            }
            else if (!found) {
                beg.add_char(self.get_char(i));
            }
            else {
                end.add_char(self.get_char(i));
            };
            i += 1;
        }
        (beg, end)
    }
}
<|endoftext|>


<commit_before>#![crate_type="staticlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(arc_counts)]
#![feature(augmented_assignments)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(core_str_ext)]
#![feature(core_slice_ext)]
#![feature(fnbox)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(op_assign_traits)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
#![feature(collections_range)]
#![feature(old_wrapping)]
#![no_std]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

extern crate system;

use acpi::Acpi;

use alloc::boxed::Box;

use collections::string::{String, ToString};
use collections::vec::Vec;

use core::cell::UnsafeCell;
use core::{ptr, mem, usize};
use core::slice::SliceExt;

use common::event::{self, EVENT_KEY, EventOption};
use common::memory;
use common::paging::Page;
use common::time::Duration;

use drivers::pci;
use drivers::io::{Io, Pio};
use drivers::ps2::*;
use drivers::rtc::*;
use drivers::serial::*;

use env::Environment;

use graphics::display;

use scheduler::{Context, Regs, TSS};
use scheduler::context::context_switch;

use schemes::Url;
use schemes::context::*;
use schemes::debug::*;
use schemes::display::*;
use schemes::interrupt::*;
use schemes::memory::*;

use syscall::execute::execute;
use syscall::handle::*;

pub use system::externs::*;

/// Common std-like functionality
#[macro_use]
pub mod common;
#[macro_use]
pub mod macros;
/// Allocation
pub mod alloc_system;
/// ACPI
pub mod acpi;
/// Disk drivers
pub mod disk;
/// Various drivers
pub mod drivers;
/// Environment
pub mod env;
/// Filesystems
pub mod fs;
/// Various graphical methods
pub mod graphics;
/// Panic
pub mod panic;
/// Schemes
pub mod schemes;
/// Scheduling
pub mod scheduler;
/// Sync primatives
pub mod sync;
/// System calls
pub mod syscall;
/// USB input/output
pub mod usb;

pub static mut TSS_PTR: Option<&'static mut TSS> = None;
pub static mut ENV_PTR: Option<&'static mut Environment> = None;

pub fn env() -> &'static Environment {
    unsafe {
        match ENV_PTR {
            Some(&mut ref p) => p,
            None => unreachable!(),
        }
    }
}

/// Pit duration
static PIT_DURATION: Duration = Duration {
    secs: 0,
    nanos: 2250286,
};

/// Idle loop (active while idle)
unsafe fn idle_loop() {
    loop {
        asm!("cli" : : : : "intel", "volatile");

        let mut halt = true;

        for i in env().contexts.lock().iter().skip(1) {
            if i.interrupted {
                halt = false;
                break;
            }
        }

        if halt {
            asm!("sti
                  hlt"
                  :
                  :
                  :
                  : "intel", "volatile");
        } else {
            asm!("sti"
                :
                :
                :
                : "intel", "volatile");
        }

        context_switch(false);
    }
}

/// Event poll loop
fn poll_loop() {
    loop {
        env().on_poll();

        unsafe { context_switch(false) };
    }
}

/// Event loop
fn event_loop() {
    {
        let mut console = env().console.lock();
        console.instant = false;
    }

    let mut cmd = String::new();
    loop {
        loop {
            let mut console = env().console.lock();
            match env().events.lock().pop_front() {
                Some(event) => {
                    if console.draw {
                        match event.to_option() {
                            EventOption::Key(key_event) => {
                                if key_event.pressed {
                                    match key_event.scancode {
                                        event::K_F2 => {
                                            console.draw = false;
                                        }
                                        event::K_BKSP => if !cmd.is_empty() {
                                            console.write(&[8]);
                                            cmd.pop();
                                        },
                                        _ => match key_event.character {
                                            '\0' => (),
                                            '\n' => {
                                                console.command = Some(cmd.clone());

                                                cmd.clear();
                                                console.write(&[10]);
                                            }
                                            _ => {
                                                cmd.push(key_event.character);
                                                console.write(&[key_event.character as u8]);
                                            }
                                        },
                                    }
                                }
                            }
                            _ => (),
                        }
                    } else {
                        if event.code == EVENT_KEY && event.b as u8 == event::K_F1 && event.c > 0 {
                            console.draw = true;
                            console.redraw = true;
                        } else {
                            // TODO: Magical orbital hack
                        }
                    }
                }
                None => break,
            }
        }

        {
            let mut console = env().console.lock();
            console.instant = false;
            if console.draw && console.redraw {
                console.redraw = false;
                console.display.flip();
            }
        }

        unsafe { context_switch(false) };
    }
}

static BSS_TEST_ZERO: usize = 0;
static BSS_TEST_NONZERO: usize = usize::MAX;

/// Initialize kernel
unsafe fn init(tss_data: usize) {

    // Test
    assume!(true);

    // Zero BSS, this initializes statics that are set to 0
    {
        extern {
            static mut __bss_start: u8;
            static mut __bss_end: u8;
        }

        let start_ptr = &mut __bss_start;
        let end_ptr = &mut __bss_end;

        if start_ptr as *const _ as usize <= end_ptr as *const _ as usize {
            let size = end_ptr as *const _ as usize - start_ptr as *const _ as usize;
            memset(start_ptr, 0, size);
        }

        assert_eq!(BSS_TEST_ZERO, 0);
        assert_eq!(BSS_TEST_NONZERO, usize::MAX);
    }

    // Setup paging, this allows for memory allocation
    Page::init();
    memory::cluster_init();
    // Unmap first page to catch null pointer errors (after reading memory map)
    Page::new(0).unmap();

    TSS_PTR = Some(&mut *(tss_data as *mut TSS));
    ENV_PTR = Some(&mut *Box::into_raw(Environment::new()));

    match ENV_PTR {
        Some(ref mut env) => {
            env.contexts.lock().push(Context::root());
            env.console.lock().draw = true;

            debug!("Redox {} bits\n", mem::size_of::<usize>() * 8);

            if let Some(acpi) = Acpi::new() {
                env.schemes.push(UnsafeCell::new(acpi));
            }

            *(env.clock_realtime.lock()) = Rtc::new().time();

            env.schemes.push(UnsafeCell::new(Ps2::new()));
            env.schemes.push(UnsafeCell::new(Serial::new(0x3F8, 0x4)));

            pci::pci_init(env);

            env.schemes.push(UnsafeCell::new(DebugScheme::new()));
            env.schemes.push(UnsafeCell::new(box DisplayScheme));
            env.schemes.push(UnsafeCell::new(box ContextScheme));
            env.schemes.push(UnsafeCell::new(box InterruptScheme));
            env.schemes.push(UnsafeCell::new(box MemoryScheme));

            Context::spawn("kpoll".to_string(),
            box move || {
                poll_loop();
            });

            Context::spawn("kevent".to_string(),
            box move || {
                event_loop();
            });

            env.contexts.lock().enabled = true;

            Context::spawn("kinit".to_string(),
            box move || {
                {
                    let wd_c = "file:/\0";
                    do_sys_chdir(wd_c.as_ptr());

                    let stdio_c = "debug:\0";
                    do_sys_open(stdio_c.as_ptr(), 0);
                    do_sys_open(stdio_c.as_ptr(), 0);
                    do_sys_open(stdio_c.as_ptr(), 0);
                }

                execute(Url::from_str("file:/apps/init/main.bin"), Vec::new());
                debug!("INIT: Failed to execute\n");

                loop {
                    context_switch(false);
                }
            });
        },
        None => unreachable!(),
    }
}

#[cold]
#[inline(never)]
#[no_mangle]
/// Take regs for kernel calls and exceptions
pub extern "cdecl" fn kernel(interrupt: usize, mut regs: &mut Regs) {
    macro_rules! exception_inner {
        ($name:expr) => ({
            {
                let contexts = ::env().contexts.lock();
                if let Some(context) = contexts.current() {
                    debugln!("PID {}: {}", context.pid, context.name);
                }
            }

            debugln!("  INT {:X}: {}", interrupt, $name);
            debugln!("    CS:  {:08X}    IP:  {:08X}    FLG: {:08X}", regs.cs, regs.ip, regs.flags);
            debugln!("    SS:  {:08X}    SP:  {:08X}    BP:  {:08X}", regs.ss, regs.sp, regs.bp);
            debugln!("    AX:  {:08X}    BX:  {:08X}    CX:  {:08X}    DX:  {:08X}", regs.ax, regs.bx, regs.cx, regs.dx);
            debugln!("    DI:  {:08X}    SI:  {:08X}", regs.di, regs.di);

            let cr0: usize;
            let cr2: usize;
            let cr3: usize;
            let cr4: usize;
            unsafe {
                asm!("mov $0, cr0" : "=r"(cr0) : : : "intel", "volatile");
                asm!("mov $0, cr2" : "=r"(cr2) : : : "intel", "volatile");
                asm!("mov $0, cr3" : "=r"(cr3) : : : "intel", "volatile");
                asm!("mov $0, cr4" : "=r"(cr4) : : : "intel", "volatile");
            }
            debugln!("    CR0: {:08X}    CR2: {:08X}    CR3: {:08X}    CR4: {:08X}", cr0, cr2, cr3, cr4);

            let sp = regs.sp as *const u32;
            for y in -15..16 {
                debug!("    {:>3}:", y * 8 * 4);
                for x in 0..8 {
                    debug!(" {:08X}", unsafe { ptr::read(sp.offset(-(x + y * 8))) });
                }
                debug!("\n");
            }
        })
    };

    macro_rules! exception {
        ($name:expr) => ({
            exception_inner!($name);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    macro_rules! exception_error {
        ($name:expr) => ({
            let error = regs.ip;
            regs.ip = regs.cs;
            regs.cs = regs.flags;
            regs.flags = regs.sp;
            regs.sp = regs.ss;
            regs.ss = 0;
            //regs.ss = regs.error;

            exception_inner!($name);
            debugln!("    ERR: {:08X}", error);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    if interrupt >= 0x20 && interrupt < 0x30 {
        if interrupt >= 0x28 {
            Pio::<u8>::new(0xA0).write(0x20);
        }

        Pio::<u8>::new(0x20).write(0x20);
    }

    //Do not catch init interrupt
    if interrupt < 0xFF {
        env().interrupts.lock()[interrupt as usize] += 1;
    }

    match interrupt {
        0x20 => {
            {
                let mut clock_monotonic = env().clock_monotonic.lock();
                *clock_monotonic = *clock_monotonic + PIT_DURATION;
            }
            {
                let mut clock_realtime = env().clock_realtime.lock();
                *clock_realtime = *clock_realtime + PIT_DURATION;
            }

            let switch = {
                let mut contexts = ::env().contexts.lock();
                if let Some(mut context) = contexts.current_mut() {
                    context.slices -= 1;
                    context.slice_total += 1;
                    context.slices == 0
                } else {
                    false
                }
            };

            if switch {
                unsafe { context_switch(true) };
            }
        }
        i @ 0x21 ... 0x2F => env().on_irq(i as u8 - 0x20),
        0x80 => if !syscall_handle(regs) {
            exception!("Unknown Syscall");
        },
        0xFF => {
            unsafe {
                init(regs.ax);
                idle_loop();
            }
        },
        0x0 => exception!("Divide by zero exception"),
        0x1 => exception!("Debug exception"),
        0x2 => exception!("Non-maskable interrupt"),
        0x3 => exception!("Breakpoint exception"),
        0x4 => exception!("Overflow exception"),
        0x5 => exception!("Bound range exceeded exception"),
        0x6 => exception!("Invalid opcode exception"),
        0x7 => exception!("Device not available exception"),
        0x8 => exception_error!("Double fault"),
        0x9 => exception!("Coprocessor Segment Overrun"), // legacy
        0xA => exception_error!("Invalid TSS exception"),
        0xB => exception_error!("Segment not present exception"),
        0xC => exception_error!("Stack-segment fault"),
        0xD => exception_error!("General protection fault"),
        0xE => exception_error!("Page fault"),
        0x10 => exception!("x87 floating-point exception"),
        0x11 => exception_error!("Alignment check exception"),
        0x12 => exception!("Machine check exception"),
        0x13 => exception!("SIMD floating-point exception"),
        0x14 => exception!("Virtualization exception"),
        0x1E => exception_error!("Security exception"),
        _ => exception!("Unknown Interrupt"),
    }
}

#[test]
fn get_slice_test() {
    let array = [1, 2, 3, 4, 5];
    assert_eq!(array.get_slice(2, None), array[2..]);
    assert_eq!(array.get_slice(2, array.len()), array[2..array.len()]);
    assert_eq!(array.get_slice(None, 2), array[..2]);
    assert_eq!(array.get_slice(0, 2), array[0..2]);
    assert_eq!(array.get_slice(1, array.len()), array[1..array.len()]);
    assert_eq!(array.get_slice(1, array.len() + 1), array[1..array.len()]);
    assert_eq!(array.get_slice(array.len(), array.len()),
               array[array.len()..array.len()]);
    assert_eq!(array.get_slice(array.len() + 2, array.len() + 2),
               array[array.len()..array.len()]);
}
<commit_msg>Fix tests for GetSlice<commit_after>#![crate_type="staticlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(arc_counts)]
#![feature(augmented_assignments)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(core_str_ext)]
#![feature(core_slice_ext)]
#![feature(fnbox)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(op_assign_traits)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
#![feature(collections_range)]
#![feature(old_wrapping)]
#![no_std]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

extern crate system;

use acpi::Acpi;

use alloc::boxed::Box;

use collections::string::{String, ToString};
use collections::vec::Vec;

use core::cell::UnsafeCell;
use core::{ptr, mem, usize};
use core::slice::SliceExt;

use common::event::{self, EVENT_KEY, EventOption};
use common::memory;
use common::paging::Page;
use common::time::Duration;

use drivers::pci;
use drivers::io::{Io, Pio};
use drivers::ps2::*;
use drivers::rtc::*;
use drivers::serial::*;

use env::Environment;

use graphics::display;

use scheduler::{Context, Regs, TSS};
use scheduler::context::context_switch;

use schemes::Url;
use schemes::context::*;
use schemes::debug::*;
use schemes::display::*;
use schemes::interrupt::*;
use schemes::memory::*;

use syscall::execute::execute;
use syscall::handle::*;

pub use system::externs::*;

/// Common std-like functionality
#[macro_use]
pub mod common;
#[macro_use]
pub mod macros;
/// Allocation
pub mod alloc_system;
/// ACPI
pub mod acpi;
/// Disk drivers
pub mod disk;
/// Various drivers
pub mod drivers;
/// Environment
pub mod env;
/// Filesystems
pub mod fs;
/// Various graphical methods
pub mod graphics;
/// Panic
pub mod panic;
/// Schemes
pub mod schemes;
/// Scheduling
pub mod scheduler;
/// Sync primatives
pub mod sync;
/// System calls
pub mod syscall;
/// USB input/output
pub mod usb;

pub static mut TSS_PTR: Option<&'static mut TSS> = None;
pub static mut ENV_PTR: Option<&'static mut Environment> = None;

pub fn env() -> &'static Environment {
    unsafe {
        match ENV_PTR {
            Some(&mut ref p) => p,
            None => unreachable!(),
        }
    }
}

/// Pit duration
static PIT_DURATION: Duration = Duration {
    secs: 0,
    nanos: 2250286,
};

/// Idle loop (active while idle)
unsafe fn idle_loop() {
    loop {
        asm!("cli" : : : : "intel", "volatile");

        let mut halt = true;

        for i in env().contexts.lock().iter().skip(1) {
            if i.interrupted {
                halt = false;
                break;
            }
        }

        if halt {
            asm!("sti
                  hlt"
                  :
                  :
                  :
                  : "intel", "volatile");
        } else {
            asm!("sti"
                :
                :
                :
                : "intel", "volatile");
        }

        context_switch(false);
    }
}

/// Event poll loop
fn poll_loop() {
    loop {
        env().on_poll();

        unsafe { context_switch(false) };
    }
}

/// Event loop
fn event_loop() {
    {
        let mut console = env().console.lock();
        console.instant = false;
    }

    let mut cmd = String::new();
    loop {
        loop {
            let mut console = env().console.lock();
            match env().events.lock().pop_front() {
                Some(event) => {
                    if console.draw {
                        match event.to_option() {
                            EventOption::Key(key_event) => {
                                if key_event.pressed {
                                    match key_event.scancode {
                                        event::K_F2 => {
                                            console.draw = false;
                                        }
                                        event::K_BKSP => if !cmd.is_empty() {
                                            console.write(&[8]);
                                            cmd.pop();
                                        },
                                        _ => match key_event.character {
                                            '\0' => (),
                                            '\n' => {
                                                console.command = Some(cmd.clone());

                                                cmd.clear();
                                                console.write(&[10]);
                                            }
                                            _ => {
                                                cmd.push(key_event.character);
                                                console.write(&[key_event.character as u8]);
                                            }
                                        },
                                    }
                                }
                            }
                            _ => (),
                        }
                    } else {
                        if event.code == EVENT_KEY && event.b as u8 == event::K_F1 && event.c > 0 {
                            console.draw = true;
                            console.redraw = true;
                        } else {
                            // TODO: Magical orbital hack
                        }
                    }
                }
                None => break,
            }
        }

        {
            let mut console = env().console.lock();
            console.instant = false;
            if console.draw && console.redraw {
                console.redraw = false;
                console.display.flip();
            }
        }

        unsafe { context_switch(false) };
    }
}

static BSS_TEST_ZERO: usize = 0;
static BSS_TEST_NONZERO: usize = usize::MAX;

/// Initialize kernel
unsafe fn init(tss_data: usize) {

    // Test
    assume!(true);

    // Zero BSS, this initializes statics that are set to 0
    {
        extern {
            static mut __bss_start: u8;
            static mut __bss_end: u8;
        }

        let start_ptr = &mut __bss_start;
        let end_ptr = &mut __bss_end;

        if start_ptr as *const _ as usize <= end_ptr as *const _ as usize {
            let size = end_ptr as *const _ as usize - start_ptr as *const _ as usize;
            memset(start_ptr, 0, size);
        }

        assert_eq!(BSS_TEST_ZERO, 0);
        assert_eq!(BSS_TEST_NONZERO, usize::MAX);
    }

    // Setup paging, this allows for memory allocation
    Page::init();
    memory::cluster_init();
    // Unmap first page to catch null pointer errors (after reading memory map)
    Page::new(0).unmap();

    TSS_PTR = Some(&mut *(tss_data as *mut TSS));
    ENV_PTR = Some(&mut *Box::into_raw(Environment::new()));

    match ENV_PTR {
        Some(ref mut env) => {
            env.contexts.lock().push(Context::root());
            env.console.lock().draw = true;

            debug!("Redox {} bits\n", mem::size_of::<usize>() * 8);

            if let Some(acpi) = Acpi::new() {
                env.schemes.push(UnsafeCell::new(acpi));
            }

            *(env.clock_realtime.lock()) = Rtc::new().time();

            env.schemes.push(UnsafeCell::new(Ps2::new()));
            env.schemes.push(UnsafeCell::new(Serial::new(0x3F8, 0x4)));

            pci::pci_init(env);

            env.schemes.push(UnsafeCell::new(DebugScheme::new()));
            env.schemes.push(UnsafeCell::new(box DisplayScheme));
            env.schemes.push(UnsafeCell::new(box ContextScheme));
            env.schemes.push(UnsafeCell::new(box InterruptScheme));
            env.schemes.push(UnsafeCell::new(box MemoryScheme));

            Context::spawn("kpoll".to_string(),
            box move || {
                poll_loop();
            });

            Context::spawn("kevent".to_string(),
            box move || {
                event_loop();
            });

            env.contexts.lock().enabled = true;

            Context::spawn("kinit".to_string(),
            box move || {
                {
                    let wd_c = "file:/\0";
                    do_sys_chdir(wd_c.as_ptr());

                    let stdio_c = "debug:\0";
                    do_sys_open(stdio_c.as_ptr(), 0);
                    do_sys_open(stdio_c.as_ptr(), 0);
                    do_sys_open(stdio_c.as_ptr(), 0);
                }

                execute(Url::from_str("file:/apps/init/main.bin"), Vec::new());
                debug!("INIT: Failed to execute\n");

                loop {
                    context_switch(false);
                }
            });
        },
        None => unreachable!(),
    }
}

#[cold]
#[inline(never)]
#[no_mangle]
/// Take regs for kernel calls and exceptions
pub extern "cdecl" fn kernel(interrupt: usize, mut regs: &mut Regs) {
    macro_rules! exception_inner {
        ($name:expr) => ({
            {
                let contexts = ::env().contexts.lock();
                if let Some(context) = contexts.current() {
                    debugln!("PID {}: {}", context.pid, context.name);
                }
            }

            debugln!("  INT {:X}: {}", interrupt, $name);
            debugln!("    CS:  {:08X}    IP:  {:08X}    FLG: {:08X}", regs.cs, regs.ip, regs.flags);
            debugln!("    SS:  {:08X}    SP:  {:08X}    BP:  {:08X}", regs.ss, regs.sp, regs.bp);
            debugln!("    AX:  {:08X}    BX:  {:08X}    CX:  {:08X}    DX:  {:08X}", regs.ax, regs.bx, regs.cx, regs.dx);
            debugln!("    DI:  {:08X}    SI:  {:08X}", regs.di, regs.di);

            let cr0: usize;
            let cr2: usize;
            let cr3: usize;
            let cr4: usize;
            unsafe {
                asm!("mov $0, cr0" : "=r"(cr0) : : : "intel", "volatile");
                asm!("mov $0, cr2" : "=r"(cr2) : : : "intel", "volatile");
                asm!("mov $0, cr3" : "=r"(cr3) : : : "intel", "volatile");
                asm!("mov $0, cr4" : "=r"(cr4) : : : "intel", "volatile");
            }
            debugln!("    CR0: {:08X}    CR2: {:08X}    CR3: {:08X}    CR4: {:08X}", cr0, cr2, cr3, cr4);

            let sp = regs.sp as *const u32;
            for y in -15..16 {
                debug!("    {:>3}:", y * 8 * 4);
                for x in 0..8 {
                    debug!(" {:08X}", unsafe { ptr::read(sp.offset(-(x + y * 8))) });
                }
                debug!("\n");
            }
        })
    };

    macro_rules! exception {
        ($name:expr) => ({
            exception_inner!($name);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    macro_rules! exception_error {
        ($name:expr) => ({
            let error = regs.ip;
            regs.ip = regs.cs;
            regs.cs = regs.flags;
            regs.flags = regs.sp;
            regs.sp = regs.ss;
            regs.ss = 0;
            //regs.ss = regs.error;

            exception_inner!($name);
            debugln!("    ERR: {:08X}", error);

            loop {
                do_sys_exit(usize::MAX);
            }
        })
    };

    if interrupt >= 0x20 && interrupt < 0x30 {
        if interrupt >= 0x28 {
            Pio::<u8>::new(0xA0).write(0x20);
        }

        Pio::<u8>::new(0x20).write(0x20);
    }

    //Do not catch init interrupt
    if interrupt < 0xFF {
        env().interrupts.lock()[interrupt as usize] += 1;
    }

    match interrupt {
        0x20 => {
            {
                let mut clock_monotonic = env().clock_monotonic.lock();
                *clock_monotonic = *clock_monotonic + PIT_DURATION;
            }
            {
                let mut clock_realtime = env().clock_realtime.lock();
                *clock_realtime = *clock_realtime + PIT_DURATION;
            }

            let switch = {
                let mut contexts = ::env().contexts.lock();
                if let Some(mut context) = contexts.current_mut() {
                    context.slices -= 1;
                    context.slice_total += 1;
                    context.slices == 0
                } else {
                    false
                }
            };

            if switch {
                unsafe { context_switch(true) };
            }
        }
        i @ 0x21 ... 0x2F => env().on_irq(i as u8 - 0x20),
        0x80 => if !syscall_handle(regs) {
            exception!("Unknown Syscall");
        },
        0xFF => {
            unsafe {
                init(regs.ax);
                idle_loop();
            }
        },
        0x0 => exception!("Divide by zero exception"),
        0x1 => exception!("Debug exception"),
        0x2 => exception!("Non-maskable interrupt"),
        0x3 => exception!("Breakpoint exception"),
        0x4 => exception!("Overflow exception"),
        0x5 => exception!("Bound range exceeded exception"),
        0x6 => exception!("Invalid opcode exception"),
        0x7 => exception!("Device not available exception"),
        0x8 => exception_error!("Double fault"),
        0x9 => exception!("Coprocessor Segment Overrun"), // legacy
        0xA => exception_error!("Invalid TSS exception"),
        0xB => exception_error!("Segment not present exception"),
        0xC => exception_error!("Stack-segment fault"),
        0xD => exception_error!("General protection fault"),
        0xE => exception_error!("Page fault"),
        0x10 => exception!("x87 floating-point exception"),
        0x11 => exception_error!("Alignment check exception"),
        0x12 => exception!("Machine check exception"),
        0x13 => exception!("SIMD floating-point exception"),
        0x14 => exception!("Virtualization exception"),
        0x1E => exception_error!("Security exception"),
        _ => exception!("Unknown Interrupt"),
    }
}

#[test]
fn get_slice_test() {
    use common::get_slice::GetSlice;
    let array = [1, 2, 3, 4, 5];

    assert_eq!(array.get_slice(100..100), &[]);
    assert_eq!(array.get_slice(..100), &array);
    assert_eq!(array.get_slice(1..), &array[1..]);
    assert_eq!(array.get_slice(1..2), &[2]);
    assert_eq!(array.get_slice(3..5), &[4, 5]);
    assert_eq!(array.get_slice(3..7), &[4, 5]);
    assert_eq!(array.get_slice(3..4), &[4]);
    assert_eq!(array.get_slice(4..2), &[]);
    assert_eq!(array.get_slice(4..1), &[]);
    assert_eq!(array.get_slice(20..), &[]);
    assert_eq!(array.get_slice(..), &array);
}
<|endoftext|>


<commit_before>use std::cmp::max;

use vec::Vec2;
use view::{View,SizeRequest,DimensionRequest};
use event::EventResult;
use printer::Printer;

/// Simple stack of views.
/// Only the top-most view is active and can receive input.
pub struct StackView {
    layers: Vec<Layer>,
}

struct Layer {
    view: Box<View>,
    size: Vec2,
}

impl StackView {
    /// Creates a new empty StackView
    pub fn new() -> Self {
        StackView {
            layers: Vec::new(),
        }
    }

    /// Add new view on top of the stack.
    pub fn add_layer<T: 'static + View>(&mut self, view: T) {
        self.layers.push(Layer {
            view: Box::new(view),
            size: Vec2::new(0,0),
        });
    }

    /// Remove the top-most layer.
    pub fn pop_layer(&mut self) {
        self.layers.pop();
    }
}

impl View for StackView {
    fn draw(&self, printer: &Printer) {
        match self.layers.last() {
            None => (),
            Some(v) => {
                let offset = (printer.size - v.size) / 2;
                v.view.draw(&printer.sub_printer(offset, v.size));
            },
        }
    }

    fn on_key_event(&mut self, ch: i32) -> EventResult {
        match self.layers.last_mut() {
            None => EventResult::Ignored,
            Some(v) => v.view.on_key_event(ch),
        }
    }

    fn layout(&mut self, size: Vec2) {
        let req = SizeRequest {
            w: DimensionRequest::AtMost(size.x),
            h: DimensionRequest::AtMost(size.y),
        };
        for layer in self.layers.iter_mut() {
            layer.size = layer.view.get_min_size(req);
            layer.view.layout(layer.size);
        }
    }

    fn get_min_size(&self, size: SizeRequest) -> Vec2 {
        // The min size is the max of all children's
        let mut s = Vec2::new(1,1);

        for layer in self.layers.iter() {
            let vs = layer.view.get_min_size(size);
            s.x = max(s.x, vs.x);
            s.y = max(s.y, vs.y);
        }

        s
    }
}
<commit_msg>Fix stack_view when screen is smaller than content<commit_after>use std::cmp::max;

use vec::Vec2;
use view::{View,SizeRequest,DimensionRequest};
use event::EventResult;
use printer::Printer;

/// Simple stack of views.
/// Only the top-most view is active and can receive input.
pub struct StackView {
    layers: Vec<Layer>,
}

struct Layer {
    view: Box<View>,
    size: Vec2,
}

impl StackView {
    /// Creates a new empty StackView
    pub fn new() -> Self {
        StackView {
            layers: Vec::new(),
        }
    }

    /// Add new view on top of the stack.
    pub fn add_layer<T: 'static + View>(&mut self, view: T) {
        self.layers.push(Layer {
            view: Box::new(view),
            size: Vec2::new(0,0),
        });
    }

    /// Remove the top-most layer.
    pub fn pop_layer(&mut self) {
        self.layers.pop();
    }
}

impl View for StackView {
    fn draw(&self, printer: &Printer) {
        match self.layers.last() {
            None => (),
            Some(v) => {
                // Center the view
                let view_size = Vec2::min(printer.size, v.size);
                let offset = (printer.size - view_size) / 2;
                v.view.draw(&printer.sub_printer(offset, v.size));
            },
        }
    }

    fn on_key_event(&mut self, ch: i32) -> EventResult {
        match self.layers.last_mut() {
            None => EventResult::Ignored,
            Some(v) => v.view.on_key_event(ch),
        }
    }

    fn layout(&mut self, size: Vec2) {
        let req = SizeRequest {
            w: DimensionRequest::AtMost(size.x),
            h: DimensionRequest::AtMost(size.y),
        };
        for layer in self.layers.iter_mut() {
            layer.size = layer.view.get_min_size(req);
            layer.view.layout(layer.size);
        }
    }

    fn get_min_size(&self, size: SizeRequest) -> Vec2 {
        // The min size is the max of all children's
        let mut s = Vec2::new(1,1);

        for layer in self.layers.iter() {
            let vs = layer.view.get_min_size(size);
            s.x = max(s.x, vs.x);
            s.y = max(s.y, vs.y);
        }

        s
    }
}
<|endoftext|>


<commit_before>extern crate time;

use std::thread;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};

use game;

const BOARD_AREA: u8 = 64;

const STARTING_DEPTH: u8 = 5;
const TIME_LIMIT: f64 = 1.0;

const LIGHT_STARTING_SCORE: i16 = -10_000;
const DARK_STARTING_SCORE:  i16 =  10_000;

const RANDOMNESS: i16 = 3;

const BONUS_TURN: i16 = 3;

const MOBILITY: i16 = 1;

pub fn make_move(game: &game::Game) -> (usize, usize) {

    let mut start_time = time::precise_time_s();
    let mut end_time;
    let mut depth = STARTING_DEPTH;

    let mut best_move: (usize, usize)  = find_best_move(game, depth);

    end_time = time::precise_time_s();

    while ( end_time - start_time < TIME_LIMIT ) && ( depth + 1 + game.get_turn() <= BOARD_AREA ) {
        depth += 1;
        start_time = time::precise_time_s();
        best_move = find_best_move(game, depth);
        end_time = time::precise_time_s();
    }

    best_move
}

fn find_best_move(game: &game::Game, depth: u8) -> (usize, usize) {

    if let game::Status::Running { next_player } = game.get_status() {

        if depth > 0 {

            let mut best_move: (usize, usize) = (game::BOARD_SIZE, game::BOARD_SIZE);
            let mut best_score: i16;

            let mut best_end_move: (usize, usize) = (game::BOARD_SIZE, game::BOARD_SIZE);
            let mut best_end_score: i16;

            let mut num_moves: u8 = 0;
            let mut end_game: bool = true;

            match next_player {
                game::Player::Light => {
                    best_score = LIGHT_STARTING_SCORE;
                    best_end_score = LIGHT_STARTING_SCORE;
                }
                game::Player::Dark  => {
                    best_score = DARK_STARTING_SCORE;
                    best_end_score = DARK_STARTING_SCORE;
                }
            }

            let (tx, rx): (Sender<((usize, usize), (i16, bool))>, Receiver<((usize, usize), (i16, bool))>) = mpsc::channel();

            for row in 0..game::BOARD_SIZE {
                for col in 0..game::BOARD_SIZE {

                    if game.check_move((row, col)) {
                        num_moves +=1;

                        let thread_tx = tx.clone();
                        let mut game = game.clone();

                        thread::spawn(move || {
                            thread_tx.send(( (row, col), eval(game.make_move((row, col)), depth - 1) )).unwrap();
                        });
                    }
                }
            }

            for _ in 0..num_moves {
                let (current_move, (current_score, current_end_game)) = rx.recv().ok().expect("Could not receive answer");

                match next_player {
                    game::Player::Light => {
                        if current_end_game {
                            if current_score > best_end_score {
                                best_end_score = current_score;
                                best_end_move = current_move;
                            }
                        } else {
                            if current_score + RANDOMNESS > best_score {
                                best_score = current_score;
                                best_move = current_move;
                                end_game = false;
                            }
                        }
                    }
                    game::Player::Dark  => {
                        if current_end_game {
                            if current_score < best_end_score {
                                best_end_score = current_score;
                                best_end_move = current_move;
                            }
                        } else {
                            if current_score - RANDOMNESS < best_score {
                                best_score = current_score;
                                best_move = current_move;
                                end_game = false;
                            }
                        }
                    }
                }
            }

            match next_player {
                game::Player::Light  => {
                    if best_end_score > 0 || (best_end_score == 0 && best_score < 0) || end_game {
                        return best_end_move;
                    } else {
                        return best_move;
                    }
                }
                game::Player::Dark  => {
                    if best_end_score < 0 || (best_end_score == 0 && best_score > 0) || end_game {
                        return best_end_move;
                    } else {
                        return best_move;
                    }
                }
            }

        } else {
            panic!("Depth cannot be zero");
        }

    } else {
        panic!{"Game ended, cannot make a move!"};
    }
}

fn eval(game: &game::Game, depth: u8) -> (i16, bool) {

    match game.get_status() {
        game::Status::Ended => {
            let (score_light, score_dark) = game.get_score();
            let score: i16 = (score_light as i16) - (score_dark as i16);
            return (score, true);
        }
        game::Status::Running { next_player } => {
            if depth == 0 {
                match next_player {
                    game::Player::Light => return (heavy_eval(game) + BONUS_TURN, false),
                    game::Player::Dark  => return (heavy_eval(game) - BONUS_TURN, false),
                }
            } else {
                let mut end_game: bool = true;
                let mut num_moves: i16 = 0;
                let mut best_end_score: i16;
                let mut best_score: i16;

                match next_player {

                    game::Player::Light => {
                        best_score = LIGHT_STARTING_SCORE;
                        best_end_score = LIGHT_STARTING_SCORE;

                        for row in 0..game::BOARD_SIZE {
                            for col in 0..game::BOARD_SIZE {
                                if game.check_move((row, col)) {

                                    let (current_score, current_end_game) = eval(game.clone().make_move((row, col)), depth - 1);

                                    if current_end_game {
                                        if current_score > best_end_score {
                                            best_end_score = current_score;
                                        }
                                    } else {
                                        num_moves += 1;
                                        if current_score > best_score {
                                            best_score = current_score;
                                            end_game = false;
                                        }
                                    }

                                }
                            }
                        }

                        if best_end_score > 0 || (best_end_score == 0 && best_score < 0) || end_game {
                            return (best_end_score, true);
                        } else {
                            return (best_score + MOBILITY*num_moves, false);
                        }
                    }

                    game::Player::Dark  => {
                        best_score = DARK_STARTING_SCORE;
                        best_end_score = DARK_STARTING_SCORE;

                        for row in 0..game::BOARD_SIZE {
                            for col in 0..game::BOARD_SIZE {
                                if game.check_move((row, col)) {

                                    let (current_score, current_end_game) = eval(game.clone().make_move((row, col)), depth - 1);

                                    if current_end_game {
                                        if current_score < best_end_score {
                                            best_end_score = current_score;
                                        }
                                    } else {
                                        num_moves += 1;
                                        if current_score < best_score {
                                            best_score = current_score;
                                            end_game = false;
                                        }
                                    }

                                }
                            }
                        }

                        if best_end_score < 0 || (best_end_score == 0 && best_score > 0) || end_game {
                            return (best_end_score, true);
                        } else {
                            return (best_score - MOBILITY*num_moves, false);
                        }
                    }

                }

            }
        }
    }
}

fn heavy_eval(game: &game::Game) -> i16 {
    const CORNER_BONUS: i16 = 12;
    const ODD_MALUS: i16 = 5;
    const EVEN_BONUS: i16 = 3;
    const ODD_CORNER_MALUS: i16 = 8;
    const EVEN_CORNER_BONUS: i16 = 5;
    const FIXED_BONUS: i16 = 2;

    const SIDES: [( (usize, usize), (usize, usize), (usize, usize), (usize, usize), (usize, usize), (usize, usize), (usize, usize) ); 4] = [
        ( (0,0), (0,1), (1,1), (0,2), (2,2), (1,0), (2,0) ), // NW corner
        ( (0,7), (1,7), (1,6), (2,7), (2,5), (0,6), (0,5) ), // NE corner
        ( (7,0), (6,0), (6,1), (5,0), (5,2), (7,1), (7,2) ), // SW corner
        ( (7,7), (6,7), (6,6), (5,7), (5,5), (7,6), (7,6) ), // SE corner
        ];

    let (score_light, score_dark) = game.get_score();
    let mut score: i16 = (score_light as i16) - (score_dark as i16);

    for special_cells in SIDES.iter() {

        let (corner, odd, odd_corner, even, even_corner, counter_odd, counter_even) = *special_cells;

        if let game::Cell::Taken { player } = game.get_cell(corner) {
            match player {
                game::Player::Light => {
                    score += CORNER_BONUS;
                    if let game::Cell::Taken { player: game::Player::Light } = game.get_cell(odd) {
                        score += FIXED_BONUS;
                        if let game::Cell::Taken { player: game::Player::Light } = game.get_cell(even) {
                            score += FIXED_BONUS;
                        }
                    }
                    if let game::Cell::Taken { player: game::Player::Light } = game.get_cell(counter_odd) {
                        score += FIXED_BONUS;
                        if let game::Cell::Taken { player: game::Player::Light } = game.get_cell(counter_even) {
                            score += FIXED_BONUS;
                        }
                    }
                }
                game::Player::Dark => {
                    score -= CORNER_BONUS;
                    if let game::Cell::Taken { player: game::Player::Dark } = game.get_cell(odd) {
                        score -= FIXED_BONUS;
                        if let game::Cell::Taken { player: game::Player::Dark } = game.get_cell(even) {
                            score -= FIXED_BONUS;
                        }
                    }
                    if let game::Cell::Taken { player: game::Player::Dark } = game.get_cell(counter_odd) {
                        score -= FIXED_BONUS;
                        if let game::Cell::Taken { player: game::Player::Dark } = game.get_cell(counter_even) {
                            score -= FIXED_BONUS;
                        }
                    }
                }
            }

        } else {

            if let game::Cell::Taken { player } = game.get_cell(odd) {
                match player {
                    game::Player::Light => score -= ODD_MALUS,
                    game::Player::Dark  => score += ODD_MALUS,
                }
            } else if let game::Cell::Taken { player } = game.get_cell(even) {
                match player {
                    game::Player::Light => score += EVEN_BONUS,
                    game::Player::Dark  => score -= EVEN_BONUS,
                }
            }

            if let game::Cell::Taken { player } = game.get_cell(counter_odd) {
                match player {
                    game::Player::Light => score -= ODD_MALUS,
                    game::Player::Dark  => score += ODD_MALUS,
                }
            } else if let game::Cell::Taken { player } = game.get_cell(counter_even) {
                match player {
                    game::Player::Light => score += EVEN_BONUS,
                    game::Player::Dark  => score -= EVEN_BONUS,
                }
            }

            if let game::Cell::Taken { player } = game.get_cell(odd_corner) {
                match player {
                    game::Player::Light => score -= ODD_CORNER_MALUS,
                    game::Player::Dark  => score += ODD_CORNER_MALUS,
                }

            } else if let game::Cell::Taken { player } = game.get_cell(even_corner) {
                match player {
                    game::Player::Light => score += EVEN_CORNER_BONUS,
                    game::Player::Dark  => score -= EVEN_CORNER_BONUS,
                }
            }
        }
    }

    score
}
<commit_msg>Small fixes<commit_after>extern crate time;

use std::thread;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};

use game;

const BOARD_AREA: u8 = 64;

const STARTING_DEPTH: u8 = 5;
const TIME_LIMIT: f64 = 1.0;

const LIGHT_STARTING_SCORE: i16 = -10_000;
const DARK_STARTING_SCORE:  i16 =  10_000;

const RANDOMNESS: i16 = 1;

const BONUS_TURN: i16 = 3;

const MOBILITY: i16 = 1;

pub fn make_move(game: &game::Game) -> (usize, usize) {

    let mut start_time = time::precise_time_s();
    let mut end_time;
    let mut depth = STARTING_DEPTH;

    let mut best_move: (usize, usize)  = find_best_move(game, depth);

    end_time = time::precise_time_s();

    while ( end_time - start_time < TIME_LIMIT ) && ( depth + 1 + game.get_turn() <= BOARD_AREA ) {
        depth += 1;
        start_time = time::precise_time_s();
        best_move = find_best_move(game, depth);
        end_time = time::precise_time_s();
    }

    best_move
}

fn find_best_move(game: &game::Game, depth: u8) -> (usize, usize) {

    if let game::Status::Running { next_player } = game.get_status() {

        if depth > 0 {

            let mut best_move: (usize, usize) = (game::BOARD_SIZE, game::BOARD_SIZE);
            let mut best_score: i16;

            let mut best_end_move: (usize, usize) = (game::BOARD_SIZE, game::BOARD_SIZE);
            let mut best_end_score: i16;

            let mut num_moves: u8 = 0;
            let mut end_game: bool = true;

            match next_player {
                game::Player::Light => {
                    best_score = LIGHT_STARTING_SCORE;
                    best_end_score = LIGHT_STARTING_SCORE;
                }
                game::Player::Dark  => {
                    best_score = DARK_STARTING_SCORE;
                    best_end_score = DARK_STARTING_SCORE;
                }
            }

            let (tx, rx): (Sender<((usize, usize), (i16, bool))>, Receiver<((usize, usize), (i16, bool))>) = mpsc::channel();

            for row in 0..game::BOARD_SIZE {
                for col in 0..game::BOARD_SIZE {

                    if game.check_move((row, col)) {
                        num_moves +=1;

                        let thread_tx = tx.clone();
                        let mut game = game.clone();

                        thread::spawn(move || {
                            thread_tx.send(( (row, col), eval(game.make_move((row, col)), depth - 1) )).unwrap();
                        });
                    }
                }
            }

            for _ in 0..num_moves {
                let (current_move, (current_score, current_end_game)) = rx.recv().ok().expect("Could not receive answer");

                match next_player {
                    game::Player::Light => {
                        if current_end_game {
                            if current_score > best_end_score {
                                best_end_score = current_score;
                                best_end_move = current_move;
                            }
                        } else {
                            if current_score + RANDOMNESS > best_score {
                                best_score = current_score;
                                best_move = current_move;
                                end_game = false;
                            }
                        }
                    }
                    game::Player::Dark  => {
                        if current_end_game {
                            if current_score < best_end_score {
                                best_end_score = current_score;
                                best_end_move = current_move;
                            }
                        } else {
                            if current_score - RANDOMNESS < best_score {
                                best_score = current_score;
                                best_move = current_move;
                                end_game = false;
                            }
                        }
                    }
                }
            }

            match next_player {
                game::Player::Light  => {
                    if best_end_score > 0 || (best_end_score == 0 && best_score < 0) || end_game {
                        return best_end_move;
                    } else {
                        return best_move;
                    }
                }
                game::Player::Dark  => {
                    if best_end_score < 0 || (best_end_score == 0 && best_score > 0) || end_game {
                        return best_end_move;
                    } else {
                        return best_move;
                    }
                }
            }

        } else {
            panic!("Depth cannot be zero");
        }

    } else {
        panic!{"Game ended, cannot make a move!"};
    }
}

fn eval(game: &game::Game, depth: u8) -> (i16, bool) {

    match game.get_status() {
        game::Status::Ended => return (game.get_score_diff(), true),
        game::Status::Running { next_player } => {
            if depth == 0 {
                match next_player {
                    game::Player::Light => return (heavy_eval(game) + BONUS_TURN, false),
                    game::Player::Dark  => return (heavy_eval(game) - BONUS_TURN, false),
                }
            } else {
                let mut end_game: bool = true;
                let mut num_moves: i16 = 0;
                let mut best_end_score: i16;
                let mut best_score: i16;

                match next_player {

                    game::Player::Light => {
                        best_score = LIGHT_STARTING_SCORE;
                        best_end_score = LIGHT_STARTING_SCORE;

                        for row in 0..game::BOARD_SIZE {
                            for col in 0..game::BOARD_SIZE {
                                if game.check_move((row, col)) {

                                    let (current_score, current_end_game) = eval(game.clone().make_move((row, col)), depth - 1);

                                    if current_end_game {
                                        if current_score > best_end_score {
                                            best_end_score = current_score;
                                        }
                                    } else {
                                        num_moves += 1;
                                        if current_score > best_score {
                                            best_score = current_score;
                                            end_game = false;
                                        }
                                    }

                                }
                            }
                        }

                        if best_end_score > 0 || (best_end_score == 0 && best_score < 0) || end_game {
                            return (best_end_score, true);
                        } else {
                            return (best_score + MOBILITY*num_moves, false);
                        }
                    }

                    game::Player::Dark  => {
                        best_score = DARK_STARTING_SCORE;
                        best_end_score = DARK_STARTING_SCORE;

                        for row in 0..game::BOARD_SIZE {
                            for col in 0..game::BOARD_SIZE {
                                if game.check_move((row, col)) {

                                    let (current_score, current_end_game) = eval(game.clone().make_move((row, col)), depth - 1);

                                    if current_end_game {
                                        if current_score < best_end_score {
                                            best_end_score = current_score;
                                        }
                                    } else {
                                        num_moves += 1;
                                        if current_score < best_score {
                                            best_score = current_score;
                                            end_game = false;
                                        }
                                    }

                                }
                            }
                        }

                        if best_end_score < 0 || (best_end_score == 0 && best_score > 0) || end_game {
                            return (best_end_score, true);
                        } else {
                            return (best_score - MOBILITY*num_moves, false);
                        }
                    }

                }

            }
        }
    }
}

fn heavy_eval(game: &game::Game) -> i16 {
    const CORNER_BONUS: i16 = 15;
    const ODD_MALUS: i16 = 3;
    const EVEN_BONUS: i16 = 3;
    const ODD_CORNER_MALUS: i16 = 10;
    const EVEN_CORNER_BONUS: i16 = 5;
    const FIXED_BONUS: i16 = 3;

    const SIDES: [( (usize, usize), (usize, usize), (usize, usize), (usize, usize), (usize, usize), (usize, usize), (usize, usize) ); 4] = [
        ( (0,0), (0,1), (1,1), (0,2), (2,2), (1,0), (2,0) ), // NW corner
        ( (0,7), (1,7), (1,6), (2,7), (2,5), (0,6), (0,5) ), // NE corner
        ( (7,0), (6,0), (6,1), (5,0), (5,2), (7,1), (7,2) ), // SW corner
        ( (7,7), (6,7), (6,6), (5,7), (5,5), (7,6), (7,6) ), // SE corner
        ];

    //let (score_light, score_dark) = game.get_score();
    let mut score: i16 = 0; // (score_light as i16) - (score_dark as i16);

    for special_cells in SIDES.iter() {

        let (corner, odd, odd_corner, even, even_corner, counter_odd, counter_even) = *special_cells;

        if let game::Cell::Taken { player } = game.get_cell(corner) {
            match player {
                game::Player::Light => {
                    score += CORNER_BONUS;
                    if let game::Cell::Taken { player: game::Player::Light } = game.get_cell(odd) {
                        score += FIXED_BONUS;
                        if let game::Cell::Taken { player: game::Player::Light } = game.get_cell(even) {
                            score += FIXED_BONUS;
                        }
                    }
                    if let game::Cell::Taken { player: game::Player::Light } = game.get_cell(counter_odd) {
                        score += FIXED_BONUS;
                        if let game::Cell::Taken { player: game::Player::Light } = game.get_cell(counter_even) {
                            score += FIXED_BONUS;
                        }
                    }
                }
                game::Player::Dark => {
                    score -= CORNER_BONUS;
                    if let game::Cell::Taken { player: game::Player::Dark } = game.get_cell(odd) {
                        score -= FIXED_BONUS;
                        if let game::Cell::Taken { player: game::Player::Dark } = game.get_cell(even) {
                            score -= FIXED_BONUS;
                        }
                    }
                    if let game::Cell::Taken { player: game::Player::Dark } = game.get_cell(counter_odd) {
                        score -= FIXED_BONUS;
                        if let game::Cell::Taken { player: game::Player::Dark } = game.get_cell(counter_even) {
                            score -= FIXED_BONUS;
                        }
                    }
                }
            }

        } else {

            if let game::Cell::Taken { player } = game.get_cell(odd) {
                match player {
                    game::Player::Light => score -= ODD_MALUS,
                    game::Player::Dark  => score += ODD_MALUS,
                }
            } else if let game::Cell::Taken { player } = game.get_cell(even) {
                match player {
                    game::Player::Light => score += EVEN_BONUS,
                    game::Player::Dark  => score -= EVEN_BONUS,
                }
            }

            if let game::Cell::Taken { player } = game.get_cell(counter_odd) {
                match player {
                    game::Player::Light => score -= ODD_MALUS,
                    game::Player::Dark  => score += ODD_MALUS,
                }
            } else if let game::Cell::Taken { player } = game.get_cell(counter_even) {
                match player {
                    game::Player::Light => score += EVEN_BONUS,
                    game::Player::Dark  => score -= EVEN_BONUS,
                }
            }

            if let game::Cell::Taken { player } = game.get_cell(odd_corner) {
                match player {
                    game::Player::Light => score -= ODD_CORNER_MALUS,
                    game::Player::Dark  => score += ODD_CORNER_MALUS,
                }

            } else if let game::Cell::Taken { player } = game.get_cell(even_corner) {
                match player {
                    game::Player::Light => score += EVEN_CORNER_BONUS,
                    game::Player::Dark  => score -= EVEN_CORNER_BONUS,
                }
            }
        }
    }

    score
}
<|endoftext|>


<commit_before>use std::mem;

use self::BufferedParserState::{Beginning, Middle, EndMatch, EndFail};
use self::MatchResult::{Undecided, Matched, Failed};
use self::ConstantParserState::{AtOffset, AtEndMatched, AtEndFailed};

use std::marker::PhantomData;

// ----------- Types with lifetimes -------------

// Borrowing encoding of paramaterized types from
// https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md#encoding-higher-kinded-types

pub trait TypeWithLifetime<'a> {
    type Type;
}

pub type At<'a,T> where T: TypeWithLifetime<'a> = T::Type;

pub struct Always<T> (T);

impl<'a,T> TypeWithLifetime<'a> for Always<T> {
    type Type = T;
}

pub type Unit = Always<()>;

// ----------- Types for consumers ------------

pub trait Consumer<T> where T: for<'a> TypeWithLifetime<'a> {
    fn accept<'a>(&mut self, arg: At<'a,T>);
}

struct DiscardConsumer<T> (PhantomData<T>);

impl<T> Consumer<T> for DiscardConsumer<T> where T: for<'a> TypeWithLifetime<'a> {
    fn accept<'a>(&mut self, _: At<'a,T>) {}
}

impl<T> DiscardConsumer<T> {
    fn new() -> DiscardConsumer<T> {
        DiscardConsumer(PhantomData)
    }
}

// ----------- Types for parsers ------------

// State machine transitions are:
//
// init -Undecided->  init
// init -Committed->  committed
// init -Matched(s)-> matched
// init -Failed(b)->  failed(b)
//
// committed -Committed->     committed
// committed -Matched(s)->    matched
// committed -Failed(false)-> failed(false)
//
// matched -Matched(s)-> matched
//
// failed(b) -Failed(b)-> failed(b)
//
// The Failed(b) action carries a boolean indicating if backtracking is allowed.
// Note that there is no transition . -Committed-> . -Failed(true)-> . so
// once a parser has committed, we can clean up space associated with backtracking.

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum MatchResult<T> {
    Undecided(bool),
    Matched(T),
    Failed(Option<T>),
}

pub trait Parser<S,T> where S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a> {
    // If push_to returns Undecided or Failed(true), it is side-effect-free
    // In the case where T is "list-like" (e.g. &str or &[T])
    // push_to(nil,d) is a no-op
    // push_to(a ++ b, d) is the same as push_to(a,d); push_to(b,d)
    fn push_to<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>>;
    // Resets the parser state back to its initial state
    // Returns true if there was a match.
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool;
    // Helper methods
    fn push<'a>(&mut self, value: At<'a,S>) -> MatchResult<At<'a,S>> {
        self.push_to(value, &mut DiscardConsumer::new())
    }
    fn done(&mut self) -> bool {
        self.done_to(&mut DiscardConsumer::new())
    }
    fn and_then<R>(self, other: R) -> AndThenParser<Self,R> where Self: Sized, R: Parser<S,T> {
        AndThenParser{ lhs: self, rhs: CommittedParser{ parser: other }, in_lhs: true }
    }
    fn many0(self) -> Many0Parser<Self> where Self: Sized {
        Many0Parser{ parser: self, first_time: true }
    }
}

pub trait BufferableMatcher<S,T> where S: for<'a> TypeWithLifetime<'a>, T: Parser<S,S> {
    fn buffer(self) -> T;
}

// ----------- Always commit ---------------

#[derive(Clone, Debug)]
pub struct CommittedParser<P> {
    parser: P,
}

impl<S,T,P> Parser<S,T> for CommittedParser<P> where P: Parser<S,T>, S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a>  {
    fn push_to<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        match self.parser.push_to(value, downstream) {
            Undecided(_)  => Undecided(false),
            Matched(rest) => Matched(rest),
            Failed(_)     => Failed(None),
        }
    }
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool {
        self.parser.done_to(downstream)
    }
}

// ----------- Sequencing ---------------

#[derive(Clone, Debug)]
pub struct AndThenParser<L,R> {
    lhs: L,
    rhs: CommittedParser<R>,
    in_lhs: bool,
}

impl<S,T,L,R> Parser<S,T> for AndThenParser<L,R> where L: Parser<S,T>, R: Parser<S,T>, S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a>  {
    fn push_to<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        if self.in_lhs {
            match self.lhs.push_to(value, downstream) {
                Undecided(b)  => Undecided(b),
                Matched(rest) => { self.in_lhs = false; self.lhs.done_to(downstream); self.rhs.push_to(rest, downstream) },
                Failed(rest)  => Failed(rest),
            }
        } else {
            self.rhs.push_to(value, downstream)
        }
    }
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool {
        if self.in_lhs {
            self.lhs.done_to(downstream) && self.rhs.done_to(downstream)
        } else {
            self.in_lhs = true;
            self.rhs.done_to(downstream)
        }
    }
}

// ----------- Kleene star ---------------

#[derive(Clone, Debug)]
pub struct Many0Parser<P> {
    parser: P,
    first_time: bool,
}

impl<S,T,P> Parser<S,T> for Many0Parser<P> where P: Parser<S,T>, S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a>  {
    fn push_to<'a>(&mut self, mut value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        loop { match self.parser.push_to(value, downstream) {
            Undecided(b)        => return Undecided(b & self.first_time),
            Matched(rest)       => { self.first_time = false; value = rest; },
            Failed(Some(rest))  => return Matched(rest),
            Failed(None)        => return Failed(None),
        } }
    }
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool {
        self.first_time = true;
        self.parser.done_to(downstream)
    }
}

// ----------- Matching strings -------------

pub struct Str;

impl<'a> TypeWithLifetime<'a> for Str {
    type Type = &'a str;
}

// ----------- Constant parsers -------------

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum ConstantParserState {
    AtOffset(usize),
    AtEndMatched(bool),
    AtEndFailed(bool),
}

#[derive(Clone, Debug)]
pub struct ConstantParser {
    constant: String,
    state: ConstantParserState,
}

impl Parser<Str,Unit> for ConstantParser {
    fn push_to<'a>(&mut self, string: &'a str, downstream: &mut Consumer<Unit>) -> MatchResult<&'a str> {
        match self.state {
            AtOffset(0)     if string.is_empty()                           => { Undecided(true) },
            AtOffset(index) if string == &self.constant[index..]           => { downstream.accept(()); self.state = AtEndMatched(true); Matched("") },
            AtOffset(index) if string.starts_with(&self.constant[index..]) => { downstream.accept(()); self.state = AtEndMatched(false); Matched(&string[(self.constant.len() - index)..]) },
            AtOffset(index) if self.constant[index..].starts_with(string)  => { self.state = AtOffset(index + string.len()); Undecided(false) },
            AtOffset(0)     if !string.starts_with(&self.constant[..1])    => { self.state = AtEndFailed(true); Failed(Some(string)) },
            AtOffset(_)                                                    => { self.state = AtEndFailed(false); Failed(None) },
            AtEndMatched(true)                                             => { self.state = AtEndMatched(string.is_empty()); Matched(string) },
            AtEndMatched(false)                                            => { Matched(string) },
            AtEndFailed(true)                                              => { Failed(Some(string)) },
            AtEndFailed(false)                                             => { Failed(None) },
        }
    }
    fn done_to(&mut self, _: &mut Consumer<Unit>) -> bool {
        let result = self.state == AtEndMatched(true);
        self.state = AtOffset(0);
        result
    }
}

pub fn constant(string: String) -> ConstantParser {
    ConstantParser{ constant: string, state: AtOffset(0) }
}

// If m is a Parser<Str,Unit> then m.buffer() is a Parser<Str,Str>.
// It does as little buffering as it can, but it does allocate as buffer for the case
// where the boundary marker of the input is misaligned with that of the parser.
// For example, m is matching string literals, and the input is '"abc' followed by 'def"'
// we have to buffer up '"abc'.

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
enum BufferedParserState {
    Beginning,
    Middle(String),
    EndMatch,
    EndFail(bool),
}

#[derive(Clone, Debug)]
pub struct BufferedParser<P> {
    parser: P,
    state: BufferedParserState,
}

impl<P> Parser<Str,Str> for BufferedParser<P> where P: Parser<Str,Unit> {
    fn push_to<'a>(&mut self, string: &'a str, downstream: &mut Consumer<Str>) -> MatchResult<&'a str> {
        match mem::replace(&mut self.state, EndMatch) {
            Beginning => {
                let result = self.parser.push(string);
                match result {
                    Undecided(_)    => self.state = Middle(String::from(string)),
                    Failed(Some(_)) => self.state = EndFail(true),
                    Failed(None)    => self.state = EndFail(false),
                    Matched(rest)   => downstream.accept(&string[..(string.len()-rest.len())]),
                }
                result
            },
            Middle(mut buffer) => {
                let result = self.parser.push(string);
                match result {
                    Undecided(_)    => { buffer.push_str(string); self.state = Middle(buffer); },
                    Failed(Some(_)) => { self.state = EndFail(true) },
                    Failed(None)    => { self.state = EndFail(false) },
                    Matched(rest)   => { buffer.push_str(&string[..(string.len()-rest.len())]); downstream.accept(&*buffer); },
                }
                result
            }
            EndMatch => Matched(string),
            EndFail(true) => Failed(Some(string)),
            EndFail(false) => Failed(None),
        }
    }
    fn done_to(&mut self, downstream: &mut Consumer<Str>) -> bool {
        let result = self.parser.done();
        if result { if let Middle(ref buffer) = self.state { downstream.accept(&*buffer) } }
        self.state = Beginning;
        result
    }
}

#[test]
fn test_constant() {
    let mut parser = constant(String::from("abc"));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("fred"), Failed(Some("fred")));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("alice"), Failed(None));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcdef"), Matched("def"));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abc"), Matched(""));
    assert_eq!(parser.done(), true);
    assert_eq!(parser.push("a"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push(""), Undecided(true));
    assert_eq!(parser.push("ab"), Undecided(false));
    assert_eq!(parser.push("cd"), Matched("d"));
    assert_eq!(parser.done(), false);
}

#[test]
fn test_and_then() {
    let mut parser = constant(String::from("abc")).and_then(constant(String::from("def")));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("fred"), Failed(Some("fred")));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("alice"), Failed(None));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("ab"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abc"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcd"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcfred"), Failed(None));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcdef"), Matched(""));
    assert_eq!(parser.done(), true);
    assert_eq!(parser.push("abcdefghi"), Matched("ghi"));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("a"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push(""), Undecided(true));
    assert_eq!(parser.push("ab"), Undecided(false));
    assert_eq!(parser.push("cd"), Undecided(false));
    assert_eq!(parser.push("efg"), Matched("g"));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push(""), Undecided(true));
    assert_eq!(parser.push("ab"), Undecided(false));
    assert_eq!(parser.push("cd"), Undecided(false));
    assert_eq!(parser.push("ef"), Matched(""));
    assert_eq!(parser.done(), true);
}
<commit_msg>Rewrote comments.<commit_after>use std::mem;

use self::BufferedParserState::{Beginning, Middle, EndMatch, EndFail};
use self::MatchResult::{Undecided, Matched, Failed};
use self::ConstantParserState::{AtOffset, AtEndMatched, AtEndFailed};

use std::marker::PhantomData;

// ----------- Types with lifetimes -------------

// Borrowing encoding of paramaterized types from
// https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md#encoding-higher-kinded-types

pub trait TypeWithLifetime<'a> {
    type Type;
}

pub type At<'a,T> where T: TypeWithLifetime<'a> = T::Type;

pub struct Always<T> (T);

impl<'a,T> TypeWithLifetime<'a> for Always<T> {
    type Type = T;
}

pub type Unit = Always<()>;

// ----------- Types for consumers ------------

pub trait Consumer<T> where T: for<'a> TypeWithLifetime<'a> {
    fn accept<'a>(&mut self, arg: At<'a,T>);
}

struct DiscardConsumer<T> (PhantomData<T>);

impl<T> Consumer<T> for DiscardConsumer<T> where T: for<'a> TypeWithLifetime<'a> {
    fn accept<'a>(&mut self, _: At<'a,T>) {}
}

impl<T> DiscardConsumer<T> {
    fn new() -> DiscardConsumer<T> {
        DiscardConsumer(PhantomData)
    }
}

// ----------- Types for parsers ------------

// State machine transitions are:
//
// init -Undecided(true)->  init
// init -Undecided(false)-> committed
// init -Matched(s)->       matched
// init -Failed(s)->        failed
//
// committed -Undecided(false)-> committed
// committed -Matched(s)->       matched
// committed -Failed(false)->    failed(false)
//
// matched -Matched(s)-> matched
//
// failed -Failed(s)-> failed
//
// The Failed(s) action carries a Option<T> indicating if backtracking is allowed,
// and if so, the value to backtrack with.

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum MatchResult<T> {
    Undecided(bool),
    Matched(T),
    Failed(Option<T>),
}

pub trait Parser<S,T> where S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a> {
    // If push_to returns Undecided(true) or Failed(Some(s)), it is side-effect-free
    // In the case where T is "list-like" (e.g. &str or &[T])
    // push_to(nil,d) returns Undecided(true)
    // push_to(a ++ b, d) is the same as push_to(a,d); push_to(b,d)
    fn push_to<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>>;
    // Resets the parser state back to its initial state
    // Returns true if there was a match.
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool;
    // Helper methods
    fn push<'a>(&mut self, value: At<'a,S>) -> MatchResult<At<'a,S>> {
        self.push_to(value, &mut DiscardConsumer::new())
    }
    fn done(&mut self) -> bool {
        self.done_to(&mut DiscardConsumer::new())
    }
    fn and_then<R>(self, other: R) -> AndThenParser<Self,R> where Self: Sized, R: Parser<S,T> {
        AndThenParser{ lhs: self, rhs: CommittedParser{ parser: other }, in_lhs: true }
    }
    fn many0(self) -> Many0Parser<Self> where Self: Sized {
        Many0Parser{ parser: self, first_time: true }
    }
}

pub trait BufferableMatcher<S,T> where S: for<'a> TypeWithLifetime<'a>, T: Parser<S,S> {
    fn buffer(self) -> T;
}

// ----------- Always commit ---------------

#[derive(Clone, Debug)]
pub struct CommittedParser<P> {
    parser: P,
}

impl<S,T,P> Parser<S,T> for CommittedParser<P> where P: Parser<S,T>, S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a>  {
    fn push_to<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        match self.parser.push_to(value, downstream) {
            Undecided(_)  => Undecided(false),
            Matched(rest) => Matched(rest),
            Failed(_)     => Failed(None),
        }
    }
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool {
        self.parser.done_to(downstream)
    }
}

// ----------- Sequencing ---------------

#[derive(Clone, Debug)]
pub struct AndThenParser<L,R> {
    lhs: L,
    rhs: CommittedParser<R>,
    in_lhs: bool,
}

impl<S,T,L,R> Parser<S,T> for AndThenParser<L,R> where L: Parser<S,T>, R: Parser<S,T>, S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a>  {
    fn push_to<'a>(&mut self, value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        if self.in_lhs {
            match self.lhs.push_to(value, downstream) {
                Undecided(b)  => Undecided(b),
                Matched(rest) => { self.in_lhs = false; self.lhs.done_to(downstream); self.rhs.push_to(rest, downstream) },
                Failed(rest)  => Failed(rest),
            }
        } else {
            self.rhs.push_to(value, downstream)
        }
    }
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool {
        if self.in_lhs {
            self.lhs.done_to(downstream) && self.rhs.done_to(downstream)
        } else {
            self.in_lhs = true;
            self.rhs.done_to(downstream)
        }
    }
}

// ----------- Kleene star ---------------

#[derive(Clone, Debug)]
pub struct Many0Parser<P> {
    parser: P,
    first_time: bool,
}

impl<S,T,P> Parser<S,T> for Many0Parser<P> where P: Parser<S,T>, S: for<'a> TypeWithLifetime<'a>, T: for<'a> TypeWithLifetime<'a>  {
    fn push_to<'a>(&mut self, mut value: At<'a,S>, downstream: &mut Consumer<T>) -> MatchResult<At<'a,S>> {
        loop { match self.parser.push_to(value, downstream) {
            Undecided(b)        => return Undecided(b & self.first_time),
            Matched(rest)       => { self.first_time = false; value = rest; },
            Failed(Some(rest))  => return Matched(rest),
            Failed(None)        => return Failed(None),
        } }
    }
    fn done_to(&mut self, downstream: &mut Consumer<T>) -> bool {
        self.first_time = true;
        self.parser.done_to(downstream)
    }
}

// ----------- Matching strings -------------

pub struct Str;

impl<'a> TypeWithLifetime<'a> for Str {
    type Type = &'a str;
}

// ----------- Constant parsers -------------

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub enum ConstantParserState {
    AtOffset(usize),
    AtEndMatched(bool),
    AtEndFailed(bool),
}

#[derive(Clone, Debug)]
pub struct ConstantParser {
    constant: String,
    state: ConstantParserState,
}

impl Parser<Str,Unit> for ConstantParser {
    fn push_to<'a>(&mut self, string: &'a str, downstream: &mut Consumer<Unit>) -> MatchResult<&'a str> {
        match self.state {
            AtOffset(0)     if string.is_empty()                           => { Undecided(true) },
            AtOffset(index) if string == &self.constant[index..]           => { downstream.accept(()); self.state = AtEndMatched(true); Matched("") },
            AtOffset(index) if string.starts_with(&self.constant[index..]) => { downstream.accept(()); self.state = AtEndMatched(false); Matched(&string[(self.constant.len() - index)..]) },
            AtOffset(index) if self.constant[index..].starts_with(string)  => { self.state = AtOffset(index + string.len()); Undecided(false) },
            AtOffset(0)     if !string.starts_with(&self.constant[..1])    => { self.state = AtEndFailed(true); Failed(Some(string)) },
            AtOffset(_)                                                    => { self.state = AtEndFailed(false); Failed(None) },
            AtEndMatched(true)                                             => { self.state = AtEndMatched(string.is_empty()); Matched(string) },
            AtEndMatched(false)                                            => { Matched(string) },
            AtEndFailed(true)                                              => { Failed(Some(string)) },
            AtEndFailed(false)                                             => { Failed(None) },
        }
    }
    fn done_to(&mut self, _: &mut Consumer<Unit>) -> bool {
        let result = self.state == AtEndMatched(true);
        self.state = AtOffset(0);
        result
    }
}

pub fn constant(string: String) -> ConstantParser {
    ConstantParser{ constant: string, state: AtOffset(0) }
}

// If m is a Parser<Str,Unit> then m.buffer() is a Parser<Str,Str>.
// It does as little buffering as it can, but it does allocate as buffer for the case
// where the boundary marker of the input is misaligned with that of the parser.
// For example, m is matching string literals, and the input is '"abc' followed by 'def"'
// we have to buffer up '"abc'.

#[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
enum BufferedParserState {
    Beginning,
    Middle(String),
    EndMatch,
    EndFail(bool),
}

#[derive(Clone, Debug)]
pub struct BufferedParser<P> {
    parser: P,
    state: BufferedParserState,
}

impl<P> Parser<Str,Str> for BufferedParser<P> where P: Parser<Str,Unit> {
    fn push_to<'a>(&mut self, string: &'a str, downstream: &mut Consumer<Str>) -> MatchResult<&'a str> {
        match mem::replace(&mut self.state, EndMatch) {
            Beginning => {
                let result = self.parser.push(string);
                match result {
                    Undecided(_)    => self.state = Middle(String::from(string)),
                    Failed(Some(_)) => self.state = EndFail(true),
                    Failed(None)    => self.state = EndFail(false),
                    Matched(rest)   => downstream.accept(&string[..(string.len()-rest.len())]),
                }
                result
            },
            Middle(mut buffer) => {
                let result = self.parser.push(string);
                match result {
                    Undecided(_)    => { buffer.push_str(string); self.state = Middle(buffer); },
                    Failed(Some(_)) => { self.state = EndFail(true) },
                    Failed(None)    => { self.state = EndFail(false) },
                    Matched(rest)   => { buffer.push_str(&string[..(string.len()-rest.len())]); downstream.accept(&*buffer); },
                }
                result
            }
            EndMatch => Matched(string),
            EndFail(true) => Failed(Some(string)),
            EndFail(false) => Failed(None),
        }
    }
    fn done_to(&mut self, downstream: &mut Consumer<Str>) -> bool {
        let result = self.parser.done();
        if result { if let Middle(ref buffer) = self.state { downstream.accept(&*buffer) } }
        self.state = Beginning;
        result
    }
}

#[test]
fn test_constant() {
    let mut parser = constant(String::from("abc"));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("fred"), Failed(Some("fred")));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("alice"), Failed(None));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcdef"), Matched("def"));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abc"), Matched(""));
    assert_eq!(parser.done(), true);
    assert_eq!(parser.push("a"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push(""), Undecided(true));
    assert_eq!(parser.push("ab"), Undecided(false));
    assert_eq!(parser.push("cd"), Matched("d"));
    assert_eq!(parser.done(), false);
}

#[test]
fn test_and_then() {
    let mut parser = constant(String::from("abc")).and_then(constant(String::from("def")));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("fred"), Failed(Some("fred")));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("alice"), Failed(None));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("ab"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abc"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcd"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcfred"), Failed(None));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("abcdef"), Matched(""));
    assert_eq!(parser.done(), true);
    assert_eq!(parser.push("abcdefghi"), Matched("ghi"));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push("a"), Undecided(false));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push(""), Undecided(true));
    assert_eq!(parser.push("ab"), Undecided(false));
    assert_eq!(parser.push("cd"), Undecided(false));
    assert_eq!(parser.push("efg"), Matched("g"));
    assert_eq!(parser.done(), false);
    assert_eq!(parser.push(""), Undecided(true));
    assert_eq!(parser.push("ab"), Undecided(false));
    assert_eq!(parser.push("cd"), Undecided(false));
    assert_eq!(parser.push("ef"), Matched(""));
    assert_eq!(parser.done(), true);
}
<|endoftext|>