<commit_before>// Reference: http://www.redblobgames.com/pathfinding/a-star/introduction.html

use std::collections::BinaryHeap;
use std::collections::HashMap;
use std::cmp::Ordering;
use std::cmp;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct Position {
    pub x: usize,
    pub y: usize
}

// Used to maintain a priority queue of positions to explore.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
struct PositionPriority {
    minimum_cost: usize,
    position: Position,
}

// The priority queue depends on `Ord`.
impl Ord for PositionPriority {
    // Reverse the comparison so the position with the lowest cost is
    // explored first.
    fn cmp(&self, other: &PositionPriority) -> Ordering {
        other.minimum_cost.cmp(&self.minimum_cost)
    }
}

impl PartialOrd for PositionPriority {
    fn partial_cmp(&self, other: &PositionPriority) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

#[inline]
fn min_distance_heuristic(p1: Position, p2: Position) -> usize {
    let x_diff = match p1.x > p2.x {
        true => p1.x - p2.x,
        false => p2.x - p1.x,
    };
    let y_diff = match p1.y > p2.y {
        true => p1.y - p2.y,
        false => p2.y - p1.y,
    };

    x_diff + y_diff
}

#[inline]
fn neighbours(grid: &Vec<Vec<char>>, pos: Position) -> Vec<Position> {
    let mut v = Vec::new();

    if pos.x > 0 && grid[pos.y][pos.x-1] == ' ' {
        v.push(Position{x: pos.x-1, y: pos.y});
    }
    if pos.x + 1 < grid[pos.y].len() && grid[pos.y][pos.x+1] == ' ' {
        v.push(Position{x: pos.x+1, y: pos.y});
    }

    if pos.y > 0 && pos.x < grid[pos.y-1].len() && grid[pos.y-1][pos.x] == ' ' {
        v.push(Position{x: pos.x, y: pos.y-1});
    }
    if pos.y + 1 < grid.len() &&
       pos.x < grid[pos.y+1].len() &&
       grid[pos.y+1][pos.x] == ' ' {
        v.push(Position{x: pos.x, y: pos.y+1});
    }
    v
}

/// Generate the optimal path from start to goal given a mapping from positions
/// to the position that lead to that position.
#[inline]
fn reconstruct(came_from: &HashMap<Position, Position>,
               start: Position,
               goal: Position) -> Vec<Position> {
    let mut current = goal;
    let mut path = vec![current];
    while current != start {
        current = came_from[&current];
        path.push(current);
    }
    path.reverse();
    path
}

/// Find the optimal path from a starting position to a goal position. Return
/// None if no path is possible. The input grid is a 2-dimensional grid of
/// characters. Any character other than a space is considered an impassable
/// obstacle.
///
/// # Examples
///
/// ```
/// use bestpath::{find_path, Position};
///
/// let grid = vec![vec![' ', '*', '*', ' '],
///                 vec![' ', ' ', ' ', '*'],
///                 vec!['*', '*', ' ', ' '],
///                 vec![' ', '*', ' ', ' ']];
/// assert_eq!(Some(vec![Position{x: 0, y: 0},
///                      Position{x: 0, y: 1},
///                      Position{x: 1, y: 1},
///                      Position{x: 2, y: 1},
///                      Position{x: 2, y: 2}]),
///            find_path(&grid, Position{x: 0, y: 0}, Position{x: 2, y: 2}));
/// assert_eq!(None,
///            find_path(&grid, Position{x: 0, y: 0}, Position{x: 3, y: 0}));
/// ```
#[inline]
pub fn find_path(grid: &Vec<Vec<char>>, start: Position, goal: Position)
        -> Option<Vec<Position>>  {
    let mut frontier = BinaryHeap::new();
    frontier.push(PositionPriority { minimum_cost: 0, position: start });

    let mut came_from = HashMap::new();
    let mut cost_so_far = HashMap::new();
    cost_so_far.insert(start, 0);

    while let Some(PositionPriority { minimum_cost, position }) = frontier.pop() {
        if position == goal {
            return Some(reconstruct(&came_from, start, goal));
        }
        let cost = cost_so_far[&position];

        for next_position in neighbours(grid, position) {
            let new_cost = cost + 1;
            if let Some(existing_cost) = cost_so_far.get(&next_position) {
                if new_cost >= *existing_cost {
                    continue;
                }
            }
            cost_so_far.insert(next_position, new_cost);
            frontier.push(PositionPriority {
                minimum_cost: new_cost +
                    min_distance_heuristic(goal, next_position),
                position: next_position });
            came_from.insert(next_position, position);
        }
    }
    None
}

/// Generate a copy of the given grid with the path filled in. The starting
/// position is shown with a '@' , the goal postiion with a 'X' and all other
/// points on the path with a 'o'.
///
/// # Examples
///
/// ```
/// use bestpath::{find_path, format_path_map, Position};
///
/// let grid = vec![vec![' ', ' ', ' ', ' '],
///                 vec![' ', '*', ' ', '*'],
///                 vec!['*', '*', ' ', ' '],
///                 vec![' ', '*', ' ', ' ']];
/// let path = find_path(&grid,
///                      Position{x: 0, y: 1},
///                      Position{x: 3, y: 2}).unwrap();
/// assert_eq!(vec![vec!['o', 'o', 'o', ' '],
///                 vec!['@', '*', 'o', '*'],
///                 vec!['*', '*', 'o', 'X'],
///                 vec![' ', '*', ' ', ' ']],
///            format_path_map(&grid, &path));
/// ```
#[inline]
pub fn format_path_map(grid: &Vec<Vec<char>>, path: &Vec<Position>)
        -> Vec<Vec<char>> {
    let mut m = grid.clone();
    let last_path = path.len() - 1;
    for (i, p) in path.iter().enumerate() {
        m[p.y][p.x] = match i {
            0 => '@',
            _ if i == last_path => 'X',
            _ => 'o',
        }
    }
    m
}

#[allow(dead_code)]
fn print_grid(grid: &Vec<Vec<char>>) {
    println!("");
    for row in grid {
        for ch in row {
            print!(" {} ", ch);
        }
        println!("");
    }
}

#[test]
fn no_path() {
    let map =
        vec![vec![' ', ' ', '█', ' ', ' ', ' ', ' '],
             vec!['█', '█', ' ', ' ', '█', '█', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█'],
             vec![' ', ' ', ' ', '█', ' ', '█', ' '],
             vec!['█', ' ', ' ', ' ', ' ', '█', ' '],
             vec![' ', '█', '█', '█', '█', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map, Position { x: 0, y: 0}, Position { x: 6, y: 6});
    assert_eq!(None, path);
}

#[test]
fn multiple_complex_paths_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['█', '█', ' ', '█', '█', ' ', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█'],
             vec![' ', '█', ' ', '█', ' ', ' ', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█'],
             vec![' ', '█', '█', ' ', ' ', ' ', ' '],
             vec!['█', '█', ' ', ' ', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', '█', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 6, y: 8}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', 'o', 'o', 'o', 'o', 'o', ' '],
             vec!['█', '█', ' ', '█', '█', 'o', ' '],
             vec![' ', '█', ' ', '█', '█', 'o', '█'],
             vec![' ', '█', ' ', '█', ' ', 'o', ' '],
             vec![' ', '█', ' ', '█', '█', 'o', '█'],
             vec![' ', '█', '█', ' ', ' ', 'o', 'o'],
             vec!['█', '█', ' ', ' ', '█', '█', 'o'],
             vec![' ', ' ', ' ', ' ', '█', '█', 'o'],
             vec![' ', ' ', ' ', ' ', '█', ' ', 'X']],
        path_map);
}

#[test]
fn verticle_map() {
    let map =
        vec![vec![' '],
             vec![' '],
             vec![' '],
             vec![' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 0, y: 3}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@'],
             vec!['o'],
             vec!['o'],
             vec!['X']],
        path_map);
}

#[test]
fn horizontal_map() {
    let map =
        vec![vec![' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 3, y: 0}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', 'o', 'o', 'X']],
        path_map);
}

#[test]
fn straight_diagonal_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 6, y: 6}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(13, path.len())  // There are many equivalent paths.
}

#[test]
fn single_walled_path_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['█', '█', '█', '█', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', '█', '█', '█', '█', '█', '█'],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['█', '█', '█', '█', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 0, y: 6}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['█', '█', '█', '█', '█', '█', 'o'],
             vec!['o', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['o', '█', '█', '█', '█', '█', '█'],
             vec!['o', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['█', '█', '█', '█', '█', '█', 'o'],
             vec!['X', 'o', 'o', 'o', 'o', 'o', 'o']],
        path_map);
}

#[test]
fn spiral_wall_path_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', '█', '█', '█', '█', '█', '█', '█'],
             vec![' ', '█', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', '█', ' ', '█', '█', '█', '█', ' '],
             vec![' ', '█', ' ', '█', ' ', ' ', '█', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█', ' '],
             vec![' ', '█', ' ', ' ', ' ', ' ', '█', ' '],
             vec![' ', '█', '█', '█', '█', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 4, y: 4}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['o', '█', '█', '█', '█', '█', '█', '█'],
             vec!['o', '█', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['o', '█', 'o', '█', '█', '█', '█', 'o'],
             vec!['o', '█', 'o', '█', 'X', 'o', '█', 'o'],
             vec!['o', '█', 'o', '█', '█', 'o', '█', 'o'],
             vec!['o', '█', 'o', 'o', 'o', 'o', '█', 'o'],
             vec!['o', '█', '█', '█', '█', '█', '█', 'o'],
             vec!['o', 'o', 'o', 'o', 'o', 'o', 'o', 'o']],
        path_map);
}
<commit_msg>Fix a >80 col line<commit_after>// Reference: http://www.redblobgames.com/pathfinding/a-star/introduction.html

use std::collections::BinaryHeap;
use std::collections::HashMap;
use std::cmp::Ordering;
use std::cmp;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct Position {
    pub x: usize,
    pub y: usize
}

// Used to maintain a priority queue of positions to explore.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
struct PositionPriority {
    minimum_cost: usize,
    position: Position,
}

// The priority queue depends on `Ord`.
impl Ord for PositionPriority {
    // Reverse the comparison so the position with the lowest cost is
    // explored first.
    fn cmp(&self, other: &PositionPriority) -> Ordering {
        other.minimum_cost.cmp(&self.minimum_cost)
    }
}

impl PartialOrd for PositionPriority {
    fn partial_cmp(&self, other: &PositionPriority) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

#[inline]
fn min_distance_heuristic(p1: Position, p2: Position) -> usize {
    let x_diff = match p1.x > p2.x {
        true => p1.x - p2.x,
        false => p2.x - p1.x,
    };
    let y_diff = match p1.y > p2.y {
        true => p1.y - p2.y,
        false => p2.y - p1.y,
    };

    x_diff + y_diff
}

#[inline]
fn neighbours(grid: &Vec<Vec<char>>, pos: Position) -> Vec<Position> {
    let mut v = Vec::new();

    if pos.x > 0 && grid[pos.y][pos.x-1] == ' ' {
        v.push(Position{x: pos.x-1, y: pos.y});
    }
    if pos.x + 1 < grid[pos.y].len() && grid[pos.y][pos.x+1] == ' ' {
        v.push(Position{x: pos.x+1, y: pos.y});
    }

    if pos.y > 0 && pos.x < grid[pos.y-1].len() && grid[pos.y-1][pos.x] == ' ' {
        v.push(Position{x: pos.x, y: pos.y-1});
    }
    if pos.y + 1 < grid.len() &&
       pos.x < grid[pos.y+1].len() &&
       grid[pos.y+1][pos.x] == ' ' {
        v.push(Position{x: pos.x, y: pos.y+1});
    }
    v
}

/// Generate the optimal path from start to goal given a mapping from positions
/// to the position that lead to that position.
#[inline]
fn reconstruct(came_from: &HashMap<Position, Position>,
               start: Position,
               goal: Position) -> Vec<Position> {
    let mut current = goal;
    let mut path = vec![current];
    while current != start {
        current = came_from[&current];
        path.push(current);
    }
    path.reverse();
    path
}

/// Find the optimal path from a starting position to a goal position. Return
/// None if no path is possible. The input grid is a 2-dimensional grid of
/// characters. Any character other than a space is considered an impassable
/// obstacle.
///
/// # Examples
///
/// ```
/// use bestpath::{find_path, Position};
///
/// let grid = vec![vec![' ', '*', '*', ' '],
///                 vec![' ', ' ', ' ', '*'],
///                 vec!['*', '*', ' ', ' '],
///                 vec![' ', '*', ' ', ' ']];
/// assert_eq!(Some(vec![Position{x: 0, y: 0},
///                      Position{x: 0, y: 1},
///                      Position{x: 1, y: 1},
///                      Position{x: 2, y: 1},
///                      Position{x: 2, y: 2}]),
///            find_path(&grid, Position{x: 0, y: 0}, Position{x: 2, y: 2}));
/// assert_eq!(None,
///            find_path(&grid, Position{x: 0, y: 0}, Position{x: 3, y: 0}));
/// ```
#[inline]
pub fn find_path(grid: &Vec<Vec<char>>, start: Position, goal: Position)
        -> Option<Vec<Position>>  {
    let mut frontier = BinaryHeap::new();
    frontier.push(PositionPriority { minimum_cost: 0, position: start });

    let mut came_from = HashMap::new();
    let mut cost_so_far = HashMap::new();
    cost_so_far.insert(start, 0);

    while let Some(PositionPriority { minimum_cost, position }) =
            frontier.pop() {
        if position == goal {
            return Some(reconstruct(&came_from, start, goal));
        }
        let cost = cost_so_far[&position];

        for next_position in neighbours(grid, position) {
            let new_cost = cost + 1;
            if let Some(existing_cost) = cost_so_far.get(&next_position) {
                if new_cost >= *existing_cost {
                    continue;
                }
            }
            cost_so_far.insert(next_position, new_cost);
            frontier.push(PositionPriority {
                minimum_cost: new_cost +
                    min_distance_heuristic(goal, next_position),
                position: next_position });
            came_from.insert(next_position, position);
        }
    }
    None
}

/// Generate a copy of the given grid with the path filled in. The starting
/// position is shown with a '@' , the goal postiion with a 'X' and all other
/// points on the path with a 'o'.
///
/// # Examples
///
/// ```
/// use bestpath::{find_path, format_path_map, Position};
///
/// let grid = vec![vec![' ', ' ', ' ', ' '],
///                 vec![' ', '*', ' ', '*'],
///                 vec!['*', '*', ' ', ' '],
///                 vec![' ', '*', ' ', ' ']];
/// let path = find_path(&grid,
///                      Position{x: 0, y: 1},
///                      Position{x: 3, y: 2}).unwrap();
/// assert_eq!(vec![vec!['o', 'o', 'o', ' '],
///                 vec!['@', '*', 'o', '*'],
///                 vec!['*', '*', 'o', 'X'],
///                 vec![' ', '*', ' ', ' ']],
///            format_path_map(&grid, &path));
/// ```
#[inline]
pub fn format_path_map(grid: &Vec<Vec<char>>, path: &Vec<Position>)
        -> Vec<Vec<char>> {
    let mut m = grid.clone();
    let last_path = path.len() - 1;
    for (i, p) in path.iter().enumerate() {
        m[p.y][p.x] = match i {
            0 => '@',
            _ if i == last_path => 'X',
            _ => 'o',
        }
    }
    m
}

#[allow(dead_code)]
fn print_grid(grid: &Vec<Vec<char>>) {
    println!("");
    for row in grid {
        for ch in row {
            print!(" {} ", ch);
        }
        println!("");
    }
}

#[test]
fn no_path() {
    let map =
        vec![vec![' ', ' ', '█', ' ', ' ', ' ', ' '],
             vec!['█', '█', ' ', ' ', '█', '█', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█'],
             vec![' ', ' ', ' ', '█', ' ', '█', ' '],
             vec!['█', ' ', ' ', ' ', ' ', '█', ' '],
             vec![' ', '█', '█', '█', '█', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map, Position { x: 0, y: 0}, Position { x: 6, y: 6});
    assert_eq!(None, path);
}

#[test]
fn multiple_complex_paths_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['█', '█', ' ', '█', '█', ' ', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█'],
             vec![' ', '█', ' ', '█', ' ', ' ', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█'],
             vec![' ', '█', '█', ' ', ' ', ' ', ' '],
             vec!['█', '█', ' ', ' ', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', '█', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 6, y: 8}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', 'o', 'o', 'o', 'o', 'o', ' '],
             vec!['█', '█', ' ', '█', '█', 'o', ' '],
             vec![' ', '█', ' ', '█', '█', 'o', '█'],
             vec![' ', '█', ' ', '█', ' ', 'o', ' '],
             vec![' ', '█', ' ', '█', '█', 'o', '█'],
             vec![' ', '█', '█', ' ', ' ', 'o', 'o'],
             vec!['█', '█', ' ', ' ', '█', '█', 'o'],
             vec![' ', ' ', ' ', ' ', '█', '█', 'o'],
             vec![' ', ' ', ' ', ' ', '█', ' ', 'X']],
        path_map);
}

#[test]
fn verticle_map() {
    let map =
        vec![vec![' '],
             vec![' '],
             vec![' '],
             vec![' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 0, y: 3}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@'],
             vec!['o'],
             vec!['o'],
             vec!['X']],
        path_map);
}

#[test]
fn horizontal_map() {
    let map =
        vec![vec![' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 3, y: 0}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', 'o', 'o', 'X']],
        path_map);
}

#[test]
fn straight_diagonal_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 6, y: 6}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(13, path.len())  // There are many equivalent paths.
}

#[test]
fn single_walled_path_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['█', '█', '█', '█', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', '█', '█', '█', '█', '█', '█'],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['█', '█', '█', '█', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 0, y: 6}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['█', '█', '█', '█', '█', '█', 'o'],
             vec!['o', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['o', '█', '█', '█', '█', '█', '█'],
             vec!['o', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['█', '█', '█', '█', '█', '█', 'o'],
             vec!['X', 'o', 'o', 'o', 'o', 'o', 'o']],
        path_map);
}

#[test]
fn spiral_wall_path_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', '█', '█', '█', '█', '█', '█', '█'],
             vec![' ', '█', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', '█', ' ', '█', '█', '█', '█', ' '],
             vec![' ', '█', ' ', '█', ' ', ' ', '█', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█', ' '],
             vec![' ', '█', ' ', ' ', ' ', ' ', '█', ' '],
             vec![' ', '█', '█', '█', '█', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 4, y: 4}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['o', '█', '█', '█', '█', '█', '█', '█'],
             vec!['o', '█', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['o', '█', 'o', '█', '█', '█', '█', 'o'],
             vec!['o', '█', 'o', '█', 'X', 'o', '█', 'o'],
             vec!['o', '█', 'o', '█', '█', 'o', '█', 'o'],
             vec!['o', '█', 'o', 'o', 'o', 'o', '█', 'o'],
             vec!['o', '█', '█', '█', '█', '█', '█', 'o'],
             vec!['o', 'o', 'o', 'o', 'o', 'o', 'o', 'o']],
        path_map);
}
<|endoftext|>


<commit_before>pub mod disk;
pub mod memory;

use db::storage::{Memory, Disk, StorageEngine};
use tempdir::TempDir;
use db::storage::Storage;

#[macro_export]
macro_rules! storage {
    ($f:ident) => {
        let storage = get_memory_storage();
        let storage2 = get_disk_storage();

        $f(&storage);
        $f(&storage2);
    };
}

fn get_memory_storage<'a>() -> StorageEngine<'a> {
    let mem = Memory::new().expect("Memory storage");
    StorageEngine::new(mem)
}

fn get_disk_storage<'a>() -> StorageEngine<'a> {
    // disk storage
    let tmp = TempDir::new("totalrecallwhatever").expect("Expected dir");
    let mut tmp2 = tmp.into_path();
    tmp2.push("blah");

    let disk = Disk::new(10, tmp2).expect("Disk storage");
    StorageEngine::new(disk)
}

#[test]
fn test_storage_engine_creation() {
    fn something(s: &StorageEngine) {
    }
    storage!(something);
}

#[test]
fn test_write_and_read_page() {
    fn body(s: &StorageEngine) {

    }
    storage!(body);
}
<commit_msg>added empty test<commit_after>pub mod disk;
pub mod memory;

use db::storage::{Memory, Disk, StorageEngine};
use tempdir::TempDir;
use db::storage::Storage;

#[macro_export]
macro_rules! storage {
    ($f:ident) => {
        let storage = get_memory_storage();
        let storage2 = get_disk_storage();

        $f(&storage);
        $f(&storage2);
    };
}

fn get_memory_storage<'a>() -> StorageEngine<'a> {
    let mem = Memory::new().expect("Memory storage");
    StorageEngine::new(mem)
}

fn get_disk_storage<'a>() -> StorageEngine<'a> {
    // disk storage
    let tmp = TempDir::new("totalrecallwhatever").expect("Expected dir");
    let mut tmp2 = tmp.into_path();
    tmp2.push("blah");

    let disk = Disk::new(10, tmp2).expect("Disk storage");
    StorageEngine::new(disk)
}

#[test]
fn test_storage_engine_creation() {
    fn something(s: &StorageEngine) {
    }
    storage!(something);
}

#[test]
fn test_insert_and_get() {
    fn body(s: &StorageEngine) {

    }
    storage!(body);
}
<|endoftext|>


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

use std::net::{SocketAddr, TcpStream};
use std::io::{self, Write};
use std::process;
use std::str;
use std::thread;
use std::time::Duration;
use relaylib::byte_buffer::ByteBuffer;

const TAG: &'static str = "AdbMonitor";

pub trait AdbMonitorCallback {
    fn on_new_device_connected(&self, serial: &String);
}

impl<F> AdbMonitorCallback for F
where
    F: Fn(&String),
{
    fn on_new_device_connected(&self, serial: &String) {
        self(serial);
    }
}
pub struct AdbMonitor {
    callback: Box<AdbMonitorCallback>,
    buf: ByteBuffer,
}

impl AdbMonitor {
    const TRACK_DEVICES_REQUEST: &'static [u8] = b"0012host:track-devices";
    const BUFFER_SIZE: usize = 1024;
    const RETRY_DELAY_ADB_DAEMON_OK: u64 = 1000;
    const RETRY_DELAY_ADB_DAEMON_KO: u64 = 5000;

    pub fn new(callback: Box<AdbMonitorCallback>) -> Self {
        Self {
            callback: callback,
            buf: ByteBuffer::new(Self::BUFFER_SIZE),
        }
    }

    pub fn monitor(&mut self) -> io::Result<()> {
        loop {
            if let Err(err) = self.track_devices() {
                error!(target: TAG, "Failed to monitor adb devices: {}", err);
                Self::repair_adb_daemon();
            }
        }
    }

    fn track_devices(&mut self) -> io::Result<()> {
        let adbd_addr = SocketAddr::from(([127, 0, 0, 1], 5037));
        let mut stream = TcpStream::connect(adbd_addr)?;
        self.track_devices_on_stream(&mut stream)
    }

    fn track_devices_on_stream(&mut self, stream: &mut TcpStream) -> io::Result<()> {
        stream.write_all(Self::TRACK_DEVICES_REQUEST)?;
        if self.consume_okay(stream)? {
            loop {
                let packet = self.next_packet(stream)?;
                self.handle_packet(&packet);
            }
        }
        Ok(())
    }

    fn consume_okay(&mut self, stream: &mut TcpStream) -> io::Result<bool> {
        while self.buf.peek().len() < 4 {
            self.buf.read_from(stream)?;
        }
        let ok = b"OKAY" == &self.buf.peek()[0..4];
        self.buf.consume(4);
        Ok(ok)
    }

    fn next_packet(&mut self, stream: &mut TcpStream) -> io::Result<String> {
        loop {
            let packet_length = Self::available_packet_length(self.buf.peek())?;
            match packet_length {
                Some(len) => {
                    // retrieve the content and consume the packet
                    let data = Self::to_string(&self.buf.peek()[4..len])?;
                    self.buf.consume(len);
                    return Ok(data);
                }
                // need more data
                None => self.fill_buffer_from(stream)?,
            };
        }
    }

    fn fill_buffer_from(&mut self, stream: &mut TcpStream) -> io::Result<()> {
        match self.buf.read_from(stream) {
            Ok(false) => Err(io::Error::new(
                io::ErrorKind::UnexpectedEof,
                "ADB daemon closed the track-devices connexion",
            )),
            Ok(_) => Ok(()),
            Err(err) => Err(err),
        }
    }

    fn available_packet_length(input: &[u8]) -> io::Result<Option<usize>> {
        if input.len() < 4 {
            Ok(None)
        } else {
            // each packet contains 4 bytes representing the String length in hexa, followed by the
            // device serial, `\t', the state, '\n'
            // for example: "00180123456789abcdef\tdevice\n": 0018 indicates that the data is 0x18
            // (24) bytes length
            let len = Self::parse_length(&input[0..4])?;
            if len > Self::BUFFER_SIZE as u32 {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidInput,
                    format!("Packet size should not be that big: {}", len),
                ));
            }
            if input.len() - 4usize >= len as usize {
                Ok(Some(4usize + len as usize))
            } else {
                // not enough data
                Ok(None)
            }
        }
    }

    fn handle_packet(&self, serial: &String) {
        let mut split = serial.split_whitespace();
        if let Some(serial) = split.next() {
            if let Some(state) = split.next() {
                if "device" == state {
                    self.callback.on_new_device_connected(&serial.to_string());
                }
            }
        }
    }

    fn parse_length(data: &[u8]) -> io::Result<u32> {
        assert!(data.len() == 4, "Invalid length field value");
        let hexa = str::from_utf8(data).map_err(|err| {
            io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("Cannot read hexa length as UTF-8 ({})", err),
            )
        })?;
        u32::from_str_radix(hexa, 0x10).map_err(|err| {
            io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("Cannot parse hexa length ({})", err),
            )
        })
    }

    fn repair_adb_daemon() {
        if Self::start_adb_daemon() {
            thread::sleep(Duration::from_millis(Self::RETRY_DELAY_ADB_DAEMON_OK));
        } else {
            thread::sleep(Duration::from_millis(Self::RETRY_DELAY_ADB_DAEMON_KO));
        }
    }

    fn start_adb_daemon() -> bool {
        info!(target: TAG, "Restarting adb daemon");
        match process::Command::new("adb")
            .args(&["start-server"])
            .status() {
            Ok(exit_status) => {
                if exit_status.success() {
                    true
                } else {
                    error!(
                        target: TAG,
                        "Could not restart adb daemon (exited on error)"
                    );
                    false
                }
            }
            Err(err) => {
                error!(target: TAG, "Could not restart adb daemon: {}", err);
                false
            }
        }
    }

    fn to_string(data: &[u8]) -> io::Result<String> {
        let raw_content = data.to_vec();
        let content = String::from_utf8(raw_content);
        if let Ok(content) = content {
            Ok(content)
        } else {
            Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Track-devices string is not valid UTF-8",
            ))
        }
    }
}
<commit_msg>Extract read_packet() from next_packet()<commit_after>/*
 * Copyright (C) 2017 Genymobile
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::net::{SocketAddr, TcpStream};
use std::io::{self, Write};
use std::process;
use std::str;
use std::thread;
use std::time::Duration;
use relaylib::byte_buffer::ByteBuffer;

const TAG: &'static str = "AdbMonitor";

pub trait AdbMonitorCallback {
    fn on_new_device_connected(&self, serial: &String);
}

impl<F> AdbMonitorCallback for F
where
    F: Fn(&String),
{
    fn on_new_device_connected(&self, serial: &String) {
        self(serial);
    }
}
pub struct AdbMonitor {
    callback: Box<AdbMonitorCallback>,
    buf: ByteBuffer,
}

impl AdbMonitor {
    const TRACK_DEVICES_REQUEST: &'static [u8] = b"0012host:track-devices";
    const BUFFER_SIZE: usize = 1024;
    const RETRY_DELAY_ADB_DAEMON_OK: u64 = 1000;
    const RETRY_DELAY_ADB_DAEMON_KO: u64 = 5000;

    pub fn new(callback: Box<AdbMonitorCallback>) -> Self {
        Self {
            callback: callback,
            buf: ByteBuffer::new(Self::BUFFER_SIZE),
        }
    }

    pub fn monitor(&mut self) -> io::Result<()> {
        loop {
            if let Err(err) = self.track_devices() {
                error!(target: TAG, "Failed to monitor adb devices: {}", err);
                Self::repair_adb_daemon();
            }
        }
    }

    fn track_devices(&mut self) -> io::Result<()> {
        let adbd_addr = SocketAddr::from(([127, 0, 0, 1], 5037));
        let mut stream = TcpStream::connect(adbd_addr)?;
        self.track_devices_on_stream(&mut stream)
    }

    fn track_devices_on_stream(&mut self, stream: &mut TcpStream) -> io::Result<()> {
        stream.write_all(Self::TRACK_DEVICES_REQUEST)?;
        if self.consume_okay(stream)? {
            loop {
                let packet = self.next_packet(stream)?;
                self.handle_packet(&packet);
            }
        }
        Ok(())
    }

    fn consume_okay(&mut self, stream: &mut TcpStream) -> io::Result<bool> {
        while self.buf.peek().len() < 4 {
            self.buf.read_from(stream)?;
        }
        let ok = b"OKAY" == &self.buf.peek()[0..4];
        self.buf.consume(4);
        Ok(ok)
    }

    fn read_packet(buf: &mut ByteBuffer) -> io::Result<Option<String>> {
        let packet_length = Self::available_packet_length(buf.peek())?;
        if let Some(len) = packet_length {
            // retrieve the content and consume the packet
            let data = Self::to_string(&buf.peek()[4..len])?;
            buf.consume(len);
            Ok(Some(data))
        } else {
            Ok(None)
        }
    }

    fn next_packet(&mut self, stream: &mut TcpStream) -> io::Result<String> {
        loop {
            let packet = Self::read_packet(&mut self.buf)?;
            if let Some(packet) = packet {
                return Ok(packet);
            } else {
                self.fill_buffer_from(stream)?;
            }
        }
    }

    fn fill_buffer_from(&mut self, stream: &mut TcpStream) -> io::Result<()> {
        match self.buf.read_from(stream) {
            Ok(false) => Err(io::Error::new(
                io::ErrorKind::UnexpectedEof,
                "ADB daemon closed the track-devices connexion",
            )),
            Ok(_) => Ok(()),
            Err(err) => Err(err),
        }
    }

    fn available_packet_length(input: &[u8]) -> io::Result<Option<usize>> {
        if input.len() < 4 {
            Ok(None)
        } else {
            // each packet contains 4 bytes representing the String length in hexa, followed by the
            // device serial, `\t', the state, '\n'
            // for example: "00180123456789abcdef\tdevice\n": 0018 indicates that the data is 0x18
            // (24) bytes length
            let len = Self::parse_length(&input[0..4])?;
            if len > Self::BUFFER_SIZE as u32 {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidInput,
                    format!("Packet size should not be that big: {}", len),
                ));
            }
            if input.len() - 4usize >= len as usize {
                Ok(Some(4usize + len as usize))
            } else {
                // not enough data
                Ok(None)
            }
        }
    }

    fn handle_packet(&self, serial: &String) {
        let mut split = serial.split_whitespace();
        if let Some(serial) = split.next() {
            if let Some(state) = split.next() {
                if "device" == state {
                    self.callback.on_new_device_connected(&serial.to_string());
                }
            }
        }
    }

    fn parse_length(data: &[u8]) -> io::Result<u32> {
        assert!(data.len() == 4, "Invalid length field value");
        let hexa = str::from_utf8(data).map_err(|err| {
            io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("Cannot read hexa length as UTF-8 ({})", err),
            )
        })?;
        u32::from_str_radix(hexa, 0x10).map_err(|err| {
            io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("Cannot parse hexa length ({})", err),
            )
        })
    }

    fn repair_adb_daemon() {
        if Self::start_adb_daemon() {
            thread::sleep(Duration::from_millis(Self::RETRY_DELAY_ADB_DAEMON_OK));
        } else {
            thread::sleep(Duration::from_millis(Self::RETRY_DELAY_ADB_DAEMON_KO));
        }
    }

    fn start_adb_daemon() -> bool {
        info!(target: TAG, "Restarting adb daemon");
        match process::Command::new("adb")
            .args(&["start-server"])
            .status() {
            Ok(exit_status) => {
                if exit_status.success() {
                    true
                } else {
                    error!(
                        target: TAG,
                        "Could not restart adb daemon (exited on error)"
                    );
                    false
                }
            }
            Err(err) => {
                error!(target: TAG, "Could not restart adb daemon: {}", err);
                false
            }
        }
    }

    fn to_string(data: &[u8]) -> io::Result<String> {
        let raw_content = data.to_vec();
        let content = String::from_utf8(raw_content);
        if let Ok(content) = content {
            Ok(content)
        } else {
            Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "Track-devices string is not valid UTF-8",
            ))
        }
    }
}
<|endoftext|>


<commit_before>use runtime::Runtime;

/**
 * A function which lets the user provide content by editing a temp files which gets removed after
 * the function got the content from it.
 */
pub fn let_user_provide_content(rt: &Runtime) -> Option<String> {
    use std::io::Read;
    use std::fs::File;

    let filepath        = "/tmp/imag-tmp.md";
    let file_created    = File::create(filepath)
                                .map(|_| true)
                                .unwrap_or(false);

    if !file_created {
        warn!("Could not create temporary file for user input!");
        return None;
    }

    let output = {
        let mut cmd = rt.editor();
        cmd.arg(filepath);
        debug!("cmd = {:?}", cmd);
        cmd.spawn()
           .and_then(|child| {
               child.wait_with_output()
            })
    };

    let process_out = output.map_err(|e| {
        error!("Editor call failed");
        debug!("Editor call failed: {:?}", e);
        return None as Option<String>;
    }).unwrap();

    if !process_out.status.success() {
        error!("Editor call failed");
        debug!("status = {:?}", process_out.status);
        debug!("stdout = {:?}", String::from_utf8(process_out.stdout));
        debug!("stderr = {:?}", String::from_utf8(process_out.stderr));
        return None;
    }

    let mut contents = String::new();
    File::open(filepath).map(|mut file| {
        file.read_to_string(&mut contents);
        Some(contents)
    }).unwrap_or(None)
}

/**
 * Edit some content in a temporary file. If anything failes within this routine, it returns the
 * old content and false.
 * If the editing succeeded, it returns the new content and true
 */
pub fn edit_content(rt: &Runtime, old_content: String) -> (String, bool) {
    use std::io::Read;
    use std::io::Write;
    use std::fs::File;
    use std::process::Command;
    use std::process::exit;

    let filepath = "/tmp/imag-tmp.md";
    {
        let mut file = match File::create(filepath) {
            Ok(f) => f,
            Err(e) => {
                error!("Error creating file {}", filepath);
                debug!("Error creating file at '{}', error = {}", filepath, e);
                exit(1);
            }
        };

        file.write(old_content.as_ref())
            .map_err(|e| {
                error!("Error writing content: {}", e);
                debug!("Error writing content: {:?}", e);
                exit(1);
            }).is_ok();
    }
    debug!("Ready with putting old content into the file");

    let output = {
        let mut cmd = rt.editor();
        cmd.arg(filepath);
        debug!("cmd = {:?}", cmd);
        cmd.spawn()
           .and_then(|child| child.wait_with_output())
    };

    let process_out = output.map_err(|e| {
        error!("Editor call failed");
        debug!("Editor call failed: {:?}", e);
        return None as Option<String>;
    }).unwrap();

    if !process_out.status.success() {
        error!("Editor call failed");
        debug!("status = {:?}", process_out.status);
        debug!("stdout = {:?}", String::from_utf8(process_out.stdout));
        debug!("stderr = {:?}", String::from_utf8(process_out.stderr));
        return (old_content, false);
    }

    let mut contents = String::new();
    File::open(filepath).map(|mut file| {
        file.read_to_string(&mut contents).map_err(|e| {
            error!("Error reading content: {}", e);
            debug!("Error reading content: {:?}", e);
            exit(1);
        }).is_ok();
        (contents, true)
    }).unwrap_or((old_content, false))
}

<commit_msg>Use return value: fail if content could not be read<commit_after>use runtime::Runtime;

/**
 * A function which lets the user provide content by editing a temp files which gets removed after
 * the function got the content from it.
 */
pub fn let_user_provide_content(rt: &Runtime) -> Option<String> {
    use std::io::Read;
    use std::fs::File;
    use std::process::exit;

    let filepath        = "/tmp/imag-tmp.md";
    let file_created    = File::create(filepath)
                                .map(|_| true)
                                .unwrap_or(false);

    if !file_created {
        warn!("Could not create temporary file for user input!");
        return None;
    }

    let output = {
        let mut cmd = rt.editor();
        cmd.arg(filepath);
        debug!("cmd = {:?}", cmd);
        cmd.spawn()
           .and_then(|child| {
               child.wait_with_output()
            })
    };

    let process_out = output.map_err(|e| {
        error!("Editor call failed");
        debug!("Editor call failed: {:?}", e);
        return None as Option<String>;
    }).unwrap();

    if !process_out.status.success() {
        error!("Editor call failed");
        debug!("status = {:?}", process_out.status);
        debug!("stdout = {:?}", String::from_utf8(process_out.stdout));
        debug!("stderr = {:?}", String::from_utf8(process_out.stderr));
        return None;
    }

    let mut contents = String::new();
    File::open(filepath).map(|mut file| {
        file.read_to_string(&mut contents)
            .map_err(|e| {
                error!("Error reading content: {}", e);
                debug!("Error reading content: {:?}", e);
                exit(1);
            })
            .is_ok();
        Some(contents)
    }).unwrap_or(None)
}

/**
 * Edit some content in a temporary file. If anything failes within this routine, it returns the
 * old content and false.
 * If the editing succeeded, it returns the new content and true
 */
pub fn edit_content(rt: &Runtime, old_content: String) -> (String, bool) {
    use std::io::Read;
    use std::io::Write;
    use std::fs::File;
    use std::process::Command;
    use std::process::exit;

    let filepath = "/tmp/imag-tmp.md";
    {
        let mut file = match File::create(filepath) {
            Ok(f) => f,
            Err(e) => {
                error!("Error creating file {}", filepath);
                debug!("Error creating file at '{}', error = {}", filepath, e);
                exit(1);
            }
        };

        file.write(old_content.as_ref())
            .map_err(|e| {
                error!("Error writing content: {}", e);
                debug!("Error writing content: {:?}", e);
                exit(1);
            }).is_ok();
    }
    debug!("Ready with putting old content into the file");

    let output = {
        let mut cmd = rt.editor();
        cmd.arg(filepath);
        debug!("cmd = {:?}", cmd);
        cmd.spawn()
           .and_then(|child| child.wait_with_output())
    };

    let process_out = output.map_err(|e| {
        error!("Editor call failed");
        debug!("Editor call failed: {:?}", e);
        return None as Option<String>;
    }).unwrap();

    if !process_out.status.success() {
        error!("Editor call failed");
        debug!("status = {:?}", process_out.status);
        debug!("stdout = {:?}", String::from_utf8(process_out.stdout));
        debug!("stderr = {:?}", String::from_utf8(process_out.stderr));
        return (old_content, false);
    }

    let mut contents = String::new();
    File::open(filepath).map(|mut file| {
        file.read_to_string(&mut contents).map_err(|e| {
            error!("Error reading content: {}", e);
            debug!("Error reading content: {:?}", e);
            exit(1);
        }).is_ok();
        (contents, true)
    }).unwrap_or((old_content, false))
}

<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::mem;

use ffi;
use LuaContext;

use AsLua;
use AsMutLua;
use Push;
use LuaRead;

///
pub struct LuaTable<L> {
    table: L,
}

unsafe impl<L> AsLua for LuaTable<L> where L: AsLua {
    fn as_lua(&self) -> LuaContext {
        self.table.as_lua()
    }
}

unsafe impl<L> AsMutLua for LuaTable<L> where L: AsMutLua {
    fn as_mut_lua(&mut self) -> LuaContext {
        self.table.as_mut_lua()
    }
}

impl<L> LuaRead<L> for LuaTable<L> where L: AsMutLua {
    fn lua_read_at_position(mut lua: L, index: i32) -> Option<LuaTable<L>> {
        assert!(index == -1);   // FIXME: not sure if it's working
        if unsafe { ffi::lua_istable(lua.as_mut_lua().0, index) } {
            Some(LuaTable { table: lua })
        } else {
            None
        }
    }
}

// while the LuaTableIterator is active, the current key is constantly pushed over the table
pub struct LuaTableIterator<'t, L: 't, K, V> {
    table: &'t mut LuaTable<L>,
    finished: bool,     // if true, the key is not on the stack anymore
    marker: PhantomData<(K, V)>,
}

unsafe impl<'t, L, K, V> AsLua for LuaTableIterator<'t, L, K, V> where L: AsLua {
    fn as_lua(&self) -> LuaContext {
        self.table.as_lua()
    }
}

unsafe impl<'t, L, K, V> AsMutLua for LuaTableIterator<'t, L, K, V> where L: AsMutLua {
    fn as_mut_lua(&mut self) -> LuaContext {
        self.table.as_mut_lua()
    }
}

impl<L> LuaTable<L> where L: AsMutLua {
    pub fn iter<K, V>(&mut self) -> LuaTableIterator<L, K, V> {
        unsafe { ffi::lua_pushnil(self.table.as_mut_lua().0) };

        LuaTableIterator {
            table: self,
            finished: false,
            marker: PhantomData,
        }
    }

    /*pub fn get<'a, R, I>(&'a mut self, index: I) -> Option<R> where R: LuaRead<&'a mut LuaTable<L>>, I: Push<&'a mut LuaTable<L>> {
        {
            let guard = index.push_to_lua(self);
            unsafe { mem::forget(guard) };
        }

        unsafe { ffi::lua_gettable(self.as_mut_lua().0, -2); }
        let value = LuaRead::lua_read(self);
        unsafe { ffi::lua_pop(self.as_mut_lua().0, 1); }
        value
    }*/

    pub fn set<'s, I, V>(&'s mut self, index: I, value: V)
                         where I: for<'a> Push<&'a mut &'s mut LuaTable<L>>,
                               V: for<'a> Push<&'a mut &'s mut LuaTable<L>>
    {
        let mut me = self;
        index.push_to_lua(&mut me).forget();
        value.push_to_lua(&mut me).forget();
        unsafe { ffi::lua_settable(me.as_mut_lua().0, -3); }
    }

    /*// Obtains or create the metatable of the table
    pub fn get_or_create_metatable(mut self) -> LuaTable<'var, L> {
        let result = unsafe { ffi::lua_getmetatable(self.variable.as_lua(), -1) };

        if result == 0 {
            unsafe {
                ffi::lua_newtable(self.variable.as_lua());
                ffi::lua_setmetatable(self.variable.as_lua(), -2);
                let r = ffi::lua_getmetatable(self.variable.as_lua(), -1);
                assert!(r != 0);
            }
        }

        // note: it would be cleaner to create another table, but cannot manage to make it compile
        self.variable.size += 1;
        self
    }*/
}

impl<'t, L, K, V> Iterator for LuaTableIterator<'t, L, K, V>
                  where L: AsMutLua + 't,
                        K: for<'i, 'j> LuaRead<&'i mut &'j mut LuaTableIterator<'t, L, K, V>> + 'static,
                        V: for<'i, 'j> LuaRead<&'i mut &'j mut LuaTableIterator<'t, L, K, V>> + 'static
{
    type Item = Option<(K, V)>;

    fn next(&mut self) -> Option<Option<(K,V)>> {
        if self.finished {
            return None;
        }

        // this call pushes the next key and value on the stack
        if unsafe { ffi::lua_next(self.table.as_mut_lua().0, -2) } == 0 {
            self.finished = true;
            return None;
        }

        let mut me = self;
        let key = LuaRead::lua_read_at_position(&mut me, -2);
        let value = LuaRead::lua_read_at_position(&mut me, -1);

        // removing the value, leaving only the key on the top of the stack
        unsafe { ffi::lua_pop(me.table.as_mut_lua().0, 1) };

        //
        if key.is_none() || value.is_none() {
            Some(None)
        } else {
            Some(Some((key.unwrap(), value.unwrap())))
        }
    }
}

#[unsafe_destructor]
impl<'t, L, K, V> Drop for LuaTableIterator<'t, L, K, V> where L: AsMutLua + 't {
    fn drop(&mut self) {
        if !self.finished {
            unsafe { ffi::lua_pop(self.table.table.as_mut_lua().0, 1) }
        }
    }
}
<commit_msg>Restore LuaTable::get_or_create_metatable<commit_after>use std::marker::PhantomData;
use std::mem;

use ffi;
use LuaContext;

use AsLua;
use AsMutLua;
use Push;
use PushGuard;
use LuaRead;

///
pub struct LuaTable<L> {
    table: L,
}

unsafe impl<L> AsLua for LuaTable<L> where L: AsLua {
    fn as_lua(&self) -> LuaContext {
        self.table.as_lua()
    }
}

unsafe impl<L> AsMutLua for LuaTable<L> where L: AsMutLua {
    fn as_mut_lua(&mut self) -> LuaContext {
        self.table.as_mut_lua()
    }
}

impl<L> LuaRead<L> for LuaTable<L> where L: AsMutLua {
    fn lua_read_at_position(mut lua: L, index: i32) -> Option<LuaTable<L>> {
        assert!(index == -1);   // FIXME: not sure if it's working
        if unsafe { ffi::lua_istable(lua.as_mut_lua().0, index) } {
            Some(LuaTable { table: lua })
        } else {
            None
        }
    }
}

// while the LuaTableIterator is active, the current key is constantly pushed over the table
pub struct LuaTableIterator<'t, L: 't, K, V> {
    table: &'t mut LuaTable<L>,
    finished: bool,     // if true, the key is not on the stack anymore
    marker: PhantomData<(K, V)>,
}

unsafe impl<'t, L, K, V> AsLua for LuaTableIterator<'t, L, K, V> where L: AsLua {
    fn as_lua(&self) -> LuaContext {
        self.table.as_lua()
    }
}

unsafe impl<'t, L, K, V> AsMutLua for LuaTableIterator<'t, L, K, V> where L: AsMutLua {
    fn as_mut_lua(&mut self) -> LuaContext {
        self.table.as_mut_lua()
    }
}

impl<L> LuaTable<L> where L: AsMutLua {
    pub fn iter<K, V>(&mut self) -> LuaTableIterator<L, K, V> {
        unsafe { ffi::lua_pushnil(self.table.as_mut_lua().0) };

        LuaTableIterator {
            table: self,
            finished: false,
            marker: PhantomData,
        }
    }

    /*pub fn get<'a, R, I>(&'a mut self, index: I) -> Option<R> where R: LuaRead<&'a mut LuaTable<L>>, I: Push<&'a mut LuaTable<L>> {
        {
            let guard = index.push_to_lua(self);
            unsafe { mem::forget(guard) };
        }

        unsafe { ffi::lua_gettable(self.as_mut_lua().0, -2); }
        let value = LuaRead::lua_read(self);
        unsafe { ffi::lua_pop(self.as_mut_lua().0, 1); }
        value
    }*/

    pub fn set<'s, I, V>(&'s mut self, index: I, value: V)
                         where I: for<'a> Push<&'a mut &'s mut LuaTable<L>>,
                               V: for<'a> Push<&'a mut &'s mut LuaTable<L>>
    {
        let mut me = self;
        index.push_to_lua(&mut me).forget();
        value.push_to_lua(&mut me).forget();
        unsafe { ffi::lua_settable(me.as_mut_lua().0, -3); }
    }

    // Obtains or create the metatable of the table
    pub fn get_or_create_metatable(mut self) -> LuaTable<PushGuard<L>> {
        let result = unsafe { ffi::lua_getmetatable(self.table.as_mut_lua().0, -1) };

        if result == 0 {
            unsafe {
                ffi::lua_newtable(self.table.as_mut_lua().0);
                ffi::lua_setmetatable(self.table.as_mut_lua().0, -2);
                let r = ffi::lua_getmetatable(self.table.as_mut_lua().0, -1);
                assert!(r != 0);
            }
        }

        LuaTable {
            table: PushGuard { lua: self.table, size: 1 }
        }
    }
}

impl<'t, L, K, V> Iterator for LuaTableIterator<'t, L, K, V>
                  where L: AsMutLua + 't,
                        K: for<'i, 'j> LuaRead<&'i mut &'j mut LuaTableIterator<'t, L, K, V>> + 'static,
                        V: for<'i, 'j> LuaRead<&'i mut &'j mut LuaTableIterator<'t, L, K, V>> + 'static
{
    type Item = Option<(K, V)>;

    fn next(&mut self) -> Option<Option<(K,V)>> {
        if self.finished {
            return None;
        }

        // this call pushes the next key and value on the stack
        if unsafe { ffi::lua_next(self.table.as_mut_lua().0, -2) } == 0 {
            self.finished = true;
            return None;
        }

        let mut me = self;
        let key = LuaRead::lua_read_at_position(&mut me, -2);
        let value = LuaRead::lua_read_at_position(&mut me, -1);

        // removing the value, leaving only the key on the top of the stack
        unsafe { ffi::lua_pop(me.table.as_mut_lua().0, 1) };

        //
        if key.is_none() || value.is_none() {
            Some(None)
        } else {
            Some(Some((key.unwrap(), value.unwrap())))
        }
    }
}

#[unsafe_destructor]
impl<'t, L, K, V> Drop for LuaTableIterator<'t, L, K, V> where L: AsMutLua + 't {
    fn drop(&mut self) {
        if !self.finished {
            unsafe { ffi::lua_pop(self.table.table.as_mut_lua().0, 1) }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(ascii_ctype)]
use std::ascii::AsciiExt;

pub fn encode(message: &str) -> String {
    let mut index = 0;
    message
        .chars()
        .filter_map(|c| match c {
            _ if c.is_ascii_digit() => Some(c),
            _ if c.is_ascii_uppercase() => {
                let v = b'z' - c.to_ascii_lowercase() as u8 + b'a';
                Some(v as char)
            }
            _ if c.is_ascii_lowercase() => {
                let v = b'z' - c as u8 + b'a';
                Some(v as char)
            }
            _ => None,
        })
        .fold(String::new(), |mut acc, x| {
            index += 1;
            if index == 6 {
                acc.push(' ');
                index = 1;
            }

            acc.push(x);
            acc
        })
}

pub fn decode(message: &str) -> String {
    message
        .chars()
        .filter_map(|c| match c {
            _ if c.is_ascii_digit() => Some(c),
            _ if c.is_ascii_lowercase() => {
                let v = b'z' - c as u8 + b'a';
                Some(v as char)
            }
            _ => None,
        })
        .collect()
}
<commit_msg>Use const instead of magic number<commit_after>#![feature(ascii_ctype)]
use std::ascii::AsciiExt;

const LA: u8 = b'a';
const LZ: u8 = b'z';

pub fn encode(message: &str) -> String {
    let mut index = 0;
    message
        .chars()
        .filter_map(|c| match c {
            _ if c.is_ascii_digit() => Some(c),
            _ if c.is_ascii_uppercase() => {
                let v = LZ - c.to_ascii_lowercase() as u8 + LA;
                Some(v as char)
            }
            _ if c.is_ascii_lowercase() => {
                let v = LZ - c as u8 + LA;
                Some(v as char)
            }
            _ => None,
        })
        .fold(String::new(), |mut acc, x| {
            index += 1;
            if index == 6 {
                acc.push(' ');
                index = 1;
            }

            acc.push(x);
            acc
        })
}

pub fn decode(message: &str) -> String {
    message
        .chars()
        .filter_map(|c| match c {
            _ if c.is_ascii_digit() => Some(c),
            _ if c.is_ascii_lowercase() => {
                let v = LZ - c as u8 + LA;
                Some(v as char)
            }
            _ => None,
        })
        .collect()
}
<|endoftext|>


<commit_before>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::{BTreeMap, Vec, VecDeque};
use spin::Mutex;

use arch;
use context::file::File;
use context::memory::{Grant, Memory, SharedMemory, Tls};
use scheme::{SchemeNamespace, FileHandle};
use syscall::data::Event;
use sync::{WaitMap, WaitQueue};

/// Unique identifier for a context (i.e. `pid`).
use ::core::sync::atomic::AtomicUsize;
int_like!(ContextId, AtomicContextId, usize, AtomicUsize);

/// The status of a context - used for scheduling
/// See syscall::process::waitpid and the sync module for examples of usage
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status {
    Runnable,
    Blocked,
    Exited(usize)
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The ID of this context
    pub id: ContextId,
    /// The ID of the parent context
    pub ppid: ContextId,
    /// The real user id
    pub ruid: u32,
    /// The real group id
    pub rgid: u32,
    /// The real namespace id
    pub rns: SchemeNamespace,
    /// The effective user id
    pub euid: u32,
    /// The effective group id
    pub egid: u32,
    /// The effective namespace id
    pub ens: SchemeNamespace,
    /// Status of context
    pub status: Status,
    /// Context running or not
    pub running: bool,
    /// CPU ID, if locked
    pub cpu_id: Option<usize>,
    /// Context is halting parent
    pub vfork: bool,
    /// Context is being waited on
    pub waitpid: Arc<WaitMap<ContextId, usize>>,
    /// Context should handle pending signals
    pub pending: VecDeque<u8>,
    /// Context should wake up at specified time
    pub wake: Option<(u64, u64)>,
    /// The architecture specific context
    pub arch: arch::context::Context,
    /// Kernel FX - used to store SIMD and FPU registers on context switch
    pub kfx: Option<Box<[u8]>>,
    /// Kernel stack
    pub kstack: Option<Box<[u8]>>,
    /// Executable image
    pub image: Vec<SharedMemory>,
    /// User heap
    pub heap: Option<SharedMemory>,
    /// User stack
    pub stack: Option<Memory>,
    /// User Thread local storage
    pub tls: Option<Tls>,
    /// User grants
    pub grants: Arc<Mutex<Vec<Grant>>>,
    /// The name of the context
    pub name: Arc<Mutex<Vec<u8>>>,
    /// The current working directory
    pub cwd: Arc<Mutex<Vec<u8>>>,
    /// Kernel events
    pub events: Arc<WaitQueue<Event>>,
    /// The process environment
    pub env: Arc<Mutex<BTreeMap<Box<[u8]>, Arc<Mutex<Vec<u8>>>>>>,
    /// The open files in the scheme
    pub files: Arc<Mutex<Vec<Option<File>>>>
}

impl Context {
    pub fn new(id: ContextId) -> Context {
        Context {
            id: id,
            ppid: ContextId::from(0),
            ruid: 0,
            rgid: 0,
            rns: SchemeNamespace::from(0),
            euid: 0,
            egid: 0,
            ens: SchemeNamespace::from(0),
            status: Status::Blocked,
            running: false,
            cpu_id: None,
            vfork: false,
            waitpid: Arc::new(WaitMap::new()),
            pending: VecDeque::new(),
            wake: None,
            arch: arch::context::Context::new(),
            kfx: None,
            kstack: None,
            image: Vec::new(),
            heap: None,
            stack: None,
            tls: None,
            grants: Arc::new(Mutex::new(Vec::new())),
            name: Arc::new(Mutex::new(Vec::new())),
            cwd: Arc::new(Mutex::new(Vec::new())),
            events: Arc::new(WaitQueue::new()),
            env: Arc::new(Mutex::new(BTreeMap::new())),
            files: Arc::new(Mutex::new(Vec::new()))
        }
    }

    /// Make a relative path absolute
    /// Given a cwd of "scheme:/path"
    /// This function will turn "foo" into "scheme:/path/foo"
    /// "/foo" will turn into "scheme:/foo"
    /// "bar:/foo" will be used directly, as it is already absolute
    pub fn canonicalize(&self, path: &[u8]) -> Vec<u8> {
        if path.iter().position(|&b| b == b':').is_none() {
            let cwd = self.cwd.lock();
            if path == b"." {
                cwd.clone()
            } else if path == b".." {
                cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/' || b == b':')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec()
            } else {
                let mut canon = if !path.starts_with(b"/") {
                    let mut c = cwd.clone();
                    if ! c.ends_with(b"/") {
                        c.push(b'/');
                    }
                    c
                } else {
                    cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec()
                };

                canon.extend_from_slice(&path);
                // NOTE: assumes the scheme does not include anything like "../" or "./"
                let mut result = {
                    let parts = canon.split(|&c| c == b'/')
                        .filter(|&part| part != b".")
                        .rev()
                        .scan(0, |nskip, part| {
                            if part == b".." {
                                *nskip += 1;
                                Some(None)
                            } else {
                                if *nskip > 0 {
                                    *nskip -= 1;
                                    Some(None)
                                } else {
                                    Some(Some(part))
                                }
                            }
                        })
                        .filter_map(|x| x)
                        .collect::<Vec<_>>();
                    parts
                        .iter()
                        .rev()
                        .fold(Vec::new(), |mut vec, &part| {
                            vec.extend_from_slice(part);
                            vec.push(b'/');
                            vec
                        })
                };
                result.pop(); // remove extra '/'

                // replace with the root of the schema if it's empty
                if result.len() == 0 {
                    let pos = canon.iter()
                                    .position(|&b| b == b':')
                                    .map_or(canon.len(), |p| p + 1);
                    canon.truncate(pos);
                    canon
                } else {
                    result
                }
            }
        } else {
            path.to_vec()
        }
    }

    /// Block the context, and return true if it was runnable before being blocked
    pub fn block(&mut self) -> bool {
        if self.status == Status::Runnable {
            self.status = Status::Blocked;
            true
        } else {
            false
        }
    }

    /// Unblock context, and return true if it was blocked before being marked runnable
    pub fn unblock(&mut self) -> bool {
        if self.status == Status::Blocked {
            self.status = Status::Runnable;
            if let Some(cpu_id) = self.cpu_id {
                if cpu_id != ::cpu_id() {
                    // Send IPI if not on current CPU
                    // TODO: Make this more architecture independent
                    unsafe { arch::device::local_apic::LOCAL_APIC.ipi(cpu_id) };
                }
            }
            true
        } else {
            false
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&self, file: File) -> Option<FileHandle> {
        let mut files = self.files.lock();
        for (i, mut file_option) in files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(FileHandle::from(i));
            }
        }
        let len = files.len();
        if len < super::CONTEXT_MAX_FILES {
            files.push(Some(file));
            Some(FileHandle::from(len))
        } else {
            None
        }
    }

    /// Get a file
    pub fn get_file(&self, i: FileHandle) -> Option<File> {
        let files = self.files.lock();
        if i.into() < files.len() {
            files[i.into()]
        } else {
            None
        }
    }

    /// Insert a file with a specific handle number. This is used by dup2
    /// Return the file descriptor number or None if the slot was not empty, or i was invalid
    pub fn insert_file(&self, i: FileHandle, file: File) -> Option<FileHandle> {
        let mut files = self.files.lock();
        if i.into() < super::CONTEXT_MAX_FILES {
            while i.into() >= files.len() {
                files.push(None);
            }
            if files[i.into()].is_none() {
                files[i.into()] = Some(file);
                Some(i)
            } else {
                None
            }
        } else {
            None
        }
    }

    /// Remove a file
    // TODO: adjust files vector to smaller size if possible
    pub fn remove_file(&self, i: FileHandle) -> Option<File> {
        let mut files = self.files.lock();
        if i.into() < files.len() {
            files[i.into()].take()
        } else {
            None
        }
    }
}
<commit_msg>Move skipping to loop encompasing entire path<commit_after>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::{BTreeMap, Vec, VecDeque};
use spin::Mutex;

use arch;
use context::file::File;
use context::memory::{Grant, Memory, SharedMemory, Tls};
use scheme::{SchemeNamespace, FileHandle};
use syscall::data::Event;
use sync::{WaitMap, WaitQueue};

/// Unique identifier for a context (i.e. `pid`).
use ::core::sync::atomic::AtomicUsize;
int_like!(ContextId, AtomicContextId, usize, AtomicUsize);

/// The status of a context - used for scheduling
/// See syscall::process::waitpid and the sync module for examples of usage
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status {
    Runnable,
    Blocked,
    Exited(usize)
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The ID of this context
    pub id: ContextId,
    /// The ID of the parent context
    pub ppid: ContextId,
    /// The real user id
    pub ruid: u32,
    /// The real group id
    pub rgid: u32,
    /// The real namespace id
    pub rns: SchemeNamespace,
    /// The effective user id
    pub euid: u32,
    /// The effective group id
    pub egid: u32,
    /// The effective namespace id
    pub ens: SchemeNamespace,
    /// Status of context
    pub status: Status,
    /// Context running or not
    pub running: bool,
    /// CPU ID, if locked
    pub cpu_id: Option<usize>,
    /// Context is halting parent
    pub vfork: bool,
    /// Context is being waited on
    pub waitpid: Arc<WaitMap<ContextId, usize>>,
    /// Context should handle pending signals
    pub pending: VecDeque<u8>,
    /// Context should wake up at specified time
    pub wake: Option<(u64, u64)>,
    /// The architecture specific context
    pub arch: arch::context::Context,
    /// Kernel FX - used to store SIMD and FPU registers on context switch
    pub kfx: Option<Box<[u8]>>,
    /// Kernel stack
    pub kstack: Option<Box<[u8]>>,
    /// Executable image
    pub image: Vec<SharedMemory>,
    /// User heap
    pub heap: Option<SharedMemory>,
    /// User stack
    pub stack: Option<Memory>,
    /// User Thread local storage
    pub tls: Option<Tls>,
    /// User grants
    pub grants: Arc<Mutex<Vec<Grant>>>,
    /// The name of the context
    pub name: Arc<Mutex<Vec<u8>>>,
    /// The current working directory
    pub cwd: Arc<Mutex<Vec<u8>>>,
    /// Kernel events
    pub events: Arc<WaitQueue<Event>>,
    /// The process environment
    pub env: Arc<Mutex<BTreeMap<Box<[u8]>, Arc<Mutex<Vec<u8>>>>>>,
    /// The open files in the scheme
    pub files: Arc<Mutex<Vec<Option<File>>>>
}

impl Context {
    pub fn new(id: ContextId) -> Context {
        Context {
            id: id,
            ppid: ContextId::from(0),
            ruid: 0,
            rgid: 0,
            rns: SchemeNamespace::from(0),
            euid: 0,
            egid: 0,
            ens: SchemeNamespace::from(0),
            status: Status::Blocked,
            running: false,
            cpu_id: None,
            vfork: false,
            waitpid: Arc::new(WaitMap::new()),
            pending: VecDeque::new(),
            wake: None,
            arch: arch::context::Context::new(),
            kfx: None,
            kstack: None,
            image: Vec::new(),
            heap: None,
            stack: None,
            tls: None,
            grants: Arc::new(Mutex::new(Vec::new())),
            name: Arc::new(Mutex::new(Vec::new())),
            cwd: Arc::new(Mutex::new(Vec::new())),
            events: Arc::new(WaitQueue::new()),
            env: Arc::new(Mutex::new(BTreeMap::new())),
            files: Arc::new(Mutex::new(Vec::new()))
        }
    }

    /// Make a relative path absolute
    /// Given a cwd of "scheme:/path"
    /// This function will turn "foo" into "scheme:/path/foo"
    /// "/foo" will turn into "scheme:/foo"
    /// "bar:/foo" will be used directly, as it is already absolute
    pub fn canonicalize(&self, path: &[u8]) -> Vec<u8> {
        let mut canon = if path.iter().position(|&b| b == b':').is_none() {
            let cwd = self.cwd.lock();
            if path == b"." {
                cwd.clone()
            } else if path == b".." {
                cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/' || b == b':')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec()
            } else {
                let mut canon = if !path.starts_with(b"/") {
                    let mut c = cwd.clone();
                    if ! c.ends_with(b"/") {
                        c.push(b'/');
                    }
                    c
                } else {
                    cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec()
                };

                canon.extend_from_slice(&path);
                canon
            }
        } else {
            path.to_vec()
        };

        // NOTE: assumes the scheme does not include anything like "../" or "./"
        let mut result = {
            let parts = canon.split(|&c| c == b'/')
                .filter(|&part| part != b".")
                .rev()
                .scan(0, |nskip, part| {
                    if part == b"." {
                        Some(None)
                    } else if part == b".." {
                        *nskip += 1;
                        Some(None)
                    } else {
                        if *nskip > 0 {
                            *nskip -= 1;
                            Some(None)
                        } else {
                            Some(Some(part))
                        }
                    }
                })
                .filter_map(|x| x)
                .collect::<Vec<_>>();
            parts
                .iter()
                .rev()
                .fold(Vec::new(), |mut vec, &part| {
                    vec.extend_from_slice(part);
                    vec.push(b'/');
                    vec
                })
        };
        result.pop(); // remove extra '/'

        // replace with the root of the scheme if it's empty
        if result.len() == 0 {
            let pos = canon.iter()
                            .position(|&b| b == b':')
                            .map_or(canon.len(), |p| p + 1);
            canon.truncate(pos);
            canon
        } else {
            result
        }
    }

    /// Block the context, and return true if it was runnable before being blocked
    pub fn block(&mut self) -> bool {
        if self.status == Status::Runnable {
            self.status = Status::Blocked;
            true
        } else {
            false
        }
    }

    /// Unblock context, and return true if it was blocked before being marked runnable
    pub fn unblock(&mut self) -> bool {
        if self.status == Status::Blocked {
            self.status = Status::Runnable;
            if let Some(cpu_id) = self.cpu_id {
                if cpu_id != ::cpu_id() {
                    // Send IPI if not on current CPU
                    // TODO: Make this more architecture independent
                    unsafe { arch::device::local_apic::LOCAL_APIC.ipi(cpu_id) };
                }
            }
            true
        } else {
            false
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&self, file: File) -> Option<FileHandle> {
        let mut files = self.files.lock();
        for (i, mut file_option) in files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(FileHandle::from(i));
            }
        }
        let len = files.len();
        if len < super::CONTEXT_MAX_FILES {
            files.push(Some(file));
            Some(FileHandle::from(len))
        } else {
            None
        }
    }

    /// Get a file
    pub fn get_file(&self, i: FileHandle) -> Option<File> {
        let files = self.files.lock();
        if i.into() < files.len() {
            files[i.into()]
        } else {
            None
        }
    }

    /// Insert a file with a specific handle number. This is used by dup2
    /// Return the file descriptor number or None if the slot was not empty, or i was invalid
    pub fn insert_file(&self, i: FileHandle, file: File) -> Option<FileHandle> {
        let mut files = self.files.lock();
        if i.into() < super::CONTEXT_MAX_FILES {
            while i.into() >= files.len() {
                files.push(None);
            }
            if files[i.into()].is_none() {
                files[i.into()] = Some(file);
                Some(i)
            } else {
                None
            }
        } else {
            None
        }
    }

    /// Remove a file
    // TODO: adjust files vector to smaller size if possible
    pub fn remove_file(&self, i: FileHandle) -> Option<File> {
        let mut files = self.files.lock();
        if i.into() < files.len() {
            files[i.into()].take()
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>//! Traits for interpreting font data

use font_types::Tag;

use crate::font_data::FontData;

/// A type that can be parsed from raw table data.
pub trait FontRead<'a>: Sized {
    fn read(data: FontData<'a>) -> Result<Self, ReadError>;
}

//NOTE: this is separate so that it can be a super trait of FontReadWithArgs and
//ComputeSize, without them needing to know about each other? I'm not sure this
//is necessary, but I don't know the full heirarchy of traits I'm going to need
//yet, so this seems... okay?

/// A trait for a type that needs additional arguments to be read.
pub trait ReadArgs {
    type Args: Copy;
}

/// A trait for types that require external data in order to be constructed.
pub trait FontReadWithArgs<'a>: Sized + ReadArgs {
    //type Args;
    /// read an item, using the provided args.
    ///
    /// If successful, returns a new item of this type, and the number of bytes
    /// used to construct it.
    ///
    /// If a type requires multiple arguments, they will be passed as a tuple.
    //TODO: split up the 'takes args' and 'reports size' parts of this into
    // separate traits
    fn read_with_args(data: FontData<'a>, args: &Self::Args) -> Result<Self, ReadError>;
}

/// A trait for tables that have multiple possible formats.
pub trait Format<T> {
    /// The format value for this table.
    const FORMAT: T;
}

/// A type that can compute its size at runtime, based on some input.
pub trait ComputeSize: ReadArgs {
    /// Compute the number of bytes required to represent this type.
    fn compute_size(args: &Self::Args) -> usize;
}

/// An error that occurs when reading font data
#[derive(Debug, Clone)]
pub enum ReadError {
    OutOfBounds,
    // i64 is flexible enough to store any value we might encounter
    InvalidFormat(i64),
    InvalidSfnt(u32),
    InvalidArrayLen,
    ValidationError,
    NullOffset,
    TableIsMissing(Tag),
}

impl std::fmt::Display for ReadError {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "Some error I guess")
    }
}

#[cfg(feature = "std")]
impl std::error::Error for ReadError {}
<commit_msg>Impl Display for ReadError<commit_after>//! Traits for interpreting font data

use font_types::Tag;

use crate::font_data::FontData;

/// A type that can be parsed from raw table data.
pub trait FontRead<'a>: Sized {
    fn read(data: FontData<'a>) -> Result<Self, ReadError>;
}

//NOTE: this is separate so that it can be a super trait of FontReadWithArgs and
//ComputeSize, without them needing to know about each other? I'm not sure this
//is necessary, but I don't know the full heirarchy of traits I'm going to need
//yet, so this seems... okay?

/// A trait for a type that needs additional arguments to be read.
pub trait ReadArgs {
    type Args: Copy;
}

/// A trait for types that require external data in order to be constructed.
pub trait FontReadWithArgs<'a>: Sized + ReadArgs {
    //type Args;
    /// read an item, using the provided args.
    ///
    /// If successful, returns a new item of this type, and the number of bytes
    /// used to construct it.
    ///
    /// If a type requires multiple arguments, they will be passed as a tuple.
    //TODO: split up the 'takes args' and 'reports size' parts of this into
    // separate traits
    fn read_with_args(data: FontData<'a>, args: &Self::Args) -> Result<Self, ReadError>;
}

/// A trait for tables that have multiple possible formats.
pub trait Format<T> {
    /// The format value for this table.
    const FORMAT: T;
}

/// A type that can compute its size at runtime, based on some input.
pub trait ComputeSize: ReadArgs {
    /// Compute the number of bytes required to represent this type.
    fn compute_size(args: &Self::Args) -> usize;
}

/// An error that occurs when reading font data
#[derive(Debug, Clone)]
pub enum ReadError {
    OutOfBounds,
    // i64 is flexible enough to store any value we might encounter
    InvalidFormat(i64),
    InvalidSfnt(u32),
    InvalidArrayLen,
    ValidationError,
    NullOffset,
    TableIsMissing(Tag),
}

impl std::fmt::Display for ReadError {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            ReadError::OutOfBounds => write!(f, "An offset was out of bounds"),
            ReadError::InvalidFormat(x) => write!(f, "Invalid format '{x}'"),
            ReadError::InvalidSfnt(ver) => write!(f, "Invalid sfnt version 0x{ver:08X}"),
            ReadError::InvalidArrayLen => {
                write!(f, "Specified array length not a multiple of item size")
            }
            ReadError::ValidationError => write!(f, "A validation error occured"),
            ReadError::NullOffset => write!(f, "An offset was unexpectedly null"),
            ReadError::TableIsMissing(tag) => write!(f, "the {tag} table is missing"),
        }
    }
}

#[cfg(feature = "std")]
impl std::error::Error for ReadError {}
<|endoftext|>