<commit_before>// Copyright 2015 Nicholas Bishop
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Vec2D is a very simple 2D container for storing rectangular data

#![deny(missing_docs)]

/// 2D coordinate
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Coord {
    /// X component
    pub x: usize,

    /// Y component
    pub y: usize
}

/// Rectangle defined by inclusive minimum and maximum coordinates
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Rect {
    /// Minimum coordinate (inclusive)
    min_coord: Coord,

    /// Maximum coordinate (inclusive)
    max_coord: Coord
}

/// Rectangle dimensions
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Size {
    /// Width of rectangle
    pub width: usize,
    /// Height of rectangle
    pub height: usize
}

/// Container for 2D data
#[derive(Clone, Debug)]
pub struct Vec2D<T> {
    elems: Vec<T>,
    size: Size
}

/// Iterator over a rectangle within a Vec2D
pub struct RectIter<'a, Elem: 'a> {
    grid: std::marker::PhantomData<&'a Vec2D<Elem>>,

    rect: Rect,
    cur_elem: *const Elem,
    cur_coord: Coord,
    stride: isize
}

/// Mutable iterator over a rectangle within a Vec2D
pub struct RectIterMut<'a, Elem: 'a> {
    grid: std::marker::PhantomData<&'a mut Vec2D<Elem>>,

    rect: Rect,
    cur_elem: *mut Elem,
    cur_coord: Coord,
    stride: isize
}

impl Coord {
    /// Create a coordinate at (x, y)
    pub fn new(x: usize, y: usize) -> Coord {
        Coord {
            x: x,
            y: y
        }
    }
}

impl std::ops::Add for Coord {
    type Output = Coord;

    fn add(self, other: Coord) -> Coord {
        Coord::new(self.x + other.x,
                   self.y + other.y)
    }
}

impl Rect {
    /// Calculate rectangle width
    pub fn width(&self) -> usize {
        return self.max_coord.x - self.min_coord.x + 1;
    }

    /// Calculate rectangle height
    pub fn height(&self) -> usize {
        return self.max_coord.y - self.min_coord.y + 1;
    }

    /// Calculate rectangle size
    pub fn size(&self) -> Size {
        Size::new(self.width(), self.height())
    }

    /// Return true if the coordinate is between `min_coord` and
    /// `max_coord` (inclusive).
    pub fn contains_coord(&self, coord: Coord) -> bool {
        (coord.x >= self.min_coord.x && coord.x <= self.max_coord.x &&
         coord.y >= self.min_coord.y && coord.y <= self.max_coord.y)
    }
}

impl Size {
    /// Create a 2D size of (width, height)
    pub fn new(width: usize, height: usize) -> Size {
        Size {
            width: width,
            height: height
        }
    }

    /// width * height
    pub fn area(&self) -> usize {
        self.width * self.height
    }

    /// Return true if the coordinate fits within self's width and
    /// height, false otherwise.
    pub fn contains_coord(&self, coord: Coord) -> bool {
        coord.x < self.width && coord.y < self.height
    }

    /// Create a rectangle starting at (0, 0) with `self`'s size.
    pub fn rect(&self) -> Rect {
        Rect {
            min_coord: Coord::new(0, 0),
            max_coord: Coord::new(self.width - 1, self.height - 1)
        }
    }
}

impl<Elem: Copy> Vec2D<Elem> {
    /// Create a Vec2D with the given `size`. All elements are
    /// initialized as copies of the `example` element.
    pub fn from_example(size: Size, example: &Elem) -> Vec2D<Elem> {
        Vec2D {
            elems: vec![*example; size.area()],
            size: size
        }
    }

    /// Create a Vec2D with the given `size`. The contents are set to
    /// `src`. None is returned if the `size` does not match the
    /// length of `src`.
    pub fn from_vec(size: Size, src: Vec<Elem>) -> Option<Vec2D<Elem>> {
        if size.area() == src.len() {
            Some(Vec2D {
                elems: src,
                size: size
            })
        }
        else {
            None
        }
    }

    /// Shortcut for self.size.rect()
    pub fn rect(&self) -> Rect {
        self.size.rect()
    }

    fn stride(&self, rect: &Rect) -> isize {
        (self.size.width + 1 - rect.width()) as isize
    }

    /// Calculate pointer offset for `start` element.
    fn start_offset(&self, start: Coord) -> isize {
        debug_assert_eq!(self.size.contains_coord(start), true);
        (start.y * self.size.width + start.x) as isize
    }

    /// Iterator over the entire Vec2D.
    pub fn iter<'a>(&'a self) -> RectIter<'a, Elem> {
        self.rect_iter(self.size.rect()).unwrap()
    }

    /// Create an iterator over a rectangular region of the
    /// Vec2D. None is returned if the given `rect` does not fit
    /// entirely within the Vec2D.
    pub fn rect_iter<'a>(&'a self, rect: Rect) -> Option<RectIter<'a, Elem>> {
        self.rect_iter_at(rect, rect.min_coord)
    }

    /// Create an iterator over a rectangular region of the Vec2D with
    /// the `start` coord. None is returned if the given `rect` does
    /// not fit entirely within the Vec2D or if the `start` coord is
    /// not within `rect`.
    pub fn rect_iter_at<'a>(&'a self, rect: Rect,
                            start: Coord) -> Option<RectIter<'a, Elem>> {
        if self.size.contains_coord(rect.max_coord) && rect.contains_coord(start) {
            Some(RectIter {
                grid: std::marker::PhantomData,
                stride: self.stride(&rect),
                cur_elem: unsafe {
                    self.elems.as_ptr().offset(self.start_offset(start))
                },
                rect: rect,
                cur_coord: start
            })
        }
        else {
            None
        }
    }

    /// Mutable iterater over the entire Vec2D.
    pub fn iter_mut<'a>(&'a mut self) -> RectIterMut<'a, Elem> {
        let rect = self.size.rect();
        self.rect_iter_mut(rect).unwrap()
    }

    /// Create a mutable iterator over a rectangular region of the
    /// Vec2D. None is returned if the given `rect` does not fit
    /// entirely within the Vec2D.
    pub fn rect_iter_mut<'a>(&'a mut self, rect: Rect) -> Option<RectIterMut<'a, Elem>> {
        if self.size.contains_coord(rect.max_coord) {
            Some(RectIterMut {
                grid: std::marker::PhantomData,
                stride: self.stride(&rect),
                cur_elem: self.elems.as_mut_ptr(),
                rect: rect,
                cur_coord: rect.min_coord
            })
        }
        else {
            None
        }
    }
}

impl<'a, Elem> Iterator for RectIter<'a, Elem> {
    type Item = (Coord, &'a Elem);

    fn next(&mut self) -> Option<Self::Item> {
        if self.cur_coord.y <= self.rect.max_coord.y {
            let result = (self.cur_coord, unsafe { & *self.cur_elem });

            self.cur_coord.x += 1;
            if self.cur_coord.x <= self.rect.max_coord.x {
                unsafe { self.cur_elem = self.cur_elem.offset(1); }
            }
            else {
                self.cur_coord.x = self.rect.min_coord.x;
                self.cur_coord.y += 1;
                unsafe { self.cur_elem = self.cur_elem.offset(self.stride); }
            }
            Some(result)
        }
        else {
            None
        }
    }
}

impl<'a, Elem> Iterator for RectIterMut<'a, Elem> {
    type Item = (Coord, &'a mut Elem);

    fn next(&mut self) -> Option<Self::Item> {
        if self.cur_coord.y <= self.rect.max_coord.y {
            let result = (self.cur_coord, unsafe { &mut *self.cur_elem });

            self.cur_coord.x += 1;
            if self.cur_coord.x <= self.rect.max_coord.x {
                unsafe { self.cur_elem = self.cur_elem.offset(1); }
            }
            else {
                self.cur_coord.x = self.rect.min_coord.x;
                self.cur_coord.y += 1;
                unsafe { self.cur_elem = self.cur_elem.offset(self.stride); }
            }
            Some(result)
        }
        else {
            None
        }
    }
}

impl Rect {
    /// Create a new Rect defined by inclusive minimum and maximum
    /// coordinates. If min_coord is greater than max_coord on either
    /// axis then None is returned.
    pub fn new(min_coord: Coord, max_coord: Coord) -> Option<Rect> {
        if min_coord.x <= max_coord.x && min_coord.y <= max_coord.y {
            Some(Rect {
                min_coord: min_coord,
                max_coord: max_coord
            })
        }
        else {
            None
        }
    }

}

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

    #[test]
    fn test_coord() {
        let coord = Coord::new(1, 2);
        assert_eq!(coord.x, 1);
        assert_eq!(coord.y, 2);
    }

    #[test]
    fn test_coord_add() {
        let a = Coord::new(1, 2);
        let b = Coord::new(5, 9);
        assert_eq!(a + b, Coord::new(6, 11));
    }

    #[test]
    fn test_rect() {
        let rect = Rect::new(Coord::new(1, 2), Coord::new(5, 3)).unwrap();
        assert_eq!(rect.width(), 5);
        assert_eq!(rect.height(), 2);

        assert_eq!(rect.width(), rect.size().width);
        assert_eq!(rect.height(), rect.size().height);

        assert_eq!(rect.contains_coord(Coord::new(0, 0)), false);
        assert_eq!(rect.contains_coord(Coord::new(4, 3)), true);
    }

    #[test]
    fn test_bad_rect() {
        assert_eq!(Rect::new(Coord::new(2, 1), Coord::new(1, 1)).is_none(),
                   true);
        assert_eq!(Rect::new(Coord::new(1, 2), Coord::new(1, 1)).is_none(),
                   true);
    }

    #[test]
    fn test_size() {
        let size = Size::new(3, 2);
        assert_eq!(size.width, 3);
        assert_eq!(size.height, 2);

        assert_eq!(size.area(), 6);

        assert_eq!(size.contains_coord(Coord::new(1, 1)), true);
        assert_eq!(size.contains_coord(Coord::new(4, 1)), false);
        assert_eq!(size.contains_coord(Coord::new(1, 3)), false);

        let rect = size.rect();
        assert_eq!(rect.min_coord, Coord::new(0, 0));
        assert_eq!(rect.max_coord, Coord::new(2, 1));
    }

    #[test]
    fn test_rect_iter_mut() {
        let elems = vec![1, 2, 3, 4];
        let mut grid = Vec2D::from_vec(Size::new(2, 2), elems).unwrap();
        let rect = Rect::new(Coord::new(0, 0), Coord::new(1, 1)).unwrap();

        let mut actual_coords = Vec::new();
        for (coord, elem) in grid.rect_iter_mut(rect).unwrap() {
            *elem = -(*elem);
            actual_coords.push((coord.x, coord.y));
        }
        assert_eq!(actual_coords, [(0, 0), (1, 0), (0, 1), (1, 1)]);
        assert_eq!(grid.elems, [-1, -2, -3, -4]);
    }

    #[test]
    fn test_two_iterators() {
        let size = Size::new(2, 1);
        let v = Vec2D::from_vec(size, vec![0, 1]).unwrap();

        let iter1 = v.rect_iter(size.rect()).unwrap();
        let iter2 = v.rect_iter(size.rect()).unwrap();

        for ((coord1, elem1), (coord2, elem2)) in iter1.zip(iter2) {
            assert_eq!(coord1, coord2);
            assert_eq!(elem1, elem2);
        }
    }

    #[test]
    fn test_rect_iter_at() {
        let size = Size::new(1, 2);
        let v = Vec2D::from_vec(size, vec![0, 1]).unwrap();

        let start = Coord::new(0, 1);
        let mut iter = v.rect_iter_at(size.rect(), start).unwrap();
        let (coord, elem) = iter.next().unwrap();
        assert_eq!((coord, *elem), (start, 1));
        assert_eq!(iter.next().is_none(), true);
    }
}
<commit_msg>add size, resize functions<commit_after>// Copyright 2015 Nicholas Bishop
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Vec2D is a very simple 2D container for storing rectangular data

#![deny(missing_docs)]

/// 2D coordinate
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Coord {
    /// X component
    pub x: usize,

    /// Y component
    pub y: usize
}

/// Rectangle defined by inclusive minimum and maximum coordinates
#[derive(Clone, Copy, Eq, Debug, PartialEq)]
pub struct Rect {
    /// Minimum coordinate (inclusive)
    min_coord: Coord,

    /// Maximum coordinate (inclusive)
    max_coord: Coord
}

/// Rectangle dimensions
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Size {
    /// Width of rectangle
    pub width: usize,
    /// Height of rectangle
    pub height: usize
}

/// Container for 2D data
#[derive(Clone, Debug)]
pub struct Vec2D<T> {
    elems: Vec<T>,
    size: Size
}

/// Iterator over a rectangle within a Vec2D
pub struct RectIter<'a, Elem: 'a> {
    grid: std::marker::PhantomData<&'a Vec2D<Elem>>,

    rect: Rect,
    cur_elem: *const Elem,
    cur_coord: Coord,
    stride: isize
}

/// Mutable iterator over a rectangle within a Vec2D
pub struct RectIterMut<'a, Elem: 'a> {
    grid: std::marker::PhantomData<&'a mut Vec2D<Elem>>,

    rect: Rect,
    cur_elem: *mut Elem,
    cur_coord: Coord,
    stride: isize
}

impl Coord {
    /// Create a coordinate at (x, y)
    pub fn new(x: usize, y: usize) -> Coord {
        Coord {
            x: x,
            y: y
        }
    }
}

impl std::ops::Add for Coord {
    type Output = Coord;

    fn add(self, other: Coord) -> Coord {
        Coord::new(self.x + other.x,
                   self.y + other.y)
    }
}

impl Rect {
    /// Calculate rectangle width
    pub fn width(&self) -> usize {
        return self.max_coord.x - self.min_coord.x + 1;
    }

    /// Calculate rectangle height
    pub fn height(&self) -> usize {
        return self.max_coord.y - self.min_coord.y + 1;
    }

    /// Calculate rectangle size
    pub fn size(&self) -> Size {
        Size::new(self.width(), self.height())
    }

    /// Return true if the coordinate is between `min_coord` and
    /// `max_coord` (inclusive).
    pub fn contains_coord(&self, coord: Coord) -> bool {
        (coord.x >= self.min_coord.x && coord.x <= self.max_coord.x &&
         coord.y >= self.min_coord.y && coord.y <= self.max_coord.y)
    }
}

impl Size {
    /// Create a 2D size of (width, height)
    pub fn new(width: usize, height: usize) -> Size {
        Size {
            width: width,
            height: height
        }
    }

    /// width * height
    pub fn area(&self) -> usize {
        self.width * self.height
    }

    /// Return true if the coordinate fits within self's width and
    /// height, false otherwise.
    pub fn contains_coord(&self, coord: Coord) -> bool {
        coord.x < self.width && coord.y < self.height
    }

    /// Create a rectangle starting at (0, 0) with `self`'s size.
    pub fn rect(&self) -> Rect {
        Rect {
            min_coord: Coord::new(0, 0),
            max_coord: Coord::new(self.width - 1, self.height - 1)
        }
    }
}

impl<Elem: Copy> Vec2D<Elem> {
    /// Create a Vec2D with the given `size`. All elements are
    /// initialized as copies of the `example` element.
    pub fn from_example(size: Size, example: &Elem) -> Vec2D<Elem> {
        Vec2D {
            elems: vec![*example; size.area()],
            size: size
        }
    }

    /// Create a Vec2D with the given `size`. The contents are set to
    /// `src`. None is returned if the `size` does not match the
    /// length of `src`.
    pub fn from_vec(size: Size, src: Vec<Elem>) -> Option<Vec2D<Elem>> {
        if size.area() == src.len() {
            Some(Vec2D {
                elems: src,
                size: size
            })
        }
        else {
            None
        }
    }

    /// Shortcut for self.size.rect()
    pub fn rect(&self) -> Rect {
        self.size.rect()
    }

    /// Resize in-place so that `size()` is equal to `new_size`
    pub fn resize(&mut self, new_size: Size, value: Elem) {
        self.elems.resize (new_size.area(), value);
        self.size = new_size;
    }

    pub fn size(&self) -> Size {
        self.size
    }

    fn stride(&self, rect: &Rect) -> isize {
        (self.size.width + 1 - rect.width()) as isize
    }

    /// Calculate pointer offset for `start` element.
    fn start_offset(&self, start: Coord) -> isize {
        debug_assert_eq!(self.size.contains_coord(start), true);
        (start.y * self.size.width + start.x) as isize
    }

    /// Iterator over the entire Vec2D.
    pub fn iter<'a>(&'a self) -> RectIter<'a, Elem> {
        self.rect_iter(self.size.rect()).unwrap()
    }

    /// Create an iterator over a rectangular region of the
    /// Vec2D. None is returned if the given `rect` does not fit
    /// entirely within the Vec2D.
    pub fn rect_iter<'a>(&'a self, rect: Rect) -> Option<RectIter<'a, Elem>> {
        self.rect_iter_at(rect, rect.min_coord)
    }

    /// Create an iterator over a rectangular region of the Vec2D with
    /// the `start` coord. None is returned if the given `rect` does
    /// not fit entirely within the Vec2D or if the `start` coord is
    /// not within `rect`.
    pub fn rect_iter_at<'a>(&'a self, rect: Rect,
                            start: Coord) -> Option<RectIter<'a, Elem>> {
        if self.size.contains_coord(rect.max_coord) && rect.contains_coord(start) {
            Some(RectIter {
                grid: std::marker::PhantomData,
                stride: self.stride(&rect),
                cur_elem: unsafe {
                    self.elems.as_ptr().offset(self.start_offset(start))
                },
                rect: rect,
                cur_coord: start
            })
        }
        else {
            None
        }
    }

    /// Mutable iterater over the entire Vec2D.
    pub fn iter_mut<'a>(&'a mut self) -> RectIterMut<'a, Elem> {
        let rect = self.size.rect();
        self.rect_iter_mut(rect).unwrap()
    }

    /// Create a mutable iterator over a rectangular region of the
    /// Vec2D. None is returned if the given `rect` does not fit
    /// entirely within the Vec2D.
    pub fn rect_iter_mut<'a>(&'a mut self, rect: Rect) -> Option<RectIterMut<'a, Elem>> {
        if self.size.contains_coord(rect.max_coord) {
            Some(RectIterMut {
                grid: std::marker::PhantomData,
                stride: self.stride(&rect),
                cur_elem: self.elems.as_mut_ptr(),
                rect: rect,
                cur_coord: rect.min_coord
            })
        }
        else {
            None
        }
    }
}

impl<'a, Elem> Iterator for RectIter<'a, Elem> {
    type Item = (Coord, &'a Elem);

    fn next(&mut self) -> Option<Self::Item> {
        if self.cur_coord.y <= self.rect.max_coord.y {
            let result = (self.cur_coord, unsafe { & *self.cur_elem });

            self.cur_coord.x += 1;
            if self.cur_coord.x <= self.rect.max_coord.x {
                unsafe { self.cur_elem = self.cur_elem.offset(1); }
            }
            else {
                self.cur_coord.x = self.rect.min_coord.x;
                self.cur_coord.y += 1;
                unsafe { self.cur_elem = self.cur_elem.offset(self.stride); }
            }
            Some(result)
        }
        else {
            None
        }
    }
}

impl<'a, Elem> Iterator for RectIterMut<'a, Elem> {
    type Item = (Coord, &'a mut Elem);

    fn next(&mut self) -> Option<Self::Item> {
        if self.cur_coord.y <= self.rect.max_coord.y {
            let result = (self.cur_coord, unsafe { &mut *self.cur_elem });

            self.cur_coord.x += 1;
            if self.cur_coord.x <= self.rect.max_coord.x {
                unsafe { self.cur_elem = self.cur_elem.offset(1); }
            }
            else {
                self.cur_coord.x = self.rect.min_coord.x;
                self.cur_coord.y += 1;
                unsafe { self.cur_elem = self.cur_elem.offset(self.stride); }
            }
            Some(result)
        }
        else {
            None
        }
    }
}

impl Rect {
    /// Create a new Rect defined by inclusive minimum and maximum
    /// coordinates. If min_coord is greater than max_coord on either
    /// axis then None is returned.
    pub fn new(min_coord: Coord, max_coord: Coord) -> Option<Rect> {
        if min_coord.x <= max_coord.x && min_coord.y <= max_coord.y {
            Some(Rect {
                min_coord: min_coord,
                max_coord: max_coord
            })
        }
        else {
            None
        }
    }

}

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

    #[test]
    fn test_coord() {
        let coord = Coord::new(1, 2);
        assert_eq!(coord.x, 1);
        assert_eq!(coord.y, 2);
    }

    #[test]
    fn test_coord_add() {
        let a = Coord::new(1, 2);
        let b = Coord::new(5, 9);
        assert_eq!(a + b, Coord::new(6, 11));
    }

    #[test]
    fn test_rect() {
        let rect = Rect::new(Coord::new(1, 2), Coord::new(5, 3)).unwrap();
        assert_eq!(rect.width(), 5);
        assert_eq!(rect.height(), 2);

        assert_eq!(rect.width(), rect.size().width);
        assert_eq!(rect.height(), rect.size().height);

        assert_eq!(rect.contains_coord(Coord::new(0, 0)), false);
        assert_eq!(rect.contains_coord(Coord::new(4, 3)), true);
    }

    #[test]
    fn test_bad_rect() {
        assert_eq!(Rect::new(Coord::new(2, 1), Coord::new(1, 1)).is_none(),
                   true);
        assert_eq!(Rect::new(Coord::new(1, 2), Coord::new(1, 1)).is_none(),
                   true);
    }

    #[test]
    fn test_size() {
        let size = Size::new(3, 2);
        assert_eq!(size.width, 3);
        assert_eq!(size.height, 2);

        assert_eq!(size.area(), 6);

        assert_eq!(size.contains_coord(Coord::new(1, 1)), true);
        assert_eq!(size.contains_coord(Coord::new(4, 1)), false);
        assert_eq!(size.contains_coord(Coord::new(1, 3)), false);

        let rect = size.rect();
        assert_eq!(rect.min_coord, Coord::new(0, 0));
        assert_eq!(rect.max_coord, Coord::new(2, 1));
    }

    #[test]
    fn test_rect_iter_mut() {
        let elems = vec![1, 2, 3, 4];
        let mut grid = Vec2D::from_vec(Size::new(2, 2), elems).unwrap();
        let rect = Rect::new(Coord::new(0, 0), Coord::new(1, 1)).unwrap();

        let mut actual_coords = Vec::new();
        for (coord, elem) in grid.rect_iter_mut(rect).unwrap() {
            *elem = -(*elem);
            actual_coords.push((coord.x, coord.y));
        }
        assert_eq!(actual_coords, [(0, 0), (1, 0), (0, 1), (1, 1)]);
        assert_eq!(grid.elems, [-1, -2, -3, -4]);
    }

    #[test]
    fn test_two_iterators() {
        let size = Size::new(2, 1);
        let v = Vec2D::from_vec(size, vec![0, 1]).unwrap();

        let iter1 = v.rect_iter(size.rect()).unwrap();
        let iter2 = v.rect_iter(size.rect()).unwrap();

        for ((coord1, elem1), (coord2, elem2)) in iter1.zip(iter2) {
            assert_eq!(coord1, coord2);
            assert_eq!(elem1, elem2);
        }
    }

    #[test]
    fn test_rect_iter_at() {
        let size = Size::new(1, 2);
        let v = Vec2D::from_vec(size, vec![0, 1]).unwrap();

        let start = Coord::new(0, 1);
        let mut iter = v.rect_iter_at(size.rect(), start).unwrap();
        let (coord, elem) = iter.next().unwrap();
        assert_eq!((coord, *elem), (start, 1));
        assert_eq!(iter.next().is_none(), true);
    }
}
<|endoftext|>


<commit_before>//! Promises in Rust.

#![warn(missing_docs)]

use std::thread;
use std::sync::mpsc::channel;
use std::time::Duration;
use std::thread::JoinHandle;
use std::marker::{Send};
use std::sync::mpsc::{Sender, Receiver, TryRecvError};

use self::internal::*;

/// A promise is a way of doing work in the background
pub struct Promise<T, E> where T: Send, E: Send {
    receiver: Receiver<Result<T, E>> // Get the result of the promise for chaining (pass into then)
}

impl<T, E> Promise<T, E> where T: Send + 'static, E: Send + 'static {

    /// Chains a function to be called after this promise resolves.
    pub fn then<T2, E2>(self, callback: fn(f: T) -> Result<T2, E2>,
                              errback:  fn(e: E) -> Result<T2, E2>)
                        -> Promise<T2, E2>
    where T2: Send + 'static, E2: Send + 'static {
        let recv = self.receiver;
        let (tx, rx) = channel();

        let thread = thread::spawn(move || {
            if let Ok(message) = recv.recv() { // Blocking receive until message
                match message {
                    Ok(val) => {
                        let _ = tx.send(callback(val)).unwrap_or(());
                    }
                    Err(err) => {
                        let _ = tx.send(errback(err)).unwrap_or(());
                    }
                }
            }
            else { // Receive failed, origin was dropped
            }
        });
        return Promise { receiver: rx };
    }

    /// Chains a function to be called after this promise resolves.
    pub fn then_result<T2, E2>(self,
                               callback: fn(input: Result<T, E>) -> Result<T2, E2>)
                               -> Promise<T2, E2>
    where T2: Send + 'static, E2: Send + 'static {
        let recv = self.receiver;
        let recv2 = self.receiver;
        let (tx, rx) = channel();

        let thread = thread::spawn(move || {
            if let Ok(result) = recv.recv() { // Blocking receive until message
                let _ = tx.send(callback(result)).unwrap_or(());
            }
            else { // Receive failed, origin was dropped
            }
        });
        return Promise { receiver: rx };
    }

    /// Creates a new promsie
    pub fn new<F>(func: F) -> Promise<T, E>
        where T: Send + 'static, E: Send + 'static,
              F: Send + 'static + FnOnce() -> Result<T, E> {
        let (tx, rx) = channel();

        let thread = thread::spawn(move || {
            let result = func();
            let _ = tx.send(result).unwrap_or(());
        });

        return Promise { receiver: rx };
    }
}

pub fn race<T, E>(promises: Vec<Promise<T, E>>) -> Promise<T, E>
where T: Send + 'static, E: Send + 'static {
    let mut receivers = promises.into_iter().map(|p| p.receiver).collect();
    let (tx, rx) = channel();

    thread::spawn(move || {
        race_function(receivers, tx);
    });

    return Promise { receiver: rx };
}

pub fn all<T, E>(promises: Vec<Promise<T, E>>) -> Promise<Vec<T>, E>
where T: Send + 'static, E: Send + 'static {
    let receivers: Vec<Receiver<Result<T, E>>> = promises.into_iter().map(|p| p.receiver).collect();
    let (tx, rx) = channel();

    thread::spawn(move || {
        all_function(receivers, tx);
    });

    return Promise { receiver: rx };
}

pub fn resolve<T, E>(val: E) -> Promise<T, E> {
}

pub fn reject<T, E>(val: E) -> Promise<T, E> {
}

fn race_function<T, E>(receivers: Vec<Receiver<Result<T, E>>>, tx: Sender<Result<T, E>>)
where T: Send + 'static, E: Send + 'static {
    'outer: loop {
        for i in 0..receivers.len() {
            match receivers[i].try_recv() {
                Ok(val) => {
                    let _ = tx.send(val).unwrap_or(());
                    return;
                }
                Err(err) => {
                    if err == TryRecvError::Disconnected {
                        receivers.remove(i);
                    }
                }
            }
        }
    }
}

fn all_function<T, E>(receivers: Vec<Receiver<Result<T, E>>>, tx: Sender<Result<Vec<T>, E>>)
where T: Send + 'static, E: Send + 'static {
    let mut values: Vec<T> = Vec::with_capacity(receivers.len());
    let mut mut_receivers = receivers; //.into_iter().map(|r| r.clone()).collect();
    'outer: loop {
        for rec in receivers {
            match rec.try_recv() {
                Ok(val) => {
                    match val {
                        Ok(t) => values.push(t),
                        Err(e) => {
                            let _ = tx.send(Err(e)).unwrap_or(());
                            return;
                        }
                    }
                }
                Err(err) => {
                    // Remove dead promises?
                }
            }
        }
    }
}
<commit_msg>Add more docs for the Promise struct<commit_after>//! Promises in Rust.

#![warn(missing_docs)]

use std::thread;
use std::sync::mpsc::channel;
use std::time::Duration;
use std::thread::JoinHandle;
use std::marker::{Send};
use std::sync::mpsc::{Sender, Receiver, TryRecvError};

mod internal;
use internal::*;

/// A promise is a way of doing work in the background. The promises in
/// this library have the same featureset as those in Ecmascript 5.
///
/// # Promises
/// Promises (sometimes known as "futures") are objects that represent
/// asynchronous tasks being run in the background, or results which
/// will exist in the future.
/// A promise will be in state of running, fulfilled, or done. In order to
/// use the results of a fulfilled promise, one attaches another promise
/// to it (i.e. via `then`). Like their Javascript counterparts, promises can
/// return an error (of type `E`).
///
/// # Panics
/// If the function being executed by a promise panics, it does so silently.
/// The panic will not resurface in the thread which created the promise,
/// and promises waiting on its result will never be called. In addition,
/// the `all` and `race` proimse methods will _ignore_ "dead" promises. They
/// will remove promises from their lists, and if there aren't any left
/// they will silently exit without doing anything.
///
/// Unfortunately, panics must be ignored for two reasons:
/// * Panic messages don't have a concrete type yet in Rust. If they did,
/// promiess would be able to inspect their predecessors' errors.
/// * Although a `Receiver` can correctly handle its paired `Sender` being
/// dropped, such as during a panic, for reasons stated above the "message"
/// of the panic is not relayed.
///
/// Finally, Ecmascript promises themselves do have the ability to return
/// and error type, represented as a `Result<T, E>` here. Thus, one should
/// use `try!` and other error handling rather than calls to `unwrap()`.
pub struct Promise<T: Send, E: Send> {
    receiver: Receiver<Result<T, E>>
}

impl<T, E> Promise<T, E> where T: Send + 'static, E: Send + 'static {

    /// Chains a function to be called after this promise resolves.
    pub fn then<T2, E2>(self, callback: fn(f: T) -> Result<T2, E2>,
                              errback:  fn(e: E) -> Result<T2, E2>)
                        -> Promise<T2, E2>
    where T2: Send + 'static, E2: Send + 'static {
        let recv = self.receiver;
        let (tx, rx) = channel();

        let thread = thread::spawn(move || {
            internal::then(tx, recv, callback, errback);
        });
        return Promise { receiver: rx };
    }

    /// Chains a function to be called after this promise resolves.
    pub fn then_result<T2, E2>(self,
                               callback: fn(input: Result<T, E>) -> Result<T2, E2>)
                               -> Promise<T2, E2>
    where T2: Send + 'static, E2: Send + 'static {
        let recv = self.receiver;
        let recv2 = self.receiver;
        let (tx, rx) = channel();

        let thread = thread::spawn(move || {
            if let Ok(result) = recv.recv() { // Blocking receive until message
                let _ = tx.send(callback(result)).unwrap_or(());
            }
            else { // Receive failed, origin was dropped
            }
        });
        return Promise { receiver: rx };
    }

    /// Creates a new promsie
    pub fn new<F>(func: F) -> Promise<T, E>
        where T: Send + 'static, E: Send + 'static,
              F: Send + 'static + FnOnce() -> Result<T, E> {
        let (tx, rx) = channel();

        let thread = thread::spawn(move || {
            let result = func();
            let _ = tx.send(result).unwrap_or(());
        });

        return Promise { receiver: rx };
    }
}

pub fn race<T, E>(promises: Vec<Promise<T, E>>) -> Promise<T, E>
where T: Send + 'static, E: Send + 'static {
    let mut receivers = promises.into_iter().map(|p| p.receiver).collect();
    let (tx, rx) = channel();

    thread::spawn(move || {
        race_function(receivers, tx);
    });

    return Promise { receiver: rx };
}

pub fn all<T, E>(promises: Vec<Promise<T, E>>) -> Promise<Vec<T>, E>
where T: Send + 'static, E: Send + 'static {
    let receivers: Vec<Receiver<Result<T, E>>> = promises.into_iter().map(|p| p.receiver).collect();
    let (tx, rx) = channel();

    thread::spawn(move || {
        all_function(receivers, tx);
    });

    return Promise { receiver: rx };
}

pub fn resolve<T, E>(val: E) -> Promise<T, E> {
}

pub fn reject<T, E>(val: E) -> Promise<T, E> {
}

fn race_function<T, E>(receivers: Vec<Receiver<Result<T, E>>>, tx: Sender<Result<T, E>>)
where T: Send + 'static, E: Send + 'static {
    'outer: loop {
        for i in 0..receivers.len() {
            match receivers[i].try_recv() {
                Ok(val) => {
                    let _ = tx.send(val).unwrap_or(());
                    return;
                }
                Err(err) => {
                    if err == TryRecvError::Disconnected {
                        receivers.remove(i);
                    }
                }
            }
        }
    }
}

fn all_function<T, E>(receivers: Vec<Receiver<Result<T, E>>>, tx: Sender<Result<Vec<T>, E>>)
where T: Send + 'static, E: Send + 'static {
    let mut values: Vec<T> = Vec::with_capacity(receivers.len());
    let mut mut_receivers = receivers; //.into_iter().map(|r| r.clone()).collect();
    'outer: loop {
        for rec in receivers {
            match rec.try_recv() {
                Ok(val) => {
                    match val {
                        Ok(t) => values.push(t),
                        Err(e) => {
                            let _ = tx.send(Err(e)).unwrap_or(());
                            return;
                        }
                    }
                }
                Err(err) => {
                    // Remove dead promises?
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![deny(missing_doc)]
#![feature(globs)]

//! A voxel rendering library on top of Gfx.

extern crate gfx;
extern crate image;
extern crate vecmath;

pub mod array;
pub mod cube;
pub mod texture;
<commit_msg>Fixed missing docs warning<commit_after>#![deny(missing_docs)]
#![feature(globs)]

//! A voxel rendering library on top of Gfx.

extern crate gfx;
extern crate image;
extern crate vecmath;

pub mod array;
pub mod cube;
pub mod texture;
<|endoftext|>


<commit_before>//! Interrupt description and set-up code.

use core::fmt;

/// x86 Exception description (see also Intel Vol. 3a Chapter 6).
#[derive(Debug)]
pub struct InterruptDescription {
    pub vector: u8,
    pub mnemonic: &'static str,
    pub description: &'static str,
    pub irqtype: &'static str,
    pub source: &'static str,
}

impl fmt::Display for InterruptDescription {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{} ({}, vec={}) {}",
               self.mnemonic,
               self.irqtype,
               self.vector,
               self.description)
    }
}

/// x86 External Interrupts (1-16).
pub static EXCEPTIONS: [InterruptDescription; 15] = [InterruptDescription {
                                                         vector: 0,
                                                         mnemonic: "#DE",
                                                         description: "Divide Error",
                                                         irqtype: "Fault",
                                                         source: "DIV and IDIV instructions.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 1,
                                                         mnemonic: "#DB",
                                                         description: "RESERVED",
                                                         irqtype: "Fault/ Trap",
                                                         source: "For Intel use only.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 2,
                                                         mnemonic: "NMI",
                                                         description: "Interrupt",
                                                         irqtype: "Interrupt",
                                                         source: "Nonmaskable external interrupt.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 3,
                                                         mnemonic: "#BP",
                                                         description: "Breakpoint",
                                                         irqtype: "Trap",
                                                         source: "INT 3 instruction.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 4,
                                                         mnemonic: "#OF",
                                                         description: "Overflow",
                                                         irqtype: "Trap",
                                                         source: "INTO instruction.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 5,
                                                         mnemonic: "#BR",
                                                         description: "BOUND Range Exceeded",
                                                         irqtype: "Fault",
                                                         source: "BOUND instruction.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 6,
                                                         mnemonic: "#UD",
                                                         description: "Invalid Opcode (Undefined \
                                                                       Opcode)",
                                                         irqtype: "Fault",
                                                         source: "UD2 instruction or reserved \
                                                                  opcode.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 7,
                                                         mnemonic: "#NM",
                                                         description: "Device Not Available (No \
                                                                       Math Coprocessor)",
                                                         irqtype: "Fault",
                                                         source: "Floating-point or WAIT/FWAIT \
                                                                  instruction.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 8,
                                                         mnemonic: "#DF",
                                                         description: "Double Fault",
                                                         irqtype: "Abort",
                                                         source: "Any instruction that can \
                                                                  generate an exception, an NMI, \
                                                                  or an INTR.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 9,
                                                         mnemonic: "",
                                                         description: "Coprocessor Segment Overrun",
                                                         irqtype: "Fault",
                                                         source: "Floating-point instruction.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 10,
                                                         mnemonic: "#TS",
                                                         description: "Invalid TSS",
                                                         irqtype: "Fault",
                                                         source: "Task switch or TSS access.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 11,
                                                         mnemonic: "#NP",
                                                         description: "Segment Not Present",
                                                         irqtype: "Fault",
                                                         source: "Loading segment registers or \
                                                                  accessing system segments.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 12,
                                                         mnemonic: "#SS",
                                                         description: "Stack-Segment Fault",
                                                         irqtype: "Fault",
                                                         source: "Stack operations and SS register \
                                                                  loads.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 13,
                                                         mnemonic: "#GP",
                                                         description: "General Protection",
                                                         irqtype: "Fault",
                                                         source: "Any memory reference and other \
                                                                  protection checks.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 14,
                                                         mnemonic: "#PF",
                                                         description: "Page Fault",
                                                         irqtype: "Fault",
                                                         source: "Any memory reference.",
                                                     }];

/// Enable Interrupts.
pub unsafe fn enable() {
    asm!("sti");
}

/// Disable Interrupts.
pub unsafe fn disable() {
    asm!("cli");
}

/// Generate a software interrupt.
/// This is a macro argument needs to be an immediate.
#[macro_export]
macro_rules! int {
    ( $x:expr ) => {
        {
            asm!("int $0" :: "N" ($x));
        }
    };
}

/// A struct describing an interrupt gate.  See the Intel manual mentioned
/// above for details, specifically, the section "6.14.1 64-Bit Mode IDT"
/// and "Table 3-2. System-Segment and Gate-Descriptor Types".
#[derive(Debug, Clone, Copy)]
#[repr(C, packed)]
pub struct IdtEntry {
    /// Lower 16 bits of ISR.
    pub base_lo: u16,
    /// Segment selector.
    pub sel: u16,
    /// This must always be zero.
    pub res0: u8,
    /// Flags.
    pub flags: u8,
    /// The upper 48 bits of ISR (the last 16 bits must be zero).
    pub base_hi: u64,
    /// Must be zero.
    pub res1: u16,
}

impl IdtEntry {
    /// Create a "missing" IdtEntry.  This is a `const` function, so we can
    /// call it at compile time to initialize static variables.
    ///
    /// If the CPU tries to invoke a missing interrupt, it will instead
    /// send a General Protection fault (13), with the interrupt number and
    /// some other data stored in the error code.
    pub const fn missing() -> IdtEntry {
        IdtEntry {
            base_lo: 0,
            sel: 0,
            res0: 0,
            flags: 0,
            base_hi: 0,
            res1: 0,
        }
    }

    /// Create a new IdtEntry pointing at `handler`, which must be a
    /// function with interrupt calling conventions.  (This must be
    /// currently defined in assembly language.)  The `gdt_code_selector`
    /// value must be the offset of code segment entry in the GDT.
    ///
    /// Create an interrupt gate with the "Present" flag set, which is the
    /// most common case.  If you need something else, you can construct it
    /// manually.
    pub fn interrupt_gate(gdt_code_selector: u16, handler: *const u8) -> IdtEntry {
        IdtEntry {
            base_lo: ((handler as u64) & 0xFFFF) as u16,
            sel: gdt_code_selector,
            res0: 0,
            // Bit 7: "Present" flag set.
            // Bits 0-4: This is an interrupt gate.
            flags: 0b1000_1110,
            base_hi: (handler as u64) >> 16,
            res1: 0,
        }
    }
}

bitflags!{
    // Taken from Intel Manual Section 4.7 Page-Fault Exceptions.
    flags PageFaultError: u32 {
        /// 0: The fault was caused by a non-present page.
        /// 1: The fault was caused by a page-level protection violation
        const PFAULT_ERROR_P = bit!(0),

        /// 0: The access causing the fault was a read.
        /// 1: The access causing the fault was a write.
        const PFAULT_ERROR_WR = bit!(1),

        /// 0: The access causing the fault originated when the processor
        /// was executing in supervisor mode.
        /// 1: The access causing the fault originated when the processor
        /// was executing in user mode.
        const PFAULT_ERROR_US = bit!(2),

        /// 0: The fault was not caused by reserved bit violation.
        /// 1: The fault was caused by reserved bits set to 1 in a page directory.
        const PFAULT_ERROR_RSVD = bit!(3),

        /// 0: The fault was not caused by an instruction fetch.
        /// 1: The fault was caused by an instruction fetch.
        const PFAULT_ERROR_ID = bit!(4),

        /// 0: The fault was not by protection keys.
        /// 1: There was a protection key violation.
        const PFAULT_ERROR_PK = bit!(5),
    }
}

impl fmt::Debug for PageFaultError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let p = match self.contains(PFAULT_ERROR_P) {
            false => "The fault was caused by a non-present page.",
            true => "The fault was caused by a page-level protection violation.",
        };
        let wr = match self.contains(PFAULT_ERROR_WR) {
            false => "The access causing the fault was a read.",
            true => "The access causing the fault was a write.",
        };
        let us = match self.contains(PFAULT_ERROR_US) {
            false => {
                "The access causing the fault originated when the processor was executing in \
                 supervisor mode."
            }
            true => {
                "The access causing the fault originated when the processor was executing in user \
                 mode."
            }
        };
        let rsvd = match self.contains(PFAULT_ERROR_RSVD) {
            false => "The fault was not caused by reserved bit violation.",
            true => "The fault was caused by reserved bits set to 1 in a page directory.",
        };
        let id = match self.contains(PFAULT_ERROR_ID) {
            false => "The fault was not caused by an instruction fetch.",
            true => "The fault was caused by an instruction fetch.",
        };

        write!(f, "{}\n{}\n{}\n{}\n{}", p, wr, us, rsvd, id)
    }
}

#[test]
fn bit_macro() {
    assert!(PFAULT_ERROR_PK.bits() == 0b100000);
    assert!(PFAULT_ERROR_ID.bits() == 0b10000);
    assert!(PFAULT_ERROR_RSVD.bits() == 0b1000);
    assert!(PFAULT_ERROR_US.bits() == 0b100);
    assert!(PFAULT_ERROR_WR.bits() == 0b10);
    assert!(PFAULT_ERROR_P.bits() == 0b1);
}
<commit_msg>Add additional exceptions<commit_after>//! Interrupt description and set-up code.

use core::fmt;

/// x86 Exception description (see also Intel Vol. 3a Chapter 6).
#[derive(Debug)]
pub struct InterruptDescription {
    pub vector: u8,
    pub mnemonic: &'static str,
    pub description: &'static str,
    pub irqtype: &'static str,
    pub source: &'static str,
}

impl fmt::Display for InterruptDescription {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{} ({}, vec={}) {}",
               self.mnemonic,
               self.irqtype,
               self.vector,
               self.description)
    }
}

/// x86 External Interrupts (1-16).
pub static EXCEPTIONS: [InterruptDescription; 21] = [InterruptDescription {
                                                         vector: 0,
                                                         mnemonic: "#DE",
                                                         description: "Divide Error",
                                                         irqtype: "Fault",
                                                         source: "DIV and IDIV instructions.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 1,
                                                         mnemonic: "#DB",
                                                         description: "Debug",
                                                         irqtype: "Fault/ Trap",
                                                         source: "Debug condition",
                                                     },
                                                     InterruptDescription {
                                                         vector: 2,
                                                         mnemonic: "NMI",
                                                         description: "Nonmaskable Interrupt",
                                                         irqtype: "Interrupt",
                                                         source: "Nonmaskable external interrupt.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 3,
                                                         mnemonic: "#BP",
                                                         description: "Breakpoint",
                                                         irqtype: "Trap",
                                                         source: "INT 3 instruction.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 4,
                                                         mnemonic: "#OF",
                                                         description: "Overflow",
                                                         irqtype: "Trap",
                                                         source: "INTO instruction.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 5,
                                                         mnemonic: "#BR",
                                                         description: "BOUND Range Exceeded",
                                                         irqtype: "Fault",
                                                         source: "BOUND instruction.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 6,
                                                         mnemonic: "#UD",
                                                         description: "Invalid Opcode (Undefined \
                                                                       Opcode)",
                                                         irqtype: "Fault",
                                                         source: "UD2 instruction or reserved \
                                                                  opcode.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 7,
                                                         mnemonic: "#NM",
                                                         description: "Device Not Available (No \
                                                                       Math Coprocessor)",
                                                         irqtype: "Fault",
                                                         source: "Floating-point or WAIT/FWAIT \
                                                                  instruction.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 8,
                                                         mnemonic: "#DF",
                                                         description: "Double Fault",
                                                         irqtype: "Abort",
                                                         source: "Any instruction that can \
                                                                  generate an exception, an NMI, \
                                                                  or an INTR.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 9,
                                                         mnemonic: "",
                                                         description: "Coprocessor Segment Overrun",
                                                         irqtype: "Fault",
                                                         source: "Floating-point instruction.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 10,
                                                         mnemonic: "#TS",
                                                         description: "Invalid TSS",
                                                         irqtype: "Fault",
                                                         source: "Task switch or TSS access.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 11,
                                                         mnemonic: "#NP",
                                                         description: "Segment Not Present",
                                                         irqtype: "Fault",
                                                         source: "Loading segment registers or \
                                                                  accessing system segments.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 12,
                                                         mnemonic: "#SS",
                                                         description: "Stack-Segment Fault",
                                                         irqtype: "Fault",
                                                         source: "Stack operations and SS register \
                                                                  loads.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 13,
                                                         mnemonic: "#GP",
                                                         description: "General Protection",
                                                         irqtype: "Fault",
                                                         source: "Any memory reference and other \
                                                                  protection checks.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 14,
                                                         mnemonic: "#PF",
                                                         description: "Page Fault",
                                                         irqtype: "Fault",
                                                         source: "Any memory reference.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 15,
                                                         mnemonic: "",
                                                         description: "RESERVED",
                                                         irqtype: "",
                                                         source: "None.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 16,
                                                         mnemonic: "#MF",
                                                         description: "x87 FPU Floating-Point",
                                                         irqtype: "Fault",
                                                         source: "x87 FPU instructions.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 17,
                                                         mnemonic: "#AC",
                                                         description: "Alignment Check",
                                                         irqtype: "Fault",
                                                         source: "Unaligned memory access.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 18,
                                                         mnemonic: "#MC",
                                                         description: "Machine Check",
                                                         irqtype: "Abort",
                                                         source: "Internal machine error.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 19,
                                                         mnemonic: "#XM",
                                                         description: "SIMD Floating-Point",
                                                         irqtype: "Fault",
                                                         source: "SSE SIMD instructions.",
                                                     },
                                                     InterruptDescription {
                                                         vector: 20,
                                                         mnemonic: "#VE",
                                                         description: "Virtualization",
                                                         irqtype: "Fault",
                                                         source: "EPT violation.",
                                                     }];

/// Enable Interrupts.
pub unsafe fn enable() {
    asm!("sti");
}

/// Disable Interrupts.
pub unsafe fn disable() {
    asm!("cli");
}

/// Generate a software interrupt.
/// This is a macro argument needs to be an immediate.
#[macro_export]
macro_rules! int {
    ( $x:expr ) => {
        {
            asm!("int $0" :: "N" ($x));
        }
    };
}

/// A struct describing an interrupt gate.  See the Intel manual mentioned
/// above for details, specifically, the section "6.14.1 64-Bit Mode IDT"
/// and "Table 3-2. System-Segment and Gate-Descriptor Types".
#[derive(Debug, Clone, Copy)]
#[repr(C, packed)]
pub struct IdtEntry {
    /// Lower 16 bits of ISR.
    pub base_lo: u16,
    /// Segment selector.
    pub sel: u16,
    /// This must always be zero.
    pub res0: u8,
    /// Flags.
    pub flags: u8,
    /// The upper 48 bits of ISR (the last 16 bits must be zero).
    pub base_hi: u64,
    /// Must be zero.
    pub res1: u16,
}

impl IdtEntry {
    /// Create a "missing" IdtEntry.  This is a `const` function, so we can
    /// call it at compile time to initialize static variables.
    ///
    /// If the CPU tries to invoke a missing interrupt, it will instead
    /// send a General Protection fault (13), with the interrupt number and
    /// some other data stored in the error code.
    pub const fn missing() -> IdtEntry {
        IdtEntry {
            base_lo: 0,
            sel: 0,
            res0: 0,
            flags: 0,
            base_hi: 0,
            res1: 0,
        }
    }

    /// Create a new IdtEntry pointing at `handler`, which must be a
    /// function with interrupt calling conventions.  (This must be
    /// currently defined in assembly language.)  The `gdt_code_selector`
    /// value must be the offset of code segment entry in the GDT.
    ///
    /// Create an interrupt gate with the "Present" flag set, which is the
    /// most common case.  If you need something else, you can construct it
    /// manually.
    pub fn interrupt_gate(gdt_code_selector: u16, handler: *const u8) -> IdtEntry {
        IdtEntry {
            base_lo: ((handler as u64) & 0xFFFF) as u16,
            sel: gdt_code_selector,
            res0: 0,
            // Bit 7: "Present" flag set.
            // Bits 0-4: This is an interrupt gate.
            flags: 0b1000_1110,
            base_hi: (handler as u64) >> 16,
            res1: 0,
        }
    }
}

bitflags!{
    // Taken from Intel Manual Section 4.7 Page-Fault Exceptions.
    flags PageFaultError: u32 {
        /// 0: The fault was caused by a non-present page.
        /// 1: The fault was caused by a page-level protection violation
        const PFAULT_ERROR_P = bit!(0),

        /// 0: The access causing the fault was a read.
        /// 1: The access causing the fault was a write.
        const PFAULT_ERROR_WR = bit!(1),

        /// 0: The access causing the fault originated when the processor
        /// was executing in supervisor mode.
        /// 1: The access causing the fault originated when the processor
        /// was executing in user mode.
        const PFAULT_ERROR_US = bit!(2),

        /// 0: The fault was not caused by reserved bit violation.
        /// 1: The fault was caused by reserved bits set to 1 in a page directory.
        const PFAULT_ERROR_RSVD = bit!(3),

        /// 0: The fault was not caused by an instruction fetch.
        /// 1: The fault was caused by an instruction fetch.
        const PFAULT_ERROR_ID = bit!(4),

        /// 0: The fault was not by protection keys.
        /// 1: There was a protection key violation.
        const PFAULT_ERROR_PK = bit!(5),
    }
}

impl fmt::Debug for PageFaultError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let p = match self.contains(PFAULT_ERROR_P) {
            false => "The fault was caused by a non-present page.",
            true => "The fault was caused by a page-level protection violation.",
        };
        let wr = match self.contains(PFAULT_ERROR_WR) {
            false => "The access causing the fault was a read.",
            true => "The access causing the fault was a write.",
        };
        let us = match self.contains(PFAULT_ERROR_US) {
            false => {
                "The access causing the fault originated when the processor was executing in \
                 supervisor mode."
            }
            true => {
                "The access causing the fault originated when the processor was executing in user \
                 mode."
            }
        };
        let rsvd = match self.contains(PFAULT_ERROR_RSVD) {
            false => "The fault was not caused by reserved bit violation.",
            true => "The fault was caused by reserved bits set to 1 in a page directory.",
        };
        let id = match self.contains(PFAULT_ERROR_ID) {
            false => "The fault was not caused by an instruction fetch.",
            true => "The fault was caused by an instruction fetch.",
        };

        write!(f, "{}\n{}\n{}\n{}\n{}", p, wr, us, rsvd, id)
    }
}

#[test]
fn bit_macro() {
    assert!(PFAULT_ERROR_PK.bits() == 0b100000);
    assert!(PFAULT_ERROR_ID.bits() == 0b10000);
    assert!(PFAULT_ERROR_RSVD.bits() == 0b1000);
    assert!(PFAULT_ERROR_US.bits() == 0b100);
    assert!(PFAULT_ERROR_WR.bits() == 0b10);
    assert!(PFAULT_ERROR_P.bits() == 0b1);
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

use bootstrap::{Action, EventHandler, MouseButton};
use color::ColorAlpha;
use overlay::{Disc, Quad, Renderer, RenderInput, Text, Texture2D, Triangle, Vert};
use scene::Scene;

type Time = f32;

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Viewport {
  pub x: f32,
  pub y: f32,
  pub w: f32,
  pub h: f32
}

pub struct GUI<'a> {
  // common
  renderer: Renderer,

  widgets: HashMap<String, Box<Widget<'a> + 'a>>,

  // event stuff
  last_cursor: [f64; 2]
}

impl<'a> GUI<'a> {
  pub fn new(viewport: Viewport, scene: &mut Scene) -> Self {
    GUI {
      renderer: Renderer::new(viewport.w.ceil() as u32, viewport.h.ceil() as u32, 1024, 1024, 1024, scene),
      widgets: HashMap::new(),
      last_cursor: [0., 0.]
    }
  }

  pub fn add_widget<W>(&mut self, id: &str, widget: &W) where W: 'a + Clone + Widget<'a> {
    self.widgets.insert(id.to_owned(), Box::new(widget.clone()));
  }

  pub fn remove_widget(&mut self, id: &str) {
    self.widgets.remove(id);
  }

  pub fn render(&self) -> &Texture2D {
    let mut tris = Vec::new();
    let mut quads = Vec::new();
    let mut discs = Vec::new();
    let mut texts = Vec::new();

    for widget in self.widgets.values() {
      for prim in (*widget).unwidget() {
        match prim {
          WidgetPrim::Triangle(ref tri) => tris.push(*tri),
          WidgetPrim::Quad(ref quad) => quads.push(*quad),
          WidgetPrim::Disc(ref disc) => discs.push(*disc),
          WidgetPrim::Text(ref text) => texts.push(*text)
        }
      }
    }

    let render_input = RenderInput::new()
      .triangles(&tris)
      .quads(&quads)
      .discs(&discs)
      .texts(&texts, 1.);

    self.renderer.render(render_input)
  }
}

impl<'a> EventHandler for GUI<'a> {
  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> bool {
    true
  }

  // TODO: change the implementation to take into account widget focus
  fn on_cursor_move(&mut self, cursor: [f64; 2]) -> bool {
    self.last_cursor = cursor;
    true
  }
}

/// Widget primitives.
///
/// A widget primitive is used as primary a tool to build up widgets. A widget is basically just a
/// sum of widget primitives used to represent it.
pub enum WidgetPrim<'a> {
  Triangle(Triangle),
  Quad(Quad),
  Disc(Disc),
  Text(Text<'a>)
}

pub trait Widget<'a> {
  fn unwidget(&self) -> Vec<WidgetPrim<'a>>;
}

pub struct ProgressBar {
  w: f32,
  progress_quad: Quad,
  inactive_quad: Quad,
  recip_dur_sec: f32,
  listeners: Vec<Rc<RefCell<ProgressBarListener>>>
}

pub enum ProgressBarEvent {
  Set(Time),
  Toggle
}

pub trait ProgressBarListener {
  fn on(&mut self, e: ProgressBarEvent) -> bool;
}

impl ProgressBar {
  pub fn new(w: f32, h: f32, progress_color: ColorAlpha, inactive_color: ColorAlpha, dur_sec: f32) -> Rc<RefCell<Self>> {
    let pcol = *progress_color.as_ref();
    let icol = *inactive_color.as_ref();

    let progress_quad = Quad(
      Vert::new([0., 0., 0.], pcol),
      Vert::new([0., h, 0.], pcol),
      Vert::new([0., 0., 0.], pcol),
      Vert::new([0., h, 0.], pcol)
    );

    let inactive_quad = Quad(
      Vert::new([w, 0., 0.], icol),
      Vert::new([w, h, 0.], icol),
      Vert::new([0., 0., 0.], icol),
      Vert::new([0., h, 0.], icol)
    );

    Rc::new(RefCell::new(ProgressBar {
      w: w,
      progress_quad: progress_quad,
      inactive_quad: inactive_quad,
      recip_dur_sec: 1. / dur_sec,
      listeners: Vec::new()
    }))
  }

  /// Set the cursor (seconds).
  pub fn set(&mut self, cursor: f32) {
    let c = cursor * self.recip_dur_sec * self.w;

    // update the quads
    self.progress_quad.0.pos[0] = c;
    self.progress_quad.1.pos[0] = c;
    self.inactive_quad.2.pos[0] = c;
    self.inactive_quad.3.pos[0] = c;

    for l in &self.listeners {
      l.borrow_mut().on(ProgressBarEvent::Set(cursor));
    }
  }

  pub fn toggle(&mut self) {
    for l in &self.listeners {
      l.borrow_mut().on(ProgressBarEvent::Toggle);
    }
  }
}

impl<'a> Widget<'a> for Rc<RefCell<ProgressBar>> {
  fn unwidget(&self) -> Vec<WidgetPrim<'a>> {
    let bar = &self.borrow();
    vec![WidgetPrim::Quad(bar.progress_quad), WidgetPrim::Quad(bar.inactive_quad)]
  }
}
<commit_msg>Click implemented in the GUI, and passed down to widgets.<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

use bootstrap::{Action, EventHandler, MouseButton};
use color::ColorAlpha;
use overlay::{Disc, Quad, Renderer, RenderInput, Text, Texture2D, Triangle, Vert};
use scene::Scene;

type Time = f32;

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Viewport {
  pub x: f32,
  pub y: f32,
  pub w: f32,
  pub h: f32
}

pub struct GUI<'a> {
  // common
  renderer: Renderer,

  widgets: HashMap<String, Box<Widget<'a> + 'a>>,

  // event stuff
  last_cursor: Option<[f64; 2]>,
  last_mouse_left_down: Option<[f64; 2]>,
  last_mouse_left_up: Option<[f64; 2]>
}

impl<'a> GUI<'a> {
  pub fn new(viewport: Viewport, scene: &mut Scene) -> Self {
    GUI {
      renderer: Renderer::new(viewport.w.ceil() as u32, viewport.h.ceil() as u32, 1024, 1024, 1024, scene),
      widgets: HashMap::new(),
      last_cursor: None,
      last_mouse_left_down: None,
      last_mouse_left_up: None
    }
  }

  pub fn add_widget<W>(&mut self, id: &str, widget: &W) where W: 'a + Clone + Widget<'a> {
    self.widgets.insert(id.to_owned(), Box::new(widget.clone()));
  }

  pub fn remove_widget(&mut self, id: &str) {
    self.widgets.remove(id);
  }

  pub fn render(&self) -> &Texture2D {
    let mut tris = Vec::new();
    let mut quads = Vec::new();
    let mut discs = Vec::new();
    let mut texts = Vec::new();

    for widget in self.widgets.values() {
      for prim in widget.unwidget() {
        match prim {
          WidgetPrim::Triangle(ref tri) => tris.push(*tri),
          WidgetPrim::Quad(ref quad) => quads.push(*quad),
          WidgetPrim::Disc(ref disc) => discs.push(*disc),
          WidgetPrim::Text(ref text) => texts.push(*text)
        }
      }
    }

    let render_input = RenderInput::new()
      .triangles(&tris)
      .quads(&quads)
      .discs(&discs)
      .texts(&texts, 1.);

    self.renderer.render(render_input)
  }
}

impl<'a> EventHandler for GUI<'a> {
  fn on_mouse_button(&mut self, button: MouseButton, action: Action) -> bool {
    if let MouseButton::Button1 = button {
      let last_cursor = self.last_cursor.unwrap();

      match action {
        Action::Press => {
          self.last_mouse_left_down = Some(last_cursor);
          self.last_mouse_left_up = None;
        },
        Action::Release => {
          // check whether it’s a click
          if px_dist(self.last_mouse_left_down.unwrap(), last_cursor) <= 5. {
            // it’s a click
            for widget in self.widgets.values() {
              widget.on_click(last_cursor);
            }
          }

          self.last_mouse_left_down = None;
          self.last_mouse_left_up = Some(last_cursor);

        },
        _ => ()
      }
    }

    true
  }

  // TODO: change the implementation to take into account widget focus
  fn on_cursor_move(&mut self, cursor: [f64; 2]) -> bool {
    self.last_cursor = Some(cursor);
    true
  }
}

/// Widget primitives.
///
/// A widget primitive is used as primary a tool to build up widgets. A widget is basically just a
/// sum of widget primitives used to represent it.
pub enum WidgetPrim<'a> {
  Triangle(Triangle),
  Quad(Quad),
  Disc(Disc),
  Text(Text<'a>)
}

pub trait Widget<'a> {
  fn unwidget(&self) -> Vec<WidgetPrim<'a>>;
  fn on_click(&self, cursor: [f64; 2]);
}

pub struct ProgressBar {
  w: f32,
  progress_quad: Quad,
  inactive_quad: Quad,
  recip_dur_sec: f32,
  listeners: Vec<Rc<RefCell<ProgressBarListener>>>
}

pub enum ProgressBarEvent {
  Set(Time),
  Toggle
}

pub trait ProgressBarListener {
  fn on(&mut self, e: ProgressBarEvent) -> bool;
}

impl ProgressBar {
  pub fn new(w: f32, h: f32, progress_color: ColorAlpha, inactive_color: ColorAlpha, dur_sec: f32) -> Rc<RefCell<Self>> {
    let pcol = *progress_color.as_ref();
    let icol = *inactive_color.as_ref();

    let progress_quad = Quad(
      Vert::new([0., 0., 0.], pcol),
      Vert::new([0., h, 0.], pcol),
      Vert::new([0., 0., 0.], pcol),
      Vert::new([0., h, 0.], pcol)
    );

    let inactive_quad = Quad(
      Vert::new([w, 0., 0.], icol),
      Vert::new([w, h, 0.], icol),
      Vert::new([0., 0., 0.], icol),
      Vert::new([0., h, 0.], icol)
    );

    Rc::new(RefCell::new(ProgressBar {
      w: w,
      progress_quad: progress_quad,
      inactive_quad: inactive_quad,
      recip_dur_sec: 1. / dur_sec,
      listeners: Vec::new()
    }))
  }

  /// Set the cursor (seconds).
  pub fn set(&mut self, cursor: f32) {
    let c = cursor * self.recip_dur_sec * self.w;

    // update the quads
    self.progress_quad.0.pos[0] = c;
    self.progress_quad.1.pos[0] = c;
    self.inactive_quad.2.pos[0] = c;
    self.inactive_quad.3.pos[0] = c;

    for l in &self.listeners {
      l.borrow_mut().on(ProgressBarEvent::Set(cursor));
    }
  }

  pub fn toggle(&mut self) {
    for l in &self.listeners {
      l.borrow_mut().on(ProgressBarEvent::Toggle);
    }
  }

  pub fn on_click(&mut self, cursor: [f64; 2]) {
    let c = cursor[0] as f32;

    // update the quads
    self.progress_quad.0.pos[0] = c;
    self.progress_quad.1.pos[0] = c;
    self.inactive_quad.2.pos[0] = c;
    self.inactive_quad.3.pos[0] = c;

    for l in &self.listeners {
      l.borrow_mut().on(ProgressBarEvent::Set(c / (self.recip_dur_sec * self.w)));
    }
  }
}

impl<'a> Widget<'a> for Rc<RefCell<ProgressBar>> {
  fn unwidget(&self) -> Vec<WidgetPrim<'a>> {
    let bar = &self.borrow();
    vec![WidgetPrim::Quad(bar.progress_quad), WidgetPrim::Quad(bar.inactive_quad)]
  }

  fn on_click(&self, cursor: [f64; 2]) {
    self.borrow_mut().on_click(cursor);
  }
}

/// Pixel distance between two points.
fn px_dist(a: [f64; 2], b: [f64; 2]) -> f64 {
  let x = b[0] - a[0];
  let y = b[1] - a[1];

  f64::sqrt(x*x + y*y)
}
<|endoftext|>


<commit_before>//! # generator
//!
//! Rust generator library
//!

#![feature(fnbox)]
#![feature(rustc_private)]
#![feature(rt)]
#![feature(box_raw)]
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]

#[macro_use]
extern crate log;
extern crate libc;
extern crate context;

pub mod env;
pub use env::ContextStack;

use context::Stack;
use context::Context as RegContext;
use std::rt::unwind::try;
use std::boxed::FnBox;
use std::any::Any;
use std::mem;
use std::ptr;

/// generator context
pub struct Context {
    /// generator regs context
    regs: RegContext,
    /// generator execution stack
    stack: Stack,
    /// passed in para for send
    para: *mut Any,
    /// this is just a buffer for the return value
    ret:  *mut Any,
    /// track generator ref, yield will -1, send will +1
    _ref: u32,
    /// priave flag that control the execution flow
    _flag: bool,
}

impl Context {
    /// return a default generator context
    pub fn new() -> Context {
        // the default generator stack size
        const STACK_SIZE: usize = 16*1024;
        Context {
            regs: RegContext::empty(),
            stack: Stack::new(STACK_SIZE),
            para: unsafe { mem::transmute(&0 as &Any) },
            ret: unsafe { mem::transmute(&0 as &Any) },
            _ref: 0,
            _flag: false,
        }
    }

    /// empty context used for the normal thread
    pub fn empty() -> Context {
        Context {
            regs: RegContext::empty(),
            stack: unsafe { Stack::dummy_stack() },
            para: unsafe { mem::transmute(&0 as &Any) },
            ret: unsafe { mem::transmute(&0 as &Any) },
            _ref: 0,
            _flag: false,
        }
    }

    /// save current generator context
    #[inline(always)]
    pub fn save(&mut self) {
        self._ref -= 1;
        self._flag = true;
        RegContext::save(&mut self.regs);
    }

    /// generator involke flag, save it along with context
    #[inline]
    pub fn get_flag(&mut self)-> &'static mut bool {
        unsafe {mem::transmute(&mut self._flag)}
    }

    /// get current generator send para
    #[inline]
    pub fn get_para<T>(&self) -> Option<T> where T: Any {
        let para = unsafe { &mut *self.para };
        let val = para.downcast_mut::<Option<T>>().unwrap();
        // simple consume the value
        mem::replace(val, None)
    }

    /// set current generator return value
    #[inline]
    pub fn set_ret<T>(&mut self, v: T) where T: Any {
        let ret = unsafe { &mut *self.ret };
        // add type check and panic with message
        let val = ret.downcast_mut::<Option<T>>().unwrap();
        mem::replace(val, Some(v));
    }
}

/// generator trait
pub trait Generator<A> {
    /// Output type
    type Output;

    /// send interface, the Result let us throw out err
    fn send(&mut self, para: Option<A>) -> Option<Self::Output>;

    /// is finished
    fn is_done(&self) -> bool;
}

/// FnGenerator
pub struct FnGenerator<A, T> {
    context: Context,
    // save the input
    para: Option<A>,
    // save the output
    ret: Option<T>,
    // boxed functor
    f: Option<Box<FnBox()->T>>
}

impl<A, T> FnGenerator<A, T> {
    fn resume_gen(&mut self) {
        let env = ContextStack::current();
        let cur = &mut env.top().regs;
        let ctx = &mut self.context as *mut Context;
        let to = unsafe {&mut (*ctx).regs};
        // save current generator context on stack
        env.push(ctx);
        // switch context
        RegContext::swap(cur, to);
    }

    #[inline]
    fn is_started(&self) -> bool {
        // when the f is consumed we think it's running
        self.f.is_none()
    }
}

impl<A: Any, T: Any> Generator<A> for FnGenerator<A, T> {
    type Output = T;

    fn send(&mut self, para: Option<A>) -> Option<T> {
        if self.is_done() {
            return None;
        }

        // every time we call the function, increase the ref count
        // yiled will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        // this is the passed in value of the send primitive
        // the yield part would read out this value in the next round
        // use the replace is would drop the old value
        mem::replace(&mut self.para, para);

        self.ret.take()
    }

    fn is_done(&self) -> bool {
       self.is_started() && self.context._ref != 0
    }
}

impl<A: Any, T: Any> Iterator for FnGenerator<A, T> {
    type Item = T;
    // The 'Iterator' trait only requires the 'next' method to be defined. The
    // return type is 'Option<T>', 'None' is returned when the 'Iterator' is
    // over, otherwise the next value is returned wrapped in 'Some'
    fn next(&mut self) -> Option<T> {
        self.send(None)
    }
}

/// switch back to parent context
pub fn yield_now() {
    let env = ContextStack::current();
    let ctx = env.top();
    let sp = ctx.stack.start();
    // judge if this is root context
    if sp != ptr::null() {
        env.pop();
        let ctx = env.top();
        RegContext::load(&ctx.regs);
    }
}

#[allow(unused_variables)]
extern "C" fn gen_init(arg: usize, f: *mut libc::c_void) {
    let func: Box<Box<FnBox()>> = unsafe {
        Box::from_raw(f as *mut Box<FnBox()>)
    };

    if let Err(cause) = unsafe { try(move|| func()) } {
        error!("Panicked inside: {:?}", cause.downcast::<&str>());
    }

    yield_now();
}

/// create generator
pub fn make_gen<A: Any, T: Any>(p: Option<A>, f: Box<FnBox()->T>) -> Box<FnGenerator<A, T>> {
    let mut g = Box::new(FnGenerator {
       para: p, ret: None, f: Some(f),
       context: Context::new()
    });

    g.context.para = &mut g.para as &mut Any;
    g.context.ret = &mut g.ret as &mut Any;

    unsafe {
        let ptr = Box::into_raw(g);

        //let start = Box::new(||{g.ret = Some((g.f.take().unwrap())())});
        let start = Box::new(move||{
            let mut g = Box::from_raw(ptr);
            g.ret = Some((g.f.take().unwrap())());
            // don't free the box here
            Box::into_raw(g);
        });

        let stk = &mut (*ptr).context.stack;
        let reg = &mut (*ptr).context.regs;
        reg.init_with(gen_init, ptr as usize, start, stk);
        Box::from_raw(ptr)
    }
}

#[macro_export]
macro_rules! generator {
    // `(func, <type>)`
    // func: the expression for unsafe async function which contains yiled
    // para: default send para type to the generator
    ($func:expr, <$para:ty>) => (
        generator::make_gen::<$para, _>(None, Box::new(move|| unsafe{$func}))
    );

    // `(func, para)`
    // func: the expression for unsafe async function which contains yiled
    // para: default send para to the generator
    ($func:expr, $para:expr) => (
        generator::make_gen(Some($para), Box::new(move|| unsafe{$func}))
    );

    ($func:expr) => (generator!($func, ()));
}

#[macro_export]
macro_rules! _yield {
    // `(para)`
    // val: the value that need to be yield
    // and got the send para from context
    ($val:expr) => (
        {
            let context = generator::ContextStack::current().top();
            let _no_use = context.get_flag();
            context.save();
            if *_no_use {
                *_no_use = false;
                // set the return value
                context.set_ret($val);
                // don't use the return instruction
                generator::yield_now();
                // will never come here, but for type check
                return $val;
            }
            context.get_para()
        }
    );

    () => (_yield!(()));
}

/// yield without get the passed in para
#[macro_export]
macro_rules! _yield_ {
    // `(para)`
    // val: the value that need to be yield
    // and got the send para from context
    ($val:expr) => (
        {
            let context = generator::ContextStack::current().top();
            let _no_use = context.get_flag();
            context.save();
            if *_no_use {
                *_no_use = false;
                context.set_ret($val);
                // don't use the return instruction
                generator::yield_now();
                // context.load();
                return $val;
            }
        }
    );

    () => (_yield_!(()));
}

<commit_msg>use rt min_stack<commit_after>//! # generator
//!
//! Rust generator library
//!

#![feature(fnbox)]
#![feature(rustc_private)]
#![feature(rt)]
#![feature(box_raw)]
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]

#[macro_use]
extern crate log;
extern crate libc;
extern crate context;

pub mod env;
pub use env::ContextStack;

use context::Stack;
use context::Context as RegContext;
use std::rt::unwind::try;
use std::rt::util::min_stack;
use std::boxed::FnBox;
use std::any::Any;
use std::mem;
use std::ptr;

/// generator context
pub struct Context {
    /// generator regs context
    regs: RegContext,
    /// generator execution stack
    stack: Stack,
    /// passed in para for send
    para: *mut Any,
    /// this is just a buffer for the return value
    ret:  *mut Any,
    /// track generator ref, yield will -1, send will +1
    _ref: u32,
    /// priave flag that control the execution flow
    _flag: bool,
}

impl Context {
    /// return a default generator context
    pub fn new() -> Context {
        Context {
            regs: RegContext::empty(),
            stack: Stack::new(min_stack()),
            para: unsafe { mem::transmute(&0 as &Any) },
            ret: unsafe { mem::transmute(&0 as &Any) },
            _ref: 0,
            _flag: false,
        }
    }

    /// empty context used for the normal thread
    pub fn empty() -> Context {
        Context {
            regs: RegContext::empty(),
            stack: unsafe { Stack::dummy_stack() },
            para: unsafe { mem::transmute(&0 as &Any) },
            ret: unsafe { mem::transmute(&0 as &Any) },
            _ref: 0,
            _flag: false,
        }
    }

    /// save current generator context
    #[inline(always)]
    pub fn save(&mut self) {
        self._ref -= 1;
        self._flag = true;
        RegContext::save(&mut self.regs);
    }

    /// generator involke flag, save it along with context
    #[inline]
    pub fn get_flag(&mut self)-> &'static mut bool {
        unsafe {mem::transmute(&mut self._flag)}
    }

    /// get current generator send para
    #[inline]
    pub fn get_para<T>(&self) -> Option<T> where T: Any {
        let para = unsafe { &mut *self.para };
        let val = para.downcast_mut::<Option<T>>().unwrap();
        // simple consume the value
        mem::replace(val, None)
    }

    /// set current generator return value
    #[inline]
    pub fn set_ret<T>(&mut self, v: T) where T: Any {
        let ret = unsafe { &mut *self.ret };
        // add type check and panic with message
        let val = ret.downcast_mut::<Option<T>>().unwrap();
        mem::replace(val, Some(v));
    }
}

/// generator trait
pub trait Generator<A> {
    /// Output type
    type Output;

    /// send interface, the Result let us throw out err
    fn send(&mut self, para: Option<A>) -> Option<Self::Output>;

    /// is finished
    fn is_done(&self) -> bool;
}

/// FnGenerator
pub struct FnGenerator<A, T> {
    context: Context,
    // save the input
    para: Option<A>,
    // save the output
    ret: Option<T>,
    // boxed functor
    f: Option<Box<FnBox()->T>>
}

impl<A, T> FnGenerator<A, T> {
    fn resume_gen(&mut self) {
        let env = ContextStack::current();
        let cur = &mut env.top().regs;
        let ctx = &mut self.context as *mut Context;
        let to = unsafe {&mut (*ctx).regs};
        // save current generator context on stack
        env.push(ctx);
        // switch context
        RegContext::swap(cur, to);
    }

    #[inline]
    fn is_started(&self) -> bool {
        // when the f is consumed we think it's running
        self.f.is_none()
    }
}

impl<A: Any, T: Any> Generator<A> for FnGenerator<A, T> {
    type Output = T;

    fn send(&mut self, para: Option<A>) -> Option<T> {
        if self.is_done() {
            return None;
        }

        // every time we call the function, increase the ref count
        // yiled will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        // this is the passed in value of the send primitive
        // the yield part would read out this value in the next round
        // use the replace is would drop the old value
        mem::replace(&mut self.para, para);

        self.ret.take()
    }

    fn is_done(&self) -> bool {
       self.is_started() && self.context._ref != 0
    }
}

impl<A: Any, T: Any> Iterator for FnGenerator<A, T> {
    type Item = T;
    // The 'Iterator' trait only requires the 'next' method to be defined. The
    // return type is 'Option<T>', 'None' is returned when the 'Iterator' is
    // over, otherwise the next value is returned wrapped in 'Some'
    fn next(&mut self) -> Option<T> {
        self.send(None)
    }
}

/// switch back to parent context
pub fn yield_now() {
    let env = ContextStack::current();
    let ctx = env.top();
    let sp = ctx.stack.start();
    // judge if this is root context
    if sp != ptr::null() {
        env.pop();
        let ctx = env.top();
        RegContext::load(&ctx.regs);
    }
}

#[allow(unused_variables)]
extern "C" fn gen_init(arg: usize, f: *mut libc::c_void) {
    let func: Box<Box<FnBox()>> = unsafe {
        Box::from_raw(f as *mut Box<FnBox()>)
    };

    if let Err(cause) = unsafe { try(move|| func()) } {
        error!("Panicked inside: {:?}", cause.downcast::<&str>());
    }

    yield_now();
}

/// create generator
pub fn make_gen<A: Any, T: Any>(p: Option<A>, f: Box<FnBox()->T>) -> Box<FnGenerator<A, T>> {
    let mut g = Box::new(FnGenerator {
       para: p, ret: None, f: Some(f),
       context: Context::new()
    });

    g.context.para = &mut g.para as &mut Any;
    g.context.ret = &mut g.ret as &mut Any;

    unsafe {
        let ptr = Box::into_raw(g);

        //let start = Box::new(||{g.ret = Some((g.f.take().unwrap())())});
        let start = Box::new(move||{
            let mut g = Box::from_raw(ptr);
            g.ret = Some((g.f.take().unwrap())());
            // don't free the box here
            Box::into_raw(g);
        });

        let stk = &mut (*ptr).context.stack;
        let reg = &mut (*ptr).context.regs;
        reg.init_with(gen_init, ptr as usize, start, stk);
        Box::from_raw(ptr)
    }
}

#[macro_export]
macro_rules! generator {
    // `(func, <type>)`
    // func: the expression for unsafe async function which contains yiled
    // para: default send para type to the generator
    ($func:expr, <$para:ty>) => (
        generator::make_gen::<$para, _>(None, Box::new(move|| unsafe{$func}))
    );

    // `(func, para)`
    // func: the expression for unsafe async function which contains yiled
    // para: default send para to the generator
    ($func:expr, $para:expr) => (
        generator::make_gen(Some($para), Box::new(move|| unsafe{$func}))
    );

    ($func:expr) => (generator!($func, ()));
}

#[macro_export]
macro_rules! _yield {
    // `(para)`
    // val: the value that need to be yield
    // and got the send para from context
    ($val:expr) => (
        {
            let context = generator::ContextStack::current().top();
            let _no_use = context.get_flag();
            context.save();
            if *_no_use {
                *_no_use = false;
                // set the return value
                context.set_ret($val);
                // don't use the return instruction
                generator::yield_now();
                // will never come here, but for type check
                return $val;
            }
            context.get_para()
        }
    );

    () => (_yield!(()));
}

/// yield without get the passed in para
#[macro_export]
macro_rules! _yield_ {
    // `(para)`
    // val: the value that need to be yield
    // and got the send para from context
    ($val:expr) => (
        {
            let context = generator::ContextStack::current().top();
            let _no_use = context.get_flag();
            context.save();
            if *_no_use {
                *_no_use = false;
                context.set_ret($val);
                // don't use the return instruction
                generator::yield_now();
                // context.load();
                return $val;
            }
        }
    );

    () => (_yield_!(()));
}

<|endoftext|>