<commit_before>//! A process-wide libuv event loop for library use.

export get;

use ll = uv_ll;
use iotask = uv_iotask;
use get_gl = get;
use iotask::{IoTask, spawn_iotask};
use private::{chan_from_global_ptr, weaken_task};
use comm = core::comm;
use comm::{Port, Chan, select2, listen};
use task::TaskBuilder;
use either::{Left, Right};

extern mod rustrt {
    fn rust_uv_get_kernel_global_chan_ptr() -> *libc::uintptr_t;
}

/**
 * Race-free helper to get access to a global task where a libuv
 * loop is running.
 *
 * Use `uv::hl::interact` to do operations against the global
 * loop that this function returns.
 *
 * # Return
 *
 * * A `hl::high_level_loop` that encapsulates communication with the global
 * loop.
 */
fn get() -> IoTask {
    return get_monitor_task_gl();
}

#[doc(hidden)]
fn get_monitor_task_gl() -> IoTask unsafe {

    let monitor_loop_chan_ptr = rustrt::rust_uv_get_kernel_global_chan_ptr();

    debug!("ENTERING global_loop::get() loop chan: %?",
           monitor_loop_chan_ptr);

    debug!("before priv::chan_from_global_ptr");
    type MonChan = Chan<IoTask>;

    let monitor_ch =
        do chan_from_global_ptr::<MonChan>(monitor_loop_chan_ptr,
                                           || {
                                                task::task().sched_mode
                                                (task::SingleThreaded)
                                                .unlinked()
                                           }) |msg_po| unsafe {
        debug!("global monitor task starting");

        // As a weak task the runtime will notify us when to exit
        do weaken_task() |weak_exit_po| {
            debug!("global monitor task is now weak");
            let hl_loop = spawn_loop();
            loop {
                debug!("in outer_loop...");
                match select2(weak_exit_po, msg_po) {
                  Left(weak_exit) => {
                    // all normal tasks have ended, tell the
                    // libuv loop to tear_down, then exit
                    debug!("weak_exit_po recv'd msg: %?", weak_exit);
                    iotask::exit(hl_loop);
                    break;
                  }
                  Right(fetch_ch) => {
                    debug!("hl_loop req recv'd: %?", fetch_ch);
                    fetch_ch.send(hl_loop);
                  }
                }
            }
            debug!("global monitor task is leaving weakend state");
        };
        debug!("global monitor task exiting");
    };

    // once we have a chan to the monitor loop, we ask it for
    // the libuv loop's async handle
    do listen |fetch_ch| {
        monitor_ch.send(fetch_ch);
        fetch_ch.recv()
    }
}

fn spawn_loop() -> IoTask {
    let builder = do task::task().add_wrapper |task_body| {
        fn~(move task_body) {
            // The I/O loop task also needs to be weak so it doesn't keep
            // the runtime alive
            unsafe {
                do weaken_task |weak_exit_po| {
                    debug!("global libuv task is now weak %?", weak_exit_po);
                    task_body();

                    // We don't wait for the exit message on weak_exit_po
                    // because the monitor task will tell the uv loop when to
                    // exit

                    debug!("global libuv task is leaving weakened state");
                }
            }
        }
    };
    spawn_iotask(move builder)
}

#[cfg(test)]
mod test {
    extern fn simple_timer_close_cb(timer_ptr: *ll::uv_timer_t) unsafe {
        let exit_ch_ptr = ll::get_data_for_uv_handle(
            timer_ptr as *libc::c_void) as *comm::Chan<bool>;
        let exit_ch = *exit_ch_ptr;
        core::comm::send(exit_ch, true);
        log(debug, fmt!("EXIT_CH_PTR simple_timer_close_cb exit_ch_ptr: %?",
                       exit_ch_ptr));
    }
    extern fn simple_timer_cb(timer_ptr: *ll::uv_timer_t,
                             _status: libc::c_int) unsafe {
        log(debug, ~"in simple timer cb");
        ll::timer_stop(timer_ptr);
        let hl_loop = get_gl();
        do iotask::interact(hl_loop) |_loop_ptr| unsafe {
            log(debug, ~"closing timer");
            ll::close(timer_ptr, simple_timer_close_cb);
            log(debug, ~"about to deref exit_ch_ptr");
            log(debug, ~"after msg sent on deref'd exit_ch");
        };
        log(debug, ~"exiting simple timer cb");
    }

    fn impl_uv_hl_simple_timer(iotask: IoTask) unsafe {
        let exit_po = core::comm::Port::<bool>();
        let exit_ch = core::comm::Chan(exit_po);
        let exit_ch_ptr = ptr::addr_of(exit_ch);
        log(debug, fmt!("EXIT_CH_PTR newly created exit_ch_ptr: %?",
                       exit_ch_ptr));
        let timer_handle = ll::timer_t();
        let timer_ptr = ptr::addr_of(timer_handle);
        do iotask::interact(iotask) |loop_ptr| unsafe {
            log(debug, ~"user code inside interact loop!!!");
            let init_status = ll::timer_init(loop_ptr, timer_ptr);
            if(init_status == 0i32) {
                ll::set_data_for_uv_handle(
                    timer_ptr as *libc::c_void,
                    exit_ch_ptr as *libc::c_void);
                let start_status = ll::timer_start(timer_ptr, simple_timer_cb,
                                                   1u, 0u);
                if(start_status == 0i32) {
                }
                else {
                    fail ~"failure on ll::timer_start()";
                }
            }
            else {
                fail ~"failure on ll::timer_init()";
            }
        };
        core::comm::recv(exit_po);
        log(debug, ~"global_loop timer test: msg recv on exit_po, done..");
    }

    #[test]
    fn test_gl_uv_global_loop_high_level_global_timer() unsafe {
        let hl_loop = get_gl();
        let exit_po = comm::Port::<()>();
        let exit_ch = comm::Chan(exit_po);
        task::spawn_sched(task::ManualThreads(1u), || {
            impl_uv_hl_simple_timer(hl_loop);
            core::comm::send(exit_ch, ());
        });
        impl_uv_hl_simple_timer(hl_loop);
        core::comm::recv(exit_po);
    }

    // keeping this test ignored until some kind of stress-test-harness
    // is set up for the build bots
    #[test]
    #[ignore]
    fn test_stress_gl_uv_global_loop_high_level_global_timer() unsafe {
        let hl_loop = get_gl();
        let exit_po = core::comm::Port::<()>();
        let exit_ch = core::comm::Chan(exit_po);
        let cycles = 5000u;
        for iter::repeat(cycles) {
            task::spawn_sched(task::ManualThreads(1u), || {
                impl_uv_hl_simple_timer(hl_loop);
                core::comm::send(exit_ch, ());
            });
        };
        for iter::repeat(cycles) {
            core::comm::recv(exit_po);
        };
        log(debug, ~"test_stress_gl_uv_global_loop_high_level_global_timer"+
            ~" exiting sucessfully!");
    }
}
<commit_msg>std: Demode uv::global_loop<commit_after>//! A process-wide libuv event loop for library use.

#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

export get;

use ll = uv_ll;
use iotask = uv_iotask;
use get_gl = get;
use iotask::{IoTask, spawn_iotask};
use private::{chan_from_global_ptr, weaken_task};
use comm = core::comm;
use comm::{Port, Chan, select2, listen};
use task::TaskBuilder;
use either::{Left, Right};

extern mod rustrt {
    fn rust_uv_get_kernel_global_chan_ptr() -> *libc::uintptr_t;
}

/**
 * Race-free helper to get access to a global task where a libuv
 * loop is running.
 *
 * Use `uv::hl::interact` to do operations against the global
 * loop that this function returns.
 *
 * # Return
 *
 * * A `hl::high_level_loop` that encapsulates communication with the global
 * loop.
 */
fn get() -> IoTask {
    return get_monitor_task_gl();
}

#[doc(hidden)]
fn get_monitor_task_gl() -> IoTask unsafe {

    let monitor_loop_chan_ptr = rustrt::rust_uv_get_kernel_global_chan_ptr();

    debug!("ENTERING global_loop::get() loop chan: %?",
           monitor_loop_chan_ptr);

    debug!("before priv::chan_from_global_ptr");
    type MonChan = Chan<IoTask>;

    let monitor_ch =
        do chan_from_global_ptr::<MonChan>(monitor_loop_chan_ptr,
                                           || {
                                                task::task().sched_mode
                                                (task::SingleThreaded)
                                                .unlinked()
                                           }) |msg_po| unsafe {
        debug!("global monitor task starting");

        // As a weak task the runtime will notify us when to exit
        do weaken_task() |weak_exit_po| {
            debug!("global monitor task is now weak");
            let hl_loop = spawn_loop();
            loop {
                debug!("in outer_loop...");
                match select2(weak_exit_po, msg_po) {
                  Left(weak_exit) => {
                    // all normal tasks have ended, tell the
                    // libuv loop to tear_down, then exit
                    debug!("weak_exit_po recv'd msg: %?", weak_exit);
                    iotask::exit(hl_loop);
                    break;
                  }
                  Right(fetch_ch) => {
                    debug!("hl_loop req recv'd: %?", fetch_ch);
                    fetch_ch.send(hl_loop);
                  }
                }
            }
            debug!("global monitor task is leaving weakend state");
        };
        debug!("global monitor task exiting");
    };

    // once we have a chan to the monitor loop, we ask it for
    // the libuv loop's async handle
    do listen |fetch_ch| {
        monitor_ch.send(fetch_ch);
        fetch_ch.recv()
    }
}

fn spawn_loop() -> IoTask {
    let builder = do task::task().add_wrapper |task_body| {
        fn~(move task_body) {
            // The I/O loop task also needs to be weak so it doesn't keep
            // the runtime alive
            unsafe {
                do weaken_task |weak_exit_po| {
                    debug!("global libuv task is now weak %?", weak_exit_po);
                    task_body();

                    // We don't wait for the exit message on weak_exit_po
                    // because the monitor task will tell the uv loop when to
                    // exit

                    debug!("global libuv task is leaving weakened state");
                }
            }
        }
    };
    spawn_iotask(move builder)
}

#[cfg(test)]
mod test {
    extern fn simple_timer_close_cb(timer_ptr: *ll::uv_timer_t) unsafe {
        let exit_ch_ptr = ll::get_data_for_uv_handle(
            timer_ptr as *libc::c_void) as *comm::Chan<bool>;
        let exit_ch = *exit_ch_ptr;
        core::comm::send(exit_ch, true);
        log(debug, fmt!("EXIT_CH_PTR simple_timer_close_cb exit_ch_ptr: %?",
                       exit_ch_ptr));
    }
    extern fn simple_timer_cb(timer_ptr: *ll::uv_timer_t,
                             _status: libc::c_int) unsafe {
        log(debug, ~"in simple timer cb");
        ll::timer_stop(timer_ptr);
        let hl_loop = get_gl();
        do iotask::interact(hl_loop) |_loop_ptr| unsafe {
            log(debug, ~"closing timer");
            ll::close(timer_ptr, simple_timer_close_cb);
            log(debug, ~"about to deref exit_ch_ptr");
            log(debug, ~"after msg sent on deref'd exit_ch");
        };
        log(debug, ~"exiting simple timer cb");
    }

    fn impl_uv_hl_simple_timer(iotask: IoTask) unsafe {
        let exit_po = core::comm::Port::<bool>();
        let exit_ch = core::comm::Chan(exit_po);
        let exit_ch_ptr = ptr::addr_of(exit_ch);
        log(debug, fmt!("EXIT_CH_PTR newly created exit_ch_ptr: %?",
                       exit_ch_ptr));
        let timer_handle = ll::timer_t();
        let timer_ptr = ptr::addr_of(timer_handle);
        do iotask::interact(iotask) |loop_ptr| unsafe {
            log(debug, ~"user code inside interact loop!!!");
            let init_status = ll::timer_init(loop_ptr, timer_ptr);
            if(init_status == 0i32) {
                ll::set_data_for_uv_handle(
                    timer_ptr as *libc::c_void,
                    exit_ch_ptr as *libc::c_void);
                let start_status = ll::timer_start(timer_ptr, simple_timer_cb,
                                                   1u, 0u);
                if(start_status == 0i32) {
                }
                else {
                    fail ~"failure on ll::timer_start()";
                }
            }
            else {
                fail ~"failure on ll::timer_init()";
            }
        };
        core::comm::recv(exit_po);
        log(debug, ~"global_loop timer test: msg recv on exit_po, done..");
    }

    #[test]
    fn test_gl_uv_global_loop_high_level_global_timer() unsafe {
        let hl_loop = get_gl();
        let exit_po = comm::Port::<()>();
        let exit_ch = comm::Chan(exit_po);
        task::spawn_sched(task::ManualThreads(1u), || {
            impl_uv_hl_simple_timer(hl_loop);
            core::comm::send(exit_ch, ());
        });
        impl_uv_hl_simple_timer(hl_loop);
        core::comm::recv(exit_po);
    }

    // keeping this test ignored until some kind of stress-test-harness
    // is set up for the build bots
    #[test]
    #[ignore]
    fn test_stress_gl_uv_global_loop_high_level_global_timer() unsafe {
        let hl_loop = get_gl();
        let exit_po = core::comm::Port::<()>();
        let exit_ch = core::comm::Chan(exit_po);
        let cycles = 5000u;
        for iter::repeat(cycles) {
            task::spawn_sched(task::ManualThreads(1u), || {
                impl_uv_hl_simple_timer(hl_loop);
                core::comm::send(exit_ch, ());
            });
        };
        for iter::repeat(cycles) {
            core::comm::recv(exit_po);
        };
        log(debug, ~"test_stress_gl_uv_global_loop_high_level_global_timer"+
            ~" exiting sucessfully!");
    }
}
<|endoftext|>


<commit_before>//! Scheduling primitives for Uni.rs.

use alloc::boxed::Box;

use intrusive::link::Link;
use intrusive::list::{Node, Owner};

use self::stack::Stack;

mod stack;
mod context;
mod scheduler;

const DEFAULT_STACK_SIZE: usize = 8192;

pub struct Thread {
    t_impl: Box<ThreadImpl>,
}

impl Thread {
    pub fn spawn<F>(fun: F) -> Thread where F: Fn() -> () {
        Builder::new().spawn(fun)
    }
}

pub struct Builder {
    stack_size: usize,
}

impl Builder {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn stack_size(mut self, stack_size: usize) -> Builder {
        self.stack_size = stack_size;
        self
    }

    pub fn spawn<F>(self, _fun: F) -> Thread where F: Fn() -> () {
        let thread_impl = Box::new(ThreadImpl::new(self.stack_size));

        Thread {
            t_impl: thread_impl,
        }
    }
}

impl Default for Builder {
    fn default() -> Self {
        Builder {
            stack_size: DEFAULT_STACK_SIZE,
        }
    }
}

struct ThreadImpl {
    // On Drop stack is released
    #[allow(dead_code)]
    stack: Stack,
    prev: Link<ThreadImpl>,
    next: Link<ThreadImpl>,
}

impl ThreadImpl {
    pub fn new(stack_size: usize) -> Self {
        let mut stack = unsafe { Stack::new(stack_size) };

        if stack.is_null() {
            panic!("Cannot allocate a stack (size: {}) for a new thread",
                   stack_size);
        }

        ThreadImpl {
            stack: stack,
            prev: Link::none(),
            next: Link::none(),
        }
    }
}

impl Node for ThreadImpl {
    #[inline]
    fn prev(&self) -> &Link<Self> {
        &self.prev
    }

    #[inline]
    fn next(&self) -> &Link<Self> {
        &self.next
    }

    #[inline]
    fn prev_mut(&mut self) -> &mut Link<Self> {
        &mut self.prev
    }

    #[inline]
    fn next_mut(&mut self) -> &mut Link<Self> {
        &mut self.prev
    }
}

// This trait cannot be implemented for Box in libintrusive as it must not
// depend on rust's liballoc
type ThreadImplBox = Box<ThreadImpl>;

impl Owner<ThreadImpl> for ThreadImplBox {
    #[inline]
    fn get(&self) -> &ThreadImpl {
        &**self
    }

    #[inline]
    fn get_mut(&mut self) -> &mut ThreadImpl {
        &mut **self
    }

    #[inline]
    fn take(self) {
        Box::into_raw(self);
    }

    unsafe fn from_raw_ptr(ptr: *mut ThreadImpl) -> Self {
        Box::from_raw(ptr)
    }
}
<commit_msg>thread: ThreadImpl now contains a context<commit_after>//! Scheduling primitives for Uni.rs.

use alloc::boxed::{Box, FnBox};

use intrusive::link::Link;
use intrusive::list::{Node, Owner};

use self::stack::Stack;
use self::context::Context;

mod stack;
mod context;
mod scheduler;

const DEFAULT_STACK_SIZE: usize = 8192;

pub struct Thread {
    t_impl: Box<ThreadImpl>,
}

impl Thread {
    pub fn spawn<F>(fun: F) -> Thread where F: Fn() -> () {
        Builder::new().spawn(fun)
    }
}

pub struct Builder {
    stack_size: usize,
}

impl Builder {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn stack_size(mut self, stack_size: usize) -> Builder {
        self.stack_size = stack_size;
        self
    }

    pub fn spawn<F>(self, fun: F) -> Thread where F: Fn() -> () {
        let thread_impl = Box::new(ThreadImpl::new(fun, self.stack_size));

        Thread {
            t_impl: thread_impl,
        }
    }
}

impl Default for Builder {
    fn default() -> Self {
        Builder {
            stack_size: DEFAULT_STACK_SIZE,
        }
    }
}

struct ThreadImpl {
    context: Context,
    // On Drop stack is released
    #[allow(dead_code)]
    stack: Stack,
    prev: Link<ThreadImpl>,
    next: Link<ThreadImpl>,
}

impl ThreadImpl {
    pub fn new<F>(fun: F, stack_size: usize) -> Self where F: Fn() -> () {
        let mut stack = unsafe { Stack::new(stack_size) };

        if stack.is_null() {
            panic!("Cannot allocate a stack (size: {}) for a new thread",
                   stack_size);
        }

        ThreadImpl {
            context: unsafe { Context::new(thread_wrapper, fun, &mut stack) },
            stack: stack,
            prev: Link::none(),
            next: Link::none(),
        }
    }
}

extern "C" fn thread_wrapper(f: *mut u8) -> ! {
    {
        let boxed_fn: Box<Box<FnBox()>> = unsafe {
            Box::from_raw(f as *mut Box<FnBox()>)
        };

        boxed_fn();
    }

    unimplemented!();
}

impl Node for ThreadImpl {
    #[inline]
    fn prev(&self) -> &Link<Self> {
        &self.prev
    }

    #[inline]
    fn next(&self) -> &Link<Self> {
        &self.next
    }

    #[inline]
    fn prev_mut(&mut self) -> &mut Link<Self> {
        &mut self.prev
    }

    #[inline]
    fn next_mut(&mut self) -> &mut Link<Self> {
        &mut self.prev
    }
}

// This trait cannot be implemented for Box in libintrusive as it must not
// depend on rust's liballoc
type ThreadImplBox = Box<ThreadImpl>;

impl Owner<ThreadImpl> for ThreadImplBox {
    #[inline]
    fn get(&self) -> &ThreadImpl {
        &**self
    }

    #[inline]
    fn get_mut(&mut self) -> &mut ThreadImpl {
        &mut **self
    }

    #[inline]
    fn take(self) {
        Box::into_raw(self);
    }

    unsafe fn from_raw_ptr(ptr: *mut ThreadImpl) -> Self {
        Box::from_raw(ptr)
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS};
use super::{AxialType, DefaultFloat, Vector2f};
use math::cgmath::{VectorSpace, Zero};
use std::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Rem,
               RemAssign, Sub, SubAssign};
use math::cgmath::prelude::{Array, MetricSpace};
use std::cmp;

/// A 2-dimensional vector in axial coordinates. See [here][hex-blog] for more
/// information.
///
/// [hex-blog]: http://www.redblobgames.com/grids/hexagons/#coordinates
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C, packed)]
pub struct AxialVector {
    pub q: AxialType,
    pub r: AxialType,
}

// TODO: implement cgmath::Zero
// TODO: implement cgmath::Array
// TODO: implement cgmath::MatricSpace
// TODO: implement cgmath::VectorSpace
// TODO: implement cgmath::InnerSpace
// TODO: implement ops::{ ... }
// TODO: Add `unit_q()` and `unit_r()` (see `Vector2::unit_x()` for reference)
// For all of the above, see
// http://bjz.github.io/cgmath/cgmath/struct.Vector2.html
//

impl AxialVector {
    pub fn new(q: AxialType, r: AxialType) -> Self {
        AxialVector { q: q, r: r }
    }

    /// Returns the position of the hexagons center in the standard coordinate
    /// system using `world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS}`.
    pub fn to_real(&self) -> Vector2f {
        Vector2f {
            x: ((2 * self.q + self.r) as DefaultFloat) * HEX_INNER_RADIUS,
            y: (self.r as DefaultFloat) * (3.0 / 2.0) * HEX_OUTER_RADIUS,
        }
    }

    /// Returns the `s` component of corresponding cube coordinates. In cube
    /// coordinates 'q + r + s = 0', so saving `s` is redundant and can be
    /// calculated on the fly when needed.
    pub fn s(&self) -> AxialType {
        -self.q - self.r
    }

    pub fn unit_q() -> AxialVector {
        AxialVector { q: 1, r: 0 }
    }

    pub fn unit_r() -> AxialVector {
        AxialVector { q: 0, r: 1 }
    }
}

impl fmt::Debug for AxialVector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("")
            .field(&self.q)
            .field(&self.r)
            .finish()
    }
}

// ********************* Basic Arithmetic (OPS) *********************

impl Neg for AxialVector {
    type Output = AxialVector;

    fn neg(self) -> Self::Output {
        AxialVector {
            q: -self.q,
            r: -self.r,
        }
    }
}

impl Add<AxialVector> for AxialVector {
    type Output = AxialVector;

    fn add(self, arg2: AxialVector) -> AxialVector {
        AxialVector {
            r: self.r + arg2.r,
            q: self.q + arg2.q,
        }
    }
}

impl AddAssign<AxialVector> for AxialVector {
    fn add_assign(&mut self, arg2: AxialVector) {
        self.r += arg2.r;
        self.q += arg2.q;

    }
}

impl Sub<AxialVector> for AxialVector {
    type Output = AxialVector;

    fn sub(self, arg2: AxialVector) -> AxialVector {
        AxialVector {
            r: self.r - arg2.r,
            q: self.q - arg2.q,
        }
    }
}

impl SubAssign<AxialVector> for AxialVector {
    fn sub_assign(&mut self, arg2: AxialVector) {
        self.r -= arg2.r;
        self.q -= arg2.q;

    }
}

impl Mul<AxialType> for AxialVector {
    type Output = AxialVector;

    fn mul(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r * arg2,
            q: self.q * arg2,
        }
    }
}

impl MulAssign<AxialType> for AxialVector {
    fn mul_assign(&mut self, arg2: AxialType) {
        self.r *= arg2;
        self.q *= arg2;

    }
}

impl Div<AxialType> for AxialVector {
    type Output = AxialVector;

    fn div(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r / arg2,
            q: self.q / arg2,
        }
    }
}

impl DivAssign<AxialType> for AxialVector {
    fn div_assign(&mut self, arg2: AxialType) {
        self.r /= arg2;
        self.q /= arg2;

    }
}

impl Rem<AxialType> for AxialVector {
    type Output = AxialVector;

    fn rem(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r % arg2,
            q: self.q % arg2,
        }
    }
}

impl RemAssign<AxialType> for AxialVector {
    fn rem_assign(&mut self, arg2: AxialType) {
        self.r %= arg2;
        self.q %= arg2;

    }
}

// ************ Metric Space ************

impl MetricSpace for AxialVector {
    type Metric = DefaultFloat;

    fn distance(self, other: AxialVector) -> DefaultFloat {
        (self.distance2(other)).sqrt()
    }

    fn distance2(self, other: AxialVector) -> DefaultFloat {
        ((self.q - other.q).pow(2) + (self.r - other.r).pow(2)) as DefaultFloat
    }
}

// ************ Vector Space ************

impl VectorSpace for AxialVector {
    type Scalar = AxialType;
}

// ************** Zero ****************

impl Zero for AxialVector {
    fn zero() -> AxialVector {
        AxialVector { q: 0, r: 0 }
    }

    fn is_zero(&self) -> bool {
        self.q == 0 && self.r == 0
    }
}

// *************** Array & Index *******************

impl Array for AxialVector {
    type Element = AxialType;

    fn from_value(value: Self::Element) -> Self {
        AxialVector::new(value, value)
    }

    fn sum(self) -> Self::Element {
        self.q + self.r
    }

    fn product(self) -> Self::Element {
        self.q * self.r
    }

    fn min(self) -> Self::Element {
        cmp::min(self.q, self.r)
    }

    fn max(self) -> Self::Element {
        cmp::max(self.q, self.r)
    }
}

impl Index<usize> for AxialVector {
    type Output = AxialType;

    fn index(&self, index: usize) -> &Self::Output {
        let ret: &AxialType = match index {
            0 => &self.q,
            1 => &self.r,
            _ => panic!("Illegal Index Argument: was {:?}", index),
        };
        ret
    }
}

impl IndexMut<usize> for AxialVector {
    fn index_mut(&mut self, index: usize) -> &mut AxialType {
        match index {
            0 => &mut self.q,
            1 => &mut self.r,
            _ => panic!("Illegal Index Argument: was {:?}", index),
        }
    }
}

//  *************  Create Unit Vectors ***************
<commit_msg>Implemented Doc<commit_after>use std::fmt;
use world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS};
use super::{AxialType, DefaultFloat, Vector2f};
use math::cgmath::{VectorSpace, Zero};
use std::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Rem,
               RemAssign, Sub, SubAssign};
use math::cgmath::prelude::{Array, MetricSpace};
use std::cmp;

/// A 2-dimensional vector in axial coordinates. See [here][hex-blog] for more
/// information.
///
/// [hex-blog]: http://www.redblobgames.com/grids/hexagons/#coordinates
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C, packed)]
pub struct AxialVector {
    pub q: AxialType,
    pub r: AxialType,
}

// TODO: implement cgmath::Zero
// TODO: implement cgmath::Array
// TODO: implement cgmath::MatricSpace
// TODO: implement cgmath::VectorSpace
// TODO: implement cgmath::InnerSpace
// TODO: implement ops::{ ... }
// TODO: Add `unit_q()` and `unit_r()` (see `Vector2::unit_x()` for reference)
// For all of the above, see
// http://bjz.github.io/cgmath/cgmath/struct.Vector2.html
//

/// <summary>
/// AxialVector defines a vector specificly for Axial cordinate system.
/// </summary>
impl AxialVector {
    pub fn new(q: AxialType, r: AxialType) -> Self {
        AxialVector { q: q, r: r }
    }

    /// Returns the position of the hexagons center in the standard coordinate
    /// system using `world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS}`.
    pub fn to_real(&self) -> Vector2f {
        Vector2f {
            x: ((2 * self.q + self.r) as DefaultFloat) * HEX_INNER_RADIUS,
            y: (self.r as DefaultFloat) * (3.0 / 2.0) * HEX_OUTER_RADIUS,
        }
    }

    /// Returns the `s` component of corresponding cube coordinates. In cube
    /// coordinates 'q + r + s = 0', so saving `s` is redundant and can be
    /// calculated on the fly when needed.
    pub fn s(&self) -> AxialType {
        -self.q - self.r
    }

    /// <summary>
    /// unit_q creates an default AxialVector with q:1 r:0.
    /// </summary>
    pub fn unit_q() -> AxialVector {
        AxialVector { q: 1, r: 0 }
    }

    /// <summary>
    /// unit_r creates an default AxialVector with q:0 r:1.
    /// </summary>
    pub fn unit_r() -> AxialVector {
        AxialVector { q: 0, r: 1 }
    }
}

/// <summary>
/// implements standart debug for AxialVector
/// </summary>
impl fmt::Debug for AxialVector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("")
            .field(&self.q)
            .field(&self.r)
            .finish()
    }
}

// ********************* Basic Arithmetic (OPS) *********************

/// <summary>
/// implements Neg for AxialVector.
/// </summary>
impl Neg for AxialVector {
    type Output = AxialVector;

    /// <summary>
    /// returns a new negated AxialVector.
    /// </summary>
    fn neg(self) -> Self::Output {
        AxialVector {
            q: -self.q,
            r: -self.r,
        }
    }
}

/// <summary>
/// implements Add for AxialVector.
/// </summary>
impl Add<AxialVector> for AxialVector {
    type Output = AxialVector;

    /// <summary>
    /// adds two AxialVector and returns a new AxialVector with the result.
    /// </summary>
    /// <param name"arg2">second AxialVector to perform operation with.</param>
    fn add(self, arg2: AxialVector) -> AxialVector {
        AxialVector {
            r: self.r + arg2.r,
            q: self.q + arg2.q,
        }
    }
}

/// <summary>
/// implements AddAssign for AxialVector.
/// </summary>
impl AddAssign<AxialVector> for AxialVector {
    /// <summary>
    /// adds a Vector to itself.
    /// </summary>
    /// <param name"arg2">second AxialVector to perform operation with.</param>
    fn add_assign(&mut self, arg2: AxialVector) {
        self.r += arg2.r;
        self.q += arg2.q;

    }
}

/// <summary>
/// implements Sub for AxialVector.
/// </summary>
impl Sub<AxialVector> for AxialVector {
    type Output = AxialVector;

    /// <summary>
    /// subtracts two AxialVector and returns a new AxialVector with the result.
    /// </summary>
    /// <param name"arg2">second AxialVector to perform operation with.</param>
    fn sub(self, arg2: AxialVector) -> AxialVector {
        AxialVector {
            r: self.r - arg2.r,
            q: self.q - arg2.q,
        }
    }
}

/// <summary>
/// implements SubAssign for AxialVector.
/// </summary>
impl SubAssign<AxialVector> for AxialVector {
    /// <summary>
    /// subtracts AxialVector from itself.
    /// </summary>
    /// <param name"arg2">second AxialVector to perform operation with.</param>
    fn sub_assign(&mut self, arg2: AxialVector) {
        self.r -= arg2.r;
        self.q -= arg2.q;

    }
}

/// <summary>
/// implements Mul for AxialVector.
/// </summary>
impl Mul<AxialType> for AxialVector {
    type Output = AxialVector;

    /// <summary>
    /// multiplicates two AxialVector and returns a new AxialVector with the
    /// result.
    /// </summary>
    /// <param name"arg2">second AxialVector to perform operation with.</param>
    fn mul(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r * arg2,
            q: self.q * arg2,
        }
    }
}

/// <summary>
/// implements MulAssign for AxialVector.
/// </summary>
impl MulAssign<AxialType> for AxialVector {
    /// <summary>
    /// multiplicates AxialVector from itself.
    /// </summary>
    /// <param name"arg2">second AxialVector to perform operation with.</param>
    fn mul_assign(&mut self, arg2: AxialType) {
        self.r *= arg2;
        self.q *= arg2;

    }
}

/// <summary>
/// implements Div for AxialVector.
/// </summary>
impl Div<AxialType> for AxialVector {
    type Output = AxialVector;

    /// <summary>
    /// divides two AxialVector and returns a new AxialVector with the result.
    /// </summary>
    /// <param name"arg2">second AxialVector to perform operation with.</param>
    fn div(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r / arg2,
            q: self.q / arg2,
        }
    }
}

/// <summary>
/// implements DivAssign for AxialVector.
/// </summary>
impl DivAssign<AxialType> for AxialVector {
    /// <summary>
    /// divides AxialVector from itself.
    /// </summary>
    /// <param name"arg2">second AxialVector to perform operation with.</param>
    fn div_assign(&mut self, arg2: AxialType) {
        self.r /= arg2;
        self.q /= arg2;

    }
}

/// <summary>
/// implements Rem for AxialVector.
/// </summary>
impl Rem<AxialType> for AxialVector {
    type Output = AxialVector;

    /// <summary>
    /// calculates the modulo of AxialVector with given AxialType.
    /// </summary>
    /// <param name"arg2">second AxialType to perform operation with.</param>
    fn rem(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r % arg2,
            q: self.q % arg2,
        }
    }
}

/// <summary>
/// implements Rem for AxialVector.
/// </summary>
impl RemAssign<AxialType> for AxialVector {
    /// <summary>
    /// calculates the modulo of AxialVector with given AxialType and assignes
    /// it to itself.
    /// </summary>
    /// <param name"arg2">second AxialType to perform operation with.</param>
    fn rem_assign(&mut self, arg2: AxialType) {
        self.r %= arg2;
        self.q %= arg2;

    }
}

// ************ Metric Space ************

/// <summary>
/// implements Rem for AxialVector.
/// </summary>
impl MetricSpace for AxialVector {
    type Metric = DefaultFloat;
    /// <summary>
    /// calculates the distance betweem given AxialVector.
    /// </summary>
    /// <param name"arg2">second AxialType to perform operation with.</param>
    fn distance(self, other: AxialVector) -> DefaultFloat {
        (self.distance2(other)).sqrt()
    }
    /// <summary>
    /// calculates the distance betweem given AxialVector without using sqrt.
    /// </summary>
    /// <param name"arg2">second AxialType to perform operation with.</param>
    fn distance2(self, other: AxialVector) -> DefaultFloat {
        ((self.q - other.q).pow(2) + (self.r - other.r).pow(2)) as DefaultFloat
    }
}

// ************ Vector Space ************

/// <summary>
/// implements VectorSpace for AxialVector.
/// </summary>
impl VectorSpace for AxialVector {
    type Scalar = AxialType;
}

// ************** Zero ****************

/// <summary>
/// implements Zero for AxialVector.
/// </summary>
impl Zero for AxialVector {
    /// <summary>
    /// returns a neutral AxialVector.
    /// </summary>
    fn zero() -> AxialVector {
        AxialVector { q: 0, r: 0 }
    }

    /// <summary>
    /// checks if AxialVector is neutral element.
    /// </summary>
    fn is_zero(&self) -> bool {
        self.q == 0 && self.r == 0
    }
}

// *************** Array & Index *******************

/// <summary>
/// implements Zero for AxialVector.
/// </summary>
impl Array for AxialVector {
    type Element = AxialType;

    /// <summary>
    /// creates an AxialVector from a given value.
    /// </summary>
    /// <param name"value">value from which AxialVector is created.</param>
    fn from_value(value: Self::Element) -> Self {
        AxialVector::new(value, value)
    }

    /// <summary>
    /// sums up all elements in AxialVector and returns them.
    /// </summary>
    fn sum(self) -> Self::Element {
        self.q + self.r
    }

    /// <summary>
    /// multiplicates up all elements in AxialVector and returns them.
    /// </summary>
    fn product(self) -> Self::Element {
        self.q * self.r
    }

    /// <summary>
    /// returns smallest element in AxialVector.
    /// </summary>
    fn min(self) -> Self::Element {
        cmp::min(self.q, self.r)
    }

    /// <summary>
    /// returns largest element in AxialVector.
    /// </summary>
    fn max(self) -> Self::Element {
        cmp::max(self.q, self.r)
    }
}

/// <summary>
/// implements Index for AxialVector.
/// </summary>
impl Index<usize> for AxialVector {
    type Output = AxialType;

    /// <summary>
    /// returns AxialType of the given index number.
    /// </summary>
    /// <param name"index">element index number.</param>
    fn index(&self, index: usize) -> &Self::Output {
        let ret: &AxialType = match index {
            0 => &self.q,
            1 => &self.r,
            _ => panic!("Illegal Index Argument: was {:?}", index),
        };
        ret
    }
}

/// <summary>
/// implements IndexMut for AxialVector.
/// </summary>
impl IndexMut<usize> for AxialVector {
    /// <summary>
    /// returns a mutable AxialType of the given index number.
    /// </summary>
    /// <param name"index">element index number.</param>
    fn index_mut(&mut self, index: usize) -> &mut AxialType {
        match index {
            0 => &mut self.q,
            1 => &mut self.r,
            _ => panic!("Illegal Index Argument: was {:?}", index),
        }
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Code for interacting with the system's VGA buffer.
#![crate_name = "sos_vga"]

#![feature( const_fn
          , slice_patterns
          , unique
          , question_mark )]
#![cfg_attr(feature = "system_term", feature(lang_items))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![no_std]

#[cfg(feature = "system_term")]
extern crate spin;

use core::mem;
use core::fmt::{Write, Result};
use core::ptr::Unique;

#[cfg(feature = "system_term")]
use spin::Mutex;

/// The system's global VGA terminal
#[cfg(feature = "system_term")]
pub static CONSOLE: Mutex<Terminal>
    = Mutex::new(unsafe { Terminal::new(
         Palette::new(Color::LightGrey, Color::Black )
       , 0xB8000
    )});

// TODO: support varying VGA screen sizes?
pub const X_MAX: usize = 80;
pub const Y_MAX: usize = 25;

/// The type signature fot the actual VGA buffer
pub type Buffer = [[Char; X_MAX]; Y_MAX];

const ANSI_ESCAPE: &'static str = "\x1b";
const FG_MASK: u8 = 0b0000_1111;
const BG_MASK: u8 = 0b1111_0000;

/// VGA color codes
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
#[repr(u8)]
pub enum Color { Black = 0
               , Blue = 1
               , Green = 2
               , Cyan = 3
               , Red = 4
               , Magenta = 5
               , Brown = 6
               , LightGrey = 7
               , DarkGrey = 8
               , LightBlue = 9
               , LightGreen = 10
               , LightCyan = 11
               , LightRed = 12
               , LightMagenta = 13
               , Yellow = 14
               , White = 15
               }

#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
pub struct Palette(u8);

impl Palette {
    /// Returns a `Palette` with the given foreground and background color.
    pub const fn new(fg: Color, bg: Color) -> Self {
        Palette( (bg as u8) << 4 | (fg as u8) )
    }

    /// Returns a new `Palette` with this palette's background color, and
    /// the specified foreground color.
    pub fn set_foreground(&self, fg: Color) -> Self {
        Palette( ( self.0 & BG_MASK) | (fg as u8 & FG_MASK) )
    }

    /// Returns a new `Palette` with this palette's foreground color, and
    /// the specified background color.
    pub fn set_background(&self, bg: Color) -> Self {
        Palette( ( (bg as u8) << 4 & BG_MASK) | (self.0 & FG_MASK) )
    }

    /// Returns this `Palette`'s foreground color.
    pub fn foreground(&self) -> Color {
        unsafe { mem::transmute(self.0 & FG_MASK) }
    }

    /// Returns this `Palette`'s background color.
    pub fn background(&self) -> Color {
        unsafe { mem::transmute((self.0 & BG_MASK) >> 4) }
    }

}
/// A colored VGA character.
#[derive(Copy, Clone)]
#[repr(C)]
pub struct Char { pub ascii: u8
                , pub colors: Palette
                }

pub struct Terminal { buffer: Unique<Buffer>
                    , x: usize
                    , y: usize
                    , colors: Palette
                    }
impl Terminal {

    /// Constructs a new `Terminal` for abuffer starting at the given address.
    ///
    /// # Arguments:
    ///   - `colors`: the default color palette for the terminal
    ///   - `buffer_start`: the address of the to the memory location where
    ///      the terminal's VGA buffer begins
    ///
    /// # Unsafe due to:
    ///   - Casting a raw address to an array
    pub const unsafe fn new( colors: Palette
                           , buffer_start: usize)
                           -> Terminal {
        Terminal { x: 0, y: 0
                 , colors: colors
                 , buffer: Unique::new(buffer_start as *mut _)
                 }
    }

    #[inline]
    fn buffer(&mut self) -> &mut  Buffer {
        unsafe { self.buffer.get_mut() }
    }

    /// Set the color palette used for writing subsequent characters.
    pub fn set_colors(&mut self, bg: Color, fg: Color) -> &mut Self {
        self.colors = Palette::new(bg,fg);
        self
    }

    /// Scrolls the terminal one row.
    fn scroll(&mut self) {
        // // construct an iterator over the whole buffer
        // let mut rows = self.buffer()
        //                    .iter_mut();
        //
        // // the current row in the buffer
        // let mut current = rows.next()
        //                    .unwrap();
        //
        // while let Some(next) = rows.next() {
        //     // while there are rows remaining in the iterator, swap the
        //     // next row with the current one (moving it back by one)
        //     mem::swap(current, next);
        //     // and advance our pointer to the current row.
        //     current = next;
        // }
        let buffer: &mut _ = self.buffer();
        for row in 1..Y_MAX {
            buffer[row - 1] = buffer[row];
        }
        // empty the last line in the buffer
        unsafe { buffer[Y_MAX - 1] = mem::zeroed() }
    }

    /// Clear the terminal
    pub fn clear(&mut self) -> &mut Self {
        // to clear the terminal, we just zero out the whole buffer.
        unsafe { *(self.buffer()) = mem::zeroed(); }
        self.x = 0;
        self.y = 0;
        self
    }

    /// Write the given byte to the terminal, and advance the cursor position.
    pub fn write_byte(&mut self, byte: u8) -> &mut Self {
        if byte == b'\n' {
            // if the byte is a newline, we just advance to the next line
            // and reset the column position.
            self.x = 0;
            self.y += 1;
        } else {
            // otherwise, it's a regular character, so we just set the
            // byte at the current position in the buffer to that
            // character (with the current color palette)
            self.buffer()[self.y][self.x]
                = Char { ascii: byte
                       , colors: self.colors };
            // and advance our column position by one
            self.x += 1;

            if self.x >= X_MAX {
                // if we've reached the end of the line, advance to the next
                self.x = 0;
                self.y += 1;
            }
        }
        if self.y >= Y_MAX {
            // if we've reached the bottom of the terminal, scroll.
            self.scroll();
            self.y -= 1;
        }
        self
    }

    fn handle_ansi_escape(&self, escape_code: &str) -> Result {
        match escape_code.as_bytes() {
            // `\x1b[3Nm` sets the foreground color to N.
            [0x1b, b'[', b'3', n, b'm'] => {
                unsafe { self.colors
                             .set_foreground(mem::transmute(n - 48)); }
                Ok(())
            }
            // `\x1b[4Nm` sets the background color to N
          , [0x1b, b'[', b'4', n, b'm'] => {
                unsafe { self.colors
                             .set_background(mem::transmute(n - 48)); }
                Ok(())
            }
          , _ => unimplemented!()
        }
        // let escape_seq: &str = bytes.take_while(|b| b != b'm')
        //                       .collect::<&str>();
        // match escape_seq {
        //     [b'3', n] => unsafe {
        //         self.colors.set_foreground(mem::transmute(n - 48))
        //     }
        // }
        // while let Some(byte) = bytes.next() {
        //     match *byte {
        //         // we've recieved an ANSI escape sequence.
        //         // this basically enters a mediocre FSM for matching ANSI
        //         // control codes.
        //         0x1b => match *next_ansi_byte!(bytes) {
        //             // handle multi-char ANSI escapes
        //             b'[' => match *next_ansi_byte!(bytes) {
        //                 // foreground color code
        //                 fg @ 30 ... 37 => {
        //                     if !(*next_ansi_byte!(bytes) == b'm') {
        //                         unsafe {
        //                             let color: vga::Color
        //                                 = mem::transmute(fg - 30);
        //                             self.colors
        //                                 .set_foreground(color);
        //                         }
        //
        //                     }
        //                 }
        //                 // background color code
        //               , 40 ... 47 => {
        //
        //                 }
        //               , _ => unimplemented!()
        //             }
        //           , _    => unimplemented!()
        //         }
        //         // otherwise, treat the byte as a normal ASCII char
        //       , b => { self.write_byte(b); }
        //     }
        // }

    }

}

struct AnsiEscapeIter<'a> { curr_slice: &'a str
                          , in_escape: bool
                          }

impl<'a> AnsiEscapeIter<'a> {

    pub fn new(s: &'a str) -> Self {
        AnsiEscapeIter { curr_slice: s
                       , in_escape: false
                       }
    }
}

impl<'a> Iterator for AnsiEscapeIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if self.curr_slice.len() == 0 {
            // if the remaining string is empty, we just return `None`
            None
        } else {
            // otherwise, find the next index to chunk on.
            let maybe_idx
                = if self.in_escape {
                     // if we're in an escape code, we split the chunk at the
                     // index of the next 'm' character, adding 1 so that the
                     // 'm' is in the escape code chunk.
                    self.curr_slice.find('m')
                        .map(|idx| idx + 1)
                } else {
                    // otherwise, split at the next ANSI escape sequence
                    self.curr_slice.find(ANSI_ESCAPE)
                };

            // if we found another index to chunk on, map over that index;
            // otherwise, we just yield the rest of the string
            maybe_idx.map_or(
                Some(self.curr_slice) // remainder (if no index to chunk on)
              , |idx| { // otherwise, chunk along that index...
                    let (chunk, next_slice) = self.curr_slice
                                                  .split_at(idx);
                    self.curr_slice = next_slice; // update current chunk
                    Some(chunk)                   // return the chunk
                })
        }

    }
}

impl Write for Terminal {

    fn write_str(&mut self, s: &str) -> Result {

        if s.contains(ANSI_ESCAPE) {
            // if the segment contains an ANSI escape, construct an iterator
            // over each chunk containing either an escape sequence or text
            for segment in AnsiEscapeIter::new(s) {
                if segment.starts_with(ANSI_ESCAPE) {
                    // if the current segment is an ANSI escape code,
                    // try to handle the escape and fail if it is malformed
                    self.handle_ansi_escape(segment)?
                } else {
                    // otherwise, just write each chunk in the string.
                    for byte in segment.as_bytes() {
                        self.write_byte(*byte);
                    }
                }
            }
        } else {
            // otherwise, if there are no ANSI escape codes,
            // we can just write each byte in the string.
            for byte in s.as_bytes() {
                self.write_byte(*byte);
            }
        }
        Ok(())
    }

}

#[cfg(feature = "system_term")]
#[macro_export]
macro_rules! println {
    ($fmt:expr) => (print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}

#[cfg(feature = "system_term")]
#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => ({
            use core::fmt::Write;
            $crate::CONSOLE.lock()
                           .write_fmt(format_args!($($arg)*))
                           .unwrap();
    });
}

#[cfg(feature = "log")]
#[macro_export]
macro_rules! log {
    (level: $level:expr, $fmt:expr, $($arg:tt)*) => ({
        println!( "[{} {}:{}] {}", $level, file!(), line!()
                , format_args!($fmt, $($arg)*));
    });
    (level: $level:expr, $fmt:expr) => ({
        println!("[{} {}:{}] {}", $level, file!(), line!(), $fmt);
    });
}
//
///// Required for Rust stack unwinding
//#[cfg(feature = "system_term")]
//#[lang = "eh_personality"]
//#[no_mangle] #[inline(never)] #[cold]
//pub extern "C" fn rust_eh_personality() {
//    // TODO: add support for stack unwinding
//    println!("eh")
//}
<commit_msg>[vga] add docs<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Code for interacting with the system's VGA buffer.
#![crate_name = "sos_vga"]

#![feature( const_fn
          , slice_patterns
          , unique
          , question_mark )]
#![cfg_attr(feature = "system_term", feature(lang_items))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![no_std]

#[cfg(feature = "system_term")]
extern crate spin;

use core::mem;
use core::fmt::{Write, Result};
use core::ptr::Unique;

#[cfg(feature = "system_term")]
use spin::Mutex;

/// The system's global VGA terminal
#[cfg(feature = "system_term")]
pub static CONSOLE: Mutex<Terminal>
    = Mutex::new(unsafe { Terminal::new(
         Palette::new(Color::LightGrey, Color::Black )
       , 0xB8000
    )});

// TODO: support varying VGA screen sizes?
pub const X_MAX: usize = 80;
pub const Y_MAX: usize = 25;

/// The type signature fot the actual VGA buffer
pub type Buffer = [[Char; X_MAX]; Y_MAX];

const ANSI_ESCAPE: &'static str = "\x1b";
const FG_MASK: u8 = 0b0000_1111;
const BG_MASK: u8 = 0b1111_0000;

/// VGA color codes
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
#[repr(u8)]
pub enum Color { Black = 0
               , Blue = 1
               , Green = 2
               , Cyan = 3
               , Red = 4
               , Magenta = 5
               , Brown = 6
               , LightGrey = 7
               , DarkGrey = 8
               , LightBlue = 9
               , LightGreen = 10
               , LightCyan = 11
               , LightRed = 12
               , LightMagenta = 13
               , Yellow = 14
               , White = 15
               }

#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
pub struct Palette(u8);

impl Palette {
    /// Returns a `Palette` with the given foreground and background color.
    pub const fn new(fg: Color, bg: Color) -> Self {
        Palette( (bg as u8) << 4 | (fg as u8) )
    }

    /// Returns a new `Palette` with this palette's background color, and
    /// the specified foreground color.
    pub fn set_foreground(&self, fg: Color) -> Self {
        Palette( ( self.0 & BG_MASK) | (fg as u8 & FG_MASK) )
    }

    /// Returns a new `Palette` with this palette's foreground color, and
    /// the specified background color.
    pub fn set_background(&self, bg: Color) -> Self {
        Palette( ( (bg as u8) << 4 & BG_MASK) | (self.0 & FG_MASK) )
    }

    /// Returns this `Palette`'s foreground color.
    pub fn foreground(&self) -> Color {
        unsafe { mem::transmute(self.0 & FG_MASK) }
    }

    /// Returns this `Palette`'s background color.
    pub fn background(&self) -> Color {
        unsafe { mem::transmute((self.0 & BG_MASK) >> 4) }
    }

}
/// A colored VGA character.
#[derive(Copy, Clone)]
#[repr(C)]
pub struct Char { pub ascii: u8
                , pub colors: Palette
                }

pub struct Terminal { buffer: Unique<Buffer>
                    , x: usize
                    , y: usize
                    , colors: Palette
                    }
impl Terminal {

    /// Constructs a new `Terminal` for abuffer starting at the given address.
    ///
    /// # Arguments:
    ///   - `colors`: the default color palette for the terminal
    ///   - `buffer_start`: the address of the to the memory location where
    ///      the terminal's VGA buffer begins
    ///
    /// # Unsafe due to:
    ///   - Casting a raw address to an array
    pub const unsafe fn new( colors: Palette
                           , buffer_start: usize)
                           -> Terminal {
        Terminal { x: 0, y: 0
                 , colors: colors
                 , buffer: Unique::new(buffer_start as *mut _)
                 }
    }

    #[inline]
    fn buffer(&mut self) -> &mut  Buffer {
        unsafe { self.buffer.get_mut() }
    }

    /// Set the color palette used for writing subsequent characters.
    pub fn set_colors(&mut self, bg: Color, fg: Color) -> &mut Self {
        self.colors = Palette::new(bg,fg);
        self
    }

    /// Scrolls the terminal one row.
    fn scroll(&mut self) {
        // // construct an iterator over the whole buffer
        // let mut rows = self.buffer()
        //                    .iter_mut();
        //
        // // the current row in the buffer
        // let mut current = rows.next()
        //                    .unwrap();
        //
        // while let Some(next) = rows.next() {
        //     // while there are rows remaining in the iterator, swap the
        //     // next row with the current one (moving it back by one)
        //     mem::swap(current, next);
        //     // and advance our pointer to the current row.
        //     current = next;
        // }
        let buffer: &mut _ = self.buffer();
        for row in 1..Y_MAX {
            buffer[row - 1] = buffer[row];
        }
        // empty the last line in the buffer
        unsafe { buffer[Y_MAX - 1] = mem::zeroed() }
    }

    /// Clear the terminal
    pub fn clear(&mut self) -> &mut Self {
        // to clear the terminal, we just zero out the whole buffer.
        unsafe { *(self.buffer()) = mem::zeroed(); }
        self.x = 0;
        self.y = 0;
        self
    }

    /// Write the given byte to the terminal, and advance the cursor position.
    pub fn write_byte(&mut self, byte: u8) -> &mut Self {
        if byte == b'\n' {
            // if the byte is a newline, we just advance to the next line
            // and reset the column position.
            self.x = 0;
            self.y += 1;
        } else {
            // otherwise, it's a regular character, so we just set the
            // byte at the current position in the buffer to that
            // character (with the current color palette)
            self.buffer()[self.y][self.x]
                = Char { ascii: byte
                       , colors: self.colors };
            // and advance our column position by one
            self.x += 1;

            if self.x >= X_MAX {
                // if we've reached the end of the line, advance to the next
                self.x = 0;
                self.y += 1;
            }
        }
        if self.y >= Y_MAX {
            // if we've reached the bottom of the terminal, scroll.
            self.scroll();
            self.y -= 1;
        }
        self
    }

    fn handle_ansi_escape(&self, escape_code: &str) -> Result {
        match escape_code.as_bytes() {
            // `\x1b[3Nm` sets the foreground color to N.
            [0x1b, b'[', b'3', n, b'm'] => {
                unsafe { self.colors
                             .set_foreground(mem::transmute(n - 48)); }
                Ok(())
            }
            // `\x1b[4Nm` sets the background color to N
          , [0x1b, b'[', b'4', n, b'm'] => {
                unsafe { self.colors
                             .set_background(mem::transmute(n - 48)); }
                Ok(())
            }
          , _ => unimplemented!()
        }
        // let escape_seq: &str = bytes.take_while(|b| b != b'm')
        //                       .collect::<&str>();
        // match escape_seq {
        //     [b'3', n] => unsafe {
        //         self.colors.set_foreground(mem::transmute(n - 48))
        //     }
        // }
        // while let Some(byte) = bytes.next() {
        //     match *byte {
        //         // we've recieved an ANSI escape sequence.
        //         // this basically enters a mediocre FSM for matching ANSI
        //         // control codes.
        //         0x1b => match *next_ansi_byte!(bytes) {
        //             // handle multi-char ANSI escapes
        //             b'[' => match *next_ansi_byte!(bytes) {
        //                 // foreground color code
        //                 fg @ 30 ... 37 => {
        //                     if !(*next_ansi_byte!(bytes) == b'm') {
        //                         unsafe {
        //                             let color: vga::Color
        //                                 = mem::transmute(fg - 30);
        //                             self.colors
        //                                 .set_foreground(color);
        //                         }
        //
        //                     }
        //                 }
        //                 // background color code
        //               , 40 ... 47 => {
        //
        //                 }
        //               , _ => unimplemented!()
        //             }
        //           , _    => unimplemented!()
        //         }
        //         // otherwise, treat the byte as a normal ASCII char
        //       , b => { self.write_byte(b); }
        //     }
        // }

    }

}

struct AnsiEscapeIter<'a> { curr_slice: &'a str
                          , in_escape: bool
                          }

impl<'a> AnsiEscapeIter<'a> {

    pub fn new(s: &'a str) -> Self {
        AnsiEscapeIter { curr_slice: s
                       , in_escape: false
                       }
    }
}

impl<'a> Iterator for AnsiEscapeIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if self.curr_slice.len() == 0 {
            // if the remaining string is empty, we just return `None`
            None
        } else {
            // otherwise, find the next index to chunk on.
            let maybe_idx
                = if self.in_escape {
                     // if we're in an escape code, we split the chunk at the
                     // index of the next 'm' character, adding 1 so that the
                     // 'm' is in the escape code chunk.
                    self.curr_slice.find('m')
                        .map(|idx| idx + 1)
                } else {
                    // otherwise, split at the next ANSI escape sequence
                    self.curr_slice.find(ANSI_ESCAPE)
                };

            // if we found another index to chunk on, map over that index;
            // otherwise, we just yield the rest of the string
            maybe_idx.map_or(
                Some(self.curr_slice) // remainder (if no index to chunk on)
              , |idx| { // otherwise, chunk along that index...
                    let (chunk, next_slice) = self.curr_slice
                                                  .split_at(idx);
                    self.curr_slice = next_slice; // update current chunk
                    Some(chunk)                   // return the chunk
                })
        }

    }
}

impl Write for Terminal {

    fn write_str(&mut self, s: &str) -> Result {

        if s.contains(ANSI_ESCAPE) {
            // if the segment contains an ANSI escape, construct an iterator
            // over each chunk containing either an escape sequence or text
            for segment in AnsiEscapeIter::new(s) {
                if segment.starts_with(ANSI_ESCAPE) {
                    // if the current segment is an ANSI escape code,
                    // try to handle the escape and fail if it is malformed
                    self.handle_ansi_escape(segment)?
                } else {
                    // otherwise, just write each chunk in the string.
                    for byte in segment.as_bytes() {
                        self.write_byte(*byte);
                    }
                }
            }
        } else {
            // otherwise, if there are no ANSI escape codes,
            // we can just write each byte in the string.
            for byte in s.as_bytes() {
                self.write_byte(*byte);
            }
        }
        Ok(())
    }

}

/// Macro for printing to the standard output.
///
/// Equivalent to the `println!` macro except that a newline is not printed at
/// the end of the message.
///
/// # Panics
///
/// Panics if writing to the VGA console fails.
///
#[cfg(feature = "system_term")]
#[macro_export]
macro_rules! println {
    ($fmt:expr) => (print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}

/// Macro for printing to the standard output.
///
/// Equivalent to the `println!` macro except that a newline is not printed at
/// the end of the message.
///
/// # Panics
///
/// Panics if writing to the VGA console fails.
#[cfg(feature = "system_term")]
#[macro_export]
macro_rules! print {
    ($($arg:tt)*) => ({
            use core::fmt::Write;
            $crate::CONSOLE.lock()
                           .write_fmt(format_args!($($arg)*))
                           .unwrap();
    });
}

#[cfg(feature = "log")]
#[macro_export]
macro_rules! log {
    (level: $level:expr, $fmt:expr, $($arg:tt)*) => ({
        println!( "[{} {}:{}] {}", $level, file!(), line!()
                , format_args!($fmt, $($arg)*));
    });
    (level: $level:expr, $fmt:expr) => ({
        println!("[{} {}:{}] {}", $level, file!(), line!(), $fmt);
    });
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-windows TempDir may cause IoError on windows: #10462

#![feature(macro_rules)]

extern crate glob;

use glob::glob;
use std::os;
use std::io;
use std::io::TempDir;

macro_rules! assert_eq ( ($e1:expr, $e2:expr) => (
    if $e1 != $e2 {
        panic!("{} != {}", stringify!($e1), stringify!($e2))
    }
) )

#[test]
fn main() {
    fn mk_file(path: &str, directory: bool) {
        if directory {
            io::fs::mkdir(&Path::new(path), io::USER_RWX).unwrap();
        } else {
            io::File::create(&Path::new(path)).unwrap();
        }
    }

    fn abs_path(path: &str) -> Path {
        os::getcwd().unwrap().join(&Path::new(path))
    }

    fn glob_vec(pattern: &str) -> Vec<Path> {
        glob(pattern).collect()
    }

    let root = TempDir::new("glob-tests");
    let root = root.ok().expect("Should have created a temp directory");
    assert!(os::change_dir(root.path()).is_ok());

    mk_file("aaa", true);
    mk_file("aaa/apple", true);
    mk_file("aaa/orange", true);
    mk_file("aaa/tomato", true);
    mk_file("aaa/tomato/tomato.txt", false);
    mk_file("aaa/tomato/tomoto.txt", false);
    mk_file("bbb", true);
    mk_file("bbb/specials", true);
    mk_file("bbb/specials/!", false);

    // windows does not allow `*` or `?` characters to exist in filenames
    if os::consts::FAMILY != "windows" {
        mk_file("bbb/specials/*", false);
        mk_file("bbb/specials/?", false);
    }

    mk_file("bbb/specials/[", false);
    mk_file("bbb/specials/]", false);
    mk_file("ccc", true);
    mk_file("xyz", true);
    mk_file("xyz/x", false);
    mk_file("xyz/y", false);
    mk_file("xyz/z", false);

    assert_eq!(glob_vec(""), Vec::new());
    assert_eq!(glob_vec("."), vec!(os::getcwd().unwrap()));
    assert_eq!(glob_vec(".."), vec!(os::getcwd().unwrap().join("..")));

    assert_eq!(glob_vec("aaa"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("aaa/"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("a"), Vec::new());
    assert_eq!(glob_vec("aa"), Vec::new());
    assert_eq!(glob_vec("aaaa"), Vec::new());

    assert_eq!(glob_vec("aaa/apple"), vec!(abs_path("aaa/apple")));
    assert_eq!(glob_vec("aaa/apple/nope"), Vec::new());

    // windows should support both / and \ as directory separators
    if os::consts::FAMILY == "windows" {
        assert_eq!(glob_vec("aaa\\apple"), vec!(abs_path("aaa/apple")));
    }

    assert_eq!(glob_vec("???/"), vec!(
        abs_path("aaa"),
        abs_path("bbb"),
        abs_path("ccc"),
        abs_path("xyz")));

    assert_eq!(glob_vec("aaa/tomato/tom?to.txt"), vec!(
        abs_path("aaa/tomato/tomato.txt"),
        abs_path("aaa/tomato/tomoto.txt")));

    assert_eq!(glob_vec("xyz/?"), vec!(
        abs_path("xyz/x"),
        abs_path("xyz/y"),
        abs_path("xyz/z")));

    assert_eq!(glob_vec("a*"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("*a*"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("a*a"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("aaa*"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("*aaa"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("*aaa*"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("*a*a*a*"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("aaa*/"), vec!(abs_path("aaa")));

    assert_eq!(glob_vec("aaa/*"), vec!(
        abs_path("aaa/apple"),
        abs_path("aaa/orange"),
        abs_path("aaa/tomato")));

    assert_eq!(glob_vec("aaa/*a*"), vec!(
        abs_path("aaa/apple"),
        abs_path("aaa/orange"),
        abs_path("aaa/tomato")));

    assert_eq!(glob_vec("*/*/*.txt"), vec!(
        abs_path("aaa/tomato/tomato.txt"),
        abs_path("aaa/tomato/tomoto.txt")));

    assert_eq!(glob_vec("*/*/t[aob]m?to[.]t[!y]t"), vec!(
        abs_path("aaa/tomato/tomato.txt"),
        abs_path("aaa/tomato/tomoto.txt")));

    assert_eq!(glob_vec("./aaa"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("./*"), glob_vec("*"));
    assert_eq!(glob_vec("*/..").pop().unwrap(), abs_path("."));
    assert_eq!(glob_vec("aaa/../bbb"), vec!(abs_path("bbb")));
    assert_eq!(glob_vec("nonexistent/../bbb"), Vec::new());
    assert_eq!(glob_vec("aaa/tomato/tomato.txt/.."), Vec::new());

    assert_eq!(glob_vec("aaa/tomato/tomato.txt/"), Vec::new());

    assert_eq!(glob_vec("aa[a]"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("aa[abc]"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("a[bca]a"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("aa[b]"), Vec::new());
    assert_eq!(glob_vec("aa[xyz]"), Vec::new());
    assert_eq!(glob_vec("aa[]]"), Vec::new());

    assert_eq!(glob_vec("aa[!b]"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("aa[!bcd]"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("a[!bcd]a"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("aa[!a]"), Vec::new());
    assert_eq!(glob_vec("aa[!abc]"), Vec::new());

    assert_eq!(glob_vec("bbb/specials/[[]"), vec!(abs_path("bbb/specials/[")));
    assert_eq!(glob_vec("bbb/specials/!"), vec!(abs_path("bbb/specials/!")));
    assert_eq!(glob_vec("bbb/specials/[]]"), vec!(abs_path("bbb/specials/]")));

    if os::consts::FAMILY != "windows" {
        assert_eq!(glob_vec("bbb/specials/[*]"), vec!(abs_path("bbb/specials/*")));
        assert_eq!(glob_vec("bbb/specials/[?]"), vec!(abs_path("bbb/specials/?")));
    }

    if os::consts::FAMILY == "windows" {

        assert_eq!(glob_vec("bbb/specials/[![]"), vec!(
            abs_path("bbb/specials/!"),
            abs_path("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!]]"), vec!(
            abs_path("bbb/specials/!"),
            abs_path("bbb/specials/[")));

        assert_eq!(glob_vec("bbb/specials/[!!]"), vec!(
            abs_path("bbb/specials/["),
            abs_path("bbb/specials/]")));

    } else {

        assert_eq!(glob_vec("bbb/specials/[![]"), vec!(
            abs_path("bbb/specials/!"),
            abs_path("bbb/specials/*"),
            abs_path("bbb/specials/?"),
            abs_path("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!]]"), vec!(
            abs_path("bbb/specials/!"),
            abs_path("bbb/specials/*"),
            abs_path("bbb/specials/?"),
            abs_path("bbb/specials/[")));

        assert_eq!(glob_vec("bbb/specials/[!!]"), vec!(
            abs_path("bbb/specials/*"),
            abs_path("bbb/specials/?"),
            abs_path("bbb/specials/["),
            abs_path("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!*]"), vec!(
            abs_path("bbb/specials/!"),
            abs_path("bbb/specials/?"),
            abs_path("bbb/specials/["),
            abs_path("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!?]"), vec!(
            abs_path("bbb/specials/!"),
            abs_path("bbb/specials/*"),
            abs_path("bbb/specials/["),
            abs_path("bbb/specials/]")));

    }
}
<commit_msg>Update to rust master<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-windows TempDir may cause IoError on windows: #10462

#![feature(macro_rules)]

extern crate glob;

use glob::glob;
use std::os;
use std::io;
use std::io::TempDir;

macro_rules! assert_eq { ($e1:expr, $e2:expr) => (
    if $e1 != $e2 {
        panic!("{} != {}", stringify!($e1), stringify!($e2))
    }
) }

#[test]
fn main() {
    fn mk_file(path: &str, directory: bool) {
        if directory {
            io::fs::mkdir(&Path::new(path), io::USER_RWX).unwrap();
        } else {
            io::File::create(&Path::new(path)).unwrap();
        }
    }

    fn abs_path(path: &str) -> Path {
        os::getcwd().unwrap().join(&Path::new(path))
    }

    fn glob_vec(pattern: &str) -> Vec<Path> {
        glob(pattern).collect()
    }

    let root = TempDir::new("glob-tests");
    let root = root.ok().expect("Should have created a temp directory");
    assert!(os::change_dir(root.path()).is_ok());

    mk_file("aaa", true);
    mk_file("aaa/apple", true);
    mk_file("aaa/orange", true);
    mk_file("aaa/tomato", true);
    mk_file("aaa/tomato/tomato.txt", false);
    mk_file("aaa/tomato/tomoto.txt", false);
    mk_file("bbb", true);
    mk_file("bbb/specials", true);
    mk_file("bbb/specials/!", false);

    // windows does not allow `*` or `?` characters to exist in filenames
    if os::consts::FAMILY != "windows" {
        mk_file("bbb/specials/*", false);
        mk_file("bbb/specials/?", false);
    }

    mk_file("bbb/specials/[", false);
    mk_file("bbb/specials/]", false);
    mk_file("ccc", true);
    mk_file("xyz", true);
    mk_file("xyz/x", false);
    mk_file("xyz/y", false);
    mk_file("xyz/z", false);

    assert_eq!(glob_vec(""), Vec::new());
    assert_eq!(glob_vec("."), vec!(os::getcwd().unwrap()));
    assert_eq!(glob_vec(".."), vec!(os::getcwd().unwrap().join("..")));

    assert_eq!(glob_vec("aaa"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("aaa/"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("a"), Vec::new());
    assert_eq!(glob_vec("aa"), Vec::new());
    assert_eq!(glob_vec("aaaa"), Vec::new());

    assert_eq!(glob_vec("aaa/apple"), vec!(abs_path("aaa/apple")));
    assert_eq!(glob_vec("aaa/apple/nope"), Vec::new());

    // windows should support both / and \ as directory separators
    if os::consts::FAMILY == "windows" {
        assert_eq!(glob_vec("aaa\\apple"), vec!(abs_path("aaa/apple")));
    }

    assert_eq!(glob_vec("???/"), vec!(
        abs_path("aaa"),
        abs_path("bbb"),
        abs_path("ccc"),
        abs_path("xyz")));

    assert_eq!(glob_vec("aaa/tomato/tom?to.txt"), vec!(
        abs_path("aaa/tomato/tomato.txt"),
        abs_path("aaa/tomato/tomoto.txt")));

    assert_eq!(glob_vec("xyz/?"), vec!(
        abs_path("xyz/x"),
        abs_path("xyz/y"),
        abs_path("xyz/z")));

    assert_eq!(glob_vec("a*"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("*a*"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("a*a"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("aaa*"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("*aaa"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("*aaa*"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("*a*a*a*"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("aaa*/"), vec!(abs_path("aaa")));

    assert_eq!(glob_vec("aaa/*"), vec!(
        abs_path("aaa/apple"),
        abs_path("aaa/orange"),
        abs_path("aaa/tomato")));

    assert_eq!(glob_vec("aaa/*a*"), vec!(
        abs_path("aaa/apple"),
        abs_path("aaa/orange"),
        abs_path("aaa/tomato")));

    assert_eq!(glob_vec("*/*/*.txt"), vec!(
        abs_path("aaa/tomato/tomato.txt"),
        abs_path("aaa/tomato/tomoto.txt")));

    assert_eq!(glob_vec("*/*/t[aob]m?to[.]t[!y]t"), vec!(
        abs_path("aaa/tomato/tomato.txt"),
        abs_path("aaa/tomato/tomoto.txt")));

    assert_eq!(glob_vec("./aaa"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("./*"), glob_vec("*"));
    assert_eq!(glob_vec("*/..").pop().unwrap(), abs_path("."));
    assert_eq!(glob_vec("aaa/../bbb"), vec!(abs_path("bbb")));
    assert_eq!(glob_vec("nonexistent/../bbb"), Vec::new());
    assert_eq!(glob_vec("aaa/tomato/tomato.txt/.."), Vec::new());

    assert_eq!(glob_vec("aaa/tomato/tomato.txt/"), Vec::new());

    assert_eq!(glob_vec("aa[a]"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("aa[abc]"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("a[bca]a"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("aa[b]"), Vec::new());
    assert_eq!(glob_vec("aa[xyz]"), Vec::new());
    assert_eq!(glob_vec("aa[]]"), Vec::new());

    assert_eq!(glob_vec("aa[!b]"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("aa[!bcd]"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("a[!bcd]a"), vec!(abs_path("aaa")));
    assert_eq!(glob_vec("aa[!a]"), Vec::new());
    assert_eq!(glob_vec("aa[!abc]"), Vec::new());

    assert_eq!(glob_vec("bbb/specials/[[]"), vec!(abs_path("bbb/specials/[")));
    assert_eq!(glob_vec("bbb/specials/!"), vec!(abs_path("bbb/specials/!")));
    assert_eq!(glob_vec("bbb/specials/[]]"), vec!(abs_path("bbb/specials/]")));

    if os::consts::FAMILY != "windows" {
        assert_eq!(glob_vec("bbb/specials/[*]"), vec!(abs_path("bbb/specials/*")));
        assert_eq!(glob_vec("bbb/specials/[?]"), vec!(abs_path("bbb/specials/?")));
    }

    if os::consts::FAMILY == "windows" {

        assert_eq!(glob_vec("bbb/specials/[![]"), vec!(
            abs_path("bbb/specials/!"),
            abs_path("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!]]"), vec!(
            abs_path("bbb/specials/!"),
            abs_path("bbb/specials/[")));

        assert_eq!(glob_vec("bbb/specials/[!!]"), vec!(
            abs_path("bbb/specials/["),
            abs_path("bbb/specials/]")));

    } else {

        assert_eq!(glob_vec("bbb/specials/[![]"), vec!(
            abs_path("bbb/specials/!"),
            abs_path("bbb/specials/*"),
            abs_path("bbb/specials/?"),
            abs_path("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!]]"), vec!(
            abs_path("bbb/specials/!"),
            abs_path("bbb/specials/*"),
            abs_path("bbb/specials/?"),
            abs_path("bbb/specials/[")));

        assert_eq!(glob_vec("bbb/specials/[!!]"), vec!(
            abs_path("bbb/specials/*"),
            abs_path("bbb/specials/?"),
            abs_path("bbb/specials/["),
            abs_path("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!*]"), vec!(
            abs_path("bbb/specials/!"),
            abs_path("bbb/specials/?"),
            abs_path("bbb/specials/["),
            abs_path("bbb/specials/]")));

        assert_eq!(glob_vec("bbb/specials/[!?]"), vec!(
            abs_path("bbb/specials/!"),
            abs_path("bbb/specials/*"),
            abs_path("bbb/specials/["),
            abs_path("bbb/specials/]")));

    }
}
<|endoftext|>


<commit_before>extern crate failure;
#[macro_use]
extern crate failure_derive;
#[macro_use]
extern crate nom;
#[macro_use]
extern crate log;
pub mod errors;
pub mod keywords;
pub mod parser;
pub mod scc;
pub mod types;

use errors::{Error, Result};
use std::path::{Path, PathBuf};
use types::Config;

/// A builder for Config
///
/// # Example buld.rs
///
/// ```rust,no_run
/// extern crate pb_rs;
/// extern crate walkdir;
///
/// use pb_rs::{types::FileDescriptor, ConfigBuilder};
/// use std::path::{Path, PathBuf};
/// use walkdir::WalkDir;
///
/// fn main() {
///     let out_dir = std::env::var("OUT_DIR").unwrap();
///     let out_dir = Path::new(&out_dir).join("protos");
///
///     let in_dir = PathBuf::from(::std::env::var("CARGO_MANIFEST_DIR").unwrap()).join("protos");
///     // Re-run this build.rs if the protos dir changes (i.e. a new file is added)
///     println!("cargo:rerun-if-changed={}", in_dir.to_str().unwrap());
///
///     // Find all *.proto files in the `in_dir` and add them to the list of files
///     let mut protos = Vec::new();
///     let proto_ext = Some(Path::new("proto").as_os_str());
///     for entry in WalkDir::new(&in_dir) {
///         let path = entry.unwrap().into_path();
///         if path.extension() == proto_ext {
///             // Re-run this build.rs if any of the files in the protos dir change
///             println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
///             protos.push(path);
///         }
///     }
///
///     // Delete all old generated files before re-generating new ones
///     if out_dir.exists() {
///         std::fs::remove_dir_all(&out_dir).unwrap();
///     }
///     std::fs::DirBuilder::new().create(&out_dir).unwrap();
///     let config_builder = ConfigBuilder::new(&protos, None, Some(&out_dir), &[in_dir]).unwrap();
///     FileDescriptor::run(&config_builder.build()).unwrap()
/// }
/// ```

#[derive(Debug, Default)]
pub struct ConfigBuilder {
    in_files: Vec<PathBuf>,
    out_file: Option<PathBuf>,
    include_paths: Vec<PathBuf>,
    single_module: bool,
    no_output: bool,
    error_cycle: bool,
    headers: bool,
    dont_use_cow: bool,
    custom_struct_derive: Vec<String>,
}

impl ConfigBuilder {
    pub fn new<P: AsRef<Path>>(
        in_files: &[P],
        output: Option<&P>,
        output_dir: Option<&P>,
        include_paths: &[P],
    ) -> Result<ConfigBuilder> {
        let in_files = in_files
            .iter()
            .map(|f| f.as_ref().into())
            .collect::<Vec<PathBuf>>();
        let output = output.map(|f| f.as_ref().into());
        let output_dir: Option<PathBuf> = output_dir.map(|f| f.as_ref().into());
        let mut include_paths = include_paths
            .iter()
            .map(|f| f.as_ref().into())
            .collect::<Vec<PathBuf>>();

        if in_files.is_empty() {
            return Err(Error::NoProto);
        }

        for f in &in_files {
            if !f.exists() {
                return Err(Error::InputFile(format!("{}", f.display())));
            }
        }

        let out_file = match (output, output_dir) {
            (Some(_), None) if in_files.len() > 1 => return Err(Error::OutputMultipleInputs),
            (Some(output), None) => Some(output),
            (None, Some(output_dir)) => {
                if !output_dir.is_dir() {
                    return Err(Error::OutputDirectory(format!("{}", output_dir.display())));
                }
                Some(output_dir)
            }
            (Some(_), Some(_)) => return Err(Error::OutputAndOutputDir),
            (None, None) => None,
        };

        let default = PathBuf::from(".");
        if include_paths.is_empty() || !include_paths.contains(&default) {
            include_paths.push(default);
        }

        Ok(ConfigBuilder {
            in_files: in_files,
            out_file: out_file,
            include_paths: include_paths,
            headers: true,
            ..Default::default()
        })
    }

    /// Omit generation of modules for each package when there is only one package
    pub fn single_module(mut self, val: bool) -> Self {
        self.single_module = val;
        self
    }

    /// Show enums and messages in this .proto file, including those imported. No code generated.
    /// `no_output` should probably only be used by the pb-rs cli.
    pub fn no_output(mut self, val: bool) -> Self {
        self.no_output = val;
        self
    }

    /// Error out if recursive messages do not have optional fields
    pub fn error_cycle(mut self, val: bool) -> Self {
        self.error_cycle = val;
        self
    }

    /// Enable module comments and module attributes in generated file (default = true)
    pub fn headers(mut self, val: bool) -> Self {
        self.headers = val;
        self
    }

    /// Add custom values to #[derive(...)] at the beginning of every structure
    pub fn custom_struct_derive(mut self, val: Vec<String>) -> Self {
        self.custom_struct_derive = val;
        self
    }

    /// Use Cow<_,_> for Strings and Bytes
    pub fn dont_use_cow(mut self, val: bool) -> Self {
        self.dont_use_cow = val;
        self
    }

    /// Build Config from this ConfigBuilder
    pub fn build(self) -> Vec<Config> {
        self.in_files
            .iter()
            .map(|in_file| {
                let mut out_file = in_file.with_extension("rs");

                if let Some(ref ofile) = self.out_file {
                    if ofile.is_dir() {
                        out_file = ofile.join(out_file.file_name().unwrap());
                    } else {
                        out_file = ofile.into();
                    }
                }

                Config {
                    in_file: in_file.to_owned(),
                    out_file: out_file,
                    import_search_path: self.include_paths.clone(),
                    single_module: self.single_module,
                    no_output: self.no_output,
                    error_cycle: self.error_cycle,
                    headers: self.headers,
                    dont_use_cow: self.dont_use_cow, //Change this to true to not use cow for v2 and v3 tests
                    custom_struct_derive: self.custom_struct_derive.clone(),
                    custom_rpc_generator: Box::new(|_,_| Ok(())),
                    custom_includes: Vec::new(),
                }
            })
            .collect()
    }
}
<commit_msg>Added more specific comment.<commit_after>extern crate failure;
#[macro_use]
extern crate failure_derive;
#[macro_use]
extern crate nom;
#[macro_use]
extern crate log;
pub mod errors;
pub mod keywords;
pub mod parser;
pub mod scc;
pub mod types;

use errors::{Error, Result};
use std::path::{Path, PathBuf};
use types::Config;

/// A builder for Config
///
/// # Example buld.rs
///
/// ```rust,no_run
/// extern crate pb_rs;
/// extern crate walkdir;
///
/// use pb_rs::{types::FileDescriptor, ConfigBuilder};
/// use std::path::{Path, PathBuf};
/// use walkdir::WalkDir;
///
/// fn main() {
///     let out_dir = std::env::var("OUT_DIR").unwrap();
///     let out_dir = Path::new(&out_dir).join("protos");
///
///     let in_dir = PathBuf::from(::std::env::var("CARGO_MANIFEST_DIR").unwrap()).join("protos");
///     // Re-run this build.rs if the protos dir changes (i.e. a new file is added)
///     println!("cargo:rerun-if-changed={}", in_dir.to_str().unwrap());
///
///     // Find all *.proto files in the `in_dir` and add them to the list of files
///     let mut protos = Vec::new();
///     let proto_ext = Some(Path::new("proto").as_os_str());
///     for entry in WalkDir::new(&in_dir) {
///         let path = entry.unwrap().into_path();
///         if path.extension() == proto_ext {
///             // Re-run this build.rs if any of the files in the protos dir change
///             println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
///             protos.push(path);
///         }
///     }
///
///     // Delete all old generated files before re-generating new ones
///     if out_dir.exists() {
///         std::fs::remove_dir_all(&out_dir).unwrap();
///     }
///     std::fs::DirBuilder::new().create(&out_dir).unwrap();
///     let config_builder = ConfigBuilder::new(&protos, None, Some(&out_dir), &[in_dir]).unwrap();
///     FileDescriptor::run(&config_builder.build()).unwrap()
/// }
/// ```

#[derive(Debug, Default)]
pub struct ConfigBuilder {
    in_files: Vec<PathBuf>,
    out_file: Option<PathBuf>,
    include_paths: Vec<PathBuf>,
    single_module: bool,
    no_output: bool,
    error_cycle: bool,
    headers: bool,
    dont_use_cow: bool,
    custom_struct_derive: Vec<String>,
}

impl ConfigBuilder {
    pub fn new<P: AsRef<Path>>(
        in_files: &[P],
        output: Option<&P>,
        output_dir: Option<&P>,
        include_paths: &[P],
    ) -> Result<ConfigBuilder> {
        let in_files = in_files
            .iter()
            .map(|f| f.as_ref().into())
            .collect::<Vec<PathBuf>>();
        let output = output.map(|f| f.as_ref().into());
        let output_dir: Option<PathBuf> = output_dir.map(|f| f.as_ref().into());
        let mut include_paths = include_paths
            .iter()
            .map(|f| f.as_ref().into())
            .collect::<Vec<PathBuf>>();

        if in_files.is_empty() {
            return Err(Error::NoProto);
        }

        for f in &in_files {
            if !f.exists() {
                return Err(Error::InputFile(format!("{}", f.display())));
            }
        }

        let out_file = match (output, output_dir) {
            (Some(_), None) if in_files.len() > 1 => return Err(Error::OutputMultipleInputs),
            (Some(output), None) => Some(output),
            (None, Some(output_dir)) => {
                if !output_dir.is_dir() {
                    return Err(Error::OutputDirectory(format!("{}", output_dir.display())));
                }
                Some(output_dir)
            }
            (Some(_), Some(_)) => return Err(Error::OutputAndOutputDir),
            (None, None) => None,
        };

        let default = PathBuf::from(".");
        if include_paths.is_empty() || !include_paths.contains(&default) {
            include_paths.push(default);
        }

        Ok(ConfigBuilder {
            in_files: in_files,
            out_file: out_file,
            include_paths: include_paths,
            headers: true,
            ..Default::default()
        })
    }

    /// Omit generation of modules for each package when there is only one package
    pub fn single_module(mut self, val: bool) -> Self {
        self.single_module = val;
        self
    }

    /// Show enums and messages in this .proto file, including those imported. No code generated.
    /// `no_output` should probably only be used by the pb-rs cli.
    pub fn no_output(mut self, val: bool) -> Self {
        self.no_output = val;
        self
    }

    /// Error out if recursive messages do not have optional fields
    pub fn error_cycle(mut self, val: bool) -> Self {
        self.error_cycle = val;
        self
    }

    /// Enable module comments and module attributes in generated file (default = true)
    pub fn headers(mut self, val: bool) -> Self {
        self.headers = val;
        self
    }

    /// Add custom values to #[derive(...)] at the beginning of every structure
    pub fn custom_struct_derive(mut self, val: Vec<String>) -> Self {
        self.custom_struct_derive = val;
        self
    }

    /// Use Cow<_,_> for Strings and Bytes
    pub fn dont_use_cow(mut self, val: bool) -> Self {
        self.dont_use_cow = val;
        self
    }

    /// Build Config from this ConfigBuilder
    pub fn build(self) -> Vec<Config> {
        self.in_files
            .iter()
            .map(|in_file| {
                let mut out_file = in_file.with_extension("rs");

                if let Some(ref ofile) = self.out_file {
                    if ofile.is_dir() {
                        out_file = ofile.join(out_file.file_name().unwrap());
                    } else {
                        out_file = ofile.into();
                    }
                }

                Config {
                    in_file: in_file.to_owned(),
                    out_file: out_file,
                    import_search_path: self.include_paths.clone(),
                    single_module: self.single_module,
                    no_output: self.no_output,
                    error_cycle: self.error_cycle,
                    headers: self.headers,
                    dont_use_cow: self.dont_use_cow, //Change this to true to not use cow with ./generate.sh for v2 and v3 tests
                    custom_struct_derive: self.custom_struct_derive.clone(),
                    custom_rpc_generator: Box::new(|_,_| Ok(())),
                    custom_includes: Vec::new(),
                }
            })
            .collect()
    }
}
<|endoftext|>