<commit_before>//! `GraphMap<N, E>` is an undirected graph where node values are mapping keys.

use std::hash::{Hash};
use std::collections::HashMap;
use std::iter::Cloned;
use std::collections::hash_map::{
    Keys,
};
use std::collections::hash_map::Iter as HashmapIter;
use std::slice::{
    Iter,
};
use std::fmt;
use std::ops::{Index, IndexMut};

use IntoWeightedEdge;

/// `GraphMap<N, E>` is an undirected graph, with generic node values `N` and edge weights `E`.
///
/// It uses an combined adjacency list and sparse adjacency matrix representation, using **O(|V|
/// + |E|)** space, and allows testing for edge existance in constant time.
///
/// The node type `N` must implement `Copy` and will be used as node identifier, duplicated
/// into several places in the data structure.
/// It must be suitable as a hash table key (implementing `Eq + Hash`).
/// The node type must also implement `Ord` so that the implementation can
/// order the pair (`a`, `b`) for an edge connecting any two nodes `a` and `b`.
///
/// `GraphMap` does not allow parallel edges, but self loops are allowed.
#[derive(Clone)]
pub struct GraphMap<N, E> {
    nodes: HashMap<N, Vec<N>>,
    edges: HashMap<(N, N), E>,
}

impl<N: Eq + Hash + fmt::Debug, E: fmt::Debug> fmt::Debug for GraphMap<N, E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.nodes.fmt(f)
    }
}

#[inline]
fn edge_key<N: Copy + Ord>(a: N, b: N) -> (N, N) {
    if a <= b { (a, b) } else { (b, a) }
}

/// A trait group for `GraphMap`'s node identifier.
pub trait NodeTrait : Copy + Ord + Hash {}
impl<N> NodeTrait for N where N: Copy + Ord + Hash {}

impl<N, E> GraphMap<N, E>
    where N: NodeTrait
{
    /// Create a new `GraphMap`.
    pub fn new() -> Self {
        GraphMap {
            nodes: HashMap::new(),
            edges: HashMap::new(),
        }
    }

    /// Create a new `GraphMap` with estimated capacity.
    pub fn with_capacity(nodes: usize, edges: usize) -> Self {
        GraphMap {
            nodes: HashMap::with_capacity(nodes),
            edges: HashMap::with_capacity(edges),
        }
    }

    /// Create a new `GraphMap` from an iterable of edges.
    ///
    /// Node values are taken directly from the list.
    /// Edge weights `E` may either be specified in the list,
    /// or they are filled with default values.
    ///
    /// Nodes are inserted automatically to match the edges.
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let gr = GraphMap::<_, ()>::from_edges(&[
    ///     (0, 1), (0, 2), (0, 3),
    ///     (1, 2), (1, 3),
    ///     (2, 3),
    /// ]);
    /// ```
    pub fn from_edges<I>(iterable: I) -> Self
        where I: IntoIterator,
              I::Item: IntoWeightedEdge<N, E>
    {
        let iter = iterable.into_iter();
        let (low, _) = iter.size_hint();
        let mut g = Self::with_capacity(0, low);
        g.extend(iter);
        g
    }

    /// Return the number of nodes in the graph.
    pub fn node_count(&self) -> usize {
        self.nodes.len()
    }

    /// Return the number of edges in the graph.
    pub fn edge_count(&self) -> usize {
        self.edges.len()
    }

    /// Remove all nodes and edges
    pub fn clear(&mut self) {
        self.nodes.clear();
        self.edges.clear();
    }

    /// Add node `n` to the graph.
    pub fn add_node(&mut self, n: N) -> N {
        self.nodes.entry(n).or_insert_with(|| Vec::new());
        n
    }

    /// Return `true` if node `n` was removed.
    pub fn remove_node(&mut self, n: N) -> bool {
        let successors = match self.nodes.remove(&n) {
            None => return false,
            Some(sus) => sus,
        };
        for succ in successors.into_iter() {
            // remove all successor links
            self.remove_single_edge(&succ, &n);
            // Remove all edge values
            self.edges.remove(&edge_key(n, succ));
        }
        true
    }

    /// Return `true` if the node is contained in the graph.
    pub fn contains_node(&self, n: N) -> bool {
        self.nodes.contains_key(&n)
    }

    /// Add an edge connecting `a` and `b` to the graph.
    ///
    /// Inserts nodes `a` and/or `b` if they aren't already part of the graph.
    ///
    /// Return `true` if edge did not previously exist.
    ///
    /// ## Example
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_edge(1, 2, -1);
    /// assert_eq!(g.node_count(), 2);
    /// assert_eq!(g.edge_count(), 1);
    /// ```
    pub fn add_edge(&mut self, a: N, b: N, edge: E) -> bool {
        // Use Ord to order the edges
        self.nodes.entry(a)
                  .or_insert_with(|| Vec::with_capacity(1))
                  .push(b);
        self.nodes.entry(b)
                  .or_insert_with(|| Vec::with_capacity(1))
                  .push(a);
        self.edges.insert(edge_key(a, b), edge).is_none()
    }

    /// Remove successor relation from a to b
    ///
    /// Return `true` if it did exist.
    fn remove_single_edge(&mut self, a: &N, b: &N) -> bool {
        match self.nodes.get_mut(a) {
            None => false,
            Some(sus) => {
                match sus.iter().position(|elt| elt == b) {
                    Some(index) => { sus.swap_remove(index); true }
                    None => false,
                }
            }
        }
    }

    /// Remove edge from `a` to `b` from the graph and return the edge weight.
    ///
    /// Return `None` if the edge didn't exist.
    ///
    /// ## Example
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_node(1);
    /// g.add_node(2);
    /// g.add_edge(1, 2, -1);
    ///
    /// let edge = g.remove_edge(2, 1);
    /// assert_eq!(edge, Some(-1));
    /// assert_eq!(g.edge_count(), 0);
    /// ```
    pub fn remove_edge(&mut self, a: N, b: N) -> Option<E> {
        let exist1 = self.remove_single_edge(&a, &b);
        let exist2 = self.remove_single_edge(&b, &a);
        let weight = self.edges.remove(&edge_key(a, b));
        debug_assert!(exist1 == exist2 && exist1 == weight.is_some());
        weight
    }

    /// Return `true` if the edge connecting `a` with `b` is contained in the graph.
    pub fn contains_edge(&self, a: N, b: N) -> bool {
        self.edges.contains_key(&edge_key(a, b))
    }

    /// Return an iterator over the nodes of the graph.
    ///
    /// Iterator element type is `N`.
    pub fn nodes(&self) -> Nodes<N> {
        Nodes{iter: self.nodes.keys().cloned()}
    }

    /// Return an iterator over the nodes that are connected with `from` by edges.
    ///
    /// If the node `from` does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is `N`.
    pub fn neighbors(&self, from: N) -> Neighbors<N> {
        Neighbors{iter:
            match self.nodes.get(&from) {
                Some(neigh) => neigh.iter(),
                None => [].iter(),
            }.cloned()
        }
    }

    /// Return an iterator over the nodes that are connected with `from` by edges,
    /// paired with the edge weight.
    ///
    /// If the node `from` does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is `(N, &E)`.
    pub fn edges(&self, from: N) -> Edges<N, E> {
        Edges {
            from: from,
            iter: self.neighbors(from),
            edges: &self.edges,
        }
    }

    /// Return a reference to the edge weight connecting `a` with `b`, or
    /// `None` if the edge does not exist in the graph.
    pub fn edge_weight(&self, a: N, b: N) -> Option<&E> {
        self.edges.get(&edge_key(a, b))
    }

    /// Return a mutable reference to the edge weight connecting `a` with `b`, or
    /// `None` if the edge does not exist in the graph.
    pub fn edge_weight_mut(&mut self, a: N, b: N) -> Option<&mut E> {
        self.edges.get_mut(&edge_key(a, b))
    }

    /// Return an iterator over all edges of the graph with their weight in arbitrary order.
    ///
    /// Iterator element type is `((N, N), &E)`
    pub fn all_edges(&self) -> AllEdges<N, E> {
        AllEdges {
            inner: self.edges.iter()
        }
    }
}

/// Extend the graph from an iterable of edges.
///
/// Nodes are inserted automatically to match the edges.
impl<N, E, Item> Extend<Item> for GraphMap<N, E>
    where Item: IntoWeightedEdge<N, E>,
          N: NodeTrait,
{
    fn extend<I>(&mut self, iterable: I)
        where I: IntoIterator<Item=Item>,
    {
        let iter = iterable.into_iter();
        let (low, _) = iter.size_hint();
        self.edges.reserve(low);

        for elt in iter {
            let (source, target, weight) = elt.into_edge();
            self.add_edge(source, target, weight);
        }
    }
}

/// Utitily macro -- reinterpret passed in macro arguments as items
macro_rules! items {
    ($($item:item)*) => ($($item)*);
}

macro_rules! iterator_wrap {
    ($name: ident <$($typarm:tt),*> where { $($bounds: tt)* }
     item: $item: ty,
     iter: $iter: ty,
     ) => (
        items! {
            pub struct $name <$($typarm),*> where $($bounds)* {
                iter: $iter,
            }
            impl<$($typarm),*> Iterator for $name <$($typarm),*>
                where $($bounds)*
            {
                type Item = $item;
                #[inline]
                fn next(&mut self) -> Option<Self::Item> {
                    self.iter.next()
                }

                #[inline]
                fn size_hint(&self) -> (usize, Option<usize>) {
                    self.iter.size_hint()
                }
            }
            impl<$($typarm),*> DoubleEndedIterator for $name <$($typarm),*>
                where $($bounds)*, $iter: DoubleEndedIterator<Item=$item>,
            {
                #[inline]
                fn next_back(&mut self) -> Option<Self::Item> {
                    self.iter.next_back()
                }
            }

            impl<$($typarm),*> ExactSizeIterator for $name <$($typarm),*>
                where $($bounds)*, $iter: ExactSizeIterator<Item=$item>,
            {
            }
        }
    );
}

iterator_wrap! {
    Nodes <'a, N> where { N: 'a + Clone }
    item: N,
    iter: Cloned<Keys<'a, N, Vec<N>>>,
}

iterator_wrap! {
    Neighbors <'a, N> where { N: 'a + Clone }
    item: N,
    iter: Cloned<Iter<'a, N>>,
}

pub struct Edges<'a, N, E: 'a> where N: 'a + NodeTrait {
    /// **Deprecated: should be private**
    pub from: N,
    /// **Deprecated: should be private**
    pub edges: &'a HashMap<(N, N), E>,
    /// **Deprecated: should be private**
    pub iter: Neighbors<'a, N>,
}

impl<'a, N, E> Iterator for Edges<'a, N, E>
    where N: 'a + NodeTrait, E: 'a
{
    type Item = (N, &'a E);
    fn next(&mut self) -> Option<(N, &'a E)>
    {
        match self.iter.next() {
            None => None,
            Some(b) => {
                let a = self.from;
                match self.edges.get(&edge_key(a, b)) {
                    None => unreachable!(),
                    Some(edge) => {
                        Some((b, edge))
                    }
                }
            }
        }
    }
}

pub struct AllEdges<'a, N, E: 'a> where N: 'a + NodeTrait {
    inner: HashmapIter<'a, (N, N), E>
}

impl<'a, N, E> Iterator for AllEdges<'a, N, E>
    where N: 'a + NodeTrait, E: 'a
{
    type Item = ((N, N), &'a E);
    fn next(&mut self) -> Option<((N, N), &'a E)>
    {
        match self.inner.next() {
            None => None,
            Some((k, v)) => Some((*k, v))
        }
    }
}

/// Index `GraphMap` by node pairs to access edge weights.
impl<N, E> Index<(N, N)> for GraphMap<N, E>
    where N: NodeTrait
{
    type Output = E;
    fn index(&self, index: (N, N)) -> &E
    {
        self.edge_weight(index.0, index.1).expect("GraphMap::index: no such edge")
    }
}

/// Index `GraphMap` by node pairs to access edge weights.
impl<N, E> IndexMut<(N, N)> for GraphMap<N, E>
    where N: NodeTrait
{
    fn index_mut(&mut self, index: (N, N)) -> &mut E
    {
        self.edge_weight_mut(index.0, index.1).expect("GraphMap::index: no such edge")
    }
}
<commit_msg>impl FromIterator for GraphMap<commit_after>//! `GraphMap<N, E>` is an undirected graph where node values are mapping keys.

use std::hash::{Hash};
use std::collections::HashMap;
use std::iter::Cloned;
use std::collections::hash_map::{
    Keys,
};
use std::collections::hash_map::Iter as HashmapIter;
use std::slice::{
    Iter,
};
use std::fmt;
use std::iter::FromIterator;
use std::ops::{Index, IndexMut};

use IntoWeightedEdge;

/// `GraphMap<N, E>` is an undirected graph, with generic node values `N` and edge weights `E`.
///
/// It uses an combined adjacency list and sparse adjacency matrix representation, using **O(|V|
/// + |E|)** space, and allows testing for edge existance in constant time.
///
/// The node type `N` must implement `Copy` and will be used as node identifier, duplicated
/// into several places in the data structure.
/// It must be suitable as a hash table key (implementing `Eq + Hash`).
/// The node type must also implement `Ord` so that the implementation can
/// order the pair (`a`, `b`) for an edge connecting any two nodes `a` and `b`.
///
/// `GraphMap` does not allow parallel edges, but self loops are allowed.
#[derive(Clone)]
pub struct GraphMap<N, E> {
    nodes: HashMap<N, Vec<N>>,
    edges: HashMap<(N, N), E>,
}

impl<N: Eq + Hash + fmt::Debug, E: fmt::Debug> fmt::Debug for GraphMap<N, E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.nodes.fmt(f)
    }
}

#[inline]
fn edge_key<N: Copy + Ord>(a: N, b: N) -> (N, N) {
    if a <= b { (a, b) } else { (b, a) }
}

/// A trait group for `GraphMap`'s node identifier.
pub trait NodeTrait : Copy + Ord + Hash {}
impl<N> NodeTrait for N where N: Copy + Ord + Hash {}

impl<N, E> GraphMap<N, E>
    where N: NodeTrait
{
    /// Create a new `GraphMap`.
    pub fn new() -> Self {
        GraphMap {
            nodes: HashMap::new(),
            edges: HashMap::new(),
        }
    }

    /// Create a new `GraphMap` with estimated capacity.
    pub fn with_capacity(nodes: usize, edges: usize) -> Self {
        GraphMap {
            nodes: HashMap::with_capacity(nodes),
            edges: HashMap::with_capacity(edges),
        }
    }

    /// Create a new `GraphMap` from an iterable of edges.
    ///
    /// Node values are taken directly from the list.
    /// Edge weights `E` may either be specified in the list,
    /// or they are filled with default values.
    ///
    /// Nodes are inserted automatically to match the edges.
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let gr = GraphMap::<_, ()>::from_edges(&[
    ///     (0, 1), (0, 2), (0, 3),
    ///     (1, 2), (1, 3),
    ///     (2, 3),
    /// ]);
    /// ```
    pub fn from_edges<I>(iterable: I) -> Self
        where I: IntoIterator,
              I::Item: IntoWeightedEdge<N, E>
    {
        Self::from_iter(iterable)
    }

    /// Return the number of nodes in the graph.
    pub fn node_count(&self) -> usize {
        self.nodes.len()
    }

    /// Return the number of edges in the graph.
    pub fn edge_count(&self) -> usize {
        self.edges.len()
    }

    /// Remove all nodes and edges
    pub fn clear(&mut self) {
        self.nodes.clear();
        self.edges.clear();
    }

    /// Add node `n` to the graph.
    pub fn add_node(&mut self, n: N) -> N {
        self.nodes.entry(n).or_insert_with(|| Vec::new());
        n
    }

    /// Return `true` if node `n` was removed.
    pub fn remove_node(&mut self, n: N) -> bool {
        let successors = match self.nodes.remove(&n) {
            None => return false,
            Some(sus) => sus,
        };
        for succ in successors.into_iter() {
            // remove all successor links
            self.remove_single_edge(&succ, &n);
            // Remove all edge values
            self.edges.remove(&edge_key(n, succ));
        }
        true
    }

    /// Return `true` if the node is contained in the graph.
    pub fn contains_node(&self, n: N) -> bool {
        self.nodes.contains_key(&n)
    }

    /// Add an edge connecting `a` and `b` to the graph.
    ///
    /// Inserts nodes `a` and/or `b` if they aren't already part of the graph.
    ///
    /// Return `true` if edge did not previously exist.
    ///
    /// ## Example
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_edge(1, 2, -1);
    /// assert_eq!(g.node_count(), 2);
    /// assert_eq!(g.edge_count(), 1);
    /// ```
    pub fn add_edge(&mut self, a: N, b: N, edge: E) -> bool {
        // Use Ord to order the edges
        self.nodes.entry(a)
                  .or_insert_with(|| Vec::with_capacity(1))
                  .push(b);
        self.nodes.entry(b)
                  .or_insert_with(|| Vec::with_capacity(1))
                  .push(a);
        self.edges.insert(edge_key(a, b), edge).is_none()
    }

    /// Remove successor relation from a to b
    ///
    /// Return `true` if it did exist.
    fn remove_single_edge(&mut self, a: &N, b: &N) -> bool {
        match self.nodes.get_mut(a) {
            None => false,
            Some(sus) => {
                match sus.iter().position(|elt| elt == b) {
                    Some(index) => { sus.swap_remove(index); true }
                    None => false,
                }
            }
        }
    }

    /// Remove edge from `a` to `b` from the graph and return the edge weight.
    ///
    /// Return `None` if the edge didn't exist.
    ///
    /// ## Example
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_node(1);
    /// g.add_node(2);
    /// g.add_edge(1, 2, -1);
    ///
    /// let edge = g.remove_edge(2, 1);
    /// assert_eq!(edge, Some(-1));
    /// assert_eq!(g.edge_count(), 0);
    /// ```
    pub fn remove_edge(&mut self, a: N, b: N) -> Option<E> {
        let exist1 = self.remove_single_edge(&a, &b);
        let exist2 = self.remove_single_edge(&b, &a);
        let weight = self.edges.remove(&edge_key(a, b));
        debug_assert!(exist1 == exist2 && exist1 == weight.is_some());
        weight
    }

    /// Return `true` if the edge connecting `a` with `b` is contained in the graph.
    pub fn contains_edge(&self, a: N, b: N) -> bool {
        self.edges.contains_key(&edge_key(a, b))
    }

    /// Return an iterator over the nodes of the graph.
    ///
    /// Iterator element type is `N`.
    pub fn nodes(&self) -> Nodes<N> {
        Nodes{iter: self.nodes.keys().cloned()}
    }

    /// Return an iterator over the nodes that are connected with `from` by edges.
    ///
    /// If the node `from` does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is `N`.
    pub fn neighbors(&self, from: N) -> Neighbors<N> {
        Neighbors{iter:
            match self.nodes.get(&from) {
                Some(neigh) => neigh.iter(),
                None => [].iter(),
            }.cloned()
        }
    }

    /// Return an iterator over the nodes that are connected with `from` by edges,
    /// paired with the edge weight.
    ///
    /// If the node `from` does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is `(N, &E)`.
    pub fn edges(&self, from: N) -> Edges<N, E> {
        Edges {
            from: from,
            iter: self.neighbors(from),
            edges: &self.edges,
        }
    }

    /// Return a reference to the edge weight connecting `a` with `b`, or
    /// `None` if the edge does not exist in the graph.
    pub fn edge_weight(&self, a: N, b: N) -> Option<&E> {
        self.edges.get(&edge_key(a, b))
    }

    /// Return a mutable reference to the edge weight connecting `a` with `b`, or
    /// `None` if the edge does not exist in the graph.
    pub fn edge_weight_mut(&mut self, a: N, b: N) -> Option<&mut E> {
        self.edges.get_mut(&edge_key(a, b))
    }

    /// Return an iterator over all edges of the graph with their weight in arbitrary order.
    ///
    /// Iterator element type is `((N, N), &E)`
    pub fn all_edges(&self) -> AllEdges<N, E> {
        AllEdges {
            inner: self.edges.iter()
        }
    }
}

/// Create a new `GraphMap` from an iterable of edges.
impl<N, E, Item> FromIterator<Item> for GraphMap<N, E>
    where Item: IntoWeightedEdge<N, E>,
          N: NodeTrait,
{
    fn from_iter<I>(iterable: I) -> Self
        where I: IntoIterator<Item=Item>,
    {
        let iter = iterable.into_iter();
        let (low, _) = iter.size_hint();
        let mut g = Self::with_capacity(0, low);
        g.extend(iter);
        g
    }
}

/// Extend the graph from an iterable of edges.
///
/// Nodes are inserted automatically to match the edges.
impl<N, E, Item> Extend<Item> for GraphMap<N, E>
    where Item: IntoWeightedEdge<N, E>,
          N: NodeTrait,
{
    fn extend<I>(&mut self, iterable: I)
        where I: IntoIterator<Item=Item>,
    {
        let iter = iterable.into_iter();
        let (low, _) = iter.size_hint();
        self.edges.reserve(low);

        for elt in iter {
            let (source, target, weight) = elt.into_edge();
            self.add_edge(source, target, weight);
        }
    }
}

/// Utitily macro -- reinterpret passed in macro arguments as items
macro_rules! items {
    ($($item:item)*) => ($($item)*);
}

macro_rules! iterator_wrap {
    ($name: ident <$($typarm:tt),*> where { $($bounds: tt)* }
     item: $item: ty,
     iter: $iter: ty,
     ) => (
        items! {
            pub struct $name <$($typarm),*> where $($bounds)* {
                iter: $iter,
            }
            impl<$($typarm),*> Iterator for $name <$($typarm),*>
                where $($bounds)*
            {
                type Item = $item;
                #[inline]
                fn next(&mut self) -> Option<Self::Item> {
                    self.iter.next()
                }

                #[inline]
                fn size_hint(&self) -> (usize, Option<usize>) {
                    self.iter.size_hint()
                }
            }
            impl<$($typarm),*> DoubleEndedIterator for $name <$($typarm),*>
                where $($bounds)*, $iter: DoubleEndedIterator<Item=$item>,
            {
                #[inline]
                fn next_back(&mut self) -> Option<Self::Item> {
                    self.iter.next_back()
                }
            }

            impl<$($typarm),*> ExactSizeIterator for $name <$($typarm),*>
                where $($bounds)*, $iter: ExactSizeIterator<Item=$item>,
            {
            }
        }
    );
}

iterator_wrap! {
    Nodes <'a, N> where { N: 'a + Clone }
    item: N,
    iter: Cloned<Keys<'a, N, Vec<N>>>,
}

iterator_wrap! {
    Neighbors <'a, N> where { N: 'a + Clone }
    item: N,
    iter: Cloned<Iter<'a, N>>,
}

pub struct Edges<'a, N, E: 'a> where N: 'a + NodeTrait {
    /// **Deprecated: should be private**
    pub from: N,
    /// **Deprecated: should be private**
    pub edges: &'a HashMap<(N, N), E>,
    /// **Deprecated: should be private**
    pub iter: Neighbors<'a, N>,
}

impl<'a, N, E> Iterator for Edges<'a, N, E>
    where N: 'a + NodeTrait, E: 'a
{
    type Item = (N, &'a E);
    fn next(&mut self) -> Option<(N, &'a E)>
    {
        match self.iter.next() {
            None => None,
            Some(b) => {
                let a = self.from;
                match self.edges.get(&edge_key(a, b)) {
                    None => unreachable!(),
                    Some(edge) => {
                        Some((b, edge))
                    }
                }
            }
        }
    }
}

pub struct AllEdges<'a, N, E: 'a> where N: 'a + NodeTrait {
    inner: HashmapIter<'a, (N, N), E>
}

impl<'a, N, E> Iterator for AllEdges<'a, N, E>
    where N: 'a + NodeTrait, E: 'a
{
    type Item = ((N, N), &'a E);
    fn next(&mut self) -> Option<((N, N), &'a E)>
    {
        match self.inner.next() {
            None => None,
            Some((k, v)) => Some((*k, v))
        }
    }
}

/// Index `GraphMap` by node pairs to access edge weights.
impl<N, E> Index<(N, N)> for GraphMap<N, E>
    where N: NodeTrait
{
    type Output = E;
    fn index(&self, index: (N, N)) -> &E
    {
        self.edge_weight(index.0, index.1).expect("GraphMap::index: no such edge")
    }
}

/// Index `GraphMap` by node pairs to access edge weights.
impl<N, E> IndexMut<(N, N)> for GraphMap<N, E>
    where N: NodeTrait
{
    fn index_mut(&mut self, index: (N, N)) -> &mut E
    {
        self.edge_weight_mut(index.0, index.1).expect("GraphMap::index: no such edge")
    }
}
<|endoftext|>


<commit_before>use xcb;
use scancode;
use err::RuwmError;

use std::process::Command;
use xcb::ffi::base::xcb_generic_event_t as xcb_generic_event_t;

pub struct Handlers;

impl Handlers {
  pub fn handle_button_press(e: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    let button_press : &xcb::ButtonPressEvent = xcb::cast_event(&e);
    println!("Button '{:X}' pressed", button_press.detail());
    Ok(false)
  }

  pub fn handle_button_release(e: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    let button_release : &xcb::ButtonReleaseEvent = xcb::cast_event(&e);
    println!("Button {:X} release", button_release.detail());
    Ok(false)
  }

  // Create an enum from config file of Key Combinations and their default mappings
  // that way, can just import it and do scancode::Scancode::Q.run()
  pub fn handle_key_press(e: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    let key_press : &xcb::KeyPressEvent = xcb::cast_event(&e);
    let code = scancode::Scancode::new(key_press.detail()).unwrap();
    println!("Key '{}', Hex: '{:X}' pressed, scancode: {:?}",
      key_press.detail(), key_press.detail(), code);
    if code == scancode::Scancode::Q {
      return Ok(true);
    }
    return Ok(false);
  }

  pub fn handle_expose(e: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    let expose : &xcb::ExposeEvent = xcb::cast_event(&e);
    println!("Received Expose Event, {:X}", expose.window());
    Ok(false)
  }

  fn handle_enter_notify(event: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    unimplemented!();
  }

  fn event_is_ignored() -> Result<bool, RuwmError> {
    unimplemented!();
  }

  fn check_crossing_screen_boundary(x: u32, y: u32) {
    unimplemented!();
  }
}
<commit_msg>MOAR HANDLERS<commit_after>use xcb;
use scancode;
use err::RuwmError;

use std::process::Command;
use xcb::ffi::base::xcb_generic_event_t as xcb_generic_event_t;

pub struct Handlers;
/*
 * Handlers for different X events.
 * Comments/Structure Shamelessly copied from i3, and modified to fit ruwm
 */

impl Handlers {

  /*
  * When a mouse button is pressed, this callback is called
  */
  pub fn handle_button_press(event: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    let button_press : &xcb::ButtonPressEvent = xcb::cast_event(&event);
    println!("Button '{:X}' pressed", button_press.detail());
    Ok(false)
  }

  /*
   * When a mouse button is released, this callback is called
   */
  pub fn handle_button_release(event: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    let button_release : &xcb::ButtonReleaseEvent = xcb::cast_event(&event);
    println!("Button {:X} release", button_release.detail());
    Ok(false)
  }

  /*
  * Called when a key is pressed
  * Create an enum from config file of Key Combinations and their default mappings
  * that way, can just import it and do scancode::Scancode::Q.run()
  */
  pub fn handle_key_press(event: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    let key_press : &xcb::KeyPressEvent = xcb::cast_event(&event);
    let code = scancode::Scancode::new(key_press.detail()).unwrap();
    println!("Key '{}', Hex: '{:X}' pressed, scancode: {:?}",
      key_press.detail(), key_press.detail(), code);
    if code == scancode::Scancode::Q {
      return Ok(true);
    }
    return Ok(false);
  }

  /*
   * when a window changes sizes or is viewed on the screen
   * means we need to redraw our windows ( = title bar)
   * so let's handle it :->
   */
  pub fn handle_expose(event: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    let expose : &xcb::ExposeEvent = xcb::cast_event(&event);
    println!("Received Expose Event, {:X}", expose.window());
    Ok(false)
  }

  /*
   * When the user moves the mouse pointer onto a window, this event is triggered
   * and callback called
   */
  fn handle_enter_notify(event: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    unimplemented!();
  }

  /*
   * When the user moves the mouse but does not change the active window
   * (e.g. when having no windows opened but moving mouse on the root screen
   * and crossing virtual screen boundaries), this callback gets called
   */
  fn handle_motion_notify(event: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    unimplemented!();
  }

  /*
   * Called when keyboard mapping changes (for example, using Xmodmap),
   * we need to update our key bindings then (re-translate symbols)
   *
   */
  fn handle_mapping_notify(event: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    unimplemented!();
  }

  /*
   * A new window appeared on the screen (=was mapped), so let's manage it.
   *
   */
  fn handle_map_request(event: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    let map : &xcb::MapRequestEvent = xcb::cast_event(&event);
    println!("Map Request!: {:?} ", map.window());
    Ok(false)
  }

  /*
   * Configure requests are received when the application wants to resize
   * windows on their own
   *
   * We generate a synthetic configure notify event to signalize the client
   * its "new" position.
   */
  fn handle_configure_request(event: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    unimplemented!();
  }

  /*
   * Gets triggered upon a RandR screen change event, that is when the user
   * changes the screen configuraton in any way (mode, position, ... )
   *
   */
  fn handle_screen_change(event: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    unimplemented!();
  }

  /*
   * Our window decorations were unmapped. That means, the window will be killed
   * now, so we better clean up before (i3, not sure if this will be the case with ruwm)
   *
   */
  fn handle_unmap_notify_event(event: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    unimplemented!();
  }

  /*
   * A destroy notify event is sent when the window is not unmapped, but
   * immediately destroyed (for example when starting a window and immediately
   * killing the program which started it).
   *
   * We just pass on the event to the unmap notify handler ( by copying the important fields
   * in the event data structure)
   *
   */
  fn handle_destroy_notify_event(event: xcb::Event<xcb_generic_event_t>) -> Result<bool, RuwmError> {
    unimplemented!();
  }

  // TODO lots of parameters for this one, get to it later
  // i3 as ref
  // fn handle_window_name_change(....)

  fn event_is_ignored() -> Result<bool, RuwmError> {
    unimplemented!();
  }

  fn check_crossing_screen_boundary(x: u32, y: u32) {
    unimplemented!();
  }
}
<|endoftext|>


<commit_before>use std::f64;
use std::f64::consts::PI;

use radians::Radians;
use {Distance};

/// Represents the various supported speeds that the turtle can move at
///
/// See [`Turtle::set_speed` method](struct.Turtle.html#method.set_speed) for more information.
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub enum Speed {
    One,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    Instant,
}

impl Speed {
    /// Converts a speed to its value as pixels per second
    pub fn to_absolute(self) -> Distance {
        use self::Speed::*;
        // Arbitrary values that can be tweaked
        // Just make sure to keep invariants like Five > Three, etc.
        match self {
            One => 10.,
            Two => 50.,
            Three => 100.,
            Four => 150.,
            Five => 200.,
            Six => 250.,
            Seven => 300.,
            Eight => 350.,
            Nine => 400.,
            Ten => 500.,
            Instant => f64::INFINITY,
        }
    }

    /// Converts a speed to its value as radians per second
    pub fn to_rotation(self) -> Radians {
        use self::Speed::*;
        // Arbitrary values that can be tweaked
        // Just make sure to keep invariants like Five > Three, etc.
        Radians::from_radians_value(match self {
            One => 0.3 * PI,
            Two => 0.6 * PI,
            Three => 0.9 * PI,
            Four => 1.2 * PI,
            Five =>  1.5 * PI,
            Six => 1.8 * PI,
            Seven => 2.1 * PI,
            Eight => 2.4 * PI,
            Nine => 2.7 * PI,
            Ten => 3.0 * PI,
            Instant => f64::INFINITY,
        })
    }
}

impl<'a> From<&'a str> for Speed {
    fn from(s: &'a str) -> Self {
        use Speed::*;

        match s {
            "slowest" => One,
            "slow" => Three,
            "normal" => Six,
            "fast" => Ten,
            "fastest" => Instant,
            _ => panic!("Invalid speed specified, use one of the words: 'slowest', 'slow', 'normal', 'fast', 'fastest'"),
        }
    }
}

impl From<i32> for Speed {
    fn from(n: i32) -> Self {
        use Speed::*;

        match n {
            1 => One,
            2 => Two,
            3 => Three,
            4 => Four,
            5 => Five,
            6 => Six,
            7 => Seven,
            8 => Eight,
            9 => Nine,
            10 => Ten,
            _ => Instant,
        }
    }
}
<commit_msg>Tweaking speeds<commit_after>use std::f64;
use std::f64::consts::PI;

use radians::Radians;
use {Distance};

/// Represents the various supported speeds that the turtle can move at
///
/// See [`Turtle::set_speed` method](struct.Turtle.html#method.set_speed) for more information.
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub enum Speed {
    One,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    Instant,
}

impl Speed {
    /// Converts a speed to its value as pixels per second
    pub fn to_absolute(self) -> Distance {
        use self::Speed::*;
        // Arbitrary values that can be tweaked
        // Just make sure to keep invariants like Five > Three, etc.
        match self {
            One => 50.,
            Two => 100.,
            Three => 150.,
            Four => 200.,
            Five => 250.,
            Six => 300.,
            Seven => 350.,
            Eight => 400.,
            Nine => 450.,
            Ten => 500.,
            Instant => f64::INFINITY,
        }
    }

    /// Converts a speed to its value as radians per second
    pub fn to_rotation(self) -> Radians {
        use self::Speed::*;
        // Arbitrary values that can be tweaked
        // Just make sure to keep invariants like Five > Three, etc.
        Radians::from_radians_value(match self {
            One => 0.3 * PI,
            Two => 0.6 * PI,
            Three => 0.9 * PI,
            Four => 1.2 * PI,
            Five =>  1.5 * PI,
            Six => 1.8 * PI,
            Seven => 2.1 * PI,
            Eight => 2.4 * PI,
            Nine => 2.7 * PI,
            Ten => 3.0 * PI,
            Instant => f64::INFINITY,
        })
    }
}

impl<'a> From<&'a str> for Speed {
    fn from(s: &'a str) -> Self {
        use Speed::*;

        match s {
            "slowest" => One,
            "slow" => Three,
            "normal" => Six,
            "fast" => Ten,
            "fastest" => Instant,
            _ => panic!("Invalid speed specified, use one of the words: 'slowest', 'slow', 'normal', 'fast', 'fastest'"),
        }
    }
}

impl From<i32> for Speed {
    fn from(n: i32) -> Self {
        use Speed::*;

        match n {
            1 => One,
            2 => Two,
            3 => Three,
            4 => Four,
            5 => Five,
            6 => Six,
            7 => Seven,
            8 => Eight,
            9 => Nine,
            10 => Ten,
            _ => Instant,
        }
    }
}
<|endoftext|>


<commit_before>//! Formatting helpers for the logger middleware.

use iron::{Request, Response};
use term::{attr, color};
use iron::status::NotFound;

use std::default::Default;
use std::from_str::FromStr;
use std::str::Chars;
use std::vec::MoveItems;
use std::iter::Peekable;

/// A formatting style for the `Logger`, consisting of multiple
/// `FormatUnit`s concatenated into one line.
#[deriving(Clone)]
pub struct Format(pub Vec<FormatUnit>);

impl Default for Format {
    /// Return the default formatting style for the `Logger`:
    ///
    /// ```ignore
    /// @[bold]{method}@ {uri} @[bold]->@ @[C]{status}@ ({response-time})
    /// // This will be written as: {method} {uri} -> {status} ({response-time})
    /// // with certain style attributes.
    /// ```
    ///
    /// The method is in bold, and the response status is colored blue for 100s,
    /// green for 200s, yellow for 300s, red for 400s, and bright red for 500s.
    fn default() -> Format {
        fn status_color(_req: &Request, res: &Response) -> Option<color::Color> {
            match res.status.as_ref().unwrap_or(&NotFound).code() / 100 {
                1 => Some(color::BLUE), // Information
                2 => Some(color::GREEN), // Success
                3 => Some(color::YELLOW), // Redirection
                4 => Some(color::RED), // Client Error
                5 => Some(color::BRIGHT_RED), // Internal Error
                _ => None
            }
        }

        Format::new("@[bold]{method}@ {uri} @[bold]->@ @[C]{status}@ ({response-time})",
           vec![FunctionColor(status_color)], vec![]).unwrap()
    }
}

impl Format {
    // TODO: Document the color/attribute tags.
    /// Create a `Format` from a format string, which can contain the fields
    /// `{method}`, `{uri}`, `{status}`, and `{response-time}`.
    ///
    /// Returns `None` if the format string syntax is incorrect.
    ///
    /// ---
    ///
    /// Colors and attributes can also be added to the format string within `@` delimiters,
    /// by specifying them in a space-delimited list within square brackets (`[bold italic]`).
    /// They can be made dependent on the request/response by passing `FunctionColor` and
    /// `FunctionAttr`s in as the `colors` and `attrs` vecs; these colors/attributes will
    /// be used sequentially when there is a `[C]` or `[A]` marker, respectively (`[bold C]`).
    ///
    /// For example: `@[bold C]{status}@` will be formatted based upon
    /// the first FormatColor constant or function in the `colors` vector,
    /// yielding a bold and colored response status.
    ///
    /// Available colors are:
    /// - `black`
    /// - `blue`
    /// - `brightblack`
    /// - `brightblue`
    /// - `brightcyan`
    /// - `brightgreen`
    /// - `brightmagenta`
    /// - `brightred`
    /// - `brightwhite`
    /// - `brightyellow`
    /// - `cyan`
    /// - `green`
    /// - `magenta`
    /// - `red`
    /// - `white`
    /// - `yellow`
    ///
    /// Available attributes are:
    /// - `bold`
    /// - `dim`
    /// - `italic`
    /// - `underline`
    /// - `blink`
    /// - `standout`
    /// - `reverse`
    /// - `secure`
    pub fn new(s: &str, colors: Vec<FormatColor>, attrs: Vec<FormatAttr>)
            -> Option<Format> {

        let mut parser = FormatParser::new(s.chars().peekable(),
                                           colors.into_iter(),
                                           attrs.into_iter());

        let mut results = Vec::new();

        for unit in parser {
            match unit {
                Some(unit) => results.push(unit),
                None => return None
            }
        }

        Some(Format(results))
    }
}

struct FormatParser<'a> {
    // The characters of the format string.
    chars: Peekable<char, Chars<'a>>,

    // Passed-in FormatColors
    colors: MoveItems<FormatColor>,

    // Passed-in FormatAttr
    attrs: MoveItems<FormatAttr>,

    // A reusable buffer for parsing style attributes.
    object_buffer: String,

    // A queue of waiting format units to avoid full-on
    // state-machine parsing.
    waitqueue: Vec<FormatUnit>,

    finished: bool
}

impl<'a> FormatParser<'a> {
    fn new(chars: Peekable<char, Chars>, colors: MoveItems<FormatColor>,
           attrs: MoveItems<FormatAttr>) -> FormatParser {
        FormatParser {
            chars: chars,
            colors: colors,
            attrs: attrs,

            // No attributes are longer than 14 characters, so we can avoid reallocating.
            object_buffer: String::with_capacity(14),

            waitqueue: vec![],
            finished: false
        }
    }
}

// Some(None) means there was a parse error and this FormatParser should be abandoned.
impl<'a> Iterator<Option<FormatUnit>> for FormatParser<'a> {
    fn next(&mut self) -> Option<Option<FormatUnit>> {
        // If the parser has been cancelled or errored for some reason.
        if self.finished { return None }

        if self.waitqueue.len() != 0 {
            return Some(self.waitqueue.remove(0));
        }

        // Try to parse a new FormatUnit.
        match self.chars.next() {
            // Parse a recognized object.
            //
            // The allowed forms are:
            //   - {method}
            //   - {uri}
            //   - {status}
            //   - {response-time}
            Some('{') => {
                self.object_buffer.clear();

                for chr in self.chars {
                    match chr {
                        // Finished parsing, parse buffer.
                        '}' => break,
                        c => self.object_buffer.push(c)
                    }
                }

                let text = match self.object_buffer.as_slice() {
                    "method" => Method,
                    "uri" => URI,
                    "status" => Status,
                    "response-time" => ResponseTime,
                    _ => {
                        // Error, so mark as finished.
                        self.finished = true;
                        return Some(None);
                    }
                };

                Some(Some(FormatUnit {
                    text: text,
                    color: ConstantColor(None),
                    attrs: ConstantAttrs(vec![])
                }))
            },

            // Parse an attribute and the thing it applies to.
            //
            // The form is:
            //   - @[attributes]target@
            Some('@') => {
                match self.chars.next() {
                    // Parse attributes
                    Some('[') => {
                        let mut buffer = String::new();

                        loop {
                            match self.chars.next() {
                                // Finished parsing into buffer.
                                Some(']') => break,
                                Some(c) => buffer.push(c),
                                // Error, so mark as finished.
                                None => {
                                    self.finished = true;
                                    return Some(None);
                                }
                            }
                        }

                        let mut attrs = ConstantAttrs(vec![]);
                        let mut color = ConstantColor(None);

                        // Collect the attributes into attrs and color, for use as properties
                        // of a FormatUnit.
                        for word in buffer.as_slice().words() {
                            match word {
                                "A" => attrs = self.attrs.next().unwrap_or(ConstantAttrs(vec![])),

                                "C" => color = self.colors.next().unwrap_or(ConstantColor(None)),

                                style => match from_str(style) {
                                    Some(Color(c)) => match color {
                                        ConstantColor(_) => { color = ConstantColor(Some(c)); },
                                        _ => {}
                                    },

                                    Some(Attr(a)) => match attrs {
                                        ConstantAttrs(ref mut v) => { v.push(a); },
                                        _ => {}
                                    },

                                    _ => {}
                                }
                            }
                        }

                        // Nested attributes are not supported.
                        if self.chars.peek() == Some(&'@') {
                            self.finished = true;
                            return Some(None);
                        }

                        // Now we have the parsed attributes, so we can parse what they apply to.
                        let mut apply_to = vec![];

                        loop {
                            match self.next() {
                                Some(Some(unit)) => apply_to.push(unit),
                                _ => {
                                    self.finished = true;
                                    return Some(None);
                                }
                            };

                            if self.chars.peek() == Some(&'@') {
                                // Jump over the closing '@'
                                self.chars.next();
                                break;
                            }
                        }

                        self.waitqueue.extend(apply_to.into_iter().map(|unit| {
                            FormatUnit {
                                text: unit.text,
                                color: color.clone(),
                                attrs: attrs.clone()
                            }
                        }));

                        self.next()
                    },

                    _ => {
                        // Error, so mark as finished.
                        self.finished = true;
                        return Some(None);
                    }
                }
            },

            // Parse a regular string part of the format string.
            Some(c) => {
                let mut buffer = String::new();
                buffer.push(c);

                loop {
                    match self.chars.peek() {
                        // Done parsing.
                        Some(&'@') | Some(&'{') | None => {
                            return Some(Some(FormatUnit {
                                text: Str(buffer),
                                color: ConstantColor(None),
                                attrs: ConstantAttrs(vec![])
                            }))
                        },

                        Some(_) => {
                            buffer.push(self.chars.next().unwrap())
                        }
                    }
                }
            },

            // Reached end of the format string.
            None => None
        }
    }
}

impl FromStr for ColorOrAttr {
    fn from_str(name: &str) -> Option<ColorOrAttr> {
        match name {
            "black" => Some(Color(color::BLACK)),
            "blue" => Some(Color(color::BLUE)),
            "brightblack" => Some(Color(color::BRIGHT_BLACK)),
            "brightblue" => Some(Color(color::BRIGHT_BLUE)),
            "brightcyan" => Some(Color(color::BRIGHT_CYAN)),
            "brightgreen" => Some(Color(color::BRIGHT_GREEN)),
            "brightmagenta" => Some(Color(color::BRIGHT_MAGENTA)),
            "brightred" => Some(Color(color::BRIGHT_RED)),
            "brightwhite" => Some(Color(color::BRIGHT_WHITE)),
            "brightyellow" => Some(Color(color::BRIGHT_YELLOW)),
            "cyan" => Some(Color(color::CYAN)),
            "green" => Some(Color(color::GREEN)),
            "magenta" => Some(Color(color::MAGENTA)),
            "red" => Some(Color(color::RED)),
            "white" => Some(Color(color::WHITE)),
            "yellow" => Some(Color(color::YELLOW)),

            "bold" => Some(Attr(attr::Bold)),
            "dim" => Some(Attr(attr::Dim)),
            "italic" => Some(Attr(attr::Italic(true))),
            "underline" => Some(Attr(attr::Underline(true))),
            "blink" => Some(Attr(attr::Blink)),
            "standout" => Some(Attr(attr::Standout(true))),
            "reverse" => Some(Attr(attr::Reverse)),
            "secure" => Some(Attr(attr::Secure)),

            _ => None
        }
    }
}

enum ColorOrAttr {
    Color(color::Color),
    Attr(attr::Attr)
}

/// A representation of color in a `FormatUnit`.
pub enum FormatColor {
    /// A constant color
    ConstantColor(Option<color::Color>),
    /// A variable color, dependent on the request/response
    ///
    /// This can be used to change the color depending on response status, &c.
    FunctionColor(fn(&Request, &Response) -> Option<color::Color>)
}

/// A representation of attributes in a `FormatUnit`.
pub enum FormatAttr {
    /// A constant attribute
    ConstantAttrs(Vec<attr::Attr>),
    /// A variable attribute, dependent on the request/response
    ///
    /// This can be used to change the attribute depending on response status, &c.
    FunctionAttrs(fn(&Request, &Response) -> Vec<attr::Attr>)
}

impl Clone for FormatColor {
    fn clone(&self) -> FormatColor { *self }
}

impl Clone for FormatAttr {
    fn clone(&self) -> FormatAttr {
        match *self {
            ConstantAttrs(ref attrs) => ConstantAttrs(attrs.iter().map(|&attr| attr).collect()),
            FunctionAttrs(f) => FunctionAttrs(f)
        }
    }
}

/// A string of text to be logged. This is either one of the data
/// fields supported by the `Logger`, or a custom `String`.
#[deriving(Clone)]
#[doc(hidden)]
pub enum FormatText {
    Str(String),
    Method,
    URI,
    Status,
    ResponseTime
}

/// A `FormatText` with associated style information.
#[deriving(Clone)]
#[doc(hidden)]
pub struct FormatUnit {
    pub text: FormatText,
    pub color: FormatColor,
    pub attrs: FormatAttr
}

<commit_msg>(docs) Fix markdown lists.<commit_after>//! Formatting helpers for the logger middleware.

use iron::{Request, Response};
use term::{attr, color};
use iron::status::NotFound;

use std::default::Default;
use std::from_str::FromStr;
use std::str::Chars;
use std::vec::MoveItems;
use std::iter::Peekable;

/// A formatting style for the `Logger`, consisting of multiple
/// `FormatUnit`s concatenated into one line.
#[deriving(Clone)]
pub struct Format(pub Vec<FormatUnit>);

impl Default for Format {
    /// Return the default formatting style for the `Logger`:
    ///
    /// ```ignore
    /// @[bold]{method}@ {uri} @[bold]->@ @[C]{status}@ ({response-time})
    /// // This will be written as: {method} {uri} -> {status} ({response-time})
    /// // with certain style attributes.
    /// ```
    ///
    /// The method is in bold, and the response status is colored blue for 100s,
    /// green for 200s, yellow for 300s, red for 400s, and bright red for 500s.
    fn default() -> Format {
        fn status_color(_req: &Request, res: &Response) -> Option<color::Color> {
            match res.status.as_ref().unwrap_or(&NotFound).code() / 100 {
                1 => Some(color::BLUE), // Information
                2 => Some(color::GREEN), // Success
                3 => Some(color::YELLOW), // Redirection
                4 => Some(color::RED), // Client Error
                5 => Some(color::BRIGHT_RED), // Internal Error
                _ => None
            }
        }

        Format::new("@[bold]{method}@ {uri} @[bold]->@ @[C]{status}@ ({response-time})",
           vec![FunctionColor(status_color)], vec![]).unwrap()
    }
}

impl Format {
    // TODO: Document the color/attribute tags.
    /// Create a `Format` from a format string, which can contain the fields
    /// `{method}`, `{uri}`, `{status}`, and `{response-time}`.
    ///
    /// Returns `None` if the format string syntax is incorrect.
    ///
    /// ---
    ///
    /// Colors and attributes can also be added to the format string within `@` delimiters,
    /// by specifying them in a space-delimited list within square brackets (`[bold italic]`).
    /// They can be made dependent on the request/response by passing `FunctionColor` and
    /// `FunctionAttr`s in as the `colors` and `attrs` vecs; these colors/attributes will
    /// be used sequentially when there is a `[C]` or `[A]` marker, respectively (`[bold C]`).
    ///
    /// For example: `@[bold C]{status}@` will be formatted based upon
    /// the first FormatColor constant or function in the `colors` vector,
    /// yielding a bold and colored response status.
    ///
    /// Available colors are:
    ///
    /// - `black`
    /// - `blue`
    /// - `brightblack`
    /// - `brightblue`
    /// - `brightcyan`
    /// - `brightgreen`
    /// - `brightmagenta`
    /// - `brightred`
    /// - `brightwhite`
    /// - `brightyellow`
    /// - `cyan`
    /// - `green`
    /// - `magenta`
    /// - `red`
    /// - `white`
    /// - `yellow`
    ///
    /// Available attributes are:
    ///
    /// - `bold`
    /// - `dim`
    /// - `italic`
    /// - `underline`
    /// - `blink`
    /// - `standout`
    /// - `reverse`
    /// - `secure`
    pub fn new(s: &str, colors: Vec<FormatColor>, attrs: Vec<FormatAttr>)
            -> Option<Format> {

        let mut parser = FormatParser::new(s.chars().peekable(),
                                           colors.into_iter(),
                                           attrs.into_iter());

        let mut results = Vec::new();

        for unit in parser {
            match unit {
                Some(unit) => results.push(unit),
                None => return None
            }
        }

        Some(Format(results))
    }
}

struct FormatParser<'a> {
    // The characters of the format string.
    chars: Peekable<char, Chars<'a>>,

    // Passed-in FormatColors
    colors: MoveItems<FormatColor>,

    // Passed-in FormatAttr
    attrs: MoveItems<FormatAttr>,

    // A reusable buffer for parsing style attributes.
    object_buffer: String,

    // A queue of waiting format units to avoid full-on
    // state-machine parsing.
    waitqueue: Vec<FormatUnit>,

    finished: bool
}

impl<'a> FormatParser<'a> {
    fn new(chars: Peekable<char, Chars>, colors: MoveItems<FormatColor>,
           attrs: MoveItems<FormatAttr>) -> FormatParser {
        FormatParser {
            chars: chars,
            colors: colors,
            attrs: attrs,

            // No attributes are longer than 14 characters, so we can avoid reallocating.
            object_buffer: String::with_capacity(14),

            waitqueue: vec![],
            finished: false
        }
    }
}

// Some(None) means there was a parse error and this FormatParser should be abandoned.
impl<'a> Iterator<Option<FormatUnit>> for FormatParser<'a> {
    fn next(&mut self) -> Option<Option<FormatUnit>> {
        // If the parser has been cancelled or errored for some reason.
        if self.finished { return None }

        if self.waitqueue.len() != 0 {
            return Some(self.waitqueue.remove(0));
        }

        // Try to parse a new FormatUnit.
        match self.chars.next() {
            // Parse a recognized object.
            //
            // The allowed forms are:
            //   - {method}
            //   - {uri}
            //   - {status}
            //   - {response-time}
            Some('{') => {
                self.object_buffer.clear();

                for chr in self.chars {
                    match chr {
                        // Finished parsing, parse buffer.
                        '}' => break,
                        c => self.object_buffer.push(c)
                    }
                }

                let text = match self.object_buffer.as_slice() {
                    "method" => Method,
                    "uri" => URI,
                    "status" => Status,
                    "response-time" => ResponseTime,
                    _ => {
                        // Error, so mark as finished.
                        self.finished = true;
                        return Some(None);
                    }
                };

                Some(Some(FormatUnit {
                    text: text,
                    color: ConstantColor(None),
                    attrs: ConstantAttrs(vec![])
                }))
            },

            // Parse an attribute and the thing it applies to.
            //
            // The form is:
            //   - @[attributes]target@
            Some('@') => {
                match self.chars.next() {
                    // Parse attributes
                    Some('[') => {
                        let mut buffer = String::new();

                        loop {
                            match self.chars.next() {
                                // Finished parsing into buffer.
                                Some(']') => break,
                                Some(c) => buffer.push(c),
                                // Error, so mark as finished.
                                None => {
                                    self.finished = true;
                                    return Some(None);
                                }
                            }
                        }

                        let mut attrs = ConstantAttrs(vec![]);
                        let mut color = ConstantColor(None);

                        // Collect the attributes into attrs and color, for use as properties
                        // of a FormatUnit.
                        for word in buffer.as_slice().words() {
                            match word {
                                "A" => attrs = self.attrs.next().unwrap_or(ConstantAttrs(vec![])),

                                "C" => color = self.colors.next().unwrap_or(ConstantColor(None)),

                                style => match from_str(style) {
                                    Some(Color(c)) => match color {
                                        ConstantColor(_) => { color = ConstantColor(Some(c)); },
                                        _ => {}
                                    },

                                    Some(Attr(a)) => match attrs {
                                        ConstantAttrs(ref mut v) => { v.push(a); },
                                        _ => {}
                                    },

                                    _ => {}
                                }
                            }
                        }

                        // Nested attributes are not supported.
                        if self.chars.peek() == Some(&'@') {
                            self.finished = true;
                            return Some(None);
                        }

                        // Now we have the parsed attributes, so we can parse what they apply to.
                        let mut apply_to = vec![];

                        loop {
                            match self.next() {
                                Some(Some(unit)) => apply_to.push(unit),
                                _ => {
                                    self.finished = true;
                                    return Some(None);
                                }
                            };

                            if self.chars.peek() == Some(&'@') {
                                // Jump over the closing '@'
                                self.chars.next();
                                break;
                            }
                        }

                        self.waitqueue.extend(apply_to.into_iter().map(|unit| {
                            FormatUnit {
                                text: unit.text,
                                color: color.clone(),
                                attrs: attrs.clone()
                            }
                        }));

                        self.next()
                    },

                    _ => {
                        // Error, so mark as finished.
                        self.finished = true;
                        return Some(None);
                    }
                }
            },

            // Parse a regular string part of the format string.
            Some(c) => {
                let mut buffer = String::new();
                buffer.push(c);

                loop {
                    match self.chars.peek() {
                        // Done parsing.
                        Some(&'@') | Some(&'{') | None => {
                            return Some(Some(FormatUnit {
                                text: Str(buffer),
                                color: ConstantColor(None),
                                attrs: ConstantAttrs(vec![])
                            }))
                        },

                        Some(_) => {
                            buffer.push(self.chars.next().unwrap())
                        }
                    }
                }
            },

            // Reached end of the format string.
            None => None
        }
    }
}

impl FromStr for ColorOrAttr {
    fn from_str(name: &str) -> Option<ColorOrAttr> {
        match name {
            "black" => Some(Color(color::BLACK)),
            "blue" => Some(Color(color::BLUE)),
            "brightblack" => Some(Color(color::BRIGHT_BLACK)),
            "brightblue" => Some(Color(color::BRIGHT_BLUE)),
            "brightcyan" => Some(Color(color::BRIGHT_CYAN)),
            "brightgreen" => Some(Color(color::BRIGHT_GREEN)),
            "brightmagenta" => Some(Color(color::BRIGHT_MAGENTA)),
            "brightred" => Some(Color(color::BRIGHT_RED)),
            "brightwhite" => Some(Color(color::BRIGHT_WHITE)),
            "brightyellow" => Some(Color(color::BRIGHT_YELLOW)),
            "cyan" => Some(Color(color::CYAN)),
            "green" => Some(Color(color::GREEN)),
            "magenta" => Some(Color(color::MAGENTA)),
            "red" => Some(Color(color::RED)),
            "white" => Some(Color(color::WHITE)),
            "yellow" => Some(Color(color::YELLOW)),

            "bold" => Some(Attr(attr::Bold)),
            "dim" => Some(Attr(attr::Dim)),
            "italic" => Some(Attr(attr::Italic(true))),
            "underline" => Some(Attr(attr::Underline(true))),
            "blink" => Some(Attr(attr::Blink)),
            "standout" => Some(Attr(attr::Standout(true))),
            "reverse" => Some(Attr(attr::Reverse)),
            "secure" => Some(Attr(attr::Secure)),

            _ => None
        }
    }
}

enum ColorOrAttr {
    Color(color::Color),
    Attr(attr::Attr)
}

/// A representation of color in a `FormatUnit`.
pub enum FormatColor {
    /// A constant color
    ConstantColor(Option<color::Color>),
    /// A variable color, dependent on the request/response
    ///
    /// This can be used to change the color depending on response status, &c.
    FunctionColor(fn(&Request, &Response) -> Option<color::Color>)
}

/// A representation of attributes in a `FormatUnit`.
pub enum FormatAttr {
    /// A constant attribute
    ConstantAttrs(Vec<attr::Attr>),
    /// A variable attribute, dependent on the request/response
    ///
    /// This can be used to change the attribute depending on response status, &c.
    FunctionAttrs(fn(&Request, &Response) -> Vec<attr::Attr>)
}

impl Clone for FormatColor {
    fn clone(&self) -> FormatColor { *self }
}

impl Clone for FormatAttr {
    fn clone(&self) -> FormatAttr {
        match *self {
            ConstantAttrs(ref attrs) => ConstantAttrs(attrs.iter().map(|&attr| attr).collect()),
            FunctionAttrs(f) => FunctionAttrs(f)
        }
    }
}

/// A string of text to be logged. This is either one of the data
/// fields supported by the `Logger`, or a custom `String`.
#[deriving(Clone)]
#[doc(hidden)]
pub enum FormatText {
    Str(String),
    Method,
    URI,
    Status,
    ResponseTime
}

/// A `FormatText` with associated style information.
#[deriving(Clone)]
#[doc(hidden)]
pub struct FormatUnit {
    pub text: FormatText,
    pub color: FormatColor,
    pub attrs: FormatAttr
}

<|endoftext|>


<commit_before>//! Module for parsing ISO Base Media Format aka video/mp4 streams.
//! Internal unit tests.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::io::Cursor;
use super::*;
extern crate test_assembler;
use self::test_assembler::*;

enum BoxSize {
    Short(u32),
    Long(u64),
    UncheckedShort(u32),
    UncheckedLong(u64),
}

fn make_box_raw<F>(size: BoxSize, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    let mut section = Section::new();
    section = match size {
        BoxSize::Short(size) | BoxSize::UncheckedShort(size) => section.B32(size),
        BoxSize::Long(_) | BoxSize::UncheckedLong(_) => section.B32(1),
    };
    section = section.append_bytes(name);
    section = match size {
        // The spec allows the 32-bit size to be 0 to indicate unknown
        // length streams.  It's not clear if this is valid when using a
        // 64-bit size, so prohibit it for now.
        BoxSize::Long(size) => {
            assert!(size > 0);
            section.B64(size)
        }
        BoxSize::UncheckedLong(size) => section.B64(size),
        _ => section,
    };
    section = func(section);
    match size {
        BoxSize::Short(size) => {
            if size > 0 {
                assert_eq!(size as u64, section.size())
            }
        }
        BoxSize::Long(size) => assert_eq!(size, section.size()),
        _ => (),
    }
    Cursor::new(section.get_contents().unwrap())
}

fn make_box<F>(size: u32, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(BoxSize::Short(size), name, func)
}

fn make_fullbox<F>(size: u32, name: &[u8; 4], version: u8, func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(BoxSize::Short(size), name, |s| {
        func(s.B8(version)
              .B8(0)
              .B8(0)
              .B8(0))
    })
}

#[test]
fn read_box_header_short() {
    let mut stream = make_box_raw(BoxSize::Short(8), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 8);
}

#[test]
fn read_box_header_long() {
    let mut stream = make_box_raw(BoxSize::Long(16), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 16);
}

#[test]
fn read_box_header_short_unknown_size() {
    let mut stream = make_box_raw(BoxSize::Short(0), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::Unsupported) => (),
        _ => panic!("unexpected result reading box with unknown size"),
    };
}

#[test]
fn read_box_header_short_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedShort(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_box_header_long_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedLong(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_ftyp() {
    let mut stream = make_box(24, b"ftyp", |s| {
        s.append_bytes(b"mp42")
         .B32(0) // minor version
         .append_bytes(b"isom")
         .append_bytes(b"mp42")
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_ftyp(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"ftyp"));
    assert_eq!(parsed.header.size, 24);
    assert_eq!(parsed.major_brand, FourCC(*b"mp42"));
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    assert_eq!(parsed.compatible_brands[0], FourCC(*b"isom"));
    assert_eq!(parsed.compatible_brands[1], FourCC(*b"mp42"));
}

#[test]
#[should_panic]
fn read_truncated_ftyp() {
    // We declare a 24 byte box, but only write 20 bytes.
    let mut stream = make_box_raw(BoxSize::UncheckedShort(24), b"ftyp", |s| {
        s.append_bytes(b"mp42")
            .B32(0) // minor version
            .append_bytes(b"isom")
    });
    let mut context = MediaContext::new();
    context.trace(true);
    match read_mp4(&mut stream, &mut context) {
        Err(Error::UnexpectedEOF) => (),
        Ok(_) => assert!(false, "expected an error result"),
        _ => assert!(false, "expected a different error result"),
    }
}

#[test]
fn read_elst_v0() {
    let mut stream = make_fullbox(28, b"elst", 0, |s| {
        s.B32(1) // list count
          // first entry
         .B32(1234) // duration
         .B32(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 28);
    assert_eq!(parsed.edits.len(), 1);
    assert_eq!(parsed.edits[0].segment_duration, 1234);
    assert_eq!(parsed.edits[0].media_time, 5678);
    assert_eq!(parsed.edits[0].media_rate_integer, 12);
    assert_eq!(parsed.edits[0].media_rate_fraction, 34);
}

#[test]
fn read_elst_v1() {
    let mut stream = make_fullbox(56, b"elst", 1, |s| {
        s.B32(2) // list count
         // first entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
         // second entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 56);
    assert_eq!(parsed.edits.len(), 2);
    assert_eq!(parsed.edits[1].segment_duration, 1234);
    assert_eq!(parsed.edits[1].media_time, 5678);
    assert_eq!(parsed.edits[1].media_rate_integer, 12);
    assert_eq!(parsed.edits[1].media_rate_fraction, 34);
}

#[test]
fn read_mdhd_v0() {
    let mut stream = make_fullbox(32, b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_v1() {
    let mut stream = make_fullbox(44, b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 44);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_unknown_duration() {
    let mut stream = make_fullbox(32, b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(::std::u32::MAX) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}

#[test]
fn read_mdhd_invalid_timescale() {
    let mut stream = make_fullbox(44, b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mdhd(&mut stream, &header, &mut super::Track::new(0));
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_v0() {
    let mut stream = make_fullbox(108, b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_v1() {
    let mut stream = make_fullbox(120, b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 120);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_invalid_timescale() {
    let mut stream = make_fullbox(120, b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mvhd(&mut stream, &header);
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_unknown_duration() {
    let mut stream = make_fullbox(108, b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(::std::u32::MAX)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}
<commit_msg>Tighten read_truncated_ftyp xfail condition.<commit_after>//! Module for parsing ISO Base Media Format aka video/mp4 streams.
//! Internal unit tests.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::io::Cursor;
use super::*;
extern crate test_assembler;
use self::test_assembler::*;

enum BoxSize {
    Short(u32),
    Long(u64),
    UncheckedShort(u32),
    UncheckedLong(u64),
}

fn make_box_raw<F>(size: BoxSize, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    let mut section = Section::new();
    section = match size {
        BoxSize::Short(size) | BoxSize::UncheckedShort(size) => section.B32(size),
        BoxSize::Long(_) | BoxSize::UncheckedLong(_) => section.B32(1),
    };
    section = section.append_bytes(name);
    section = match size {
        // The spec allows the 32-bit size to be 0 to indicate unknown
        // length streams.  It's not clear if this is valid when using a
        // 64-bit size, so prohibit it for now.
        BoxSize::Long(size) => {
            assert!(size > 0);
            section.B64(size)
        }
        BoxSize::UncheckedLong(size) => section.B64(size),
        _ => section,
    };
    section = func(section);
    match size {
        BoxSize::Short(size) => {
            if size > 0 {
                assert_eq!(size as u64, section.size())
            }
        }
        BoxSize::Long(size) => assert_eq!(size, section.size()),
        _ => (),
    }
    Cursor::new(section.get_contents().unwrap())
}

fn make_box<F>(size: u32, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(BoxSize::Short(size), name, func)
}

fn make_fullbox<F>(size: u32, name: &[u8; 4], version: u8, func: F) -> Cursor<Vec<u8>>
    where F: Fn(Section) -> Section
{
    make_box_raw(BoxSize::Short(size), name, |s| {
        func(s.B8(version)
              .B8(0)
              .B8(0)
              .B8(0))
    })
}

#[test]
fn read_box_header_short() {
    let mut stream = make_box_raw(BoxSize::Short(8), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 8);
}

#[test]
fn read_box_header_long() {
    let mut stream = make_box_raw(BoxSize::Long(16), b"test", |s| s);
    let parsed = read_box_header(&mut stream).unwrap();
    assert_eq!(parsed.name, FourCC(*b"test"));
    assert_eq!(parsed.size, 16);
}

#[test]
fn read_box_header_short_unknown_size() {
    let mut stream = make_box_raw(BoxSize::Short(0), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::Unsupported) => (),
        _ => panic!("unexpected result reading box with unknown size"),
    };
}

#[test]
fn read_box_header_short_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedShort(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_box_header_long_invalid_size() {
    let mut stream = make_box_raw(BoxSize::UncheckedLong(2), b"test", |s| s);
    match read_box_header(&mut stream) {
        Err(Error::InvalidData) => (),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_ftyp() {
    let mut stream = make_box(24, b"ftyp", |s| {
        s.append_bytes(b"mp42")
         .B32(0) // minor version
         .append_bytes(b"isom")
         .append_bytes(b"mp42")
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_ftyp(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"ftyp"));
    assert_eq!(parsed.header.size, 24);
    assert_eq!(parsed.major_brand, FourCC(*b"mp42"));
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    assert_eq!(parsed.compatible_brands[0], FourCC(*b"isom"));
    assert_eq!(parsed.compatible_brands[1], FourCC(*b"mp42"));
}

#[test]
#[should_panic(expected = "expected an error result")]
fn read_truncated_ftyp() {
    // We declare a 24 byte box, but only write 20 bytes.
    let mut stream = make_box_raw(BoxSize::UncheckedShort(24), b"ftyp", |s| {
        s.append_bytes(b"mp42")
            .B32(0) // minor version
            .append_bytes(b"isom")
    });
    let mut context = MediaContext::new();
    context.trace(true);
    match read_mp4(&mut stream, &mut context) {
        Err(Error::UnexpectedEOF) => (),
        Ok(_) => assert!(false, "expected an error result"),
        _ => assert!(false, "expected a different error result"),
    }
}

#[test]
fn read_elst_v0() {
    let mut stream = make_fullbox(28, b"elst", 0, |s| {
        s.B32(1) // list count
          // first entry
         .B32(1234) // duration
         .B32(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 28);
    assert_eq!(parsed.edits.len(), 1);
    assert_eq!(parsed.edits[0].segment_duration, 1234);
    assert_eq!(parsed.edits[0].media_time, 5678);
    assert_eq!(parsed.edits[0].media_rate_integer, 12);
    assert_eq!(parsed.edits[0].media_rate_fraction, 34);
}

#[test]
fn read_elst_v1() {
    let mut stream = make_fullbox(56, b"elst", 1, |s| {
        s.B32(2) // list count
         // first entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
         // second entry
         .B64(1234) // duration
         .B64(5678) // time
         .B16(12) // rate integer
         .B16(34) // rate fraction
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_elst(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"elst"));
    assert_eq!(parsed.header.size, 56);
    assert_eq!(parsed.edits.len(), 2);
    assert_eq!(parsed.edits[1].segment_duration, 1234);
    assert_eq!(parsed.edits[1].media_time, 5678);
    assert_eq!(parsed.edits[1].media_rate_integer, 12);
    assert_eq!(parsed.edits[1].media_rate_fraction, 34);
}

#[test]
fn read_mdhd_v0() {
    let mut stream = make_fullbox(32, b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_v1() {
    let mut stream = make_fullbox(44, b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 44);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_unknown_duration() {
    let mut stream = make_fullbox(32, b"mdhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234) // timescale
         .B32(::std::u32::MAX) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mdhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mdhd"));
    assert_eq!(parsed.header.size, 32);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}

#[test]
fn read_mdhd_invalid_timescale() {
    let mut stream = make_fullbox(44, b"mdhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0) // timescale
         .B64(5678) // duration
         .B32(0)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mdhd(&mut stream, &header, &mut super::Track::new(0));
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_v0() {
    let mut stream = make_fullbox(108, b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_v1() {
    let mut stream = make_fullbox(120, b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(1234)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 120);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_invalid_timescale() {
    let mut stream = make_fullbox(120, b"mvhd", 1, |s| {
        s.B64(0)
         .B64(0)
         .B32(0)
         .B64(5678)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let r = super::parse_mvhd(&mut stream, &header);
    assert_eq!(r.is_err(), true);
}

#[test]
fn read_mvhd_unknown_duration() {
    let mut stream = make_fullbox(108, b"mvhd", 0, |s| {
        s.B32(0)
         .B32(0)
         .B32(1234)
         .B32(::std::u32::MAX)
         .append_repeated(0, 80)
    });
    let header = read_box_header(&mut stream).unwrap();
    let parsed = super::read_mvhd(&mut stream, &header).unwrap();
    assert_eq!(parsed.header.name, FourCC(*b"mvhd"));
    assert_eq!(parsed.header.size, 108);
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, ::std::u64::MAX);
}
<|endoftext|>


<commit_before>use std::env::current_exe;
use std::fs::{File, remove_file};
use std::io::Read;
use std::path::Path;
use std::process::exit;
use std::thread::sleep;
use std::time::Duration;
use super::Result;
use team::Team;
use tmux;

const MOB_FILE_PATH: &'static str = "/tmp/mob";

pub fn run(time_per_driver_in_minutes: &f64, team: &mut Team) -> Result<()> {
    let time_per_driver_in_seconds = time_per_driver_in_minutes * 60.0;

    let mut elapsed_time = 0.0;

    loop {
        if is_time_for_next_driver(&time_per_driver_in_seconds, elapsed_time) {
            prompt_user(team)?;
        };

        elapsed_time += 1.0;
        sleep(Duration::from_secs(1))
    }
}

fn prompt_user(team: &mut Team) -> Result<()> {
    let bin = current_exe()?.to_str().expect("Binary path").to_owned();
    let next_driver = team.next_driver();

    let prompt_command = format!("{} prompt {}", bin, next_driver);
    let exit_status = tmux::new_window_with_command(&prompt_command)?;

    wait_for_file();

    if exit_status.success() && is_continue()? {
        team.change_driver(&next_driver);
        Ok(())
    } else {
        exit(1);
    }
}

fn wait_for_file() {
    let path = Path::new(MOB_FILE_PATH);

    while !path.exists() {
        sleep(Duration::from_millis(500));
    }
}

fn is_continue() -> Result<bool> {
    let path = Path::new(MOB_FILE_PATH);

    let mut file = File::open(path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    remove_file(path)?;

    Ok(contents == "y")
}

fn is_time_for_next_driver(time_per_driver: &f64, elapsed_time: f64) -> bool {
    if elapsed_time != 0.0 && elapsed_time % time_per_driver == 0.0 {
        true
    } else {
        false
    }
}
<commit_msg>feat: Print out current driver<commit_after>use std::env::current_exe;
use std::fs::{File, remove_file};
use std::io::Read;
use std::path::Path;
use std::process::exit;
use std::thread::sleep;
use std::time::Duration;
use super::Result;
use team::Team;
use tmux;

const MOB_FILE_PATH: &'static str = "/tmp/mob";

pub fn run(time_per_driver_in_minutes: &f64, team: &mut Team) -> Result<()> {
    let time_per_driver_in_seconds = time_per_driver_in_minutes * 60.0;

    let mut elapsed_time = 0.0;

    loop {
        println!("{}", team.driver);
        if is_time_for_next_driver(&time_per_driver_in_seconds, elapsed_time) {
            prompt_user(team)?;
        };

        elapsed_time += 1.0;
        sleep(Duration::from_secs(1))
    }
}

fn prompt_user(team: &mut Team) -> Result<()> {
    let bin = current_exe()?.to_str().expect("Binary path").to_owned();
    let next_driver = team.next_driver();

    let prompt_command = format!("{} prompt {}", bin, next_driver);
    let exit_status = tmux::new_window_with_command(&prompt_command)?;

    wait_for_file();

    if exit_status.success() && is_continue()? {
        team.change_driver(&next_driver);
        Ok(())
    } else {
        exit(1);
    }
}

fn wait_for_file() {
    let path = Path::new(MOB_FILE_PATH);

    while !path.exists() {
        sleep(Duration::from_millis(500));
    }
}

fn is_continue() -> Result<bool> {
    let path = Path::new(MOB_FILE_PATH);

    let mut file = File::open(path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    remove_file(path)?;

    Ok(contents == "y")
}

fn is_time_for_next_driver(time_per_driver: &f64, elapsed_time: f64) -> bool {
    if elapsed_time != 0.0 && elapsed_time % time_per_driver == 0.0 {
        true
    } else {
        false
    }
}
<|endoftext|>