<commit_before>pub(crate) mod base;
pub mod mutators;
pub mod nav;
pub mod search;

use std::cell::UnsafeCell;
use std::hash::Hash;
use std::ops::Deref;

use base::{EdgeId, RawEdge, RawVertex, VertexId};
use mutators::{MutEdge, MutNode};
use nav::{Edge, Node};
use symbol_map::indexing::{Indexing, Insertion};
use symbol_map::SymbolId;

/// A search graph.
///
/// Supports incremental rollout of game state topology and vertex
/// de-duplication with transposition tables. Limited support is provided for
/// deletion of components and compaction in memory after deletion.
///
/// - `T`: The type of game states. It is required to derive `Hash` and `Eq` to
///   so that it may be stored in a hashtable, where game states are looked up to
///   support de-duplication of game states. It is required to derive `Clone` to
///   accommodate a limitation of the `HashMap` interface.
/// - `S`: The type of graph vertex data.
/// - `A`: The type of graph edge data.
///
/// Vertices are addressed by content. To examine graph contents, obtain a node
/// handle with `get_node`. To modify graph contents, add new root vertices with
/// `add_node` and retrieve extant vertices with `get_node_mut`.
pub struct Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  /// Lookup table that maps from game states to `VertexId`.
  state_ids: symbol_map::indexing::HashIndexing<T, VertexId>,
  vertices: Vec<RawVertex<S>>, // Indexed by VertexId.
  arcs: Vec<RawEdge<A>>,       // Indexed by EdgeId.
}

impl<T, S, A> Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  /// Creates an empty `Graph` with no vertices or edges.
  pub fn new() -> Self {
    Graph {
      state_ids: Default::default(),
      vertices: Vec::new(),
      arcs: Vec::new(),
    }
  }

  /// Returns the vertex for the given `VertexId`.
  fn get_vertex(&self, state: VertexId) -> &RawVertex<S> {
    &self.vertices[state.as_usize()]
  }

  /// Returns the vertex for the given `VertexId`.
  fn get_vertex_mut(&mut self, state: VertexId) -> &mut RawVertex<S> {
    &mut self.vertices[state.as_usize()]
  }

  /// Returns the edge for the given `EdgeId`.
  fn get_arc(&self, arc: EdgeId) -> &RawEdge<A> {
    &self.arcs[arc.as_usize()]
  }

  /// Returns the edge for the given `EdgeId`.
  fn get_arc_mut(&mut self, arc: EdgeId) -> &mut RawEdge<A> {
    &mut self.arcs[arc.as_usize()]
  }

  /// Returns the game state associated with `id`.
  fn get_state(&self, id: VertexId) -> Option<&T> {
    self.state_ids.get_symbol(&id).as_ref().map(|x| x.data())
  }

  /// Adds a new vertex with the given data, returning a mutable reference to it.
  ///
  /// This method does not add incoming or outgoing edges (expanded or
  /// not). That must be done by calling `add_arc` with the new vertex
  /// `VertexId`.
  fn add_raw_vertex(&mut self, data: S) -> &mut RawVertex<S> {
    self.vertices.push(RawVertex {
      data: data,
      parents: Vec::new(),
      children: Vec::new(),
    });
    self.vertices.last_mut().unwrap()
  }

  /// Adds a new edge with the given data, source, and target. Returns the
  /// internal ID for the new edge.
  fn add_raw_edge(&mut self, data: A, source: VertexId, target: VertexId) -> EdgeId {
    let arc_id = EdgeId(self.arcs.len());
    self.get_vertex_mut(source).children.push(arc_id);
    self.get_vertex_mut(target).parents.push(arc_id);
    self.arcs.push(RawEdge {
      data: data,
      source: source,
      target: target,
    });
    arc_id
  }

  /// Gets a node handle for the given game state.
  ///
  /// If `state` does not correspond to a known game state, returns `None`.
  pub fn get_node<'s>(&'s self, state: &T) -> Option<Node<'s, T, S, A>> {
    match self.state_ids.get(state) {
      Some(symbol) => Some(Node::new(self, *symbol.id())),
      None => None,
    }
  }

  /// Gets a mutable node handle for the given game state.
  ///
  /// If `state` does not correspond to a known game state, returns `None`.
  pub fn get_node_mut<'s>(&'s mut self, state: &T) -> Option<MutNode<'s, T, S, A>> {
    match self.state_ids.get(state).map(|s| s.id().clone()) {
      Some(id) => Some(MutNode::new(self, id)),
      None => None,
    }
  }

  /// Adds a vertex (with no parents or children) for the given game state and
  /// data and returns a mutable handle for it.
  ///
  /// If `state` is already known, returns a mutable handle to that state,
  /// ignoring the `data` parameter. As a result, this method is guaranteed to
  /// return a handle for a root vertex only when `state` is a novel game
  /// state.
  pub fn add_node<'s>(&'s mut self, state: T, data: S) -> MutNode<'s, T, S, A> {
    let node_id = match self.state_ids.get_or_insert(state).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        self.add_raw_vertex(data);
        id
      }
    };
    MutNode::new(self, node_id)
  }

  /// Adds an edge from the vertex with state data `source` to the vertex with
  /// state data `dest`. If vertices are not found for `source` or `dest`,
  /// they are added, with the data provided by `source_data` and `dest_data`
  /// callbacks.
  ///
  /// The edge that is created will have the data `edge_data`. Returns a
  /// mutable edge handle for that edge.
  pub fn add_edge<'s, F, G>(
    &'s mut self,
    source: T,
    source_data: F,
    dest: T,
    dest_data: G,
    edge_data: A,
  ) -> MutEdge<'s, T, S, A>
  where
    F: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
    G: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
  {
    let source_id = match self.state_ids.get_or_insert(source).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        let data = source_data(Node::new(self, id));
        self.add_raw_vertex(data);
        id
      }
    };
    let dest_id = match self.state_ids.get_or_insert(dest).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        let data = dest_data(Node::new(self, id));
        self.add_raw_vertex(data);
        id
      }
    };
    let edge_id = self.add_raw_edge(edge_data, source_id, dest_id);
    MutEdge::new(self, edge_id)
  }

  /// Returns the number of vertices in the graph.
  pub fn vertex_count(&self) -> usize {
    // TODO: This is actually the number of vertices we have allocated.
    self.vertices.len()
  }

  /// Returns the number of edges in the graph.
  pub fn edge_count(&self) -> usize {
    // TODO: This is actually the number of edges we have allocated.
    self.arcs.len()
  }

  /// Deletes all graph components that are not reachable by traversal
  /// starting from each vertex corresponding to the game states in `roots`.
  ///
  /// Game states in `roots` which do not have a corresponding vertex are
  /// ignored.
  pub fn retain_reachable_from(&mut self, roots: &[&T]) {
    let mut root_ids = Vec::with_capacity(roots.len());
    for state in roots.iter() {
      if let Some(symbol) = self.state_ids.get(state) {
        root_ids.push(*symbol.id());
      }
    }
    self.retain_reachable_from_ids(&root_ids);
  }

  /// As `retain_reachable_from`, but working over raw `VertexId`s instead of
  /// root data.
  fn retain_reachable_from_ids(&mut self, root_ids: &[VertexId]) {
    mutators::mark_compact::Collector::retain_reachable(self, root_ids);
  }
}

/// Allows both read-only references into a `Graph` and operations that modify
/// the graph but do not invalidate family of types defined in the `nav`
/// module.
///
/// All methods on `Graph` that take a `&self` parameter may also be called on
/// an `AppendOnlyGraph`. The `add_node` and `add_edge` methods may also be
/// called, because they do not invalidate `Node`, `Edge`, or other such smart
/// pointers into the underlying graph. Unlike the analogous methods on `Graph`,
/// these methods return a read-only view of the graph topology, instead of
/// granting read-write access.
///
/// For example:
///
/// ```rust
/// # use search_graph::{AppendOnlyGraph, Graph};
/// # use search_graph::nav::{Node, Edge};
/// # fn main() {
/// let appendable: AppendOnlyGraph<u32, String, ()> = Graph::new().into();
/// let root1 = appendable.add_node(0, "data1".to_string());
/// // If appendable were a Graph, we could not call add_node while root1 is alive.
/// let root2 = appendable.add_node(1, "data2".to_string());
/// assert_eq!("data1", appendable.get_node(&0).unwrap().get_data());
/// # }
/// ```
pub struct AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  graph: UnsafeCell<Graph<T, S, A>>,
}

impl<T, S, A> AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  pub fn add_node<'s>(&'s self, state: T, data: S) -> Node<'s, T, S, A> {
    unsafe { (*self.graph.get()).add_node(state, data).to_node() }
  }

  pub fn add_edge<'s, F, G>(
    &'s mut self,
    source: T,
    source_data: F,
    dest: T,
    dest_data: G,
    edge_data: A,
  ) -> Edge<'s, T, S, A>
  where
    F: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
    G: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
  {
    unsafe {
      (*self.graph.get())
        .add_edge(source, source_data, dest, dest_data, edge_data)
        .to_edge()
    }
  }
}

impl<T, S, A> Deref for AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  type Target = Graph<T, S, A>;

  fn deref(&self) -> &Graph<T, S, A> {
    unsafe { &*self.graph.get() }
  }
}

impl<T, S, A> From<AppendOnlyGraph<T, S, A>> for Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  fn from(graph: AppendOnlyGraph<T, S, A>) -> Self {
    graph.graph.into_inner()
  }
}

impl<T, S, A> From<Graph<T, S, A>> for AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  fn from(graph: Graph<T, S, A>) -> Self {
    AppendOnlyGraph { graph: UnsafeCell::new(graph) }
  }
}

#[cfg(test)]
mod test {
  use crossbeam_utils::thread;
  use std::sync::Arc;

  type Graph = crate::Graph<&'static str, &'static str, &'static str>;

  #[test]
  fn send_to_thread_safe_ok() {
    let mut g = Graph::new();
    g.add_edge("root", |_| "root_data", "0", |_| "0_data", "root_0_data");
    g.add_edge("root", |_| "root_data", "1", |_| "1_data", "root_1_data");
    let graph = Arc::new(g);
    thread::scope(move |s| {
      let g = graph.clone();
      let t1 = s.spawn(move |_| g.get_node(&"root").map(|n| n.get_id()));
      let g = graph.clone();
      let t2 = s.spawn(move |_| g.get_node(&"1").map(|n| n.get_id()));
      match t1.join() {
        Ok(Some(id)) => assert_eq!(id, 0),
        _ => panic!(),
      }
      match t2.join() {
        Ok(Some(id)) => assert_eq!(id, 2),
        _ => panic!(),
      }
    })
    .unwrap();
  }

  #[test]
  fn sync_to_thread_ok() {
    let mut g = Graph::new();
    g.add_edge("root", |_| "root_data", "0", |_| "0_data", "root_0_data");
    g.add_edge("root", |_| "root_data", "1", |_| "1_data", "root_1_data");
    let g = &g;
    thread::scope(|s| {
      let t1 = s.spawn(move |_| g.get_node(&"root").map(|n| n.get_id()));
      let t2 = s.spawn(move |_| g.get_node(&"1").map(|n| n.get_id()));
      match t1.join() {
        Ok(Some(id)) => assert_eq!(id, 0),
        _ => panic!(),
      }
      match t2.join() {
        Ok(Some(id)) => assert_eq!(id, 2),
        _ => panic!(),
      }
    })
    .unwrap();
  }
}
<commit_msg>AppendOnlyGraph.add_edge doesn't need &mut self.<commit_after>pub(crate) mod base;
pub mod mutators;
pub mod nav;
pub mod search;

use std::cell::UnsafeCell;
use std::hash::Hash;
use std::ops::Deref;

use base::{EdgeId, RawEdge, RawVertex, VertexId};
use mutators::{MutEdge, MutNode};
use nav::{Edge, Node};
use symbol_map::indexing::{Indexing, Insertion};
use symbol_map::SymbolId;

/// A search graph.
///
/// Supports incremental rollout of game state topology and vertex
/// de-duplication with transposition tables. Limited support is provided for
/// deletion of components and compaction in memory after deletion.
///
/// - `T`: The type of game states. It is required to derive `Hash` and `Eq` to
///   so that it may be stored in a hashtable, where game states are looked up to
///   support de-duplication of game states. It is required to derive `Clone` to
///   accommodate a limitation of the `HashMap` interface.
/// - `S`: The type of graph vertex data.
/// - `A`: The type of graph edge data.
///
/// Vertices are addressed by content. To examine graph contents, obtain a node
/// handle with `get_node`. To modify graph contents, add new root vertices with
/// `add_node` and retrieve extant vertices with `get_node_mut`.
pub struct Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  /// Lookup table that maps from game states to `VertexId`.
  state_ids: symbol_map::indexing::HashIndexing<T, VertexId>,
  vertices: Vec<RawVertex<S>>, // Indexed by VertexId.
  arcs: Vec<RawEdge<A>>,       // Indexed by EdgeId.
}

impl<T, S, A> Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  /// Creates an empty `Graph` with no vertices or edges.
  pub fn new() -> Self {
    Graph {
      state_ids: Default::default(),
      vertices: Vec::new(),
      arcs: Vec::new(),
    }
  }

  /// Returns the vertex for the given `VertexId`.
  fn get_vertex(&self, state: VertexId) -> &RawVertex<S> {
    &self.vertices[state.as_usize()]
  }

  /// Returns the vertex for the given `VertexId`.
  fn get_vertex_mut(&mut self, state: VertexId) -> &mut RawVertex<S> {
    &mut self.vertices[state.as_usize()]
  }

  /// Returns the edge for the given `EdgeId`.
  fn get_arc(&self, arc: EdgeId) -> &RawEdge<A> {
    &self.arcs[arc.as_usize()]
  }

  /// Returns the edge for the given `EdgeId`.
  fn get_arc_mut(&mut self, arc: EdgeId) -> &mut RawEdge<A> {
    &mut self.arcs[arc.as_usize()]
  }

  /// Returns the game state associated with `id`.
  fn get_state(&self, id: VertexId) -> Option<&T> {
    self.state_ids.get_symbol(&id).as_ref().map(|x| x.data())
  }

  /// Adds a new vertex with the given data, returning a mutable reference to it.
  ///
  /// This method does not add incoming or outgoing edges (expanded or
  /// not). That must be done by calling `add_arc` with the new vertex
  /// `VertexId`.
  fn add_raw_vertex(&mut self, data: S) -> &mut RawVertex<S> {
    self.vertices.push(RawVertex {
      data: data,
      parents: Vec::new(),
      children: Vec::new(),
    });
    self.vertices.last_mut().unwrap()
  }

  /// Adds a new edge with the given data, source, and target. Returns the
  /// internal ID for the new edge.
  fn add_raw_edge(&mut self, data: A, source: VertexId, target: VertexId) -> EdgeId {
    let arc_id = EdgeId(self.arcs.len());
    self.get_vertex_mut(source).children.push(arc_id);
    self.get_vertex_mut(target).parents.push(arc_id);
    self.arcs.push(RawEdge {
      data: data,
      source: source,
      target: target,
    });
    arc_id
  }

  /// Gets a node handle for the given game state.
  ///
  /// If `state` does not correspond to a known game state, returns `None`.
  pub fn get_node<'s>(&'s self, state: &T) -> Option<Node<'s, T, S, A>> {
    match self.state_ids.get(state) {
      Some(symbol) => Some(Node::new(self, *symbol.id())),
      None => None,
    }
  }

  /// Gets a mutable node handle for the given game state.
  ///
  /// If `state` does not correspond to a known game state, returns `None`.
  pub fn get_node_mut<'s>(&'s mut self, state: &T) -> Option<MutNode<'s, T, S, A>> {
    match self.state_ids.get(state).map(|s| s.id().clone()) {
      Some(id) => Some(MutNode::new(self, id)),
      None => None,
    }
  }

  /// Adds a vertex (with no parents or children) for the given game state and
  /// data and returns a mutable handle for it.
  ///
  /// If `state` is already known, returns a mutable handle to that state,
  /// ignoring the `data` parameter. As a result, this method is guaranteed to
  /// return a handle for a root vertex only when `state` is a novel game
  /// state.
  pub fn add_node<'s>(&'s mut self, state: T, data: S) -> MutNode<'s, T, S, A> {
    let node_id = match self.state_ids.get_or_insert(state).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        self.add_raw_vertex(data);
        id
      }
    };
    MutNode::new(self, node_id)
  }

  /// Adds an edge from the vertex with state data `source` to the vertex with
  /// state data `dest`. If vertices are not found for `source` or `dest`,
  /// they are added, with the data provided by `source_data` and `dest_data`
  /// callbacks.
  ///
  /// The edge that is created will have the data `edge_data`. Returns a
  /// mutable edge handle for that edge.
  pub fn add_edge<'s, F, G>(
    &'s mut self,
    source: T,
    source_data: F,
    dest: T,
    dest_data: G,
    edge_data: A,
  ) -> MutEdge<'s, T, S, A>
  where
    F: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
    G: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
  {
    let source_id = match self.state_ids.get_or_insert(source).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        let data = source_data(Node::new(self, id));
        self.add_raw_vertex(data);
        id
      }
    };
    let dest_id = match self.state_ids.get_or_insert(dest).map(|s| s.id().clone()) {
      Insertion::Present(id) => id,
      Insertion::New(id) => {
        let data = dest_data(Node::new(self, id));
        self.add_raw_vertex(data);
        id
      }
    };
    let edge_id = self.add_raw_edge(edge_data, source_id, dest_id);
    MutEdge::new(self, edge_id)
  }

  /// Returns the number of vertices in the graph.
  pub fn vertex_count(&self) -> usize {
    // TODO: This is actually the number of vertices we have allocated.
    self.vertices.len()
  }

  /// Returns the number of edges in the graph.
  pub fn edge_count(&self) -> usize {
    // TODO: This is actually the number of edges we have allocated.
    self.arcs.len()
  }

  /// Deletes all graph components that are not reachable by traversal
  /// starting from each vertex corresponding to the game states in `roots`.
  ///
  /// Game states in `roots` which do not have a corresponding vertex are
  /// ignored.
  pub fn retain_reachable_from(&mut self, roots: &[&T]) {
    let mut root_ids = Vec::with_capacity(roots.len());
    for state in roots.iter() {
      if let Some(symbol) = self.state_ids.get(state) {
        root_ids.push(*symbol.id());
      }
    }
    self.retain_reachable_from_ids(&root_ids);
  }

  /// As `retain_reachable_from`, but working over raw `VertexId`s instead of
  /// root data.
  fn retain_reachable_from_ids(&mut self, root_ids: &[VertexId]) {
    mutators::mark_compact::Collector::retain_reachable(self, root_ids);
  }
}

/// Allows both read-only references into a `Graph` and operations that modify
/// the graph but do not invalidate family of types defined in the `nav`
/// module.
///
/// All methods on `Graph` that take a `&self` parameter may also be called on
/// an `AppendOnlyGraph`. The `add_node` and `add_edge` methods may also be
/// called, because they do not invalidate `Node`, `Edge`, or other such smart
/// pointers into the underlying graph. Unlike the analogous methods on `Graph`,
/// these methods return a read-only view of the graph topology, instead of
/// granting read-write access.
///
/// For example:
///
/// ```rust
/// # use search_graph::{AppendOnlyGraph, Graph};
/// # use search_graph::nav::{Node, Edge};
/// # fn main() {
/// let appendable: AppendOnlyGraph<u32, String, ()> = Graph::new().into();
/// let root1 = appendable.add_node(0, "data1".to_string());
/// // If appendable were a Graph, we could not call add_node while root1 is alive.
/// let root2 = appendable.add_node(1, "data2".to_string());
/// assert_eq!("data1", appendable.get_node(&0).unwrap().get_data());
/// # }
/// ```
pub struct AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  graph: UnsafeCell<Graph<T, S, A>>,
}

impl<T, S, A> AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  pub fn add_node<'s>(&'s self, state: T, data: S) -> Node<'s, T, S, A> {
    unsafe { (*self.graph.get()).add_node(state, data).to_node() }
  }

  pub fn add_edge<'s, F, G>(
    &'s self,
    source: T,
    source_data: F,
    dest: T,
    dest_data: G,
    edge_data: A,
  ) -> Edge<'s, T, S, A>
  where
    F: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
    G: for<'b> FnOnce(Node<'b, T, S, A>) -> S,
  {
    unsafe {
      (*self.graph.get())
        .add_edge(source, source_data, dest, dest_data, edge_data)
        .to_edge()
    }
  }
}

impl<T, S, A> Deref for AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  type Target = Graph<T, S, A>;

  fn deref(&self) -> &Graph<T, S, A> {
    unsafe { &*self.graph.get() }
  }
}

impl<T, S, A> From<AppendOnlyGraph<T, S, A>> for Graph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  fn from(graph: AppendOnlyGraph<T, S, A>) -> Self {
    graph.graph.into_inner()
  }
}

impl<T, S, A> From<Graph<T, S, A>> for AppendOnlyGraph<T, S, A>
where
  T: Hash + Eq + Clone,
{
  fn from(graph: Graph<T, S, A>) -> Self {
    AppendOnlyGraph { graph: UnsafeCell::new(graph) }
  }
}

#[cfg(test)]
mod test {
  use crossbeam_utils::thread;
  use std::sync::Arc;

  type Graph = crate::Graph<&'static str, &'static str, &'static str>;

  #[test]
  fn send_to_thread_safe_ok() {
    let mut g = Graph::new();
    g.add_edge("root", |_| "root_data", "0", |_| "0_data", "root_0_data");
    g.add_edge("root", |_| "root_data", "1", |_| "1_data", "root_1_data");
    let graph = Arc::new(g);
    thread::scope(move |s| {
      let g = graph.clone();
      let t1 = s.spawn(move |_| g.get_node(&"root").map(|n| n.get_id()));
      let g = graph.clone();
      let t2 = s.spawn(move |_| g.get_node(&"1").map(|n| n.get_id()));
      match t1.join() {
        Ok(Some(id)) => assert_eq!(id, 0),
        _ => panic!(),
      }
      match t2.join() {
        Ok(Some(id)) => assert_eq!(id, 2),
        _ => panic!(),
      }
    })
    .unwrap();
  }

  #[test]
  fn sync_to_thread_ok() {
    let mut g = Graph::new();
    g.add_edge("root", |_| "root_data", "0", |_| "0_data", "root_0_data");
    g.add_edge("root", |_| "root_data", "1", |_| "1_data", "root_1_data");
    let g = &g;
    thread::scope(|s| {
      let t1 = s.spawn(move |_| g.get_node(&"root").map(|n| n.get_id()));
      let t2 = s.spawn(move |_| g.get_node(&"1").map(|n| n.get_id()));
      match t1.join() {
        Ok(Some(id)) => assert_eq!(id, 0),
        _ => panic!(),
      }
      match t2.join() {
        Ok(Some(id)) => assert_eq!(id, 2),
        _ => panic!(),
      }
    })
    .unwrap();
  }
}
<|endoftext|>


<commit_before>/*!
Miscellaneous utilities grab-bag.

 */

#![crate_name="calx"]
#![feature(core, collections, path_ext, std_misc)]
#![feature(plugin, custom_attribute, unboxed_closures, slice_patterns)]
#![feature(custom_derive)]
#![plugin(rand_macros)]

#[no_link] extern crate rand_macros;
extern crate collections;
extern crate rustc_serialize;
extern crate time;
extern crate rand;
extern crate num;
extern crate nalgebra;
extern crate image;
extern crate glutin;
#[macro_use]
extern crate glium;

use num::{Float};
use std::path::{Path, PathBuf};
use std::ops::{Add, Sub, Mul};

pub use rgb::{ToColor, FromColor, Rgba, color, parse_color};
pub use geom::{V2, V3, Rect, RectIter};
pub use img::{color_key};
pub use atlas::{AtlasBuilder, Atlas, AtlasItem};
pub use dijkstra::{DijkstraNode, Dijkstra};
pub use hex::{HexGeom, Dir6, HexFov};
pub use projection::{Projection};
pub use rng::{EncodeRng, RngExt};

mod atlas;
mod dijkstra;
mod geom;
mod hex;
mod img;
mod projection;
mod rgb;
mod rng;

pub mod backend;
pub mod text;
pub mod timing;
pub mod vorud;

/// Clamp a value to range.
pub fn clamp<C: PartialOrd+Copy>(mn: C, mx: C, x: C) -> C {
    if x < mn { mn }
    else if x > mx { mx }
    else { x }
}

/// Deterministic noise.
pub fn noise(n: i32) -> f32 {
    use std::num::Wrapping;

    let n = Wrapping(n);
    let n = (n << 13) ^ n;
    let m = (n * (n * n * Wrapping(15731) + Wrapping(789221)) + Wrapping(1376312589))
        & Wrapping(0x7fffffff);
    let Wrapping(m) = m;
    1.0 - m as f32 / 1073741824.0
}

/// Convert probability to a log odds deciban value.
///
/// Log odds correspond to the Bayesian probability for a hypothesis that
/// has decibans * 1/10 log_2(10) bits of evidence in favor of it. They're
/// a bit like rolling a d20 but better.
pub fn to_log_odds(p: f32) -> f32 {
    10.0 * (p / (1.0 - p)).log(10.0)
}

/// Convert a log odds deciban value to the corresponding probability.
pub fn from_log_odds(db: f32) -> f32 {
    (1.0 - 1.0 / (1.0 + 10.0.powf(db / 10.0)))
}

/// Interpolate linearly between two values.
pub fn lerp<T, U>(t: T, a: U, b: U) -> U where
        U: Add<U, Output=U> + Sub<U, Output=U> + Mul<T, Output=U> + Copy {
    a + (b - a) * t
}

/// Rectangle anchoring points.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Anchor {
    TopLeft,
    TopRight,
    BottomLeft,
    BottomRight,
    Top,
    Left,
    Right,
    Bottom,
    Center
}

/// Return the application data directory path for the current platform.
pub fn app_data_path(app_name: &str) -> PathBuf {
    use std::env;
    // On Windows, a portable application is just an .exe the user downloads
    // and drops somewhere. The convention here is for a portable application
    // to add its files to wherever its exe file is. An installed application
    // uses an actual installer program and deploys its files to user data
    // directories.
    let is_portable_application = true;

    // TODO: Handle not having the expected env variables.
    if cfg!(windows) {
        if is_portable_application {
            match env::current_exe() {
                Ok(mut p) => { p.pop(); p }
                // If couldn't get self exe path, just use the local relative path and
                // hope for the best.
                _ => Path::new(".").to_path_buf()
            }
        } else {
            Path::new(
                &format!("{}\\{}", env::var("APPDATA").unwrap(), app_name))
            .to_path_buf()
        }
    } else if cfg!(macos) {
        Path::new(
            &format!("{}/Library/Application Support/{}",
                    env::var("HOME").unwrap(), app_name))
        .to_path_buf()
    } else {
        Path::new(
            &format!("{}/.config/{}", env::var("HOME").unwrap(), app_name))
        .to_path_buf()
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_noise() {
        use super::noise;

        for i in 0i32..100 {
            assert!(noise(i) >= -1.0 && noise(i) <= 1.0);
        }
    }

    #[test]
    fn test_log_odds() {
        use super::{to_log_odds, from_log_odds};
        assert_eq!(from_log_odds(0.0), 0.5);
        assert_eq!(to_log_odds(0.5), 0.0);

        assert_eq!((from_log_odds(-5.0) * 100.0) as i32, 24);
        assert_eq!(to_log_odds(0.909091) as i32, 10);
    }
}
<commit_msg>Pseudo-ordering for isometric tiles<commit_after>/*!
Miscellaneous utilities grab-bag.

 */

#![crate_name="calx"]
#![feature(core, collections, path_ext, std_misc)]
#![feature(plugin, custom_attribute, unboxed_closures, slice_patterns)]
#![feature(custom_derive)]
#![plugin(rand_macros)]

#[no_link] extern crate rand_macros;
extern crate collections;
extern crate rustc_serialize;
extern crate time;
extern crate rand;
extern crate num;
extern crate nalgebra;
extern crate image;
extern crate glutin;
#[macro_use]
extern crate glium;

use num::{Float, Zero, One};
use std::path::{Path, PathBuf};
use std::ops::{Add, Sub, Mul};
use std::cmp::{Ordering};
use num::traits::{Num};

pub use rgb::{ToColor, FromColor, Rgba, color, parse_color};
pub use geom::{V2, V3, Rect, RectIter};
pub use img::{color_key};
pub use atlas::{AtlasBuilder, Atlas, AtlasItem};
pub use dijkstra::{DijkstraNode, Dijkstra};
pub use hex::{HexGeom, Dir6, HexFov};
pub use projection::{Projection};
pub use rng::{EncodeRng, RngExt};

mod atlas;
mod dijkstra;
mod geom;
mod hex;
mod img;
mod projection;
mod rgb;
mod rng;

pub mod backend;
pub mod text;
pub mod timing;
pub mod vorud;

/// Clamp a value to range.
pub fn clamp<C: PartialOrd+Copy>(mn: C, mx: C, x: C) -> C {
    if x < mn { mn }
    else if x > mx { mx }
    else { x }
}

/// Deterministic noise.
pub fn noise(n: i32) -> f32 {
    use std::num::Wrapping;

    let n = Wrapping(n);
    let n = (n << 13) ^ n;
    let m = (n * (n * n * Wrapping(15731) + Wrapping(789221)) + Wrapping(1376312589))
        & Wrapping(0x7fffffff);
    let Wrapping(m) = m;
    1.0 - m as f32 / 1073741824.0
}

/// Convert probability to a log odds deciban value.
///
/// Log odds correspond to the Bayesian probability for a hypothesis that
/// has decibans * 1/10 log_2(10) bits of evidence in favor of it. They're
/// a bit like rolling a d20 but better.
pub fn to_log_odds(p: f32) -> f32 {
    10.0 * (p / (1.0 - p)).log(10.0)
}

/// Convert a log odds deciban value to the corresponding probability.
pub fn from_log_odds(db: f32) -> f32 {
    (1.0 - 1.0 / (1.0 + 10.0.powf(db / 10.0)))
}

/// Interpolate linearly between two values.
pub fn lerp<T, U>(t: T, a: U, b: U) -> U where
        U: Add<U, Output=U> + Sub<U, Output=U> + Mul<T, Output=U> + Copy {
    a + (b - a) * t
}

/// Rectangle anchoring points.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Anchor {
    TopLeft,
    TopRight,
    BottomLeft,
    BottomRight,
    Top,
    Left,
    Right,
    Bottom,
    Center
}

/// Return the application data directory path for the current platform.
pub fn app_data_path(app_name: &str) -> PathBuf {
    use std::env;
    // On Windows, a portable application is just an .exe the user downloads
    // and drops somewhere. The convention here is for a portable application
    // to add its files to wherever its exe file is. An installed application
    // uses an actual installer program and deploys its files to user data
    // directories.
    let is_portable_application = true;

    // TODO: Handle not having the expected env variables.
    if cfg!(windows) {
        if is_portable_application {
            match env::current_exe() {
                Ok(mut p) => { p.pop(); p }
                // If couldn't get self exe path, just use the local relative path and
                // hope for the best.
                _ => Path::new(".").to_path_buf()
            }
        } else {
            Path::new(
                &format!("{}\\{}", env::var("APPDATA").unwrap(), app_name))
            .to_path_buf()
        }
    } else if cfg!(macos) {
        Path::new(
            &format!("{}/Library/Application Support/{}",
                    env::var("HOME").unwrap(), app_name))
        .to_path_buf()
    } else {
        Path::new(
            &format!("{}/.config/{}", env::var("HOME").unwrap(), app_name))
        .to_path_buf()
    }
}

/// A non-transitive pseudo-ordering relation between isometric axis-aligned boxes.
///
/// XXX: The relation is NOT TRANSITIVE, the more disparate box sizes
/// you feed it the worse it's likely to perform.
///
/// The box format is (bottom_pos, top_pos) pairs. The camera looks towards (-1, -1, -1).
pub fn isometric_pseudo_ord<T: PartialOrd+Num+Copy>(
    &(ref first_bot, ref first_top): &(V3<T>, V3<T>),
    &(ref second_bot, ref second_top): &(V3<T>, V3<T>)) -> Ordering {
    // Return Less if first box is drawn before second box
    // Return Greater if first box is drawn after second box
    // If the boxes overlap, compare their top Z positions.

    // Look for the unambiguous order with the largest distance between
    // box faces.
    let mut less_weight = None;
    let mut greater_weight = None;

    less_weight = comp(second_bot.0, first_top.0, less_weight);
    less_weight = comp(second_bot.1, first_top.1, less_weight);
    less_weight = comp(second_bot.2, first_top.2, less_weight);

    greater_weight = comp(first_bot.0, second_top.0, greater_weight);
    greater_weight = comp(first_bot.1, second_top.1, greater_weight);
    greater_weight = comp(first_bot.2, second_top.2, greater_weight);

    return match (less_weight, greater_weight) {
        (Some(_), None) => Ordering::Less,
        (None, Some(_)) => Ordering::Greater,
        (Some(ls), Some(gt)) => if ls > gt { Ordering::Less } else { Ordering::Greater },
        _ => {
            let camera: V3<T> = V3(One::one(), One::one(), One::one());
            (first_top).dot(camera).partial_cmp(&second_top.dot(camera))
            .unwrap_or(Ordering::Equal)
        }
    };

    // Update a result weight counter with a comparison along an axis.
    fn comp<T: PartialOrd+Num+Copy>(bottom_point: T, top_point: T, weight_counter: Option<T>) -> Option<T> {
        let diff = bottom_point - top_point ;
        if diff >= Zero::zero() {
            Some(weight_counter.map_or(diff, |old| if diff > old { diff } else { old }))
        } else {
            weight_counter
        }
    }

}

#[cfg(test)]
mod test {
    use super::geom::{V3};

    #[test]
    fn test_noise() {
        use super::noise;

        for i in 0i32..100 {
            assert!(noise(i) >= -1.0 && noise(i) <= 1.0);
        }
    }

    #[test]
    fn test_log_odds() {
        use super::{to_log_odds, from_log_odds};
        assert_eq!(from_log_odds(0.0), 0.5);
        assert_eq!(to_log_odds(0.5), 0.0);

        assert_eq!((from_log_odds(-5.0) * 100.0) as i32, 24);
        assert_eq!(to_log_odds(0.909091) as i32, 10);
    }

    fn gen_boxes(positions: Vec<V3<i32>>) -> Vec<(V3<i32>, V3<i32>)> {
        positions.into_iter().map(|p| (p, p + V3(2, 2, 2))).collect()
    }

    #[test]
    fn test_iso_sort() {
        use super::{isometric_pseudo_ord};

        // XXX: Just a sanity check, actually debugging the problems
        // with the slightly iffy sorter would take a lot more heavy
        // testing.
        let mut boxes = gen_boxes(vec![V3(0, 0, 2), V3(-2, 0, 0), V3(0, 0, 0)]);
        boxes.sort_by(isometric_pseudo_ord);

        assert_eq!(V3(-2, 0, 0), boxes[0].0);
        assert_eq!(V3(0, 0, 2), boxes[2].0);
    }
}
<|endoftext|>


<commit_before>//! A brush for generative fine art.

mod gpu;
mod noise_traits;
mod raster;
mod render;

pub mod canvas;
pub mod forms;
pub mod paint;
pub mod path;
pub mod shaders;
pub mod transforms;
pub mod uniforms;

/// Exhuastive set of imports for painting.
pub mod prelude {
    pub use self::{
        canvas::*,
        forms::*,
        paint::*,
        path::*,
        shaders::*,
        transforms::*,
        uniforms::*,
    };
    pub use super::*;
    pub use euclid::{self, Rect};
    pub use noise::{self, *};
    pub use noise_traits::*;
    pub use rayon::{self, prelude::*};

    pub use palette::{
        self,
        encoding::Srgb,
        Alpha,
        Blend,
        ComponentWise,
        Hue,
        IntoColor,
        LinSrgb,
        LinSrgba,
        Saturate,
        *,
    };
    pub use rand::{self, rngs::StdRng, Rng, SeedableRng};
    pub use structopt::StructOpt;

    pub use std::f32::consts::PI;
}

pub use self::{
    gpu::{Gpu, Shader},
    render::Context,
    shaders::ShaderProgram,
};

use self::{gpu::*, prelude::*, raster::Method};
use euclid::{Point3D, Size2D, UnknownUnit, Vector2D, Vector3D};
use failure::Error;
use lyon_path::math::Point;
use render::*;
use std::{path::PathBuf, time::Duration};

/// A two dimensional point.
pub type P2 = Point;

/// A three dimensional point.
pub type P3 = Point3D<f32, UnknownUnit>;

/// A two dimensional vector.
pub type V2 = Vector2D<f32, UnknownUnit>;

/// A three dimensional vector.
pub type V3 = Vector3D<f32, UnknownUnit>;

/// A two dimensional size.
pub type S2 = Size2D<f32, UnknownUnit>;

/// An angle.
pub type Angle = euclid::Angle<f32>;

/// A compiled GLSL program.
pub type Program = glium::program::Program;

/// A value or an error.
pub type Result<T> = std::result::Result<T, Error>;

/// Command line options for a painting run.
///
/// Construct with `Options::from_args()` to run the CLI.
#[derive(StructOpt, Debug, Clone)]
#[structopt(name = "valora")]
pub struct Options {
    #[structopt(flatten)]
    pub world: World,

    /// In brainstorm mode:
    ///
    ///   * When rendering a limited number of frames to screen, the preview will not close.
    ///
    ///   * When rendering to file, every frame will be rendered with a different seed.
    #[structopt(short = "b", long = "brainstorm")]
    pub brainstorm: bool,

    /// The number of frames to delay saving to file. For example, if delay=100,
    /// 100 frames will be rendered silently and then the 101st and those after it
    /// will be saved to file.
    #[structopt(short = "d", long = "delay", default_value = "0")]
    pub delay: usize,

    /// Prefix of output path. Output is <prefix>/<seed>/<frame_number>.png
    #[structopt(short = "o", long = "output", parse(from_os_str))]
    pub output: Option<PathBuf>,
}

/// The world in which the painting takes place.
#[derive(StructOpt, Debug, Copy, Clone)]
#[structopt(name = "world")]
pub struct World {
    /// The RNG seed for this painting.
    #[structopt(short = "e", long = "seed", default_value = "0")]
    pub seed: u64,

    /// The width in coordinate space of the painting.
    ///
    /// Coordinate space may differ from output space. If width is 500 but scale is 10, the painting
    /// will have a coordinate space width of 500, but the final output will have a width of 5000 pixels.
    #[structopt(short = "w", long = "width", default_value = "512")]
    pub width: f32,
    /// The height in coordinate space of the painting.
    ///
    /// Coordinate space may differ from output space. If height is 500 but scale is 10, the painting
    /// will have a coordinate space height of 500, but the final output will have a height of 5000 pixels.
    #[structopt(short = "h", long = "height", default_value = "650")]
    pub height: f32,

    /// The scale of the output.
    ///
    /// The final output space is (width*scale)x(height*scale). This value is useful for painting
    /// and doing work at one quickly rendering resolution, and later exporting at a much higher
    /// resolution while preserving the composition exactly.
    ///
    /// This value may be needed when writing shaders or using other raster graphics, to adjust them
    /// for the real output size. Vector painting such as with paths should not need to consider this.
    #[structopt(short = "s", long = "scale", default_value = "1.0")]
    pub scale: f32,

    /// The total number of frames in this painting.
    #[structopt(short = "f", long = "frames")]
    pub frames: Option<usize>,

    /// The number of frames (to try) to render per second.
    #[structopt(short = "r", long = "frames_per_second", default_value = "24")]
    pub framerate: usize,
}

impl World {
    /// Normalizes coordinates into the range [0, 1] by dividing them by the coordinate space dimensions.
    pub fn normalize(&self, p: P2) -> P2 { P2::new(p.x / self.width, p.y / self.height) }

    /// Returns the center of the coordinate space.
    pub fn center(&self) -> P2 { P2::new(self.width / 2.0, self.height / 2.0) }
}

/// Draws a rectangle path covering the entire canvas.
impl Paint for World {
    fn paint(&self, comp: &mut Canvas) {
        comp.line_to(P2::new(0.0, 0.0));
        comp.line_to(P2::new(self.width, 0.0));
        comp.line_to(P2::new(self.width, self.height));
        comp.line_to(P2::new(0.0, self.height));
        comp.line_to(P2::new(0.0, 0.0));
    }
}

/// A trait for types which paint canvases.
pub trait Artist: Sized {
    /// Constructs the artist.
    ///
    /// This would be a place to compile any GLSL or construct any expensive
    /// resources needed across the whole composition.
    fn setup(gpu: Gpu, world: World, rng: &mut StdRng) -> Result<Self>;

    /// Paints a single frame.
    fn paint(&mut self, ctx: Context, canvas: &mut Canvas);
}

/// Run an artist defined by raw functions.
///
/// Takes a function that produces the function that should paint each frame.
pub fn run_fn<F>(options: Options, f: impl Fn(Gpu, World, &mut StdRng) -> Result<F>) -> Result<()>
where
    F: FnMut(Context, &mut Canvas),
{
    let (output_width, output_height) = (
        (options.world.width as f32 * options.world.scale) as u32,
        (options.world.height as f32 * options.world.scale) as u32,
    );

    let number_width = options
        .world
        .frames
        .unwrap_or(0)
        .to_string()
        .chars()
        .count();

    let (gpu, mut strategy) = if let Some(base_path) = options.output.clone() {
        let (gpu, _) = Gpu::new()?;
        let buffer = gpu.build_texture(output_width, output_height)?;

        (
            gpu,
            RenderStrategy::File {
                buffer,
                output_path: move |frame_number: usize, seed: u64| {
                    let mut base_path = base_path.clone();
                    base_path.push(format!("{}", seed));
                    std::fs::create_dir_all(&base_path)
                        .expect(&format!("To create save directory {:?}", base_path));
                    base_path.push(format!(
                        "{number:>0width$}.png",
                        number = frame_number,
                        width = number_width
                    ));
                    base_path
                },
            },
        )
    } else {
        let (gpu, events_loop, (screen_width, screen_height)) =
            Gpu::with_window(output_width, output_height)?;
        let buffer = gpu.build_texture(screen_width, screen_height)?;

        let wait = Duration::from_secs_f64(1. / options.world.framerate as f64);
        let gpu_clone = gpu.clone();

        let texture_glsl = include_str!("shaders/texture.frag");
        let texture_program = gpu.compile_glsl(texture_glsl)?;

        (
            gpu,
            RenderStrategy::Screen {
                events_loop,
                wait,
                buffer,
                texture_program,
                get_frame: move || {
                    gpu_clone
                        .get_frame()
                        .expect("To get frame from windowed gpu")
                },
            },
        )
    };

    let mut current_seed = options.world.seed;
    loop {
        let mut rng = StdRng::seed_from_u64(current_seed);
        let mut paint_fn = f(gpu.clone(), options.world, &mut rng)?;

        let mut renderer = Renderer {
            strategy: &mut strategy,
            gpu: &gpu,
            options: Options {
                world: World {
                    seed: current_seed,
                    ..options.world
                },
                ..options.clone()
            },
            rng: &mut rng,
            output_width: output_width,
            output_height: output_height,
        };

        let report = renderer.render_frames(|ctx, canvas| paint_fn(ctx, canvas))?;

        if let Some(rebuild) = report.rebuild {
            match rebuild {
                Rebuild::NewSeed(new_seed) => {
                    current_seed = new_seed;
                }
            }
        } else if report.explicit_quit || !options.brainstorm {
            break;
        }
    }

    Ok(())
}

/// Run an artist.
pub fn run<A: Artist>(options: Options) -> Result<()> {
    run_fn(options, |gpu, world, rng| {
        let mut artist = A::setup(gpu, world, rng)?;
        Ok(move |ctx: Context, canvas: &mut Canvas| artist.paint(ctx, canvas))
    })
}
<commit_msg>Terminate brainstorm file output<commit_after>//! A brush for generative fine art.

mod gpu;
mod noise_traits;
mod raster;
mod render;

pub mod canvas;
pub mod forms;
pub mod paint;
pub mod path;
pub mod shaders;
pub mod transforms;
pub mod uniforms;

/// Exhuastive set of imports for painting.
pub mod prelude {
    pub use self::{
        canvas::*,
        forms::*,
        paint::*,
        path::*,
        shaders::*,
        transforms::*,
        uniforms::*,
    };
    pub use super::*;
    pub use euclid::{self, Rect};
    pub use noise::{self, *};
    pub use noise_traits::*;
    pub use rayon::{self, prelude::*};

    pub use palette::{
        self,
        encoding::Srgb,
        Alpha,
        Blend,
        ComponentWise,
        Hue,
        IntoColor,
        LinSrgb,
        LinSrgba,
        Saturate,
        *,
    };
    pub use rand::{self, rngs::StdRng, Rng, SeedableRng};
    pub use structopt::StructOpt;

    pub use std::f32::consts::PI;
}

pub use self::{
    gpu::{Gpu, Shader},
    render::Context,
    shaders::ShaderProgram,
};

use self::{gpu::*, prelude::*, raster::Method};
use euclid::{Point3D, Size2D, UnknownUnit, Vector2D, Vector3D};
use failure::Error;
use lyon_path::math::Point;
use render::*;
use std::{path::PathBuf, time::Duration};

/// A two dimensional point.
pub type P2 = Point;

/// A three dimensional point.
pub type P3 = Point3D<f32, UnknownUnit>;

/// A two dimensional vector.
pub type V2 = Vector2D<f32, UnknownUnit>;

/// A three dimensional vector.
pub type V3 = Vector3D<f32, UnknownUnit>;

/// A two dimensional size.
pub type S2 = Size2D<f32, UnknownUnit>;

/// An angle.
pub type Angle = euclid::Angle<f32>;

/// A compiled GLSL program.
pub type Program = glium::program::Program;

/// A value or an error.
pub type Result<T> = std::result::Result<T, Error>;

/// Command line options for a painting run.
///
/// Construct with `Options::from_args()` to run the CLI.
#[derive(StructOpt, Debug, Clone)]
#[structopt(name = "valora")]
pub struct Options {
    #[structopt(flatten)]
    pub world: World,

    /// In brainstorm mode:
    ///
    ///   * When rendering a limited number of frames to screen, the preview will not close.
    ///
    ///   * When rendering to file, every frame will be rendered with a different seed.
    #[structopt(short = "b", long = "brainstorm")]
    pub brainstorm: bool,

    /// The number of frames to delay saving to file. For example, if delay=100,
    /// 100 frames will be rendered silently and then the 101st and those after it
    /// will be saved to file.
    #[structopt(short = "d", long = "delay", default_value = "0")]
    pub delay: usize,

    /// Prefix of output path. Output is <prefix>/<seed>/<frame_number>.png
    #[structopt(short = "o", long = "output", parse(from_os_str))]
    pub output: Option<PathBuf>,
}

/// The world in which the painting takes place.
#[derive(StructOpt, Debug, Copy, Clone)]
#[structopt(name = "world")]
pub struct World {
    /// The RNG seed for this painting.
    #[structopt(short = "e", long = "seed", default_value = "0")]
    pub seed: u64,

    /// The width in coordinate space of the painting.
    ///
    /// Coordinate space may differ from output space. If width is 500 but scale is 10, the painting
    /// will have a coordinate space width of 500, but the final output will have a width of 5000 pixels.
    #[structopt(short = "w", long = "width", default_value = "512")]
    pub width: f32,
    /// The height in coordinate space of the painting.
    ///
    /// Coordinate space may differ from output space. If height is 500 but scale is 10, the painting
    /// will have a coordinate space height of 500, but the final output will have a height of 5000 pixels.
    #[structopt(short = "h", long = "height", default_value = "650")]
    pub height: f32,

    /// The scale of the output.
    ///
    /// The final output space is (width*scale)x(height*scale). This value is useful for painting
    /// and doing work at one quickly rendering resolution, and later exporting at a much higher
    /// resolution while preserving the composition exactly.
    ///
    /// This value may be needed when writing shaders or using other raster graphics, to adjust them
    /// for the real output size. Vector painting such as with paths should not need to consider this.
    #[structopt(short = "s", long = "scale", default_value = "1.0")]
    pub scale: f32,

    /// The total number of frames in this painting.
    #[structopt(short = "f", long = "frames")]
    pub frames: Option<usize>,

    /// The number of frames (to try) to render per second.
    #[structopt(short = "r", long = "frames_per_second", default_value = "24")]
    pub framerate: usize,
}

impl World {
    /// Normalizes coordinates into the range [0, 1] by dividing them by the coordinate space dimensions.
    pub fn normalize(&self, p: P2) -> P2 { P2::new(p.x / self.width, p.y / self.height) }

    /// Returns the center of the coordinate space.
    pub fn center(&self) -> P2 { P2::new(self.width / 2.0, self.height / 2.0) }
}

/// Draws a rectangle path covering the entire canvas.
impl Paint for World {
    fn paint(&self, comp: &mut Canvas) {
        comp.line_to(P2::new(0.0, 0.0));
        comp.line_to(P2::new(self.width, 0.0));
        comp.line_to(P2::new(self.width, self.height));
        comp.line_to(P2::new(0.0, self.height));
        comp.line_to(P2::new(0.0, 0.0));
    }
}

/// A trait for types which paint canvases.
pub trait Artist: Sized {
    /// Constructs the artist.
    ///
    /// This would be a place to compile any GLSL or construct any expensive
    /// resources needed across the whole composition.
    fn setup(gpu: Gpu, world: World, rng: &mut StdRng) -> Result<Self>;

    /// Paints a single frame.
    fn paint(&mut self, ctx: Context, canvas: &mut Canvas);
}

/// Run an artist defined by raw functions.
///
/// Takes a function that produces the function that should paint each frame.
pub fn run_fn<F>(options: Options, f: impl Fn(Gpu, World, &mut StdRng) -> Result<F>) -> Result<()>
where
    F: FnMut(Context, &mut Canvas),
{
    let (output_width, output_height) = (
        (options.world.width as f32 * options.world.scale) as u32,
        (options.world.height as f32 * options.world.scale) as u32,
    );

    let number_width = options
        .world
        .frames
        .unwrap_or(0)
        .to_string()
        .chars()
        .count();

    let (gpu, mut strategy) = if let Some(base_path) = options.output.clone() {
        let (gpu, _) = Gpu::new()?;
        let buffer = gpu.build_texture(output_width, output_height)?;

        (
            gpu,
            RenderStrategy::File {
                buffer,
                output_path: move |frame_number: usize, seed: u64| {
                    let mut base_path = base_path.clone();
                    base_path.push(format!("{}", seed));
                    std::fs::create_dir_all(&base_path)
                        .expect(&format!("To create save directory {:?}", base_path));
                    base_path.push(format!(
                        "{number:>0width$}.png",
                        number = frame_number,
                        width = number_width
                    ));
                    base_path
                },
            },
        )
    } else {
        let (gpu, events_loop, (screen_width, screen_height)) =
            Gpu::with_window(output_width, output_height)?;
        let buffer = gpu.build_texture(screen_width, screen_height)?;

        let wait = Duration::from_secs_f64(1. / options.world.framerate as f64);
        let gpu_clone = gpu.clone();

        let texture_glsl = include_str!("shaders/texture.frag");
        let texture_program = gpu.compile_glsl(texture_glsl)?;

        (
            gpu,
            RenderStrategy::Screen {
                events_loop,
                wait,
                buffer,
                texture_program,
                get_frame: move || {
                    gpu_clone
                        .get_frame()
                        .expect("To get frame from windowed gpu")
                },
            },
        )
    };

    let mut current_seed = options.world.seed;
    loop {
        let mut rng = StdRng::seed_from_u64(current_seed);
        let mut paint_fn = f(gpu.clone(), options.world, &mut rng)?;

        let mut renderer = Renderer {
            strategy: &mut strategy,
            gpu: &gpu,
            options: Options {
                world: World {
                    seed: current_seed,
                    ..options.world
                },
                ..options.clone()
            },
            rng: &mut rng,
            output_width: output_width,
            output_height: output_height,
        };

        let report = renderer.render_frames(|ctx, canvas| paint_fn(ctx, canvas))?;

        if let Some(rebuild) = report.rebuild {
            match rebuild {
                Rebuild::NewSeed(new_seed) => {
                    current_seed = new_seed;
                }
            }
        } else if report.explicit_quit || !options.brainstorm || options.output.is_some() {
            break;
        }
    }

    Ok(())
}

/// Run an artist.
pub fn run<A: Artist>(options: Options) -> Result<()> {
    run_fn(options, |gpu, world, rng| {
        let mut artist = A::setup(gpu, world, rng)?;
        Ok(move |ctx: Context, canvas: &mut Canvas| artist.paint(ctx, canvas))
    })
}
<|endoftext|>


<commit_before>//! Complex numbers

#![deny(missing_docs, warnings)]
#![feature(macro_rules)]

extern crate onezero;

use std::fmt;
use std::rand::{Rand, Rng};

use onezero::{One, Zero};

mod ffi;
mod math;

pub mod f32;
pub mod f64;

/// A complex number in Cartesian form.
#[repr(C)]
#[deriving(Clone, Copy, PartialEq)]
pub struct Complex<T> {
    /// The real part
    pub re: T,
    /// The imaginary part
    pub im: T,
}

/// Single precision complex number
#[allow(non_camel_case_types)]
pub type c64 = Complex<f32>;
/// Double precision complex number
#[allow(non_camel_case_types)]
pub type c128 = Complex<f64>;

impl<T> Complex<T> {
    /// Create a new complex number
    pub fn new(re: T, im: T) -> Complex<T> {
        Complex {
            im: im,
            re: re,
        }
    }
}

impl<T> Complex<T> where T: Add<T, T> + Mul<T, T> {
    fn norm_sqr(&self) -> T {
        self.re * self.re + self.im * self.im
    }
}

impl<T> Add<T, Complex<T>> for Complex<T> where T: Add<T, T> + Clone {
    fn add(&self, rhs: &T) -> Complex<T> {
        Complex {
            re: self.re.add(rhs),
            im: self.im.clone(),
        }
    }
}

impl<T> Add<Complex<T>, Complex<T>> for Complex<T> where T: Add<T, T> {
    fn add(&self, rhs: &Complex<T>) -> Complex<T> {
        Complex {
            re: self.re + rhs.re,
            im: self.im + rhs.im,
        }
    }
}

impl<T> Add<Complex<T>, Complex<T>> for T where T: Add<T, T> + Clone {
    fn add(&self, rhs: &Complex<T>) -> Complex<T> {
        rhs.add(self)
    }
}

impl<T> Div<T, Complex<T>> for Complex<T> where T: Div<T, T> {
    fn div(&self, rhs: &T) -> Complex<T> {
        Complex {
            re: self.re.div(rhs),
            im: self.im.div(rhs),
        }
    }
}

impl<T> Div<Complex<T>, Complex<T>> for Complex<T> where
    T: Add<T, T> + Div<T, T> + Mul<T, T> + Sub<T, T>
{
    fn div(&self, rhs: &Complex<T>) -> Complex<T> {
        let den = rhs.norm_sqr();

        Complex {
            re: (self.re * rhs.re + self.im * rhs.im) / den,
            im: (self.im * rhs.re - self.re * rhs.im) / den,
        }
    }
}

impl<T> Div<Complex<T>, Complex<T>> for T where T: Add<T, T> + Div<T, T> + Mul<T, T> + Neg<T> {
    fn div(&self, rhs: &Complex<T>) -> Complex<T> {
        let den = rhs.norm_sqr();

        Complex {
            re: (self.mul(&rhs.re)) / den,
            im: -(self.mul(&rhs.im)) / den,
        }
    }
}

impl<T> Mul<T, Complex<T>> for Complex<T> where T: Mul<T, T> {
    fn mul(&self, rhs: &T) -> Complex<T> {
        Complex {
            re: self.re.mul(rhs),
            im: self.im.mul(rhs),
        }
    }
}

impl<T> Mul<Complex<T>, Complex<T>> for Complex<T> where T: Add<T, T> + Mul<T, T> + Sub<T, T> {
    fn mul(&self, rhs: &Complex<T>) -> Complex<T> {
        Complex {
            re: self.re * rhs.re - self.im * rhs.im,
            im: self.re * rhs.im + self.im * rhs.re,
        }
    }
}

impl<T> Mul<Complex<T>, Complex<T>> for T where T: Mul<T, T> {
    fn mul(&self, rhs: &Complex<T>) -> Complex<T> {
        rhs.mul(self)
    }
}

impl<T> Neg<Complex<T>> for Complex<T> where T: Neg<T> {
    fn neg(&self) -> Complex<T> {
        Complex {
            re: self.re.neg(),
            im: self.im.neg(),
        }
    }
}

impl<T> One for Complex<T> where T: Mul<T, T> + One + Sub<T, T> + Zero {
    fn one() -> Complex<T> {
        Complex {
            re: One::one(),
            im: Zero::zero(),
        }
    }
}

impl<T> Rand for Complex<T> where T: Rand {
    fn rand<R>(rng: &mut R) -> Complex<T> where R: Rng {
        Complex::new(rng.gen(), rng.gen())
    }
}

impl<T> fmt::Show for Complex<T> where T: PartialOrd + fmt::Show + Zero {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.im < Zero::zero() {
            write!(f, "{}-{}i", self.re, self.im)
        } else {
            write!(f, "{}+{}i", self.re, self.im)
        }
    }
}

impl<T> Sub<T, Complex<T>> for Complex<T> where T: Clone + Sub<T, T> {
    fn sub(&self, rhs: &T) -> Complex<T> {
        Complex {
            re: self.re.sub(rhs),
            im: self.im.clone(),
        }
    }
}

impl<T> Sub<Complex<T>, Complex<T>> for Complex<T> where T: Sub<T, T> {
    fn sub(&self, rhs: &Complex<T>) -> Complex<T> {
        Complex {
            re: self.re - rhs.re,
            im: self.im - rhs.im,
        }
    }
}

impl<T> Sub<Complex<T>, Complex<T>> for T where T: Neg<T> + Sub<T, T> {
    fn sub(&self, rhs: &Complex<T>) -> Complex<T> {
        Complex {
            re: self.sub(&rhs.re),
            im: -rhs.im,
        }
    }
}

impl<T> Zero for Complex<T> where T: Zero {
    fn zero() -> Complex<T> {
        Complex {
            re: Zero::zero(),
            im: Zero::zero(),
        }
    }
}

/// Mathematical operations on complex numbers
// FIXME (AI) `T` should be an associated output type
pub trait Math<T> {
    /// Computes the complex absolute value (also called norm, modulus or magnitude)
    fn abs(self) -> T;

    /// Computes the arc cosine
    fn acos(self) -> Self;

    /// Computes the arc hyperbolic cosine
    fn acosh(self) -> Self;

    /// Computes the argument (also called the phase angle)
    fn arg(self) -> T;

    /// Computes the arc sine
    fn asin(self) -> Self;

    /// Computes the arc hyperbolic sine
    fn asinh(self) -> Self;

    /// Computes the arc tangent
    fn atan(self) -> Self;

    /// Computes the arc hyperbolic tangent
    fn atanh(self) -> Self;

    /// Computes the arc cosine
    fn cos(self) -> Self;

    /// Computes the arc hyperbolic cosine
    fn cosh(self) -> Self;

    /// Computes the complex base-e exponential
    fn exp(self) -> Self;

    /// Returns the imaginary part
    fn imag(self) -> T;

    /// Computes the complex base-e logarithm
    fn log(self) -> Self;

    /// Computes the complex conjugate
    fn conj(self) -> Self;

    /// Computes the complex power
    fn pow(self, Self) -> Self;

    /// Computes the Riemann sphere projection
    fn proj(self) -> Self;

    /// Returns the real part
    fn real(self) -> T;

    /// Computes the arc sine
    fn sin(self) -> Self;

    /// Computes the arc hyperbolic sine
    fn sinh(self) -> Self;

    /// Computes the square root
    fn sqrt(self) -> Self;

    /// Computes the arc tangent
    fn tan(self) -> Self;

    /// Computes the arc hyperbolic tangent
    fn tanh(self) -> Self;
}

#[cfg(test)]
mod test {
    macro_rules! test {
        ($($ty:ident),+) => {$(
            mod $ty {
                use Complex;
                use $ty::I;

                #[test]
                fn constructor() {
                    assert_eq!(Complex::new(3., 4.), I * 4. + 3.)
                }
            })+
         }
    }

    test!(f32, f64)
}
<commit_msg>fix(lib): adapt to the new move semantics of binary operators<commit_after>//! Complex numbers

#![deny(missing_docs, warnings)]
#![feature(macro_rules)]

extern crate onezero;

use std::fmt;
use std::rand::{Rand, Rng};

use onezero::{One, Zero};

mod ffi;
mod math;

pub mod f32;
pub mod f64;

/// A complex number in Cartesian form.
#[repr(C)]
#[deriving(Clone, Copy, PartialEq)]
pub struct Complex<T> {
    /// The real part
    pub re: T,
    /// The imaginary part
    pub im: T,
}

/// Single precision complex number
#[allow(non_camel_case_types)]
pub type c64 = Complex<f32>;
/// Double precision complex number
#[allow(non_camel_case_types)]
pub type c128 = Complex<f64>;

impl<T> Complex<T> {
    /// Create a new complex number
    pub fn new(re: T, im: T) -> Complex<T> {
        Complex {
            im: im,
            re: re,
        }
    }
}

impl<T> Complex<T> where T: Add<T, T> + Clone + Mul<T, T> {
    fn norm_sqr(self) -> T {
        self.re.clone() * self.re + self.im.clone() * self.im
    }
}

impl<T> Add<T, Complex<T>> for Complex<T> where T: Add<T, T> + Clone {
    fn add(self, rhs: T) -> Complex<T> {
        Complex {
            re: self.re + rhs,
            im: self.im.clone(),
        }
    }
}

impl<T> Add<Complex<T>, Complex<T>> for Complex<T> where T: Add<T, T> {
    fn add(self, rhs: Complex<T>) -> Complex<T> {
        Complex {
            re: self.re + rhs.re,
            im: self.im + rhs.im,
        }
    }
}

impl<T> Add<Complex<T>, Complex<T>> for T where T: Add<T, T> + Clone {
    fn add(self, rhs: Complex<T>) -> Complex<T> {
        rhs + self
    }
}

impl<T> Div<T, Complex<T>> for Complex<T> where T: Clone + Div<T, T> {
    fn div(self, rhs: T) -> Complex<T> {
        Complex {
            re: self.re / rhs.clone(),
            im: self.im / rhs,
        }
    }
}

impl<T> Div<Complex<T>, Complex<T>> for Complex<T> where
    T: Add<T, T> + Clone + Div<T, T> + Mul<T, T> + Sub<T, T>
{
    fn div(self, rhs: Complex<T>) -> Complex<T> {
        let den = rhs.clone().norm_sqr();

        Complex {
            re: {
                self.re.clone() * rhs.re.clone() + self.im.clone() * rhs.im.clone()
            } / den.clone(),
            im: (self.im * rhs.re - self.re * rhs.im) / den,
        }
    }
}

impl<T> Div<Complex<T>, Complex<T>> for T where
    T: Add<T, T> + Clone + Div<T, T> + Mul<T, T> + Neg<T>,
{
    fn div(self, rhs: Complex<T>) -> Complex<T> {
        let den = rhs.clone().norm_sqr();

        Complex {
            re: (self.clone() * rhs.re) / den.clone(),
            im: -(self * rhs.im) / den,
        }
    }
}

impl<T> Mul<T, Complex<T>> for Complex<T> where T: Clone + Mul<T, T> {
    fn mul(self, rhs: T) -> Complex<T> {
        Complex {
            re: self.re * rhs.clone(),
            im: self.im * rhs,
        }
    }
}

impl<T> Mul<Complex<T>, Complex<T>> for Complex<T> where
    T: Add<T, T> + Clone + Mul<T, T> + Sub<T, T>,
{
    fn mul(self, rhs: Complex<T>) -> Complex<T> {
        Complex {
            re: self.re.clone() * rhs.re.clone() - self.im.clone() * rhs.im.clone(),
            im: self.re * rhs.im + self.im * rhs.re,
        }
    }
}

impl<T> Mul<Complex<T>, Complex<T>> for T where T: Clone + Mul<T, T> {
    fn mul(self, rhs: Complex<T>) -> Complex<T> {
        rhs * self
    }
}

impl<T> Neg<Complex<T>> for Complex<T> where T: Neg<T> {
    fn neg(&self) -> Complex<T> {
        Complex {
            re: -self.re,
            im: -self.im,
        }
    }
}

impl<T> One for Complex<T> where T: Mul<T, T> + One + Sub<T, T> + Zero {
    fn one() -> Complex<T> {
        Complex {
            re: One::one(),
            im: Zero::zero(),
        }
    }
}

impl<T> Rand for Complex<T> where T: Rand {
    fn rand<R>(rng: &mut R) -> Complex<T> where R: Rng {
        Complex::new(rng.gen(), rng.gen())
    }
}

impl<T> fmt::Show for Complex<T> where T: PartialOrd + fmt::Show + Zero {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.im < Zero::zero() {
            write!(f, "{}-{}i", self.re, self.im)
        } else {
            write!(f, "{}+{}i", self.re, self.im)
        }
    }
}

impl<T> Sub<T, Complex<T>> for Complex<T> where T: Clone + Sub<T, T> {
    fn sub(self, rhs: T) -> Complex<T> {
        Complex {
            re: self.re - rhs,
            im: self.im.clone(),
        }
    }
}

impl<T> Sub<Complex<T>, Complex<T>> for Complex<T> where T: Sub<T, T> {
    fn sub(self, rhs: Complex<T>) -> Complex<T> {
        Complex {
            re: self.re - rhs.re,
            im: self.im - rhs.im,
        }
    }
}

impl<T> Sub<Complex<T>, Complex<T>> for T where T: Neg<T> + Sub<T, T> {
    fn sub(self, rhs: Complex<T>) -> Complex<T> {
        Complex {
            re: self - rhs.re,
            im: -rhs.im,
        }
    }
}

impl<T> Zero for Complex<T> where T: Zero {
    fn zero() -> Complex<T> {
        Complex {
            re: Zero::zero(),
            im: Zero::zero(),
        }
    }
}

/// Mathematical operations on complex numbers
// FIXME (AI) `T` should be an associated output type
pub trait Math<T> {
    /// Computes the complex absolute value (also called norm, modulus or magnitude)
    fn abs(self) -> T;

    /// Computes the arc cosine
    fn acos(self) -> Self;

    /// Computes the arc hyperbolic cosine
    fn acosh(self) -> Self;

    /// Computes the argument (also called the phase angle)
    fn arg(self) -> T;

    /// Computes the arc sine
    fn asin(self) -> Self;

    /// Computes the arc hyperbolic sine
    fn asinh(self) -> Self;

    /// Computes the arc tangent
    fn atan(self) -> Self;

    /// Computes the arc hyperbolic tangent
    fn atanh(self) -> Self;

    /// Computes the arc cosine
    fn cos(self) -> Self;

    /// Computes the arc hyperbolic cosine
    fn cosh(self) -> Self;

    /// Computes the complex base-e exponential
    fn exp(self) -> Self;

    /// Returns the imaginary part
    fn imag(self) -> T;

    /// Computes the complex base-e logarithm
    fn log(self) -> Self;

    /// Computes the complex conjugate
    fn conj(self) -> Self;

    /// Computes the complex power
    fn pow(self, Self) -> Self;

    /// Computes the Riemann sphere projection
    fn proj(self) -> Self;

    /// Returns the real part
    fn real(self) -> T;

    /// Computes the arc sine
    fn sin(self) -> Self;

    /// Computes the arc hyperbolic sine
    fn sinh(self) -> Self;

    /// Computes the square root
    fn sqrt(self) -> Self;

    /// Computes the arc tangent
    fn tan(self) -> Self;

    /// Computes the arc hyperbolic tangent
    fn tanh(self) -> Self;
}

#[cfg(test)]
mod test {
    macro_rules! test {
        ($($ty:ident),+) => {$(
            mod $ty {
                use Complex;
                use $ty::I;

                #[test]
                fn constructor() {
                    assert_eq!(Complex::new(3., 4.), I * 4. + 3.)
                }
            })+
         }
    }

    test!(f32, f64)
}
<|endoftext|>


<commit_before>//! A work-stealing fork-join queue used to perform processors' work asynchronously.
//! This is intended to be short-lived. Long running asynchronous tasks should use another method.
//! For infinite loops, the longest-running of tasks, behavior will be as expected.
#![cfg_attr(nightly, feature(core_intrinsics))]

mod job;
mod queue;
mod pool;

use self::job::Job;
use self::pool::Pool;
use self::queue::Queue;

use std::io::Error;
use std::marker::PhantomData;
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;

const MAX_JOBS: usize = 4096;

// messages to workers.
enum ToWorker {
    Start, // start
    Clear, // run all jobs to completion, then reset the pool.
    Shutdown, // all workers are clear and no jobs are running. safe to tear down pools.
}
// messages to the leader from workers.
enum ToLeader {
    Cleared, // done clearing. will wait for start or shutdown
    Panicked,
}

struct WorkerHandle {
    tx: Sender<ToWorker>,
    rx: Receiver<ToLeader>,
    thread: Option<thread::JoinHandle<()>>,
}

// Finite state machine for controlling workers.
#[derive(Clone, Copy, PartialEq)]
enum State {
    Running, // running jobs normally. waiting for state change.
    Paused, // paused, waiting for start or shutdown message.
}

struct Worker {
    queues: Arc<Vec<Queue>>,
    pools: Arc<Vec<Pool>>,
    idx: usize, // the index of this worker's queue and pool in the Vec.
}

// TODO: implement !Sync for Worker.

impl Worker {
    // pop a job from the worker's queue, or steal one from the queue with the most work.
    unsafe fn pop_or_steal(&self) -> Option<*mut Job> {
        if let Some(job) = self.queues[self.idx].pop() {
            return Some(job);
        }

        // if the queue is empty (pop failed), we can clear the pool for this queue.
        // this works only because
        // A) we push pool-allocated jobs only onto the local queue,
        // B) pop gets priority when racing against "steal".
        self.pools[self.idx].reset();

        let (mut most_work, mut most_idx) = (0, None);
        for (i, queue) in self.queues.iter().enumerate() {
            let len = queue.len();
            if len > most_work {
                most_work = len;
                most_idx = Some(i);
            }
        }

        if let Some(idx) = most_idx {
            self.queues[idx].steal()
        } else {
            None
        }
    }

    // do a sweep through all the queues, saying whether all
    // were observed to be empty initially.
    fn clear_pass(&self) -> bool {
        let mut all_clear = true;
        for (idx, queue) in self.queues.iter().enumerate() {
            if idx != self.idx {
                while let Some(job) = queue.steal() {
                    all_clear = false;
                    unsafe { (*job).call(self) }
                }
            } else {
                while let Some(job) = unsafe { queue.pop() } {
                    all_clear = false;
                    unsafe { (*job).call(self) }
                }
            }
        }

        all_clear
    }

    fn clear(&self) {
        while !self.clear_pass() {}
    }

    // run the next job.
    unsafe fn run_next(&self) {
        if let Some(job) = self.pop_or_steal() {
            (*job).call(self)
        }
    }

    // This must be called on the thread the worker is active on.
    unsafe fn submit_internal<F>(&self, counter: *const AtomicUsize, f: F)
        where F: Send + FnOnce(&Worker)
    {
        let job = Job::new(counter, f);
        let job_ptr = self.pools[self.idx].alloc(job);
        self.queues[self.idx].push(job_ptr);
    }

    // construct a new spawning scope.
    // this waits for all jobs submitted internally
    // to complete.
    fn scope<'pool, 'new, F>(&'pool self, f: F)
        where F: FnOnce(&Spawner<'pool, 'new>)
    {
        let counter = AtomicUsize::new(0);
        let s = make_spawner(self, &counter);
        f(&s);

        while counter.load(Ordering::Acquire) != 0 {
            unsafe { self.run_next() }
        }
    }
}

/// A job spawner associated with a specific scope.
/// Jobs spawned using this may spawn new jobs with the same lifetime.
pub struct Spawner<'pool, 'scope> {
    worker: &'pool Worker,
    counter: *const AtomicUsize,
    // invariant lifetime.
    _marker: PhantomData<*mut &'scope mut ()>,
}

impl<'pool, 'scope> Spawner<'pool, 'scope> {
    /// Execute a function which necessarily outlives the scope which
    /// this resides in.
    pub fn submit<F>(&self, f: F)
        where F: 'scope + Send + FnOnce(&Spawner<'pool, 'scope>)
    {
        use std::mem;

        // for sending the counter pointer across thread boundaries.
        struct SendCounter(*const AtomicUsize);
        unsafe impl Send for SendCounter {}

        unsafe {
            // increment the counter first just in case, somehow, this job
            // gets grabbed before we have a chance to increment it,
            // and we wait for all jobs to complete.
            let counter: SendCounter = SendCounter(self.counter);
            (*self.counter).fetch_add(1, Ordering::AcqRel);
            self.worker.submit_internal(self.counter, move |worker| {
                let SendCounter(count_ptr) = counter;
                // make a new spawner associated with the same scope,
                // but with the correct worker for the thread -- so if
                // this job spawns any children, we won't break any
                // invariants by accessing other workers' queues/pools
                // in unexpected ways.
                let spawner = make_spawner(worker, count_ptr);
                f(&mem::transmute(spawner))
            });
        }
    }

    /// Construct a new spawning scope smaller than the one this spawner resides in.
    pub fn scope<'new, F>(&self, f: F)
        where 'scope: 'new,
              F: FnOnce(&Spawner<'pool, 'new>)
    {
        self.worker.scope(f);
    }

    /// Execute two closures, possibly asynchronously, and return their results.
    pub fn join<A, B, R_A, R_B>(&self, oper_a: A, oper_b: B) -> (R_A, R_B)
    where A: Send + FnOnce(&Spawner) -> R_A,
          B: Send + FnOnce(&Spawner) -> R_B,
          R_A: Send,
          R_B: Send
    {
        let mut a = None;
        let mut b = None;
        self.scope(|spawner| {
            spawner.submit(|s| a = Some(oper_a(s)));
            spawner.submit(|s| b = Some(oper_b(s)));
        });

        (a.unwrap(), b.unwrap())
    }
}
fn make_spawner<'a, 'b>(worker: &'a Worker, counter: *const AtomicUsize) -> Spawner<'a, 'b> {
    Spawner {
        worker: worker,
        counter: counter,
        _marker: PhantomData,
    }
}

fn worker_main(tx: Sender<ToLeader>, rx: Receiver<ToWorker>, worker: Worker) {
    struct PanicGuard(Sender<ToLeader>);
    impl Drop for PanicGuard {
        fn drop(&mut self) {
            if thread::panicking() {
                let _ = self.0.send(ToLeader::Panicked);
            }
        }
    }
    // if the worker for this thread panics,
    let _guard = PanicGuard(tx.clone());

    let mut state = State::Paused;
    loop {
        match state {
            State::Running => {
                match rx.try_recv() {
                    Ok(ToWorker::Clear) => {
                        worker.clear();
                        tx.send(ToLeader::Cleared).expect("Pool hung up on worker");
                        state = State::Paused;
                    }
                    Ok(_) => unreachable!(),
                    Err(TryRecvError::Disconnected) => panic!("Pool hung up on worker"),
                    _ => {}
                }

                unsafe { worker.run_next() }
            }

            State::Paused => {
                if let Ok(msg) = rx.recv() {
                    match msg {
                        ToWorker::Start => {
                            state = State::Running;
                            continue;
                        }

                        ToWorker::Shutdown => {
                            break;
                        }

                        _ => unreachable!(),
                    }
                } else {
                    panic!("Pool hung up on worker");
                }
            }
        }
    }
}

/// The work pool manages worker threads in a
/// work-stealing fork-join thread pool.
// The fields here are put in Vecs for cache contiguity.
pub struct WorkPool {
    workers: Vec<WorkerHandle>,
    local_worker: Worker,
    state: State,
}

impl WorkPool {
    /// Creates a work pool with `n` worker threads.
    pub fn new(n: usize) -> Result<Self, Error> {
        // one extra queue and pool for the job system.
        let queues = Arc::new((0..n + 1).map(|_| Queue::new()).collect::<Vec<_>>());
        let pools = Arc::new((0..n + 1).map(|_| Pool::new()).collect::<Vec<_>>());
        let mut workers = Vec::with_capacity(n);

        for i in 0..n {
            let (work_send, work_recv) = channel();
            let (lead_send, lead_recv) = channel();

            let worker = Worker {
                queues: queues.clone(),
                pools: pools.clone(),
                idx: i + 1,
            };

            let builder = thread::Builder::new().name(format!("worker_{}", i));
            let handle = try!(builder.spawn(|| worker_main(lead_send, work_recv, worker)));

            workers.push(WorkerHandle {
                tx: work_send,
                rx: lead_recv,
                thread: Some(handle),
            });
        }

        let mut pool = WorkPool {
            workers: workers,
            local_worker: Worker {
                queues: queues,
                pools: pools,
                idx: 0,
            },
            state: State::Paused,
        };

        pool.spin_up();

        Ok(pool)
    }

    /// Finish all current jobs which are queued, and synchronize the workers until
    /// it's time to start again.
    ///
    /// If any of the threads have panicked, that panic
    /// will be propagated to this thread. Until the next job is submitted,
    /// workers will block, allowing other threads to have higher priority.
    pub fn synchronize(&mut self) {
        self.clear_all();
    }

    /// Create a new spawning scope for submitting jobs.
    /// Any jobs submitted in this scope will be completed
    /// by the end of this function call.
    pub fn scope<'pool, 'new, F>(&'pool mut self, f: F)
        where F: FnOnce(&Spawner<'pool, 'new>)
    {
        self.spin_up();
        self.local_worker.scope(f);
    }

    /// Execute a job which strictly owns its contents.
    /// The execution of this function may be deferred to beyond
    /// this function call.
    /// In the general case, it is safe to submit jobs which only
    /// strictly outlive the pool. However, there is always the
    /// chance that the pool could be leaked, violating the invariant
    /// that the job is completed before the borrow of the data is.
    pub fn submit<'a, F>(&'a mut self, f: F)
        where F: 'static + Send + FnOnce(&Spawner<'a, 'static>)
    {
        self.spawner().submit(f);
    }

    /// Spin up all the workers, in case they were in a paused
    /// state.
    pub fn spin_up(&mut self) {
        if self.state != State::Running {
            for worker in &self.workers {
                worker.tx.send(ToWorker::Start).expect("Worker hung up on pool");
            }

            self.state = State::Running;
        }
    }

    /// Get a reference to the local spawner.
    /// This can only be used to spawn static jobs.
    pub fn spawner<'a>(&'a mut self) -> Spawner<'a, 'static> {
        use std::ptr;

        self.spin_up();
        make_spawner(&self.local_worker, ptr::null_mut())
    }

    // clear all the workers and sets the state to paused.
    fn clear_all(&mut self) {
        if self.state == State::Paused {
            return;
        }
        // send every worker a clear message
        for worker in &self.workers {
            worker.tx.send(ToWorker::Clear).ok().expect("Worker hung up on pool.");
        }

        // do a clear run on the local worker as well.
        self.local_worker.clear();

        let mut panicked = false;
        // wait for confirmation from each worker.
        // the queues are not guaranteed to be empty until the last one responds!
        for worker in &self.workers {
            match worker.rx.recv() {
                Ok(msg) => {
                    match msg {
                        ToLeader::Cleared => continue,
                        ToLeader::Panicked => {
                            panicked = true;
                        }
                    }
                }

                Err(_) => panic!("Worker hung up on job system."),
            }
        }

        // reset the counters in every queue so there's no chance of
        // overlap.
        for queue in self.local_worker.queues.iter() {
            // asserts that len == 0 in debug mode.
            queue.reset_counters();
        }

        // reset all the pools.
        for pool in self.local_worker.pools.iter() {
            pool.reset();
        }

        // cleared and panicked workers are waiting for a shutdown message.
        if panicked {
            panic!("Propagating worker thread panic")
        }

        self.state = State::Paused;
    }
}

impl Drop for WorkPool {
    fn drop(&mut self) {
        // finish all work.
        self.clear_all();

        // now tell every worker they can shut down safely.
        for worker in &self.workers {
            worker.tx.send(ToWorker::Shutdown).ok().expect("Worker hung up on job system");
        }

        // join the threads (although they should already be at this point).
        for worker in &mut self.workers {
            worker.thread.take().map(|handle| handle.join());
        }
    }
}

/// Create a pool with `n` worker threads.
pub fn make_pool(n: usize) -> Result<WorkPool, Error> {
    WorkPool::new(n)
}

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

    #[test]
    fn creation_destruction() {
        for i in 0..32 {
            let _ = WorkPool::new(i).unwrap();
        }
    }

    #[test]
    fn split_work() {
        let mut pool = WorkPool::new(4).unwrap();
        let mut v = vec![0; 1024];
        pool.scope(|spawner| {
            for (idx, v) in v.iter_mut().enumerate() {
                spawner.submit(move |_| {
                    *v += idx;
                });
            }
        });

        assert_eq!(v, (0..1024).collect::<Vec<_>>());
    }

    #[test]
    fn multilevel_scoping() {
        let mut pool = WorkPool::new(4).unwrap();
        pool.scope(|spawner| {
            let mut v = vec![0; 256];
            spawner.scope(|s| {
                for i in &mut v {
                    s.submit(move |_| *i += 1)
                }
            });
            // job is forcibly joined here.

            assert_eq!(v, (0..256).map(|_| 1).collect::<Vec<_>>())
        }); // any other jobs would be forcibly joined here.
    }

    #[test]
    fn multiple_synchronizations() {
        let mut pool = WorkPool::new(4).unwrap();
        for _ in 0..100 {
            pool.synchronize();
        }
    }

    #[test]
    fn outlives_pool() {
        let mut v = vec![0; 256];
        let mut pool = WorkPool::new(4).unwrap();

        // can only execute 'static functions here -- otherwise,
        // some person might make the dumb mistake of calling `forget` the
        // pool before it has the chance to run all submitted jobs.
        pool.submit(move |_| {
            for i in &mut v {
                *i += 1
            }
        });
    }

    #[test]
    #[should_panic]
    fn job_panic() {
        let mut pool = WorkPool::new(4).unwrap();

        pool.submit(|_| panic!("Eep!"));
    }
}
<commit_msg>check counter pointer before submitting<commit_after>//! A work-stealing fork-join queue used to perform processors' work asynchronously.
//! This is intended to be short-lived. Long running asynchronous tasks should use another method.
//! For infinite loops, the longest-running of tasks, behavior will be as expected.
#![cfg_attr(nightly, feature(core_intrinsics))]

mod job;
mod queue;
mod pool;

use self::job::Job;
use self::pool::Pool;
use self::queue::Queue;

use std::io::Error;
use std::marker::PhantomData;
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;

const MAX_JOBS: usize = 4096;

// messages to workers.
enum ToWorker {
    Start, // start
    Clear, // run all jobs to completion, then reset the pool.
    Shutdown, // all workers are clear and no jobs are running. safe to tear down pools.
}
// messages to the leader from workers.
enum ToLeader {
    Cleared, // done clearing. will wait for start or shutdown
    Panicked,
}

struct WorkerHandle {
    tx: Sender<ToWorker>,
    rx: Receiver<ToLeader>,
    thread: Option<thread::JoinHandle<()>>,
}

// Finite state machine for controlling workers.
#[derive(Clone, Copy, PartialEq)]
enum State {
    Running, // running jobs normally. waiting for state change.
    Paused, // paused, waiting for start or shutdown message.
}

struct Worker {
    queues: Arc<Vec<Queue>>,
    pools: Arc<Vec<Pool>>,
    idx: usize, // the index of this worker's queue and pool in the Vec.
}

// TODO: implement !Sync for Worker.

impl Worker {
    // pop a job from the worker's queue, or steal one from the queue with the most work.
    unsafe fn pop_or_steal(&self) -> Option<*mut Job> {
        if let Some(job) = self.queues[self.idx].pop() {
            return Some(job);
        }

        // if the queue is empty (pop failed), we can clear the pool for this queue.
        // this works only because
        // A) we push pool-allocated jobs only onto the local queue,
        // B) pop gets priority when racing against "steal".
        self.pools[self.idx].reset();

        let (mut most_work, mut most_idx) = (0, None);
        for (i, queue) in self.queues.iter().enumerate() {
            let len = queue.len();
            if len > most_work {
                most_work = len;
                most_idx = Some(i);
            }
        }

        if let Some(idx) = most_idx {
            self.queues[idx].steal()
        } else {
            None
        }
    }

    // do a sweep through all the queues, saying whether all
    // were observed to be empty initially.
    fn clear_pass(&self) -> bool {
        let mut all_clear = true;
        for (idx, queue) in self.queues.iter().enumerate() {
            if idx != self.idx {
                while let Some(job) = queue.steal() {
                    all_clear = false;
                    unsafe { (*job).call(self) }
                }
            } else {
                while let Some(job) = unsafe { queue.pop() } {
                    all_clear = false;
                    unsafe { (*job).call(self) }
                }
            }
        }

        all_clear
    }

    fn clear(&self) {
        while !self.clear_pass() {}
    }

    // run the next job.
    unsafe fn run_next(&self) {
        if let Some(job) = self.pop_or_steal() {
            (*job).call(self)
        }
    }

    // This must be called on the thread the worker is active on.
    unsafe fn submit_internal<F>(&self, counter: *const AtomicUsize, f: F)
        where F: Send + FnOnce(&Worker)
    {
        let job = Job::new(counter, f);
        let job_ptr = self.pools[self.idx].alloc(job);
        self.queues[self.idx].push(job_ptr);
    }

    // construct a new spawning scope.
    // this waits for all jobs submitted internally
    // to complete.
    fn scope<'pool, 'new, F>(&'pool self, f: F)
        where F: FnOnce(&Spawner<'pool, 'new>)
    {
        let counter = AtomicUsize::new(0);
        let s = make_spawner(self, &counter);
        f(&s);

        while counter.load(Ordering::Acquire) != 0 {
            unsafe { self.run_next() }
        }
    }
}

/// A job spawner associated with a specific scope.
/// Jobs spawned using this may spawn new jobs with the same lifetime.
pub struct Spawner<'pool, 'scope> {
    worker: &'pool Worker,
    counter: *const AtomicUsize,
    // invariant lifetime.
    _marker: PhantomData<*mut &'scope mut ()>,
}

impl<'pool, 'scope> Spawner<'pool, 'scope> {
    /// Execute a function which necessarily outlives the scope which
    /// this resides in.
    pub fn submit<F>(&self, f: F)
        where F: 'scope + Send + FnOnce(&Spawner<'pool, 'scope>)
    {
        use std::mem;

        // for sending the counter pointer across thread boundaries.
        struct SendCounter(*const AtomicUsize);
        unsafe impl Send for SendCounter {}

        unsafe {
            // increment the counter first just in case, somehow, this job
            // gets grabbed before we have a chance to increment it,
            // and we wait for all jobs to complete.
            let counter: SendCounter = SendCounter(self.counter);
            if !self.counter.is_null() {
                (*self.counter).fetch_add(1, Ordering::AcqRel);
            }
            self.worker.submit_internal(self.counter, move |worker| {
                let SendCounter(count_ptr) = counter;
                // make a new spawner associated with the same scope,
                // but with the correct worker for the thread -- so if
                // this job spawns any children, we won't break any
                // invariants by accessing other workers' queues/pools
                // in unexpected ways.
                let spawner = make_spawner(worker, count_ptr);
                f(&mem::transmute(spawner))
            });
        }
    }

    /// Construct a new spawning scope smaller than the one this spawner resides in.
    pub fn scope<'new, F>(&self, f: F)
        where 'scope: 'new,
              F: FnOnce(&Spawner<'pool, 'new>)
    {
        self.worker.scope(f);
    }

    /// Execute two closures, possibly asynchronously, and return their results.
    pub fn join<A, B, R_A, R_B>(&self, oper_a: A, oper_b: B) -> (R_A, R_B)
    where A: Send + FnOnce(&Spawner) -> R_A,
          B: Send + FnOnce(&Spawner) -> R_B,
          R_A: Send,
          R_B: Send
    {
        let mut a = None;
        let mut b = None;
        self.scope(|spawner| {
            spawner.submit(|s| a = Some(oper_a(s)));
            spawner.submit(|s| b = Some(oper_b(s)));
        });

        (a.unwrap(), b.unwrap())
    }
}
fn make_spawner<'a, 'b>(worker: &'a Worker, counter: *const AtomicUsize) -> Spawner<'a, 'b> {
    Spawner {
        worker: worker,
        counter: counter,
        _marker: PhantomData,
    }
}

fn worker_main(tx: Sender<ToLeader>, rx: Receiver<ToWorker>, worker: Worker) {
    struct PanicGuard(Sender<ToLeader>);
    impl Drop for PanicGuard {
        fn drop(&mut self) {
            if thread::panicking() {
                let _ = self.0.send(ToLeader::Panicked);
            }
        }
    }
    // if the worker for this thread panics,
    let _guard = PanicGuard(tx.clone());

    let mut state = State::Paused;
    loop {
        match state {
            State::Running => {
                match rx.try_recv() {
                    Ok(ToWorker::Clear) => {
                        worker.clear();
                        tx.send(ToLeader::Cleared).expect("Pool hung up on worker");
                        state = State::Paused;
                    }
                    Ok(_) => unreachable!(),
                    Err(TryRecvError::Disconnected) => panic!("Pool hung up on worker"),
                    _ => {}
                }

                unsafe { worker.run_next() }
            }

            State::Paused => {
                if let Ok(msg) = rx.recv() {
                    match msg {
                        ToWorker::Start => {
                            state = State::Running;
                            continue;
                        }

                        ToWorker::Shutdown => {
                            break;
                        }

                        _ => unreachable!(),
                    }
                } else {
                    panic!("Pool hung up on worker");
                }
            }
        }
    }
}

/// The work pool manages worker threads in a
/// work-stealing fork-join thread pool.
// The fields here are put in Vecs for cache contiguity.
pub struct WorkPool {
    workers: Vec<WorkerHandle>,
    local_worker: Worker,
    state: State,
}

impl WorkPool {
    /// Creates a work pool with `n` worker threads.
    pub fn new(n: usize) -> Result<Self, Error> {
        // one extra queue and pool for the job system.
        let queues = Arc::new((0..n + 1).map(|_| Queue::new()).collect::<Vec<_>>());
        let pools = Arc::new((0..n + 1).map(|_| Pool::new()).collect::<Vec<_>>());
        let mut workers = Vec::with_capacity(n);

        for i in 0..n {
            let (work_send, work_recv) = channel();
            let (lead_send, lead_recv) = channel();

            let worker = Worker {
                queues: queues.clone(),
                pools: pools.clone(),
                idx: i + 1,
            };

            let builder = thread::Builder::new().name(format!("worker_{}", i));
            let handle = try!(builder.spawn(|| worker_main(lead_send, work_recv, worker)));

            workers.push(WorkerHandle {
                tx: work_send,
                rx: lead_recv,
                thread: Some(handle),
            });
        }

        let mut pool = WorkPool {
            workers: workers,
            local_worker: Worker {
                queues: queues,
                pools: pools,
                idx: 0,
            },
            state: State::Paused,
        };

        pool.spin_up();

        Ok(pool)
    }

    /// Finish all current jobs which are queued, and synchronize the workers until
    /// it's time to start again.
    ///
    /// If any of the threads have panicked, that panic
    /// will be propagated to this thread. Until the next job is submitted,
    /// workers will block, allowing other threads to have higher priority.
    pub fn synchronize(&mut self) {
        self.clear_all();
    }

    /// Create a new spawning scope for submitting jobs.
    /// Any jobs submitted in this scope will be completed
    /// by the end of this function call.
    pub fn scope<'pool, 'new, F>(&'pool mut self, f: F)
        where F: FnOnce(&Spawner<'pool, 'new>)
    {
        self.spin_up();
        self.local_worker.scope(f);
    }

    /// Execute a job which strictly owns its contents.
    /// The execution of this function may be deferred to beyond
    /// this function call.
    /// In the general case, it is safe to submit jobs which only
    /// strictly outlive the pool. However, there is always the
    /// chance that the pool could be leaked, violating the invariant
    /// that the job is completed before the borrow of the data is.
    pub fn submit<'a, F>(&'a mut self, f: F)
        where F: 'static + Send + FnOnce(&Spawner<'a, 'static>)
    {
        self.spawner().submit(f);
    }

    /// Spin up all the workers, in case they were in a paused
    /// state.
    pub fn spin_up(&mut self) {
        if self.state != State::Running {
            for worker in &self.workers {
                worker.tx.send(ToWorker::Start).expect("Worker hung up on pool");
            }

            self.state = State::Running;
        }
    }

    /// Get a reference to the local spawner.
    /// This can only be used to spawn static jobs.
    pub fn spawner<'a>(&'a mut self) -> Spawner<'a, 'static> {
        use std::ptr;

        self.spin_up();
        make_spawner(&self.local_worker, ptr::null_mut())
    }

    // clear all the workers and sets the state to paused.
    fn clear_all(&mut self) {
        if self.state == State::Paused {
            return;
        }
        // send every worker a clear message
        for worker in &self.workers {
            worker.tx.send(ToWorker::Clear).ok().expect("Worker hung up on pool.");
        }

        // do a clear run on the local worker as well.
        self.local_worker.clear();

        let mut panicked = false;
        // wait for confirmation from each worker.
        // the queues are not guaranteed to be empty until the last one responds!
        for worker in &self.workers {
            match worker.rx.recv() {
                Ok(msg) => {
                    match msg {
                        ToLeader::Cleared => continue,
                        ToLeader::Panicked => {
                            panicked = true;
                        }
                    }
                }

                Err(_) => panic!("Worker hung up on job system."),
            }
        }

        // reset the counters in every queue so there's no chance of
        // overlap.
        for queue in self.local_worker.queues.iter() {
            // asserts that len == 0 in debug mode.
            queue.reset_counters();
        }

        // reset all the pools.
        for pool in self.local_worker.pools.iter() {
            pool.reset();
        }

        // cleared and panicked workers are waiting for a shutdown message.
        if panicked {
            panic!("Propagating worker thread panic")
        }

        self.state = State::Paused;
    }
}

impl Drop for WorkPool {
    fn drop(&mut self) {
        // finish all work.
        self.clear_all();

        // now tell every worker they can shut down safely.
        for worker in &self.workers {
            worker.tx.send(ToWorker::Shutdown).ok().expect("Worker hung up on job system");
        }

        // join the threads (although they should already be at this point).
        for worker in &mut self.workers {
            worker.thread.take().map(|handle| handle.join());
        }
    }
}

/// Create a pool with `n` worker threads.
pub fn make_pool(n: usize) -> Result<WorkPool, Error> {
    WorkPool::new(n)
}

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

    #[test]
    fn creation_destruction() {
        for i in 0..32 {
            let _ = WorkPool::new(i).unwrap();
        }
    }

    #[test]
    fn split_work() {
        let mut pool = WorkPool::new(4).unwrap();
        let mut v = vec![0; 1024];
        pool.scope(|spawner| {
            for (idx, v) in v.iter_mut().enumerate() {
                spawner.submit(move |_| {
                    *v += idx;
                });
            }
        });

        assert_eq!(v, (0..1024).collect::<Vec<_>>());
    }

    #[test]
    fn multilevel_scoping() {
        let mut pool = WorkPool::new(4).unwrap();
        pool.scope(|spawner| {
            let mut v = vec![0; 256];
            spawner.scope(|s| {
                for i in &mut v {
                    s.submit(move |_| *i += 1)
                }
            });
            // job is forcibly joined here.

            assert_eq!(v, (0..256).map(|_| 1).collect::<Vec<_>>())
        }); // any other jobs would be forcibly joined here.
    }

    #[test]
    fn multiple_synchronizations() {
        let mut pool = WorkPool::new(4).unwrap();
        for _ in 0..100 {
            pool.synchronize();
        }
    }

    #[test]
    fn outlives_pool() {
        let mut v = vec![0; 256];
        let mut pool = WorkPool::new(4).unwrap();

        // can only execute 'static functions here -- otherwise,
        // some person might make the dumb mistake of calling `forget` the
        // pool before it has the chance to run all submitted jobs.
        pool.submit(move |_| {
            for i in &mut v {
                *i += 1
            }
        });
    }

    #[test]
    #[should_panic]
    fn job_panic() {
        let mut pool = WorkPool::new(4).unwrap();

        pool.submit(|_| panic!("Eep!"));
    }
}
<|endoftext|>