<commit_before>//! `petgraph` is a graph data structure library.
//!
//! Graphs are collections of nodes, and edges between nodes. `petgraph`
//! provides several [graph types](index.html#graph-types) (each differing in the
//! tradeoffs taken in their internal representation),
//! [algorithms](./algo/index.html#functions) on those graphs, and functionality to
//! [output graphs](./doc/petgraph/dot/struct.Dot.html) in
//! [`graphviz`](https://www.graphviz.org/) format. Both nodes and edges
//! can have arbitrary associated data, and edges may be either directed or undirected.
//!
//! # Example
//!
//! ```rust
//! use petgraph::graph::{NodeIndex, UnGraph};
//! use petgraph::algo::{dijkstra, min_spanning_tree};
//! use petgraph::data::FromElements;
//! use petgraph::dot::{Dot, Config};
//!
//! // Create an undirected graph with `i32` nodes and edges with `()` associated data.
//! let g = UnGraph::<i32, ()>::from_edges(&[
//!     (1, 2), (2, 3), (3, 4),
//!     (1, 4)]);
//!
//! // Find the shortest path from `1` to `4` using `1` as the cost for every edge.
//! let node_map = dijkstra(&g, 1.into(), Some(4.into()), |_| 1);
//! assert_eq!(&1i32, node_map.get(&NodeIndex::new(4)).unwrap());
//!
//! // Get the minimum spanning tree of the graph as a new graph, and check that
//! // one edge was trimmed.
//! let mst = UnGraph::<_, _>::from_elements(min_spanning_tree(&g));
//! assert_eq!(g.raw_edges().len() - 1, mst.raw_edges().len());
//!
//! // Output the tree to `graphviz` `DOT` format
//! println!("{:?}", Dot::with_config(&mst, &[Config::EdgeNoLabel]));
//! // graph {
//! //     0 [label="\"0\""]
//! //     1 [label="\"0\""]
//! //     2 [label="\"0\""]
//! //     3 [label="\"0\""]
//! //     1 -- 2
//! //     3 -- 4
//! //     2 -- 3
//! // }
//! ```
//!
//! # Graph types
//!
//! * [`Graph`](./graph/struct.Graph.html) -
//!   An adjacency list graph with arbitrary associated data.
//! * [`StableGraph`](./stable_graph/struct.StableGraph.html) -
//!   Similar to `Graph`, but it keeps indices stable across removals.
//! * [`GraphMap`](./graphmap/struct.GraphMap.html) -
//!   An adjacency list graph backed by a hash table. The node identifiers are the keys
//!   into the table.
//! * [`MatrixGraph`](./matrix_graph/struct.MatrixGraph.html) -
//!   An adjacency matrix graph.
//! * [`CSR`](./csr/struct.Csr.html) -
//!   A sparse adjacency matrix graph with arbitrary associated data.
//!
//! ### Generic parameters
//!
//! Each graph type is generic over a handful of parameters. All graphs share 3 common
//! parameters, `N`, `E`, and `Ty`. This is a broad overview of what those are. Each
//! type's documentation will have finer detail on these parameters.
//!
//! `N` & `E` are called *weights* in this implementation, and are associated with
//! nodes and edges respectively. They can generally be of arbitrary type, and don't have to
//! be what you might conventionally consider weight-like. For example, using `&str` for `N`
//! will work. Many algorithms that require costs let you provide a cost function that
//! translates your `N` and `E` weights into costs appropriate to the algorithm. Some graph
//! types and choices do impose bounds on `N` or `E`.
//! [`min_spanning_tree`](./algo/fn.min_spanning_tree.html) for example requires edge weights that
//! implement [`PartialOrd`](https://doc.rust-lang.org/stable/core/cmp/trait.PartialOrd.html).
//! [`GraphMap`](./graphmap/struct.GraphMap.html) requires node weights that can serve as hash
//! map keys, since that graph type does not create standalone node indices.
//!
//! `Ty` controls whether edges are [`Directed`](./petgraph/enum.Directed.html) or
//! [`Undirected`](./petgraph/enum.Unirected.html).
//!
//! `Ix` appears on graph types that use indices. It is exposed so you can control
//! the size of node and edge indices, and therefore the memory footprint of your graphs.
//! Allowed values are `u8`, `u16`, `u32`, and `usize`, with `u32` being the default.
//!
//! ### Shorthand types
//!
//! Each graph type vends a few shorthand type definitions that name some specific
//! generic choices. For example, [`DiGraph<_, _>`](./graph/type.DiGraph.html) is shorthand
//! for [`Graph<_, _, Undirected>`](graph/struct.Graph.html).
//! [`UnMatrix<_, _>`](./matrix_graph/type.UnMatrix.html) is shorthand for
//! [`MatrixGraph<_, _, Undirected>`](./matrix_graph/struct.MatrixGraph.html). Each graph type's
//! module documentation lists the available shorthand types.
//!
//! # Crate features
//!
//! * **serde-1** -
//!   Defaults off. Enables serialization for ``Graph, StableGraph`` using
//!   [`serde 1.0`](https://crates.io/crates/serde). May require a more recent version
//!   of Rust than petgraph alone.
//! * **graphmap** -
//!   Defaults on. Enables [`GraphMap`](./graphmap/struct.GraphMap.html).
//! * **stable_graph** -
//!   Defaults on. Enables [`StableGraph`](./stable_graph/struct.StableGraph.html).
//! * **matrix_graph** -
//!   Defaults on. Enables [`MatrixGraph`](./matrix_graph/struct.MatrixGraph.html).
//!
#![doc(html_root_url = "https://docs.rs/petgraph/0.4/")]

extern crate fixedbitset;
#[cfg(feature = "graphmap")]
extern crate indexmap;

#[cfg(feature = "serde-1")]
extern crate serde;
#[cfg(feature = "serde-1")]
#[macro_use]
extern crate serde_derive;

#[cfg(all(feature = "serde-1", test))]
extern crate itertools;

#[doc(no_inline)]
pub use crate::graph::Graph;

pub use crate::Direction::{Incoming, Outgoing};

#[macro_use]
mod macros;
mod scored;

// these modules define trait-implementing macros
#[macro_use]
pub mod visit;
#[macro_use]
pub mod data;

pub mod algo;
mod astar;
pub mod csr;
mod dijkstra;
pub mod dot;
#[cfg(feature = "generate")]
pub mod generate;
mod graph_impl;
#[cfg(feature = "graphmap")]
pub mod graphmap;
mod isomorphism;
mod iter_format;
mod iter_utils;
#[cfg(feature = "matrix_graph")]
pub mod matrix_graph;
#[cfg(feature = "quickcheck")]
mod quickcheck;
#[cfg(feature = "serde-1")]
mod serde_utils;
mod simple_paths;
mod traits_graph;
pub mod unionfind;
mod util;

pub mod prelude;

/// `Graph<N, E, Ty, Ix>` is a graph datastructure using an adjacency list representation.
pub mod graph {
    pub use crate::graph_impl::{
        edge_index, node_index, DefaultIx, DiGraph, Edge, EdgeIndex, EdgeIndices, EdgeReference,
        EdgeReferences, EdgeWeightsMut, Edges, EdgesConnecting, Externals, Frozen, Graph,
        GraphIndex, IndexType, Neighbors, Node, NodeIndex, NodeIndices, NodeReferences,
        NodeWeightsMut, UnGraph, WalkNeighbors,
    };
}

#[cfg(feature = "stable_graph")]
pub use crate::graph_impl::stable_graph;

macro_rules! copyclone {
    ($name:ident) => {
        impl Clone for $name {
            #[inline]
            fn clone(&self) -> Self {
                *self
            }
        }
    };
}

// Index into the NodeIndex and EdgeIndex arrays
/// Edge direction.
#[derive(Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
#[repr(usize)]
pub enum Direction {
    /// An `Outgoing` edge is an outward edge *from* the current node.
    Outgoing = 0,
    /// An `Incoming` edge is an inbound edge *to* the current node.
    Incoming = 1,
}

copyclone!(Direction);

impl Direction {
    /// Return the opposite `Direction`.
    #[inline]
    pub fn opposite(&self) -> Direction {
        match *self {
            Outgoing => Incoming,
            Incoming => Outgoing,
        }
    }

    /// Return `0` for `Outgoing` and `1` for `Incoming`.
    #[inline]
    pub fn index(&self) -> usize {
        (*self as usize) & 0x1
    }
}

#[doc(hidden)]
pub use crate::Direction as EdgeDirection;

/// Marker type for a directed graph.
#[derive(Copy, Debug)]
pub enum Directed {}
copyclone!(Directed);

/// Marker type for an undirected graph.
#[derive(Copy, Debug)]
pub enum Undirected {}
copyclone!(Undirected);

/// A graph's edge type determines whether it has directed edges or not.
pub trait EdgeType {
    fn is_directed() -> bool;
}

impl EdgeType for Directed {
    #[inline]
    fn is_directed() -> bool {
        true
    }
}

impl EdgeType for Undirected {
    #[inline]
    fn is_directed() -> bool {
        false
    }
}

/// Convert an element like `(i, j)` or `(i, j, w)` into
/// a triple of source, target, edge weight.
///
/// For `Graph::from_edges` and `GraphMap::from_edges`.
pub trait IntoWeightedEdge<E> {
    type NodeId;
    fn into_weighted_edge(self) -> (Self::NodeId, Self::NodeId, E);
}

impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix)
where
    E: Default,
{
    type NodeId = Ix;

    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        let (s, t) = self;
        (s, t, E::default())
    }
}

impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix, E) {
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        self
    }
}

impl<'a, Ix, E> IntoWeightedEdge<E> for (Ix, Ix, &'a E)
where
    E: Clone,
{
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        let (a, b, c) = self;
        (a, b, c.clone())
    }
}

impl<'a, Ix, E> IntoWeightedEdge<E> for &'a (Ix, Ix)
where
    Ix: Copy,
    E: Default,
{
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        let (s, t) = *self;
        (s, t, E::default())
    }
}

impl<'a, Ix, E> IntoWeightedEdge<E> for &'a (Ix, Ix, E)
where
    Ix: Copy,
    E: Clone,
{
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        self.clone()
    }
}
<commit_msg>Fix typo in explaining of shorthand types<commit_after>//! `petgraph` is a graph data structure library.
//!
//! Graphs are collections of nodes, and edges between nodes. `petgraph`
//! provides several [graph types](index.html#graph-types) (each differing in the
//! tradeoffs taken in their internal representation),
//! [algorithms](./algo/index.html#functions) on those graphs, and functionality to
//! [output graphs](./doc/petgraph/dot/struct.Dot.html) in
//! [`graphviz`](https://www.graphviz.org/) format. Both nodes and edges
//! can have arbitrary associated data, and edges may be either directed or undirected.
//!
//! # Example
//!
//! ```rust
//! use petgraph::graph::{NodeIndex, UnGraph};
//! use petgraph::algo::{dijkstra, min_spanning_tree};
//! use petgraph::data::FromElements;
//! use petgraph::dot::{Dot, Config};
//!
//! // Create an undirected graph with `i32` nodes and edges with `()` associated data.
//! let g = UnGraph::<i32, ()>::from_edges(&[
//!     (1, 2), (2, 3), (3, 4),
//!     (1, 4)]);
//!
//! // Find the shortest path from `1` to `4` using `1` as the cost for every edge.
//! let node_map = dijkstra(&g, 1.into(), Some(4.into()), |_| 1);
//! assert_eq!(&1i32, node_map.get(&NodeIndex::new(4)).unwrap());
//!
//! // Get the minimum spanning tree of the graph as a new graph, and check that
//! // one edge was trimmed.
//! let mst = UnGraph::<_, _>::from_elements(min_spanning_tree(&g));
//! assert_eq!(g.raw_edges().len() - 1, mst.raw_edges().len());
//!
//! // Output the tree to `graphviz` `DOT` format
//! println!("{:?}", Dot::with_config(&mst, &[Config::EdgeNoLabel]));
//! // graph {
//! //     0 [label="\"0\""]
//! //     1 [label="\"0\""]
//! //     2 [label="\"0\""]
//! //     3 [label="\"0\""]
//! //     1 -- 2
//! //     3 -- 4
//! //     2 -- 3
//! // }
//! ```
//!
//! # Graph types
//!
//! * [`Graph`](./graph/struct.Graph.html) -
//!   An adjacency list graph with arbitrary associated data.
//! * [`StableGraph`](./stable_graph/struct.StableGraph.html) -
//!   Similar to `Graph`, but it keeps indices stable across removals.
//! * [`GraphMap`](./graphmap/struct.GraphMap.html) -
//!   An adjacency list graph backed by a hash table. The node identifiers are the keys
//!   into the table.
//! * [`MatrixGraph`](./matrix_graph/struct.MatrixGraph.html) -
//!   An adjacency matrix graph.
//! * [`CSR`](./csr/struct.Csr.html) -
//!   A sparse adjacency matrix graph with arbitrary associated data.
//!
//! ### Generic parameters
//!
//! Each graph type is generic over a handful of parameters. All graphs share 3 common
//! parameters, `N`, `E`, and `Ty`. This is a broad overview of what those are. Each
//! type's documentation will have finer detail on these parameters.
//!
//! `N` & `E` are called *weights* in this implementation, and are associated with
//! nodes and edges respectively. They can generally be of arbitrary type, and don't have to
//! be what you might conventionally consider weight-like. For example, using `&str` for `N`
//! will work. Many algorithms that require costs let you provide a cost function that
//! translates your `N` and `E` weights into costs appropriate to the algorithm. Some graph
//! types and choices do impose bounds on `N` or `E`.
//! [`min_spanning_tree`](./algo/fn.min_spanning_tree.html) for example requires edge weights that
//! implement [`PartialOrd`](https://doc.rust-lang.org/stable/core/cmp/trait.PartialOrd.html).
//! [`GraphMap`](./graphmap/struct.GraphMap.html) requires node weights that can serve as hash
//! map keys, since that graph type does not create standalone node indices.
//!
//! `Ty` controls whether edges are [`Directed`](./petgraph/enum.Directed.html) or
//! [`Undirected`](./petgraph/enum.Unirected.html).
//!
//! `Ix` appears on graph types that use indices. It is exposed so you can control
//! the size of node and edge indices, and therefore the memory footprint of your graphs.
//! Allowed values are `u8`, `u16`, `u32`, and `usize`, with `u32` being the default.
//!
//! ### Shorthand types
//!
//! Each graph type vends a few shorthand type definitions that name some specific
//! generic choices. For example, [`DiGraph<_, _>`](./graph/type.DiGraph.html) is shorthand
//! for [`Graph<_, _, Directed>`](graph/struct.Graph.html).
//! [`UnMatrix<_, _>`](./matrix_graph/type.UnMatrix.html) is shorthand for
//! [`MatrixGraph<_, _, Undirected>`](./matrix_graph/struct.MatrixGraph.html). Each graph type's
//! module documentation lists the available shorthand types.
//!
//! # Crate features
//!
//! * **serde-1** -
//!   Defaults off. Enables serialization for ``Graph, StableGraph`` using
//!   [`serde 1.0`](https://crates.io/crates/serde). May require a more recent version
//!   of Rust than petgraph alone.
//! * **graphmap** -
//!   Defaults on. Enables [`GraphMap`](./graphmap/struct.GraphMap.html).
//! * **stable_graph** -
//!   Defaults on. Enables [`StableGraph`](./stable_graph/struct.StableGraph.html).
//! * **matrix_graph** -
//!   Defaults on. Enables [`MatrixGraph`](./matrix_graph/struct.MatrixGraph.html).
//!
#![doc(html_root_url = "https://docs.rs/petgraph/0.4/")]

extern crate fixedbitset;
#[cfg(feature = "graphmap")]
extern crate indexmap;

#[cfg(feature = "serde-1")]
extern crate serde;
#[cfg(feature = "serde-1")]
#[macro_use]
extern crate serde_derive;

#[cfg(all(feature = "serde-1", test))]
extern crate itertools;

#[doc(no_inline)]
pub use crate::graph::Graph;

pub use crate::Direction::{Incoming, Outgoing};

#[macro_use]
mod macros;
mod scored;

// these modules define trait-implementing macros
#[macro_use]
pub mod visit;
#[macro_use]
pub mod data;

pub mod algo;
mod astar;
pub mod csr;
mod dijkstra;
pub mod dot;
#[cfg(feature = "generate")]
pub mod generate;
mod graph_impl;
#[cfg(feature = "graphmap")]
pub mod graphmap;
mod isomorphism;
mod iter_format;
mod iter_utils;
#[cfg(feature = "matrix_graph")]
pub mod matrix_graph;
#[cfg(feature = "quickcheck")]
mod quickcheck;
#[cfg(feature = "serde-1")]
mod serde_utils;
mod simple_paths;
mod traits_graph;
pub mod unionfind;
mod util;

pub mod prelude;

/// `Graph<N, E, Ty, Ix>` is a graph datastructure using an adjacency list representation.
pub mod graph {
    pub use crate::graph_impl::{
        edge_index, node_index, DefaultIx, DiGraph, Edge, EdgeIndex, EdgeIndices, EdgeReference,
        EdgeReferences, EdgeWeightsMut, Edges, EdgesConnecting, Externals, Frozen, Graph,
        GraphIndex, IndexType, Neighbors, Node, NodeIndex, NodeIndices, NodeReferences,
        NodeWeightsMut, UnGraph, WalkNeighbors,
    };
}

#[cfg(feature = "stable_graph")]
pub use crate::graph_impl::stable_graph;

macro_rules! copyclone {
    ($name:ident) => {
        impl Clone for $name {
            #[inline]
            fn clone(&self) -> Self {
                *self
            }
        }
    };
}

// Index into the NodeIndex and EdgeIndex arrays
/// Edge direction.
#[derive(Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
#[repr(usize)]
pub enum Direction {
    /// An `Outgoing` edge is an outward edge *from* the current node.
    Outgoing = 0,
    /// An `Incoming` edge is an inbound edge *to* the current node.
    Incoming = 1,
}

copyclone!(Direction);

impl Direction {
    /// Return the opposite `Direction`.
    #[inline]
    pub fn opposite(&self) -> Direction {
        match *self {
            Outgoing => Incoming,
            Incoming => Outgoing,
        }
    }

    /// Return `0` for `Outgoing` and `1` for `Incoming`.
    #[inline]
    pub fn index(&self) -> usize {
        (*self as usize) & 0x1
    }
}

#[doc(hidden)]
pub use crate::Direction as EdgeDirection;

/// Marker type for a directed graph.
#[derive(Copy, Debug)]
pub enum Directed {}
copyclone!(Directed);

/// Marker type for an undirected graph.
#[derive(Copy, Debug)]
pub enum Undirected {}
copyclone!(Undirected);

/// A graph's edge type determines whether it has directed edges or not.
pub trait EdgeType {
    fn is_directed() -> bool;
}

impl EdgeType for Directed {
    #[inline]
    fn is_directed() -> bool {
        true
    }
}

impl EdgeType for Undirected {
    #[inline]
    fn is_directed() -> bool {
        false
    }
}

/// Convert an element like `(i, j)` or `(i, j, w)` into
/// a triple of source, target, edge weight.
///
/// For `Graph::from_edges` and `GraphMap::from_edges`.
pub trait IntoWeightedEdge<E> {
    type NodeId;
    fn into_weighted_edge(self) -> (Self::NodeId, Self::NodeId, E);
}

impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix)
where
    E: Default,
{
    type NodeId = Ix;

    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        let (s, t) = self;
        (s, t, E::default())
    }
}

impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix, E) {
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        self
    }
}

impl<'a, Ix, E> IntoWeightedEdge<E> for (Ix, Ix, &'a E)
where
    E: Clone,
{
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        let (a, b, c) = self;
        (a, b, c.clone())
    }
}

impl<'a, Ix, E> IntoWeightedEdge<E> for &'a (Ix, Ix)
where
    Ix: Copy,
    E: Default,
{
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        let (s, t) = *self;
        (s, t, E::default())
    }
}

impl<'a, Ix, E> IntoWeightedEdge<E> for &'a (Ix, Ix, E)
where
    Ix: Copy,
    E: Clone,
{
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        self.clone()
    }
}
<|endoftext|>


<commit_before>/*!

This crate provides the `error_type!` macro, which is designed to produce a fresh, reasonably well-featured error type from a concise definition.

A simple example of the usage is given below:

```rust
#[macro_use] extern crate error_type;

use std::borrow::Cow;
use std::error::Error;
use std::io;

error_type! {
    #[derive(Debug)]
    pub enum LibError {
        Io(std::io::Error) {
            cause;
        },
        Message(Cow<'static, str>) {
            desc (e) &**e;
            from (s: &'static str) s.into();
            from (s: String) s.into();
        },
        Other(Box<Error>) {
            desc (e) e.description();
            cause (e) Some(&**e);
        }
    }
}
# fn main() {}
```

The expansion of the above includes the following:

- The `LibError` enumeration (plus the provided `#[derive(Debug)]` annotation), with `Io`, `Message` and `Other` variants.

- An implicit `impl From<Payload> for LibError` for each variant's payload type.

- An implicit `impl Display for LibError`, using the existing `Display` implementation for each variant's payload type.

- An implicit `impl Error for LibError`.

- For the `Io` variant:

  - An implicit `description`, forwarded to the existing definition for `std::io::Error`.

  - An automatic `cause`, forwarded to the existing definition for `std::io::Error`.

    **Note**: the automatic `cause` returns the result of `std::io::Error::cause`, *not* the payload itself.  This macro considers the payload to *be* the error, not the underlying cause.

- For the `Message` variant:

  - An explicit `description`, which just returns the contents of the `Cow<'static, str>`.

  - An implicit `cause`, which just returns `None`.

  - An explicit `From<&'static str>` conversion.

  - An explicit `From<String>` conversion.

- For the `Other` variant:

  - An explicit `description` which forwards to the existing definition for the boxed `Error`.

  - An explicit `cause` which returns the boxed error *itself* as the cause.  This is distinct from the behaviour of an *automatic* `cause`.

## FAQ

* *Can I use unitary variants; ones without a payload?*

  No, not as yet.  Maybe if there's demand.

* *Can I use tuple variants with more than one element?*

  No.  This would likely be rather inconvenient to implement, due to the way the various parts of the implementation are constructed.  Not impossible, though.

* *Can I use struct variants?*

  No, for much the same reason as tuple variants.

* *Can I have fields common to all variants; i.e. have the enum wrapped in a struct?*

  No.  It would be nice, but I'm not sure how to go about that.  You can always use the expansion of `error_type!` in a custom structure for the added information.

*/

#[doc(hidden)]
#[macro_export]
macro_rules! error_type_as_item {
    ($i:item) => {$i};
}

#[doc(hidden)]
#[macro_export]
macro_rules! error_type_var_body_emit {
    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident
    ) => {
        // Done.
    };

    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        desc ()
        $($tail:tt)*
    ) => {
        impl<'a> $ed_tr<'a> for (&'a $err_name, &'a $var_ty) {
            fn error_desc(&self) -> &'a str {
                std::error::Error::description(self.1)
            }
        }

        error_type_var_body_emit! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr $($tail)*
        }
    };

    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        desc (($desc_arg:ident) $desc_expr:expr)
        $($tail:tt)*
    ) => {
        impl<'a> $ed_tr<'a> for (&'a $err_name, &'a $var_ty) {
            fn error_desc(&self) -> &'a str {
                let $desc_arg = self.1;
                $desc_expr
            }
        }

        error_type_var_body_emit! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr $($tail)*
        }
    };

    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        cause ()
        $($tail:tt)*
    ) => {
        impl<'a> $ec_tr<'a> for (&'a $err_name, &'a $var_ty) {
            fn error_cause(&self) -> Option<&'a std::error::Error> {
                None
            }
        }

        error_type_var_body_emit! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr $($tail)*
        }
    };

    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        cause (($cl_arg:ident) $cl_expr:expr)
        $($tail:tt)*
    ) => {
        impl<'a> $ec_tr<'a> for (&'a $err_name, &'a $var_ty) {
            fn error_cause(&self) -> Option<&'a std::error::Error> {
                let $cl_arg = self.1;
                $cl_expr
            }
        }

        error_type_var_body_emit! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr $($tail)*
        }
    };

    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        from ($(($cl_arg:ident: $cl_ty:ty) $cl_expr:expr);*)
        $($tail:tt)*
    ) => {
        $(
            impl From<$cl_ty> for $err_name {
                fn from($cl_arg: $cl_ty) -> $err_name {
                    $err_name::$var_name($cl_expr)
                }
            }
        )*

        error_type_var_body_emit! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr $($tail)*
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! error_type_var_body {
    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        $desc:tt, $cause:tt, $from:tt; {}
    ) => {
        error_type_var_body_emit! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr,
            desc $desc, cause $cause, from $from
        }
    };

    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        $desc:tt, $cause:tt, $from:tt; {
            desc ($cl_arg:ident) $cl_body:expr;
            $($tail:tt)*
        }
    ) => {
        error_type_var_body! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr,
            (($cl_arg) $cl_body), $cause, $from;
            {$($tail)*}
        }
    };

    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        $desc:tt, $cause:tt, $from:tt; {
            cause ($cl_arg:ident) $cl_body:expr;
            $($tail:tt)*
        }
    ) => {
        error_type_var_body! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr,
            $desc, (($cl_arg) $cl_body), $from;
            {$($tail)*}
        }
    };

    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        $desc:tt, $cause:tt, $from:tt; {
            cause;
            $($tail:tt)*
        }
    ) => {
        error_type_var_body! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr,
            $desc, ((e) std::error::Error::cause(e)), $from;
            {$($tail)*}
        }
    };

    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        $desc:tt, $cause:tt, (); {
            from ($cl_arg:ident: $cl_ty:ty) $cl_body:expr;
            $($tail:tt)*
        }
    ) => {
        error_type_var_body! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr,
            $desc, $cause, (($cl_arg: $cl_ty) $cl_body);
            {$($tail)*}
        }
    };

    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        $desc:tt, $cause:tt, ($($from:tt)*); {
            from ($cl_arg:ident: $cl_ty:ty) $cl_body:expr;
            $($tail:tt)*
        }
    ) => {
        error_type_var_body! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr,
            $desc, $cause, (($cl_arg: $cl_ty) $cl_body; $($from)*);
            {$($tail)*}
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! error_type_impl {
    (
        $(#[$($derive_tts:tt)*])*
        enum $err_name:ident {
            $($var_name:ident($var_ty:ty) $var_body:tt),+
            $(,)*
        }
    ) => {
        $(
            impl From<$var_ty> for $err_name {
                fn from(value: $var_ty) -> $err_name {
                    $err_name::$var_name(value)
                }
            }
        )+

        impl std::fmt::Display for $err_name {
            fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
                match *self {
                    $(
                        $err_name::$var_name(ref v) => std::fmt::Display::fmt(v, fmt)
                    ),+
                }
            }
        }

        pub trait ErrorDescription<'a> {
            fn error_desc(&self) -> &'a str;
        }

        pub trait ErrorCause<'a> {
            fn error_cause(&self) -> Option<&'a std::error::Error>;
        }

        impl std::error::Error for $err_name {
            fn description(&self) -> &str {
                use ErrorDescription;
                match *self {
                    $(
                        $err_name::$var_name(ref v) => (self, v).error_desc()
                    ),+
                }
            }

            fn cause(&self) -> Option<&std::error::Error> {
                use ErrorCause;
                match *self {
                    $(
                        $err_name::$var_name(ref v) => (self, v).error_cause()
                    ),+
                }
            }
        }

        $(
            error_type_var_body! {
                $err_name, $var_name, $var_ty,
                ErrorDescription, ErrorCause,
                (), (), ();
                $var_body
            }
        )+
    };
}

/**
Constructs a reasonably well-featured error type from a concise description.

For details, see the crate documentation.
*/
#[macro_export]
macro_rules! error_type {
    (
        $(#[$($derive_tts:tt)*])*
        pub enum $err_name:ident {
            $($var_name:ident($var_ty:ty) $var_body:tt),+
            $(,)*
        }
    ) => {
        error_type_as_item! {
            $(#[$($derive_tts)*])*
            pub enum $err_name {
                $($var_name($var_ty)),+
            }
        }

        error_type_impl! {
            $(#[$($derive_tts)*])*
            enum $err_name {
                $($var_name($var_ty) $var_body),+
            }
        }
    };

    (
        $(#[$($derive_tts:tt)*])*
        enum $err_name:ident {
            $($var_name:ident($var_ty:ty) $var_body:tt),+
            $(,)*
        }
    ) => {
        error_type_as_item! {
            $(#[$($derive_tts)*])*
            enum $err_name {
                $($var_name($var_ty)),+
            }
        }

        error_type_impl! {
            $(#[$($derive_tts)*])*
            enum $err_name {
                $($var_name($var_ty) $var_body),+
            }
        }
    };

    (
        $(#[$($derive_tts:tt)*])*
        pub enum $err_name:ident {
            $($body_tts:tt)*
        }

        $($tail:tt)*
    ) => {
        error_type_impl! {
            $(#[$($derive_tts)*])*
            (pub) enum $err_name {
                $($body_tts)*
            }
        }

        error_type! { $($tail)* }
    };
}
<commit_msg>Added some comments to help break up the giant macros.<commit_after>/*!

This crate provides the `error_type!` macro, which is designed to produce a fresh, reasonably well-featured error type from a concise definition.

A simple example of the usage is given below:

```rust
#[macro_use] extern crate error_type;

use std::borrow::Cow;
use std::error::Error;
use std::io;

error_type! {
    #[derive(Debug)]
    pub enum LibError {
        Io(std::io::Error) {
            cause;
        },
        Message(Cow<'static, str>) {
            desc (e) &**e;
            from (s: &'static str) s.into();
            from (s: String) s.into();
        },
        Other(Box<Error>) {
            desc (e) e.description();
            cause (e) Some(&**e);
        }
    }
}
# fn main() {}
```

The expansion of the above includes the following:

- The `LibError` enumeration (plus the provided `#[derive(Debug)]` annotation), with `Io`, `Message` and `Other` variants.

- An implicit `impl From<Payload> for LibError` for each variant's payload type.

- An implicit `impl Display for LibError`, using the existing `Display` implementation for each variant's payload type.

- An implicit `impl Error for LibError`.

- For the `Io` variant:

  - An implicit `description`, forwarded to the existing definition for `std::io::Error`.

  - An automatic `cause`, forwarded to the existing definition for `std::io::Error`.

    **Note**: the automatic `cause` returns the result of `std::io::Error::cause`, *not* the payload itself.  This macro considers the payload to *be* the error, not the underlying cause.

- For the `Message` variant:

  - An explicit `description`, which just returns the contents of the `Cow<'static, str>`.

  - An implicit `cause`, which just returns `None`.

  - An explicit `From<&'static str>` conversion.

  - An explicit `From<String>` conversion.

- For the `Other` variant:

  - An explicit `description` which forwards to the existing definition for the boxed `Error`.

  - An explicit `cause` which returns the boxed error *itself* as the cause.  This is distinct from the behaviour of an *automatic* `cause`.

## FAQ

* *Can I use unitary variants; ones without a payload?*

  No, not as yet.  Maybe if there's demand.

* *Can I use tuple variants with more than one element?*

  No.  This would likely be rather inconvenient to implement, due to the way the various parts of the implementation are constructed.  Not impossible, though.

* *Can I use struct variants?*

  No, for much the same reason as tuple variants.

* *Can I have fields common to all variants; i.e. have the enum wrapped in a struct?*

  No.  It would be nice, but I'm not sure how to go about that.  You can always use the expansion of `error_type!` in a custom structure for the added information.

*/

#[doc(hidden)]
#[macro_export]
macro_rules! error_type_as_item {
    ($i:item) => {$i};
}

#[doc(hidden)]
#[macro_export]
macro_rules! error_type_var_body_emit {
    /*
    Nothing left.
    */
    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident
    ) => {
        // Done.
    };

    /*
    desc () clause.
    */
    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        desc ()
        $($tail:tt)*
    ) => {
        impl<'a> $ed_tr<'a> for (&'a $err_name, &'a $var_ty) {
            fn error_desc(&self) -> &'a str {
                std::error::Error::description(self.1)
            }
        }

        error_type_var_body_emit! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr $($tail)*
        }
    };

    /*
    desc ((arg) expr) clause.
    */
    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        desc (($desc_arg:ident) $desc_expr:expr)
        $($tail:tt)*
    ) => {
        impl<'a> $ed_tr<'a> for (&'a $err_name, &'a $var_ty) {
            fn error_desc(&self) -> &'a str {
                let $desc_arg = self.1;
                $desc_expr
            }
        }

        error_type_var_body_emit! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr $($tail)*
        }
    };

    /*
    cause () clause.
    */
    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        cause ()
        $($tail:tt)*
    ) => {
        impl<'a> $ec_tr<'a> for (&'a $err_name, &'a $var_ty) {
            fn error_cause(&self) -> Option<&'a std::error::Error> {
                None
            }
        }

        error_type_var_body_emit! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr $($tail)*
        }
    };

    /*
    cause ((arg) expr) clause.
    */
    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        cause (($cl_arg:ident) $cl_expr:expr)
        $($tail:tt)*
    ) => {
        impl<'a> $ec_tr<'a> for (&'a $err_name, &'a $var_ty) {
            fn error_cause(&self) -> Option<&'a std::error::Error> {
                let $cl_arg = self.1;
                $cl_expr
            }
        }

        error_type_var_body_emit! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr $($tail)*
        }
    };

    /*
    from ((arg: ty) expr) clause.
    */
    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        from ($(($cl_arg:ident: $cl_ty:ty) $cl_expr:expr);*)
        $($tail:tt)*
    ) => {
        $(
            impl From<$cl_ty> for $err_name {
                fn from($cl_arg: $cl_ty) -> $err_name {
                    $err_name::$var_name($cl_expr)
                }
            }
        )*

        error_type_var_body_emit! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr $($tail)*
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! error_type_var_body {
    /*
    Base case: no more clauses.
    */
    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        $desc:tt, $cause:tt, $from:tt; {}
    ) => {
        error_type_var_body_emit! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr,
            desc $desc, cause $cause, from $from
        }
    };

    /*
    desc (arg) expr;
    */
    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        $desc:tt, $cause:tt, $from:tt; {
            desc ($cl_arg:ident) $cl_body:expr;
            $($tail:tt)*
        }
    ) => {
        error_type_var_body! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr,
            (($cl_arg) $cl_body), $cause, $from;
            {$($tail)*}
        }
    };

    /*
    cause (arg) expr;
    */
    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        $desc:tt, $cause:tt, $from:tt; {
            cause ($cl_arg:ident) $cl_body:expr;
            $($tail:tt)*
        }
    ) => {
        error_type_var_body! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr,
            $desc, (($cl_arg) $cl_body), $from;
            {$($tail)*}
        }
    };

    /*
    cause;
    */
    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        $desc:tt, $cause:tt, $from:tt; {
            cause;
            $($tail:tt)*
        }
    ) => {
        error_type_var_body! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr,
            $desc, ((e) std::error::Error::cause(e)), $from;
            {$($tail)*}
        }
    };

    /*
    from (arg: Ty) expr; (first)
    */
    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        $desc:tt, $cause:tt, (); {
            from ($cl_arg:ident: $cl_ty:ty) $cl_body:expr;
            $($tail:tt)*
        }
    ) => {
        error_type_var_body! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr,
            $desc, $cause, (($cl_arg: $cl_ty) $cl_body);
            {$($tail)*}
        }
    };

    /*
    from (arg: Ty) expr; (not first)
    */
    (
        $err_name:ident, $var_name:ident, $var_ty:ty, $ed_tr:ident, $ec_tr:ident,
        $desc:tt, $cause:tt, ($($from:tt)*); {
            from ($cl_arg:ident: $cl_ty:ty) $cl_body:expr;
            $($tail:tt)*
        }
    ) => {
        error_type_var_body! {
            $err_name, $var_name, $var_ty, $ed_tr, $ec_tr,
            $desc, $cause, (($cl_arg: $cl_ty) $cl_body; $($from)*);
            {$($tail)*}
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! error_type_impl {
    (
        $(#[$($derive_tts:tt)*])*
        enum $err_name:ident {
            $($var_name:ident($var_ty:ty) $var_body:tt),+
            $(,)*
        }
    ) => {
        $(
            impl From<$var_ty> for $err_name {
                fn from(value: $var_ty) -> $err_name {
                    $err_name::$var_name(value)
                }
            }
        )+

        impl std::fmt::Display for $err_name {
            fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
                match *self {
                    $(
                        $err_name::$var_name(ref v) => std::fmt::Display::fmt(v, fmt)
                    ),+
                }
            }
        }

        pub trait ErrorDescription<'a> {
            fn error_desc(&self) -> &'a str;
        }

        pub trait ErrorCause<'a> {
            fn error_cause(&self) -> Option<&'a std::error::Error>;
        }

        impl std::error::Error for $err_name {
            fn description(&self) -> &str {
                use ErrorDescription;
                match *self {
                    $(
                        $err_name::$var_name(ref v) => (self, v).error_desc()
                    ),+
                }
            }

            fn cause(&self) -> Option<&std::error::Error> {
                use ErrorCause;
                match *self {
                    $(
                        $err_name::$var_name(ref v) => (self, v).error_cause()
                    ),+
                }
            }
        }

        $(
            error_type_var_body! {
                $err_name, $var_name, $var_ty,
                ErrorDescription, ErrorCause,
                (), (), ();
                $var_body
            }
        )+
    };
}

/**
Constructs a reasonably well-featured error type from a concise description.

For details, see the crate documentation.
*/
#[macro_export]
macro_rules! error_type {
    (
        $(#[$($derive_tts:tt)*])*
        pub enum $err_name:ident {
            $($var_name:ident($var_ty:ty) $var_body:tt),+
            $(,)*
        }
    ) => {
        error_type_as_item! {
            $(#[$($derive_tts)*])*
            pub enum $err_name {
                $($var_name($var_ty)),+
            }
        }

        error_type_impl! {
            $(#[$($derive_tts)*])*
            enum $err_name {
                $($var_name($var_ty) $var_body),+
            }
        }
    };

    (
        $(#[$($derive_tts:tt)*])*
        enum $err_name:ident {
            $($var_name:ident($var_ty:ty) $var_body:tt),+
            $(,)*
        }
    ) => {
        error_type_as_item! {
            $(#[$($derive_tts)*])*
            enum $err_name {
                $($var_name($var_ty)),+
            }
        }

        error_type_impl! {
            $(#[$($derive_tts)*])*
            enum $err_name {
                $($var_name($var_ty) $var_body),+
            }
        }
    };

    (
        $(#[$($derive_tts:tt)*])*
        pub enum $err_name:ident {
            $($body_tts:tt)*
        }

        $($tail:tt)*
    ) => {
        error_type_impl! {
            $(#[$($derive_tts)*])*
            (pub) enum $err_name {
                $($body_tts)*
            }
        }

        error_type! { $($tail)* }
    };
}
<|endoftext|>


<commit_before>#![feature(collections, core, hash)]
// Silence feature warnings for test module.
#![cfg_attr(test, feature(rand, test))]

extern crate image;
extern crate "rustc-serialize" as serialize;

use self::dct::{dct_2d, crop_dct};

use image::{
    imageops,
    DynamicImage,
    FilterType,
    GrayImage,
    GrayAlphaImage,
    Pixel,
    RgbImage,
    RgbaImage,
};

use serialize::base64::{ToBase64, STANDARD, FromBase64, FromBase64Error};

use std::collections::Bitv;

const FILTER_TYPE: FilterType = FilterType::Nearest;

mod dct;

/// A struct representing an image processed by a perceptual hash.
/// For efficiency, does not retain a copy of the image data after hashing.
///
/// Get an instance with `ImageHash::hash()`.
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
pub struct ImageHash {
    bitv: Bitv,
    hash_type: HashType,
}

impl ImageHash {

    /// Calculate the Hamming distance between this and `other`.
    /// Equivalent to counting the 1-bits of the XOR of the two `Bitv`.
    ///
    /// Essential to determining the perceived difference between `self` and `other`.
    ///
    /// ###Panics
    /// If `self` and `other` have differing hash types or hash sizes.
    pub fn dist(&self, other: &ImageHash) -> usize {
        assert!(self.hash_type == other.hash_type,
               "Image hashes must use the same algorithm for proper comparison!");
        assert!(self.bitv.len() == other.bitv.len(),
                "Image hashes must be the same length for proper comparison!");

        self.bitv.iter().zip(other.bitv.iter())
            .filter(|&(left, right)| left != right).count()
    }

    /// Calculate the Hamming distance between `self` and `other`,
    /// then normalize it to `[0, 1]`, as a fraction of the total bits.
    ///
    /// Roughly equivalent to the % difference between the two images,
    /// represented as a decimal.
    ///
    /// See `ImageHash::dist()`.
    pub fn dist_ratio(&self, other: &ImageHash) -> f32 {
        self.dist(other) as f32 / self.size() as f32
    }

    /// Get the hash size of this image. Should be equal to the number of bits in the hash.
    pub fn size(&self) -> u32 { self.bitv.len() as u32 }

    /// Get the `HashType` that this `ImageHash` was created with.
    pub fn hash_type(&self) -> HashType { self.hash_type }

    /// Create a hash of `img` with a length of `hash_size * hash_size` using the hash algorithm
    /// described by `hash_type`.
    pub fn hash<I: HashImage>(img: &I, hash_size: u32, hash_type: HashType) -> ImageHash {
        let hash = hash_type.hash(img, hash_size);

        assert!((hash_size * hash_size) as usize == hash.len());

        ImageHash {
            bitv: hash,
            hash_type: hash_type,
        }
    }

    /// Create an `ImageHash` instance from the given Base64-encoded string.
    pub fn from_base64(encoded_hash: &str) -> Result<ImageHash, FromBase64Error>{
        let data = try!(encoded_hash.from_base64());
        // The hash type should be the first bit of the hash
        let hash_type = HashType::from_byte(data.remove(0));

        Ok(ImageHash{
            bitv: Bitv::from_bytes(&*data),
            hash_type: hash_type,
        })
    }

    /// Get a Base64 string representing the bits of this hash.
    ///
    /// Mostly for printing convenience.
    pub fn to_base64(&self) -> String {
        let mut bytes = self.bitv.to_bytes();
        // Insert the hash type as the first byte.
        bytes.insert(0, self.hash_type.to_byte());

        bytes.to_base64(STANDARD)
    }
}

/// An enum describing the hash algorithms that `img_hash` offers.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum HashType {
    /// Fastest, but inaccurate. Really only useful for finding duplicates.
    Mean,
    /// Slowest, but detects changes in color gamut and sometimes significant edits.
    DCT,
}

impl HashType {
    fn hash<I: HashImage>(self, img: &I, hash_size: u32) -> Bitv {
        use HashType::*;

        match self {
            Mean => mean_hash(img, hash_size),
            DCT => dct_hash(img, hash_size),
        }
    }

    fn to_byte(self) -> u8 {
        use HashType::*;

        match self {
            Mean => 1,
            DCT => 2,
        }
    }

    fn from_byte(byte: u8) -> HashType {
        use HashType::*;

        match byte {
            1 => Mean,
            2 => DCT,
            _ => panic!("Byte {:?} cannot be coerced to a `HashType`!", byte),
        }
    }
}

fn mean_hash<I: HashImage>(img: &I, hash_size: u32) -> Bitv {
    let hash_values = img.gray_resize_square(hash_size).into_raw();

    let mean = hash_values.iter().fold(0u32, |b, &a| a as u32 + b)
        / hash_values.len() as u32;

    hash_values.into_iter().map(|x| x as u32 >= mean).collect()
}

fn dct_hash<I: HashImage>(img: &I, hash_size: u32) -> Bitv {
    let large_size = hash_size * 4;

    // We take a bigger resize than fast_hash,
    // then we only take the lowest corner of the DCT
    let hash_values: Vec<_> = img.gray_resize_square(large_size)
        .into_raw().into_iter().map(|val| val as f64).collect();

    let dct = dct_2d(hash_values.as_slice(),
        large_size as usize, large_size as usize);

    let original = (large_size as usize, large_size as usize);
    let new = (hash_size as usize, hash_size as usize);

    let cropped_dct = crop_dct(dct, original, new);

    let mean = cropped_dct.iter().fold(0f64, |b, &a| a + b)
        / cropped_dct.len() as f64;

    cropped_dct.into_iter().map(|x| x >= mean).collect()
}

/// A trait for describing an image that can be successfully hashed.
pub trait HashImage {
    /// Apply a grayscale filter and drop the alpha channel (if present),
    /// then resize the image to `size` width by `size` height (making it square).
    ///
    /// Returns a copy, leaving `self` unmodified.
    fn gray_resize_square(&self, size: u32) -> GrayImage;
}

macro_rules! hash_img_impl {
    ($ty:ty) => (
        impl HashImage for $ty {
            fn gray_resize_square(&self, size: u32) -> GrayImage {
                let ref gray = imageops::grayscale(self);
                imageops::resize(gray, size, size, FILTER_TYPE)
            }
        }
    );
    ($($ty:ty),+) => ( $(hash_img_impl! { $ty })+ );
}

hash_img_impl! { GrayImage, GrayAlphaImage, RgbImage, RgbaImage, DynamicImage }

#[cfg(test)]
mod test {
    extern crate test;

    use image::{Rgba, ImageBuffer};

    use self::test::Bencher;

    use super::{HashType, ImageHash};

    use std::rand::{weak_rng, Rng};

    type RgbaBuf = ImageBuffer<Rgba<u8>, Vec<u8>>;

    fn gen_test_img(width: u32, height: u32) -> RgbaBuf {
        let len = (width * height * 4) as usize;
        let mut buf = Vec::with_capacity(len);
        unsafe { buf.set_len(len); } // We immediately fill the buffer.
        weak_rng().fill_bytes(&mut *buf);

        ImageBuffer::from_raw(width, height, buf).unwrap()
    }

    #[test]
    fn hash_equality() {
        let test_img = gen_test_img(1024, 1024);
        let hash1 = ImageHash::hash(&test_img, 32, HashType::Mean);
        let hash2 = ImageHash::hash(&test_img, 32, HashType::Mean);

        assert_eq!(hash1, hash2);
    }

    #[test]
    fn size() {
        let test_img = gen_test_img(1024, 1024);
        let hash = ImageHash::hash(&test_img, 32, HashType::Mean);
        assert_eq!(32*32, hash.size());
    }

    #[test]
    fn base64_encoding_decoding() {
        let test_img = gen_test_img(1024, 1024);
        let hash1 = ImageHash::hash(&test_img, 32, HashType::Mean);

        let base64_string = hash1.to_base64();
        let decoded_result = ImageHash::from_base64(&*base64_string);

        assert!(decoded_result.is_ok());

        assert_eq!(decoded_result.unwrap(), hash1);
    }

    #[bench]
    fn bench_hash(b: &mut Bencher) {
        let test_img = gen_test_img(1024, 1024);

        b.iter(|| ImageHash::hash(&test_img, 32, HashType::Mean));
    }
}
<commit_msg>Add Gradient and DoubleGradient hash types, benchmarks<commit_after>#![feature(collections, core, hash)]
// Silence feature warnings for test module.
#![cfg_attr(test, feature(rand, test))]

extern crate image;
extern crate "rustc-serialize" as serialize;

use self::dct::{dct_2d, crop_dct};

use image::{
    imageops,
    DynamicImage,
    FilterType,
    GrayImage,
    GrayAlphaImage,
    Pixel,
    RgbImage,
    RgbaImage,
};

use serialize::base64::{ToBase64, STANDARD, FromBase64, FromBase64Error};

use std::collections::Bitv;

const FILTER_TYPE: FilterType = FilterType::Nearest;

mod dct;

/// A struct representing an image processed by a perceptual hash.
/// For efficiency, does not retain a copy of the image data after hashing.
///
/// Get an instance with `ImageHash::hash()`.
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
pub struct ImageHash {
    bitv: Bitv,
    hash_type: HashType,
}

impl ImageHash {

    /// Calculate the Hamming distance between this and `other`.
    /// Equivalent to counting the 1-bits of the XOR of the two `Bitv`.
    ///
    /// Essential to determining the perceived difference between `self` and `other`.
    ///
    /// ###Panics
    /// If `self` and `other` have differing hash types or hash sizes.
    pub fn dist(&self, other: &ImageHash) -> usize {
        assert!(self.hash_type == other.hash_type,
               "Image hashes must use the same algorithm for proper comparison!");
        assert!(self.bitv.len() == other.bitv.len(),
                "Image hashes must be the same length for proper comparison!");

        self.bitv.iter().zip(other.bitv.iter())
            .filter(|&(left, right)| left != right).count()
    }

    /// Calculate the Hamming distance between `self` and `other`,
    /// then normalize it to `[0, 1]`, as a fraction of the total bits.
    ///
    /// Roughly equivalent to the % difference between the two images,
    /// represented as a decimal.
    ///
    /// See `ImageHash::dist()`.
    pub fn dist_ratio(&self, other: &ImageHash) -> f32 {
        self.dist(other) as f32 / self.size() as f32
    }

    /// Get the hash size of this image. Should be equal to the number of bits in the hash.
    pub fn size(&self) -> u32 { self.bitv.len() as u32 }

    /// Get the `HashType` that this `ImageHash` was created with.
    pub fn hash_type(&self) -> HashType { self.hash_type }

    /// Create a hash of `img` with a length of `hash_size * hash_size`
    /// (`* 2` that when using `HashType::DoubleGradient`)
    /// using the hash algorithm described by `hash_type`.
    pub fn hash<I: HashImage>(img: &I, hash_size: u32, hash_type: HashType) -> ImageHash {
        let hash = hash_type.hash(img, hash_size);

        ImageHash {
            bitv: hash,
            hash_type: hash_type,
        }
    }

    /// Create an `ImageHash` instance from the given Base64-encoded string.
    pub fn from_base64(encoded_hash: &str) -> Result<ImageHash, FromBase64Error>{
        let mut data = try!(encoded_hash.from_base64());
        // The hash type should be the first bit of the hash
        let hash_type = HashType::from_byte(data.remove(0));

        Ok(ImageHash{
            bitv: Bitv::from_bytes(&*data),
            hash_type: hash_type,
        })
    }

    /// Get a Base64 string representing the bits of this hash.
    ///
    /// Mostly for printing convenience.
    pub fn to_base64(&self) -> String {
        let mut bytes = self.bitv.to_bytes();
        // Insert the hash type as the first byte.
        bytes.insert(0, self.hash_type.to_byte());

        bytes.to_base64(STANDARD)
    }
}

/// An enum describing the hash algorithms that `img_hash` offers.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum HashType {
    /// This algorithm first averages the pixels of the reduced-size and color image,
    /// and then compares each pixel to the average.
    ///
    /// Fastest, but inaccurate. Really only useful for finding duplicates.
    Mean,
    /// This algorithm compares each pixel in a row to its neighbor and registers changes in
    /// gradients (e.g. edges and color boundaries).
    ///
    /// More accurate than `Mean` but much faster than `DCT`.
    Gradient,
    /// A version of `Gradient` that adds an extra hash pass orthogonal to the first
    /// (i.e. on columns in addition to rows).
    ///
    /// Slower than `Gradient` and produces a double-sized hash, but much more accurate.
    DoubleGradient,
    /// This algorithm runs a Discrete Cosine Transform on the reduced-color and size image,
    /// then compares each datapoint in the transform to the average.
    ///
    /// Slowest by far, but can detect changes in color gamut and sometimes relatively significant edits.
    DCT,
}

impl HashType {
    fn hash<I: HashImage>(self, img: &I, hash_size: u32) -> Bitv {
        use HashType::*;

        match self {
            Mean => mean_hash(img, hash_size),
            DCT => dct_hash(img, hash_size),
            Gradient => gradient_hash(img, hash_size),
            DoubleGradient => double_gradient_hash(img, hash_size),
        }
    }

    fn to_byte(self) -> u8 {
        use HashType::*;

        match self {
            Mean => 1,
            DCT => 2,
            Gradient => 3,
            DoubleGradient => 4,
        }
    }

    fn from_byte(byte: u8) -> HashType {
        use HashType::*;

        match byte {
            1 => Mean,
            2 => DCT,
            3 => Gradient,
            4 => DoubleGradient,
            _ => panic!("Byte {:?} cannot be coerced to a `HashType`!", byte),
        }
    }
}

fn mean_hash<I: HashImage>(img: &I, hash_size: u32) -> Bitv {
    let hash_values = img.gray_resize_square(hash_size).into_raw();

    let mean = hash_values.iter().fold(0u32, |b, &a| a as u32 + b)
        / hash_values.len() as u32;

    hash_values.into_iter().map(|x| x as u32 >= mean).collect()
}

fn dct_hash<I: HashImage>(img: &I, hash_size: u32) -> Bitv {
    let large_size = hash_size * 4;

    // We take a bigger resize than fast_hash,
    // then we only take the lowest corner of the DCT
    let hash_values: Vec<_> = img.gray_resize_square(large_size)
        .into_raw().into_iter().map(|val| val as f64).collect();

    let dct = dct_2d(hash_values.as_slice(),
        large_size as usize, large_size as usize);

    let original = (large_size as usize, large_size as usize);
    let new = (hash_size as usize, hash_size as usize);

    let cropped_dct = crop_dct(dct, original, new);

    let mean = cropped_dct.iter().fold(0f64, |b, &a| a + b)
        / cropped_dct.len() as f64;

    cropped_dct.into_iter().map(|x| x >= mean).collect()
}

/// The guts of the gradient hash,
/// separate so we can reuse them for both `Gradient` and `DoubleGradient`.
fn gradient_hash_impl(resized: &GrayImage, hash_size: u32, bitv: &mut Bitv) {
    for row in resized.as_slice().chunks(hash_size as usize) {
        for idx in 1 .. row.len() {
            // These two should never be out of bounds, so we can skip bounds checking.
            let this = unsafe { row.get_unchecked(idx) };
            let last = unsafe { row.get_unchecked(idx - 1) };

            bitv.push(last < this);
        }

        // Wrap the last comparison so we get `hash_size` total comparisons
        let last = unsafe { row.get_unchecked(row.len() - 1) };
        let first = unsafe { row.get_unchecked(0) };

        bitv.push(last < first);
    }

}

fn gradient_hash<I: HashImage>(img: &I, hash_size: u32) -> Bitv {
    let resized = img.gray_resize_square(hash_size);
    let mut bitv = Bitv::with_capacity((hash_size * hash_size) as usize);

    gradient_hash_impl(&resized, hash_size, &mut bitv);

    bitv
}

fn double_gradient_hash<I: HashImage>(img: &I, hash_size: u32) -> Bitv {
    let resized = img.gray_resize_square(hash_size);
    let mut bitv = Bitv::with_capacity((hash_size * hash_size * 2) as usize);

    gradient_hash_impl(&resized, hash_size, &mut bitv);

    // Rotate the image 90 degrees so rows become columns
    let rotated: GrayImage = imageops::rotate90(&resized);
    gradient_hash_impl(&rotated, hash_size, &mut bitv);

    bitv
}

/// A trait for describing an image that can be successfully hashed.
pub trait HashImage {
    /// Apply a grayscale filter and drop the alpha channel (if present),
    /// then resize the image to `size` by `size` (making it square).
    ///
    /// Returns a copy, leaving `self` unmodified.
    fn gray_resize_square(&self, size: u32) -> GrayImage;
}

macro_rules! hash_img_impl {
    ($ty:ty) => (
        impl HashImage for $ty {
            fn gray_resize_square(&self, size: u32) -> GrayImage {
                let ref gray = imageops::grayscale(self);
                imageops::resize(gray, size, size, FILTER_TYPE)
            }
        }
    );
    ($($ty:ty),+) => ( $(hash_img_impl! { $ty })+ );
}

hash_img_impl! { GrayImage, GrayAlphaImage, RgbImage, RgbaImage, DynamicImage }

#[cfg(test)]
mod test {
    extern crate test;

    use image::{Rgba, ImageBuffer};

    use self::test::Bencher;

    use super::{HashType, ImageHash};

    use std::rand::{weak_rng, Rng};

    type RgbaBuf = ImageBuffer<Rgba<u8>, Vec<u8>>;

    fn gen_test_img(width: u32, height: u32) -> RgbaBuf {
        let len = (width * height * 4) as usize;
        let mut buf = Vec::with_capacity(len);
        unsafe { buf.set_len(len); } // We immediately fill the buffer.
        weak_rng().fill_bytes(&mut *buf);

        ImageBuffer::from_raw(width, height, buf).unwrap()
    }

    #[test]
    fn hash_equality() {
        let test_img = gen_test_img(1024, 1024);
        let hash1 = ImageHash::hash(&test_img, 32, HashType::Mean);
        let hash2 = ImageHash::hash(&test_img, 32, HashType::Mean);

        assert_eq!(hash1, hash2);
    }

    #[test]
    fn size() {
        let test_img = gen_test_img(1024, 1024);
        let hash = ImageHash::hash(&test_img, 32, HashType::Mean);
        assert_eq!(32*32, hash.size());
    }

    #[test]
    fn base64_encoding_decoding() {
        let test_img = gen_test_img(1024, 1024);
        let hash1 = ImageHash::hash(&test_img, 32, HashType::Mean);

        let base64_string = hash1.to_base64();
        let decoded_result = ImageHash::from_base64(&*base64_string);

        assert!(decoded_result.is_ok());

        assert_eq!(decoded_result.unwrap(), hash1);
    }

    fn bench_hash(b: &mut Bencher, hash_type: HashType) {
        let test_img = gen_test_img(512, 512);

        b.iter(|| ImageHash::hash(&test_img, 8, hash_type));
    }

    macro_rules! bench_hash {
        ($bench_fn:ident : $hash_type:expr) => (
            #[bench]
            fn $bench_fn(b: &mut Bencher) {
                bench_hash(b, $hash_type);
            }
        )
    }

    bench_hash! { bench_mean_hash : HashType::Mean }
    bench_hash! { bench_gradient_hash : HashType::Gradient }
    bench_hash! { bench_dbl_gradient_hash : HashType::DoubleGradient }
    bench_hash! { bench_dct_hash : HashType::DCT }
}
<|endoftext|>


<commit_before>#![crate_name = "liquid"]
#![doc(html_root_url = "https://cobalt-org.github.io/liquid-rust/")]

// This library uses Clippy!
#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

// Deny warnings, except in dev mode
#![deny(warnings)]
#![cfg_attr(feature="dev", warn(warnings))]

// Ignore clippy, except in dev mode
#![cfg_attr(feature="clippy", allow(clippy))]
#![cfg_attr(feature="dev", warn(clippy))]

// Stuff we want clippy to fail on
#![cfg_attr(feature="clippy", deny(
        string_to_string,
        str_to_string,
        ptr_arg,
        useless_vec,
        redundant_closure,
        clone_on_copy,
        len_zero,
        explicit_iter_loop
        ))]

#[macro_use]
extern crate lazy_static;
extern crate regex;

use std::collections::HashMap;
use lexer::Element;
use tags::{assign_tag, comment_block, raw_block, for_block, if_block, capture_block};
use std::default::Default;
use error::Result;

pub use value::Value;
pub use context::Context;
pub use template::Template;
pub use error::Error;
pub use filters::{FilterResult, FilterError};
pub use token::Token;

pub mod lexer;
pub mod parser;

mod token;
mod error;
mod template;
mod output;
mod text;
mod tags;
mod filters;
mod value;
mod variable;
mod context;

/// The ErrorMode to use.
/// This currently does not have an effect, until
/// ErrorModes are properly implemented.
#[derive(Clone, Copy)]
pub enum ErrorMode {
    Strict,
    Warn,
    Lax,
}

impl Default for ErrorMode {
    fn default() -> ErrorMode {
        ErrorMode::Warn
    }
}

/// A trait for creating custom tags. This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a tag and returns
/// a new [Renderable](trait.Renderable.html) based on its parameters. The received parameters
/// specify the name of the tag, the argument [Tokens](lexer/enum.Token.html) passed to
/// the tag and the global [LiquidOptions](struct.LiquidOptions.html).
///
/// ## Minimal Example
/// ```
/// # use liquid::{Renderable, LiquidOptions, Context, Error};
///
/// struct HelloWorld;
///
/// impl Renderable for HelloWorld {
///     fn render(&self, _context: &mut Context) -> Result<Option<String>, Error>{
///         Ok(Some("Hello World!".to_owned()))
///     }
/// }
///
/// let mut options : LiquidOptions = Default::default();
/// options.tags.insert("hello_world".to_owned(), Box::new(|_tag_name, _arguments, _options| {
///      Ok(Box::new(HelloWorld))
/// }));
///
/// let template = liquid::parse("{{hello_world}}", options).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Hello World!".to_owned()));
/// ```
pub type Tag = Fn(&str, &[Token], &LiquidOptions) -> Result<Box<Renderable>>;

/// A trait for creating custom custom block-size tags (`{% if something %}{% endif %}`). This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a block and returns
/// a new `Renderable` based on its parameters. The received parameters specify the name
/// of the block, the argument [Tokens](lexer/enum.Token.html) passed to
/// the block, a Vec of all [Elements](lexer/enum.Element.html) inside the block and the global [LiquidOptions](struct.LiquidOptions.html).
pub type Block = Fn(&str, &[Token], Vec<Element>, &LiquidOptions) -> Result<Box<Renderable>>;

/// Any object (tag/block) that can be rendered by liquid must implement this trait.
pub trait Renderable{
    fn render(&self, context: &mut Context) -> Result<Option<String>>;
}

#[derive(Default)]
pub struct LiquidOptions {
    pub blocks: HashMap<String, Box<Block>>,
    pub tags: HashMap<String, Box<Tag>>,
    pub error_mode: ErrorMode,
}

impl LiquidOptions {
    pub fn register_block(&mut self, name: &str, block: Box<Block>) {
        self.blocks.insert(name.to_owned(), block);
    }

    pub fn register_tag(&mut self, name: &str, tag: Box<Tag>) {
        self.tags.insert(name.to_owned(), tag);
    }}

/// Parses a liquid template, returning a Template object.
/// # Examples
///
/// ## Minimal Template
///
/// ```
/// use liquid::{Renderable, LiquidOptions, Context};
///
/// let template = liquid::parse("Liquid!", LiquidOptions::default()).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Liquid!".to_owned()));
/// ```
///
pub fn parse(text: &str, options: LiquidOptions) -> Result<Template> {
    let mut options = options;
    let tokens = try!(lexer::tokenize(&text));

    options.register_tag("assign", Box::new(assign_tag));

    options.register_block("raw",     Box::new(raw_block));
    options.register_block("if",      Box::new(if_block));
    options.register_block("for",     Box::new(for_block));
    options.register_block("comment", Box::new(comment_block));
    options.register_block("capture", Box::new(capture_block));

    parser::parse(&tokens, &options).map(Template::new)
}
<commit_msg>Update clippy lints<commit_after>#![crate_name = "liquid"]
#![doc(html_root_url = "https://cobalt-org.github.io/liquid-rust/")]

// This library uses Clippy!
#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

// Deny warnings, except in dev mode
#![deny(warnings)]
#![cfg_attr(feature="dev", warn(warnings))]

// Ignore clippy, except in dev mode
#![cfg_attr(feature="clippy", allow(clippy))]
#![cfg_attr(feature="dev", warn(clippy))]

// Stuff we want clippy to fail on
#![cfg_attr(feature="clippy", deny(
        explicit_iter_loop,
        clone_on_copy,
        len_zero,
        map_clone,
        map_entry,
        match_bool,
        match_same_arms,
        new_ret_no_self,
        new_without_default,
        needless_lifetimes,
        needless_range_loop,
        no_effect,
        ok_expect,
        out_of_bounds_indexing,
        ptr_arg,
        redundant_closure,
        single_char_pattern,
        unused_collect,
        useless_vec,
        ))]

#[macro_use]
extern crate lazy_static;
extern crate regex;

use std::collections::HashMap;
use lexer::Element;
use tags::{assign_tag, comment_block, raw_block, for_block, if_block, capture_block};
use std::default::Default;
use error::Result;

pub use value::Value;
pub use context::Context;
pub use template::Template;
pub use error::Error;
pub use filters::{FilterResult, FilterError};
pub use token::Token;

pub mod lexer;
pub mod parser;

mod token;
mod error;
mod template;
mod output;
mod text;
mod tags;
mod filters;
mod value;
mod variable;
mod context;

/// The ErrorMode to use.
/// This currently does not have an effect, until
/// ErrorModes are properly implemented.
#[derive(Clone, Copy)]
pub enum ErrorMode {
    Strict,
    Warn,
    Lax,
}

impl Default for ErrorMode {
    fn default() -> ErrorMode {
        ErrorMode::Warn
    }
}

/// A trait for creating custom tags. This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a tag and returns
/// a new [Renderable](trait.Renderable.html) based on its parameters. The received parameters
/// specify the name of the tag, the argument [Tokens](lexer/enum.Token.html) passed to
/// the tag and the global [LiquidOptions](struct.LiquidOptions.html).
///
/// ## Minimal Example
/// ```
/// # use liquid::{Renderable, LiquidOptions, Context, Error};
///
/// struct HelloWorld;
///
/// impl Renderable for HelloWorld {
///     fn render(&self, _context: &mut Context) -> Result<Option<String>, Error>{
///         Ok(Some("Hello World!".to_owned()))
///     }
/// }
///
/// let mut options : LiquidOptions = Default::default();
/// options.tags.insert("hello_world".to_owned(), Box::new(|_tag_name, _arguments, _options| {
///      Ok(Box::new(HelloWorld))
/// }));
///
/// let template = liquid::parse("{{hello_world}}", options).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Hello World!".to_owned()));
/// ```
pub type Tag = Fn(&str, &[Token], &LiquidOptions) -> Result<Box<Renderable>>;

/// A trait for creating custom custom block-size tags (`{% if something %}{% endif %}`). This is a simple type alias for a function.
///
/// This function will be called whenever the parser encounters a block and returns
/// a new `Renderable` based on its parameters. The received parameters specify the name
/// of the block, the argument [Tokens](lexer/enum.Token.html) passed to
/// the block, a Vec of all [Elements](lexer/enum.Element.html) inside the block and the global [LiquidOptions](struct.LiquidOptions.html).
pub type Block = Fn(&str, &[Token], Vec<Element>, &LiquidOptions) -> Result<Box<Renderable>>;

/// Any object (tag/block) that can be rendered by liquid must implement this trait.
pub trait Renderable{
    fn render(&self, context: &mut Context) -> Result<Option<String>>;
}

#[derive(Default)]
pub struct LiquidOptions {
    pub blocks: HashMap<String, Box<Block>>,
    pub tags: HashMap<String, Box<Tag>>,
    pub error_mode: ErrorMode,
}

impl LiquidOptions {
    pub fn register_block(&mut self, name: &str, block: Box<Block>) {
        self.blocks.insert(name.to_owned(), block);
    }

    pub fn register_tag(&mut self, name: &str, tag: Box<Tag>) {
        self.tags.insert(name.to_owned(), tag);
    }}

/// Parses a liquid template, returning a Template object.
/// # Examples
///
/// ## Minimal Template
///
/// ```
/// use liquid::{Renderable, LiquidOptions, Context};
///
/// let template = liquid::parse("Liquid!", LiquidOptions::default()).unwrap();
/// let mut data = Context::new();
/// let output = template.render(&mut data);
/// assert_eq!(output.unwrap(), Some("Liquid!".to_owned()));
/// ```
///
pub fn parse(text: &str, options: LiquidOptions) -> Result<Template> {
    let mut options = options;
    let tokens = try!(lexer::tokenize(&text));

    options.register_tag("assign", Box::new(assign_tag));

    options.register_block("raw",     Box::new(raw_block));
    options.register_block("if",      Box::new(if_block));
    options.register_block("for",     Box::new(for_block));
    options.register_block("comment", Box::new(comment_block));
    options.register_block("capture", Box::new(capture_block));

    parser::parse(&tokens, &options).map(Template::new)
}
<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(slice_patterns)]

use std::fs::{File};
use std::string::String;
use std::path::Path;
use std::error::FromError;
use std::io::{Read, BufReader, Write};
use std::vec::Vec;
use std::num::ParseIntError;
use std::mem;

#[derive(Debug)]
pub enum Error {
    IO,
    Parse,
    DataType,
    FieldType,
    Malformed,
    NotImplemented
}

impl FromError<std::io::Error> for Error {
    fn from_error(_: std::io::Error) -> Error {
        Error::IO
    }
}

impl FromError<ParseIntError> for Error {
    fn from_error(_: ParseIntError) -> Error {
        Error::Parse
    }
}

#[derive(Debug)]
pub enum DataType {
    XDRFloat,
    FloatLE,
}

impl DataType {
    fn from_str(s: &str) -> Result<DataType, Error> {
        match s {
            "float_le" => Ok(DataType::FloatLE),
//            "xdr_float" => Ok(DataType::XDRFloat),
            _ => Err(Error::DataType)
        }
    }
}

#[derive(Debug)]
pub enum FieldType {
    Uniform
}

impl FieldType {
    fn from_str(s: &str) -> Result<FieldType, Error> {
        match s {
            "uniform" => Ok(FieldType::Uniform),
            _ => Err(Error::FieldType)
        }
    }
}

pub struct AVSFile {
    pub ndim: usize,
    pub sizes: Vec<usize>,
    pub data_type: DataType,
    pub field_type: FieldType,
    reader: Box<Read>
}

impl AVSFile {
    pub fn write<W: Write, T>(
                writer: &mut W, dims: &[usize], data: &[T])
                    -> Result<(), Error> {
        // header
        let ndim = dims.len();
        try!(writer.write_fmt(format_args!("# AVS FLD file (written by avsfldrs github.com/greyhill/avsfldrs)\n")));
        try!(writer.write_fmt(format_args!("ndim={}\n", ndim)));
        try!(writer.write_fmt(format_args!("veclen=1\n")));
        try!(writer.write_fmt(format_args!("nspace={}\n", ndim)));
        try!(writer.write_fmt(format_args!("field=uniform\n")));
        try!(writer.write_fmt(format_args!("data=float_le\n"))); // TODO
        for (id, size) in dims.iter().enumerate() {
            try!(writer.write_fmt(format_args!("dim{}={}\n", id+1, size)));
        }
        try!(writer.write_fmt(format_args!("{}{}", 12 as char, 12 as char)));
        let b: &[u8] = unsafe {
            std::slice::from_raw_parts(data.as_ptr() as *const u8,
                                       data.len()*mem::size_of::<T>())
        };
        try!(writer.write_all(b));
        Ok(())
    }

    pub fn read<T>(self: &mut Self) -> Result<Vec<T>, Error> {
        let size = self.sizes.iter().fold(1 as usize, |l, r| l * *r);
        let mut buf_u8 = Vec::<u8>::with_capacity(mem::size_of::<T>()*size);
        try!(self.reader.read_to_end(&mut buf_u8));
        let buf: Vec<T> = unsafe {
            let ptr = buf_u8.as_mut_ptr();
            let cap = buf_u8.capacity();
            mem::forget(buf_u8);
            Vec::<T>::from_raw_parts(
                mem::transmute(ptr),
                size,
                cap / mem::size_of::<T>())
        };
        Ok(buf)
    }

    pub fn open(path: &Path) -> Result<AVSFile, Error> {
        let mut reader = BufReader::new(try!(File::open(path)));

        let mut ndim: Option<usize> = None;
        let mut sizes = Vec::<Option<usize>>::new();
        let mut data_type: Option<DataType> = None;
        let mut field_type: Option<FieldType> = None;
        let mut external: Option<String> = None;

        let mut line = String::new();
        let mut last_char: u8 = 0;
        loop {
            let mut new_char_buf: [u8;1] = [ 0u8 ];
            try!(reader.read(&mut new_char_buf));

            // break on two chr 14s
            let new_char = new_char_buf[0];
            if (new_char, last_char) == (12u8, 12u8) {
                break;
            }
            last_char = new_char;

            line.push(new_char as char);

            // new line; process the line and discard
            if new_char == 10 {
                let tokens: Vec<&str> = line.split('=')
                    .map(|s| s.trim()).collect();
                match &tokens[..] {
                    ["ndim", s] => {
                        let nd = try!(s.parse::<usize>());
                        ndim = Some(nd);
                        for _ in 0..nd {
                            sizes.push(None);
                        }
                    },
                    ["dim1", s] => sizes[0] = Some(try!(s.parse::<usize>())),
                    ["dim2", s] => sizes[1] = Some(try!(s.parse::<usize>())),
                    ["dim3", s] => sizes[2] = Some(try!(s.parse::<usize>())),
                    ["dim4", s] => sizes[3] = Some(try!(s.parse::<usize>())),
                    ["dim5", s] => sizes[4] = Some(try!(s.parse::<usize>())),
                    ["dim6", s] => sizes[5] = Some(try!(s.parse::<usize>())),
                    ["dim7", s] => sizes[6] = Some(try!(s.parse::<usize>())),
                    ["data", s] =>
                        data_type = Some(try!(DataType::from_str(s))),
                    ["field", s] =>
                        field_type = Some(try!(FieldType::from_str(s))),
                    ["variable 1 file", s] =>
                        external = Some(String::from_str(s)),
                    _ => {}
                }
            }
            // hack?  code smell?  need borrow in previous block to expire
            if new_char == 10 {
                line.clear();
            }
        }

        match external {
            None => {
                let mut tr = AVSFile {
                    ndim: try!(ndim.ok_or(Error::Malformed)),
                    sizes: Vec::<usize>::new(),
                    data_type: try!(data_type.ok_or(Error::Malformed)),
                    field_type: try!(field_type.ok_or(Error::Malformed)),
                    reader: Box::new(reader),
                };
                for idx in 0..ndim.unwrap() {
                    tr.sizes.push(
                        try!(sizes[idx].ok_or(Error::Malformed)));
                }
                Ok(tr)
            },
            Some(path) => {
                let new_reader = BufReader::new(try!(File::open(&path)));
                let mut tr = AVSFile {
                    ndim: try!(ndim.ok_or(Error::Malformed)),
                    sizes: Vec::<usize>::new(),
                    data_type: try!(data_type.ok_or(Error::Malformed)),
                    field_type: try!(field_type.ok_or(Error::Malformed)),
                    reader: Box::new(new_reader),
                };
                for idx in 0..ndim.unwrap() {
                    tr.sizes.push(
                        try!(sizes[idx].ok_or(Error::Malformed)));
                }
                Ok(tr)
            },
        }
    }
}

<commit_msg>builds on beta<commit_after>use std::fs::{File};
use std::string::String;
use std::path::Path;
use std::convert::From;
use std::io::{Read, BufReader, Write};
use std::vec::Vec;
use std::num::ParseIntError;
use std::mem;

#[derive(Debug)]
pub enum Error {
    IO,
    Parse,
    DataType,
    FieldType,
    Malformed,
    NotImplemented
}

impl From<std::io::Error> for Error {
    fn from(_: std::io::Error) -> Error {
        Error::IO
    }
}

impl From<ParseIntError> for Error {
    fn from(_: ParseIntError) -> Error {
        Error::Parse
    }
}

#[derive(Debug)]
pub enum DataType {
    XDRFloat,
    FloatLE,
}

impl DataType {
    fn from_str(s: &str) -> Result<DataType, Error> {
        match s {
            "float_le" => Ok(DataType::FloatLE),
//            "xdr_float" => Ok(DataType::XDRFloat),
            _ => Err(Error::DataType)
        }
    }
}

#[derive(Debug)]
pub enum FieldType {
    Uniform
}

impl FieldType {
    fn from_str(s: &str) -> Result<FieldType, Error> {
        match s {
            "uniform" => Ok(FieldType::Uniform),
            _ => Err(Error::FieldType)
        }
    }
}

pub struct AVSFile {
    pub ndim: usize,
    pub sizes: Vec<usize>,
    pub data_type: DataType,
    pub field_type: FieldType,
    reader: Box<Read>
}

impl AVSFile {
    pub fn write<W: Write, T>(
                writer: &mut W, dims: &[usize], data: &[T])
                    -> Result<(), Error> {
        // header
        let ndim = dims.len();
        try!(writer.write_fmt(format_args!("# AVS FLD file (written by avsfldrs github.com/greyhill/avsfldrs)\n")));
        try!(writer.write_fmt(format_args!("ndim={}\n", ndim)));
        try!(writer.write_fmt(format_args!("veclen=1\n")));
        try!(writer.write_fmt(format_args!("nspace={}\n", ndim)));
        try!(writer.write_fmt(format_args!("field=uniform\n")));
        try!(writer.write_fmt(format_args!("data=float_le\n"))); // TODO
        for (id, size) in dims.iter().enumerate() {
            try!(writer.write_fmt(format_args!("dim{}={}\n", id+1, size)));
        }
        try!(writer.write_fmt(format_args!("{}{}", 12 as char, 12 as char)));
        let b: &[u8] = unsafe {
            std::slice::from_raw_parts(data.as_ptr() as *const u8,
                                       data.len()*mem::size_of::<T>())
        };
        try!(writer.write_all(b));
        Ok(())
    }

    pub fn read<T>(self: &mut Self) -> Result<Vec<T>, Error> {
        let size = self.sizes.iter().fold(1 as usize, |l, r| l * *r);
        let mut buf_u8 = Vec::<u8>::with_capacity(mem::size_of::<T>()*size);
        try!(self.reader.read_to_end(&mut buf_u8));
        let buf: Vec<T> = unsafe {
            let ptr = buf_u8.as_mut_ptr();
            let cap = buf_u8.capacity();
            mem::forget(buf_u8);
            Vec::<T>::from_raw_parts(
                mem::transmute(ptr),
                size,
                cap / mem::size_of::<T>())
        };
        Ok(buf)
    }

    pub fn open(path: &Path) -> Result<AVSFile, Error> {
        let mut reader = BufReader::new(try!(File::open(path)));

        let mut ndim: Option<usize> = None;
        let mut sizes = Vec::<Option<usize>>::new();
        let mut data_type: Option<DataType> = None;
        let mut field_type: Option<FieldType> = None;
        let mut external: Option<String> = None;

        let mut line = String::new();
        let mut last_char: u8 = 0;
        loop {
            let mut new_char_buf: [u8;1] = [ 0u8 ];
            try!(reader.read(&mut new_char_buf));

            // break on two chr 14s
            let new_char = new_char_buf[0];
            if (new_char, last_char) == (12u8, 12u8) {
                break;
            }
            last_char = new_char;

            line.push(new_char as char);

            // new line; process the line and discard
            if new_char == 10 {
                let tokens: Vec<&str> = line.split('=')
                    .map(|s| s.trim()).collect();
                match tokens[0] {
                    "ndim" => {
                        let nd = try!(tokens[1].parse::<usize>());
                        ndim = Some(nd);
                        for _ in 0..nd {
                            sizes.push(None);
                        }
                    },
                    "dim1" => sizes[0] = Some(try!(tokens[1].parse::<usize>())),
                    "dim2" => sizes[1] = Some(try!(tokens[1].parse::<usize>())),
                    "dim3" => sizes[2] = Some(try!(tokens[1].parse::<usize>())),
                    "dim4" => sizes[3] = Some(try!(tokens[1].parse::<usize>())),
                    "dim5" => sizes[4] = Some(try!(tokens[1].parse::<usize>())),
                    "dim6" => sizes[5] = Some(try!(tokens[1].parse::<usize>())),
                    "dim7" => sizes[6] = Some(try!(tokens[1].parse::<usize>())),
                    "data" =>
                        data_type = Some(try!(DataType::from_str(tokens[1]))),
                    "field" =>
                        field_type = Some(try!(FieldType::from_str(tokens[1]))),
                    "variable 1 file" =>
                        external = Some(tokens[1].to_string()),
                    _ => {}
                }
            }
            // hack?  code smell?  need borrow in previous block to expire
            if new_char == 10 {
                line.clear();
            }
        }

        match external {
            None => {
                let mut tr = AVSFile {
                    ndim: try!(ndim.ok_or(Error::Malformed)),
                    sizes: Vec::<usize>::new(),
                    data_type: try!(data_type.ok_or(Error::Malformed)),
                    field_type: try!(field_type.ok_or(Error::Malformed)),
                    reader: Box::new(reader),
                };
                for idx in 0..ndim.unwrap() {
                    tr.sizes.push(
                        try!(sizes[idx].ok_or(Error::Malformed)));
                }
                Ok(tr)
            },
            Some(path) => {
                let new_reader = BufReader::new(try!(File::open(&path)));
                let mut tr = AVSFile {
                    ndim: try!(ndim.ok_or(Error::Malformed)),
                    sizes: Vec::<usize>::new(),
                    data_type: try!(data_type.ok_or(Error::Malformed)),
                    field_type: try!(field_type.ok_or(Error::Malformed)),
                    reader: Box::new(new_reader),
                };
                for idx in 0..ndim.unwrap() {
                    tr.sizes.push(
                        try!(sizes[idx].ok_or(Error::Malformed)));
                }
                Ok(tr)
            },
        }
    }
}

<|endoftext|>