<commit_before>//! Graph visitor algorithms.
//!

use std::marker;
use std::collections::{
    HashSet,
    BitSet,
    VecDeque,
};
use std::hash::Hash;

use super::{
    graphmap,
    graph,
    EdgeType,
    EdgeDirection,
    Graph,
    GraphMap,
};

use graph::{
    IndexType,
};

pub trait Graphlike : marker::MarkerTrait {
    type NodeId: Clone;
}

/// A graph trait for accessing the neighbors iterator
pub trait NeighborIter<'a> : Graphlike{
    type Iter: Iterator<Item=Self::NodeId>;
    fn neighbors(&'a self, n: Self::NodeId) -> Self::Iter;
}

impl<'a, N, E, Ty, Ix> NeighborIter<'a> for Graph<N, E, Ty, Ix> where
    Ty: EdgeType,
    Ix: IndexType,
{
    type Iter = graph::Neighbors<'a, E, Ix>;
    fn neighbors(&'a self, n: graph::NodeIndex<Ix>) -> graph::Neighbors<'a, E, Ix>
    {
        Graph::neighbors(self, n)
    }
}

impl<'a, N, E> NeighborIter<'a> for GraphMap<N, E>
where N: Copy + Clone + Ord + Hash + Eq
{
    type Iter = graphmap::Neighbors<'a, N>;
    fn neighbors(&'a self, n: N) -> graphmap::Neighbors<'a, N>
    {
        GraphMap::neighbors(self, n)
    }
}

/// Wrapper type for walking the graph as if it is undirected
pub struct AsUndirected<G>(pub G);
/// Wrapper type for walking edges the other way
pub struct Reversed<G>(pub G);

impl<'a, 'b, N, E, Ty, Ix> NeighborIter<'a> for AsUndirected<&'b Graph<N, E, Ty, Ix>> where
    Ty: EdgeType,
    Ix: IndexType,
{
    type Iter = graph::Neighbors<'a, E, Ix>;

    fn neighbors(&'a self, n: graph::NodeIndex<Ix>) -> graph::Neighbors<'a, E, Ix>
    {
        Graph::neighbors_undirected(self.0, n)
    }
}

impl<'a, 'b, N, E, Ty, Ix> NeighborIter<'a> for Reversed<&'b Graph<N, E, Ty, Ix>> where
    Ty: EdgeType,
    Ix: IndexType,
{
    type Iter = graph::Neighbors<'a, E, Ix>;
    fn neighbors(&'a self, n: graph::NodeIndex<Ix>) -> graph::Neighbors<'a, E, Ix>
    {
        Graph::neighbors_directed(self.0, n, EdgeDirection::Incoming)
    }
}

pub trait VisitMap<N> {
    /// Return **true** if the value is not already present.
    fn visit(&mut self, N) -> bool;
    fn is_visited(&self, &N) -> bool;
}

impl<Ix> VisitMap<graph::NodeIndex<Ix>> for BitSet where
    Ix: IndexType,
{
    fn visit(&mut self, x: graph::NodeIndex<Ix>) -> bool {
        self.insert(x.index())
    }
    fn is_visited(&self, x: &graph::NodeIndex<Ix>) -> bool {
        self.contains(&x.index())
    }
}

impl<N: Eq + Hash> VisitMap<N> for HashSet<N> {
    fn visit(&mut self, x: N) -> bool {
        self.insert(x)
    }
    fn is_visited(&self, x: &N) -> bool {
        self.contains(x)
    }
}

/// Trait for GraphMap that knows which datastructure is the best for its visitor map
pub trait Visitable : Graphlike {
    type Map: VisitMap<<Self as Graphlike>::NodeId>;
    fn visit_map(&self) -> Self::Map;
}

impl<N, E, Ty, Ix> Graphlike for Graph<N, E, Ty, Ix> where
    Ix: IndexType,
{
    type NodeId = graph::NodeIndex<Ix>;
}

impl<N, E, Ty, Ix> Visitable for Graph<N, E, Ty, Ix> where
    Ty: EdgeType,
    Ix: IndexType,
{
    type Map = BitSet;
    fn visit_map(&self) -> BitSet { BitSet::with_capacity(self.node_count()) }
}

impl<N: Clone, E> Graphlike for GraphMap<N, E>
{
    type NodeId = N;
}

impl<N, E> Visitable for GraphMap<N, E>
    where N: Copy + Clone + Ord + Eq + Hash
{
    type Map = HashSet<N>;
    fn visit_map(&self) -> HashSet<N> { HashSet::with_capacity(self.node_count()) }
}

impl<'a, V: Graphlike> Graphlike for AsUndirected<&'a V>
{
    type NodeId = <V as Graphlike>::NodeId;
}

impl<'a, V: Graphlike> Graphlike for Reversed<&'a V>
{
    type NodeId = <V as Graphlike>::NodeId;
}

impl<'a, V: Visitable> Visitable for AsUndirected<&'a V>
{
    type Map = <V as Visitable>::Map;
    fn visit_map(&self) -> <V as Visitable>::Map {
        self.0.visit_map()
    }
}

impl<'a, V: Visitable> Visitable for Reversed<&'a V>
{
    type Map = <V as Visitable>::Map;
    fn visit_map(&self) -> <V as Visitable>::Map {
        self.0.visit_map()
    }
}

/// Create or access the adjacency matrix of a graph
pub trait GetAdjacencyMatrix : Graphlike {
    type AdjMatrix;
    fn adjacency_matrix(&self) -> Self::AdjMatrix;
    fn is_adjacent(&self, matrix: &Self::AdjMatrix, a: Self::NodeId, b: Self::NodeId) -> bool;
}

/// A depth first search (DFS) of a graph.
///
/// Using a **Dfs** you can run a traversal over a graph while still retaining
/// mutable access to it, if you use it like the following example:
///
/// ```
/// use petgraph::{Graph, Dfs};
///
/// let mut graph = Graph::<_,()>::new();
/// let a = graph.add_node(0);
///
/// let mut dfs = Dfs::new(&graph, a);
/// while let Some(nx) = dfs.next(&graph) {
///     // we can access `graph` mutably here still
///     graph[nx] += 1;
/// }
///
/// assert_eq!(graph[a], 1);
/// ```
///
/// **Note:** The algorithm may not behave correctly if nodes are removed
/// during iteration. It may not necessarily visit added nodes or edges.
#[derive(Clone, Debug)]
pub struct Dfs<N, VM> {
    pub stack: Vec<N>,
    pub discovered: VM,
}

impl<G: Visitable> Dfs<G::NodeId, G::Map>
{
    /// Create a new **Dfs**, using the graph's visitor map, and put **start**
    /// in the stack of nodes to visit.
    pub fn new(graph: &G, start: G::NodeId) -> Self
    {
        let mut dfs = Dfs::empty(graph);
        dfs.move_to(start);
        dfs
    }

    /// Create a new **Dfs** using the graph's visitor map, and no stack.
    pub fn empty(graph: &G) -> Self
    {
        Dfs {
            stack: Vec::new(),
            discovered: graph.visit_map(),
        }
    }
}

impl<N, VM> Dfs<N, VM> where
    N: Clone,
    VM: VisitMap<N>
{
    /// Keep the discovered map, but clear the visit stack and restart
    /// the dfs from a particular node.
    pub fn move_to(&mut self, start: N)
    {
        self.discovered.visit(start.clone());
        self.stack.clear();
        self.stack.push(start);
    }
}

impl<N, VM> Dfs<N, VM> where
    N: Clone,
    VM: VisitMap<N>
{
    /// Return the next node in the dfs, or **None** if the traversal is done.
    pub fn next<'a, G>(&mut self, graph: &'a G) -> Option<N> where
        G: Graphlike<NodeId=N>,
        G: for<'b> NeighborIter<'b>,
    {
        while let Some(node) = self.stack.pop() {
            for succ in graph.neighbors(node.clone()) {
                if self.discovered.visit(succ.clone()) {
                    self.stack.push(succ);
                }
            }

            return Some(node);
        }
        None
    }
}

/// A breadth first search (BFS) of a graph.
///
/// Using a **Bfs** you can run a traversal over a graph while still retaining
/// mutable access to it, if you use it like the following example:
///
/// ```
/// use petgraph::{Graph, Bfs};
///
/// let mut graph = Graph::<_,()>::new();
/// let a = graph.add_node(0);
///
/// let mut bfs = Bfs::new(&graph, a);
/// while let Some(nx) = bfs.next(&graph) {
///     // we can access `graph` mutably here still
///     graph[nx] += 1;
/// }
///
/// assert_eq!(graph[a], 1);
/// ```
///
/// **Note:** The algorithm may not behave correctly if nodes are removed
/// during iteration. It may not necessarily visit added nodes or edges.
#[derive(Clone)]
pub struct Bfs<N, VM> {
    pub stack: VecDeque<N>,
    pub discovered: VM,
}

impl<G: Visitable> Bfs<G::NodeId, <G as Visitable>::Map> where
    G::NodeId: Clone,
{
    /// Create a new **Bfs**, using the graph's visitor map, and put **start**
    /// in the stack of nodes to visit.
    pub fn new(graph: &G, start: G::NodeId) -> Self
    {
        let mut discovered = graph.visit_map();
        discovered.visit(start.clone());
        let mut stack = VecDeque::new();
        stack.push_front(start.clone());
        Bfs {
            stack: stack,
            discovered: discovered,
        }
    }
}

impl<N, VM> Bfs<N, VM> where
    N: Clone,
    VM: VisitMap<N>
{
    /// Return the next node in the dfs, or **None** if the traversal is done.
    pub fn next<'a, G>(&mut self, graph: &'a G) -> Option<N> where
        G: Graphlike<NodeId=N>,
        G: for<'b> NeighborIter<'b>,
    {
        while let Some(node) = self.stack.pop_front() {
            for succ in graph.neighbors(node.clone()) {
                if self.discovered.visit(succ.clone()) {
                    self.stack.push_back(succ);
                }
            }

            return Some(node);
        }
        None
    }

}

/*
pub struct Visitor<G> where
    G: Visitable,
{
    stack: Vec<<G as Graphlike>::NodeId>,
    discovered: <G as Visitable>::Map,
}

pub fn visitor<G>(graph: &G, start: <G as Graphlike>::NodeId) -> Visitor<G> where
    G: Visitable
{
    Visitor{
        stack: vec![start],
        discovered: graph.visit_map(),
    }
}
*/

<commit_msg>impl GetAdjacencyMatrix for GraphMap<commit_after>//! Graph visitor algorithms.
//!

use std::marker;
use std::collections::{
    HashSet,
    BitSet,
    VecDeque,
};
use std::hash::Hash;

use super::{
    graphmap,
    graph,
    EdgeType,
    EdgeDirection,
    Graph,
    GraphMap,
};

use graph::{
    IndexType,
};

pub trait Graphlike : marker::MarkerTrait {
    type NodeId: Clone;
}

/// A graph trait for accessing the neighbors iterator
pub trait NeighborIter<'a> : Graphlike{
    type Iter: Iterator<Item=Self::NodeId>;
    fn neighbors(&'a self, n: Self::NodeId) -> Self::Iter;
}

impl<'a, N, E, Ty, Ix> NeighborIter<'a> for Graph<N, E, Ty, Ix> where
    Ty: EdgeType,
    Ix: IndexType,
{
    type Iter = graph::Neighbors<'a, E, Ix>;
    fn neighbors(&'a self, n: graph::NodeIndex<Ix>) -> graph::Neighbors<'a, E, Ix>
    {
        Graph::neighbors(self, n)
    }
}

impl<'a, N, E> NeighborIter<'a> for GraphMap<N, E>
where N: Copy + Clone + Ord + Hash + Eq
{
    type Iter = graphmap::Neighbors<'a, N>;
    fn neighbors(&'a self, n: N) -> graphmap::Neighbors<'a, N>
    {
        GraphMap::neighbors(self, n)
    }
}

/// Wrapper type for walking the graph as if it is undirected
pub struct AsUndirected<G>(pub G);
/// Wrapper type for walking edges the other way
pub struct Reversed<G>(pub G);

impl<'a, 'b, N, E, Ty, Ix> NeighborIter<'a> for AsUndirected<&'b Graph<N, E, Ty, Ix>> where
    Ty: EdgeType,
    Ix: IndexType,
{
    type Iter = graph::Neighbors<'a, E, Ix>;

    fn neighbors(&'a self, n: graph::NodeIndex<Ix>) -> graph::Neighbors<'a, E, Ix>
    {
        Graph::neighbors_undirected(self.0, n)
    }
}

impl<'a, 'b, N, E, Ty, Ix> NeighborIter<'a> for Reversed<&'b Graph<N, E, Ty, Ix>> where
    Ty: EdgeType,
    Ix: IndexType,
{
    type Iter = graph::Neighbors<'a, E, Ix>;
    fn neighbors(&'a self, n: graph::NodeIndex<Ix>) -> graph::Neighbors<'a, E, Ix>
    {
        Graph::neighbors_directed(self.0, n, EdgeDirection::Incoming)
    }
}

pub trait VisitMap<N> {
    /// Return **true** if the value is not already present.
    fn visit(&mut self, N) -> bool;
    fn is_visited(&self, &N) -> bool;
}

impl<Ix> VisitMap<graph::NodeIndex<Ix>> for BitSet where
    Ix: IndexType,
{
    fn visit(&mut self, x: graph::NodeIndex<Ix>) -> bool {
        self.insert(x.index())
    }
    fn is_visited(&self, x: &graph::NodeIndex<Ix>) -> bool {
        self.contains(&x.index())
    }
}

impl<N: Eq + Hash> VisitMap<N> for HashSet<N> {
    fn visit(&mut self, x: N) -> bool {
        self.insert(x)
    }
    fn is_visited(&self, x: &N) -> bool {
        self.contains(x)
    }
}

/// Trait for GraphMap that knows which datastructure is the best for its visitor map
pub trait Visitable : Graphlike {
    type Map: VisitMap<<Self as Graphlike>::NodeId>;
    fn visit_map(&self) -> Self::Map;
}

impl<N, E, Ty, Ix> Graphlike for Graph<N, E, Ty, Ix> where
    Ix: IndexType,
{
    type NodeId = graph::NodeIndex<Ix>;
}

impl<N, E, Ty, Ix> Visitable for Graph<N, E, Ty, Ix> where
    Ty: EdgeType,
    Ix: IndexType,
{
    type Map = BitSet;
    fn visit_map(&self) -> BitSet { BitSet::with_capacity(self.node_count()) }
}

impl<N: Clone, E> Graphlike for GraphMap<N, E>
{
    type NodeId = N;
}

impl<N, E> Visitable for GraphMap<N, E>
    where N: Copy + Clone + Ord + Eq + Hash
{
    type Map = HashSet<N>;
    fn visit_map(&self) -> HashSet<N> { HashSet::with_capacity(self.node_count()) }
}

impl<'a, V: Graphlike> Graphlike for AsUndirected<&'a V>
{
    type NodeId = <V as Graphlike>::NodeId;
}

impl<'a, V: Graphlike> Graphlike for Reversed<&'a V>
{
    type NodeId = <V as Graphlike>::NodeId;
}

impl<'a, V: Visitable> Visitable for AsUndirected<&'a V>
{
    type Map = <V as Visitable>::Map;
    fn visit_map(&self) -> <V as Visitable>::Map {
        self.0.visit_map()
    }
}

impl<'a, V: Visitable> Visitable for Reversed<&'a V>
{
    type Map = <V as Visitable>::Map;
    fn visit_map(&self) -> <V as Visitable>::Map {
        self.0.visit_map()
    }
}

/// Create or access the adjacency matrix of a graph
pub trait GetAdjacencyMatrix : Graphlike {
    type AdjMatrix;
    fn adjacency_matrix(&self) -> Self::AdjMatrix;
    fn is_adjacent(&self, matrix: &Self::AdjMatrix, a: Self::NodeId, b: Self::NodeId) -> bool;
}

impl<N, E> GetAdjacencyMatrix for GraphMap<N, E>
    where N: Copy + Clone + Ord + Eq + Hash
{
    type AdjMatrix = ();
    #[inline]
    fn adjacency_matrix(&self) { }
    #[inline]
    fn is_adjacent(&self, _: &(), a: N, b: N) -> bool {
        self.contains_edge(a, b)
    }
}

/// A depth first search (DFS) of a graph.
///
/// Using a **Dfs** you can run a traversal over a graph while still retaining
/// mutable access to it, if you use it like the following example:
///
/// ```
/// use petgraph::{Graph, Dfs};
///
/// let mut graph = Graph::<_,()>::new();
/// let a = graph.add_node(0);
///
/// let mut dfs = Dfs::new(&graph, a);
/// while let Some(nx) = dfs.next(&graph) {
///     // we can access `graph` mutably here still
///     graph[nx] += 1;
/// }
///
/// assert_eq!(graph[a], 1);
/// ```
///
/// **Note:** The algorithm may not behave correctly if nodes are removed
/// during iteration. It may not necessarily visit added nodes or edges.
#[derive(Clone, Debug)]
pub struct Dfs<N, VM> {
    pub stack: Vec<N>,
    pub discovered: VM,
}

impl<G: Visitable> Dfs<G::NodeId, G::Map>
{
    /// Create a new **Dfs**, using the graph's visitor map, and put **start**
    /// in the stack of nodes to visit.
    pub fn new(graph: &G, start: G::NodeId) -> Self
    {
        let mut dfs = Dfs::empty(graph);
        dfs.move_to(start);
        dfs
    }

    /// Create a new **Dfs** using the graph's visitor map, and no stack.
    pub fn empty(graph: &G) -> Self
    {
        Dfs {
            stack: Vec::new(),
            discovered: graph.visit_map(),
        }
    }
}

impl<N, VM> Dfs<N, VM> where
    N: Clone,
    VM: VisitMap<N>
{
    /// Keep the discovered map, but clear the visit stack and restart
    /// the dfs from a particular node.
    pub fn move_to(&mut self, start: N)
    {
        self.discovered.visit(start.clone());
        self.stack.clear();
        self.stack.push(start);
    }
}

impl<N, VM> Dfs<N, VM> where
    N: Clone,
    VM: VisitMap<N>
{
    /// Return the next node in the dfs, or **None** if the traversal is done.
    pub fn next<'a, G>(&mut self, graph: &'a G) -> Option<N> where
        G: Graphlike<NodeId=N>,
        G: for<'b> NeighborIter<'b>,
    {
        while let Some(node) = self.stack.pop() {
            for succ in graph.neighbors(node.clone()) {
                if self.discovered.visit(succ.clone()) {
                    self.stack.push(succ);
                }
            }

            return Some(node);
        }
        None
    }
}

/// A breadth first search (BFS) of a graph.
///
/// Using a **Bfs** you can run a traversal over a graph while still retaining
/// mutable access to it, if you use it like the following example:
///
/// ```
/// use petgraph::{Graph, Bfs};
///
/// let mut graph = Graph::<_,()>::new();
/// let a = graph.add_node(0);
///
/// let mut bfs = Bfs::new(&graph, a);
/// while let Some(nx) = bfs.next(&graph) {
///     // we can access `graph` mutably here still
///     graph[nx] += 1;
/// }
///
/// assert_eq!(graph[a], 1);
/// ```
///
/// **Note:** The algorithm may not behave correctly if nodes are removed
/// during iteration. It may not necessarily visit added nodes or edges.
#[derive(Clone)]
pub struct Bfs<N, VM> {
    pub stack: VecDeque<N>,
    pub discovered: VM,
}

impl<G: Visitable> Bfs<G::NodeId, <G as Visitable>::Map> where
    G::NodeId: Clone,
{
    /// Create a new **Bfs**, using the graph's visitor map, and put **start**
    /// in the stack of nodes to visit.
    pub fn new(graph: &G, start: G::NodeId) -> Self
    {
        let mut discovered = graph.visit_map();
        discovered.visit(start.clone());
        let mut stack = VecDeque::new();
        stack.push_front(start.clone());
        Bfs {
            stack: stack,
            discovered: discovered,
        }
    }
}

impl<N, VM> Bfs<N, VM> where
    N: Clone,
    VM: VisitMap<N>
{
    /// Return the next node in the dfs, or **None** if the traversal is done.
    pub fn next<'a, G>(&mut self, graph: &'a G) -> Option<N> where
        G: Graphlike<NodeId=N>,
        G: for<'b> NeighborIter<'b>,
    {
        while let Some(node) = self.stack.pop_front() {
            for succ in graph.neighbors(node.clone()) {
                if self.discovered.visit(succ.clone()) {
                    self.stack.push_back(succ);
                }
            }

            return Some(node);
        }
        None
    }

}

/*
pub struct Visitor<G> where
    G: Visitable,
{
    stack: Vec<<G as Graphlike>::NodeId>,
    discovered: <G as Visitable>::Map,
}

pub fn visitor<G>(graph: &G, start: <G as Graphlike>::NodeId) -> Visitor<G> where
    G: Visitable
{
    Visitor{
        stack: vec![start],
        discovered: graph.visit_map(),
    }
}
*/

<|endoftext|>


<commit_before>use {SChunks};
use std::io::Error;
use std::fs::File;
use std::io::Write;

/// This function takes as parameter a file name and a vector of chaunks.
/// The function will create a file, and append to the buffer each chunk.
pub fn write_file(name_file: &str, chunks: &SChunks) -> Result<(), Error> {

    // Create the file - check if it doesn't exists
    let mut local_file = File::create(name_file).unwrap();

    // Get the access to the chunks
    let chunks_m = chunks.lock().unwrap();

    // For each ones, write it into the file buffer
    for chunk in chunks_m.iter() {
        match local_file.write_all(chunk) {
            Ok(_) => (),
            // Exit if there is an error
            Err(error) => return Err(error),
        }
    }

    // Return a positive result if the remote content has been saved
    Ok(())
}<commit_msg>Change the definition of the function<commit_after>use {SChunks};
use std::io::Error;
use std::fs::File;
use std::io::Write;

/// This function takes as parameter a file name and a vector of chaunks.
/// The function will create a file, and append to the buffer each chunk.
pub fn write_file(local_file: &mut File, chunks: &SChunks) -> Result<(), Error> {

    // Get the access to the chunks
    let chunks_m = chunks.lock().unwrap();

    // For each ones, write it into the file buffer
    for chunk in chunks_m.iter() {
        match local_file.write_all(chunk) {
            Ok(_) => (),
            // Exit if there is an error
            Err(error) => return Err(error),
        }
    }

    // Return a positive result if the remote content has been saved
    Ok(())
}<|endoftext|>


<commit_before>//! A queue-backed exclusive data lock.
//!
//
// * It is unclear how many of the unsafe methods within need actually remain
//   unsafe.

use crossbeam::queue::SegQueue;
use futures::sync::oneshot::{self, Canceled, Receiver, Sender};
use futures::{Future, Poll};
use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::Arc;

/// Allows access to the data contained within a lock just like a mutex guard.
#[derive(Debug)]
pub struct Guard<T> {
    qutex: Qutex<T>,
}

impl<T> Guard<T> {
    /// Releases the lock held by a `Guard` and returns the original `Qutex`.
    pub fn unlock(guard: Guard<T>) -> Qutex<T> {
        let qutex = unsafe { ::std::ptr::read(&guard.qutex) };
        ::std::mem::forget(guard);
        qutex
    }
}

impl<T> Deref for Guard<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.qutex.inner.cell.get() }
    }
}

impl<T> DerefMut for Guard<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.qutex.inner.cell.get() }
    }
}

impl<T> Drop for Guard<T> {
    fn drop(&mut self) {
        // unsafe { self.qutex.direct_unlock().expect("Error dropping Guard") };
        unsafe { self.qutex.direct_unlock() }
    }
}

/// A future which resolves to a `Guard`.
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct FutureGuard<T> {
    qutex: Option<Qutex<T>>,
    rx: Receiver<()>,
}

impl<T> FutureGuard<T> {
    /// Returns a new `FutureGuard`.
    fn new(qutex: Qutex<T>, rx: Receiver<()>) -> FutureGuard<T> {
        FutureGuard {
            qutex: Some(qutex),
            rx: rx,
        }
    }

    /// Blocks the current thread until this future resolves.
    #[inline]
    pub fn wait(self) -> Result<Guard<T>, Canceled> {
        <Self as Future>::wait(self)
    }
}

impl<T> Future for FutureGuard<T> {
    type Item = Guard<T>;
    type Error = Canceled;

    #[inline]
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        if self.qutex.is_some() {
            unsafe { self.qutex.as_ref().unwrap().process_queue() }

            match self.rx.poll() {
                Ok(status) => Ok(status.map(|_| Guard {
                    qutex: self.qutex.take().unwrap(),
                })),
                Err(e) => Err(e.into()),
            }
        } else {
            panic!("FutureGuard::poll: Task already completed.");
        }
    }
}

impl<T> Drop for FutureGuard<T> {
    /// Gracefully unlock if this guard has a lock acquired but has not yet
    /// been polled to completion.
    fn drop(&mut self) {
        if let Some(qutex) = self.qutex.take() {
            self.rx.close();

            match self.rx.try_recv() {
                Ok(status) => {
                    if status.is_some() {
                        unsafe {
                            qutex.direct_unlock();
                        }
                    }
                }
                Err(_) => (),
            }
        }
    }
}

/// A request to lock the qutex for exclusive access.
#[derive(Debug)]
pub struct Request {
    tx: Sender<()>,
}

impl Request {
    /// Returns a new `Request`.
    pub fn new(tx: Sender<()>) -> Request {
        Request { tx: tx }
    }
}

#[derive(Debug)]
struct Inner<T> {
    // TODO: Convert to `AtomicBool` if no additional states are needed:
    state: AtomicUsize,
    cell: UnsafeCell<T>,
    queue: SegQueue<Request>,
}

impl<T> From<T> for Inner<T> {
    #[inline]
    fn from(val: T) -> Inner<T> {
        Inner {
            state: AtomicUsize::new(0),
            cell: UnsafeCell::new(val),
            queue: SegQueue::new(),
        }
    }
}

unsafe impl<T: Send> Send for Inner<T> {}
unsafe impl<T: Send> Sync for Inner<T> {}

/// A lock-free-queue-backed exclusive data lock.
#[derive(Debug)]
pub struct Qutex<T> {
    inner: Arc<Inner<T>>,
}

impl<T> Qutex<T> {
    /// Creates and returns a new `Qutex`.
    #[inline]
    pub fn new(val: T) -> Qutex<T> {
        Qutex {
            inner: Arc::new(Inner::from(val)),
        }
    }

    /// Returns a new `FutureGuard` which can be used as a future and will
    /// resolve into a `Guard`.
    pub fn lock(self) -> FutureGuard<T> {
        let (tx, rx) = oneshot::channel();
        unsafe {
            self.push_request(Request::new(tx));
        }
        FutureGuard::new(self, rx)
    }

    /// Pushes a lock request onto the queue.
    ///
    //
    // TODO: Evaluate unsafe-ness.
    //
    #[inline]
    pub unsafe fn push_request(&self, req: Request) {
        self.inner.queue.push(req);
    }

    /// Returns a mutable reference to the inner `Vec` if there are currently
    /// no other copies of this `Qutex`.
    ///
    /// Since this call borrows the inner lock mutably, no actual locking needs to
    /// take place---the mutable borrow statically guarantees no locks exist.
    ///
    #[inline]
    pub fn get_mut(&mut self) -> Option<&mut T> {
        Arc::get_mut(&mut self.inner).map(|inn| unsafe { &mut *inn.cell.get() })
    }

    /// Returns a reference to the inner value.
    ///
    #[inline]
    pub fn as_ptr(&self) -> *const T {
        self.inner.cell.get()
    }

    /// Returns a mutable reference to the inner value.
    ///
    #[inline]
    pub fn as_mut_ptr(&self) -> *mut T {
        self.inner.cell.get()
    }

    /// Pops the next lock request in the queue if this (the caller's) lock is
    /// unlocked.
    //
    // TODO:
    // * This is currently public due to 'derivers' (aka. sub-types). Evaluate.
    // * Consider removing unsafe qualifier.
    // * Return proper error type.
    //
    pub unsafe fn process_queue(&self) {
        match self.inner.state.compare_and_swap(0, 1, SeqCst) {
            // Unlocked:
            0 => {
                loop {
                    if let Some(req) = self.inner.queue.pop().ok() {
                        // If there is a send error, a requester has dropped
                        // its receiver so just go to the next.
                        if req.tx.send(()).is_err() {
                            continue;
                        } else {
                            break;
                        }
                    } else {
                        self.inner.state.store(0, SeqCst);
                        break;
                    }
                }
            }
            // Already locked, leave it alone:
            1 => (),
            // Something else:
            n => panic!("Qutex::process_queue: inner.state: {}.", n),
        }
    }

    /// Unlocks this (the caller's) lock and wakes up the next task in the
    /// queue.
    //
    // TODO:
    // * Evaluate unsafe-ness.
    // * Return proper error type
    // pub unsafe fn direct_unlock(&self) -> Result<(), ()> {
    pub unsafe fn direct_unlock(&self) {
        // TODO: Consider using `Ordering::Release`.
        self.inner.state.store(0, SeqCst);
        self.process_queue()
    }
}

impl<T> From<T> for Qutex<T> {
    #[inline]
    fn from(val: T) -> Qutex<T> {
        Qutex::new(val)
    }
}

// Avoids needing `T: Clone`.
impl<T> Clone for Qutex<T> {
    #[inline]
    fn clone(&self) -> Qutex<T> {
        Qutex {
            inner: self.inner.clone(),
        }
    }
}

#[cfg(test)]
// Woefully incomplete:
mod tests {
    use super::*;
    use futures::Future;

    #[test]
    fn simple() {
        let val = Qutex::from(999i32);

        println!("Reading val...");
        {
            let future_guard = val.clone().lock();
            let guard = future_guard.wait().unwrap();
            println!("val: {}", *guard);
        }

        println!("Storing new val...");
        {
            let future_guard = val.clone().lock();
            let mut guard = future_guard.wait().unwrap();

            *guard = 5;
        }

        println!("Reading val...");
        {
            let future_guard = val.clone().lock();
            let guard = future_guard.wait().unwrap();
            println!("val: {}", *guard);
        }
    }

    #[test]
    fn concurrent() {
        use std::thread;

        let thread_count = 20;
        let mut threads = Vec::with_capacity(thread_count);
        let start_val = 0i32;
        let qutex = Qutex::new(start_val);

        for i in 0..thread_count {
            let future_guard = qutex.clone().lock();

            let future_write = future_guard.and_then(|mut guard| {
                *guard += 1;
                Ok(())
            });

            threads.push(
                thread::Builder::new()
                    .name(format!("test_thread_{}", i))
                    .spawn(|| future_write.wait().unwrap())
                    .unwrap(),
            );
        }

        for i in 0..thread_count {
            let future_guard = qutex.clone().lock();

            threads.push(
                thread::Builder::new()
                    .name(format!("test_thread_{}", i + thread_count))
                    .spawn(|| {
                        let mut guard = future_guard.wait().unwrap();
                        *guard -= 1;
                    })
                    .unwrap(),
            )
        }

        for thread in threads {
            thread.join().unwrap();
        }

        let guard = qutex.clone().lock().wait().unwrap();
        assert_eq!(*guard, start_val);
    }

    #[test]
    fn future_guard_drop() {
        let lock = Qutex::from(true);
        let _future_guard_0 = lock.clone().lock();
        let _future_guard_1 = lock.clone().lock();
        let _future_guard_2 = lock.clone().lock();

        // TODO: FINISH ME
    }
}
<commit_msg>Properly unlock qutex when explicitly unlocking with guard.<commit_after>//! A queue-backed exclusive data lock.
//!
//
// * It is unclear how many of the unsafe methods within need actually remain
//   unsafe.

use crossbeam::queue::SegQueue;
use futures::sync::oneshot::{self, Canceled, Receiver, Sender};
use futures::{Future, Poll};
use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::Arc;

/// Allows access to the data contained within a lock just like a mutex guard.
#[derive(Debug)]
pub struct Guard<T> {
    qutex: Qutex<T>,
}

impl<T> Guard<T> {
    /// Releases the lock held by a `Guard` and returns the original `Qutex`.
    pub fn unlock(guard: Guard<T>) -> Qutex<T> {
        let qutex = unsafe { ::std::ptr::read(&guard.qutex) };
        ::std::mem::forget(guard);
        unsafe { qutex.direct_unlock() }
        qutex
    }
}

impl<T> Deref for Guard<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.qutex.inner.cell.get() }
    }
}

impl<T> DerefMut for Guard<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.qutex.inner.cell.get() }
    }
}

impl<T> Drop for Guard<T> {
    fn drop(&mut self) {
        // unsafe { self.qutex.direct_unlock().expect("Error dropping Guard") };
        unsafe { self.qutex.direct_unlock() }
    }
}

/// A future which resolves to a `Guard`.
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct FutureGuard<T> {
    qutex: Option<Qutex<T>>,
    rx: Receiver<()>,
}

impl<T> FutureGuard<T> {
    /// Returns a new `FutureGuard`.
    fn new(qutex: Qutex<T>, rx: Receiver<()>) -> FutureGuard<T> {
        FutureGuard {
            qutex: Some(qutex),
            rx: rx,
        }
    }

    /// Blocks the current thread until this future resolves.
    #[inline]
    pub fn wait(self) -> Result<Guard<T>, Canceled> {
        <Self as Future>::wait(self)
    }
}

impl<T> Future for FutureGuard<T> {
    type Item = Guard<T>;
    type Error = Canceled;

    #[inline]
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        if self.qutex.is_some() {
            unsafe { self.qutex.as_ref().unwrap().process_queue() }

            match self.rx.poll() {
                Ok(status) => Ok(status.map(|_| Guard {
                    qutex: self.qutex.take().unwrap(),
                })),
                Err(e) => Err(e.into()),
            }
        } else {
            panic!("FutureGuard::poll: Task already completed.");
        }
    }
}

impl<T> Drop for FutureGuard<T> {
    /// Gracefully unlock if this guard has a lock acquired but has not yet
    /// been polled to completion.
    fn drop(&mut self) {
        if let Some(qutex) = self.qutex.take() {
            self.rx.close();

            match self.rx.try_recv() {
                Ok(status) => {
                    if status.is_some() {
                        unsafe {
                            qutex.direct_unlock();
                        }
                    }
                }
                Err(_) => (),
            }
        }
    }
}

/// A request to lock the qutex for exclusive access.
#[derive(Debug)]
pub struct Request {
    tx: Sender<()>,
}

impl Request {
    /// Returns a new `Request`.
    pub fn new(tx: Sender<()>) -> Request {
        Request { tx: tx }
    }
}

#[derive(Debug)]
struct Inner<T> {
    // TODO: Convert to `AtomicBool` if no additional states are needed:
    state: AtomicUsize,
    cell: UnsafeCell<T>,
    queue: SegQueue<Request>,
}

impl<T> From<T> for Inner<T> {
    #[inline]
    fn from(val: T) -> Inner<T> {
        Inner {
            state: AtomicUsize::new(0),
            cell: UnsafeCell::new(val),
            queue: SegQueue::new(),
        }
    }
}

unsafe impl<T: Send> Send for Inner<T> {}
unsafe impl<T: Send> Sync for Inner<T> {}

/// A lock-free-queue-backed exclusive data lock.
#[derive(Debug)]
pub struct Qutex<T> {
    inner: Arc<Inner<T>>,
}

impl<T> Qutex<T> {
    /// Creates and returns a new `Qutex`.
    #[inline]
    pub fn new(val: T) -> Qutex<T> {
        Qutex {
            inner: Arc::new(Inner::from(val)),
        }
    }

    /// Returns a new `FutureGuard` which can be used as a future and will
    /// resolve into a `Guard`.
    pub fn lock(self) -> FutureGuard<T> {
        let (tx, rx) = oneshot::channel();
        unsafe {
            self.push_request(Request::new(tx));
        }
        FutureGuard::new(self, rx)
    }

    /// Pushes a lock request onto the queue.
    ///
    //
    // TODO: Evaluate unsafe-ness.
    //
    #[inline]
    pub unsafe fn push_request(&self, req: Request) {
        self.inner.queue.push(req);
    }

    /// Returns a mutable reference to the inner `Vec` if there are currently
    /// no other copies of this `Qutex`.
    ///
    /// Since this call borrows the inner lock mutably, no actual locking needs to
    /// take place---the mutable borrow statically guarantees no locks exist.
    ///
    #[inline]
    pub fn get_mut(&mut self) -> Option<&mut T> {
        Arc::get_mut(&mut self.inner).map(|inn| unsafe { &mut *inn.cell.get() })
    }

    /// Returns a reference to the inner value.
    ///
    #[inline]
    pub fn as_ptr(&self) -> *const T {
        self.inner.cell.get()
    }

    /// Returns a mutable reference to the inner value.
    ///
    #[inline]
    pub fn as_mut_ptr(&self) -> *mut T {
        self.inner.cell.get()
    }

    /// Pops the next lock request in the queue if this (the caller's) lock is
    /// unlocked.
    //
    // TODO:
    // * This is currently public due to 'derivers' (aka. sub-types). Evaluate.
    // * Consider removing unsafe qualifier.
    // * Return proper error type.
    //
    pub unsafe fn process_queue(&self) {
        match self.inner.state.compare_and_swap(0, 1, SeqCst) {
            // Unlocked:
            0 => {
                loop {
                    if let Some(req) = self.inner.queue.pop().ok() {
                        // If there is a send error, a requester has dropped
                        // its receiver so just go to the next.
                        if req.tx.send(()).is_err() {
                            continue;
                        } else {
                            break;
                        }
                    } else {
                        self.inner.state.store(0, SeqCst);
                        break;
                    }
                }
            }
            // Already locked, leave it alone:
            1 => (),
            // Something else:
            n => panic!("Qutex::process_queue: inner.state: {}.", n),
        }
    }

    /// Unlocks this (the caller's) lock and wakes up the next task in the
    /// queue.
    //
    // TODO:
    // * Evaluate unsafe-ness.
    // * Return proper error type
    // pub unsafe fn direct_unlock(&self) -> Result<(), ()> {
    pub unsafe fn direct_unlock(&self) {
        // TODO: Consider using `Ordering::Release`.
        self.inner.state.store(0, SeqCst);
        self.process_queue()
    }
}

impl<T> From<T> for Qutex<T> {
    #[inline]
    fn from(val: T) -> Qutex<T> {
        Qutex::new(val)
    }
}

// Avoids needing `T: Clone`.
impl<T> Clone for Qutex<T> {
    #[inline]
    fn clone(&self) -> Qutex<T> {
        Qutex {
            inner: self.inner.clone(),
        }
    }
}

#[cfg(test)]
// Woefully incomplete:
mod tests {
    use super::*;
    use futures::Future;

    #[test]
    fn simple() {
        let val = Qutex::from(999i32);

        println!("Reading val...");
        {
            let future_guard = val.clone().lock();
            let guard = future_guard.wait().unwrap();
            println!("val: {}", *guard);
        }

        println!("Storing new val...");
        {
            let future_guard = val.clone().lock();
            let mut guard = future_guard.wait().unwrap();

            *guard = 5;
        }

        println!("Reading val...");
        {
            let future_guard = val.clone().lock();
            let guard = future_guard.wait().unwrap();
            println!("val: {}", *guard);
        }
    }

    #[test]
    fn concurrent() {
        use std::thread;

        let thread_count = 20;
        let mut threads = Vec::with_capacity(thread_count);
        let start_val = 0i32;
        let qutex = Qutex::new(start_val);

        for i in 0..thread_count {
            let future_guard = qutex.clone().lock();

            let future_write = future_guard.and_then(|mut guard| {
                *guard += 1;
                Ok(())
            });

            threads.push(
                thread::Builder::new()
                    .name(format!("test_thread_{}", i))
                    .spawn(|| future_write.wait().unwrap())
                    .unwrap(),
            );
        }

        for i in 0..thread_count {
            let future_guard = qutex.clone().lock();

            threads.push(
                thread::Builder::new()
                    .name(format!("test_thread_{}", i + thread_count))
                    .spawn(|| {
                        let mut guard = future_guard.wait().unwrap();
                        *guard -= 1;
                    })
                    .unwrap(),
            )
        }

        for thread in threads {
            thread.join().unwrap();
        }

        let guard = qutex.clone().lock().wait().unwrap();
        assert_eq!(*guard, start_val);
    }

    #[test]
    fn future_guard_drop() {
        let lock = Qutex::from(true);
        let _future_guard_0 = lock.clone().lock();
        let _future_guard_1 = lock.clone().lock();
        let _future_guard_2 = lock.clone().lock();

        // TODO: FINISH ME
    }

    #[test]
    fn explicit_unlock() {
        let lock = Qutex::from(true);

        let mut guard_0 = lock.clone().lock().wait().unwrap();
        *guard_0 = false;
        let _ = Guard::unlock(guard_0);
        // Will deadlock if this doesn't work:
        let guard_1 = lock.clone().lock().wait().unwrap();
        assert!(*guard_1 == false);
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::cmp::{max, min};

use enums::Direction;
use structs::Point;
use traits::{HasValues, HasWalls};
use travel::travel;

/// Find the points within the provided manhattan distance
///
/// # Example
///
/// ```
/// use std::collections::HashSet;
///
/// use hex_math::{Point,range};
///
/// let point: Point = Point::new(1, 2, 5);
/// let set: HashSet<Point> = range(&point, 1);
///
/// assert!(set.contains(&Point::new(1, 2, 5)));
/// assert!(set.contains(&Point::new(2, 2, 5)));
/// assert!(set.contains(&Point::new(1, 3, 5)));
/// assert!(set.contains(&Point::new(0, 3, 5)));
/// assert!(set.contains(&Point::new(0, 2, 5)));
/// assert!(set.contains(&Point::new(1, 1, 5)));
/// assert!(set.contains(&Point::new(2, 1, 5)));
/// assert!(set.contains(&Point::new(1, 2, 4)));
/// assert!(set.contains(&Point::new(1, 2, 6)));
/// assert_eq!(set.len(), 9);
/// ```
pub fn range<T: HasValues>(point: &T, range: i32) -> HashSet<Point> {
  let mut set: HashSet<Point> = range_2d(point, range);

  for index in 1..range + 1 {
    let diff = range - index;
    let up: Point = travel(point, &Direction::Up, index);
    let down: Point = travel(point, &Direction::Down, index);
    let up_range: HashSet<Point> = range_2d(&up, diff);
    let down_range: HashSet<Point> = range_2d(&down, diff);

    set.extend(up_range);
    set.extend(down_range);
  }

  set
}

/// Find the points at the same height within the provided manhattan distance
///
/// # Example
///
/// ```
/// use std::collections::HashSet;
///
/// use hex_math::{Point, range_2d};
///
/// let point: Point = Point::new(1, 2, 5);
/// let set: HashSet<Point> = range_2d(&point, 1);
///
/// assert!(set.contains(&Point::new(1, 2, 5)));
/// assert!(set.contains(&Point::new(2, 2, 5)));
/// assert!(set.contains(&Point::new(1, 3, 5)));
/// assert!(set.contains(&Point::new(0, 3, 5)));
/// assert!(set.contains(&Point::new(0, 2, 5)));
/// assert!(set.contains(&Point::new(1, 1, 5)));
/// assert!(set.contains(&Point::new(2, 1, 5)));
/// assert_eq!(set.len(), 7);
/// ```
pub fn range_2d<T: HasValues>(point: &T, range: i32) -> HashSet<Point> {
  let mut set: HashSet<Point> = HashSet::new();
  let point: Point = Point::from(point.values());

  for dq in -range..range + 1 {
    let lower: i32 = max(-range, -dq - range);
    let upper: i32 = min(range, -dq + range);

    for ds in lower..upper + 1 {
      let dr: i32 = -dq - ds;
      let found = &point + &Point::new(dq, dr, 0);

      set.insert(found);
    }

  }

  set
}

/// Find reachable points within a specified range
///
/// A point may be within range while being unreachable if the path to that
/// point is blocked by an invalid point.
///
/// # Example
///
/// ```
/// use std::collections::{HashMap, HashSet};
///
/// use hex_math::{
///   flood,
///   Point,
///   Prism,
///   HasValues,
///   travel,
///   IsPointMap,
///   Direction
/// };
///
/// let mut map: HashMap<Point, Prism> = HashMap::new();
///
/// let start: Point = Point::new(1, 2, 2);
///
/// map.insert_walled_point(Prism::new(start.values().into(), 1, 1, 1, 1));
///
/// let west: Point = travel(&start, &Direction::West, 1);
/// map.insert_walled_point(Prism::new(west, 0, 1, 0, 0));
///
/// let northwest: Point = travel(&start, &Direction::Northwest, 1);
/// map.insert_walled_point(Prism::new(northwest, 0, 1, 1, 0));
///
/// let northeast: Point = travel(&start, &Direction::Northeast, 1);
/// map.insert_walled_point(Prism::new(northeast, 0, 0, 1, 0));
///
/// let up: Point = travel(&start, &Direction::Up, 1);
/// map.insert_walled_point(Prism::new(up, 0, 0, 0, 1));
///
/// let result: HashSet<Point> = flood(&start, 2, &map);
///
/// assert!(result.contains(&start));
/// assert!(result.contains(&Point::new( 0, 2, 2)));
/// assert!(result.contains(&Point::new( 0, 1, 2)));
/// assert!(result.contains(&Point::new(-1, 2, 2)));
/// assert!(result.contains(&Point::new(-1, 3, 2)));
/// assert!(result.contains(&Point::new( 0, 2, 1)));
/// assert!(result.contains(&Point::new( 0, 2, 3)));
/// assert_eq!(result.len(), 7);
/// ```
pub fn flood<T: HasValues, U: HasWalls>(
  point: &T,
  range: i32,
  map: &HashMap<Point, U>,
) -> HashSet<Point> {
  util::flood(point, range, self::range, map)
}

/// Find reachable points of the same height within a specified range
///
/// A point may be within range while being unreachable if the path to that
/// point is blocked by an invalid point.
///
/// # Example
///
/// ```
/// use std::collections::{HashMap, HashSet};
///
/// use hex_math::{
///   flood_2d,
///   Point,
///   Prism,
///   HasValues,
///   travel,
///   IsPointMap,
///   Direction
/// };
///
/// let mut map: HashMap<Point, Prism> = HashMap::new();
///
/// let start: Point = Point::new_2d(1, 2);
///
/// map.insert_walled_point(Prism::new(start.values().into(), 1, 1, 1, 0));
///
/// let west: Point = travel(&start, &Direction::West, 1);
/// map.insert_walled_point(Prism::new(west, 0, 1, 0, 0));
///
/// let northwest: Point = travel(&start, &Direction::Northwest, 1);
/// map.insert_walled_point(Prism::new(northwest, 0, 1, 1, 0));
///
/// let northeast: Point = travel(&start, &Direction::Northeast, 1);
/// map.insert_walled_point(Prism::new(northeast, 0, 0, 1, 0));
///
/// let result: HashSet<Point> = flood_2d(&start, 2, &map);
///
/// assert!(result.contains(&start));
/// assert!(result.contains(&Point::new_2d(0, 2)));
/// assert!(result.contains(&Point::new_2d(0, 1)));
/// assert!(result.contains(&Point::new_2d(-1, 2)));
/// assert!(result.contains(&Point::new_2d(-1, 3)));
/// assert_eq!(result.len(), 5);
/// ```
pub fn flood_2d<T: HasValues, U: HasWalls>(
  point: &T,
  range: i32,
  map: &HashMap<Point, U>,
) -> HashSet<Point> {
  util::flood(point, range, self::range_2d, map)
}

mod util {
  use std::collections::{HashMap, HashSet};

  use traits::{HasValues, HasWalls, IsPointMap};
  use structs::Point;

  /// Find reachable points within a specified range with a provided function
  pub fn flood<T: HasValues, U: HasWalls>(
    start: &T,
    range: i32,
    range_fn: fn(&Point, i32) -> HashSet<Point>,
    map: &HashMap<Point, U>,
  ) -> HashSet<Point> {

    let mut visited: HashSet<Point> = HashSet::new();
    let mut fringes: Vec<Point> = Vec::new();

    let start: Point = Point::from(start.values());

    fringes.push(start);

    for _ in 0 .. range {

      let mut found = vec![];

      for point in &fringes {
        for neighbor in range_fn(point, 1) {

          if visited.contains(&neighbor) {
            continue;
          }

          if !map.has_wall_between(&point, &neighbor) {
            found.push(neighbor);
          }

        }
      }

      visited.extend(fringes);
      fringes = found;

    }

    visited.extend(fringes);

    visited

  }

}

#[cfg(test)]
mod tests {
  use enums::Direction;
  use structs::{Point, Prism};
  use traits::HasValues;
  use travel::travel;

  use super::util;

  use std::collections::{HashMap, HashSet};

  #[test]
  fn flood() {

    let start: Point = Point::new(0, 0, 0);
    let wall: Point = Point::new(0, 0, 2);

    let mut map: HashMap<Point, Prism> = HashMap::new();

    map.insert(wall.values().into(), Prism::new(wall, 0, 0, 0, 1));

    fn range_1d(point: &Point, range: i32) -> HashSet<Point> {

      let mut set: HashSet<Point> = HashSet::new();
      let up: Point = travel(point, &Direction::Up, range);
      let down: Point = travel(point, &Direction::Down, range);

      set.insert(up);
      set.insert(down);

      set

    };

    let result: HashSet<Point> = util::flood(&start, 2, range_1d, &map);

    assert!(result.contains(&start));
    assert!(result.contains(&Point::new(0, 0, 1)));
    assert!(result.contains(&Point::new(0, 0, -1)));
    assert!(result.contains(&Point::new(0, 0, -2)));
    assert_eq!(result.len(), 4);

  }

}
<commit_msg>Issue #33: Refactor range<commit_after>use std::collections::{HashMap, HashSet};
use std::cmp::{max, min};

use enums::Direction;
use structs::Point;
use traits::{HasValues, HasWalls};
use travel::travel;

/// Find the points within the provided manhattan distance
pub fn range<T: HasValues>(point: &T, range: i32) -> HashSet<Point> {
  let mut set: HashSet<Point> = range_2d(point, range);

  for index in 1..range + 1 {
    let diff = range - index;
    let up: Point = travel(point, &Direction::Up, index);
    let down: Point = travel(point, &Direction::Down, index);
    let up_range: HashSet<Point> = range_2d(&up, diff);
    let down_range: HashSet<Point> = range_2d(&down, diff);

    set.extend(up_range);
    set.extend(down_range);
  }

  set
}

/// Find the points at the same height within the provided manhattan distance
pub fn range_2d<T: HasValues>(point: &T, range: i32) -> HashSet<Point> {
  let mut set: HashSet<Point> = HashSet::new();
  let point: Point = Point::from(point.values());

  for dq in -range..range + 1 {
    let lower: i32 = max(-range, -dq - range);
    let upper: i32 = min(range, -dq + range);

    for ds in lower..upper + 1 {
      let dr: i32 = -dq - ds;
      let found = &point + &Point::new(dq, dr, 0);

      set.insert(found);
    }

  }

  set
}

/// Find reachable points within a specified range
///
/// A point may be within range while being unreachable if the path to that
/// point is blocked by an invalid point.
pub fn flood<T: HasValues, U: HasWalls>(
  point: &T,
  range: i32,
  map: &HashMap<Point, U>,
) -> HashSet<Point> {
  util::flood(point, range, self::range, map)
}

/// Find reachable points of the same height within a specified range
///
/// A point may be within range while being unreachable if the path to that
/// point is blocked by an invalid point.
pub fn flood_2d<T: HasValues, U: HasWalls>(
  point: &T,
  range: i32,
  map: &HashMap<Point, U>,
) -> HashSet<Point> {
  util::flood(point, range, self::range_2d, map)
}

mod util {
  use std::collections::{HashMap, HashSet};

  use traits::{HasValues, HasWalls, IsPointMap};
  use structs::Point;

  /// Find reachable points within a specified range with a provided function
  pub fn flood<T: HasValues, U: HasWalls>(
    start: &T,
    range: i32,
    range_fn: fn(&Point, i32) -> HashSet<Point>,
    map: &HashMap<Point, U>,
  ) -> HashSet<Point> {

    let mut visited: HashSet<Point> = HashSet::new();
    let mut fringes: Vec<Point> = Vec::new();

    let start: Point = Point::from(start.values());

    fringes.push(start);

    for _ in 0 .. range {

      let mut found = vec![];

      for point in &fringes {
        for neighbor in range_fn(point, 1) {

          if visited.contains(&neighbor) {
            continue;
          }

          if !map.has_wall_between(&point, &neighbor) {
            found.push(neighbor);
          }

        }
      }

      visited.extend(fringes);
      fringes = found;

    }

    visited.extend(fringes);

    visited

  }

}

#[cfg(test)]
mod tests {
  use super::*;
  use structs::Prism;
  use traits::IsPointMap;

  #[test]
  fn range() {
    let point: Point = Point::new(1, 2, 5);
    let set: HashSet<Point> = super::range(&point, 1);

    assert!(set.contains(&Point::new(1, 2, 5)));
    assert!(set.contains(&Point::new(2, 2, 5)));
    assert!(set.contains(&Point::new(1, 3, 5)));
    assert!(set.contains(&Point::new(0, 3, 5)));
    assert!(set.contains(&Point::new(0, 2, 5)));
    assert!(set.contains(&Point::new(1, 1, 5)));
    assert!(set.contains(&Point::new(2, 1, 5)));
    assert!(set.contains(&Point::new(1, 2, 4)));
    assert!(set.contains(&Point::new(1, 2, 6)));
    assert!(set.len() == 9);
  }

  #[test]
  fn range_2d() {
    let point: Point = Point::new(1, 2, 5);
    let set: HashSet<Point> = super::range_2d(&point, 1);

    assert!(set.contains(&Point::new(1, 2, 5)));
    assert!(set.contains(&Point::new(2, 2, 5)));
    assert!(set.contains(&Point::new(1, 3, 5)));
    assert!(set.contains(&Point::new(0, 3, 5)));
    assert!(set.contains(&Point::new(0, 2, 5)));
    assert!(set.contains(&Point::new(1, 1, 5)));
    assert!(set.contains(&Point::new(2, 1, 5)));
    assert!(set.len() == 7);
  }

  #[test]
  fn flood() {
    let mut map: HashMap<Point, Prism> = HashMap::new();

    let start: Point = Point::new(1, 2, 2);

    map.insert_walled_point(Prism::new(start.values().into(), 1, 1, 1, 1));

    let west: Point = travel(&start, &Direction::West, 1);
    map.insert_walled_point(Prism::new(west, 0, 1, 0, 0));

    let northwest: Point = travel(&start, &Direction::Northwest, 1);
    map.insert_walled_point(Prism::new(northwest, 0, 1, 1, 0));

    let northeast: Point = travel(&start, &Direction::Northeast, 1);
    map.insert_walled_point(Prism::new(northeast, 0, 0, 1, 0));

    let up: Point = travel(&start, &Direction::Up, 1);
    map.insert_walled_point(Prism::new(up, 0, 0, 0, 1));

    let result: HashSet<Point> = super::flood(&start, 2, &map);

    assert!(result.contains(&start));
    assert!(result.contains(&Point::new( 0, 2, 2)));
    assert!(result.contains(&Point::new( 0, 1, 2)));
    assert!(result.contains(&Point::new(-1, 2, 2)));
    assert!(result.contains(&Point::new(-1, 3, 2)));
    assert!(result.contains(&Point::new( 0, 2, 1)));
    assert!(result.contains(&Point::new( 0, 2, 3)));
    assert!(result.len() == 7);
  }

  #[test]
  fn flood_2d() {
    let mut map: HashMap<Point, Prism> = HashMap::new();

    let start: Point = Point::new_2d(1, 2);

    map.insert_walled_point(Prism::new(start.values().into(), 1, 1, 1, 0));

    let west: Point = travel(&start, &Direction::West, 1);
    map.insert_walled_point(Prism::new(west, 0, 1, 0, 0));

    let northwest: Point = travel(&start, &Direction::Northwest, 1);
    map.insert_walled_point(Prism::new(northwest, 0, 1, 1, 0));

    let northeast: Point = travel(&start, &Direction::Northeast, 1);
    map.insert_walled_point(Prism::new(northeast, 0, 0, 1, 0));

    let result: HashSet<Point> = super::flood_2d(&start, 2, &map);

    assert!(result.contains(&start));
    assert!(result.contains(&Point::new_2d(0, 2)));
    assert!(result.contains(&Point::new_2d(0, 1)));
    assert!(result.contains(&Point::new_2d(-1, 2)));
    assert!(result.contains(&Point::new_2d(-1, 3)));
    assert!(result.len() == 5);
  }

  #[test]
  fn flood_util() {

    let start: Point = Point::new(0, 0, 0);
    let wall: Point = Point::new(0, 0, 2);

    let mut map: HashMap<Point, Prism> = HashMap::new();

    map.insert(wall.values().into(), Prism::new(wall, 0, 0, 0, 1));

    fn range_1d(point: &Point, range: i32) -> HashSet<Point> {

      let mut set: HashSet<Point> = HashSet::new();
      let up: Point = travel(point, &Direction::Up, range);
      let down: Point = travel(point, &Direction::Down, range);

      set.insert(up);
      set.insert(down);

      set

    };

    let result: HashSet<Point> = util::flood(&start, 2, range_1d, &map);

    assert!(result.contains(&start));
    assert!(result.contains(&Point::new(0, 0, 1)));
    assert!(result.contains(&Point::new(0, 0, -1)));
    assert!(result.contains(&Point::new(0, 0, -2)));
    assert!(result.len() == 4);
  }
}
<|endoftext|>


<commit_before>use byteorder::{ByteOrder, LittleEndian};

use std;

use gameboy;
use gameboy::{Interconnect, Interrupt, Irq, Memory};
use gameboy::gfx::{Color, Frame, GpuMode, GpuStat, SpriteShape, TileRenderOptions, TileRenderType};
use gameboy::ui::theme::Theme;

pub struct Gpu {
    pub enabled: bool,
    pub ram: Memory,
    pub sprite_data: Memory,

    pub ly: u8,
    pub lyc: u8,

    pub frame: Frame,
    pub backbuffer: Frame,
    pub mode: GpuMode,

    control_register: u8,
    stat: GpuStat,
    scroll_y: u8,
    scroll_x: u8,
    window_y: u8,
    window_x: u8,
    bg_palette: u8,
    palette0: u8,
    palette1: u8,

    cycles: usize,

    counter: u8,
    tile_data_addr: usize,
    background_tilemap_addr: usize,
    window_tilemap_addr: usize,
    sprite_shape: SpriteShape,
    sprites_enabled: bool,
    background_enabled: bool,
    window_enabled: bool,

    pub theme: Theme,
}

impl Gpu {
    pub fn new() -> Gpu {
        Gpu {
            enabled: true,
            ram: Memory::new(gameboy::gfx::VRAM_SIZE),
            sprite_data: Memory::new(gameboy::gfx::SPRITE_DATA_SIZE),
            control_register: 0x00,
            stat: GpuStat::new(),
            scroll_y: 0x00,
            scroll_x: 0x00,
            window_y: 0x00,
            window_x: 0x00,
            ly: 0x00,
            lyc: 0x00,
            bg_palette: 0x00,
            palette0: 0x00,
            palette1: 0x00,
            cycles: 0x00,
            frame: Frame::new(),
            backbuffer: Frame::new(),
            mode: GpuMode::HBlank,
            counter: 0,
            tile_data_addr: 0x00,
            background_tilemap_addr: 0xC00,
            window_tilemap_addr: 0x00,
            sprite_shape: SpriteShape::Square,
            sprites_enabled: true,
            background_enabled: true,
            window_enabled: true,

            theme: Theme::Default,
        }
    }

    pub fn reset(&mut self) {
        *self = Gpu::new();
    }

    /*fn set_status(&mut self, irq: &mut Irq) {
        if !self.enabled {
            self.cycles = 0x1C8;
            self.ly = 0x00;
            self.stat = GpuStat::from(0xFD);
        }

        let current_mode = self.mode.clone();

        if self.ly >= 0x90 {
            self.mode = GpuMode::VBlank;
        } else {
            if self.cycles >= 0x178 {
                self.mode = GpuMode::SearchingRam;
            } else if self.cycles >= 0xCC {
                self.mode = GpuMode::TransferringData;
            } else {
                self.mode = GpuMode::HBlank;
            }
        }

        if self.mode != current_mode {
            irq.request(Interrupt::Lcd);
        }

        self.check_coincidence(irq);
    }*/

    pub fn step(&mut self, irq: &mut Irq, cycles: usize) -> Result<(), String> {
        /*self.set_status(irq);

        let cycles = cycles as isize;
        if self.enabled {
            self.cycles -= cycles;
        } else {
            return Ok(());
        }

        if self.cycles <= 0 {
            self.ly += 0x01;

            self.cycles = 0x1C8;

            if self.ly == 0x90 {
                irq.request(Interrupt::Vblank);
            } else if self.ly > 0x99 {
                self.ly = 0x00;
            } else if self.ly < 0x90 {
                self.render_scanline();
            }
        }*/

        let current_mode = self.mode.clone();

        self.cycles += cycles;

        match self.mode {
            GpuMode::OAM => {
                    if self.cycles >= 0x50 {
                        self.cycles = 0x00;
                        self.mode = GpuMode::VRAM;
                    }
            },
            GpuMode::VRAM => {
                if self.cycles >= 0xAC {
                    self.cycles = 0x00;
                    self.mode = GpuMode::HBlank;
                    if self.enabled {
                        self.render_scanline();
                    }
                }
            },
            GpuMode::HBlank => {
                if self.cycles >= 0xCC {
                    self.cycles = 0x00;
                    self.ly += 0x01;

                    if self.ly == 0x8F {
                        self.mode = GpuMode::VBlank;
                        self.frame = self.backbuffer.clone();
                        irq.request(Interrupt::Vblank);
                    } else {
                        self.mode = GpuMode::OAM;
                    }
                }
            },
            GpuMode::VBlank => {
                if self.cycles >= 0x1C8 {
                    self.cycles = 0x00;
                    self.ly += 0x01;

                    if self.ly > 0x99 {
                        self.mode = GpuMode::OAM;
                        self.ly = 0x00;
                    }
                }
            }
        }

        self.check_coincidence(irq);

        Ok(())
    }

    fn render_scanline(&mut self) {
        self.render_background();
        self.render_window();
        self.render_sprites();
    }

    fn render_background(&mut self) {
        requires!(self.background_enabled);

        let options = TileRenderOptions::new(
            TileRenderType::Background,
            self.ly,
            self.background_tilemap_addr,
            self.tile_data_addr,
        );
        self.render_tile(&options);
    }

    fn render_window(&mut self) {
        requires!(self.window_enabled);
        requires!(self.ly as usize >= self.window_y as usize);

        let options = TileRenderOptions::new(
            TileRenderType::Window,
            self.ly,
            self.window_tilemap_addr,
            self.tile_data_addr,
        );
        self.render_tile(&options);
    }

    fn render_tile(&mut self, options: &TileRenderOptions) {
        let window = variant_equals!(TileRenderType::Window, options.render_type);
        let y = if window {
            options.line as usize
        } else {
            options.line.wrapping_add(self.scroll_y) as usize
        };

        // If rendering a window tile, we need to make sure we offset tile line properly
        let window_offset = if window { self.window_y as usize } else { 0x00 };
        let map_row = ((y - window_offset) / 0x08) as usize;
        let start = if window {
            // Gameboy manual: "With WX = 7, the window is displayed from the left edge of the LCD screen."
            // If we don't do this, the window begins rendering slightly to the right
            self.window_x.wrapping_sub(0x07) as usize
        } else {
            0
        };

        for i in start..gameboy::SCREEN_WIDTH {
            // If we're at the window, lets negate the window X position from where we
            // need to be in the tile map
            let x = if window {
                i as u8 - self.window_x
            } else {
                // Otherwise, scroll the background
                (i as u8).wrapping_add(self.scroll_x)
            };
            let map_col = (x / 0x08) as usize;
            let raw_tile_number = self.ram[options.map_addr + (map_row * 0x20 + map_col)] as usize;

            let line_offset = (y % 0x08) << 0x01;

            let tile_data_start = options.tile_base_addr + (if options.tile_base_addr == 0x00 {
                raw_tile_number
            } else {
                (raw_tile_number as i8 as i16 + 0x80) as usize
            }) * 0x10 + line_offset;

            let x_shift = (x % 8).wrapping_sub(0x07).wrapping_mul(0xFF);
            let color_value = Self::build_palette_index(&self.ram[tile_data_start..], x_shift);
            let c = self.get_background_color_for_byte(color_value as u8);
            self.backbuffer.pixels[self.ly as usize * gameboy::SCREEN_WIDTH + i as usize] = c;
        }
    }

    fn render_sprites(&mut self) {
        requires!(self.sprites_enabled);

        for i in 0..40 {
            let sprite_table_entry_base = i * 0x04;
            let s_y = self.sprite_data[sprite_table_entry_base] as i16 - 0x10;
            let s_x = self.sprite_data[sprite_table_entry_base + 0x01] as i16 - 0x08;
            let sprite_height = if let SpriteShape::Rectangle = self.sprite_shape {
                0x10
            } else {
                0x08
            };

            if s_y <= self.ly as i16 && (s_y + sprite_height as i16) > self.ly as i16 {
                let tile_number = self.sprite_data[sprite_table_entry_base + 0x02] as i16;
                let attributes = self.sprite_data[sprite_table_entry_base + 0x03];
                let above_background = attributes & 0x80 == 0x00;
                let flip_y = attributes & 0x40 == 0x40;
                let flip_x = attributes & 0x20 == 0x20;

                let sprite_line = (self.ly as i16 - s_y) << 0x01;
                let tile_data_start = (tile_number * 0x10) + sprite_line;
                for x in 0..8 {
                    if s_x + x < 0 || s_x + x >= gameboy::SCREEN_WIDTH as i16 {
                        continue;
                    }
                    let shift = if flip_x { x } else { 0x07 - x };
                    let color_value = Self::build_palette_index(
                        &self.ram[tile_data_start as usize..],
                        shift as u8,
                    );
                    if color_value == 0x00 {
                        continue;
                    }
                    let c = self.get_sprite_color_for_byte(
                        color_value as u8,
                        ((attributes & 0x10) >> 0x04) as u8,
                    );
                    let idx =
                        self.ly as usize * gameboy::SCREEN_WIDTH + (s_x as usize + x as usize);
                    if idx > self.backbuffer.pixels.len() - 1 {
                        panic!(format!(
                            "Just tried to place a pixel outside framebuffer size. \
                             Index was {} and backbuffer length is {}. line: {:b}, \
                             gameboy::SCREEN_WIDTH: {:b}, s_x: {:b}, x: {:b}",
                            idx,
                            self.backbuffer.pixels.len(),
                            self.ly,
                            gameboy::SCREEN_WIDTH,
                            s_x,
                            x
                        ));
                    } else {
                        self.backbuffer.pixels[idx] = c;
                    }
                }
            }
        }
    }

    fn get_background_color_for_byte(&self, b: u8) -> Color {
        let palette_index = match b {
            0x00 => self.bg_palette & 0x0003,
            0x01 => (self.bg_palette & 0x000C) >> 0x02,
            0x02 => (self.bg_palette & 0x0030) >> 0x04,
            0x03 => (self.bg_palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from(palette_index as u8, &self.theme)
    }

    fn get_sprite_color_for_byte(&self, b: u8, palette_entry: u8) -> Color {
        let palette = if palette_entry == 0x00 {
            self.palette0
        } else {
            self.palette1
        };

        let palette_index = match b {
            0x00 => palette & 0x0003,
            0x01 => (palette & 0x000C) >> 0x02,
            0x02 => (palette & 0x0030) >> 0x04,
            0x03 => (palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from(palette_index as u8, &self.theme)
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        match addr {
            0x40 => self.control_register,
            0x41 => self.stat.to_u8(self),
            0x42 => self.scroll_y,
            0x43 => self.scroll_x,
            0x4A => self.window_y,
            0x4B => self.window_x,
            0x44 => self.ly,
            0x45 => self.lyc,
            0x47 => self.bg_palette,
            0x48 => self.palette0,
            0x49 => self.palette1,
            _ => panic!("tried to read GPU memory that is not mapped"),
        }
    }

    pub fn write_u8(&mut self, addr: u16, val: u8) {
        match addr {
            0x40 => {
                self.control_register = val;
                self.enabled = self.control_register & 0x80 == 0x80;
                self.tile_data_addr = if self.control_register & 0x10 == 0x10 {
                    0x00
                } else {
                    0x800
                };
                self.window_tilemap_addr = if self.control_register & 0x40 == 0x40 {
                    0x1C00
                } else {
                    0x1800
                };
                self.background_tilemap_addr = if self.control_register & 0x08 == 0x08 {
                    0x1C00
                } else {
                    0x1800
                };
                self.sprite_shape = if self.control_register & 0x04 == 0x04 {
                    SpriteShape::Rectangle
                } else {
                    SpriteShape::Square
                };
                self.window_enabled = self.control_register & 0x20 == 0x20;
                self.sprites_enabled = self.control_register & 0x02 == 0x02;
                self.background_enabled = self.control_register & 0x01 == 0x01;
            }
            0x41 => self.stat = GpuStat::from(val),
            0x42 => self.scroll_y = val,
            0x43 => self.scroll_x = val,
            0x44 => (),
            0x45 => {
                self.lyc = val;
            }
            0x47 => self.bg_palette = val,
            0x48 => self.palette0 = val,
            0x49 => self.palette1 = val,
            0x4A => self.window_y = val,
            0x4B => self.window_x = val,
            _ => panic!("tried to write GPU memory that is not mapped: {:04}", addr),
        }
    }

    pub fn write_u16(&mut self, addr: u16, val: u16) {
        let addr = addr as usize;
        LittleEndian::write_u16(&mut self.ram[addr..], val)
    }

    fn check_coincidence(&mut self, irq: &mut Irq) {
        // If LY == LYC then set the coincidence flag
        if self.lyc == self.ly && self.stat.coincidence_interrupt_enabled {
            irq.request(Interrupt::Lcd);
        }
    }

    fn build_palette_index(data: &[u8], x_shift: u8) -> u8 {
        let tile_data1 = (data[0x00] >> x_shift) & 0x01;
        let tile_data2 = (data[0x01] >> x_shift) & 0x01;
        let pixel_palette_entry = (tile_data2 << 1) | tile_data1;
        pixel_palette_entry
    }
}
<commit_msg>GPU cleanups<commit_after>use byteorder::{ByteOrder, LittleEndian};

use std;

use gameboy;
use gameboy::{Interconnect, Interrupt, Irq, Memory};
use gameboy::gfx::{Color, Frame, GpuMode, GpuStat, SpriteShape, TileRenderOptions, TileRenderType};
use gameboy::ui::theme::Theme;

pub struct Gpu {
    pub enabled: bool,
    pub ram: Memory,
    pub sprite_data: Memory,

    pub ly: u8,
    pub lyc: u8,

    pub frame: Frame,
    pub backbuffer: Frame,
    pub mode: GpuMode,

    control_register: u8,
    stat: GpuStat,
    scroll_y: u8,
    scroll_x: u8,
    window_y: u8,
    window_x: u8,
    bg_palette: u8,
    palette0: u8,
    palette1: u8,

    cycles: usize,

    counter: u8,
    tile_data_addr: usize,
    background_tilemap_addr: usize,
    window_tilemap_addr: usize,
    sprite_shape: SpriteShape,
    sprites_enabled: bool,
    background_enabled: bool,
    window_enabled: bool,

    pub theme: Theme,
}

impl Gpu {
    pub fn new() -> Gpu {
        Gpu {
            enabled: true,
            ram: Memory::new(gameboy::gfx::VRAM_SIZE),
            sprite_data: Memory::new(gameboy::gfx::SPRITE_DATA_SIZE),
            control_register: 0x00,
            stat: GpuStat::new(),
            scroll_y: 0x00,
            scroll_x: 0x00,
            window_y: 0x00,
            window_x: 0x00,
            ly: 0x00,
            lyc: 0x00,
            bg_palette: 0x00,
            palette0: 0x00,
            palette1: 0x00,
            cycles: 0x00,
            frame: Frame::new(),
            backbuffer: Frame::new(),
            mode: GpuMode::HBlank,
            counter: 0,
            tile_data_addr: 0x00,
            background_tilemap_addr: 0xC00,
            window_tilemap_addr: 0x00,
            sprite_shape: SpriteShape::Square,
            sprites_enabled: true,
            background_enabled: true,
            window_enabled: true,

            theme: Theme::Default,
        }
    }

    pub fn reset(&mut self) {
        *self = Gpu::new();
    }

    pub fn step(&mut self, irq: &mut Irq, cycles: usize) -> Result<(), String> {
        if !self.enabled {
            return Ok(());
        }

        self.cycles += cycles;

        match self.mode {
            GpuMode::OAM => {
                    if self.cycles >= 0x50 {
                        self.cycles = 0x00;
                        self.mode = GpuMode::VRAM;
                    }
            },
            GpuMode::VRAM => {
                if self.cycles >= 0xAC {
                    self.cycles = 0x00;
                    self.mode = GpuMode::HBlank;
                    if self.enabled {
                        self.render_scanline();
                    }
                }
            },
            GpuMode::HBlank => {
                if self.cycles >= 0xCC {
                    self.cycles = 0x00;
                    self.ly += 0x01;

                    if self.ly == 0x8F {
                        self.mode = GpuMode::VBlank;
                        self.frame = self.backbuffer.clone();
                        irq.request(Interrupt::Vblank);
                    } else {
                        self.mode = GpuMode::OAM;
                    }
                }
            },
            GpuMode::VBlank => {
                if self.cycles >= 0x1C8 {
                    self.cycles = 0x00;
                    self.ly += 0x01;

                    if self.ly > 0x99 {
                        self.mode = GpuMode::OAM;
                        self.ly = 0x00;
                    }
                }
            }
        }

        self.check_coincidence(irq);

        Ok(())
    }

    fn render_scanline(&mut self) {
        self.render_background();
        self.render_window();
        self.render_sprites();
    }

    fn render_background(&mut self) {
        requires!(self.background_enabled);

        let options = TileRenderOptions::new(
            TileRenderType::Background,
            self.ly,
            self.background_tilemap_addr,
            self.tile_data_addr,
        );
        self.render_tile(&options);
    }

    fn render_window(&mut self) {
        requires!(self.window_enabled);
        requires!(self.ly as usize >= self.window_y as usize);

        let options = TileRenderOptions::new(
            TileRenderType::Window,
            self.ly,
            self.window_tilemap_addr,
            self.tile_data_addr,
        );
        self.render_tile(&options);
    }

    fn render_tile(&mut self, options: &TileRenderOptions) {
        let window = variant_equals!(TileRenderType::Window, options.render_type);
        let y = if window {
            options.line as usize
        } else {
            options.line.wrapping_add(self.scroll_y) as usize
        };

        // If rendering a window tile, we need to make sure we offset tile line properly
        let window_offset = if window { self.window_y as usize } else { 0x00 };
        let map_row = ((y - window_offset) / 0x08) as usize;
        let start = if window {
            // Gameboy manual: "With WX = 7, the window is displayed from the left edge of the LCD screen."
            // If we don't do this, the window begins rendering slightly to the right
            self.window_x.wrapping_sub(0x07) as usize
        } else {
            0
        };

        for i in start..gameboy::SCREEN_WIDTH {
            // If we're at the window, lets negate the window X position from where we
            // need to be in the tile map
            let x = if window {
                i as u8 - self.window_x
            } else {
                // Otherwise, scroll the background
                (i as u8).wrapping_add(self.scroll_x)
            };
            let map_col = (x / 0x08) as usize;
            let raw_tile_number = self.ram[options.map_addr + (map_row * 0x20 + map_col)] as usize;

            let line_offset = (y % 0x08) << 0x01;

            let tile_data_start = options.tile_base_addr + (if options.tile_base_addr == 0x00 {
                raw_tile_number
            } else {
                (raw_tile_number as i8 as i16 + 0x80) as usize
            }) * 0x10 + line_offset;

            let x_shift = (x % 8).wrapping_sub(0x07).wrapping_mul(0xFF);
            let color_value = Self::build_palette_index(&self.ram[tile_data_start..], x_shift);
            let c = self.get_background_color_for_byte(color_value as u8);
            self.backbuffer.pixels[self.ly as usize * gameboy::SCREEN_WIDTH + i as usize] = c;
        }
    }

    fn render_sprites(&mut self) {
        requires!(self.sprites_enabled);

        for i in 0..40 {
            let sprite_table_entry_base = i * 0x04;
            let s_y = self.sprite_data[sprite_table_entry_base] as i16 - 0x10;
            let s_x = self.sprite_data[sprite_table_entry_base + 0x01] as i16 - 0x08;
            let sprite_height = if let SpriteShape::Rectangle = self.sprite_shape {
                0x10
            } else {
                0x08
            };

            if s_y <= self.ly as i16 && (s_y + sprite_height as i16) > self.ly as i16 {
                let tile_number = self.sprite_data[sprite_table_entry_base + 0x02] as i16;
                let attributes = self.sprite_data[sprite_table_entry_base + 0x03];
                let above_background = attributes & 0x80 == 0x00;
                let flip_y = attributes & 0x40 == 0x40;
                let flip_x = attributes & 0x20 == 0x20;

                let sprite_line = (self.ly as i16 - s_y) << 0x01;
                let tile_data_start = (tile_number * 0x10) + sprite_line;
                for x in 0..8 {
                    if s_x + x < 0 || s_x + x >= gameboy::SCREEN_WIDTH as i16 {
                        continue;
                    }
                    let shift = if flip_x { x } else { 0x07 - x };
                    let color_value = Self::build_palette_index(
                        &self.ram[tile_data_start as usize..],
                        shift as u8,
                    );
                    if color_value == 0x00 {
                        continue;
                    }
                    let c = self.get_sprite_color_for_byte(
                        color_value as u8,
                        ((attributes & 0x10) >> 0x04) as u8,
                    );
                    let idx =
                        self.ly as usize * gameboy::SCREEN_WIDTH + (s_x as usize + x as usize);
                    if idx > self.backbuffer.pixels.len() - 1 {
                        panic!(format!(
                            "Just tried to place a pixel outside framebuffer size. \
                             Index was {} and backbuffer length is {}. line: {:b}, \
                             gameboy::SCREEN_WIDTH: {:b}, s_x: {:b}, x: {:b}",
                            idx,
                            self.backbuffer.pixels.len(),
                            self.ly,
                            gameboy::SCREEN_WIDTH,
                            s_x,
                            x
                        ));
                    } else {
                        self.backbuffer.pixels[idx] = c;
                    }
                }
            }
        }
    }

    fn get_background_color_for_byte(&self, b: u8) -> Color {
        let palette_index = match b {
            0x00 => self.bg_palette & 0x0003,
            0x01 => (self.bg_palette & 0x000C) >> 0x02,
            0x02 => (self.bg_palette & 0x0030) >> 0x04,
            0x03 => (self.bg_palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from(palette_index as u8, &self.theme)
    }

    fn get_sprite_color_for_byte(&self, b: u8, palette_entry: u8) -> Color {
        let palette = if palette_entry == 0x00 {
            self.palette0
        } else {
            self.palette1
        };

        let palette_index = match b {
            0x00 => palette & 0x0003,
            0x01 => (palette & 0x000C) >> 0x02,
            0x02 => (palette & 0x0030) >> 0x04,
            0x03 => (palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from(palette_index as u8, &self.theme)
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        match addr {
            0x40 => self.control_register,
            0x41 => self.stat.to_u8(self),
            0x42 => self.scroll_y,
            0x43 => self.scroll_x,
            0x4A => self.window_y,
            0x4B => self.window_x,
            0x44 => self.ly,
            0x45 => self.lyc,
            0x47 => self.bg_palette,
            0x48 => self.palette0,
            0x49 => self.palette1,
            _ => panic!("tried to read GPU memory that is not mapped"),
        }
    }

    pub fn write_u8(&mut self, addr: u16, val: u8) {
        match addr {
            0x40 => {
                let was_enabled = self.enabled;
                self.control_register = val;
                self.enabled = self.control_register & 0x80 == 0x80;
                self.tile_data_addr = if self.control_register & 0x10 == 0x10 {
                    0x00
                } else {
                    0x800
                };
                self.window_tilemap_addr = if self.control_register & 0x40 == 0x40 {
                    0x1C00
                } else {
                    0x1800
                };
                self.background_tilemap_addr = if self.control_register & 0x08 == 0x08 {
                    0x1C00
                } else {
                    0x1800
                };
                self.sprite_shape = if self.control_register & 0x04 == 0x04 {
                    SpriteShape::Rectangle
                } else {
                    SpriteShape::Square
                };
                self.window_enabled = self.control_register & 0x20 == 0x20;
                self.sprites_enabled = self.control_register & 0x02 == 0x02;
                self.background_enabled = self.control_register & 0x01 == 0x01;

                if was_enabled && !self.enabled {
                    self.cycles = 0x00;
                    self.ly = 0x00;
                    self.mode = GpuMode::HBlank;
                    self.frame = Frame::new();
                }
            }
            0x41 => self.stat = GpuStat::from(val),
            0x42 => self.scroll_y = val,
            0x43 => self.scroll_x = val,
            0x44 => (),
            0x45 => {
                self.lyc = val;
            }
            0x47 => self.bg_palette = val,
            0x48 => self.palette0 = val,
            0x49 => self.palette1 = val,
            0x4A => self.window_y = val,
            0x4B => self.window_x = val,
            _ => panic!("tried to write GPU memory that is not mapped: {:04}", addr),
        }
    }

    pub fn write_u16(&mut self, addr: u16, val: u16) {
        let addr = addr as usize;
        LittleEndian::write_u16(&mut self.ram[addr..], val)
    }

    fn check_coincidence(&mut self, irq: &mut Irq) {
        // If LY == LYC then set the coincidence flag
        if self.lyc == self.ly && self.stat.coincidence_interrupt_enabled {
            irq.request(Interrupt::Lcd);
        }
    }

    fn build_palette_index(data: &[u8], x_shift: u8) -> u8 {
        let tile_data1 = (data[0x00] >> x_shift) & 0x01;
        let tile_data2 = (data[0x01] >> x_shift) & 0x01;
        let pixel_palette_entry = (tile_data2 << 1) | tile_data1;
        pixel_palette_entry
    }
}
<|endoftext|>


<commit_before>use crate::cli::Command;
use mprovision as mp;
use std::env;
use std::io::{self, Write};
use std::path::Path;
use std::path::PathBuf;
use std::time::{Duration, SystemTime};

mod cli;

fn main() {
    if let Err(e) = cli::parse(env::args()).and_then(run) {
        e.exit();
    }
}

fn run(command: cli::Command) -> Result<(), cli::Error> {
    match command {
        Command::List(cli::ListParams {
            text,
            expire_in_days,
            directory,
        }) => list(&text, expire_in_days, directory),
        Command::ShowUuid(cli::ShowUuidParams { uuid, directory }) => show_uuid(&uuid, directory),
        Command::ShowFile(cli::ShowFileParams { file }) => show_file(&file),
        Command::Remove(cli::RemoveParams { ids, directory }) => remove(&ids, directory),
        Command::Clean(cli::CleanParams { directory }) => clean(directory),
    }
}

fn list(
    text: &Option<String>,
    expires_in_days: Option<u64>,
    directory: Option<PathBuf>,
) -> Result<(), cli::Error> {
    let dir = mp::with_directory(directory)?;
    let entries = mp::entries(&dir).map(|entries| entries.collect::<Vec<_>>())?;
    let date =
        expires_in_days.map(|days| SystemTime::now() + Duration::from_secs(days * 24 * 60 * 60));
    let filter_string = text.as_ref();
    let mut profiles = mp::filter(entries, |profile| match (date, filter_string) {
        (Some(date), Some(string)) => {
            profile.info.expiration_date <= date && profile.info.contains(string)
        }
        (Some(date), _) => profile.info.expiration_date <= date,
        (_, Some(string)) => profile.info.contains(string),
        (_, _) => true,
    });
    profiles.sort_by(|a, b| a.info.creation_date.cmp(&b.info.creation_date));
    if profiles.is_empty() {
        Ok(())
    } else {
        let stdout = io::stdout();
        let mut stdout = stdout.lock();
        for profile in &profiles {
            writeln!(&mut stdout, "{}\n", profile.info.description())?;
        }
        Ok(())
    }
}

fn show_uuid(uuid: &str, directory: Option<PathBuf>) -> Result<(), cli::Error> {
    let dir = mp::with_directory(directory)?;
    let profile = mp::find_by_uuid(&dir, &uuid)?;
    let xml = mp::show(&profile.path)?;
    writeln!(io::stdout(), "{}", xml)?;
    Ok(())
}

fn show_file(path: &Path) -> Result<(), cli::Error> {
    let xml = mp::show(&path)?;
    writeln!(io::stdout(), "{}", xml)?;
    Ok(())
}

fn remove(ids: &[String], directory: Option<PathBuf>) -> Result<(), cli::Error> {
    let dir = mp::with_directory(directory)?;
    let profiles = mp::find_by_ids(&dir, &ids)?;
    for profile in profiles {
        if mp::remove(&profile.path).is_ok() {
            println!("\nRemoved: {}", profile.info.description());
        } else {
            println!("\nError while removing '{}'", profile.info.uuid);
        }
    }
    Ok(())
}

fn clean(directory: Option<PathBuf>) -> Result<(), cli::Error> {
    let date = SystemTime::now();
    let dir = mp::with_directory(directory)?;
    let entries = mp::entries(&dir).map(|entries| entries.collect::<Vec<_>>())?;
    let profiles = mp::filter(entries, |profile| profile.info.expiration_date <= date);
    if profiles.is_empty() {
        println!("All provisioning profiles are valid");
    } else {
        for profile in profiles {
            if mp::remove(&profile.path).is_ok() {
                println!("\nRemoved: {}", profile.info.description());
            } else {
                println!("\nError while removing '{}'", profile.info.uuid);
            }
        }
    }
    Ok(())
}
<commit_msg>Introduce Result type alias in main.rs<commit_after>use crate::cli::Command;
use mprovision as mp;
use std::env;
use std::io::{self, Write};
use std::path::Path;
use std::path::PathBuf;
use std::time::{Duration, SystemTime};

mod cli;

type Result = std::result::Result<(), cli::Error>;

fn main() {
    if let Err(e) = cli::parse(env::args()).and_then(run) {
        e.exit();
    }
}

fn run(command: cli::Command) -> Result {
    match command {
        Command::List(cli::ListParams {
            text,
            expire_in_days,
            directory,
        }) => list(&text, expire_in_days, directory),
        Command::ShowUuid(cli::ShowUuidParams { uuid, directory }) => show_uuid(&uuid, directory),
        Command::ShowFile(cli::ShowFileParams { file }) => show_file(&file),
        Command::Remove(cli::RemoveParams { ids, directory }) => remove(&ids, directory),
        Command::Clean(cli::CleanParams { directory }) => clean(directory),
    }
}

fn list(text: &Option<String>, expires_in_days: Option<u64>, directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let entries = mp::entries(&dir).map(|entries| entries.collect::<Vec<_>>())?;
    let date =
        expires_in_days.map(|days| SystemTime::now() + Duration::from_secs(days * 24 * 60 * 60));
    let filter_string = text.as_ref();
    let mut profiles = mp::filter(entries, |profile| match (date, filter_string) {
        (Some(date), Some(string)) => {
            profile.info.expiration_date <= date && profile.info.contains(string)
        }
        (Some(date), _) => profile.info.expiration_date <= date,
        (_, Some(string)) => profile.info.contains(string),
        (_, _) => true,
    });
    profiles.sort_by(|a, b| a.info.creation_date.cmp(&b.info.creation_date));
    if profiles.is_empty() {
        Ok(())
    } else {
        let stdout = io::stdout();
        let mut stdout = stdout.lock();
        for profile in &profiles {
            writeln!(&mut stdout, "{}\n", profile.info.description())?;
        }
        Ok(())
    }
}

fn show_uuid(uuid: &str, directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let profile = mp::find_by_uuid(&dir, &uuid)?;
    let xml = mp::show(&profile.path)?;
    writeln!(io::stdout(), "{}", xml)?;
    Ok(())
}

fn show_file(path: &Path) -> Result {
    let xml = mp::show(&path)?;
    writeln!(io::stdout(), "{}", xml)?;
    Ok(())
}

fn remove(ids: &[String], directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let profiles = mp::find_by_ids(&dir, &ids)?;
    for profile in profiles {
        if mp::remove(&profile.path).is_ok() {
            println!("\nRemoved: {}", profile.info.description());
        } else {
            println!("\nError while removing '{}'", profile.info.uuid);
        }
    }
    Ok(())
}

fn clean(directory: Option<PathBuf>) -> Result {
    let date = SystemTime::now();
    let dir = mp::with_directory(directory)?;
    let entries = mp::entries(&dir).map(|entries| entries.collect::<Vec<_>>())?;
    let profiles = mp::filter(entries, |profile| profile.info.expiration_date <= date);
    if profiles.is_empty() {
        println!("All provisioning profiles are valid");
    } else {
        for profile in profiles {
            if mp::remove(&profile.path).is_ok() {
                println!("\nRemoved: {}", profile.info.description());
            } else {
                println!("\nError while removing '{}'", profile.info.uuid);
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>#![feature(rustc_private, custom_attribute)]
#![allow(unused_attributes)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate env_logger;
extern crate log_settings;
extern crate log;

use miri::interpreter;
use rustc::session::Session;
use rustc_driver::{driver, CompilerCalls};

struct MiriCompilerCalls;

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn build_controller(
        &mut self,
        _: &Session,
        _: &getopts::Matches
    ) -> driver::CompileController<'a> {
        let mut control = driver::CompileController::basic();

        control.after_analysis.callback = Box::new(|state| {
            state.session.abort_if_errors();
            interpreter::interpret_start_points(state.tcx.unwrap(), state.mir_map.unwrap());
        });

        control
    }
}

#[miri_run]
fn main() {
    init_logger();
    let args: Vec<String> = std::env::args().collect();
    rustc_driver::run_compiler(&args, &mut MiriCompilerCalls);
}

#[miri_run]
fn init_logger() {
    let format = |record: &log::LogRecord| {
        // prepend spaces to indent the final string
        let indentation = log_settings::settings().indentation;
        let spaces = "                                        ";
        let depth = indentation / spaces.len();
        let indentation = indentation % spaces.len();
        let indentation = &spaces[..indentation];
        format!("{}:{}{:2}{} {}", record.level(), record.location().module_path(), depth, indentation, record.args())
    };

    let mut builder = env_logger::LogBuilder::new();
    builder.format(format).filter(None, log::LogLevelFilter::Info);

    if std::env::var("MIRI_LOG").is_ok() {
        builder.parse(&std::env::var("MIRI_LOG").unwrap());
    }

    builder.init().unwrap();
}
<commit_msg>use format! compile time magics for indentation<commit_after>#![feature(rustc_private, custom_attribute)]
#![allow(unused_attributes)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate env_logger;
extern crate log_settings;
extern crate log;

use miri::interpreter;
use rustc::session::Session;
use rustc_driver::{driver, CompilerCalls};

struct MiriCompilerCalls;

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn build_controller(
        &mut self,
        _: &Session,
        _: &getopts::Matches
    ) -> driver::CompileController<'a> {
        let mut control = driver::CompileController::basic();

        control.after_analysis.callback = Box::new(|state| {
            state.session.abort_if_errors();
            interpreter::interpret_start_points(state.tcx.unwrap(), state.mir_map.unwrap());
        });

        control
    }
}

#[miri_run]
fn main() {
    init_logger();
    let args: Vec<String> = std::env::args().collect();
    rustc_driver::run_compiler(&args, &mut MiriCompilerCalls);
}

#[miri_run]
fn init_logger() {
    const NSPACES: usize = 40;
    let format = |record: &log::LogRecord| {
        // prepend spaces to indent the final string
        let indentation = log_settings::settings().indentation;
        let depth = indentation / NSPACES;
        let indentation = indentation % NSPACES;
        format!("{lvl}:{module}{depth:2}{indent:<indentation$}{text}",
            lvl = record.level(),
            module = record.location().module_path(),
            depth = depth,
            indentation = indentation,
            indent = "",
            text = record.args())
    };

    let mut builder = env_logger::LogBuilder::new();
    builder.format(format).filter(None, log::LogLevelFilter::Info);

    if std::env::var("MIRI_LOG").is_ok() {
        builder.parse(&std::env::var("MIRI_LOG").unwrap());
    }

    builder.init().unwrap();
}
<|endoftext|>