<commit_before>use alga::general::Id;
use na;
use query::{PointQuery, PointProjection};
use shape::{BaseMesh, BaseMeshElement, TriMesh, Polyline};
use bounding_volume::AABB;
use partitioning::{BVTCostFn, BVTVisitor};
use math::{Point, Isometry};

impl<P, M, I, E> PointQuery<P, M> for BaseMesh<P, I, E>
    where P: Point,
          M: Isometry<P>,
          E: BaseMeshElement<I, P> + PointQuery<P, Id> {
    #[inline]
    fn project_point(&self, m: &M, point: &P, _: bool) -> PointProjection<P> {
        let ls_pt = m.inverse_transform_point(point);
        let mut cost_fn = BaseMeshPointProjCostFn { mesh: self, point: &ls_pt };

        let mut proj = self.bvt().best_first_search(&mut cost_fn).unwrap().1;
        proj.point = m.transform_point(&proj.point);

        proj
    }

    #[inline]
    fn contains_point(&self, m: &M, point: &P) -> bool {
        let ls_pt = m.inverse_transform_point(point);
        let mut test = PointContainementTest { mesh: self, point: &ls_pt, found: false };

        self.bvt().visit(&mut test);

        test.found
    }
}

/*
 * Costs function.
 */
struct BaseMeshPointProjCostFn<'a, P: 'a + Point, I: 'a, E: 'a> {
    mesh:  &'a BaseMesh<P, I, E>,
    point: &'a P
}

impl<'a, P, I, E> BVTCostFn<P::Real, usize, AABB<P>> for BaseMeshPointProjCostFn<'a, P, I, E>
    where P: Point,
          E: BaseMeshElement<I, P> + PointQuery<P, Id> {
    type UserData = PointProjection<P>;

    #[inline]
    fn compute_bv_cost(&mut self, aabb: &AABB<P>) -> Option<P::Real> {
        Some(aabb.distance_to_point(&Id::new(), self.point, true))
    }

    #[inline]
    fn compute_b_cost(&mut self, b: &usize) -> Option<(P::Real, PointProjection<P>)> {
        let proj = self.mesh.element_at(*b).project_point(&Id::new(), self.point, true);

        Some((na::distance(self.point, &proj.point), proj))
    }
}

/*
 * Visitor.
 */
/// Bounding Volume Tree visitor collecting nodes that may contain a given point.
struct PointContainementTest<'a, P: 'a + Point, I: 'a, E: 'a> {
    mesh:  &'a BaseMesh<P, I, E>,
    point: &'a P,
    found: bool
}

impl<'a, P, I, E> BVTVisitor<usize, AABB<P>> for PointContainementTest<'a, P, I, E>
    where P: Point,
          E: BaseMeshElement<I, P> + PointQuery<P, Id> {
    #[inline]
    fn visit_internal(&mut self, bv: &AABB<P>) -> bool {
        !self.found && bv.contains_point(&Id::new(), self.point)
    }

    #[inline]
    fn visit_leaf(&mut self, b: &usize, bv: &AABB<P>) {
        if !self.found &&
           bv.contains_point(&Id::new(), self.point) &&
           self.mesh.element_at(*b).contains_point(&Id::new(), self.point) {
            self.found = true;
        }
    }
}

/*
 * fwd impls to exact meshes.
 */
impl<P: Point, M: Isometry<P>> PointQuery<P, M> for TriMesh<P> {
    #[inline]
    fn project_point(&self, m: &M, point: &P, solid: bool) -> PointProjection<P> {
        self.base_mesh().project_point(m, point, solid)
    }

    #[inline]
    fn distance_to_point(&self, m: &M, point: &P, solid: bool) -> P::Real {
        self.base_mesh().distance_to_point(m, point, solid)
    }

    #[inline]
    fn contains_point(&self, m: &M, point: &P) -> bool {
        self.base_mesh().contains_point(m, point)
    }
}

impl<P: Point, M: Isometry<P>> PointQuery<P, M> for Polyline<P> {
    #[inline]
    fn project_point(&self, m: &M, point: &P, solid: bool) -> PointProjection<P> {
        self.base_mesh().project_point(m, point, solid)
    }

    #[inline]
    fn distance_to_point(&self, m: &M, point: &P, solid: bool) -> P::Real {
        self.base_mesh().distance_to_point(m, point, solid)
    }

    #[inline]
    fn contains_point(&self, m: &M, point: &P) -> bool {
        self.base_mesh().contains_point(m, point)
    }
}
<commit_msg>Clean up method signature<commit_after>use alga::general::Id;
use na;
use query::{PointQuery, PointProjection};
use shape::{BaseMesh, BaseMeshElement, TriMesh, Polyline};
use bounding_volume::AABB;
use partitioning::{BVTCostFn, BVTVisitor};
use math::{Point, Isometry};

impl<P, M, I, E> PointQuery<P, M> for BaseMesh<P, I, E>
    where P: Point,
          M: Isometry<P>,
          E: BaseMeshElement<I, P> + PointQuery<P, Id> {
    #[inline]
    fn project_point(&self, m: &M, point: &P, _: bool) -> PointProjection<P> {
        let ls_pt = m.inverse_transform_point(point);
        let mut cost_fn = BaseMeshPointProjCostFn { mesh: self, point: &ls_pt };

        let mut proj = self.bvt().best_first_search(&mut cost_fn).unwrap().1;
        proj.point = m.transform_point(&proj.point);

        proj
    }

    #[inline]
    fn contains_point(&self, m: &M, point: &P) -> bool {
        let ls_pt = m.inverse_transform_point(point);
        let mut test = PointContainementTest { mesh: self, point: &ls_pt, found: false };

        self.bvt().visit(&mut test);

        test.found
    }
}

/*
 * Costs function.
 */
struct BaseMeshPointProjCostFn<'a, P: 'a + Point, I: 'a, E: 'a> {
    mesh:  &'a BaseMesh<P, I, E>,
    point: &'a P
}

impl<'a, P, I, E> BVTCostFn<P::Real, usize, AABB<P>> for BaseMeshPointProjCostFn<'a, P, I, E>
    where P: Point,
          E: BaseMeshElement<I, P> + PointQuery<P, Id> {
    type UserData = PointProjection<P>;

    #[inline]
    fn compute_bv_cost(&mut self, aabb: &AABB<P>) -> Option<P::Real> {
        Some(aabb.distance_to_point(&Id::new(), self.point, true))
    }

    #[inline]
    fn compute_b_cost(&mut self, b: &usize) -> Option<(P::Real, Self::UserData)> {
        let proj = self.mesh.element_at(*b).project_point(&Id::new(), self.point, true);

        Some((na::distance(self.point, &proj.point), proj))
    }
}

/*
 * Visitor.
 */
/// Bounding Volume Tree visitor collecting nodes that may contain a given point.
struct PointContainementTest<'a, P: 'a + Point, I: 'a, E: 'a> {
    mesh:  &'a BaseMesh<P, I, E>,
    point: &'a P,
    found: bool
}

impl<'a, P, I, E> BVTVisitor<usize, AABB<P>> for PointContainementTest<'a, P, I, E>
    where P: Point,
          E: BaseMeshElement<I, P> + PointQuery<P, Id> {
    #[inline]
    fn visit_internal(&mut self, bv: &AABB<P>) -> bool {
        !self.found && bv.contains_point(&Id::new(), self.point)
    }

    #[inline]
    fn visit_leaf(&mut self, b: &usize, bv: &AABB<P>) {
        if !self.found &&
           bv.contains_point(&Id::new(), self.point) &&
           self.mesh.element_at(*b).contains_point(&Id::new(), self.point) {
            self.found = true;
        }
    }
}

/*
 * fwd impls to exact meshes.
 */
impl<P: Point, M: Isometry<P>> PointQuery<P, M> for TriMesh<P> {
    #[inline]
    fn project_point(&self, m: &M, point: &P, solid: bool) -> PointProjection<P> {
        self.base_mesh().project_point(m, point, solid)
    }

    #[inline]
    fn distance_to_point(&self, m: &M, point: &P, solid: bool) -> P::Real {
        self.base_mesh().distance_to_point(m, point, solid)
    }

    #[inline]
    fn contains_point(&self, m: &M, point: &P) -> bool {
        self.base_mesh().contains_point(m, point)
    }
}

impl<P: Point, M: Isometry<P>> PointQuery<P, M> for Polyline<P> {
    #[inline]
    fn project_point(&self, m: &M, point: &P, solid: bool) -> PointProjection<P> {
        self.base_mesh().project_point(m, point, solid)
    }

    #[inline]
    fn distance_to_point(&self, m: &M, point: &P, solid: bool) -> P::Real {
        self.base_mesh().distance_to_point(m, point, solid)
    }

    #[inline]
    fn contains_point(&self, m: &M, point: &P) -> bool {
        self.base_mesh().contains_point(m, point)
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate regex;

#[macro_use]
extern crate lazy_static;

use std::io::prelude::*;
use std::fs::File;
use regex::Regex;
use std::collections::{HashMap, HashSet, VecDeque};

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

impl std::fmt::Display for Position {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(f, "node-x{}-y{}", self.x, self.y)
    }
}

impl Position {
    fn neighbors(&self) -> Vec<Position> {
        let &Position { x, y } = self;
        let mut neighbors = vec![Position { x: x + 1, y: y }, Position { x: x, y: y + 1 }];
        if x != 0 {
            neighbors.push(Position { x: x - 1, y: y });
        }
        if y != 0 {
            neighbors.push(Position { x: x, y: y - 1 });
        }
        neighbors
    }
}

#[derive(Debug, Clone)]
struct NodeInfo {
    size: usize,
    used: usize,
    avail: usize,
}

#[derive(Debug)]
struct NodeListing {
    pos: Position,
    info: NodeInfo,
}

impl std::str::FromStr for NodeListing {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        lazy_static! {
            static ref NODE_RE: Regex =
                Regex::new(
                    r"/dev/grid/node-x(\d+)-y(\d+)\s+(\d+)T\s+(\d+)T\s+(\d+)T\s+\d+%")
                .expect("bad regex NODE_RE");
        }
        if let Some(cap) = NODE_RE.captures(s) {
            Ok(NodeListing {
                pos: Position {
                    x: cap[1].parse().unwrap(),
                    y: cap[2].parse().unwrap(),
                },
                info: NodeInfo {
                    size: cap[3].parse().unwrap(),
                    used: cap[4].parse().unwrap(),
                    avail: cap[5].parse().unwrap(),
                },
            })
        } else {
            Err(format!("Could not parse NodeListing from {}", s))
        }
    }
}

fn valid_pairs(nodes: &HashMap<Position, NodeInfo>) -> Vec<(Position, Position)> {
    let mut pairs = Vec::new();
    for (&pos_a, ref info_a) in nodes.iter() {
        for (&pos_b, ref info_b) in nodes.iter() {
            if info_a.used != 0 && pos_a != pos_b && info_a.used <= info_b.avail {
                pairs.push((pos_a, pos_b));
            }
        }
    }
    pairs
}

fn possible_moves(nodes: &HashMap<Position, NodeInfo>, hole: Position) -> Vec<Position> {
    let mut possibilities = Vec::with_capacity(4);
    let avail = nodes[&hole].avail;
    for pos in hole.neighbors() {
        if let Some(from_info) = nodes.get(&pos) {
            if from_info.used <= avail {
                possibilities.push(pos);
            }
        }
    }
    possibilities
}

fn move_data(nodes: &mut HashMap<Position, NodeInfo>, from: Position, to: Position) {
    let from_info = nodes.get(&from)
        .unwrap_or_else(|| panic!("Invalid move: {} does not exist", from))
        .clone();
    if let Some(ref mut to_info) = nodes.get_mut(&to) {
        if from_info.used > to_info.avail {
            panic!("Invalid move: {} (avail: {}) cannot hold {} (used: {})",
                   to,
                   to_info.avail,
                   from,
                   from_info.avail);
        }
        to_info.used += from_info.used;
        to_info.avail -= from_info.used;
    } else {
        panic!("Invalid move: {} does not exist", to);
    }
    let mut from_info_mut = nodes.get_mut(&from).unwrap();
    from_info_mut.avail = from_info.size;
    from_info_mut.used = 0;
}

fn make_moves(mut nodes: &mut HashMap<Position, NodeInfo>,
              initial_hole: Position,
              moves: &[Position])
              -> Position {
    let mut hole = initial_hole;
    for mov in moves.iter() {
        move_data(&mut nodes, *mov, hole);
        hole = *mov;
    }
    hole
}

fn solve(nodes: &HashMap<Position, NodeInfo>) -> Option<Vec<Position>> {
    let mut state_queue = VecDeque::new();
    let initial_target_loc = nodes.keys()
        .filter(|pos| pos.y == 0)
        .max_by_key(|pos| pos.x)
        .expect("Invalid target state")
        .clone();
    let mut initial_holes: Vec<_> = nodes.iter()
        .filter(|&(_, info)| info.used == 0)
        .map(|(pos, _)| *pos)
        .collect();
    if initial_holes.len() != 1 {
        panic!("sorry, consult a better path-finding algorithm =p");
    }
    let initial_hole = initial_holes.pop().unwrap();
    let mut visited = HashSet::new();
    visited.insert((initial_hole, initial_target_loc));
    state_queue.push_back((initial_target_loc, Vec::new()));
    while let Some((target_loc, moves)) = state_queue.pop_front() {
        let mut state = nodes.clone();
        let old_hole = make_moves(&mut state, initial_hole, &moves);
        for from in possible_moves(&state, old_hole) {
            let mut new_state = state.clone();
            move_data(&mut new_state, from, old_hole);
            let mut new_moves = moves.clone();
            new_moves.push(from);
            let new_target_loc = if from == target_loc {
                old_hole
            } else {
                target_loc
            };
            if new_target_loc.x == 0 && new_target_loc.y == 0 {
                return Some(new_moves);
            }
            if !visited.contains(&(from, new_target_loc)) {
                visited.insert((from, new_target_loc));
                state_queue.push_back((new_target_loc, new_moves));
            }
        }
    }
    None
}

fn parse_args() -> std::io::Result<String> {
    let matches = clap::App::new("Day 22")
        .author("Devon Hollowood")
        .arg(clap::Arg::with_name("nodes")
            .index(1)
            .help("file containing output of nodes `df`. Reads from stdin otherwise"))
        .get_matches();
    let source = matches.value_of_os("nodes");
    let mut contents = String::new();
    match source {
        Some(filename) => {
            let mut input = File::open(filename)?;
            input.read_to_string(&mut contents)?;
        }
        None => {
            let mut input = std::io::stdin();
            input.read_to_string(&mut contents)?;
        }
    }
    Ok(contents)
}

fn main() {
    let input = parse_args().unwrap_or_else(|err| panic!("Error reading args: {}", err));
    let nodes: HashMap<Position, NodeInfo> = input.lines()
        .map(|line| line.trim().parse::<NodeListing>())
        .filter_map(|r| r.ok())
        .map(|listing| (listing.pos, listing.info))
        .collect();
    println!("number of valid node pairs: {}", valid_pairs(&nodes).len());
    if let Some(solution) = solve(&nodes) {
        let mut initial_holes: Vec<_> = nodes.iter()
            .filter(|&(_, info)| info.used == 0)
            .map(|(pos, _)| *pos)
            .collect();
        if initial_holes.len() != 1 {
            panic!("sorry, consult a better path-finding algorithm =p");
        }
        let initial_hole = initial_holes.pop().unwrap();
        println!("Solution:");
        println!("{}", initial_hole);
        for mov in &solution {
            println!("-> {}", mov);
        }
        println!("Total moves taken: {}", solution.len())
    }
}

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

    #[test]
    fn example() {
        let nodes = ["/dev/grid/node-x0-y0   10T    8T     2T   80%",
                     "/dev/grid/node-x0-y1   11T    6T     5T   54%",
                     "/dev/grid/node-x0-y2   32T   28T     4T   87%",
                     "/dev/grid/node-x1-y0    9T    7T     2T   77%",
                     "/dev/grid/node-x1-y1    8T    0T     8T    0%",
                     "/dev/grid/node-x1-y2   11T    7T     4T   63%",
                     "/dev/grid/node-x2-y0   10T    6T     4T   60%",
                     "/dev/grid/node-x2-y1    9T    8T     1T   88%",
                     "/dev/grid/node-x2-y2    9T    6T     3T   66%"]
            .into_iter()
            .map(|s| s.parse::<NodeListing>().unwrap())
            .map(|listing| (listing.pos, listing.info))
            .collect();
        assert_eq!(solve(&nodes).unwrap().len(), 7);
    }
}
<commit_msg>Day 22 clippy<commit_after>extern crate clap;
extern crate regex;

#[macro_use]
extern crate lazy_static;

use std::io::prelude::*;
use std::fs::File;
use regex::Regex;
use std::collections::{HashMap, HashSet, VecDeque};

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

impl std::fmt::Display for Position {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(f, "node-x{}-y{}", self.x, self.y)
    }
}

impl Position {
    fn neighbors(&self) -> Vec<Position> {
        let &Position { x, y } = self;
        let mut neighbors = vec![Position { x: x + 1, y: y }, Position { x: x, y: y + 1 }];
        if x != 0 {
            neighbors.push(Position { x: x - 1, y: y });
        }
        if y != 0 {
            neighbors.push(Position { x: x, y: y - 1 });
        }
        neighbors
    }
}

#[derive(Debug, Clone)]
struct NodeInfo {
    size: usize,
    used: usize,
    avail: usize,
}

#[derive(Debug)]
struct NodeListing {
    pos: Position,
    info: NodeInfo,
}

impl std::str::FromStr for NodeListing {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        lazy_static! {
            static ref NODE_RE: Regex =
                Regex::new(
                    r"/dev/grid/node-x(\d+)-y(\d+)\s+(\d+)T\s+(\d+)T\s+(\d+)T\s+\d+%")
                .expect("bad regex NODE_RE");
        }
        if let Some(cap) = NODE_RE.captures(s) {
            Ok(NodeListing {
                pos: Position {
                    x: cap[1].parse().unwrap(),
                    y: cap[2].parse().unwrap(),
                },
                info: NodeInfo {
                    size: cap[3].parse().unwrap(),
                    used: cap[4].parse().unwrap(),
                    avail: cap[5].parse().unwrap(),
                },
            })
        } else {
            Err(format!("Could not parse NodeListing from {}", s))
        }
    }
}

fn valid_pairs(nodes: &HashMap<Position, NodeInfo>) -> Vec<(Position, Position)> {
    let mut pairs = Vec::new();
    for (&pos_a, info_a) in nodes.iter() {
        for (&pos_b, info_b) in nodes.iter() {
            if info_a.used != 0 && pos_a != pos_b && info_a.used <= info_b.avail {
                pairs.push((pos_a, pos_b));
            }
        }
    }
    pairs
}

fn possible_moves(nodes: &HashMap<Position, NodeInfo>, hole: Position) -> Vec<Position> {
    let mut possibilities = Vec::with_capacity(4);
    let avail = nodes[&hole].avail;
    for pos in hole.neighbors() {
        if let Some(from_info) = nodes.get(&pos) {
            if from_info.used <= avail {
                possibilities.push(pos);
            }
        }
    }
    possibilities
}

fn move_data(nodes: &mut HashMap<Position, NodeInfo>, from: Position, to: Position) {
    let from_info = nodes.get(&from)
        .unwrap_or_else(|| panic!("Invalid move: {} does not exist", from))
        .clone();
    if let Some(ref mut to_info) = nodes.get_mut(&to) {
        if from_info.used > to_info.avail {
            panic!("Invalid move: {} (avail: {}) cannot hold {} (used: {})",
                   to,
                   to_info.avail,
                   from,
                   from_info.avail);
        }
        to_info.used += from_info.used;
        to_info.avail -= from_info.used;
    } else {
        panic!("Invalid move: {} does not exist", to);
    }
    let mut from_info_mut = nodes.get_mut(&from).unwrap();
    from_info_mut.avail = from_info.size;
    from_info_mut.used = 0;
}

fn make_moves(mut nodes: &mut HashMap<Position, NodeInfo>,
              initial_hole: Position,
              moves: &[Position])
              -> Position {
    let mut hole = initial_hole;
    for mov in moves.iter() {
        move_data(&mut nodes, *mov, hole);
        hole = *mov;
    }
    hole
}

fn solve(nodes: &HashMap<Position, NodeInfo>) -> Option<Vec<Position>> {
    let mut state_queue = VecDeque::new();
    let initial_target_loc = *nodes.keys()
        .filter(|pos| pos.y == 0)
        .max_by_key(|pos| pos.x)
        .expect("Invalid target state");
    let mut initial_holes: Vec<_> = nodes.iter()
        .filter(|&(_, info)| info.used == 0)
        .map(|(pos, _)| *pos)
        .collect();
    if initial_holes.len() != 1 {
        panic!("sorry, consult a better path-finding algorithm =p");
    }
    let initial_hole = initial_holes.pop().unwrap();
    let mut visited = HashSet::new();
    visited.insert((initial_hole, initial_target_loc));
    state_queue.push_back((initial_target_loc, Vec::new()));
    while let Some((target_loc, moves)) = state_queue.pop_front() {
        let mut state = nodes.clone();
        let old_hole = make_moves(&mut state, initial_hole, &moves);
        for from in possible_moves(&state, old_hole) {
            let mut new_state = state.clone();
            move_data(&mut new_state, from, old_hole);
            let mut new_moves = moves.clone();
            new_moves.push(from);
            let new_target_loc = if from == target_loc {
                old_hole
            } else {
                target_loc
            };
            if new_target_loc.x == 0 && new_target_loc.y == 0 {
                return Some(new_moves);
            }
            if !visited.contains(&(from, new_target_loc)) {
                visited.insert((from, new_target_loc));
                state_queue.push_back((new_target_loc, new_moves));
            }
        }
    }
    None
}

fn parse_args() -> std::io::Result<String> {
    let matches = clap::App::new("Day 22")
        .author("Devon Hollowood")
        .arg(clap::Arg::with_name("nodes")
            .index(1)
            .help("file containing output of nodes `df`. Reads from stdin otherwise"))
        .get_matches();
    let source = matches.value_of_os("nodes");
    let mut contents = String::new();
    match source {
        Some(filename) => {
            let mut input = File::open(filename)?;
            input.read_to_string(&mut contents)?;
        }
        None => {
            let mut input = std::io::stdin();
            input.read_to_string(&mut contents)?;
        }
    }
    Ok(contents)
}

fn main() {
    let input = parse_args().unwrap_or_else(|err| panic!("Error reading args: {}", err));
    let nodes: HashMap<Position, NodeInfo> = input.lines()
        .map(|line| line.trim().parse::<NodeListing>())
        .filter_map(|r| r.ok())
        .map(|listing| (listing.pos, listing.info))
        .collect();
    println!("number of valid node pairs: {}", valid_pairs(&nodes).len());
    if let Some(solution) = solve(&nodes) {
        let mut initial_holes: Vec<_> = nodes.iter()
            .filter(|&(_, info)| info.used == 0)
            .map(|(pos, _)| *pos)
            .collect();
        if initial_holes.len() != 1 {
            panic!("sorry, consult a better path-finding algorithm =p");
        }
        let initial_hole = initial_holes.pop().unwrap();
        println!("Solution:");
        println!("{}", initial_hole);
        for mov in &solution {
            println!("-> {}", mov);
        }
        println!("Total moves taken: {}", solution.len())
    }
}

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

    #[test]
    fn example() {
        let nodes = ["/dev/grid/node-x0-y0   10T    8T     2T   80%",
                     "/dev/grid/node-x0-y1   11T    6T     5T   54%",
                     "/dev/grid/node-x0-y2   32T   28T     4T   87%",
                     "/dev/grid/node-x1-y0    9T    7T     2T   77%",
                     "/dev/grid/node-x1-y1    8T    0T     8T    0%",
                     "/dev/grid/node-x1-y2   11T    7T     4T   63%",
                     "/dev/grid/node-x2-y0   10T    6T     4T   60%",
                     "/dev/grid/node-x2-y1    9T    8T     1T   88%",
                     "/dev/grid/node-x2-y2    9T    6T     3T   66%"]
            .into_iter()
            .map(|s| s.parse::<NodeListing>().unwrap())
            .map(|listing| (listing.pos, listing.info))
            .collect();
        assert_eq!(solve(&nodes).unwrap().len(), 7);
    }
}
<|endoftext|>


<commit_before>#![warn(missing_docs)]
#![feature(slice_patterns)]

//! rebind
//! =========
//!
//! A library for binding input keys to actions, and modifying mouse behaviour. Keys can be
//! bound to actions, and then translated during runtime. `Keys` are mapped to `Actions` using
//! a `HashMap`, so lookup time is constant.

extern crate input;
extern crate itertools;
extern crate window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;

#[cfg(test)]
mod test;

use input::{Input, Button, Motion};
use window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::cmp::{PartialEq, Eq};
use std::fmt::{Debug, Formatter, Result};
use std::hash::Hash;
use viewport::Viewport;

pub use builder::RebindBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward. Needs to be hashable, as it is used as a
/// lookup key when rebinding an action to a different button.
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// A three-element tuple of Option<Button>. For simplicity, a maximum number of 3
/// buttons can be bound to each action, and this is exposed through the `InputRebind`
/// struct.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    /// Creates a new tuple with no buttons in it (equivalent to `Default::default()`).
    pub fn new() -> Self { Default::default() }

    /// Check if the button is in the tuple.
    pub fn contains(&self, button: Button) -> bool {
        let sbtn = Some(button);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    /// Insert a button into the tuple if there is room, searching from left to right.
    /// If the button is inserted, returns true. Otherwise, if the button is not inserted,
    /// this function returns false.
    pub fn insert_inplace(&mut self, button: Button) -> bool {
        let sbtn = Some(button);
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(sbtn, b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, sbtn, c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, sbtn); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    /// Creates a new tuple with no buttons in it.
    fn default() -> Self { ButtonTuple(None, None, None) }
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone, Debug, PartialEq)]
pub struct InputTranslator<A: Action> {
    keymap: HashMap<Button, A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {
    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: HashMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event. Returns `None` if there is no
    /// action associated with the `Input` variant.
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.get(&$but_var).map(|x| *x) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

impl Debug for MouseTranslationData {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}, {}, {}, {}, ({}, {})",
               self.x_axis_motion_inverted,
               self.y_axis_motion_inverted,
               self.x_axis_scroll_inverted,
               self.y_axis_scroll_inverted,
               self.viewport_size.width,
               self.viewport_size.height)
    }
}

impl PartialEq for MouseTranslationData {
    fn eq(&self, other: &Self) -> bool {
        self.x_axis_motion_inverted == other.x_axis_motion_inverted &&
        self.y_axis_motion_inverted == other.y_axis_motion_inverted &&
        self.x_axis_scroll_inverted == other.x_axis_scroll_inverted &&
        self.y_axis_scroll_inverted == other.y_axis_scroll_inverted &&
        self.viewport_size.width    == other.viewport_size.width &&
        self.viewport_size.height   == other.viewport_size.height
    }
}

#[derive(Clone, Debug, PartialEq)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

/// An interface for rebinding keys to actions. This is freely convertable to and
/// from an InputTranslator.
#[derive(Clone, Debug, PartialEq)]
pub struct InputRebind<A: Action> {
    keymap: HashMap<A, ButtonTuple>,
    mouse_data: MouseTranslationData
}

impl<A: Action> InputRebind<A> {
    /// Creates a new InputRebind with no stored Action/ButtonTuple pairs.
    pub fn new(size: Size) -> Self {
        InputRebind {
            keymap: HashMap::new(),
            mouse_data: MouseTranslationData::new(size)
        }
    }

    /// Insert an Action into this InputRebind. If the Action is already in the
    /// InputRebind, then its ButtonTuple will be reset to (None, None, None), and
    /// the old ButtonTuple will be returned.
    pub fn insert_action(&mut self, action: A) -> Option<ButtonTuple> {
        self.keymap.insert(action, ButtonTuple::new())
    }

    /// Insert an Action into this InputRebind, and assign it to the ButtonTuple.
    /// If the Action is already in the InputRebind, the old ButtonTuple will be
    /// returned.
    pub fn insert_action_with_buttons(&mut self, action: A, buttons: ButtonTuple) -> Option<ButtonTuple> {
        self.keymap.insert(action, buttons)
    }

    /// Return a reference to the current ButtonTuple stored for an action. If the action
    /// is not stored in this InputRebind, then `None` will be returned.
    pub fn get_bindings(&self, action: &A) -> Option<&ButtonTuple> {
        self.keymap.get(action)
    }

    /// Returns a mutable reference to the current ButtonTuple stored for an action. If the
    /// action is not stored in this InputRebind, then `None` will be returned.
    pub fn get_bindings_mut(&mut self, action: &mut A) -> Option<&mut ButtonTuple> {
        self.keymap.get_mut(action)
    }

    /// Returns a reference to the boolean which represents whether x axis scrolling is inverted.
    pub fn get_x_scroll_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_scroll_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether x axis scrolling is inverted.
    pub fn get_x_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_scroll_inverted
    }

    /// Returns a reference to the boolean which represents whether y axis scrolling is inverted.
    pub fn get_y_scroll_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_scroll_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether y axis scrolling is inverted.
    pub fn get_y_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_scroll_inverted
    }

    /// Returns a reference to the boolean which represents whether mouse movement along the x axis is
    /// inverted.
    pub fn get_x_motion_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_motion_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether mouse movement along the
    /// x axis is inverted.
    pub fn get_x_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_motion_inverted
    }

    /// Returns a reference to the boolean which represents whether mouse movement along the y axis is
    /// inverted.
    pub fn get_y_motion_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_motion_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether mouse movement along the
    /// y axis is inverted.
    pub fn get_y_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_motion_inverted
    }

    /// Returns a reference to the currently stored viewport size used for calculating the imaginary mouse
    /// position.
    pub fn get_viewport_size(&self) -> &Size {
        &self.mouse_data.viewport_size
    }

    /// Returns a mutable reference to the currently stored viewport size used for calculating the imaginary
    /// mouse position.
    pub fn get_viewport_size_mut(&mut self) -> &mut Size {
        &mut self.mouse_data.viewport_size
    }
}

impl<A: Action> Default for InputRebind<A> {
    /// Creates an `InputRebind` with no pairs. In addition, the viewport size is set to [800, 600].
    fn default() -> Self {
        InputRebind::new((800, 600).into())
    }
}

impl<A: Action> Into<InputTranslator<A>> for InputRebind<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputTranslator<A> {
        let mut input_translator = InputTranslator::new(self.mouse_data.viewport_size);
        input_translator.mouse_translator.data = self.mouse_data;
        input_translator.keymap = self.keymap.values()
                                             .flat_map(|&bt| bt.into_iter())
                                             .filter_map(|x| x)
                                             .zip(self.keymap.keys().cloned())
                                             .collect();

        input_translator
    }
}

impl<A: Action> Into<InputRebind<A>> for InputTranslator<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputRebind<A> {
        use itertools::Itertools;

        let mut input_rebind = InputRebind::new(self.mouse_translator.data.viewport_size);
        input_rebind.mouse_data = self.mouse_translator.data;
        input_rebind.keymap = self.keymap.keys()
                                         .map(|x| vec![Some(x)])
                                         .coalesce(|b0, b1| if b0 == b1 {
                                                 Ok(b0.into_iter().chain(b1).collect())
                                             } else {
                                                 Err((b0, b1))
                                             })
                                         .map(|s| if let [b0, b1, b2] = &s.iter()
                                                                          .fuse()
                                                                          .take(3)
                                                                          .map(|x| x.cloned())
                                                                          .collect::<Vec<_>>()[..] {
                                                 ButtonTuple(b0, b1, b2)
                                             } else {
                                                 unreachable!();
                                             })
                                         .zip(self.keymap.values().cloned())
                                         .map(|(k, v)| (v, k))
                                         .collect();

        input_rebind
    }
}

impl ButtonTuple {
    fn into_iter(self) -> ButtonTupleIterator {
        ButtonTupleIterator {
            button_tuple: self,
            i: 0
        }
    }
}

struct ButtonTupleIterator {
    button_tuple: ButtonTuple,
    i: usize
}

impl Iterator for ButtonTupleIterator {
    type Item = Option<Button>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        self.i += 1;
        match i {
            0 => Some(self.button_tuple.0),
            1 => Some(self.button_tuple.1),
            2 => Some(self.button_tuple.2),
            _ => None
        }
    }
}
<commit_msg>Remove unnecessary allow(missing_docs) annotations on trait implementation methods<commit_after>#![warn(missing_docs)]
#![feature(slice_patterns)]

//! rebind
//! =========
//!
//! A library for binding input keys to actions, and modifying mouse behaviour. Keys can be
//! bound to actions, and then translated during runtime. `Keys` are mapped to `Actions` using
//! a `HashMap`, so lookup time is constant.

extern crate input;
extern crate itertools;
extern crate window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;

#[cfg(test)]
mod test;

use input::{Input, Button, Motion};
use window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::cmp::{PartialEq, Eq};
use std::fmt::{Debug, Formatter, Result};
use std::hash::Hash;
use viewport::Viewport;

pub use builder::RebindBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward. Needs to be hashable, as it is used as a
/// lookup key when rebinding an action to a different button.
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// A three-element tuple of Option<Button>. For simplicity, a maximum number of 3
/// buttons can be bound to each action, and this is exposed through the `InputRebind`
/// struct.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    /// Creates a new tuple with no buttons in it (equivalent to `Default::default()`).
    pub fn new() -> Self { Default::default() }

    /// Check if the button is in the tuple.
    pub fn contains(&self, button: Button) -> bool {
        let sbtn = Some(button);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    /// Insert a button into the tuple if there is room, searching from left to right.
    /// If the button is inserted, returns true. Otherwise, if the button is not inserted,
    /// this function returns false.
    pub fn insert_inplace(&mut self, button: Button) -> bool {
        let sbtn = Some(button);
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(sbtn, b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, sbtn, c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, sbtn); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    /// Creates a new tuple with no buttons in it.
    fn default() -> Self { ButtonTuple(None, None, None) }
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone, Debug, PartialEq)]
pub struct InputTranslator<A: Action> {
    keymap: HashMap<Button, A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {
    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: HashMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event. Returns `None` if there is no
    /// action associated with the `Input` variant.
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.get(&$but_var).map(|x| *x) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

impl Debug for MouseTranslationData {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}, {}, {}, {}, ({}, {})",
               self.x_axis_motion_inverted,
               self.y_axis_motion_inverted,
               self.x_axis_scroll_inverted,
               self.y_axis_scroll_inverted,
               self.viewport_size.width,
               self.viewport_size.height)
    }
}

impl PartialEq for MouseTranslationData {
    fn eq(&self, other: &Self) -> bool {
        self.x_axis_motion_inverted == other.x_axis_motion_inverted &&
        self.y_axis_motion_inverted == other.y_axis_motion_inverted &&
        self.x_axis_scroll_inverted == other.x_axis_scroll_inverted &&
        self.y_axis_scroll_inverted == other.y_axis_scroll_inverted &&
        self.viewport_size.width    == other.viewport_size.width &&
        self.viewport_size.height   == other.viewport_size.height
    }
}

#[derive(Clone, Debug, PartialEq)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

/// An interface for rebinding keys to actions. This is freely convertable to and
/// from an InputTranslator.
#[derive(Clone, Debug, PartialEq)]
pub struct InputRebind<A: Action> {
    keymap: HashMap<A, ButtonTuple>,
    mouse_data: MouseTranslationData
}

impl<A: Action> InputRebind<A> {
    /// Creates a new InputRebind with no stored Action/ButtonTuple pairs.
    pub fn new(size: Size) -> Self {
        InputRebind {
            keymap: HashMap::new(),
            mouse_data: MouseTranslationData::new(size)
        }
    }

    /// Insert an Action into this InputRebind. If the Action is already in the
    /// InputRebind, then its ButtonTuple will be reset to (None, None, None), and
    /// the old ButtonTuple will be returned.
    pub fn insert_action(&mut self, action: A) -> Option<ButtonTuple> {
        self.keymap.insert(action, ButtonTuple::new())
    }

    /// Insert an Action into this InputRebind, and assign it to the ButtonTuple.
    /// If the Action is already in the InputRebind, the old ButtonTuple will be
    /// returned.
    pub fn insert_action_with_buttons(&mut self, action: A, buttons: ButtonTuple) -> Option<ButtonTuple> {
        self.keymap.insert(action, buttons)
    }

    /// Return a reference to the current ButtonTuple stored for an action. If the action
    /// is not stored in this InputRebind, then `None` will be returned.
    pub fn get_bindings(&self, action: &A) -> Option<&ButtonTuple> {
        self.keymap.get(action)
    }

    /// Returns a mutable reference to the current ButtonTuple stored for an action. If the
    /// action is not stored in this InputRebind, then `None` will be returned.
    pub fn get_bindings_mut(&mut self, action: &mut A) -> Option<&mut ButtonTuple> {
        self.keymap.get_mut(action)
    }

    /// Returns a reference to the boolean which represents whether x axis scrolling is inverted.
    pub fn get_x_scroll_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_scroll_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether x axis scrolling is inverted.
    pub fn get_x_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_scroll_inverted
    }

    /// Returns a reference to the boolean which represents whether y axis scrolling is inverted.
    pub fn get_y_scroll_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_scroll_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether y axis scrolling is inverted.
    pub fn get_y_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_scroll_inverted
    }

    /// Returns a reference to the boolean which represents whether mouse movement along the x axis is
    /// inverted.
    pub fn get_x_motion_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_motion_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether mouse movement along the
    /// x axis is inverted.
    pub fn get_x_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_motion_inverted
    }

    /// Returns a reference to the boolean which represents whether mouse movement along the y axis is
    /// inverted.
    pub fn get_y_motion_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_motion_inverted
    }

    /// Returns a mutable reference to the boolean which represents whether mouse movement along the
    /// y axis is inverted.
    pub fn get_y_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_motion_inverted
    }

    /// Returns a reference to the currently stored viewport size used for calculating the imaginary mouse
    /// position.
    pub fn get_viewport_size(&self) -> &Size {
        &self.mouse_data.viewport_size
    }

    /// Returns a mutable reference to the currently stored viewport size used for calculating the imaginary
    /// mouse position.
    pub fn get_viewport_size_mut(&mut self) -> &mut Size {
        &mut self.mouse_data.viewport_size
    }
}

impl<A: Action> Default for InputRebind<A> {
    /// Creates an `InputRebind` with no pairs. In addition, the viewport size is set to [800, 600].
    fn default() -> Self {
        InputRebind::new((800, 600).into())
    }
}

impl<A: Action> Into<InputTranslator<A>> for InputRebind<A> {
    fn into(self) -> InputTranslator<A> {
        let mut input_translator = InputTranslator::new(self.mouse_data.viewport_size);
        input_translator.mouse_translator.data = self.mouse_data;
        input_translator.keymap = self.keymap.values()
                                             .flat_map(|&bt| bt.into_iter())
                                             .filter_map(|x| x)
                                             .zip(self.keymap.keys().cloned())
                                             .collect();

        input_translator
    }
}

impl<A: Action> Into<InputRebind<A>> for InputTranslator<A> {
    fn into(self) -> InputRebind<A> {
        use itertools::Itertools;

        let mut input_rebind = InputRebind::new(self.mouse_translator.data.viewport_size);
        input_rebind.mouse_data = self.mouse_translator.data;
        input_rebind.keymap = self.keymap.keys()
                                         .map(|x| vec![Some(x)])
                                         .coalesce(|b0, b1| if b0 == b1 {
                                                 Ok(b0.into_iter().chain(b1).collect())
                                             } else {
                                                 Err((b0, b1))
                                             })
                                         .map(|s| if let [b0, b1, b2] = &s.iter()
                                                                          .fuse()
                                                                          .take(3)
                                                                          .map(|x| x.cloned())
                                                                          .collect::<Vec<_>>()[..] {
                                                 ButtonTuple(b0, b1, b2)
                                             } else {
                                                 unreachable!();
                                             })
                                         .zip(self.keymap.values().cloned())
                                         .map(|(k, v)| (v, k))
                                         .collect();

        input_rebind
    }
}

impl ButtonTuple {
    fn into_iter(self) -> ButtonTupleIterator {
        ButtonTupleIterator {
            button_tuple: self,
            i: 0
        }
    }
}

struct ButtonTupleIterator {
    button_tuple: ButtonTuple,
    i: usize
}

impl Iterator for ButtonTupleIterator {
    type Item = Option<Button>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        self.i += 1;
        match i {
            0 => Some(self.button_tuple.0),
            1 => Some(self.button_tuple.1),
            2 => Some(self.button_tuple.2),
            _ => None
        }
    }
}
<|endoftext|>


<commit_before>//! Macro for declaring/implementing traits with fake associated consts (in stable Rust)
//!
//! Currently very fragile in terms of syntax: does not support traits/impls with _any_ kind of
//! generic parameters (either lifetimes or types).
//!
//! The same macro is used for declaring a trait with associated consts, implementing such a trait,
//! and accessing the consts.
//!
//! The syntax is the same as that proposed for associated consts, _except_ that:
//!
//! - all consts must be at the beginning of the trait/impl, before any functions
//! - const declarations end with a comma, instead of a semicolon (this is due to a limitation of
//! the macro system -- a type followed by a semicolon is for some reason not parseable)
//!
//! See the tests for example usage.
//!
//! At the moment they are not consts at all -- they simply expand to static functions with the
//! same name as the declared const. You may therefore access the const by calling
//! `Trait::CONST()`, or (for future proofing, in case the macro implementation changes), call the
//! macro again to access the const, as `guilty!(Trait::CONST)`.

/// Macro for declaring/implementing traits with fake associated consts
///
/// See the [crate-level documentation](index.html) for more.
#[macro_export]
macro_rules! guilty {
    // These are the user facing invocations:

    // FIXME what if the traits have docs/attributes?
    // 1. define a private trait
    ($(#[$attr:meta])* trait $traitname:ident $body:tt) => {
        guilty!(INTERNAL: DEFINE TRAIT, [$(#[$attr])*] [trait] [$traitname], $body);
    };
    // 2. define a public trait
    ($(#[$attr:meta])* pub trait $traitname:ident $body:tt) => {
        guilty!(INTERNAL: DEFINE TRAIT, [$(#[$attr])*] [pub trait] [$traitname], $body);
    };
    // 3. implement a trait (public or private)
    (impl $traitname:ident for $structname:ident $body:tt) => {
        guilty!(INTERNAL: DEFINE IMPL, $traitname, $structname, $body);
    };
    // 4. access a const declared with this macro
    ($structname:ident :: $constname:ident) => {
        guilty!(INTERNAL: ACCESS CONST, $structname, $constname);
    };

    // Following are the internal macro calls
    // Since you can't export a macro which calls other unexported macros, guilty! calls itself
    // recursively in order to continue parsing. The invocation syntax for all these recursive
    // calls starts with the tokens `INTERNAL:`.
    //
    // The general strategy for parsing these declarations is we parse one const declaration from
    // the beginning of the trait/impl at a time, turning it into a static function which is
    // appended to the end of the trait/impl. When there are no more consts, the recursion stops
    // and the trait/impl is outputted (with an indirection through AS ITEM to appease the parser).

    // parse-trait-defconst: parse a trait with a const (that has a default value) as the first declaration
    // the square brackets contain [trait Trait] or [pub trait Trait]
    // this calls on to:
    //  - itself if there is another default-valued const
    //  - parse-trait-nodefconst if there is another const with no default value
    //  - def-trait-fn/def-trait-attr/def-trait-ty if there are no more consts
    // FIXME what if the const has docs/attributes?
    (INTERNAL: DEFINE TRAIT, [$(#[$attr:meta])*] [$($before:ident)+] [$($traitname:tt)*],
     {
         const $constname:ident : $consttype:ty = $constdefault:expr,
         $($body:tt)*
     }) => {
        guilty!(INTERNAL: DEFINE TRAIT, [$(#[$attr])*] [$($before)+] [$($traitname)*],
                {
                    $($body)*
                    #[allow(non_snake_case)] fn $constname() -> $consttype { $constdefault }
                });
    };
    // parse-trait-nodefconst: parse a trait with a const (that has no default value) as the first declaration
    // this calls on to:
    //  - itself is there is another non-default-valued const
    //  - parse-trait-defconst if there is another default-valued const
    //  - def-trait-fn/def-trait-attr/def-trait-ty if there are no more consts
    (INTERNAL: DEFINE TRAIT, [$(#[$attr:meta])*] [$($before:ident)+] [$($traitname:tt)*],
     {
         const $constname:ident : $consttype:ty,
         $($body:tt)*
     }) => {
        guilty!(INTERNAL: DEFINE TRAIT, [$(#[$attr])*] [$($before)+] [$($traitname)*],
                {
                    $($body)*
                    #[allow(non_snake_case)] fn $constname() -> $consttype;
                });
    };
    // def-trait-fn: output a trait that has no consts at the beginning (starts with an unadorned fn)
    // indirection through item-redir
    (INTERNAL: DEFINE TRAIT, [$(#[$attr:meta])*] [$($before:ident)+] [$($traitname:tt)*],
     {
         fn $($body:tt)*
     }) => {
        guilty!(INTERNAL: AS ITEM, $(#[$attr])* $($before)+ $($traitname)* { fn $($body)* });
    };
    // def-trait-attr: output a trait that has no consts at the beginning (starts with fn that has
    //    docs/attributes)
    // indirection through item-redir
    (INTERNAL: DEFINE TRAIT, [$(#[$attr:meta])*] [$($before:ident)+] [$($traitname:tt)*],
     {
         # $($body:tt)*
     }) => {
        guilty!(INTERNAL: AS ITEM, $(#[$attr])* $($before)+ $($traitname)* { # $($body)* });
    };
    // def-trait-ty: output a trait that has no consts at the beginning (starts with an associated type)
    // indirection through item-redir
    (INTERNAL: DEFINE TRAIT, [$(#[$attr:meta])*] [$($before:ident)+] [$($traitname:tt)*],
     {
         type $($body:tt)*
     }) => {
        guilty!(INTERNAL: AS ITEM, $(#[$attr])* $($before)+ $($traitname)* { type $($body)* });
    };

    // parse-impl-const: parse an impl with a const as the first declaration
    // calls on to:
    //  - itself if there is another const
    //  - def-impl-fn/def-impl-ty if there are no more consts
    (INTERNAL: DEFINE IMPL, $traitname:ty, $structname:ident,
     {
         const $constname:ident : $consttype:ty = $constvalue:expr,
         $($body:tt)*
     }) => {
        guilty!(INTERNAL: DEFINE IMPL, $traitname, $structname,
                {
                    $($body)*
                    fn $constname() -> $consttype { $constvalue }
                });
    };
    // def-impl-fn: output an impl that has no consts at the beginning (starts with fn)
    // indirection through item-redir
    (INTERNAL: DEFINE IMPL, $traitname:ty, $structname:ident,
     {
         fn $($body:tt)*
     }) => {
        guilty!(INTERNAL: AS ITEM, impl $traitname for $structname { fn $($body)* });
    };
    // def-impl-ty: output an impl that has no consts at the beginning (starts with type)
    // indirection through item-redir
    (INTERNAL: DEFINE IMPL, $traitname:ty, $structname:ident,
     {
         type $($body:tt)*
     }) => {
        guilty!(INTERNAL: AS ITEM, impl $traitname for $structname { type $($body)* });
    };
    // FIXME: need another DEFINE IMPL that's like def-trait-attr?

    // access: access a const defined with this macro
    // For now, it just calls the function, since we turn consts into functions. In the future, it
    // might do something more clever if the implementation changes.
    (INTERNAL: ACCESS CONST, $structname:ident, $constname:ident) => {{
        $structname :: $constname ()
    }};

    // item-redir: Item redirection.
    // For some reason the parser sometimes complains "expected item" when you are trying to output
    // a perfectly good item. The solution (sometimes) is to redirect through a macro like this.
    (INTERNAL: AS ITEM, $i:item) => ($i)
}

/*
 * BEFORE
 *
trait Trait {
    const WithDefault: i32 = 0,
    const NoDefault: Self,

    fn with_impl(&self) -> &Self { self }
    fn no_impl(&self) -> &Self;
}

struct Struct { i: i32 }

impl Trait for Struct {
    const WithDefault: i32 = 42,
    const NoDefault: Self = Self { i: 42 },

    fn no_impl(&self) -> &Self { self }
}
*/

/*
 * AFTER
 *
trait Trait {
    fn with_impl(&self) -> &Self { self }
    fn no_impl(&self) -> &Self;

    #[allow(non_snake_case)] fn WithDefault() -> i32 { 0 }
    #[allow(non_snake_case)] fn NoDefault() -> Self;
}

struct Struct { i: i32 }

impl Trait for Struct {
    fn no_impl(&self) -> &Self { self }

    fn WithDefault() -> i32 { 42 }
    fn NoDefault() -> Self { Struct { i: 42 } }
}
*/

<commit_msg>trait inheritance (only one parent)<commit_after>//! Macro for declaring/implementing traits with fake associated consts (in stable Rust)
//!
//! Currently very fragile in terms of syntax: does not support traits/impls with _any_ kind of
//! generic parameters (either lifetimes or types).
//!
//! The same macro is used for declaring a trait with associated consts, implementing such a trait,
//! and accessing the consts.
//!
//! The syntax is the same as that proposed for associated consts, _except_ that:
//!
//! - all consts must be at the beginning of the trait/impl, before any functions
//! - const declarations end with a comma, instead of a semicolon (this is due to a limitation of
//! the macro system -- a type followed by a semicolon is for some reason not parseable)
//!
//! See the tests for example usage.
//!
//! At the moment they are not consts at all -- they simply expand to static functions with the
//! same name as the declared const. You may therefore access the const by calling
//! `Trait::CONST()`, or (for future proofing, in case the macro implementation changes), call the
//! macro again to access the const, as `guilty!(Trait::CONST)`.

/// Macro for declaring/implementing traits with fake associated consts
///
/// See the [crate-level documentation](index.html) for more.
#[macro_export]
macro_rules! guilty {
    // These are the user facing invocations:

    // FIXME what if the traits have docs/attributes?
    // 1. define a private trait
    ($(#[$attr:meta])* trait $traitname:ident $body:tt) => {
        guilty!(INTERNAL: DEFINE TRAIT, [$(#[$attr])*] [trait] [$traitname], $body);
    };
    // 2. define a private trait with inheritance
    ($(#[$attr:meta])* trait $traitname:ident : $parent:ident $body:tt) => {
        guilty!(INTERNAL: DEFINE TRAIT, [$(#[$attr])*] [pub trait] [$traitname : $parent], $body);
    };
    // 3. define a public trait
    ($(#[$attr:meta])* pub trait $traitname:ident $body:tt) => {
        guilty!(INTERNAL: DEFINE TRAIT, [$(#[$attr])*] [pub trait] [$traitname], $body);
    };
    // 4. define a public trait with inheritance
    ($(#[$attr:meta])* pub trait $traitname:ident : $parent:ident $body:tt) => {
        guilty!(INTERNAL: DEFINE TRAIT, [$(#[$attr])*] [pub trait] [$traitname : $parent], $body);
    };
    // 5. implement a trait (public or private)
    (impl $traitname:ident for $structname:ident $body:tt) => {
        guilty!(INTERNAL: DEFINE IMPL, $traitname, $structname, $body);
    };
    // 6. access a const declared with this macro
    ($structname:ident :: $constname:ident) => {
        guilty!(INTERNAL: ACCESS CONST, $structname, $constname);
    };

    // Following are the internal macro calls
    // Since you can't export a macro which calls other unexported macros, guilty! calls itself
    // recursively in order to continue parsing. The invocation syntax for all these recursive
    // calls starts with the tokens `INTERNAL:`.
    //
    // The general strategy for parsing these declarations is we parse one const declaration from
    // the beginning of the trait/impl at a time, turning it into a static function which is
    // appended to the end of the trait/impl. When there are no more consts, the recursion stops
    // and the trait/impl is outputted (with an indirection through AS ITEM to appease the parser).

    // parse-trait-defconst: parse a trait with a const (that has a default value) as the first declaration
    // the square brackets contain [trait Trait] or [pub trait Trait]
    // this calls on to:
    //  - itself if there is another default-valued const
    //  - parse-trait-nodefconst if there is another const with no default value
    //  - def-trait-fn/def-trait-attr/def-trait-ty if there are no more consts
    // FIXME what if the const has docs/attributes?
    (INTERNAL: DEFINE TRAIT, [$(#[$attr:meta])*] [$($before:ident)+] [$($traitname:tt)*],
     {
         const $constname:ident : $consttype:ty = $constdefault:expr,
         $($body:tt)*
     }) => {
        guilty!(INTERNAL: DEFINE TRAIT, [$(#[$attr])*] [$($before)+] [$($traitname)*],
                {
                    $($body)*
                    #[allow(non_snake_case)] fn $constname() -> $consttype { $constdefault }
                });
    };
    // parse-trait-nodefconst: parse a trait with a const (that has no default value) as the first declaration
    // this calls on to:
    //  - itself is there is another non-default-valued const
    //  - parse-trait-defconst if there is another default-valued const
    //  - def-trait-fn/def-trait-attr/def-trait-ty if there are no more consts
    (INTERNAL: DEFINE TRAIT, [$(#[$attr:meta])*] [$($before:ident)+] [$($traitname:tt)*],
     {
         const $constname:ident : $consttype:ty,
         $($body:tt)*
     }) => {
        guilty!(INTERNAL: DEFINE TRAIT, [$(#[$attr])*] [$($before)+] [$($traitname)*],
                {
                    $($body)*
                    #[allow(non_snake_case)] fn $constname() -> $consttype;
                });
    };
    // def-trait-fn: output a trait that has no consts at the beginning (starts with an unadorned fn)
    // indirection through item-redir
    (INTERNAL: DEFINE TRAIT, [$(#[$attr:meta])*] [$($before:ident)+] [$($traitname:tt)*],
     {
         fn $($body:tt)*
     }) => {
        guilty!(INTERNAL: AS ITEM, $(#[$attr])* $($before)+ $($traitname)* { fn $($body)* });
    };
    // def-trait-attr: output a trait that has no consts at the beginning (starts with fn that has
    //    docs/attributes)
    // indirection through item-redir
    (INTERNAL: DEFINE TRAIT, [$(#[$attr:meta])*] [$($before:ident)+] [$($traitname:tt)*],
     {
         # $($body:tt)*
     }) => {
        guilty!(INTERNAL: AS ITEM, $(#[$attr])* $($before)+ $($traitname)* { # $($body)* });
    };
    // def-trait-ty: output a trait that has no consts at the beginning (starts with an associated type)
    // indirection through item-redir
    (INTERNAL: DEFINE TRAIT, [$(#[$attr:meta])*] [$($before:ident)+] [$($traitname:tt)*],
     {
         type $($body:tt)*
     }) => {
        guilty!(INTERNAL: AS ITEM, $(#[$attr])* $($before)+ $($traitname)* { type $($body)* });
    };

    // parse-impl-const: parse an impl with a const as the first declaration
    // calls on to:
    //  - itself if there is another const
    //  - def-impl-fn/def-impl-ty if there are no more consts
    (INTERNAL: DEFINE IMPL, $traitname:ty, $structname:ident,
     {
         const $constname:ident : $consttype:ty = $constvalue:expr,
         $($body:tt)*
     }) => {
        guilty!(INTERNAL: DEFINE IMPL, $traitname, $structname,
                {
                    $($body)*
                    fn $constname() -> $consttype { $constvalue }
                });
    };
    // def-impl-fn: output an impl that has no consts at the beginning (starts with fn)
    // indirection through item-redir
    (INTERNAL: DEFINE IMPL, $traitname:ty, $structname:ident,
     {
         fn $($body:tt)*
     }) => {
        guilty!(INTERNAL: AS ITEM, impl $traitname for $structname { fn $($body)* });
    };
    // def-impl-ty: output an impl that has no consts at the beginning (starts with type)
    // indirection through item-redir
    (INTERNAL: DEFINE IMPL, $traitname:ty, $structname:ident,
     {
         type $($body:tt)*
     }) => {
        guilty!(INTERNAL: AS ITEM, impl $traitname for $structname { type $($body)* });
    };
    // FIXME: need another DEFINE IMPL that's like def-trait-attr?

    // access: access a const defined with this macro
    // For now, it just calls the function, since we turn consts into functions. In the future, it
    // might do something more clever if the implementation changes.
    (INTERNAL: ACCESS CONST, $structname:ident, $constname:ident) => {{
        $structname :: $constname ()
    }};

    // item-redir: Item redirection.
    // For some reason the parser sometimes complains "expected item" when you are trying to output
    // a perfectly good item. The solution (sometimes) is to redirect through a macro like this.
    (INTERNAL: AS ITEM, $i:item) => ($i)
}

/*
 * BEFORE
 *
trait Trait {
    const WithDefault: i32 = 0,
    const NoDefault: Self,

    fn with_impl(&self) -> &Self { self }
    fn no_impl(&self) -> &Self;
}

struct Struct { i: i32 }

impl Trait for Struct {
    const WithDefault: i32 = 42,
    const NoDefault: Self = Self { i: 42 },

    fn no_impl(&self) -> &Self { self }
}
*/

/*
 * AFTER
 *
trait Trait {
    fn with_impl(&self) -> &Self { self }
    fn no_impl(&self) -> &Self;

    #[allow(non_snake_case)] fn WithDefault() -> i32 { 0 }
    #[allow(non_snake_case)] fn NoDefault() -> Self;
}

struct Struct { i: i32 }

impl Trait for Struct {
    fn no_impl(&self) -> &Self { self }

    fn WithDefault() -> i32 { 42 }
    fn NoDefault() -> Self { Struct { i: 42 } }
}
*/

<|endoftext|>


<commit_before>//! Crate `retry` provides utilities for retrying operations that can fail.
//!
//! # Usage
//!
//! Retry an operation using the `retry` function. `retry` accepts an iterator over `Duration`s and
//! a closure that returns a `Result`. The iterator is used to determine how long to wait after
//! each unsuccessful try and how many times to try before giving up and returning `Result::Err`.
//!
//! Any type that implements `Iterator<Duration>` can be used to determine retry behavior, though a
//! few useful implementations are provided in the `delay` module, including a fixed delay and
//! exponential back-off.
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! let mut collection = vec![1, 2, 3].into_iter();
//!
//! let result = retry(Fixed::from_millis(100), || {
//!     match collection.next() {
//!         Some(n) if n == 3 => Ok("n is 3!"),
//!         Some(_) => Err("n must be 3!"),
//!         None => Err("n was never 3!"),
//!     }
//! });
//!
//! assert!(result.is_ok());
//! ```
//!
//! The `Iterator` API can be used to limit or modify the delay strategy. For example, to limit the
//! number of retries to 1:
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! let mut collection = vec![1, 2, 3].into_iter();
//!
//! let result = retry(Fixed::from_millis(100).take(1), || {
//!     match collection.next() {
//!         Some(n) if n == 3 => Ok("n is 3!"),
//!         Some(_) => Err("n must be 3!"),
//!         None => Err("n was never 3!"),
//!     }
//! });
//!
//! assert!(result.is_err());
//! ```

#![deny(missing_debug_implementations)]
#![deny(missing_docs)]

extern crate rand;

use std::error::Error as StdError;
use std::fmt::Error as FmtError;
use std::fmt::{Display,Formatter};
use std::thread::sleep;
use std::time::Duration;

pub mod delay;

/// Retry the given operation synchronously until it succeeds, or until the given `Duration`
/// iterator ends.
pub fn retry<I, O, R, E>(mut iterator: I, mut operation: O) -> Result<R, Error<E>>
where I: Iterator<Item=Duration>, O: FnMut() -> Result<R, E> {
    let mut try = 1;
    let mut total_delay = Duration::default();

    loop {
        match operation() {
            Ok(value) => return Ok(value),
            Err(error) => {
                if let Some(delay) = iterator.next() {
                    sleep(delay);
                    try += 1;
                    total_delay = delay;
                } else {
                    return Err(Error::Operation {
                        error: error,
                        total_delay: total_delay,
                        tries: try,
                    });
                }
            }
        }
    }
}

/// An error with a retryable operation.
#[derive(Debug)]
pub enum Error<E> {
    /// The operation's last error, plus the number of times the operation was tried and the
    /// duration spent waiting between tries.
    Operation {
        /// The error returned by the operation on the last try.
        error: E,
        /// The duration spent waiting between retries of the operation.
        ///
        /// Note that this does not include the time spent running the operation itself.
        total_delay: Duration,
        /// The total number of times the operation was tried.
        tries: u64,
    }
}

impl<E> Display for Error<E> where E: StdError {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
        write!(formatter, "{}", self.description())
    }
}

impl<E> StdError for Error<E> where E: StdError {
    fn description(&self) -> &str {
        match *self {
            Error::Operation { ref error, .. } => error.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Error::Operation { ref error, .. } => Some(error),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::time::Duration;

    use super::{Error, retry};
    use super::delay::{Exponential, Fixed, NoDelay, Range};

    #[test]
    fn succeeds_with_infinite_retries() {
        let mut collection = vec![1, 2, 3, 4, 5].into_iter();

        let value = retry(NoDelay, || {
            match collection.next() {
                Some(n) if n == 5 => Ok(n),
                Some(_) => Err("not 5"),
                None => Err("not 5"),
            }
        }).unwrap();

        assert_eq!(value, 5);
    }

    #[test]
    fn succeeds_with_maximum_retries() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(NoDelay.take(1), || {
            match collection.next() {
                Some(n) if n == 2 => Ok(n),
                Some(_) => Err("not 2"),
                None => Err("not 2"),
            }
        }).unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fails_after_last_try() {
        let mut collection = vec![1].into_iter();

        let Error::Operation { error, total_delay, tries } =
            retry(NoDelay.take(1), || {
                match collection.next() {
                    Some(n) if n == 2 => Ok(n),
                    Some(_) => Err("not 2"),
                    None => Err("not 2"),
                }
        }).err().unwrap();

        assert_eq!(error, "not 2");
        assert_eq!(total_delay, Duration::default());
        assert_eq!(tries, 2);
    }

    #[test]
    fn succeeds_with_fixed_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Fixed::from_millis(1), || {
            match collection.next() {
                Some(n) if n == 2 => Ok(n),
                Some(_) => Err("not 2"),
                None => Err("not 2"),
            }
        }).unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn succeeds_with_exponential_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Exponential::from_millis(1), || {
            match collection.next() {
                Some(n) if n == 2 => Ok(n),
                Some(_) => Err("not 2"),
                None => Err("not 2"),
            }
        }).unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn succeeds_with_ranged_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Range::from_millis(1, 10), || {
            match collection.next() {
                Some(n) if n == 2 => Ok(n),
                Some(_) => Err("not 2"),
                None => Err("not 2"),
            }
        }).unwrap();

        assert_eq!(value, 2);
    }
}
<commit_msg>Take an IntoIterator for retry.<commit_after>//! Crate `retry` provides utilities for retrying operations that can fail.
//!
//! # Usage
//!
//! Retry an operation using the `retry` function. `retry` accepts an iterator over `Duration`s and
//! a closure that returns a `Result`. The iterator is used to determine how long to wait after
//! each unsuccessful try and how many times to try before giving up and returning `Result::Err`.
//!
//! Any type that implements `Iterator<Duration>` can be used to determine retry behavior, though a
//! few useful implementations are provided in the `delay` module, including a fixed delay and
//! exponential back-off.
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! let mut collection = vec![1, 2, 3].into_iter();
//!
//! let result = retry(Fixed::from_millis(100), || {
//!     match collection.next() {
//!         Some(n) if n == 3 => Ok("n is 3!"),
//!         Some(_) => Err("n must be 3!"),
//!         None => Err("n was never 3!"),
//!     }
//! });
//!
//! assert!(result.is_ok());
//! ```
//!
//! The `Iterator` API can be used to limit or modify the delay strategy. For example, to limit the
//! number of retries to 1:
//!
//! ```
//! # use retry::retry;
//! # use retry::delay::Fixed;
//! let mut collection = vec![1, 2, 3].into_iter();
//!
//! let result = retry(Fixed::from_millis(100).take(1), || {
//!     match collection.next() {
//!         Some(n) if n == 3 => Ok("n is 3!"),
//!         Some(_) => Err("n must be 3!"),
//!         None => Err("n was never 3!"),
//!     }
//! });
//!
//! assert!(result.is_err());
//! ```

#![deny(missing_debug_implementations)]
#![deny(missing_docs)]

extern crate rand;

use std::error::Error as StdError;
use std::fmt::Error as FmtError;
use std::fmt::{Display,Formatter};
use std::thread::sleep;
use std::time::Duration;

pub mod delay;

/// Retry the given operation synchronously until it succeeds, or until the given `Duration`
/// iterator ends.
pub fn retry<I, O, R, E>(iterable: I, mut operation: O) -> Result<R, Error<E>>
where I: IntoIterator<Item=Duration>, O: FnMut() -> Result<R, E> {
    let mut iterator = iterable.into_iter();
    let mut try = 1;
    let mut total_delay = Duration::default();

    loop {
        match operation() {
            Ok(value) => return Ok(value),
            Err(error) => {
                if let Some(delay) = iterator.next() {
                    sleep(delay);
                    try += 1;
                    total_delay = delay;
                } else {
                    return Err(Error::Operation {
                        error: error,
                        total_delay: total_delay,
                        tries: try,
                    });
                }
            }
        }
    }
}

/// An error with a retryable operation.
#[derive(Debug)]
pub enum Error<E> {
    /// The operation's last error, plus the number of times the operation was tried and the
    /// duration spent waiting between tries.
    Operation {
        /// The error returned by the operation on the last try.
        error: E,
        /// The duration spent waiting between retries of the operation.
        ///
        /// Note that this does not include the time spent running the operation itself.
        total_delay: Duration,
        /// The total number of times the operation was tried.
        tries: u64,
    }
}

impl<E> Display for Error<E> where E: StdError {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
        write!(formatter, "{}", self.description())
    }
}

impl<E> StdError for Error<E> where E: StdError {
    fn description(&self) -> &str {
        match *self {
            Error::Operation { ref error, .. } => error.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match *self {
            Error::Operation { ref error, .. } => Some(error),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::time::Duration;

    use super::{Error, retry};
    use super::delay::{Exponential, Fixed, NoDelay, Range};

    #[test]
    fn succeeds_with_infinite_retries() {
        let mut collection = vec![1, 2, 3, 4, 5].into_iter();

        let value = retry(NoDelay, || {
            match collection.next() {
                Some(n) if n == 5 => Ok(n),
                Some(_) => Err("not 5"),
                None => Err("not 5"),
            }
        }).unwrap();

        assert_eq!(value, 5);
    }

    #[test]
    fn succeeds_with_maximum_retries() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(NoDelay.take(1), || {
            match collection.next() {
                Some(n) if n == 2 => Ok(n),
                Some(_) => Err("not 2"),
                None => Err("not 2"),
            }
        }).unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fails_after_last_try() {
        let mut collection = vec![1].into_iter();

        let Error::Operation { error, total_delay, tries } =
            retry(NoDelay.take(1), || {
                match collection.next() {
                    Some(n) if n == 2 => Ok(n),
                    Some(_) => Err("not 2"),
                    None => Err("not 2"),
                }
        }).err().unwrap();

        assert_eq!(error, "not 2");
        assert_eq!(total_delay, Duration::default());
        assert_eq!(tries, 2);
    }

    #[test]
    fn succeeds_with_fixed_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Fixed::from_millis(1), || {
            match collection.next() {
                Some(n) if n == 2 => Ok(n),
                Some(_) => Err("not 2"),
                None => Err("not 2"),
            }
        }).unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn succeeds_with_exponential_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Exponential::from_millis(1), || {
            match collection.next() {
                Some(n) if n == 2 => Ok(n),
                Some(_) => Err("not 2"),
                None => Err("not 2"),
            }
        }).unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn succeeds_with_ranged_delay() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(Range::from_millis(1, 10), || {
            match collection.next() {
                Some(n) if n == 2 => Ok(n),
                Some(_) => Err("not 2"),
                None => Err("not 2"),
            }
        }).unwrap();

        assert_eq!(value, 2);
    }
}
<|endoftext|>


<commit_before>//! A generic event loop for games and interactive applications

#![deny(missing_docs)]
#![deny(missing_copy_implementations)]

extern crate time;
extern crate current;

use std::io::timer::sleep;
use std::time::duration::Duration;
use current::{ ActOn, Action, GetFrom, Get, SetAt };
use std::cmp;

/// Whether window should close or not.
#[deriving(Copy)]
pub struct ShouldClose(pub bool);

impl Sized for ShouldClose {}

/// The size of the window.
#[deriving(Copy)]
pub struct Size(pub [u32, ..2]);

impl Sized for Size {}

/// Tells window to swap buffers.
///
/// ~~~ignore
/// use current::Action;
///
/// ...
/// window.action(SwapBuffers);
/// ~~~
#[deriving(Copy)]
pub struct SwapBuffers;

impl Sized for SwapBuffers {}

/// Polls event from window.
///
/// ~~~ignore
/// use current::Action;
///
/// ...
/// let e = window.action(PollEvent);
/// ~~~
#[deriving(Copy)]
pub struct PollEvent;

impl Sized for PollEvent {}

/// Render arguments
#[deriving(Copy, Clone, PartialEq, Show)]
pub struct RenderArgs {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// The width of rendered area.
    pub width: u32,
    /// The height of rendered area.
    pub height: u32,
}

/// Update arguments, such as delta time in seconds
#[deriving(Copy, Clone, PartialEq, Show)]
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Methods required to map from consumed event to emitted event.
pub trait EventMap<I> {
    /// Creates a render event.
    fn render(args: RenderArgs) -> Self;
    /// Creates an update event.
    fn update(args: UpdateArgs) -> Self;
    /// Creates an input event.
    fn input(args: I) -> Self;
}

#[deriving(Copy, Show)]
enum State {
    Render,
    SwapBuffers,
    UpdateLoop,
    HandleEvents,
    Update,
}

/// The number of updates per second
///
/// This is the fixed update rate on average over time.
/// If the event loop lags, it will try to catch up.
#[deriving(Copy)]
pub struct Ups(pub u64);

impl<W> SetAt<Events<W>> for Ups {
    fn set_at(self, events: &mut Events<W>) {
        let Ups(frames) = self;
        events.dt_update_in_ns = BILLION / frames;
        events.dt = 1.0 / frames as f64;
    }
}

/// The maximum number of frames per second
///
/// The frame rate can be lower because the
/// next frame is always scheduled from the previous frame.
/// This causes the frames to "slip" over time.
#[deriving(Copy)]
pub struct MaxFps(pub u64);

impl<W> SetAt<Events<W>> for MaxFps {
    fn set_at(self, events: &mut Events<W>) {
        let MaxFps(frames) = self;
        events.dt_frame_in_ns = BILLION / frames;
    }
}

/// An event loop iterator
///
/// *Warning: Because the iterator polls events from the window back-end,
/// it must be used on the same thread as the window back-end (usually main thread),
/// unless the window back-end supports multi-thread event polling.*
///
/// Example:
///
/// ~~~ignore
/// fn main() {
///     let opengl = shader_version::opengl::OpenGL_3_2;
///     let window = Sdl2Window::new(
///         opengl,
///         WindowSettings {
///             title: "Example".to_string(),
///             size: [500, 500],
///             fullscreen: false,
///             exit_on_esc: true,
///             samples: 0,
///         }
///     )
///     let ref mut gl = Gl::new();
///     let window = RefCell::new(window);
///     for e in Events::new(&window)
///         .set(Ups(120))
///         .set(MaxFps(60)) {
///         use event::RenderEvent;
///         e.render(|args| {
///             // Set the viewport in window to render graphics.
///             gl.viewport(0, 0, args.width as i32, args.height as i32);
///             // Create graphics context with absolute coordinates.
///             let c = Context::abs(args.width as f64, args.height as f64);
///             // Do rendering here.
///         });
///     }
/// }
/// ~~~
pub struct Events<W> {
    /// The game window used by iterator.
    pub window: W,
    state: State,
    last_update: u64,
    last_frame: u64,
    dt_update_in_ns: u64,
    dt_frame_in_ns: u64,
    dt: f64,
}

static BILLION: u64 = 1_000_000_000;

/// The default updates per second.
pub const DEFAULT_UPS: Ups = Ups(120);
/// The default maximum frames per second.
pub const DEFAULT_MAX_FPS: MaxFps = MaxFps(60);

impl<W> Events<W> {
    /// Creates a new event iterator with default UPS and FPS settings.
    pub fn new(window: W) -> Events<W> {
        let start = time::precise_time_ns();
        let Ups(updates_per_second) = DEFAULT_UPS;
        let MaxFps(max_frames_per_second) = DEFAULT_MAX_FPS;
        Events {
            window: window,
            state: State::Render,
            last_update: start,
            last_frame: start,
            dt_update_in_ns: BILLION / updates_per_second,
            dt_frame_in_ns: BILLION / max_frames_per_second,
            dt: 1.0 / updates_per_second as f64,
        }
    }
}

impl<W, I, E: EventMap<I>>
Iterator<E>
for Events<W>
    where
        ShouldClose: GetFrom<W>,
        Size: GetFrom<W>,
        SwapBuffers: ActOn<W, ()>,
        PollEvent: ActOn<W, Option<I>>
{
    /// Returns the next game event.
    fn next(&mut self) -> Option<E> {
        loop {
            self.state = match self.state {
                State::Render => {
                    let ShouldClose(should_close) = self.window.get();
                    if should_close { return None; }

                    let start_render = time::precise_time_ns();
                    self.last_frame = start_render;

                    let Size([w, h]) = self.window.get();
                    if w != 0 && h != 0 {
                        // Swap buffers next time.
                        self.state = State::SwapBuffers;
                        return Some(EventMap::render(RenderArgs {
                            // Extrapolate time forward to allow smooth motion.
                            ext_dt: (start_render - self.last_update) as f64
                                    / BILLION as f64,
                            width: w,
                            height: h,
                        }));
                    }

                    State::UpdateLoop
                }
                State::SwapBuffers => {
                    self.window.action(SwapBuffers);
                    State::UpdateLoop
                }
                State::UpdateLoop => {
                    let current_time = time::precise_time_ns();
                    let next_frame = self.last_frame + self.dt_frame_in_ns;
                    let next_update = self.last_update + self.dt_update_in_ns;
                    let next_event = cmp::min(next_frame, next_update);
                    if next_event > current_time {
                        sleep( Duration::nanoseconds((next_event - current_time) as i64) );
                        State::UpdateLoop
                    } else if next_event == next_frame {
                        State::Render
                    } else {
                        State::HandleEvents
                    }
                }
                State::HandleEvents => {
                    // Handle all events before updating.
                    match self.window.action(PollEvent) {
                        None => State::Update,
                        Some(x) => { return Some(EventMap::input(x)); },
                    }
                }
                State::Update => {
                    self.state = State::UpdateLoop;
                    self.last_update += self.dt_update_in_ns;
                    return Some(EventMap::update(UpdateArgs{ dt: self.dt }));
                }
            };
        }
    }
}
<commit_msg>Made `Events::window` private<commit_after>//! A generic event loop for games and interactive applications

#![deny(missing_docs)]
#![deny(missing_copy_implementations)]

extern crate time;
extern crate current;

use std::io::timer::sleep;
use std::time::duration::Duration;
use current::{ ActOn, Action, GetFrom, Get, SetAt };
use std::cmp;

/// Whether window should close or not.
#[deriving(Copy)]
pub struct ShouldClose(pub bool);

impl Sized for ShouldClose {}

/// The size of the window.
#[deriving(Copy)]
pub struct Size(pub [u32, ..2]);

impl Sized for Size {}

/// Tells window to swap buffers.
///
/// ~~~ignore
/// use current::Action;
///
/// ...
/// window.action(SwapBuffers);
/// ~~~
#[deriving(Copy)]
pub struct SwapBuffers;

impl Sized for SwapBuffers {}

/// Polls event from window.
///
/// ~~~ignore
/// use current::Action;
///
/// ...
/// let e = window.action(PollEvent);
/// ~~~
#[deriving(Copy)]
pub struct PollEvent;

impl Sized for PollEvent {}

/// Render arguments
#[deriving(Copy, Clone, PartialEq, Show)]
pub struct RenderArgs {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// The width of rendered area.
    pub width: u32,
    /// The height of rendered area.
    pub height: u32,
}

/// Update arguments, such as delta time in seconds
#[deriving(Copy, Clone, PartialEq, Show)]
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Methods required to map from consumed event to emitted event.
pub trait EventMap<I> {
    /// Creates a render event.
    fn render(args: RenderArgs) -> Self;
    /// Creates an update event.
    fn update(args: UpdateArgs) -> Self;
    /// Creates an input event.
    fn input(args: I) -> Self;
}

#[deriving(Copy, Show)]
enum State {
    Render,
    SwapBuffers,
    UpdateLoop,
    HandleEvents,
    Update,
}

/// The number of updates per second
///
/// This is the fixed update rate on average over time.
/// If the event loop lags, it will try to catch up.
#[deriving(Copy)]
pub struct Ups(pub u64);

impl<W> SetAt<Events<W>> for Ups {
    fn set_at(self, events: &mut Events<W>) {
        let Ups(frames) = self;
        events.dt_update_in_ns = BILLION / frames;
        events.dt = 1.0 / frames as f64;
    }
}

/// The maximum number of frames per second
///
/// The frame rate can be lower because the
/// next frame is always scheduled from the previous frame.
/// This causes the frames to "slip" over time.
#[deriving(Copy)]
pub struct MaxFps(pub u64);

impl<W> SetAt<Events<W>> for MaxFps {
    fn set_at(self, events: &mut Events<W>) {
        let MaxFps(frames) = self;
        events.dt_frame_in_ns = BILLION / frames;
    }
}

/// An event loop iterator
///
/// *Warning: Because the iterator polls events from the window back-end,
/// it must be used on the same thread as the window back-end (usually main thread),
/// unless the window back-end supports multi-thread event polling.*
///
/// Example:
///
/// ~~~ignore
/// fn main() {
///     let opengl = shader_version::opengl::OpenGL_3_2;
///     let window = Sdl2Window::new(
///         opengl,
///         WindowSettings {
///             title: "Example".to_string(),
///             size: [500, 500],
///             fullscreen: false,
///             exit_on_esc: true,
///             samples: 0,
///         }
///     )
///     let ref mut gl = Gl::new();
///     let window = RefCell::new(window);
///     for e in Events::new(&window)
///         .set(Ups(120))
///         .set(MaxFps(60)) {
///         use event::RenderEvent;
///         e.render(|args| {
///             // Set the viewport in window to render graphics.
///             gl.viewport(0, 0, args.width as i32, args.height as i32);
///             // Create graphics context with absolute coordinates.
///             let c = Context::abs(args.width as f64, args.height as f64);
///             // Do rendering here.
///         });
///     }
/// }
/// ~~~
pub struct Events<W> {
    window: W,
    state: State,
    last_update: u64,
    last_frame: u64,
    dt_update_in_ns: u64,
    dt_frame_in_ns: u64,
    dt: f64,
}

static BILLION: u64 = 1_000_000_000;

/// The default updates per second.
pub const DEFAULT_UPS: Ups = Ups(120);
/// The default maximum frames per second.
pub const DEFAULT_MAX_FPS: MaxFps = MaxFps(60);

impl<W> Events<W> {
    /// Creates a new event iterator with default UPS and FPS settings.
    pub fn new(window: W) -> Events<W> {
        let start = time::precise_time_ns();
        let Ups(updates_per_second) = DEFAULT_UPS;
        let MaxFps(max_frames_per_second) = DEFAULT_MAX_FPS;
        Events {
            window: window,
            state: State::Render,
            last_update: start,
            last_frame: start,
            dt_update_in_ns: BILLION / updates_per_second,
            dt_frame_in_ns: BILLION / max_frames_per_second,
            dt: 1.0 / updates_per_second as f64,
        }
    }
}

impl<W, I, E: EventMap<I>>
Iterator<E>
for Events<W>
    where
        ShouldClose: GetFrom<W>,
        Size: GetFrom<W>,
        SwapBuffers: ActOn<W, ()>,
        PollEvent: ActOn<W, Option<I>>
{
    /// Returns the next game event.
    fn next(&mut self) -> Option<E> {
        loop {
            self.state = match self.state {
                State::Render => {
                    let ShouldClose(should_close) = self.window.get();
                    if should_close { return None; }

                    let start_render = time::precise_time_ns();
                    self.last_frame = start_render;

                    let Size([w, h]) = self.window.get();
                    if w != 0 && h != 0 {
                        // Swap buffers next time.
                        self.state = State::SwapBuffers;
                        return Some(EventMap::render(RenderArgs {
                            // Extrapolate time forward to allow smooth motion.
                            ext_dt: (start_render - self.last_update) as f64
                                    / BILLION as f64,
                            width: w,
                            height: h,
                        }));
                    }

                    State::UpdateLoop
                }
                State::SwapBuffers => {
                    self.window.action(SwapBuffers);
                    State::UpdateLoop
                }
                State::UpdateLoop => {
                    let current_time = time::precise_time_ns();
                    let next_frame = self.last_frame + self.dt_frame_in_ns;
                    let next_update = self.last_update + self.dt_update_in_ns;
                    let next_event = cmp::min(next_frame, next_update);
                    if next_event > current_time {
                        sleep( Duration::nanoseconds((next_event - current_time) as i64) );
                        State::UpdateLoop
                    } else if next_event == next_frame {
                        State::Render
                    } else {
                        State::HandleEvents
                    }
                }
                State::HandleEvents => {
                    // Handle all events before updating.
                    match self.window.action(PollEvent) {
                        None => State::Update,
                        Some(x) => { return Some(EventMap::input(x)); },
                    }
                }
                State::Update => {
                    self.state = State::UpdateLoop;
                    self.last_update += self.dt_update_in_ns;
                    return Some(EventMap::update(UpdateArgs{ dt: self.dt }));
                }
            };
        }
    }
}
<|endoftext|>