<commit_before>use std::ops::Range;
use std::slice;
use libc::c_void;

use objc::Id;
use {INSObject, INSCopying, INSMutableCopying, NSRange};

pub trait INSData : INSObject {
    fn len(&self) -> usize {
        unsafe {
            msg_send![self, length]
        }
    }

    fn bytes(&self) -> &[u8] {
        let ptr: *const c_void = unsafe { msg_send![self, bytes] };
        // The bytes pointer may be null for length zero
        let (ptr, len) = if ptr.is_null() {
            (0x1 as *const u8, 0)
        } else {
            (ptr as *const u8, self.len())
        };
        unsafe {
            slice::from_raw_parts(ptr, len)
        }
    }

    fn with_bytes(bytes: &[u8]) -> Id<Self> {
        let cls = <Self as INSObject>::class();
        unsafe {
            let obj: *mut Self = msg_send![cls, alloc];
            let obj: *mut Self = msg_send![obj, initWithBytes:bytes.as_ptr()
                                                       length:bytes.len()];
            Id::from_retained_ptr(obj)
        }
    }
}

object_struct!(NSData);

impl INSData for NSData { }

impl INSCopying for NSData {
    type Output = NSData;
}

impl INSMutableCopying for NSData {
    type Output = NSMutableData;
}

pub trait INSMutableData : INSData {
    fn bytes_mut(&mut self) -> &mut [u8] {
        let ptr: *mut c_void = unsafe { msg_send![self, mutableBytes] };
        // The bytes pointer may be null for length zero
        let (ptr, len) = if ptr.is_null() {
            (0x1 as *mut u8, 0)
        } else {
            (ptr as *mut u8, self.len())
        };
        unsafe {
            slice::from_raw_parts_mut(ptr, len)
        }
    }

    fn set_len(&mut self, len: usize) {
        unsafe {
            let _: () = msg_send![self, setLength:len];
        }
    }

    fn append(&mut self, bytes: &[u8]) {
        unsafe {
            let _: () = msg_send![self, appendBytes:bytes.as_ptr()
                                             length:bytes.len()];
        }
    }

    fn replace_range(&mut self, range: Range<usize>, bytes: &[u8]) {
        let range = NSRange::from_range(range);
        unsafe {
            let _: () = msg_send![self, replaceBytesInRange:range
                                                  withBytes:bytes.as_ptr()
                                                     length:bytes.len()];
        }
    }

    fn set_bytes(&mut self, bytes: &[u8]) {
        let len = self.len();
        self.replace_range(0..len, bytes);
    }
}

object_struct!(NSMutableData);

impl INSData for NSMutableData { }

impl INSMutableData for NSMutableData { }

impl INSCopying for NSMutableData {
    type Output = NSData;
}

impl INSMutableCopying for NSMutableData {
    type Output = NSMutableData;
}

#[cfg(test)]
mod tests {
    use objc::Id;
    use INSObject;
    use super::{INSData, NSData};

    #[test]
    fn test_bytes() {
        let bytes = [3u8, 7, 16, 52, 112, 19];
        let data: Id<NSData> = INSData::with_bytes(&bytes);
        assert!(data.len() == bytes.len());
        assert!(data.bytes() == bytes.as_slice());
    }

    #[test]
    fn test_no_bytes() {
        let data: Id<NSData> = INSObject::new();
        assert!(Some(data.bytes()).is_some());
    }
}
<commit_msg>Added NSMutableData tests.<commit_after>use std::ops::Range;
use std::slice;
use libc::c_void;

use objc::Id;
use {INSObject, INSCopying, INSMutableCopying, NSRange};

pub trait INSData : INSObject {
    fn len(&self) -> usize {
        unsafe {
            msg_send![self, length]
        }
    }

    fn bytes(&self) -> &[u8] {
        let ptr: *const c_void = unsafe { msg_send![self, bytes] };
        // The bytes pointer may be null for length zero
        let (ptr, len) = if ptr.is_null() {
            (0x1 as *const u8, 0)
        } else {
            (ptr as *const u8, self.len())
        };
        unsafe {
            slice::from_raw_parts(ptr, len)
        }
    }

    fn with_bytes(bytes: &[u8]) -> Id<Self> {
        let cls = <Self as INSObject>::class();
        unsafe {
            let obj: *mut Self = msg_send![cls, alloc];
            let obj: *mut Self = msg_send![obj, initWithBytes:bytes.as_ptr()
                                                       length:bytes.len()];
            Id::from_retained_ptr(obj)
        }
    }
}

object_struct!(NSData);

impl INSData for NSData { }

impl INSCopying for NSData {
    type Output = NSData;
}

impl INSMutableCopying for NSData {
    type Output = NSMutableData;
}

pub trait INSMutableData : INSData {
    fn bytes_mut(&mut self) -> &mut [u8] {
        let ptr: *mut c_void = unsafe { msg_send![self, mutableBytes] };
        // The bytes pointer may be null for length zero
        let (ptr, len) = if ptr.is_null() {
            (0x1 as *mut u8, 0)
        } else {
            (ptr as *mut u8, self.len())
        };
        unsafe {
            slice::from_raw_parts_mut(ptr, len)
        }
    }

    fn set_len(&mut self, len: usize) {
        unsafe {
            let _: () = msg_send![self, setLength:len];
        }
    }

    fn append(&mut self, bytes: &[u8]) {
        unsafe {
            let _: () = msg_send![self, appendBytes:bytes.as_ptr()
                                             length:bytes.len()];
        }
    }

    fn replace_range(&mut self, range: Range<usize>, bytes: &[u8]) {
        let range = NSRange::from_range(range);
        unsafe {
            let _: () = msg_send![self, replaceBytesInRange:range
                                                  withBytes:bytes.as_ptr()
                                                     length:bytes.len()];
        }
    }

    fn set_bytes(&mut self, bytes: &[u8]) {
        let len = self.len();
        self.replace_range(0..len, bytes);
    }
}

object_struct!(NSMutableData);

impl INSData for NSMutableData { }

impl INSMutableData for NSMutableData { }

impl INSCopying for NSMutableData {
    type Output = NSData;
}

impl INSMutableCopying for NSMutableData {
    type Output = NSMutableData;
}

#[cfg(test)]
mod tests {
    use objc::Id;
    use INSObject;
    use super::{INSData, INSMutableData, NSData, NSMutableData};

    #[test]
    fn test_bytes() {
        let bytes = [3, 7, 16, 52, 112, 19];
        let data: Id<NSData> = INSData::with_bytes(&bytes);
        assert!(data.len() == bytes.len());
        assert!(data.bytes() == bytes);
    }

    #[test]
    fn test_no_bytes() {
        let data: Id<NSData> = INSObject::new();
        assert!(Some(data.bytes()).is_some());
    }

    #[test]
    fn test_bytes_mut() {
        let mut data: Id<NSMutableData> = INSData::with_bytes(&[7, 16]);
        data.bytes_mut()[0] = 3;
        assert!(data.bytes() == [3, 16]);
    }

    #[test]
    fn test_set_len() {
        let mut data: Id<NSMutableData> = INSData::with_bytes(&[7, 16]);
        data.set_len(4);
        assert!(data.len() == 4);
        assert!(data.bytes() == [7, 16, 0, 0]);

        data.set_len(1);
        assert!(data.len() == 1);
        assert!(data.bytes() == [7]);
    }

    #[test]
    fn test_append() {
        let mut data: Id<NSMutableData> = INSData::with_bytes(&[7, 16]);
        data.append(&[3, 52]);
        assert!(data.len() == 4);
        assert!(data.bytes() == [7, 16, 3, 52]);
    }

    #[test]
    fn test_replace() {
        let mut data: Id<NSMutableData> = INSData::with_bytes(&[7, 16]);
        data.replace_range(0..0, &[3]);
        assert!(data.bytes() == [3, 7, 16]);

        data.replace_range(1..2, &[52, 13]);
        assert!(data.bytes() == [3, 52, 13, 16]);

        data.replace_range(2..4, &[6]);
        assert!(data.bytes() == [3, 52, 6]);

        data.set_bytes(&[8, 17]);
        assert!(data.bytes() == [8, 17]);
    }
}
<|endoftext|>


<commit_before>#![cfg(test)]
use traits::Cell;
use traits::Coord;
use traits::Grid;
use traits::Engine;
use traits::Consumer;
use engine::Sequential;
use grid::nhood::VonNeumannNhood;
use grid::square::SquareGrid;

/// Implementation of [HPP model](https://en.wikipedia.org/wiki/HPP_model).
/// Assumes Von Nuemann's neighborhood.
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
enum Stage {
    Collision,
    Transport,
}

impl Default for Stage {
    fn default() -> Self {
        Stage::Collision
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
enum Direction {
    Up,
    Left,
    Right,
    Down,
}

impl Direction {
    fn opposite(&self) -> Self {

        match *self {
            Direction::Up => Direction::Down,
            Direction::Left => Direction::Right,
            Direction::Right => Direction::Left,
            Direction::Down => Direction::Up,
        }
    }

    fn perpendicular(&self) -> Self {

        match *self {
            Direction::Up => Direction::Left,
            Direction::Left => Direction::Down,
            Direction::Right => Direction::Up,
            Direction::Down => Direction::Right,
        }
    }
}

impl From<usize> for Direction {
    fn from(int: usize) -> Self {
        match int {
            0 => Direction::Up,
            1 => Direction::Left,
            2 => Direction::Right,
            3 => Direction::Down,
            i => panic!("No associated variant to number {}.", i),
        }
    }
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
struct HPP {
    particles: [bool; 4],
    stage: Stage,
    coord: (i32, i32),
}

impl Cell for HPP {
    type Coord = (i32, i32);

    fn step<'a, I>(&'a self, neighbors: I) -> Self
        where I: Iterator<Item = Option<&'a Self>>
    {

        match self.stage {
            Stage::Collision => self.collision(neighbors),
            Stage::Transport => self.transport(neighbors),
        }
    }

    fn with_coord<C: Coord>(coord: C) -> Self {
        HPP {
            stage: Stage::Collision,
            coord: (coord.x(), coord.y()),
            ..Default::default()
        }
    }

    fn coord(&self) -> &Self::Coord {
        &self.coord
    }

    fn set_coord<C: Coord>(&mut self, coord: &C) {
        self.coord = (coord.x(), coord.y());
    }
}

impl HPP {
    fn collision<'a, I>(&self, neighbors: I) -> Self
        where I: Iterator<Item = Option<&'a Self>>
    {

        let mut new = HPP { stage: Stage::Transport, ..Default::default() };

        for (neighbor, direction) in neighbors.zip(self.directions().iter()) {

            match neighbor {

                Some(neighbor) => {
                    let opposite = direction.opposite();
                    let head_on = self.particle(&direction) && neighbor.particle(&opposite) &&
                                  !self.particle(&direction.perpendicular()) &&
                                  !neighbor.particle(&opposite.perpendicular());

                    if head_on {
                        new.set_particle(&direction.perpendicular(), self.particle(&direction));
                    } else {
                        let particle = new.particle(&direction) || self.particle(&direction);
                        new.set_particle(&direction, particle);
                    }
                }
                // Rebound
                None => {
                    if self.particle(&direction) {
                        let opposite = direction.opposite();
                        new.set_particle(&opposite, true);
                    }
                }
            }
        }

        new
    }

    fn transport<'a, I>(&self, neighbors: I) -> Self
        where I: Iterator<Item = Option<&'a Self>>
    {

        let mut new = HPP { stage: Stage::Collision, ..Default::default() };

        for (neighbor, direction) in neighbors.zip(self.directions().iter()) {

            match neighbor {
                Some(neighbor) => {
                    let opposite = direction.opposite();

                    if neighbor.particle(&opposite) {
                        new.set_particle(&opposite, neighbor.particle(&opposite));
                    }
                }
                None => {
                    if self.particle(&direction) {
                        new.set_particle(&direction, true);
                    }
                }
            }
        }

        new
    }

    pub fn particle(&self, direction: &Direction) -> bool {

        match *direction {
            Direction::Up => self.particles[0],
            Direction::Left => self.particles[1],
            Direction::Right => self.particles[2],
            Direction::Down => self.particles[3],
        }
    }

    fn set_particle(&mut self, direction: &Direction, exists: bool) {

        match *direction {
            Direction::Up => self.particles[0] = exists,
            Direction::Left => self.particles[1] = exists,
            Direction::Right => self.particles[2] = exists,
            Direction::Down => self.particles[3] = exists,
        }
    }

    #[inline]
    pub fn directions(&self) -> [Direction; 4] {
        [Direction::Up, Direction::Left, Direction::Right, Direction::Down]
    }
}

#[derive(Debug)]
struct HPPRulesTestConsumer;

use test_helpers::to_cell;

impl HPPRulesTestConsumer {
    pub fn new() -> Self {
        HPPRulesTestConsumer {}
    }

    fn particles_count<C: Cell>(&self, cells: &Vec<C>, direction: &Direction) -> i32 {

        cells.iter()
            .map(|c| to_cell(c))
            .filter(|c: &HPP| c.particle(direction) == true)
            .count() as i32
    }

    fn find_cell<C: Cell>(&self, cells: &Vec<C>, x: i32, y: i32) -> HPP {

        assert!(cells.iter().any(|c| c.coord().x() == x && c.coord().y() == y));

        let found = cells.iter()
            .find(|c| c.coord().x() == x && c.coord().y() == y)
            .unwrap();

        to_cell(found)
    }

    fn test_collision<G: Grid>(&self, grid: &G) {

        let left_particle_count = self.particles_count(&grid.cells(), &Direction::Left);
        assert_eq!(left_particle_count, 0);

        let right_particle_count = self.particles_count(&grid.cells(), &Direction::Right);
        assert_eq!(right_particle_count, 2);

        let up_particles_count = self.particles_count(&grid.cells(), &Direction::Up);
        assert_eq!(up_particles_count, 1);

        let down_particles_count = self.particles_count(&grid.cells(), &Direction::Down);
        assert_eq!(down_particles_count, 1);

        let rebound_to_right = self.find_cell(&grid.cells(), 0, 1);
        assert_eq!(rebound_to_right.particle(&Direction::Right), true);

        let head_on_up = self.find_cell(&grid.cells(), 1, 0);
        assert_eq!(head_on_up.particle(&Direction::Up), true);

        let head_on_down = self.find_cell(&grid.cells(), 2, 0);
        assert_eq!(head_on_down.particle(&Direction::Down), true);
    }

    fn test_transport<G: Grid>(&self, grid: &G) {

        let simple_move_to_right = self.find_cell(&grid.cells(), 1, 2);
        assert_eq!(simple_move_to_right.particle(&Direction::Right), true);

        let move_to_right_after_rebound = self.find_cell(&grid.cells(), 1, 2);
        assert_eq!(move_to_right_after_rebound.particle(&Direction::Right),
                   true);

        let move_to_down_after_head_on = self.find_cell(&grid.cells(), 2, 1);
        assert_eq!(move_to_down_after_head_on.particle(&Direction::Down), true);

        let fixed_to_up_after_head_on = self.find_cell(&grid.cells(), 1, 0);
        assert_eq!(fixed_to_up_after_head_on.particle(&Direction::Up), true);
    }

    fn pretty_print<G: Grid>(&self, grid: &G) {
        println!("");

        for y in 0..3 {
            print!("|");

            for x in 0..3 {
                let cell = self.find_cell(grid.cells(), x, y);
                let directions = cell.directions();
                let maybe_particle = directions.iter().find(|d| cell.particle(d));

                let to_print = match maybe_particle {
                    Some(&Direction::Up) => " ^ |",
                    Some(&Direction::Left) => " < |",
                    Some(&Direction::Right) => " > |",
                    Some(&Direction::Down) => " v |",
                    None => " * |",
                };
                print!("{}", to_print);
            }

            println!("");
        }
    }
}

impl Consumer for HPPRulesTestConsumer {
    type Cell = HPP;

    fn consume<G: Grid>(&mut self, grid: &mut G) {
        assert_eq!(grid.cells().len(), 9);

        self.pretty_print(grid);

        // We are testing previous state.
        let first: HPP = to_cell(&grid.cells()[0]);

        match first.stage {
            Stage::Collision => self.test_transport(grid),
            Stage::Transport => self.test_collision(grid),
        }
    }
}

#[test]
fn test_rules() {
    // initial      collision    transport
    // | * > < |    | * ^ v |    | * ^ * |
    // | < * * | => | > * * | => | * > v |
    // | > * * |    | > * * |    | * > * |
    // 3x3 grid with 4 particles. There should be
    // one rebound, head-on collision and simple move.

    let left_particle = [false, true, false, false];
    let right_particle = [false, false, true, false];

    let cells = vec![
        HPP { stage: Stage::Collision, particles: right_particle, coord: (1, 0) },
        HPP { stage: Stage::Collision, particles: left_particle, coord: (2, 0) },
        HPP { stage: Stage::Collision, particles: left_particle, coord: (0, 1) },
        HPP { stage: Stage::Collision, particles: right_particle, coord: (0, 2) },
    ];

    let nhood = VonNeumannNhood::new();
    let mut grid: SquareGrid<HPP, _> = SquareGrid::new(3, 3, nhood);
    grid.set_cells(cells);

    let right_particles_count = grid.cells()
        .iter()
        .map(|c| to_cell(c))
        .filter(|c: &HPP| c.particle(&Direction::Right) == true)
        .count();
    assert_eq!(right_particles_count, 2);

    let consumer = HPPRulesTestConsumer::new();
    let mut engine = Sequential::new(grid, consumer);
    engine.run_times(2);
}

struct HPPSpreadTestConsumer {
    cur_y: i32,
    cur_direction: Direction,
}

impl HPPSpreadTestConsumer {
    pub fn new() -> Self {
        HPPSpreadTestConsumer {
            cur_y: 0,
            cur_direction: Direction::Down,
        }
    }

    fn particles_count<C: Cell>(&self, cells: &Vec<C>, direction: &Direction) -> i32 {

        cells.iter()
            .map(|c| to_cell(c))
            .filter(|c: &HPP| c.particle(direction) == true)
            .count() as i32
    }

    fn find_cell<C: Cell>(&self, cells: &Vec<C>, x: i32, y: i32) -> HPP {

        assert!(cells.iter().any(|c| c.coord().x() == x && c.coord().y() == y));

        let found = cells.iter()
            .find(|c| c.coord().x() == x && c.coord().y() == y)
            .unwrap();

        to_cell(found)
    }

    fn pretty_print<G: Grid>(&self, grid: &G) {
        println!("");

        for y in 0..5 {
            print!("|");

            for x in 0..5 {
                let cell = self.find_cell(grid.cells(), x, y);
                let directions = cell.directions();
                let maybe_particle = directions.iter().find(|d| cell.particle(d));

                let to_print = match maybe_particle {
                    Some(&Direction::Up) => " ^ |",
                    Some(&Direction::Left) => " < |",
                    Some(&Direction::Right) => " > |",
                    Some(&Direction::Down) => " v |",
                    None => " * |",
                };
                print!("{}", to_print);
            }

            println!("");
        }
    }

    fn test_collision<G: Grid>(&mut self, grid: &G) {

        if self.cur_y == 0 {
            self.cur_direction = Direction::Down;
        }

        let particles_count = self.particles_count(&grid.cells(), &self.cur_direction);
        assert_eq!(particles_count, 5);

        if self.cur_direction == Direction::Down {
            self.cur_y += 1;
        } else {
            self.cur_y -= 1;
        }
    }

    fn test_transport<G: Grid>(&mut self, grid: &G) {

        let particles_count = self.particles_count(&grid.cells(), &self.cur_direction);
        assert_eq!(particles_count, 5);

        assert!(grid.cells()
            .iter()
            .map(|c| to_cell(c))
            .filter(|c: &HPP| c.coord().y() == self.cur_y)
            .all(|c| c.particle(&self.cur_direction) == true));

        if self.cur_y == 4 {
            self.cur_direction = Direction::Up;
        }
    }
}

impl Consumer for HPPSpreadTestConsumer {
    type Cell = HPP;

    fn consume<G: Grid>(&mut self, grid: &mut G) {
        assert_eq!(grid.cells().len(), 25);

        self.pretty_print(grid);

        // We are testing previous state.
        let first: HPP = to_cell(&grid.cells()[0]);

        match first.stage {
            Stage::Collision => self.test_transport(grid),
            Stage::Transport => self.test_collision(grid),
        }
    }
}

#[test]
fn test_spread() {
    // initial          later
    // | v v v v v |    | * * * * * |
    // | * * * * * |    | v v v v v |
    // | * * * * * | => | * * * * * | => (so on)
    // | * * * * * |    | * * * * * |
    // | * * * * * |    | * * * * * |
    // 5x5 grid with 5 particles. Particles should move
    // to lower border then rebound, then move to upper and so on.

    let down_particle = [false, false, false, true];

    let mut cells = Vec::new();
    for x in 0..5 {
        cells.push(HPP {
            stage: Stage::Collision,
            particles: down_particle,
            coord: (x, 0),
        });
    }

    let nhood = VonNeumannNhood::new();
    let mut grid: SquareGrid<HPP, _> = SquareGrid::new(5, 5, nhood);
    grid.set_cells(cells);

    let consumer = HPPSpreadTestConsumer::new();
    let mut engine = Sequential::new(grid, consumer);
    // 2 phases * 10 full cycles = 20 times.
    engine.run_times(20);
}
<commit_msg>More consice index <-> dir mapping.<commit_after>#![cfg(test)]
use traits::Cell;
use traits::Coord;
use traits::Grid;
use traits::Engine;
use traits::Consumer;
use engine::Sequential;
use grid::nhood::VonNeumannNhood;
use grid::square::SquareGrid;

/// Implementation of [HPP model](https://en.wikipedia.org/wiki/HPP_model).
/// Assumes Von Nuemann's neighborhood.
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
enum Stage {
    Collision,
    Transport,
}

impl Default for Stage {
    fn default() -> Self {
        Stage::Collision
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
enum Direction {
    Up,
    Left,
    Right,
    Down,
}

impl Direction {
    fn opposite(&self) -> Self {

        match *self {
            Direction::Up => Direction::Down,
            Direction::Left => Direction::Right,
            Direction::Right => Direction::Left,
            Direction::Down => Direction::Up,
        }
    }

    fn perpendicular(&self) -> Self {

        match *self {
            Direction::Up => Direction::Left,
            Direction::Left => Direction::Down,
            Direction::Right => Direction::Up,
            Direction::Down => Direction::Right,
        }
    }
}

impl From<usize> for Direction {
    fn from(int: usize) -> Self {
        match int {
            0 => Direction::Up,
            1 => Direction::Left,
            2 => Direction::Right,
            3 => Direction::Down,
            i => panic!("No associated variant to number {}.", i),
        }
    }
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
struct HPP {
    particles: [bool; 4],
    stage: Stage,
    coord: (i32, i32),
}

impl Cell for HPP {
    type Coord = (i32, i32);

    fn step<'a, I>(&'a self, neighbors: I) -> Self
        where I: Iterator<Item = Option<&'a Self>>
    {

        match self.stage {
            Stage::Collision => self.collision(neighbors),
            Stage::Transport => self.transport(neighbors),
        }
    }

    fn with_coord<C: Coord>(coord: C) -> Self {
        HPP {
            stage: Stage::Collision,
            coord: (coord.x(), coord.y()),
            ..Default::default()
        }
    }

    fn coord(&self) -> &Self::Coord {
        &self.coord
    }

    fn set_coord<C: Coord>(&mut self, coord: &C) {
        self.coord = (coord.x(), coord.y());
    }
}

impl HPP {
    fn collision<'a, I>(&self, neighbors: I) -> Self
        where I: Iterator<Item = Option<&'a Self>>
    {

        let mut new = HPP { stage: Stage::Transport, ..Default::default() };

        for (neighbor, direction) in neighbors.zip(self.directions().iter()) {

            match neighbor {

                Some(neighbor) => {
                    let opposite = direction.opposite();
                    let head_on = self.particle(&direction) && neighbor.particle(&opposite) &&
                                  !self.particle(&direction.perpendicular()) &&
                                  !neighbor.particle(&opposite.perpendicular());

                    if head_on {
                        new.set_particle(&direction.perpendicular(), self.particle(&direction));
                    } else {
                        let particle = new.particle(&direction) || self.particle(&direction);
                        new.set_particle(&direction, particle);
                    }
                }
                // Rebound
                None => {
                    if self.particle(&direction) {
                        let opposite = direction.opposite();
                        new.set_particle(&opposite, true);
                    }
                }
            }
        }

        new
    }

    fn transport<'a, I>(&self, neighbors: I) -> Self
        where I: Iterator<Item = Option<&'a Self>>
    {

        let mut new = HPP { stage: Stage::Collision, ..Default::default() };

        for (neighbor, direction) in neighbors.zip(self.directions().iter()) {

            match neighbor {
                Some(neighbor) => {
                    let opposite = direction.opposite();

                    if neighbor.particle(&opposite) {
                        new.set_particle(&opposite, neighbor.particle(&opposite));
                    }
                }
                None => {
                    if self.particle(&direction) {
                        new.set_particle(&direction, true);
                    }
                }
            }
        }

        new
    }

    pub fn particle(&self, direction: &Direction) -> bool {
        let index = *direction as usize;
        self.particles[index]
    }

    fn set_particle(&mut self, direction: &Direction, exists: bool) {
        let index = *direction as usize;
        self.particles[index] = exists;
    }

    #[inline]
    pub fn directions(&self) -> [Direction; 4] {
        [Direction::Up, Direction::Left, Direction::Right, Direction::Down]
    }
}

#[derive(Debug)]
struct HPPRulesTestConsumer;

use test_helpers::to_cell;

impl HPPRulesTestConsumer {
    pub fn new() -> Self {
        HPPRulesTestConsumer {}
    }

    fn particles_count<C: Cell>(&self, cells: &Vec<C>, direction: &Direction) -> i32 {

        cells.iter()
            .map(|c| to_cell(c))
            .filter(|c: &HPP| c.particle(direction) == true)
            .count() as i32
    }

    fn find_cell<C: Cell>(&self, cells: &Vec<C>, x: i32, y: i32) -> HPP {

        assert!(cells.iter().any(|c| c.coord().x() == x && c.coord().y() == y));

        let found = cells.iter()
            .find(|c| c.coord().x() == x && c.coord().y() == y)
            .unwrap();

        to_cell(found)
    }

    fn test_collision<G: Grid>(&self, grid: &G) {

        let left_particle_count = self.particles_count(&grid.cells(), &Direction::Left);
        assert_eq!(left_particle_count, 0);

        let right_particle_count = self.particles_count(&grid.cells(), &Direction::Right);
        assert_eq!(right_particle_count, 2);

        let up_particles_count = self.particles_count(&grid.cells(), &Direction::Up);
        assert_eq!(up_particles_count, 1);

        let down_particles_count = self.particles_count(&grid.cells(), &Direction::Down);
        assert_eq!(down_particles_count, 1);

        let rebound_to_right = self.find_cell(&grid.cells(), 0, 1);
        assert_eq!(rebound_to_right.particle(&Direction::Right), true);

        let head_on_up = self.find_cell(&grid.cells(), 1, 0);
        assert_eq!(head_on_up.particle(&Direction::Up), true);

        let head_on_down = self.find_cell(&grid.cells(), 2, 0);
        assert_eq!(head_on_down.particle(&Direction::Down), true);
    }

    fn test_transport<G: Grid>(&self, grid: &G) {

        let simple_move_to_right = self.find_cell(&grid.cells(), 1, 2);
        assert_eq!(simple_move_to_right.particle(&Direction::Right), true);

        let move_to_right_after_rebound = self.find_cell(&grid.cells(), 1, 2);
        assert_eq!(move_to_right_after_rebound.particle(&Direction::Right),
                   true);

        let move_to_down_after_head_on = self.find_cell(&grid.cells(), 2, 1);
        assert_eq!(move_to_down_after_head_on.particle(&Direction::Down), true);

        let fixed_to_up_after_head_on = self.find_cell(&grid.cells(), 1, 0);
        assert_eq!(fixed_to_up_after_head_on.particle(&Direction::Up), true);
    }

    fn pretty_print<G: Grid>(&self, grid: &G) {
        println!("");

        for y in 0..3 {
            print!("|");

            for x in 0..3 {
                let cell = self.find_cell(grid.cells(), x, y);
                let directions = cell.directions();
                let maybe_particle = directions.iter().find(|d| cell.particle(d));

                let to_print = match maybe_particle {
                    Some(&Direction::Up) => " ^ |",
                    Some(&Direction::Left) => " < |",
                    Some(&Direction::Right) => " > |",
                    Some(&Direction::Down) => " v |",
                    None => " * |",
                };
                print!("{}", to_print);
            }

            println!("");
        }
    }
}

impl Consumer for HPPRulesTestConsumer {
    type Cell = HPP;

    fn consume<G: Grid>(&mut self, grid: &mut G) {
        assert_eq!(grid.cells().len(), 9);

        self.pretty_print(grid);

        // We are testing previous state.
        let first: HPP = to_cell(&grid.cells()[0]);

        match first.stage {
            Stage::Collision => self.test_transport(grid),
            Stage::Transport => self.test_collision(grid),
        }
    }
}

#[test]
fn test_rules() {
    // initial      collision    transport
    // | * > < |    | * ^ v |    | * ^ * |
    // | < * * | => | > * * | => | * > v |
    // | > * * |    | > * * |    | * > * |
    // 3x3 grid with 4 particles. There should be
    // one rebound, head-on collision and simple move.

    let left_particle = [false, true, false, false];
    let right_particle = [false, false, true, false];

    let cells = vec![
        HPP { stage: Stage::Collision, particles: right_particle, coord: (1, 0) },
        HPP { stage: Stage::Collision, particles: left_particle, coord: (2, 0) },
        HPP { stage: Stage::Collision, particles: left_particle, coord: (0, 1) },
        HPP { stage: Stage::Collision, particles: right_particle, coord: (0, 2) },
    ];

    let nhood = VonNeumannNhood::new();
    let mut grid: SquareGrid<HPP, _> = SquareGrid::new(3, 3, nhood);
    grid.set_cells(cells);

    let right_particles_count = grid.cells()
        .iter()
        .map(|c| to_cell(c))
        .filter(|c: &HPP| c.particle(&Direction::Right) == true)
        .count();
    assert_eq!(right_particles_count, 2);

    let consumer = HPPRulesTestConsumer::new();
    let mut engine = Sequential::new(grid, consumer);
    engine.run_times(2);
}

struct HPPSpreadTestConsumer {
    cur_y: i32,
    cur_direction: Direction,
}

impl HPPSpreadTestConsumer {
    pub fn new() -> Self {
        HPPSpreadTestConsumer {
            cur_y: 0,
            cur_direction: Direction::Down,
        }
    }

    fn particles_count<C: Cell>(&self, cells: &Vec<C>, direction: &Direction) -> i32 {

        cells.iter()
            .map(|c| to_cell(c))
            .filter(|c: &HPP| c.particle(direction) == true)
            .count() as i32
    }

    fn find_cell<C: Cell>(&self, cells: &Vec<C>, x: i32, y: i32) -> HPP {

        assert!(cells.iter().any(|c| c.coord().x() == x && c.coord().y() == y));

        let found = cells.iter()
            .find(|c| c.coord().x() == x && c.coord().y() == y)
            .unwrap();

        to_cell(found)
    }

    fn pretty_print<G: Grid>(&self, grid: &G) {
        println!("");

        for y in 0..5 {
            print!("|");

            for x in 0..5 {
                let cell = self.find_cell(grid.cells(), x, y);
                let directions = cell.directions();
                let maybe_particle = directions.iter().find(|d| cell.particle(d));

                let to_print = match maybe_particle {
                    Some(&Direction::Up) => " ^ |",
                    Some(&Direction::Left) => " < |",
                    Some(&Direction::Right) => " > |",
                    Some(&Direction::Down) => " v |",
                    None => " * |",
                };
                print!("{}", to_print);
            }

            println!("");
        }
    }

    fn test_collision<G: Grid>(&mut self, grid: &G) {

        if self.cur_y == 0 {
            self.cur_direction = Direction::Down;
        }

        let particles_count = self.particles_count(&grid.cells(), &self.cur_direction);
        assert_eq!(particles_count, 5);

        if self.cur_direction == Direction::Down {
            self.cur_y += 1;
        } else {
            self.cur_y -= 1;
        }
    }

    fn test_transport<G: Grid>(&mut self, grid: &G) {

        let particles_count = self.particles_count(&grid.cells(), &self.cur_direction);
        assert_eq!(particles_count, 5);

        assert!(grid.cells()
            .iter()
            .map(|c| to_cell(c))
            .filter(|c: &HPP| c.coord().y() == self.cur_y)
            .all(|c| c.particle(&self.cur_direction) == true));

        if self.cur_y == 4 {
            self.cur_direction = Direction::Up;
        }
    }
}

impl Consumer for HPPSpreadTestConsumer {
    type Cell = HPP;

    fn consume<G: Grid>(&mut self, grid: &mut G) {
        assert_eq!(grid.cells().len(), 25);

        self.pretty_print(grid);

        // We are testing previous state.
        let first: HPP = to_cell(&grid.cells()[0]);

        match first.stage {
            Stage::Collision => self.test_transport(grid),
            Stage::Transport => self.test_collision(grid),
        }
    }
}

#[test]
fn test_spread() {
    // initial          later
    // | v v v v v |    | * * * * * |
    // | * * * * * |    | v v v v v |
    // | * * * * * | => | * * * * * | => (so on)
    // | * * * * * |    | * * * * * |
    // | * * * * * |    | * * * * * |
    // 5x5 grid with 5 particles. Particles should move
    // to lower border then rebound, then move to upper and so on.

    let down_particle = [false, false, false, true];

    let mut cells = Vec::new();
    for x in 0..5 {
        cells.push(HPP {
            stage: Stage::Collision,
            particles: down_particle,
            coord: (x, 0),
        });
    }

    let nhood = VonNeumannNhood::new();
    let mut grid: SquareGrid<HPP, _> = SquareGrid::new(5, 5, nhood);
    grid.set_cells(cells);

    let consumer = HPPSpreadTestConsumer::new();
    let mut engine = Sequential::new(grid, consumer);
    // 2 phases * 10 full cycles = 20 times.
    engine.run_times(20);
}
<|endoftext|>


<commit_before>use crate::error::Error;
use crate::instance::{InstanceHandle, RunResult, State, TerminationDetails};
use crate::val::{UntypedRetVal, Val};
use crate::vmctx::{Vmctx, VmctxInternal};
use std::any::Any;
use std::future::Future;
use std::pin::Pin;

/// This is the same type defined by the `futures` library, but we don't need the rest of the
/// library for this purpose.
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;

/// A unique type that wraps a boxed future with a boxed return value.
///
/// Type and lifetime guarantees are maintained by `Vmctx::block_on` and `Instance::run_async`. The
/// user never sees this type.
struct YieldedFuture(BoxFuture<'static, ResumeVal>);

/// A unique type for a boxed return value. The user never sees this type.
pub struct ResumeVal(Box<dyn Any + Send + 'static>);

unsafe impl Send for ResumeVal {}

impl Vmctx {
    /// Block on the result of an `async` computation from an instance run by `Instance::run_async`.
    ///
    /// Lucet hostcalls are synchronous `extern "C" fn` functions called from WebAssembly. In that
    /// context, we cannot use `.await` directly because the hostcall is not `async`. While we could
    /// block on an executor using `futures::executor::block_on` or
    /// `tokio::runtime::Runtime::block_on`, that has two drawbacks:
    ///
    /// - If the Lucet instance was originally invoked from an async context, trying to block on the
    ///   same runtime will fail if the executor cannot be nested (all executors we know of have this
    ///   restriction).
    ///
    /// - The current OS thread would be blocked on the result of the computation, rather than being
    ///   able to run other async tasks while awaiting. This means an application will need more
    ///   threads than otherwise would be necessary.
    ///
    /// Instead, this block_on operator is designed to work only when called within an invocation
    /// of [`Instance::run_async`]. The `run_async` method executes instance code within a
    /// trampoline, itself running within an async context, making it possible to temporarily pause
    /// guest execution, jump back to the trampoline, and await there. The future given to block_on
    /// is in passed back to that trampoline, and runs on the same runtime that invoked
    /// `run_async`, avoiding problems of nesting, and allowing the current OS thread to continue
    /// performing other async work.
    ///
    /// Note that this method may only be used if `Instance::run_async` was used to run the VM,
    /// otherwise it will terminate the instance with `TerminationDetails::BlockOnNeedsAsync`.
    pub fn block_on<'a, R>(&'a self, f: impl Future<Output = R> + Send + 'a) -> R
    where
        R: Any + Send + 'static,
    {
        // Die if we aren't in Instance::run_async
        match self.instance().state {
            State::Running { async_context } => {
                if !async_context {
                    panic!(TerminationDetails::BlockOnNeedsAsync)
                }
            }
            _ => unreachable!("Access to vmctx implies instance is Running"),
        }
        // Wrap the Output of `f` as a boxed ResumeVal. Then, box the entire
        // async computation.
        let f = Box::pin(async move { ResumeVal(Box::new(f.await)) });
        // Change the lifetime of the async computation from `'a` to `'static.
        // We need to lie about this lifetime so that `YieldedFuture` may impl
        // `Any` and be passed through the yield. `Instance::run_async`
        // rehydrates this lifetime to be at most as long as the Vmctx's `'a`.
        // This is safe because the stack frame that `'a` is tied to gets
        // frozen in place as part of `self.yield_val_expecting_val`.
        let f = unsafe {
            std::mem::transmute::<BoxFuture<'a, ResumeVal>, BoxFuture<'static, ResumeVal>>(f)
        };
        // Wrap the computation in `YieldedFuture` so that
        // `Instance::run_async` can catch and run it.  We will get the
        // `ResumeVal` we applied to `f` above.
        self.yield_impl::<YieldedFuture, ResumeVal>(YieldedFuture(f), false);
        let ResumeVal(v) = self.take_resumed_val();
        // We may now downcast and unbox the returned Box<dyn Any> into an `R`
        // again.
        *v.downcast().expect("run_async broke invariant")
    }
}

/// This struct needs to be exposed publicly in order for the signature of a
/// "block_in_place" function to be writable, a concession we must make because
/// Rust does not have rank 2 types. To prevent the user from inspecting or
/// constructing the inside of this type, it is completely opaque.
pub struct Bounce<'a>(BounceInner<'a>);

enum BounceInner<'a> {
    Done(UntypedRetVal),
    More(BoxFuture<'a, ResumeVal>),
}

impl InstanceHandle {
    /// Run a WebAssembly function with arguments in the guest context at the given entrypoint.
    ///
    /// This method is similar to `Instance::run()`, but allows the Wasm program to invoke hostcalls
    /// that use `Vmctx::block_on` and provides the trampoline that `.await`s those futures on
    /// behalf of the guest.
    ///
    /// # `Vmctx` Restrictions
    ///
    /// This method permits the use of `Vmctx::block_on`, but disallows all other uses of `Vmctx::
    /// yield_val_expecting_val` and family (`Vmctx::yield_`, `Vmctx::yield_expecting_val`,
    /// `Vmctx::yield_val`).
    ///
    /// # Blocking thread
    ///
    /// The `wrap_blocking` argument is a function that is called with a closure that runs the Wasm
    /// program. Since Wasm may execute for an arbitrarily long time without `await`ing, we need to
    /// make sure that it runs on a thread that is allowed to block.
    ///
    /// This argument is designed with [`tokio::task::block_in_place`][tokio] in mind. The odd type
    /// is a concession to the fact that we don't have rank 2 types in Rust, and so must fall back
    /// to trait objects in order to be able to take an argument that is itself a function that
    /// takes a closure.
    ///
    /// In order to provide an appropriate function, you may have to wrap the library function in
    /// another closure so that the types are compatible. For example:
    ///
    /// ```no_run
    /// # async fn f() {
    /// # let instance: lucet_runtime_internals::instance::InstanceHandle = unimplemented!();
    /// fn block_in_place<F, R>(f: F) -> R
    /// where
    ///     F: FnOnce() -> R,
    /// {
    ///     // ...
    ///     # f()
    /// }
    ///
    /// instance.run_async("entrypoint", &[], |f| block_in_place(f)).await.unwrap();
    /// # }
    /// ```
    ///
    /// [tokio]: https://docs.rs/tokio/0.2.21/tokio/task/fn.block_in_place.html
    pub async fn run_async<'a, F>(
        &'a mut self,
        entrypoint: &'a str,
        args: &'a [Val],
        wrap_blocking: F,
    ) -> Result<UntypedRetVal, Error>
    where
        F: for<'b> Fn(&mut (dyn FnMut() -> Result<Bounce<'b>, Error>)) -> Result<Bounce<'b>, Error>,
    {
        if self.is_yielded() {
            return Err(Error::Unsupported(
                "cannot run_async a yielded instance".to_owned(),
            ));
        }

        // Store the ResumeVal here when we get it.
        let mut resume_val: Option<ResumeVal> = None;
        loop {
            // Run the WebAssembly program
            let bounce = wrap_blocking(&mut || {
                let run_result = if self.is_yielded() {
                    // A previous iteration of the loop stored the ResumeVal in
                    // `resume_val`, send it back to the guest ctx and continue
                    // running:
                    self.resume_with_val_impl(
                        resume_val
                            .take()
                            .expect("is_yielded implies resume_value is some"),
                        true,
                    )
                } else {
                    // This is the first iteration, call the entrypoint:
                    let func = self.module.get_export_func(entrypoint)?;
                    self.run_func(func, args, true)
                };
                match run_result? {
                    RunResult::Returned(rval) => {
                        // Finished running, return UntypedReturnValue
                        return Ok(Bounce(BounceInner::Done(rval)));
                    }
                    RunResult::Yielded(yval) => {
                        // Check if the yield came from Vmctx::block_on:
                        if yval.is::<YieldedFuture>() {
                            let YieldedFuture(future) = *yval.downcast::<YieldedFuture>().unwrap();
                            // Rehydrate the lifetime from `'static` to `'a`, which
                            // is morally the same lifetime as was passed into
                            // `Vmctx::block_on`.
                            Ok(Bounce(BounceInner::More(future as BoxFuture<'a, ResumeVal>)))
                        } else {
                            // Any other yielded value is not supported - die with an error.
                            Err(Error::Unsupported(
                                "cannot yield anything besides a future in Instance::run_async"
                                    .to_owned(),
                            ))
                        }
                    }
                }
            })?;
            match bounce {
                Bounce(BounceInner::Done(rval)) => return Ok(rval),
                Bounce(BounceInner::More(fut)) => {
                    // await on the computation. Store its result in
                    // `resume_val`.
                    resume_val = Some(fut.await);
                    // Now we want to `Instance::resume_with_val` and start
                    // this cycle over.
                }
            }
        }
    }
}
<commit_msg>rustfmt<commit_after>use crate::error::Error;
use crate::instance::{InstanceHandle, RunResult, State, TerminationDetails};
use crate::val::{UntypedRetVal, Val};
use crate::vmctx::{Vmctx, VmctxInternal};
use std::any::Any;
use std::future::Future;
use std::pin::Pin;

/// This is the same type defined by the `futures` library, but we don't need the rest of the
/// library for this purpose.
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;

/// A unique type that wraps a boxed future with a boxed return value.
///
/// Type and lifetime guarantees are maintained by `Vmctx::block_on` and `Instance::run_async`. The
/// user never sees this type.
struct YieldedFuture(BoxFuture<'static, ResumeVal>);

/// A unique type for a boxed return value. The user never sees this type.
pub struct ResumeVal(Box<dyn Any + Send + 'static>);

unsafe impl Send for ResumeVal {}

impl Vmctx {
    /// Block on the result of an `async` computation from an instance run by `Instance::run_async`.
    ///
    /// Lucet hostcalls are synchronous `extern "C" fn` functions called from WebAssembly. In that
    /// context, we cannot use `.await` directly because the hostcall is not `async`. While we could
    /// block on an executor using `futures::executor::block_on` or
    /// `tokio::runtime::Runtime::block_on`, that has two drawbacks:
    ///
    /// - If the Lucet instance was originally invoked from an async context, trying to block on the
    ///   same runtime will fail if the executor cannot be nested (all executors we know of have this
    ///   restriction).
    ///
    /// - The current OS thread would be blocked on the result of the computation, rather than being
    ///   able to run other async tasks while awaiting. This means an application will need more
    ///   threads than otherwise would be necessary.
    ///
    /// Instead, this block_on operator is designed to work only when called within an invocation
    /// of [`Instance::run_async`]. The `run_async` method executes instance code within a
    /// trampoline, itself running within an async context, making it possible to temporarily pause
    /// guest execution, jump back to the trampoline, and await there. The future given to block_on
    /// is in passed back to that trampoline, and runs on the same runtime that invoked
    /// `run_async`, avoiding problems of nesting, and allowing the current OS thread to continue
    /// performing other async work.
    ///
    /// Note that this method may only be used if `Instance::run_async` was used to run the VM,
    /// otherwise it will terminate the instance with `TerminationDetails::BlockOnNeedsAsync`.
    pub fn block_on<'a, R>(&'a self, f: impl Future<Output = R> + Send + 'a) -> R
    where
        R: Any + Send + 'static,
    {
        // Die if we aren't in Instance::run_async
        match self.instance().state {
            State::Running { async_context } => {
                if !async_context {
                    panic!(TerminationDetails::BlockOnNeedsAsync)
                }
            }
            _ => unreachable!("Access to vmctx implies instance is Running"),
        }
        // Wrap the Output of `f` as a boxed ResumeVal. Then, box the entire
        // async computation.
        let f = Box::pin(async move { ResumeVal(Box::new(f.await)) });
        // Change the lifetime of the async computation from `'a` to `'static.
        // We need to lie about this lifetime so that `YieldedFuture` may impl
        // `Any` and be passed through the yield. `Instance::run_async`
        // rehydrates this lifetime to be at most as long as the Vmctx's `'a`.
        // This is safe because the stack frame that `'a` is tied to gets
        // frozen in place as part of `self.yield_val_expecting_val`.
        let f = unsafe {
            std::mem::transmute::<BoxFuture<'a, ResumeVal>, BoxFuture<'static, ResumeVal>>(f)
        };
        // Wrap the computation in `YieldedFuture` so that
        // `Instance::run_async` can catch and run it.  We will get the
        // `ResumeVal` we applied to `f` above.
        self.yield_impl::<YieldedFuture, ResumeVal>(YieldedFuture(f), false);
        let ResumeVal(v) = self.take_resumed_val();
        // We may now downcast and unbox the returned Box<dyn Any> into an `R`
        // again.
        *v.downcast().expect("run_async broke invariant")
    }
}

/// This struct needs to be exposed publicly in order for the signature of a
/// "block_in_place" function to be writable, a concession we must make because
/// Rust does not have rank 2 types. To prevent the user from inspecting or
/// constructing the inside of this type, it is completely opaque.
pub struct Bounce<'a>(BounceInner<'a>);

enum BounceInner<'a> {
    Done(UntypedRetVal),
    More(BoxFuture<'a, ResumeVal>),
}

impl InstanceHandle {
    /// Run a WebAssembly function with arguments in the guest context at the given entrypoint.
    ///
    /// This method is similar to `Instance::run()`, but allows the Wasm program to invoke hostcalls
    /// that use `Vmctx::block_on` and provides the trampoline that `.await`s those futures on
    /// behalf of the guest.
    ///
    /// # `Vmctx` Restrictions
    ///
    /// This method permits the use of `Vmctx::block_on`, but disallows all other uses of `Vmctx::
    /// yield_val_expecting_val` and family (`Vmctx::yield_`, `Vmctx::yield_expecting_val`,
    /// `Vmctx::yield_val`).
    ///
    /// # Blocking thread
    ///
    /// The `wrap_blocking` argument is a function that is called with a closure that runs the Wasm
    /// program. Since Wasm may execute for an arbitrarily long time without `await`ing, we need to
    /// make sure that it runs on a thread that is allowed to block.
    ///
    /// This argument is designed with [`tokio::task::block_in_place`][tokio] in mind. The odd type
    /// is a concession to the fact that we don't have rank 2 types in Rust, and so must fall back
    /// to trait objects in order to be able to take an argument that is itself a function that
    /// takes a closure.
    ///
    /// In order to provide an appropriate function, you may have to wrap the library function in
    /// another closure so that the types are compatible. For example:
    ///
    /// ```no_run
    /// # async fn f() {
    /// # let instance: lucet_runtime_internals::instance::InstanceHandle = unimplemented!();
    /// fn block_in_place<F, R>(f: F) -> R
    /// where
    ///     F: FnOnce() -> R,
    /// {
    ///     // ...
    ///     # f()
    /// }
    ///
    /// instance.run_async("entrypoint", &[], |f| block_in_place(f)).await.unwrap();
    /// # }
    /// ```
    ///
    /// [tokio]: https://docs.rs/tokio/0.2.21/tokio/task/fn.block_in_place.html
    pub async fn run_async<'a, F>(
        &'a mut self,
        entrypoint: &'a str,
        args: &'a [Val],
        wrap_blocking: F,
    ) -> Result<UntypedRetVal, Error>
    where
        F: for<'b> Fn(&mut (dyn FnMut() -> Result<Bounce<'b>, Error>)) -> Result<Bounce<'b>, Error>,
    {
        if self.is_yielded() {
            return Err(Error::Unsupported(
                "cannot run_async a yielded instance".to_owned(),
            ));
        }

        // Store the ResumeVal here when we get it.
        let mut resume_val: Option<ResumeVal> = None;
        loop {
            // Run the WebAssembly program
            let bounce = wrap_blocking(&mut || {
                let run_result = if self.is_yielded() {
                    // A previous iteration of the loop stored the ResumeVal in
                    // `resume_val`, send it back to the guest ctx and continue
                    // running:
                    self.resume_with_val_impl(
                        resume_val
                            .take()
                            .expect("is_yielded implies resume_value is some"),
                        true,
                    )
                } else {
                    // This is the first iteration, call the entrypoint:
                    let func = self.module.get_export_func(entrypoint)?;
                    self.run_func(func, args, true)
                };
                match run_result? {
                    RunResult::Returned(rval) => {
                        // Finished running, return UntypedReturnValue
                        return Ok(Bounce(BounceInner::Done(rval)));
                    }
                    RunResult::Yielded(yval) => {
                        // Check if the yield came from Vmctx::block_on:
                        if yval.is::<YieldedFuture>() {
                            let YieldedFuture(future) = *yval.downcast::<YieldedFuture>().unwrap();
                            // Rehydrate the lifetime from `'static` to `'a`, which
                            // is morally the same lifetime as was passed into
                            // `Vmctx::block_on`.
                            Ok(Bounce(BounceInner::More(
                                future as BoxFuture<'a, ResumeVal>,
                            )))
                        } else {
                            // Any other yielded value is not supported - die with an error.
                            Err(Error::Unsupported(
                                "cannot yield anything besides a future in Instance::run_async"
                                    .to_owned(),
                            ))
                        }
                    }
                }
            })?;
            match bounce {
                Bounce(BounceInner::Done(rval)) => return Ok(rval),
                Bounce(BounceInner::More(fut)) => {
                    // await on the computation. Store its result in
                    // `resume_val`.
                    resume_val = Some(fut.await);
                    // Now we want to `Instance::resume_with_val` and start
                    // this cycle over.
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::sync::Arc;

use buffer::BufferResource;
use descriptor_set::layout_def::PipelineLayoutDesc;
use descriptor_set::layout_def::DescriptorSetDesc;
use descriptor_set::layout_def::DescriptorWrite;
use descriptor_set::layout_def::DescriptorBind;
use descriptor_set::pool::DescriptorPool;
use device::Device;

use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// An actual descriptor set with the resources that are binded to it.
pub struct DescriptorSet<S> {
    set: vk::DescriptorSet,
    pool: Arc<DescriptorPool>,
    layout: Arc<DescriptorSetLayout<S>>,
}

impl<S> DescriptorSet<S> where S: DescriptorSetDesc {
    ///
    /// # Panic
    ///
    /// - Panicks if the pool and the layout were not created from the same `Device`.
    ///
    pub fn new(pool: &Arc<DescriptorPool>, layout: &Arc<DescriptorSetLayout<S>>, init: S::Init)
               -> Result<Arc<DescriptorSet<S>>, OomError>
    {
        unsafe {
            let set = try!(DescriptorSet::uninitialized(pool, layout));
            set.unchecked_write(layout.description().decode_init(init));
            Ok(set)
        }
    }

    ///
    /// # Panic
    ///
    /// - Panicks if the pool and the layout were not created from the same `Device`.
    ///
    // FIXME: this has to check whether there's still enough room in the pool
    pub unsafe fn uninitialized(pool: &Arc<DescriptorPool>, layout: &Arc<DescriptorSetLayout<S>>)
                                -> Result<Arc<DescriptorSet<S>>, OomError>
    {
        assert_eq!(&**pool.device() as *const Device, &*layout.device as *const Device);

        let vk = pool.device().pointers();

        let set = {
            let infos = vk::DescriptorSetAllocateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
                pNext: ptr::null(),
                descriptorPool: pool.internal_object(),
                descriptorSetCount: 1,
                pSetLayouts: &layout.layout,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.AllocateDescriptorSets(pool.device().internal_object(), &infos,
                                                        &mut output)));
            output
        };

        Ok(Arc::new(DescriptorSet {
            set: set,
            pool: pool.clone(),
            layout: layout.clone(),
        }))
    }

    /// Modifies a descriptor set.
    ///
    /// The parameter depends on your implementation of `DescriptorSetDesc`.
    ///
    /// This function trusts the implementation of `DescriptorSetDesc` when it comes to making sure
    /// that the correct resource type is written to the correct descriptor.
    pub fn write(&self, write: S::Write) {
        let write = self.layout.description().decode_write(write);
        unsafe { self.unchecked_write(write); }
    }

    /// Modifies a descriptor set without checking that the writes are correct.
    pub unsafe fn unchecked_write(&self, write: Vec<DescriptorWrite>) {
        let vk = self.pool.device().pointers();

        // FIXME: store resources in the descriptor set so that they aren't destroyed

        // TODO: the architecture of this function is going to be tricky

        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let buffer_descriptors = write.iter().enumerate().map(|(num, write)| {
            match write.content {
                DescriptorBind::UniformBuffer(ref buffer) => {
                    Some(vk::DescriptorBufferInfo {
                        buffer: buffer.internal_object(),
                        offset: 0,      // FIXME: allow buffer slices
                        range: buffer.size() as u64,       // FIXME: allow buffer slices
                    })
                },
            }
        }).collect::<Vec<_>>();

        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let vk_writes = write.iter().enumerate().map(|(num, write)| {
            vk::WriteDescriptorSet {
                sType: vk::STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
                pNext: ptr::null(),
                dstSet: self.set,
                dstBinding: write.binding,
                dstArrayElement: write.array_element,
                descriptorCount: 1,
                descriptorType: vk::DESCRIPTOR_TYPE_UNIFORM_BUFFER,     // FIXME:
                pImageInfo: ptr::null(),        // FIXME:
                pBufferInfo: if let Some(ref b) = buffer_descriptors[num] { b } else { ptr::null() },
                pTexelBufferView: ptr::null(),      // FIXME:
            }
        }).collect::<Vec<_>>();

        if !vk_writes.is_empty() {
            vk.UpdateDescriptorSets(self.pool.device().internal_object(),
                                    vk_writes.len() as u32, vk_writes.as_ptr(), 0, ptr::null());
        }
    }
}

unsafe impl<S> VulkanObject for DescriptorSet<S> {
    type Object = vk::DescriptorSet;

    #[inline]
    fn internal_object(&self) -> vk::DescriptorSet {
        self.set
    }
}

impl<S> Drop for DescriptorSet<S> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.pool.device().pointers();
            vk.FreeDescriptorSets(self.pool.device().internal_object(),
                                  self.pool.internal_object(), 1, &self.set);
        }
    }
}

/// Implemented on all `DescriptorSet` objects. Hides the template parameters.
pub unsafe trait AbstractDescriptorSet: ::VulkanObjectU64 {}
unsafe impl<S> AbstractDescriptorSet for DescriptorSet<S> {}

/// Describes the layout of all descriptors within a descriptor set.
pub struct DescriptorSetLayout<S> {
    layout: vk::DescriptorSetLayout,
    device: Arc<Device>,
    description: S,
}

impl<S> DescriptorSetLayout<S> where S: DescriptorSetDesc {
    pub fn new(device: &Arc<Device>, description: S)
               -> Result<Arc<DescriptorSetLayout<S>>, OomError>
    {
        let vk = device.pointers();

        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let bindings = description.descriptors().into_iter().map(|desc| {
            vk::DescriptorSetLayoutBinding {
                binding: desc.binding,
                descriptorType: desc.ty.vk_enum(),
                descriptorCount: desc.array_count,
                stageFlags: desc.stages.into(),
                pImmutableSamplers: ptr::null(),        // FIXME: not yet implemented
            }
        }).collect::<Vec<_>>();

        let layout = unsafe {
            let infos = vk::DescriptorSetLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                bindingCount: bindings.len() as u32,
                pBindings: bindings.as_ptr(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateDescriptorSetLayout(device.internal_object(), &infos,
                                                           ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(DescriptorSetLayout {
            layout: layout,
            device: device.clone(),
            description: description,
        }))
    }

    #[inline]
    pub fn description(&self) -> &S {
        &self.description
    }
}

unsafe impl<S> VulkanObject for DescriptorSetLayout<S> {
    type Object = vk::DescriptorSetLayout;

    #[inline]
    fn internal_object(&self) -> vk::DescriptorSetLayout {
        self.layout
    }
}

impl<S> Drop for DescriptorSetLayout<S> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyDescriptorSetLayout(self.device.internal_object(), self.layout, ptr::null());
        }
    }
}

/// Implemented on all `DescriptorSetLayout` objects. Hides the template parameters.
pub unsafe trait AbstractDescriptorSetLayout: ::VulkanObjectU64 {}
unsafe impl<S> AbstractDescriptorSetLayout for DescriptorSetLayout<S> {}

/// A collection of `DescriptorSetLayout` structs.
// TODO: push constants.
pub struct PipelineLayout<P> {
    device: Arc<Device>,
    layout: vk::PipelineLayout,
    description: P,
    layouts: Vec<Arc<AbstractDescriptorSetLayout>>,     // TODO: is it necessary to keep the layouts alive? check the specs
}

impl<P> PipelineLayout<P> where P: PipelineLayoutDesc {
    /// Creates a new `PipelineLayout`.
    pub fn new(device: &Arc<Device>, description: P, layouts: P::DescriptorSetLayouts)
               -> Result<Arc<PipelineLayout<P>>, OomError>
    {
        let vk = device.pointers();

        let layouts = description.decode_descriptor_set_layouts(layouts);
        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let layouts_ids = layouts.iter().map(|l| {
            // FIXME: check that they belong to the same device
            ::VulkanObjectU64::internal_object(&**l)
        }).collect::<Vec<_>>();

        let layout = unsafe {
            let infos = vk::PipelineLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                setLayoutCount: layouts_ids.len() as u32,
                pSetLayouts: layouts_ids.as_ptr(),
                pushConstantRangeCount: 0,      // TODO: unimplemented
                pPushConstantRanges: ptr::null(),    // TODO: unimplemented
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreatePipelineLayout(device.internal_object(), &infos,
                                                      ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(PipelineLayout {
            device: device.clone(),
            layout: layout,
            description: description,
            layouts: layouts,
        }))
    }

    #[inline]
    pub fn description(&self) -> &P {
        &self.description
    }
}

unsafe impl<P> VulkanObject for PipelineLayout<P> {
    type Object = vk::PipelineLayout;

    #[inline]
    fn internal_object(&self) -> vk::PipelineLayout {
        self.layout
    }
}

impl<P> Drop for PipelineLayout<P> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyDescriptorSetLayout(self.device.internal_object(), self.layout, ptr::null());
        }
    }
}
<commit_msg>Writing a descriptor set requires &mut<commit_after>use std::mem;
use std::ptr;
use std::sync::Arc;

use buffer::BufferResource;
use descriptor_set::layout_def::PipelineLayoutDesc;
use descriptor_set::layout_def::DescriptorSetDesc;
use descriptor_set::layout_def::DescriptorWrite;
use descriptor_set::layout_def::DescriptorBind;
use descriptor_set::pool::DescriptorPool;
use device::Device;

use OomError;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

/// An actual descriptor set with the resources that are binded to it.
pub struct DescriptorSet<S> {
    set: vk::DescriptorSet,
    pool: Arc<DescriptorPool>,
    layout: Arc<DescriptorSetLayout<S>>,
}

impl<S> DescriptorSet<S> where S: DescriptorSetDesc {
    ///
    /// # Panic
    ///
    /// - Panicks if the pool and the layout were not created from the same `Device`.
    ///
    pub fn new(pool: &Arc<DescriptorPool>, layout: &Arc<DescriptorSetLayout<S>>, init: S::Init)
               -> Result<Arc<DescriptorSet<S>>, OomError>
    {
        unsafe {
            let mut set = try!(DescriptorSet::uninitialized(pool, layout));
            Arc::get_mut(&mut set).unwrap().unchecked_write(layout.description().decode_init(init));
            Ok(set)
        }
    }

    ///
    /// # Panic
    ///
    /// - Panicks if the pool and the layout were not created from the same `Device`.
    ///
    // FIXME: this has to check whether there's still enough room in the pool
    pub unsafe fn uninitialized(pool: &Arc<DescriptorPool>, layout: &Arc<DescriptorSetLayout<S>>)
                                -> Result<Arc<DescriptorSet<S>>, OomError>
    {
        assert_eq!(&**pool.device() as *const Device, &*layout.device as *const Device);

        let vk = pool.device().pointers();

        let set = {
            let infos = vk::DescriptorSetAllocateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
                pNext: ptr::null(),
                descriptorPool: pool.internal_object(),
                descriptorSetCount: 1,
                pSetLayouts: &layout.layout,
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.AllocateDescriptorSets(pool.device().internal_object(), &infos,
                                                        &mut output)));
            output
        };

        Ok(Arc::new(DescriptorSet {
            set: set,
            pool: pool.clone(),
            layout: layout.clone(),
        }))
    }

    /// Modifies a descriptor set.
    ///
    /// The parameter depends on your implementation of `DescriptorSetDesc`.
    ///
    /// This function trusts the implementation of `DescriptorSetDesc` when it comes to making sure
    /// that the correct resource type is written to the correct descriptor.
    pub fn write(&mut self, write: S::Write) {
        let write = self.layout.description().decode_write(write);
        unsafe { self.unchecked_write(write); }
    }

    /// Modifies a descriptor set without checking that the writes are correct.
    pub unsafe fn unchecked_write(&mut self, write: Vec<DescriptorWrite>) {
        let vk = self.pool.device().pointers();

        // FIXME: store resources in the descriptor set so that they aren't destroyed

        // TODO: the architecture of this function is going to be tricky

        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let buffer_descriptors = write.iter().enumerate().map(|(num, write)| {
            match write.content {
                DescriptorBind::UniformBuffer(ref buffer) => {
                    Some(vk::DescriptorBufferInfo {
                        buffer: buffer.internal_object(),
                        offset: 0,      // FIXME: allow buffer slices
                        range: buffer.size() as u64,       // FIXME: allow buffer slices
                    })
                },
            }
        }).collect::<Vec<_>>();

        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let vk_writes = write.iter().enumerate().map(|(num, write)| {
            vk::WriteDescriptorSet {
                sType: vk::STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
                pNext: ptr::null(),
                dstSet: self.set,
                dstBinding: write.binding,
                dstArrayElement: write.array_element,
                descriptorCount: 1,
                descriptorType: vk::DESCRIPTOR_TYPE_UNIFORM_BUFFER,     // FIXME:
                pImageInfo: ptr::null(),        // FIXME:
                pBufferInfo: if let Some(ref b) = buffer_descriptors[num] { b } else { ptr::null() },
                pTexelBufferView: ptr::null(),      // FIXME:
            }
        }).collect::<Vec<_>>();

        if !vk_writes.is_empty() {
            vk.UpdateDescriptorSets(self.pool.device().internal_object(),
                                    vk_writes.len() as u32, vk_writes.as_ptr(), 0, ptr::null());
        }
    }
}

unsafe impl<S> VulkanObject for DescriptorSet<S> {
    type Object = vk::DescriptorSet;

    #[inline]
    fn internal_object(&self) -> vk::DescriptorSet {
        self.set
    }
}

impl<S> Drop for DescriptorSet<S> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.pool.device().pointers();
            vk.FreeDescriptorSets(self.pool.device().internal_object(),
                                  self.pool.internal_object(), 1, &self.set);
        }
    }
}

/// Implemented on all `DescriptorSet` objects. Hides the template parameters.
pub unsafe trait AbstractDescriptorSet: ::VulkanObjectU64 {}
unsafe impl<S> AbstractDescriptorSet for DescriptorSet<S> {}

/// Describes the layout of all descriptors within a descriptor set.
pub struct DescriptorSetLayout<S> {
    layout: vk::DescriptorSetLayout,
    device: Arc<Device>,
    description: S,
}

impl<S> DescriptorSetLayout<S> where S: DescriptorSetDesc {
    pub fn new(device: &Arc<Device>, description: S)
               -> Result<Arc<DescriptorSetLayout<S>>, OomError>
    {
        let vk = device.pointers();

        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let bindings = description.descriptors().into_iter().map(|desc| {
            vk::DescriptorSetLayoutBinding {
                binding: desc.binding,
                descriptorType: desc.ty.vk_enum(),
                descriptorCount: desc.array_count,
                stageFlags: desc.stages.into(),
                pImmutableSamplers: ptr::null(),        // FIXME: not yet implemented
            }
        }).collect::<Vec<_>>();

        let layout = unsafe {
            let infos = vk::DescriptorSetLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                bindingCount: bindings.len() as u32,
                pBindings: bindings.as_ptr(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateDescriptorSetLayout(device.internal_object(), &infos,
                                                           ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(DescriptorSetLayout {
            layout: layout,
            device: device.clone(),
            description: description,
        }))
    }

    #[inline]
    pub fn description(&self) -> &S {
        &self.description
    }
}

unsafe impl<S> VulkanObject for DescriptorSetLayout<S> {
    type Object = vk::DescriptorSetLayout;

    #[inline]
    fn internal_object(&self) -> vk::DescriptorSetLayout {
        self.layout
    }
}

impl<S> Drop for DescriptorSetLayout<S> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyDescriptorSetLayout(self.device.internal_object(), self.layout, ptr::null());
        }
    }
}

/// Implemented on all `DescriptorSetLayout` objects. Hides the template parameters.
pub unsafe trait AbstractDescriptorSetLayout: ::VulkanObjectU64 {}
unsafe impl<S> AbstractDescriptorSetLayout for DescriptorSetLayout<S> {}

/// A collection of `DescriptorSetLayout` structs.
// TODO: push constants.
pub struct PipelineLayout<P> {
    device: Arc<Device>,
    layout: vk::PipelineLayout,
    description: P,
    layouts: Vec<Arc<AbstractDescriptorSetLayout>>,     // TODO: is it necessary to keep the layouts alive? check the specs
}

impl<P> PipelineLayout<P> where P: PipelineLayoutDesc {
    /// Creates a new `PipelineLayout`.
    pub fn new(device: &Arc<Device>, description: P, layouts: P::DescriptorSetLayouts)
               -> Result<Arc<PipelineLayout<P>>, OomError>
    {
        let vk = device.pointers();

        let layouts = description.decode_descriptor_set_layouts(layouts);
        // TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
        let layouts_ids = layouts.iter().map(|l| {
            // FIXME: check that they belong to the same device
            ::VulkanObjectU64::internal_object(&**l)
        }).collect::<Vec<_>>();

        let layout = unsafe {
            let infos = vk::PipelineLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                setLayoutCount: layouts_ids.len() as u32,
                pSetLayouts: layouts_ids.as_ptr(),
                pushConstantRangeCount: 0,      // TODO: unimplemented
                pPushConstantRanges: ptr::null(),    // TODO: unimplemented
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreatePipelineLayout(device.internal_object(), &infos,
                                                      ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(PipelineLayout {
            device: device.clone(),
            layout: layout,
            description: description,
            layouts: layouts,
        }))
    }

    #[inline]
    pub fn description(&self) -> &P {
        &self.description
    }
}

unsafe impl<P> VulkanObject for PipelineLayout<P> {
    type Object = vk::PipelineLayout;

    #[inline]
    fn internal_object(&self) -> vk::PipelineLayout {
        self.layout
    }
}

impl<P> Drop for PipelineLayout<P> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyDescriptorSetLayout(self.device.internal_object(), self.layout, ptr::null());
        }
    }
}
<|endoftext|>


<commit_before>extern crate timely;
extern crate interactive;

use std::time::{Instant, Duration};

use timely::synchronization::Sequencer;
use interactive::{Manager, Command, Query, Rule, Plan};

use interactive::plan::join::Join;
use interactive::plan::project::Project;

type Value = usize;

fn main() {

    let mut args = std::env::args();
    args.next();

    timely::execute_from_args(args, |worker| {

        let timer = Instant::now();
        let mut manager = Manager::new();
        let mut sequencer = Some(Sequencer::<Command<Value>>::new(worker, Instant::now()));

        if worker.index() == 0 {

            let edges = (0 .. 100).map(|x| vec![x, (x+1)%100]).collect::<Vec<_>>();

            sequencer.as_mut().map(|x| x.push(Command::CreateInput("edges".to_string(), edges)));
            worker.step();
            sequencer.as_mut().map(|x| x.push(Command::AdvanceTime(1)));
            worker.step();
            sequencer.as_mut().map(|x| x.push(Command::Query(
                Query {
                    rules: vec![Rule {
                        name: "fof".to_string(),
                        plan: Plan::source("edges").join(Plan::source("edges"), vec![(0,1)])
                                                   .project(vec![1,2])
                                                   .inspect("fof"),
                    }]
                }
            )));
            worker.step();
            sequencer.as_mut().map(|x| x.push(Command::AdvanceTime(2)));
            worker.step();
            sequencer.as_mut().map(|x| x.push(Command::CloseInput("edges".to_string())));
            worker.step();
            sequencer.as_mut().map(|x| x.push(Command::Shutdown));
        }

        let mut shutdown = false;

        while !shutdown {

            if let Some(command) = sequencer.as_mut().unwrap().next() {
                println!("{:?}\tExecuting {:#?}", timer.elapsed(), command);
                if command == Command::Shutdown {
                    shutdown = true;
                    sequencer = None;
                }
                command.execute(&mut manager, worker);
            }

            worker.step();
        }

    }).expect("Timely computation did not exit cleanly");
}
<commit_msg>remove worker.step()<commit_after>extern crate timely;
extern crate interactive;

use timely::synchronization::Sequencer;
use interactive::{Manager, Command, Query, Rule, Plan};

fn main() {

    let mut args = std::env::args();
    args.next();

    timely::execute_from_args(args, |worker| {

        let timer = ::std::time::Instant::now();
        let mut manager = Manager::new();
        let mut sequencer = Some(Sequencer::new(worker, timer));

        if worker.index() == 0 {

            let edges = (0 .. 100).map(|x| vec![x, (x+1)%100]).collect::<Vec<_>>();

            sequencer.as_mut().map(|x| x.push(Command::CreateInput("edges".to_string(), edges)));
            sequencer.as_mut().map(|x| x.push(Command::AdvanceTime(1)));
            sequencer.as_mut().map(|x| x.push(Command::Query(
                Query {
                    rules: vec![Rule {
                        name: "fof".to_string(),
                        plan: Plan::source("edges").join(Plan::source("edges"), vec![(0,1)])
                                                   .project(vec![1,2])
                                                   .inspect("fof"),
                    }]
                }
            )));
            sequencer.as_mut().map(|x| x.push(Command::AdvanceTime(2)));
            sequencer.as_mut().map(|x| x.push(Command::CloseInput("edges".to_string())));
            sequencer.as_mut().map(|x| x.push(Command::Query(
                Query {
                    rules: vec![Rule {
                        name: "fof2".to_string(),
                        plan: Plan::source("fof").join(Plan::source("fof"), vec![(0,1)])
                                                   .project(vec![1,2])
                                                   .inspect("fof2"),
                    }]
                }
            )));
            sequencer.as_mut().map(|x| x.push(Command::Shutdown));
        }

        let mut shutdown = false;

        while !shutdown {

            if let Some(command) = sequencer.as_mut().unwrap().next() {
                println!("{:?}\tExecuting {:?}", timer.elapsed(), command);
                if command == Command::Shutdown {
                    shutdown = true;
                    sequencer = None;
                }
                command.execute(&mut manager, worker);
            }

            worker.step();
        }

    }).expect("Timely computation did not exit cleanly");
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2016 Alexander Samoilov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

// Algebraic Data Type (ADT) `GridVariant` use case using Rust `enum`
// should be more robust than `std::Any`

#![feature(plugin)]
#![plugin(docopt_macros)]
#![feature(custom_derive)]

extern crate rustc_serialize;
extern crate docopt;
extern crate num;

use docopt::Docopt;
use std::io;
use std::fs::File;
use std::io::Read;
use std::io::Cursor;
use std::mem;
use std::iter::FromIterator;

extern crate endianness;
use endianness::{ByteOrder, read_u32, read_f32, read_f64};
use num::Num;

use std::fmt::Debug;

type c32 = num::Complex<f32>;
type c64 = num::Complex<f64>;

struct Grid<T> {
    points: Vec<Vec<T>>,
}

#[derive(Debug)]
enum GridType { f32_t, f64_t, c32_t, c64_t, }

enum GridVariant {
    Grid_f32(Box<Grid<f32>>),
    Grid_f64(Box<Grid<f64>>),
    Grid_c32(Box<Grid<c32>>),
    Grid_c64(Box<Grid<c64>>),
}

trait GridTrait<T> {
    // a constructor
    fn new() -> Grid<T> { Grid {points: Vec::new() } }

    // unformatted read from the buffer
    fn read(&mut self,
            byte_order: ByteOrder,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>);
}

impl GridTrait<f32> for Grid<f32> {
    fn read(&mut self,
            byte_order: ByteOrder,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>) {
        self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start = (i * ysize + j) * mem::size_of::<f32>();
                let val = read_f32(&grid_buf[start .. ], byte_order);
                val.unwrap()
            }))
        }));
    }
}

impl GridTrait<c32> for Grid<c32> {
    fn read(&mut self,
            byte_order: ByteOrder,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>) {
         self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start_1 = (i * ysize + j) * 2 * mem::size_of::<f32>();
                let start_2 = start_1 + mem::size_of::<f32>(); // next f32 number
                let (real, imag) =
                    (read_f32(&grid_buf[start_1 .. ], byte_order),
                     read_f32(&grid_buf[start_2 .. ], byte_order));
                c32::new(real.unwrap(), imag.unwrap())
            }))
        }));
    }
}

impl GridTrait<f64> for Grid<f64> {
    fn read(&mut self,
            byte_order: ByteOrder,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>) {
         self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start = (i * ysize + j) * mem::size_of::<f64>();
                let val = read_f64(&grid_buf[start .. ], byte_order);
                val.unwrap()
            }))
        }));
    }
}

// the Docopt usage string.
// https://github.com/docopt/docopt.rs
docopt!(Args derive Debug, "
Read grid gen.

Usage:
  gridgen read <file> [--verbose] [-d <dpath>]

Options:
  -h --help       Show this screen.
  -d --data-path  path to input data.
  --verbose       Be verbose.

");

fn read_from_file(namein: &String, data_path: &String, verbose: bool) -> Result<(ByteOrder, GridType, u32, u32, Vec<u8>), io::Error> {
    //let name = format!("{}/{}.bin", data_path, namein);
    let name = format!("{}/{}", data_path, namein);
    let mut try_open = File::open(name.clone());
    let mut file = match try_open {
        Ok(f) => f,
        Err(err) => {panic!("\"{}\" : {}\n",name, err)}
    };
    let mut buf = [0u8; 4];
    if verbose {
        println!("read from file: {}", name);
    }
    try!(file.read(&mut buf[0..1]));
    let is_big_endian = unsafe {mem::transmute::<[u8; 1], u8>([buf[0]])} == 1;
    let byte_order = if is_big_endian {ByteOrder::BigEndian} else {ByteOrder::LittleEndian};

    try!(file.read(&mut buf[..]));
    let prec = read_u32(&buf[..], byte_order).unwrap();

    try!(file.read(&mut buf[..]));
    let typ = read_u32(&buf[..], byte_order).unwrap();

    try!(file.read(&mut buf[..]));
    let xe = read_u32(&buf[..], byte_order).unwrap();

    try!(file.read(&mut buf[..]));
    let ye = read_u32(&buf[..], byte_order).unwrap();

    if verbose {
        println!("prec: {} (1 - Single Precision, 2 - Double Precision) typ: {} (1 - Real Values, 2 - Complex Values) xe: {} ye: {}",
                 prec, typ, xe, ye);
    }

    let (grid_type, grid_elem_size) =
        match (prec,typ) {
            (1,1) => (GridType::f32_t, mem::size_of::<f32>()),
            (1,2) => (GridType::c32_t, mem::size_of::<c32>()),
            (2,1) => (GridType::f64_t, mem::size_of::<f64>()),
            (2,2) => (GridType::c64_t, mem::size_of::<c64>()),
            (_,_) => panic!("illegal combination of prec: {} typ: {}", prec, typ)
        };
    let grid_sz = (xe * ye) as usize;
    let mut grid_buf = Vec::new();
    let sz = file.read_to_end(&mut grid_buf).unwrap();
    if sz != (grid_sz * grid_elem_size) {
        panic!("corrupted grid sz: {} xe*ye: {}", sz, xe * ye);
    }

    Ok((byte_order, grid_type, xe, ye, grid_buf))
}

fn dump_grid<T: std::fmt::Display>(grid_name: &str, grid: &Grid<T>) {
    println!("-I- dumping grid: {}", grid_name);
    let points = &grid.points;
    for i in 0 .. points.len() {
        let row = &points[i];
        for j in 0 .. row.len() {
            let p = &points[i][j] ; // as c64;
            println!("{} [{}][{}] = {:}", grid_name, i, j, p /*.to_string()*/);
        }
    }
}

fn count_nnz<T: Num>(grid: &Grid<T>) -> (usize, usize) {
    let points = &grid.points;
    let mut nnz = 0;
    for i in 0 .. points.len() {
        let row = &points[i];
        for j in 0 .. row.len() {
            let p = &points[i][j];
            if !p.is_zero() {
                nnz += 1;
            }
        }
    }
    (nnz, points.len() * points[0].len())
}

fn count_nnz_functional_way<T: Num>(grid: &Grid<T>) -> (usize, usize) {
    let points = &grid.points;
    let mut nnz = points.iter().fold(0, |sum, row| {
        let incr = {
            row.iter().fold(0, |c, v| if v.is_zero() {c} else {c+1} )
        };
        sum + incr
    } );
    (nnz, points.len() * points[0].len())
}

fn main() {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

    if args.flag_verbose {
        println!("{:?}", args);
        println!("input file name: {:?}", args.arg_file);
    }

    let fname = args.arg_file;
    let dpath = args.arg_dpath;
    let (byte_order, grid_type, xe, ye, grid_buf) = read_from_file(&fname, &dpath, args.flag_verbose).unwrap();

    let mut mask_grid =
        match grid_type {
            GridType::f32_t => {
                let mut f32_grid = Box::new(Grid::<f32>::new());
                (*f32_grid).read(byte_order, xe as usize, ye as usize, &grid_buf);
                GridVariant::Grid_f32(f32_grid)
            },
            GridType::c32_t => {
                let mut c32_grid = Box::new(Grid::<c32>::new());
                (*c32_grid).read(byte_order, xe as usize, ye as usize, &grid_buf);
                GridVariant::Grid_c32(c32_grid)
            },
            _ => panic!("not yet implemented for grid type: {:?}", grid_type)
        };

    match mask_grid {
        GridVariant::Grid_f32(agrid) => //dump_grid("f32_grid", &*agrid),
        {
          let (nnz, total) = count_nnz_functional_way(&*agrid);
          println!("nnz for f32 grid: {:} total: {:} ratio: {:.3}%",
                    nnz, total, (nnz as f64 / total as f64)* 100.0);
        }

        GridVariant::Grid_c32(agrid) => dump_grid("c32_grid", &*agrid),
        _ => panic!("not yet implemented")
    }

}
<commit_msg>`grid_bb_indices` - bounding box indices for the grid.<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016 Alexander Samoilov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

// Algebraic Data Type (ADT) `GridVariant` use case using Rust `enum`
// should be more robust than `std::Any`

#![feature(plugin)]
#![plugin(docopt_macros)]
#![feature(custom_derive)]

extern crate rustc_serialize;
extern crate docopt;
extern crate num;

use docopt::Docopt;
use std::io;
use std::fs::File;
use std::io::Read;
use std::io::Cursor;
use std::mem;
use std::iter::FromIterator;

extern crate endianness;
use endianness::{ByteOrder, read_u32, read_f32, read_f64};
use num::Num;

use std::fmt::Debug;

type c32 = num::Complex<f32>;
type c64 = num::Complex<f64>;

struct Grid<T> {
    points: Vec<Vec<T>>,
}

#[derive(Debug)]
enum GridType { f32_t, f64_t, c32_t, c64_t, }

enum GridVariant {
    Grid_f32(Box<Grid<f32>>),
    Grid_f64(Box<Grid<f64>>),
    Grid_c32(Box<Grid<c32>>),
    Grid_c64(Box<Grid<c64>>),
}

trait GridTrait<T> {
    // a constructor
    fn new() -> Grid<T> { Grid {points: Vec::new() } }

    // unformatted read from the buffer
    fn read(&mut self,
            byte_order: ByteOrder,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>);
}

impl GridTrait<f32> for Grid<f32> {
    fn read(&mut self,
            byte_order: ByteOrder,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>) {
        self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start = (i * ysize + j) * mem::size_of::<f32>();
                let val = read_f32(&grid_buf[start .. ], byte_order);
                val.unwrap()
            }))
        }));
    }
}

impl GridTrait<c32> for Grid<c32> {
    fn read(&mut self,
            byte_order: ByteOrder,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>) {
         self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start_1 = (i * ysize + j) * 2 * mem::size_of::<f32>();
                let start_2 = start_1 + mem::size_of::<f32>(); // next f32 number
                let (real, imag) =
                    (read_f32(&grid_buf[start_1 .. ], byte_order),
                     read_f32(&grid_buf[start_2 .. ], byte_order));
                c32::new(real.unwrap(), imag.unwrap())
            }))
        }));
    }
}

impl GridTrait<f64> for Grid<f64> {
    fn read(&mut self,
            byte_order: ByteOrder,
            xsize: usize,
            ysize: usize,
            grid_buf: &Vec<u8>) {
         self.points = Vec::from_iter((0..xsize).map(|i| {
            Vec::from_iter((0..ysize).map(|j| {
                let start = (i * ysize + j) * mem::size_of::<f64>();
                let val = read_f64(&grid_buf[start .. ], byte_order);
                val.unwrap()
            }))
        }));
    }
}

// the Docopt usage string.
// https://github.com/docopt/docopt.rs
docopt!(Args derive Debug, "
Read grid gen.

Usage:
  gridgen read <file> [--verbose] [-d <dpath>]

Options:
  -h --help       Show this screen.
  -d --data-path  path to input data.
  --verbose       Be verbose.

");

fn read_from_file(namein: &String, data_path: &String, verbose: bool) -> Result<(ByteOrder, GridType, u32, u32, Vec<u8>), io::Error> {
    //let name = format!("{}/{}.bin", data_path, namein);
    let name = format!("{}/{}", data_path, namein);
    let mut try_open = File::open(name.clone());
    let mut file = match try_open {
        Ok(f) => f,
        Err(err) => {panic!("\"{}\" : {}\n",name, err)}
    };
    let mut buf = [0u8; 4];
    if verbose {
        println!("read from file: {}", name);
    }
    try!(file.read(&mut buf[0..1]));
    let is_big_endian = unsafe {mem::transmute::<[u8; 1], u8>([buf[0]])} == 1;
    let byte_order = if is_big_endian {ByteOrder::BigEndian} else {ByteOrder::LittleEndian};

    try!(file.read(&mut buf[..]));
    let prec = read_u32(&buf[..], byte_order).unwrap();

    try!(file.read(&mut buf[..]));
    let typ = read_u32(&buf[..], byte_order).unwrap();

    try!(file.read(&mut buf[..]));
    let xe = read_u32(&buf[..], byte_order).unwrap();

    try!(file.read(&mut buf[..]));
    let ye = read_u32(&buf[..], byte_order).unwrap();

    if verbose {
        println!("prec: {} (1 - Single Precision, 2 - Double Precision) typ: {} (1 - Real Values, 2 - Complex Values) xe: {} ye: {}",
                 prec, typ, xe, ye);
    }

    let (grid_type, grid_elem_size) =
        match (prec,typ) {
            (1,1) => (GridType::f32_t, mem::size_of::<f32>()),
            (1,2) => (GridType::c32_t, mem::size_of::<c32>()),
            (2,1) => (GridType::f64_t, mem::size_of::<f64>()),
            (2,2) => (GridType::c64_t, mem::size_of::<c64>()),
            (_,_) => panic!("illegal combination of prec: {} typ: {}", prec, typ)
        };
    let grid_sz = (xe * ye) as usize;
    let mut grid_buf = Vec::new();
    let sz = file.read_to_end(&mut grid_buf).unwrap();
    if sz != (grid_sz * grid_elem_size) {
        panic!("corrupted grid sz: {} xe*ye: {}", sz, xe * ye);
    }

    Ok((byte_order, grid_type, xe, ye, grid_buf))
}

fn dump_grid<T: std::fmt::Display>(grid_name: &str, grid: &Grid<T>) {
    println!("-I- dumping grid: {}", grid_name);
    let points = &grid.points;
    for i in 0 .. points.len() {
        let row = &points[i];
        for j in 0 .. row.len() {
            let p = &points[i][j] ; // as c64;
            println!("{} [{}][{}] = {:}", grid_name, i, j, p /*.to_string()*/);
        }
    }
}

fn count_nnz<T: Num>(grid: &Grid<T>) -> (usize, usize) {
    let points = &grid.points;
    let mut nnz = 0;
    for i in 0 .. points.len() {
        let row = &points[i];
        for j in 0 .. row.len() {
            let p = &points[i][j];
            if !p.is_zero() {
                nnz += 1;
            }
        }
    }
    (nnz, points.len() * points[0].len())
}

fn count_nnz_functional_way<T: Num>(grid: &Grid<T>) -> (usize, usize) {
    let points = &grid.points;
    let mut nnz = points.iter().fold(0, |sum, row| {
        let incr = {
            row.iter().fold(0, |c, v| if v.is_zero() {c} else {c+1} )
        };
        sum + incr
    } );
    (nnz, points.len() * points[0].len())
}

// bounding box indices for the grid
fn grid_bb_indices<T: Num>(grid: &Grid<T>) -> ((isize, isize), (isize, isize)) {
    let points = &grid.points;
    let ((mut llx,mut lly), (mut urx,mut ury)) =
        ((std::isize::MAX,std::isize::MAX),
         (std::isize::MIN,std::isize::MIN));
    for i in 0 .. points.len() {
        let row = &points[i];
        for j in 0 .. row.len() {
            let p = &points[i][j];
            if !p.is_zero() {
                let ii = i as isize;
                let jj = j as isize;
                if llx > ii { llx = ii; }
                if lly > jj { lly = jj; }
                if urx < ii { urx = ii; }
                if ury < jj { ury = jj; }
            }
        }
    }

    ((llx,lly), (urx,ury))
}

fn main() {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

    if args.flag_verbose {
        println!("{:?}", args);
        println!("input file name: {:?}", args.arg_file);
    }

    let fname = args.arg_file;
    let dpath = args.arg_dpath;
    let (byte_order, grid_type, xe, ye, grid_buf) = read_from_file(&fname, &dpath, args.flag_verbose).unwrap();

    let mut mask_grid =
        match grid_type {
            GridType::f32_t => {
                let mut f32_grid = Box::new(Grid::<f32>::new());
                (*f32_grid).read(byte_order, xe as usize, ye as usize, &grid_buf);
                GridVariant::Grid_f32(f32_grid)
            },
            GridType::c32_t => {
                let mut c32_grid = Box::new(Grid::<c32>::new());
                (*c32_grid).read(byte_order, xe as usize, ye as usize, &grid_buf);
                GridVariant::Grid_c32(c32_grid)
            },
            _ => panic!("not yet implemented for grid type: {:?}", grid_type)
        };

    match mask_grid {
        GridVariant::Grid_f32(agrid) => //dump_grid("f32_grid", &*agrid),
        {
          let (nnz, total) = count_nnz_functional_way(&*agrid);
          println!("nnz for f32 grid: {:} total: {:} ratio: {:.3}%",
                    nnz, total, (nnz as f64 / total as f64)* 100.0);
          let bb = grid_bb_indices(&*agrid);
          let ((llx,lly), (urx,ury)) = bb;
          println!("a bounding box indices for the grid mask: {:?} x_extent: {:} y_extent: {:}",
                   bb, urx-llx, ury-lly);
        }

        GridVariant::Grid_c32(agrid) => dump_grid("c32_grid", &*agrid),
        _ => panic!("not yet implemented")
    }

}
<|endoftext|>