<commit_before>// Copyright 2017 Samuel Loretan <tynril@gmail.com>

//! Triangulate a set of points

/// A two dimentional point.
#[derive(Clone, Copy, Debug)]
pub struct Point {
    x: f64,
    y: f64,
}

impl Point {
    /// Makes a new point from xy coordinates.
    pub fn new(x: f64, y: f64) -> Point {
        Point { x: x, y: y }
    }
}

/// A triangle, represented by indexes into a vertice list.
#[derive(Debug, PartialEq)]
pub struct Triangle(usize, usize, usize);

/// An edge, represented by indexes into a vertice list.
#[derive(Debug, Clone)]
struct Edge(usize, usize);

impl PartialEq for Edge {
    /// Compare edges regardless of directionality.
    fn eq(&self, other: &Edge) -> bool {
        (self.0 == other.1 && self.1 == other.0) || (self.0 == other.0 && self.1 == other.1)
    }
}

/// An indexable view over two slices.
struct TwoSlices<'a, T: 'a>(&'a [T], &'a [T]);

use std::ops::Index;
impl<'a, T: 'a> Index<usize> for TwoSlices<'a, T> {
    type Output = T;
    fn index(&self, index: usize) -> &T {
        let first_slice_len = self.0.len();
        if index < first_slice_len {
            &self.0[index]
        } else {
            &self.1[index - first_slice_len]
        }
    }
}

/// Triangulate a given set of points. The returned triangles are indices into the list of points.
pub fn triangulate(points: &[Point]) -> Vec<Triangle> {
    // Make sure we have enough points to do a triangulation.
    let points_count = points.len();
    if points_count < 3 {
        panic!("Can't triangulate less than three points.")
    }

    // Find the bounds of the space that contains our points.
    let (min_point, max_point) = points.iter().fold((points[0], points[0]), |acc, &p| {
        (Point::new(acc.0.x.min(p.x), acc.0.y.min(p.y)),
         Point::new(acc.1.x.max(p.x), acc.1.y.max(p.y)))
    });
    let delta_point = Point::new(max_point.x - min_point.x, max_point.y - min_point.y);
    let delta_max = delta_point.x.max(delta_point.y);
    let mid_point = Point::new((max_point.x + min_point.x) * 0.5,
                               (max_point.y + min_point.y) * 0.5);

    // Compute the supertriangle, which encompasses all the input points.
    let supertriangle = [Point::new(mid_point.x - 2.0 * delta_max, mid_point.y - delta_max),
                         Point::new(mid_point.x, mid_point.y + 2.0 * delta_max),
                         Point::new(mid_point.x + 2.0 * delta_max, mid_point.y - delta_max)];

    // Make an iterable slice of our points and the supertriangle.
    let all_points = TwoSlices(points, &supertriangle);

    // The list of triangles we're gonna fill, initialized with the super-triangle.
    let mut triangles = vec![Triangle(points_count, points_count + 1, points_count + 2)];

    // Include each of the input point into the mesh.
    for i in 0..points_count {
        // Storage for the edges
        let mut edges = Vec::<Edge>::new();
        triangles.retain(|ref t| {
            if in_circumcircle(all_points[i],
                               (all_points[t.0], all_points[t.1], all_points[t.2])) {
                edges.extend([Edge(t.0, t.1), Edge(t.1, t.2), Edge(t.2, t.0)].iter().cloned());
                false
            } else {
                true
            }
        });

        // Remove duplicate edges.
        let mut to_remove = Vec::<usize>::new();
        let edges_count = edges.len();
        for (j, ref e1) in edges.iter().enumerate().rev().skip(1) {
            for (k, ref e2) in edges.iter().enumerate().rev().take(edges_count - j - 1) {
                if e1 == e2 {
                    to_remove.extend([j, k].iter().cloned());
                    break;
                }
            }
        }
        to_remove.sort();
        for j in to_remove.iter().rev() {
            edges.remove(*j);
        }

        // Form new triangles from the remaining edges. Edges are added in clockwise order.
        triangles.extend(edges.iter().map(|ref e| Triangle(e.0, e.1, i)));
    }

    // Remove triangles with supertriangle vertices
    triangles.retain(|ref t| t.0 < points_count && t.1 < points_count && t.2 < points_count);

    triangles
}

/// Returns true if the point lies inside (or on the edge of) the circumcircle made from the
/// triangle.
fn in_circumcircle(point: Point, triangle: (Point, Point, Point)) -> bool {
    // Handle coincident points in the input triangle.
    if (triangle.0.y - triangle.1.y).abs() < std::f64::EPSILON &&
       (triangle.1.y - triangle.2.y).abs() < std::f64::EPSILON {
        return false;
    }

    // Compute the center of the triangle's circumcircle.
    let mut circumcircle_center = Point::new(0.0, 0.0);
    if (triangle.1.y - triangle.0.y).abs() < std::f64::EPSILON {
        let mid = 0.0 - (triangle.2.x - triangle.1.x) / (triangle.2.y - triangle.1.y);
        let mid_point = Point::new((triangle.1.x + triangle.2.x) * 0.5,
                                   (triangle.1.y + triangle.2.y) * 0.5);
        circumcircle_center.x = (triangle.1.x + triangle.0.x) * 0.5;
        circumcircle_center.y = mid * (circumcircle_center.x - mid_point.x) + mid_point.y;
    } else if (triangle.2.y - triangle.1.y).abs() < std::f64::EPSILON {
        let mid = 0.0 - (triangle.1.x - triangle.0.x) / (triangle.1.y - triangle.0.y);
        let mid_point = Point::new((triangle.0.x + triangle.1.x) * 0.5,
                                   (triangle.0.y + triangle.1.y) * 0.5);
        circumcircle_center.x = (triangle.2.x + triangle.1.x) * 0.5;
        circumcircle_center.y = mid * (circumcircle_center.x - mid_point.x) + mid_point.y;
    } else {
        let mid1 = 0.0 - (triangle.1.x - triangle.0.x) / (triangle.1.y - triangle.0.y);
        let mid2 = 0.0 - (triangle.2.x - triangle.1.x) / (triangle.2.y - triangle.1.y);
        let mid_point1 = Point::new((triangle.0.x + triangle.1.x) * 0.5,
                                    (triangle.0.y + triangle.1.y) * 0.5);
        let mid_point2 = Point::new((triangle.1.x + triangle.2.x) * 0.5,
                                    (triangle.1.y + triangle.2.y) * 0.5);
        circumcircle_center.x = (mid1 * mid_point1.x - mid2 * mid_point2.x + mid_point2.y -
                                 mid_point1.y) / (mid1 - mid2);
        circumcircle_center.y = mid1 * (circumcircle_center.x - mid_point1.x) + mid_point1.y;
    }

    // Check the radius of the circumcircle against the point's distance from its center.
    let circumcircle_radius_sq = (triangle.1.x - circumcircle_center.x).powf(2.0) +
                                 (triangle.1.y - circumcircle_center.y).powf(2.0);
    let point_distance_sq = (point.x - circumcircle_center.x).powf(2.0) +
                            (point.y - circumcircle_center.y).powf(2.0);

    point_distance_sq <= circumcircle_radius_sq
}

#[cfg(test)]
mod test {
    use super::{Point, Triangle, triangulate};

    #[test]
    fn test_simple() {
        let points = vec![Point::new(10.0, 10.0), Point::new(25.0, 15.0), Point::new(15.0, 25.0)];

        let tris: Vec<Triangle> = triangulate(&points);

        assert_eq!(tris.len(), 1);
        assert_eq!(tris[..], [Triangle(1, 0, 2)][..]);
    }

    #[test]
    fn test_four_triangles() {
        let points = vec![Point::new(10.0, 10.0),
                          Point::new(25.0, 15.0),
                          Point::new(15.0, 25.0),
                          Point::new(30.0, 25.0),
                          Point::new(40.0, 15.0)];

        let tris: Vec<Triangle> = triangulate(&points);
        assert_eq!(tris.len(), 4);

        let expected_tris =
            [Triangle(1, 0, 2), Triangle(1, 2, 3), Triangle(0, 1, 4), Triangle(1, 3, 4)];
        assert_eq!(tris[..], expected_tris[..]);
    }

    #[test]
    fn test_overlapping() {
        let points = vec![Point::new(10.0, 10.0), Point::new(25.0, 15.0), Point::new(25.0, 15.0)];

        let tris: Vec<Triangle> = triangulate(&points);

        assert_eq!(tris.len(), 1);
        assert_eq!(tris[..], [Triangle(0, 1, 2)][..]);
    }

    #[test]
    fn test_complex() {
        let points = vec![Point::new(601.0, 535.0),
                          Point::new(895.0, 666.0),
                          Point::new(876.0, 110.0),
                          Point::new(448.0, 36.0),
                          Point::new(829.0, 512.0),
                          Point::new(742.0, 363.0),
                          Point::new(267.0, 152.0),
                          Point::new(331.0, 244.0),
                          Point::new(623.0, 335.0),
                          Point::new(245.0, 119.0),
                          Point::new(104.0, 522.0),
                          Point::new(285.0, 561.0),
                          Point::new(282.0, 17.0),
                          Point::new(836.0, 20.0),
                          Point::new(667.0, 462.0),
                          Point::new(65.0, 216.0),
                          Point::new(839.0, 178.0),
                          Point::new(11.0, 264.0),
                          Point::new(181.0, 479.0),
                          Point::new(168.0, 90.0),
                          Point::new(348.0, 504.0),
                          Point::new(688.0, 605.0),
                          Point::new(329.0, 432.0),
                          Point::new(627.0, 461.0),
                          Point::new(450.0, 514.0)];

        let tris: Vec<Triangle> = triangulate(&points);

        let expected_tris = [Triangle(1, 2, 4),
                             Triangle(3, 6, 7),
                             Triangle(3, 7, 8),
                             Triangle(6, 3, 12),
                             Triangle(9, 6, 12),
                             Triangle(12, 3, 13),
                             Triangle(4, 5, 14),
                             Triangle(5, 8, 14),
                             Triangle(7, 6, 15),
                             Triangle(4, 2, 16),
                             Triangle(5, 4, 16),
                             Triangle(8, 5, 16),
                             Triangle(3, 8, 16),
                             Triangle(13, 3, 16),
                             Triangle(2, 13, 16),
                             Triangle(10, 11, 18),
                             Triangle(7, 15, 18),
                             Triangle(15, 17, 18),
                             Triangle(17, 10, 18),
                             Triangle(6, 9, 19),
                             Triangle(15, 6, 19),
                             Triangle(9, 12, 19),
                             Triangle(17, 15, 19),
                             Triangle(1, 4, 21),
                             Triangle(4, 14, 21),
                             Triangle(14, 0, 21),
                             Triangle(8, 7, 22),
                             Triangle(7, 18, 22),
                             Triangle(18, 11, 22),
                             Triangle(11, 20, 22),
                             Triangle(0, 14, 23),
                             Triangle(14, 8, 23),
                             Triangle(20, 11, 24),
                             Triangle(11, 21, 24),
                             Triangle(21, 0, 24),
                             Triangle(8, 22, 24),
                             Triangle(23, 8, 24),
                             Triangle(0, 23, 24),
                             Triangle(22, 20, 24)];

        assert_eq!(tris.len(), 39);
        assert_eq!(tris[..], expected_tris[..]);
    }
}
<commit_msg>Some small tests cleanup.<commit_after>// Copyright 2017 Samuel Loretan <tynril@gmail.com>

//! Triangulate a set of points

/// A two dimentional point.
#[derive(Clone, Copy, Debug)]
pub struct Point {
    x: f64,
    y: f64,
}

impl Point {
    /// Makes a new point from xy coordinates.
    pub fn new(x: f64, y: f64) -> Point {
        Point { x: x, y: y }
    }
}

/// A triangle, represented by indexes into a vertice list.
#[derive(Debug, PartialEq)]
pub struct Triangle(usize, usize, usize);

/// An edge, represented by indexes into a vertice list.
#[derive(Debug, Clone)]
struct Edge(usize, usize);

impl PartialEq for Edge {
    /// Compare edges regardless of directionality.
    fn eq(&self, other: &Edge) -> bool {
        (self.0 == other.1 && self.1 == other.0) || (self.0 == other.0 && self.1 == other.1)
    }
}

/// An indexable view over two slices.
struct TwoSlices<'a, T: 'a>(&'a [T], &'a [T]);

use std::ops::Index;
impl<'a, T: 'a> Index<usize> for TwoSlices<'a, T> {
    type Output = T;
    fn index(&self, index: usize) -> &T {
        let first_slice_len = self.0.len();
        if index < first_slice_len {
            &self.0[index]
        } else {
            &self.1[index - first_slice_len]
        }
    }
}

/// Triangulate a given set of points. The returned triangles are indices into the list of points.
pub fn triangulate(points: &[Point]) -> Vec<Triangle> {
    // Make sure we have enough points to do a triangulation.
    let points_count = points.len();
    if points_count < 3 {
        panic!("Can't triangulate less than three points.")
    }

    // Find the bounds of the space that contains our points.
    let (min_point, max_point) = points.iter().fold((points[0], points[0]), |acc, &p| {
        (Point::new(acc.0.x.min(p.x), acc.0.y.min(p.y)),
         Point::new(acc.1.x.max(p.x), acc.1.y.max(p.y)))
    });
    let delta_point = Point::new(max_point.x - min_point.x, max_point.y - min_point.y);
    let delta_max = delta_point.x.max(delta_point.y);
    let mid_point = Point::new((max_point.x + min_point.x) * 0.5,
                               (max_point.y + min_point.y) * 0.5);

    // Compute the supertriangle, which encompasses all the input points.
    let supertriangle = [Point::new(mid_point.x - 2.0 * delta_max, mid_point.y - delta_max),
                         Point::new(mid_point.x, mid_point.y + 2.0 * delta_max),
                         Point::new(mid_point.x + 2.0 * delta_max, mid_point.y - delta_max)];

    // Make an iterable slice of our points and the supertriangle.
    let all_points = TwoSlices(points, &supertriangle);

    // The list of triangles we're gonna fill, initialized with the super-triangle.
    let mut triangles = vec![Triangle(points_count, points_count + 1, points_count + 2)];

    // Include each of the input point into the mesh.
    for i in 0..points_count {
        // Storage for the edges
        let mut edges = Vec::<Edge>::new();
        triangles.retain(|ref t| {
            if in_circumcircle(all_points[i],
                               (all_points[t.0], all_points[t.1], all_points[t.2])) {
                edges.extend([Edge(t.0, t.1), Edge(t.1, t.2), Edge(t.2, t.0)].iter().cloned());
                false
            } else {
                true
            }
        });

        // Remove duplicate edges.
        let mut to_remove = Vec::<usize>::new();
        let edges_count = edges.len();
        for (j, ref e1) in edges.iter().enumerate().rev().skip(1) {
            for (k, ref e2) in edges.iter().enumerate().rev().take(edges_count - j - 1) {
                if e1 == e2 {
                    to_remove.extend([j, k].iter().cloned());
                    break;
                }
            }
        }
        to_remove.sort();
        for j in to_remove.iter().rev() {
            edges.remove(*j);
        }

        // Form new triangles from the remaining edges. Edges are added in clockwise order.
        triangles.extend(edges.iter().map(|ref e| Triangle(e.0, e.1, i)));
    }

    // Remove triangles with supertriangle vertices
    triangles.retain(|ref t| t.0 < points_count && t.1 < points_count && t.2 < points_count);

    triangles
}

/// Returns true if the point lies inside (or on the edge of) the circumcircle made from the
/// triangle.
fn in_circumcircle(point: Point, triangle: (Point, Point, Point)) -> bool {
    // Handle coincident points in the input triangle.
    if (triangle.0.y - triangle.1.y).abs() < std::f64::EPSILON &&
       (triangle.1.y - triangle.2.y).abs() < std::f64::EPSILON {
        return false;
    }

    // Compute the center of the triangle's circumcircle.
    let mut circumcircle_center = Point::new(0.0, 0.0);
    if (triangle.1.y - triangle.0.y).abs() < std::f64::EPSILON {
        let mid = 0.0 - (triangle.2.x - triangle.1.x) / (triangle.2.y - triangle.1.y);
        let mid_point = Point::new((triangle.1.x + triangle.2.x) * 0.5,
                                   (triangle.1.y + triangle.2.y) * 0.5);
        circumcircle_center.x = (triangle.1.x + triangle.0.x) * 0.5;
        circumcircle_center.y = mid * (circumcircle_center.x - mid_point.x) + mid_point.y;
    } else if (triangle.2.y - triangle.1.y).abs() < std::f64::EPSILON {
        let mid = 0.0 - (triangle.1.x - triangle.0.x) / (triangle.1.y - triangle.0.y);
        let mid_point = Point::new((triangle.0.x + triangle.1.x) * 0.5,
                                   (triangle.0.y + triangle.1.y) * 0.5);
        circumcircle_center.x = (triangle.2.x + triangle.1.x) * 0.5;
        circumcircle_center.y = mid * (circumcircle_center.x - mid_point.x) + mid_point.y;
    } else {
        let mid1 = 0.0 - (triangle.1.x - triangle.0.x) / (triangle.1.y - triangle.0.y);
        let mid2 = 0.0 - (triangle.2.x - triangle.1.x) / (triangle.2.y - triangle.1.y);
        let mid_point1 = Point::new((triangle.0.x + triangle.1.x) * 0.5,
                                    (triangle.0.y + triangle.1.y) * 0.5);
        let mid_point2 = Point::new((triangle.1.x + triangle.2.x) * 0.5,
                                    (triangle.1.y + triangle.2.y) * 0.5);
        circumcircle_center.x = (mid1 * mid_point1.x - mid2 * mid_point2.x + mid_point2.y -
                                 mid_point1.y) / (mid1 - mid2);
        circumcircle_center.y = mid1 * (circumcircle_center.x - mid_point1.x) + mid_point1.y;
    }

    // Check the radius of the circumcircle against the point's distance from its center.
    let circumcircle_radius_sq = (triangle.1.x - circumcircle_center.x).powf(2.0) +
                                 (triangle.1.y - circumcircle_center.y).powf(2.0);
    let point_distance_sq = (point.x - circumcircle_center.x).powf(2.0) +
                            (point.y - circumcircle_center.y).powf(2.0);

    point_distance_sq <= circumcircle_radius_sq
}

#[cfg(test)]
mod tests {
    use super::{Point, Triangle, triangulate};

    #[test]
    fn test_simple() {
        let points = [Point::new(10.0, 10.0), Point::new(25.0, 15.0), Point::new(15.0, 25.0)];
        let tris: Vec<Triangle> = triangulate(&points);

        assert_eq!(tris.len(), 1);
        assert_eq!(tris[..], [Triangle(1, 0, 2)][..]);
    }

    #[test]
    fn test_four_triangles() {
        let points = [Point::new(10.0, 10.0),
                      Point::new(25.0, 15.0),
                      Point::new(15.0, 25.0),
                      Point::new(30.0, 25.0),
                      Point::new(40.0, 15.0)];

        let tris: Vec<Triangle> = triangulate(&points);
        assert_eq!(tris.len(), 4);

        let expected_tris =
            [Triangle(1, 0, 2), Triangle(1, 2, 3), Triangle(0, 1, 4), Triangle(1, 3, 4)];
        assert_eq!(tris[..], expected_tris[..]);
    }

    #[test]
    fn test_overlapping() {
        let points = vec![Point::new(10.0, 10.0), Point::new(25.0, 15.0), Point::new(25.0, 15.0)];

        let tris: Vec<Triangle> = triangulate(&points);

        assert_eq!(tris.len(), 1);
        assert_eq!(tris[..], [Triangle(0, 1, 2)][..]);
    }

    #[test]
    fn test_complex() {
        let points = [Point::new(601.0, 535.0),
                      Point::new(895.0, 666.0),
                      Point::new(876.0, 110.0),
                      Point::new(448.0, 36.0),
                      Point::new(829.0, 512.0),
                      Point::new(742.0, 363.0),
                      Point::new(267.0, 152.0),
                      Point::new(331.0, 244.0),
                      Point::new(623.0, 335.0),
                      Point::new(245.0, 119.0),
                      Point::new(104.0, 522.0),
                      Point::new(285.0, 561.0),
                      Point::new(282.0, 17.0),
                      Point::new(836.0, 20.0),
                      Point::new(667.0, 462.0),
                      Point::new(65.0, 216.0),
                      Point::new(839.0, 178.0),
                      Point::new(11.0, 264.0),
                      Point::new(181.0, 479.0),
                      Point::new(168.0, 90.0),
                      Point::new(348.0, 504.0),
                      Point::new(688.0, 605.0),
                      Point::new(329.0, 432.0),
                      Point::new(627.0, 461.0),
                      Point::new(450.0, 514.0)];

        let tris: Vec<Triangle> = triangulate(&points);

        let expected_tris = [Triangle(1, 2, 4),
                             Triangle(3, 6, 7),
                             Triangle(3, 7, 8),
                             Triangle(6, 3, 12),
                             Triangle(9, 6, 12),
                             Triangle(12, 3, 13),
                             Triangle(4, 5, 14),
                             Triangle(5, 8, 14),
                             Triangle(7, 6, 15),
                             Triangle(4, 2, 16),
                             Triangle(5, 4, 16),
                             Triangle(8, 5, 16),
                             Triangle(3, 8, 16),
                             Triangle(13, 3, 16),
                             Triangle(2, 13, 16),
                             Triangle(10, 11, 18),
                             Triangle(7, 15, 18),
                             Triangle(15, 17, 18),
                             Triangle(17, 10, 18),
                             Triangle(6, 9, 19),
                             Triangle(15, 6, 19),
                             Triangle(9, 12, 19),
                             Triangle(17, 15, 19),
                             Triangle(1, 4, 21),
                             Triangle(4, 14, 21),
                             Triangle(14, 0, 21),
                             Triangle(8, 7, 22),
                             Triangle(7, 18, 22),
                             Triangle(18, 11, 22),
                             Triangle(11, 20, 22),
                             Triangle(0, 14, 23),
                             Triangle(14, 8, 23),
                             Triangle(20, 11, 24),
                             Triangle(11, 21, 24),
                             Triangle(21, 0, 24),
                             Triangle(8, 22, 24),
                             Triangle(23, 8, 24),
                             Triangle(0, 23, 24),
                             Triangle(22, 20, 24)];

        assert_eq!(tris.len(), 39);
        assert_eq!(tris[..], expected_tris[..]);
    }
}
<|endoftext|>


<commit_before>#![feature(zero_one, box_syntax)]

extern crate asexp;

pub mod num_expr;
pub mod cond;

use std::fmt::Debug;
use std::cmp::{PartialEq, PartialOrd};

#[derive(Debug, Eq, PartialEq)]
pub enum ExpressionError {
    /// In case of division by zero.
    DivByZero,
    /// In case an invalid variable in references from the expression.
    InvalidVariable,
    /// In case of an invalid operation.
    InvalidOperation,
}

pub trait ElementType: Debug + Copy + Clone + PartialEq + PartialOrd + Default + Sized {}

pub trait Expression: Debug + Clone + PartialEq
{
    type Element: ElementType;
    /// Evaluates the expression with the given variables bound.
    fn evaluate(&self, variables: &[Self::Element]) -> Result<Self::Element, ExpressionError>;

    /// Constructs a constant expression. Required by lindenmayer-system.
    fn make_const(elm: Self::Element) -> Self;
}

pub trait Condition: Debug + Clone + PartialEq
{
    type Expr: Expression;
    /// Evaluate the condition with the given variables bound.
    fn evaluate(&self,
                variables: &[<Self::Expr as Expression>::Element])
                -> Result<bool, ExpressionError>;
}
<commit_msg>Revert "Add Sized trait to ElementType"<commit_after>#![feature(zero_one, box_syntax)]

extern crate asexp;

pub mod num_expr;
pub mod cond;

use std::fmt::Debug;
use std::cmp::{PartialEq, PartialOrd};

#[derive(Debug, Eq, PartialEq)]
pub enum ExpressionError {
    /// In case of division by zero.
    DivByZero,
    /// In case an invalid variable in references from the expression.
    InvalidVariable,
    /// In case of an invalid operation.
    InvalidOperation,
}

pub trait ElementType: Debug + Copy + Clone + PartialEq + PartialOrd + Default {}

pub trait Expression: Debug + Clone + PartialEq
{
    type Element: ElementType;
    /// Evaluates the expression with the given variables bound.
    fn evaluate(&self, variables: &[Self::Element]) -> Result<Self::Element, ExpressionError>;

    /// Constructs a constant expression. Required by lindenmayer-system.
    fn make_const(elm: Self::Element) -> Self;
}

pub trait Condition: Debug + Clone + PartialEq
{
    type Expr: Expression;
    /// Evaluate the condition with the given variables bound.
    fn evaluate(&self,
                variables: &[<Self::Expr as Expression>::Element])
                -> Result<bool, ExpressionError>;
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate "posix-ipc" as ipc;

use std::os;
use std::ptr;
use std::default::Default;
use std::vec::Vec;
use std::mem;
use std::iter;
use std::num::FromPrimitive;

pub type Address = u64;
pub type Word = u64;

pub enum Action {
  Allow,
  Kill
}

#[derive(Show)]
pub enum Request {
  TraceMe = 0,
  PeekText = 1,
  PeekData = 2,
  PeekUser = 3,
  PokeText = 4,
  PokeData = 5,
  PokeUser = 6,
  Continue = 7,
  Kill = 8,
  SingleStep = 9,
  GetRegs = 12,
  SetRegs = 13,
  Attach = 16,
  Detatch = 17,
  SetOptions = 0x4200,
  Seize = 0x4206
}

#[derive(Copy, Show, FromPrimitive)]
pub enum Event {
  Fork = 1,
  VFork = 2,
  Clone = 3,
  Exec = 4,
  VForkDone = 5,
  Exit = 6,
  Seccomp = 7,
  Stop = 128
}

impl Event {
    pub fn from_wait_status(st: i32) -> Option<Event> {
        let e: Option<Event> = FromPrimitive::from_i32(((st >> 8) & !5) >> 8);
        return e;
    }
}

#[derive(Copy, Default, Show)]
pub struct Registers {
  pub r15: Word,
  pub r14: Word,
  pub r13: Word,
  pub r12: Word,
  pub rbp: Word,
  pub rbx: Word,
  pub r11: Word,
  pub r10: Word,
  pub r9: Word,
  pub r8: Word,
  pub rax: Word,
  pub rcx: Word,
  pub rdx: Word,
  pub rsi: Word,
  pub rdi: Word,
  pub orig_rax: Word,
  pub rip: Word,
  pub cs: Word,
  pub eflags: Word,
  pub rsp: Word,
  pub ss: Word,
  pub fs_base: Word,
  pub gs_base: Word,
  pub ds: Word,
  pub es: Word,
  pub fs: Word,
  pub gs: Word
}

bitflags! {
  flags Options: u32 {
    const SysGood = 1,
    const TraceFork = 1 << 1,
    const TraceVFork = 1 << 2,
    const TraceClone = 1 << 3,
    const TraceExec = 1 << 4,
    const TraceVForkDone = 1 << 5,
    const TraceExit = 1 << 6,
    const TraceSeccomp = 1 << 7,
    const ExitKill = 1 << 20
  }
}

pub fn setoptions(pid: libc::pid_t, opts: Options) -> Result<libc::c_long, usize> {
  unsafe {
    raw (Request::SetOptions, pid, ptr::null_mut(), opts.bits as *mut
    libc::c_void)
  }
}

pub fn getregs(pid: libc::pid_t) -> Registers {
  let mut buf: Registers = Default::default();
  let buf_mut: *mut Registers = &mut buf;

  unsafe {
    raw (Request::GetRegs, pid, ptr::null_mut(), buf_mut as *mut libc::c_void);
  }

  return buf;
}

pub fn setregs(pid: libc::pid_t, regs: &Registers) -> Result<libc::c_long, usize> {
    unsafe {
        let mut buf: *mut libc::c_void = mem::transmute(regs);
        raw (Request::SetRegs, pid, ptr::null_mut(), buf)
    }
}

pub fn seize(pid: libc::pid_t) -> Result<libc::c_long, usize> {
    unsafe {
        raw (Request::Seize, pid, ptr::null_mut(), ptr::null_mut())
    }
}

pub fn attach(pid: libc::pid_t) -> Result<libc::c_long, usize> {
  unsafe {
    raw (Request::Attach, pid, ptr::null_mut(), ptr::null_mut())
  }
}

pub fn release(pid: libc::pid_t, signal: ipc::signals::Signal) {
  unsafe {
    raw (Request::Detatch, pid, ptr::null_mut(), (signal as u32) as *mut libc::c_void);
  }
}

pub fn cont(pid: libc::pid_t, signal: ipc::signals::Signal) -> Result<libc::c_long, usize> {
  unsafe {
    raw (Request::Continue, pid, ptr::null_mut(), (signal as u32) as *mut libc::c_void)
  }
}

pub fn traceme() -> Result<libc::c_long, usize> {
  unsafe {
    raw (Request::TraceMe, 0, ptr::null_mut(), ptr::null_mut())
  }
}

unsafe fn raw(request: Request,
       pid: libc::pid_t,
       addr: *mut libc::c_void,
       data: *mut libc::c_void) -> Result<libc::c_long, usize> {
  let v = ptrace (request as libc::c_int, pid, addr, data);
  match v {
      -1 => Result::Err(os::errno()),
      _ => Result::Ok(v)
  }
}

extern {
  fn ptrace(request: libc::c_int,
            pid: libc::pid_t,
            addr: *mut libc::c_void,
            data: *mut libc::c_void) -> libc::c_long;
}

#[derive(Copy, Show)]
pub struct Syscall {
  pub args: [Word; 6],
  pub call: u64,
  pub pid: libc::pid_t,
  pub returnVal: Word
}

impl Syscall {
  pub fn from_pid(pid: libc::pid_t) -> Syscall {
    let regs = getregs (pid);
    Syscall {
      pid: pid,
      call: regs.orig_rax,
      args: [regs.rdi, regs.rsi, regs.rdx, regs.rcx, regs.r8, regs.r9],
      returnVal: 0
    }
  }

  pub fn write(&self) -> Result<libc::c_long, usize> {
      let mut regs = getregs(self.pid);
      regs.rdi = self.args[0];
      regs.rsi = self.args[1];
      regs.rdx = self.args[2];
      regs.rcx = self.args[3];
      regs.r8 = self.args[4];
      regs.r9 = self.args[5];
      regs.orig_rax = self.call;
      regs.rax = self.returnVal;
      setregs(self.pid, &regs)
  }
}

pub struct Reader {
  pub pid: libc::pid_t
}

impl Reader {
  pub fn new(pid: libc::pid_t) -> Reader {
    Reader {
      pid: pid
    }
  }

    pub fn peek_data(&self, address: Address) -> Result<Word, usize> {
        let l;
        unsafe {
            l = raw (Request::PeekData, self.pid, address as *mut libc::c_void, ptr::null_mut())
        }
        match l {
            Result::Err(e) => Result::Err(e),
            _ => Result::Ok(l.unwrap() as Word)
        }
    }

    pub fn read_string(&self, address: Address) -> Vec<u8> {
        let mut end_of_str = false;
        let mut buf: Vec<u8> = Vec::with_capacity(1024);
        let max_addr = address + buf.capacity() as Address;
        let align_end = max_addr - (max_addr % mem::size_of::<Word>() as Address);
        'finish: for read_addr in iter::range_step(address, align_end, mem::size_of::<Word>() as Address) {
            let d = self.peek_data(read_addr).ok().expect("Could not read");
            for word_idx in iter::range(0, mem::size_of::<Word>()) {
                let chr = ((d >> (word_idx*8) as uint) & 0xff) as u8;
                if chr == 0 {
                    end_of_str = true;
                    break 'finish;
                }
                buf.push (chr);
            }
        }
        if !end_of_str {
            let d = self.peek_data(align_end).ok().expect("Could not read");
            for word_idx in range(0, mem::size_of::<Word>()) {
                let chr = ((d >> (word_idx*8) as uint) & 0xff) as u8;
                if chr == 0 {
                    break;
                }
                buf.push (chr);
            }
        }
        return buf;
    }
}
<commit_msg>warnings--<commit_after>#[allow(unstable)]
extern crate libc;
extern crate "posix-ipc" as ipc;

use std::os;
use std::ptr;
use std::default::Default;
use std::vec::Vec;
use std::mem;
use std::iter;
use std::num::FromPrimitive;

pub type Address = u64;
pub type Word = u64;

#[derive(Copy)]
pub enum Action {
  Allow,
  Kill
}

#[derive(Show, Copy)]
pub enum Request {
  TraceMe = 0,
  PeekText = 1,
  PeekData = 2,
  PeekUser = 3,
  PokeText = 4,
  PokeData = 5,
  PokeUser = 6,
  Continue = 7,
  Kill = 8,
  SingleStep = 9,
  GetRegs = 12,
  SetRegs = 13,
  Attach = 16,
  Detatch = 17,
  SetOptions = 0x4200,
  Seize = 0x4206
}

#[derive(Copy, Show, FromPrimitive)]
pub enum Event {
  Fork = 1,
  VFork = 2,
  Clone = 3,
  Exec = 4,
  VForkDone = 5,
  Exit = 6,
  Seccomp = 7,
  Stop = 128
}

impl Event {
    pub fn from_wait_status(st: i32) -> Option<Event> {
        let e: Option<Event> = FromPrimitive::from_i32(((st >> 8) & !5) >> 8);
        return e;
    }
}

#[derive(Copy, Default, Show)]
pub struct Registers {
  pub r15: Word,
  pub r14: Word,
  pub r13: Word,
  pub r12: Word,
  pub rbp: Word,
  pub rbx: Word,
  pub r11: Word,
  pub r10: Word,
  pub r9: Word,
  pub r8: Word,
  pub rax: Word,
  pub rcx: Word,
  pub rdx: Word,
  pub rsi: Word,
  pub rdi: Word,
  pub orig_rax: Word,
  pub rip: Word,
  pub cs: Word,
  pub eflags: Word,
  pub rsp: Word,
  pub ss: Word,
  pub fs_base: Word,
  pub gs_base: Word,
  pub ds: Word,
  pub es: Word,
  pub fs: Word,
  pub gs: Word
}

bitflags! {
  flags Options: u32 {
    const SysGood = 1,
    const TraceFork = 1 << 1,
    const TraceVFork = 1 << 2,
    const TraceClone = 1 << 3,
    const TraceExec = 1 << 4,
    const TraceVForkDone = 1 << 5,
    const TraceExit = 1 << 6,
    const TraceSeccomp = 1 << 7,
    const ExitKill = 1 << 20
  }
}

pub fn setoptions(pid: libc::pid_t, opts: Options) -> Result<libc::c_long, usize> {
  unsafe {
    raw (Request::SetOptions, pid, ptr::null_mut(), opts.bits as *mut
    libc::c_void)
  }
}

pub fn getregs(pid: libc::pid_t) -> Registers {
  let mut buf: Registers = Default::default();
  let buf_mut: *mut Registers = &mut buf;

  unsafe {
    raw (Request::GetRegs, pid, ptr::null_mut(), buf_mut as *mut libc::c_void);
  }

  return buf;
}

pub fn setregs(pid: libc::pid_t, regs: &Registers) -> Result<libc::c_long, usize> {
    unsafe {
        let mut buf: *mut libc::c_void = mem::transmute(regs);
        raw (Request::SetRegs, pid, ptr::null_mut(), buf)
    }
}

pub fn seize(pid: libc::pid_t) -> Result<libc::c_long, usize> {
    unsafe {
        raw (Request::Seize, pid, ptr::null_mut(), ptr::null_mut())
    }
}

pub fn attach(pid: libc::pid_t) -> Result<libc::c_long, usize> {
  unsafe {
    raw (Request::Attach, pid, ptr::null_mut(), ptr::null_mut())
  }
}

pub fn release(pid: libc::pid_t, signal: ipc::signals::Signal) {
  unsafe {
    raw (Request::Detatch, pid, ptr::null_mut(), (signal as u32) as *mut libc::c_void);
  }
}

pub fn cont(pid: libc::pid_t, signal: ipc::signals::Signal) -> Result<libc::c_long, usize> {
  unsafe {
    raw (Request::Continue, pid, ptr::null_mut(), (signal as u32) as *mut libc::c_void)
  }
}

pub fn traceme() -> Result<libc::c_long, usize> {
  unsafe {
    raw (Request::TraceMe, 0, ptr::null_mut(), ptr::null_mut())
  }
}

unsafe fn raw(request: Request,
       pid: libc::pid_t,
       addr: *mut libc::c_void,
       data: *mut libc::c_void) -> Result<libc::c_long, usize> {
  let v = ptrace (request as libc::c_int, pid, addr, data);
  match v {
      -1 => Result::Err(os::errno()),
      _ => Result::Ok(v)
  }
}

extern {
  fn ptrace(request: libc::c_int,
            pid: libc::pid_t,
            addr: *mut libc::c_void,
            data: *mut libc::c_void) -> libc::c_long;
}

#[derive(Copy, Show)]
pub struct Syscall {
  pub args: [Word; 6],
  pub call: u64,
  pub pid: libc::pid_t,
  pub returnVal: Word
}

impl Syscall {
  pub fn from_pid(pid: libc::pid_t) -> Syscall {
    let regs = getregs (pid);
    Syscall {
      pid: pid,
      call: regs.orig_rax,
      args: [regs.rdi, regs.rsi, regs.rdx, regs.rcx, regs.r8, regs.r9],
      returnVal: 0
    }
  }

  pub fn write(&self) -> Result<libc::c_long, usize> {
      let mut regs = getregs(self.pid);
      regs.rdi = self.args[0];
      regs.rsi = self.args[1];
      regs.rdx = self.args[2];
      regs.rcx = self.args[3];
      regs.r8 = self.args[4];
      regs.r9 = self.args[5];
      regs.orig_rax = self.call;
      regs.rax = self.returnVal;
      setregs(self.pid, &regs)
  }
}

pub struct Reader {
  pub pid: libc::pid_t
}

impl Reader {
  pub fn new(pid: libc::pid_t) -> Reader {
    Reader {
      pid: pid
    }
  }

    pub fn peek_data(&self, address: Address) -> Result<Word, usize> {
        let l;
        unsafe {
            l = raw (Request::PeekData, self.pid, address as *mut libc::c_void, ptr::null_mut())
        }
        match l {
            Result::Err(e) => Result::Err(e),
            _ => Result::Ok(l.unwrap() as Word)
        }
    }

    pub fn read_string(&self, address: Address) -> Vec<u8> {
        let mut end_of_str = false;
        let mut buf: Vec<u8> = Vec::with_capacity(1024);
        let max_addr = address + buf.capacity() as Address;
        let align_end = max_addr - (max_addr % mem::size_of::<Word>() as Address);
        'finish: for read_addr in iter::range_step(address, align_end, mem::size_of::<Word>() as Address) {
            let d = self.peek_data(read_addr).ok().expect("Could not read");
            for word_idx in iter::range(0, mem::size_of::<Word>()) {
                let chr = ((d >> (word_idx*8) as usize) & 0xff) as u8;
                if chr == 0 {
                    end_of_str = true;
                    break 'finish;
                }
                buf.push (chr);
            }
        }
        if !end_of_str {
            let d = self.peek_data(align_end).ok().expect("Could not read");
            for word_idx in range(0, mem::size_of::<Word>()) {
                let chr = ((d >> (word_idx*8) as usize) & 0xff) as u8;
                if chr == 0 {
                    break;
                }
                buf.push (chr);
            }
        }
        return buf;
    }
}
<|endoftext|>


<commit_before>//! A DEFLATE-based stream compression/decompression library
//!
//! This library is meant to supplement/replace the standard distributon's
//! libflate library by providing a streaming encoder/decoder rather than purely
//! in in-memory encoder/decoder.
//!
//! Like with libflate, flate2 is based on [`miniz.c`][1]
//!
//! [1]: https://code.google.com/p/miniz/
//!
//! # Organization
//!
//! This crate contains mainly of two modules, `reader` and `writer`. Each
//! module contains a number of types used to encode and decode various streams
//! of data. All types in the `writer` module work on instances of `Writer`,
//! whereas all types in the `reader` module work on instances of `Reader`.
//!
//! Other various types are provided at the top-level of the crate for
//! mangement and dealing with encoders/decoders.
//!
//! # Helper traits
//!
//! There are two helper traits, provided, `FlateReader` and `FlateWriter`.
//! These provide convenience methods for creating a decoder/encoder out of an
//! already existing stream to chain construction.

#![doc(html_root_url = "http://alexcrichton.com/flate2-rs")]
#![feature(io)]
#![deny(missing_docs)]
#![feature(unsafe_destructor)]
#![cfg_attr(test, deny(warnings))]

extern crate libc;
extern crate "miniz-sys" as ffi;
#[cfg(test)] extern crate rand;

use std::io::prelude::*;
use std::io;

pub use gz::Builder as GzBuilder;
pub use gz::Header as GzHeader;

mod crc;
mod deflate;
mod gz;
mod raw;
mod zlib;
mod stream;

/// Types which operate over `Reader` streams, both encoders and decoders for
/// various formats.
pub mod read {
    pub use deflate::EncoderReader as DeflateEncoder;
    pub use deflate::DecoderReader as DeflateDecoder;
    pub use zlib::EncoderReader as ZlibEncoder;
    pub use zlib::DecoderReader as ZlibDecoder;
    pub use gz::EncoderReader as GzEncoder;
    pub use gz::DecoderReader as GzDecoder;
}

/// Types which operate over `Writer` streams, both encoders and decoders for
/// various formats.
pub mod write {
    pub use deflate::EncoderWriter as DeflateEncoder;
    pub use deflate::DecoderWriter as DeflateDecoder;
    pub use zlib::EncoderWriter as ZlibEncoder;
    pub use zlib::DecoderWriter as ZlibDecoder;
    pub use gz::EncoderWriter as GzEncoder;
}

/// When compressing data, the compression level can be specified by a value in
/// this enum.
#[derive(Copy)]
pub enum Compression {
    /// No compression is to be performed, this may actually inflate data
    /// slightly when encoding.
    None = 0,
    /// Optimize for the best speed of encoding.
    Fast = 1,
    /// Optimize for the size of data being encoded.
    Best = 9,
    /// Choose the default compression, a balance between speed and size.
    Default = 6,
}

/// A helper trait to create encoder/decoders with method syntax.
pub trait FlateReadExt: Read + Sized {
    /// Consume this reader to create a compression stream at the specified
    /// compression level.
    fn gz_encode(self, lvl: Compression) -> read::GzEncoder<Self> {
        read::GzEncoder::new(self, lvl)
    }

    /// Consume this reader to create a decompression stream of this stream.
    fn gz_decode(self) -> io::Result<read::GzDecoder<Self>> {
        read::GzDecoder::new(self)
    }

    /// Consume this reader to create a compression stream at the specified
    /// compression level.
    fn zlib_encode(self, lvl: Compression) -> read::ZlibEncoder<Self> {
        read::ZlibEncoder::new(self, lvl)
    }

    /// Consume this reader to create a decompression stream of this stream.
    fn zlib_decode(self) -> read::ZlibDecoder<Self> {
        read::ZlibDecoder::new(self)
    }

    /// Consume this reader to create a compression stream at the specified
    /// compression level.
    fn deflate_encode(self, lvl: Compression) -> read::DeflateEncoder<Self> {
        read::DeflateEncoder::new(self, lvl)
    }

    /// Consume this reader to create a decompression stream of this stream.
    fn deflate_decode(self) -> read::DeflateDecoder<Self> {
        read::DeflateDecoder::new(self)
    }
}

/// A helper trait to create encoder/decoders with method syntax.
pub trait FlateWriteExt: Write + Sized {
    /// Consume this writer to create a compression stream at the specified
    /// compression level.
    fn gz_encode(self, lvl: Compression) -> write::GzEncoder<Self> {
        write::GzEncoder::new(self, lvl)
    }

    // TODO: coming soon to a theater near you!
    // /// Consume this writer to create a decompression stream of this stream.
    // fn gz_decode(self) -> IoResult<write::GzDecoder<Self>> {
    //     write::GzDecoder::new(self)
    // }

    /// Consume this writer to create a compression stream at the specified
    /// compression level.
    fn zlib_encode(self, lvl: Compression) -> write::ZlibEncoder<Self> {
        write::ZlibEncoder::new(self, lvl)
    }

    /// Consume this writer to create a decompression stream of this stream.
    fn zlib_decode(self) -> write::ZlibDecoder<Self> {
        write::ZlibDecoder::new(self)
    }

    /// Consume this writer to create a compression stream at the specified
    /// compression level.
    fn deflate_encode(self, lvl: Compression) -> write::DeflateEncoder<Self> {
        write::DeflateEncoder::new(self, lvl)
    }

    /// Consume this writer to create a decompression stream of this stream.
    fn deflate_decode(self) -> write::DeflateDecoder<Self> {
        write::DeflateDecoder::new(self)
    }
}

impl<T: Read> FlateReadExt for T {}
impl<T: Write> FlateWriteExt for T {}

#[cfg(test)]
mod test {
    use std::io::prelude::*;
    use {FlateReadExt, Compression};

    #[test]
    fn crazy() {
        let rdr = &mut b"foobar";
        let mut res = Vec::new();
        rdr.gz_encode(Compression::Default)
              .deflate_encode(Compression::Default)
                  .zlib_encode(Compression::Default)
                  .zlib_decode()
              .deflate_decode()
           .gz_decode().unwrap()
           .read_to_end(&mut res).unwrap();
        assert_eq!(res, b"foobar");
    }
}
<commit_msg>Consolidate feature tags<commit_after>//! A DEFLATE-based stream compression/decompression library
//!
//! This library is meant to supplement/replace the standard distributon's
//! libflate library by providing a streaming encoder/decoder rather than purely
//! in in-memory encoder/decoder.
//!
//! Like with libflate, flate2 is based on [`miniz.c`][1]
//!
//! [1]: https://code.google.com/p/miniz/
//!
//! # Organization
//!
//! This crate contains mainly of two modules, `reader` and `writer`. Each
//! module contains a number of types used to encode and decode various streams
//! of data. All types in the `writer` module work on instances of `Writer`,
//! whereas all types in the `reader` module work on instances of `Reader`.
//!
//! Other various types are provided at the top-level of the crate for
//! mangement and dealing with encoders/decoders.
//!
//! # Helper traits
//!
//! There are two helper traits, provided, `FlateReader` and `FlateWriter`.
//! These provide convenience methods for creating a decoder/encoder out of an
//! already existing stream to chain construction.

#![doc(html_root_url = "http://alexcrichton.com/flate2-rs")]
#![feature(io, unsafe_destructor)]
#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

extern crate libc;
extern crate "miniz-sys" as ffi;
#[cfg(test)] extern crate rand;

use std::io::prelude::*;
use std::io;

pub use gz::Builder as GzBuilder;
pub use gz::Header as GzHeader;

mod crc;
mod deflate;
mod gz;
mod raw;
mod zlib;
mod stream;

/// Types which operate over `Reader` streams, both encoders and decoders for
/// various formats.
pub mod read {
    pub use deflate::EncoderReader as DeflateEncoder;
    pub use deflate::DecoderReader as DeflateDecoder;
    pub use zlib::EncoderReader as ZlibEncoder;
    pub use zlib::DecoderReader as ZlibDecoder;
    pub use gz::EncoderReader as GzEncoder;
    pub use gz::DecoderReader as GzDecoder;
}

/// Types which operate over `Writer` streams, both encoders and decoders for
/// various formats.
pub mod write {
    pub use deflate::EncoderWriter as DeflateEncoder;
    pub use deflate::DecoderWriter as DeflateDecoder;
    pub use zlib::EncoderWriter as ZlibEncoder;
    pub use zlib::DecoderWriter as ZlibDecoder;
    pub use gz::EncoderWriter as GzEncoder;
}

/// When compressing data, the compression level can be specified by a value in
/// this enum.
#[derive(Copy)]
pub enum Compression {
    /// No compression is to be performed, this may actually inflate data
    /// slightly when encoding.
    None = 0,
    /// Optimize for the best speed of encoding.
    Fast = 1,
    /// Optimize for the size of data being encoded.
    Best = 9,
    /// Choose the default compression, a balance between speed and size.
    Default = 6,
}

/// A helper trait to create encoder/decoders with method syntax.
pub trait FlateReadExt: Read + Sized {
    /// Consume this reader to create a compression stream at the specified
    /// compression level.
    fn gz_encode(self, lvl: Compression) -> read::GzEncoder<Self> {
        read::GzEncoder::new(self, lvl)
    }

    /// Consume this reader to create a decompression stream of this stream.
    fn gz_decode(self) -> io::Result<read::GzDecoder<Self>> {
        read::GzDecoder::new(self)
    }

    /// Consume this reader to create a compression stream at the specified
    /// compression level.
    fn zlib_encode(self, lvl: Compression) -> read::ZlibEncoder<Self> {
        read::ZlibEncoder::new(self, lvl)
    }

    /// Consume this reader to create a decompression stream of this stream.
    fn zlib_decode(self) -> read::ZlibDecoder<Self> {
        read::ZlibDecoder::new(self)
    }

    /// Consume this reader to create a compression stream at the specified
    /// compression level.
    fn deflate_encode(self, lvl: Compression) -> read::DeflateEncoder<Self> {
        read::DeflateEncoder::new(self, lvl)
    }

    /// Consume this reader to create a decompression stream of this stream.
    fn deflate_decode(self) -> read::DeflateDecoder<Self> {
        read::DeflateDecoder::new(self)
    }
}

/// A helper trait to create encoder/decoders with method syntax.
pub trait FlateWriteExt: Write + Sized {
    /// Consume this writer to create a compression stream at the specified
    /// compression level.
    fn gz_encode(self, lvl: Compression) -> write::GzEncoder<Self> {
        write::GzEncoder::new(self, lvl)
    }

    // TODO: coming soon to a theater near you!
    // /// Consume this writer to create a decompression stream of this stream.
    // fn gz_decode(self) -> IoResult<write::GzDecoder<Self>> {
    //     write::GzDecoder::new(self)
    // }

    /// Consume this writer to create a compression stream at the specified
    /// compression level.
    fn zlib_encode(self, lvl: Compression) -> write::ZlibEncoder<Self> {
        write::ZlibEncoder::new(self, lvl)
    }

    /// Consume this writer to create a decompression stream of this stream.
    fn zlib_decode(self) -> write::ZlibDecoder<Self> {
        write::ZlibDecoder::new(self)
    }

    /// Consume this writer to create a compression stream at the specified
    /// compression level.
    fn deflate_encode(self, lvl: Compression) -> write::DeflateEncoder<Self> {
        write::DeflateEncoder::new(self, lvl)
    }

    /// Consume this writer to create a decompression stream of this stream.
    fn deflate_decode(self) -> write::DeflateDecoder<Self> {
        write::DeflateDecoder::new(self)
    }
}

impl<T: Read> FlateReadExt for T {}
impl<T: Write> FlateWriteExt for T {}

#[cfg(test)]
mod test {
    use std::io::prelude::*;
    use {FlateReadExt, Compression};

    #[test]
    fn crazy() {
        let rdr = &mut b"foobar";
        let mut res = Vec::new();
        rdr.gz_encode(Compression::Default)
              .deflate_encode(Compression::Default)
                  .zlib_encode(Compression::Default)
                  .zlib_decode()
              .deflate_decode()
           .gz_decode().unwrap()
           .read_to_end(&mut res).unwrap();
        assert_eq!(res, b"foobar");
    }
}
<|endoftext|>


<commit_before>//!
//! A Decimal implementation written in pure Rust suitable
//! for financial calculations that require significant integral
//! and fractional digits with no round-off errors.
//!
//! The binary representation consists of a 96 bit integer number,
//! a scaling factor used to specify the decimal fraction and a 1
//! bit sign. Because of this representation, trailing zeros are
//! preserved and may be exposed when in string form. These can be
//! truncated using the `normalize` or `round_dp` functions.
//!
//! ## Getting started
//!
//! To get started, add `rust_decimal` and optionally `rust_decimal_macros` to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! rust_decimal = "1.18"
//! rust_decimal_macros = "1.18"
//! ```
//!
//! ## Usage
//!
//! Decimal numbers can be created in a few distinct ways. The easiest and most optimal
//! method of creating a Decimal is to use the procedural macro within the
//! `rust_decimal_macros` crate:
//!
//! ```ignore
//! // Procedural macros need importing directly
//! use rust_decimal_macros::dec;
//!
//! let number = dec!(-1.23);
//! assert_eq!("-1.23", number.to_string());
//! ```
//!
//! Alternatively you can also use one of the Decimal number convenience functions:
//!
//! ```rust
//! // Using the prelude can help importing trait based functions (e.g. core::str::FromStr).
//! use rust_decimal::prelude::*;
//!
//! // Using an integer followed by the decimal points
//! let scaled = Decimal::new(202, 2);
//! assert_eq!("2.02", scaled.to_string());
//!
//! // From a string representation
//! let from_string = Decimal::from_str("2.02").unwrap();
//! assert_eq!("2.02", from_string.to_string());
//!
//! // From a string representation in a different base
//! let from_string_base16 = Decimal::from_str_radix("ffff", 16).unwrap();
//! assert_eq!("65535", from_string_base16.to_string());
//!
//! // Using the `Into` trait
//! let my_int: Decimal = 3i32.into();
//! assert_eq!("3", my_int.to_string());
//!
//! // Using the raw decimal representation
//! let pi = Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28);
//! assert_eq!("3.1415926535897932384626433832", pi.to_string());
//! ```
//!
//! Once you have instantiated your `Decimal` number you can perform calculations with it just like any other number:
//!
//! ```rust
//! use rust_decimal::prelude::*;
//!
//! let amount = Decimal::from_str("25.12").unwrap();
//! let tax = Decimal::from_str("0.085").unwrap();
//! let total = amount + (amount * tax).round_dp(2);
//! assert_eq!(total.to_string(), "27.26");
//! ```
//!
//! ## Features
//!
//! * [c-repr](#c-repr)
//! * [db-postgres](#db-postgres)
//! * [db-tokio-postgres](#db-tokio-postgres)
//! * [db-diesel-postgres](#db-diesel-postgres)
//! * [legacy-ops](#legacy-ops)
//! * [maths](#maths)
//! * [rocket-traits](#rocket-traits)
//! * [rust-fuzz](#rust-fuzz)
//! * [serde-float](#serde-float)
//! * [serde-str](#serde-str)
//! * [serde-arbitrary-precision](#serde-arbitrary-precision)
//! * [std](#std)
//!
//! ### `c-repr`
//!
//! Forces `Decimal` to use `[repr(C)]`. The corresponding target layout is 128 bit aligned.
//!
//! ### `db-postgres`
//!
//! This feature enables a PostgreSQL communication module. It allows for reading and writing the `Decimal`
//! type by transparently serializing/deserializing into the `NUMERIC` data type within PostgreSQL.
//!
//! ### `db-tokio-postgres`
//!
//! Enables the tokio postgres module allowing for async communication with PostgreSQL.
//!
//! ### `db-diesel-postgres`
//!
//! Enable `diesel` PostgreSQL support.
//!
//! ### `legacy-ops`
//!
//! As of `1.10` the algorithms used to perform basic operations have changed which has benefits of significant speed improvements.
//! To maintain backwards compatibility this can be opted out of by enabling the `legacy-ops` feature.
//!
//! ### `maths`
//!
//! The `maths` feature enables additional complex mathematical functions such as `pow`, `ln`, `enf`, `exp` etc.
//! Documentation detailing the additional functions can be found on the
//! [`MathematicalOps`](https://docs.rs/rust_decimal/latest/rust_decimal/trait.MathematicalOps.html) trait.
//!
//! Please note that `ln` and `log10` will panic on invalid input with `checked_ln` and `checked_log10` the preferred functions
//! to curb against this. When the `maths` feature was first developed the library would return `0` on invalid input. To re-enable this
//! non-panicing behavior, please use the feature: `maths-nopanic`.
//!
//! ### `rocket-traits`
//!
//! Enable support for forms by implementing the `FromFormField` trait.
//!
//! ### `rust-fuzz`
//!
//! Enable `rust-fuzz` support by implementing the `Arbitrary` trait.
//!
//! ### `serde-float`
//!
//! Enable this so that JSON serialization of `Decimal` types are sent as a float instead of a string (default).
//!
//! e.g. with this turned on, JSON serialization would output:
//! ```json
//! {
//!   "value": 1.234
//! }
//! ```
//!
//! ### `serde-str`
//!
//! This is typically useful for `bincode` or `csv` like implementations.
//!
//! Since `bincode` does not specify type information, we need to ensure that a type hint is provided in order to
//! correctly be able to deserialize. Enabling this feature on its own will force deserialization to use `deserialize_str`
//! instead of `deserialize_any`.
//!
//! If, for some reason, you also have `serde-float` enabled then this will use `deserialize_f64` as a type hint. Because
//! converting to `f64` _loses_ precision, it's highly recommended that you do NOT enable this feature when working with
//! `bincode`. That being said, this will only use 8 bytes so is slightly more efficient in terms of storage size.
//!
//! ### `serde-arbitrary-precision`
//!
//! This is used primarily with `serde_json` and consequently adds it as a "weak dependency". This supports the
//! `arbitrary_precision` feature inside `serde_json` when parsing decimals.
//!
//! This is recommended when parsing "float" looking data as it will prevent data loss.
//!
//! ### `std`
//!
//! Enable `std` library support. This is enabled by default, however in the future will be opt in. For now, to support `no_std`
//! libraries, this crate can be compiled with `--no-default-features`.
//!
//! ## Building
//!
//! Please refer to the [Build document](BUILD.md) for more information on building and testing Rust Decimal.
//!
#![forbid(unsafe_code)]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;

mod constants;
mod decimal;
mod error;
mod ops;
mod str;

#[cfg(feature = "rust-fuzz")]
mod fuzz;
#[cfg(feature = "maths")]
mod maths;
#[cfg(any(feature = "db-diesel-mysql"))]
mod mysql;
#[cfg(any(
    feature = "db-tokio-postgres",
    feature = "db-postgres",
    feature = "db-diesel-postgres",
))]
mod postgres;
#[cfg(feature = "rocket-traits")]
mod rocket;
#[cfg(feature = "serde")]
mod serde;

pub use decimal::{Decimal, RoundingStrategy};
pub use error::Error;
#[cfg(feature = "maths")]
pub use maths::MathematicalOps;

/// A convenience module appropriate for glob imports (`use rust_decimal::prelude::*;`).
pub mod prelude {
    #[cfg(feature = "maths")]
    pub use crate::maths::MathematicalOps;
    pub use crate::{Decimal, RoundingStrategy};
    pub use core::str::FromStr;
    pub use num_traits::{FromPrimitive, One, ToPrimitive, Zero};
}

#[cfg(feature = "diesel")]
#[macro_use]
extern crate diesel;

/// Shortcut for `core::result::Result<T, rust_decimal::Error>`. Useful to distinguish
/// between `rust_decimal` and `std` types.
pub type Result<T> = core::result::Result<T, Error>;
<commit_msg>added num_traits `Signed` to prelude (#450)<commit_after>//!
//! A Decimal implementation written in pure Rust suitable
//! for financial calculations that require significant integral
//! and fractional digits with no round-off errors.
//!
//! The binary representation consists of a 96 bit integer number,
//! a scaling factor used to specify the decimal fraction and a 1
//! bit sign. Because of this representation, trailing zeros are
//! preserved and may be exposed when in string form. These can be
//! truncated using the `normalize` or `round_dp` functions.
//!
//! ## Getting started
//!
//! To get started, add `rust_decimal` and optionally `rust_decimal_macros` to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! rust_decimal = "1.18"
//! rust_decimal_macros = "1.18"
//! ```
//!
//! ## Usage
//!
//! Decimal numbers can be created in a few distinct ways. The easiest and most optimal
//! method of creating a Decimal is to use the procedural macro within the
//! `rust_decimal_macros` crate:
//!
//! ```ignore
//! // Procedural macros need importing directly
//! use rust_decimal_macros::dec;
//!
//! let number = dec!(-1.23);
//! assert_eq!("-1.23", number.to_string());
//! ```
//!
//! Alternatively you can also use one of the Decimal number convenience functions:
//!
//! ```rust
//! // Using the prelude can help importing trait based functions (e.g. core::str::FromStr).
//! use rust_decimal::prelude::*;
//!
//! // Using an integer followed by the decimal points
//! let scaled = Decimal::new(202, 2);
//! assert_eq!("2.02", scaled.to_string());
//!
//! // From a string representation
//! let from_string = Decimal::from_str("2.02").unwrap();
//! assert_eq!("2.02", from_string.to_string());
//!
//! // From a string representation in a different base
//! let from_string_base16 = Decimal::from_str_radix("ffff", 16).unwrap();
//! assert_eq!("65535", from_string_base16.to_string());
//!
//! // Using the `Into` trait
//! let my_int: Decimal = 3i32.into();
//! assert_eq!("3", my_int.to_string());
//!
//! // Using the raw decimal representation
//! let pi = Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28);
//! assert_eq!("3.1415926535897932384626433832", pi.to_string());
//! ```
//!
//! Once you have instantiated your `Decimal` number you can perform calculations with it just like any other number:
//!
//! ```rust
//! use rust_decimal::prelude::*;
//!
//! let amount = Decimal::from_str("25.12").unwrap();
//! let tax = Decimal::from_str("0.085").unwrap();
//! let total = amount + (amount * tax).round_dp(2);
//! assert_eq!(total.to_string(), "27.26");
//! ```
//!
//! ## Features
//!
//! * [c-repr](#c-repr)
//! * [db-postgres](#db-postgres)
//! * [db-tokio-postgres](#db-tokio-postgres)
//! * [db-diesel-postgres](#db-diesel-postgres)
//! * [legacy-ops](#legacy-ops)
//! * [maths](#maths)
//! * [rocket-traits](#rocket-traits)
//! * [rust-fuzz](#rust-fuzz)
//! * [serde-float](#serde-float)
//! * [serde-str](#serde-str)
//! * [serde-arbitrary-precision](#serde-arbitrary-precision)
//! * [std](#std)
//!
//! ### `c-repr`
//!
//! Forces `Decimal` to use `[repr(C)]`. The corresponding target layout is 128 bit aligned.
//!
//! ### `db-postgres`
//!
//! This feature enables a PostgreSQL communication module. It allows for reading and writing the `Decimal`
//! type by transparently serializing/deserializing into the `NUMERIC` data type within PostgreSQL.
//!
//! ### `db-tokio-postgres`
//!
//! Enables the tokio postgres module allowing for async communication with PostgreSQL.
//!
//! ### `db-diesel-postgres`
//!
//! Enable `diesel` PostgreSQL support.
//!
//! ### `legacy-ops`
//!
//! As of `1.10` the algorithms used to perform basic operations have changed which has benefits of significant speed improvements.
//! To maintain backwards compatibility this can be opted out of by enabling the `legacy-ops` feature.
//!
//! ### `maths`
//!
//! The `maths` feature enables additional complex mathematical functions such as `pow`, `ln`, `enf`, `exp` etc.
//! Documentation detailing the additional functions can be found on the
//! [`MathematicalOps`](https://docs.rs/rust_decimal/latest/rust_decimal/trait.MathematicalOps.html) trait.
//!
//! Please note that `ln` and `log10` will panic on invalid input with `checked_ln` and `checked_log10` the preferred functions
//! to curb against this. When the `maths` feature was first developed the library would return `0` on invalid input. To re-enable this
//! non-panicing behavior, please use the feature: `maths-nopanic`.
//!
//! ### `rocket-traits`
//!
//! Enable support for forms by implementing the `FromFormField` trait.
//!
//! ### `rust-fuzz`
//!
//! Enable `rust-fuzz` support by implementing the `Arbitrary` trait.
//!
//! ### `serde-float`
//!
//! Enable this so that JSON serialization of `Decimal` types are sent as a float instead of a string (default).
//!
//! e.g. with this turned on, JSON serialization would output:
//! ```json
//! {
//!   "value": 1.234
//! }
//! ```
//!
//! ### `serde-str`
//!
//! This is typically useful for `bincode` or `csv` like implementations.
//!
//! Since `bincode` does not specify type information, we need to ensure that a type hint is provided in order to
//! correctly be able to deserialize. Enabling this feature on its own will force deserialization to use `deserialize_str`
//! instead of `deserialize_any`.
//!
//! If, for some reason, you also have `serde-float` enabled then this will use `deserialize_f64` as a type hint. Because
//! converting to `f64` _loses_ precision, it's highly recommended that you do NOT enable this feature when working with
//! `bincode`. That being said, this will only use 8 bytes so is slightly more efficient in terms of storage size.
//!
//! ### `serde-arbitrary-precision`
//!
//! This is used primarily with `serde_json` and consequently adds it as a "weak dependency". This supports the
//! `arbitrary_precision` feature inside `serde_json` when parsing decimals.
//!
//! This is recommended when parsing "float" looking data as it will prevent data loss.
//!
//! ### `std`
//!
//! Enable `std` library support. This is enabled by default, however in the future will be opt in. For now, to support `no_std`
//! libraries, this crate can be compiled with `--no-default-features`.
//!
//! ## Building
//!
//! Please refer to the [Build document](BUILD.md) for more information on building and testing Rust Decimal.
//!
#![forbid(unsafe_code)]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;

mod constants;
mod decimal;
mod error;
mod ops;
mod str;

#[cfg(feature = "rust-fuzz")]
mod fuzz;
#[cfg(feature = "maths")]
mod maths;
#[cfg(any(feature = "db-diesel-mysql"))]
mod mysql;
#[cfg(any(
    feature = "db-tokio-postgres",
    feature = "db-postgres",
    feature = "db-diesel-postgres",
))]
mod postgres;
#[cfg(feature = "rocket-traits")]
mod rocket;
#[cfg(feature = "serde")]
mod serde;

pub use decimal::{Decimal, RoundingStrategy};
pub use error::Error;
#[cfg(feature = "maths")]
pub use maths::MathematicalOps;

/// A convenience module appropriate for glob imports (`use rust_decimal::prelude::*;`).
pub mod prelude {
    #[cfg(feature = "maths")]
    pub use crate::maths::MathematicalOps;
    pub use crate::{Decimal, RoundingStrategy};
    pub use core::str::FromStr;
    pub use num_traits::{FromPrimitive, One, Signed, ToPrimitive, Zero};
}

#[cfg(feature = "diesel")]
#[macro_use]
extern crate diesel;

/// Shortcut for `core::result::Result<T, rust_decimal::Error>`. Useful to distinguish
/// between `rust_decimal` and `std` types.
pub type Result<T> = core::result::Result<T, Error>;
<|endoftext|>


<commit_before>#![crate_name="nock"]

#![feature(box_syntax, box_patterns)]

use std::fmt;
use std::str;

/// A Nock noun, the basic unit of representation.
///
/// The noun is either an atom a that's a positive integer or a pair of two
/// nouns, [a b].
#[derive(Clone, PartialEq, Eq)]
pub enum Noun {
    Atom(u64), // TODO: Need bigints?
    Cell(Box<Noun>, Box<Noun>),
}

impl Noun {
    pub fn new<T: Into<Noun>>(val: T) -> Noun {
        val.into()
    }
}

impl Into<Noun> for u64 {
    fn into(self) -> Noun { Noun::Atom(self) }
}

impl fmt::Display for Noun {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Atom(ref n) => write!(f, "{}", n),
            &Cell(ref a, ref b) => {
                try!(write!(f, "[{} ", a));
                // List pretty-printer.
                let mut cur = b;
                loop {
                    match cur {
                        &box Cell(ref a, ref b) => {
                            try!(write!(f, "{} ", a));
                            cur = &b;
                        }
                        &box Atom(ref n) => {
                            return write!(f, "{}]", n);
                        }
                    }
                }
            }
        }
    }
}

impl fmt::Debug for Noun {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self) }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct ParseNockError;

impl str::FromStr for Noun {
    type Err = ParseNockError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        unimplemented!();
    }
}

/// An operator for a Nock formula.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Op {
    Wut, // ?
    Lus, // +
    Tis, // =
    Fas, // /
    Tar, // *
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Formula(pub Op, pub Noun);

impl str::FromStr for Formula {
    type Err = ParseNockError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        unimplemented!();
    }
}

use Op::*;
use Noun::*;

// Nock(a)          *a
// [a b c]          [a [b c]]
//
// ?[a b]           0
// ?a               1
// +[a b]           +[a b]
// +a               1 + a
// =[a a]           0
// =[a b]           1
// =a               =a
//
// /[1 a]           a
// /[2 a b]         a
// /[3 a b]         b
// /[(a + a) b]     /[2 /[a b]]
// /[(a + a + 1) b] /[3 /[a b]]
// /a               /a
//
// *[a [b c] d]     [*[a b c] *[a d]]
//
// *[a 0 b]         /[b a]
// *[a 1 b]         b
// *[a 2 b c]       *[*[a b] *[a c]]
// *[a 3 b]         ?*[a b]
// *[a 4 b]         +*[a b]
// *[a 5 b]         =*[a b]
//
// *[a 6 b c d]     *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
// *[a 7 b c]       *[a 2 b 1 c]
// *[a 8 b c]       *[a 7 [[7 [0 1] b] 0 1] c]
// *[a 9 b c]       *[a 7 c 2 [0 1] 0 b]
// *[a 10 [b c] d]  *[a 8 c 7 [0 3] d]
// *[a 10 b c]      *[a c]
//
// *a               *a

pub fn eval(op: Op, noun: Noun) -> Result<Noun, Noun> {
    match (op, noun) {
        (Wut, Cell(_, _)) => Ok(Atom(0)),
        (Wut, Atom(_)) => Ok(Atom(1)),
        (Lus, Atom(a)) => Ok(Atom(1 + a)),
        (Lus, a) => Err(a),
        (Tis, Cell(a, b)) => Ok(Atom(if a == b { 0 } else { 1 })),
        (Tis, a) => Err(a),

        (Fas, Cell(box Atom(1), box a)) => Ok(a),
        (Fas, Cell(box Atom(2), box Cell(box a, _))) => Ok(a),
        (Fas, Cell(box Atom(3), box Cell(_, box b))) => Ok(b),
        (Fas, Cell(box Atom(a), b)) => {
            let x = try!(eval(Fas, Cell(box Atom(a / 2), b)));
            eval(Fas, Cell(box Atom(if a % 2 == 0 { 2 } else { 3 }), box x))
        }
        (Fas, a) => Err(a),

        (Tar, Cell(a, box Cell(box Cell(b, c), d))) => {
            let x = try!(eval(Tar, Cell(a.clone(), box Cell(b, c))));
            let y = try!(eval(Tar, Cell(a, d)));
            Ok(Cell(box x, box y))
        }

        // TODO: Numbered tar ops.

        (Tar, a) => Err(a)
    }
}

pub fn nock(noun: Noun) -> Result<Noun, Noun> { eval(Wut, noun) }

pub fn a(val: u64) -> Noun { Noun::Atom(val) }

macro_rules! n {
    [$x:expr, $y:expr] => { ::nock::Noun::Cell(box ::nock::Noun::new($x), box ::nock::Noun::new($y)) };
    [$x:expr, $y:expr, $($ys:expr),+] => { ::nock::Noun::Cell(box ::nock::Noun::new($x), box n![$y, $($ys),+]) };
}

// Re-export hack for testing macros.
mod nock {
    pub use Noun;
}

#[cfg(test)]
mod test {
#[test]
    fn test_macro() {
        use super::Noun::*;

        assert_eq!(n![1, 2], Cell(box Atom(1), box Atom(2)));
        assert_eq!(n![1, n![2, 3]], Cell(box Atom(1), box Cell(box Atom(2), box Atom(3))));
        assert_eq!(n![1, 2, 3], Cell(box Atom(1), box Cell(box Atom(2), box Atom(3))));
        assert_eq!(n![n![1, 2], 3], Cell(box Cell(box Atom(1), box Atom(2)), box Atom(3)));
        assert_eq!(n![n![1, 2], n![3, 4]], Cell(box Cell(box Atom(1), box Atom(2)), box Cell(box Atom(3), box Atom(4))));
        assert_eq!(n![n![1, 2], n![3, 4], n![5, 6]],
                   Cell(box Cell(box Atom(1), box Atom(2)),
                   box Cell(box Cell(box Atom(3), box Atom(4)),
                   box Cell(box Atom(5), box Atom(6)))));
    }
#[test]
    fn test_eval() {
        use super::Op::*;
        use super::{a, eval};

        // Examples from https://github.com/cgyarvin/urbit/blob/master/doc/book/1-nock.markdown

        assert_eq!(eval(Tis, n![0, 0]), Ok(a(0)));
        assert_eq!(eval(Tis, n![2, 2]), Ok(a(0)));
        assert_eq!(eval(Tis, n![0, 1]), Ok(a(1)));

        assert_eq!(eval(Fas, n![1, n![n![4, 5], n![6, 14, 15]]]), Ok(n![n![4, 5], n![6, 14, 15]]));
        assert_eq!(eval(Fas, n![2, n![n![4, 5], n![6, 14, 15]]]), Ok(n![4, 5]));
        assert_eq!(eval(Fas, n![3, n![n![4, 5], n![6, 14, 15]]]), Ok(n![6, 14, 15]));
        assert_eq!(eval(Fas, n![7, n![n![4, 5], n![6, 14, 15]]]), Ok(n![14, 15]));
    }

#[test]
    fn test_parse_noun() {
        use super::Noun;

        assert!("".parse::<Noun>().is_err());
        assert!("[]".parse::<Noun>().is_err());
        assert!("[1]".parse::<Noun>().is_err());
        assert!("[x y]".parse::<Noun>().is_err());
        assert_eq!("[1 2]".parse::<Noun>(), Ok(n![1, 2]));
        assert_eq!("[1 2 3]".parse::<Noun>(), Ok(n![1, 2, 3]));
        assert_eq!("[[1 2] 3]".parse::<Noun>(), Ok(n![n![1, 2], 3]));
        assert_eq!("[1 [2 3]]".parse::<Noun>(), Ok(n![1, n![2, 3]]));

    }

#[test]
    fn test_parse_formula() {
        use super::Op::*;
        use super::Formula;

        assert_eq!("+[1 2]".parse::<Formula>(), Ok(Formula(Lus, n![1, 2])));
    }
}
<commit_msg>Eval in Formula type<commit_after>#![crate_name="nock"]

#![feature(box_syntax, box_patterns)]

use std::fmt;
use std::str;

/// A Nock noun, the basic unit of representation.
///
/// The noun is either an atom a that's a positive integer or a pair of two
/// nouns, [a b].
#[derive(Clone, PartialEq, Eq)]
pub enum Noun {
    Atom(u64), // TODO: Need bigints?
    Cell(Box<Noun>, Box<Noun>),
}

impl Noun {
    pub fn new<T: Into<Noun>>(val: T) -> Noun {
        val.into()
    }
}

impl Into<Noun> for u64 {
    fn into(self) -> Noun { Noun::Atom(self) }
}

impl fmt::Display for Noun {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Atom(ref n) => write!(f, "{}", n),
            &Cell(ref a, ref b) => {
                try!(write!(f, "[{} ", a));
                // List pretty-printer.
                let mut cur = b;
                loop {
                    match cur {
                        &box Cell(ref a, ref b) => {
                            try!(write!(f, "{} ", a));
                            cur = &b;
                        }
                        &box Atom(ref n) => {
                            return write!(f, "{}]", n);
                        }
                    }
                }
            }
        }
    }
}

impl fmt::Debug for Noun {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self) }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct ParseNockError;

impl str::FromStr for Noun {
    type Err = ParseNockError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        unimplemented!();
    }
}

/// An operator for a Nock formula.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Op {
    Wut, // ?
    Lus, // +
    Tis, // =
    Fas, // /
    Tar, // *
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Formula(pub Op, pub Noun);

impl str::FromStr for Formula {
    type Err = ParseNockError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        unimplemented!();
    }
}

use Op::*;
use Noun::*;

// Nock(a)          *a
// [a b c]          [a [b c]]
//
// ?[a b]           0
// ?a               1
// +[a b]           +[a b]
// +a               1 + a
// =[a a]           0
// =[a b]           1
// =a               =a
//
// /[1 a]           a
// /[2 a b]         a
// /[3 a b]         b
// /[(a + a) b]     /[2 /[a b]]
// /[(a + a + 1) b] /[3 /[a b]]
// /a               /a
//
// *[a [b c] d]     [*[a b c] *[a d]]
//
// *[a 0 b]         /[b a]
// *[a 1 b]         b
// *[a 2 b c]       *[*[a b] *[a c]]
// *[a 3 b]         ?*[a b]
// *[a 4 b]         +*[a b]
// *[a 5 b]         =*[a b]
//
// *[a 6 b c d]     *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
// *[a 7 b c]       *[a 2 b 1 c]
// *[a 8 b c]       *[a 7 [[7 [0 1] b] 0 1] c]
// *[a 9 b c]       *[a 7 c 2 [0 1] 0 b]
// *[a 10 [b c] d]  *[a 8 c 7 [0 3] d]
// *[a 10 b c]      *[a c]
//
// *a               *a

impl Formula {
    pub fn eval(self) -> Result<Noun, Noun> {
        match (self.0, self.1) {
            (Wut, Cell(_, _)) => Ok(Atom(0)),
            (Wut, Atom(_)) => Ok(Atom(1)),
            (Lus, Atom(a)) => Ok(Atom(1 + a)),
            (Lus, a) => Err(a),
            (Tis, Cell(a, b)) => Ok(Atom(if a == b { 0 } else { 1 })),
            (Tis, a) => Err(a),

            (Fas, Cell(box Atom(1), box a)) => Ok(a),
            (Fas, Cell(box Atom(2), box Cell(box a, _))) => Ok(a),
            (Fas, Cell(box Atom(3), box Cell(_, box b))) => Ok(b),
            (Fas, Cell(box Atom(a), b)) => {
                let x = try!(eval(Fas, Cell(box Atom(a / 2), b)));
                eval(Fas, Cell(box Atom(if a % 2 == 0 { 2 } else { 3 }), box x))
            }
            (Fas, a) => Err(a),

            (Tar, Cell(a, box Cell(box Cell(b, c), d))) => {
                let x = try!(eval(Tar, Cell(a.clone(), box Cell(b, c))));
                let y = try!(eval(Tar, Cell(a, d)));
                Ok(Cell(box x, box y))
            }

            // TODO: Numbered tar ops.

            (Tar, a) => Err(a)
        }
    }
}

pub fn eval(op: Op, noun: Noun) -> Result<Noun, Noun> {
    Formula(op, noun).eval()
}

pub fn nock(noun: Noun) -> Result<Noun, Noun> { eval(Wut, noun) }

pub fn a(val: u64) -> Noun { Noun::Atom(val) }

macro_rules! n {
    [$x:expr, $y:expr] => { ::nock::Noun::Cell(box ::nock::Noun::new($x), box ::nock::Noun::new($y)) };
    [$x:expr, $y:expr, $($ys:expr),+] => { ::nock::Noun::Cell(box ::nock::Noun::new($x), box n![$y, $($ys),+]) };
}

// Re-export hack for testing macros.
mod nock {
    pub use Noun;
}

#[cfg(test)]
mod test {
#[test]
    fn test_macro() {
        use super::Noun::*;

        assert_eq!(n![1, 2], Cell(box Atom(1), box Atom(2)));
        assert_eq!(n![1, n![2, 3]], Cell(box Atom(1), box Cell(box Atom(2), box Atom(3))));
        assert_eq!(n![1, 2, 3], Cell(box Atom(1), box Cell(box Atom(2), box Atom(3))));
        assert_eq!(n![n![1, 2], 3], Cell(box Cell(box Atom(1), box Atom(2)), box Atom(3)));
        assert_eq!(n![n![1, 2], n![3, 4]], Cell(box Cell(box Atom(1), box Atom(2)), box Cell(box Atom(3), box Atom(4))));
        assert_eq!(n![n![1, 2], n![3, 4], n![5, 6]],
                   Cell(box Cell(box Atom(1), box Atom(2)),
                   box Cell(box Cell(box Atom(3), box Atom(4)),
                   box Cell(box Atom(5), box Atom(6)))));
    }
#[test]
    fn test_eval() {
        use super::Op::*;
        use super::{a, eval};

        // Examples from https://github.com/cgyarvin/urbit/blob/master/doc/book/1-nock.markdown

        assert_eq!(eval(Tis, n![0, 0]), Ok(a(0)));
        assert_eq!(eval(Tis, n![2, 2]), Ok(a(0)));
        assert_eq!(eval(Tis, n![0, 1]), Ok(a(1)));

        assert_eq!(eval(Fas, n![1, n![n![4, 5], n![6, 14, 15]]]), Ok(n![n![4, 5], n![6, 14, 15]]));
        assert_eq!(eval(Fas, n![2, n![n![4, 5], n![6, 14, 15]]]), Ok(n![4, 5]));
        assert_eq!(eval(Fas, n![3, n![n![4, 5], n![6, 14, 15]]]), Ok(n![6, 14, 15]));
        assert_eq!(eval(Fas, n![7, n![n![4, 5], n![6, 14, 15]]]), Ok(n![14, 15]));
    }

#[test]
    fn test_parse_noun() {
        use super::Noun;

        assert!("".parse::<Noun>().is_err());
        assert!("[]".parse::<Noun>().is_err());
        assert!("[1]".parse::<Noun>().is_err());
        assert!("[x y]".parse::<Noun>().is_err());
        assert_eq!("[1 2]".parse::<Noun>(), Ok(n![1, 2]));
        assert_eq!("[1 2 3]".parse::<Noun>(), Ok(n![1, 2, 3]));
        assert_eq!("[[1 2] 3]".parse::<Noun>(), Ok(n![n![1, 2], 3]));
        assert_eq!("[1 [2 3]]".parse::<Noun>(), Ok(n![1, n![2, 3]]));

    }

#[test]
    fn test_parse_formula() {
        use super::Op::*;
        use super::Formula;

        assert_eq!("+[1 2]".parse::<Formula>(), Ok(Formula(Lus, n![1, 2])));
    }
}
<|endoftext|>


<commit_before>//! Hash-consing with automated release of unused values

#[macro_use]
extern crate log;

use std::ops::{Deref, Drop};
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::fmt::{self, Debug};
use std::cell::UnsafeCell;

/// Box that encapsulates a value to hash-cons, a reference to the conser,
/// and a reference counter
struct HashConsedBox<T>
    where T: Eq + Hash
{
    value: T,
    conser: HashConser<T>,
    refs: usize,
}

/// Unsafed reference to a hash-consed value
///
/// It is simply a pointer to the hash-consed box that encapsulate the raw value,
/// a reference to the conser and the current number of references.
///
/// **N.B.:** An unsafed hash-consed value:
///
///   * may or may not be in the conser's map,
///
///   * should be `destroy()`-ed manually,
///
///   * does not update automatically the ref count,
///
///   * inherits PartialEq, Eq, and Hash from the raw value.
struct UnsafeRef<T>(*mut UnsafeCell<HashConsedBox<T>>) where T: Eq + Hash;

impl<T> UnsafeRef<T> where T: Eq + Hash {

    /// Make an unsafed reference to a owned hash-consed box
    #[inline]
    fn make(conser: &HashConser<T>, value: T) -> Self {
        UnsafeRef(Box::into_raw(Box::new(UnsafeCell::new(HashConsedBox {
            value: value,
            conser: conser.copy(),
            refs: 0,
        }))))
    }

    /// Destroy (drop) the underlying hash-consed box
    #[inline]
    fn destroy(&self) {
        drop(unsafe { Box::from_raw(self.0) });
    }

    /// Get pointer to conser
    #[inline]
    fn conser(&mut self) -> *mut HashConser<T> {
        unsafe { &mut (*self.as_ptr()).conser as *mut HashConser<T> }
    }

    #[inline]
    fn refs(&self) -> usize {
        unsafe { (*self.as_ptr()).refs }
    }

    #[inline]
    fn inc_refs(&self) {
        let refs = unsafe { &mut (*self.as_ptr()).refs };
        *refs += 1;
    }

    #[inline]
    fn dec_refs(&self) {
        let refs = unsafe { &mut (*self.as_ptr()).refs };
        *refs -= 1;
    }

    #[inline]
    fn value(&self) -> &T {
        unsafe { &(*self.as_ptr()).value }
    }

    #[inline]
    fn as_ptr(&self) -> *mut HashConsedBox<T> {
        unsafe { (*self.0).get() }
    }
}

/// Hash the underlying value
impl<T> Hash for UnsafeRef<T> where T: Eq + Hash {

    #[inline]
    fn hash<H>(&self, h: &mut H)
        where H: Hasher
    {
        self.value().hash(h);
    }

}

/// Compare the underlying values
impl<T> PartialEq<UnsafeRef<T>> for UnsafeRef<T> where T: Eq + Hash {

    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.value() == other.value()
    }

}

impl<T> Eq for UnsafeRef<T> where T: Eq + Hash {
}

/// Clone a new reference to the hash-consed value
impl<T> Clone for UnsafeRef<T> where T: Eq + Hash {

    #[inline]
    fn clone(&self) -> Self {
        UnsafeRef(self.0)
    }

}

impl<T> Copy for UnsafeRef<T> where T: Eq + Hash {}

/// Reference to a hash-consed value.
///
/// Built through a `HashConser`, it points to a single copy of the raw value existing in the
/// `HashConser`.
///
/// Uses fast pointer equality and hash.
pub struct HashConsed<T>(UnsafeRef<T>) where T: Eq + Hash;

impl<T> HashConsed<T> where T: Eq + Hash {

    /// Wrap an unsafe reference
    fn from_unsafe(u: &UnsafeRef<T>) -> Self {
        u.inc_refs();
        debug!("new ref {:p} ({} ref total)", u.value(), u.refs());
        HashConsed(*u)
    }

    /// Get underlying value
    #[inline]
    pub fn value(&self) -> &T {
        self.0.value()
    }

    /// Get number of references
    #[cfg(test)]
    pub fn refs(&self) -> usize {
        self.0.refs()
    }

}

/// Get reference to the raw value
impl<T> Deref for HashConsed<T> where T: Eq + Hash {

    type Target = T;

    fn deref(&self) -> &T {
        return self.value();
    }

}

/// Fast hash (pointer-based)
///
/// Beware that it does not make any sense if the compared values where built through different
/// `HashConser`.
impl<T> Hash for HashConsed<T> where T: Eq + Hash {

    fn hash<H>(&self, h: &mut H)
        where H: Hasher
    {
        self.0.as_ptr().hash(h);
    }

}

/// Fast comparison (pointer-based)
///
/// Beware that it does not make any sense if the compared values where built through different
/// `HashConser`
impl<T> PartialEq<HashConsed<T>> for HashConsed<T> where T: Eq + Hash {

    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.0.as_ptr() == other.0.as_ptr()
    }

}

impl<T> Eq for HashConsed<T> where T: Eq + Hash {}

impl<T> Drop for HashConsed<T> where T: Eq + Hash {

    fn drop(&mut self) {
        self.0.dec_refs();
        debug!("del ref {:p} ({} refs remaining)",
               self.0.value(),
               self.0.refs());
        if self.0.refs() == 0 {
            debug!("del val {:p}", self.value());
            let conser = unsafe { &mut *self.0.conser() };
            conser.remove(&self.0);
            self.0.destroy();
        }
    }

}

impl<T> Debug for HashConsed<T> where T: Eq + Hash + Debug {

    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self.0.value(), fmt)
    }

}

/// Get a new reference to this hash-consed value.
impl<T> Clone for HashConsed<T> where T: Eq + Hash {
    fn clone(&self) -> Self {
        self.0.inc_refs();
        debug!("new ref {:p} (clone, {} refs total)",
               self.0.value(),
               self.0.refs());
        HashConsed(self.0)
    }
}

type HM<T> where T: Eq + Hash = HashMap<UnsafeRef<T>, UnsafeRef<T>>;

/// Hash-conser, i.e. hash-consed value factory and cache.
pub struct HashConser<T>(*mut UnsafeCell<HM<T>>) where T: Eq + Hash;

impl<T> HashConser<T> where T: Eq + Hash {

    /// Create a hash-conser.
    pub fn new() -> Self {
        HashConser(Box::into_raw(Box::new(UnsafeCell::new(HashMap::new()))))
    }

    #[inline]
    fn map(&self) -> &mut HM<T> {
        unsafe { &mut (*(*self.0).get()) }
    }

    /// Make a hash-consed value from an unwrapped value
    pub fn make(&mut self, obj: T) -> HashConsed<T> {
        debug!("h-cons  {:p} in {:p}", &obj, self);
        let input = UnsafeRef::make(self, obj);
        let map = self.map();
        let safe = match map.get(&input) {
            Some(output) => {
                debug!("recycle {:p} (already {} refs)",
                       output.value(),
                       output.refs());
                input.destroy();
                HashConsed::from_unsafe(output)
            }
            None => {
                debug!("new val {:p} in {:p}", input.value(), self);
                self.map().insert(input.clone(), input);
                HashConsed::from_unsafe(&input)
            }
        };
        debug!("/h-cons");
        safe
    }

    #[inline]
    fn remove(&mut self, hc: &UnsafeRef<T>) {
        self.map().remove(hc);
    }

    /// Private: get a new reference of the conference
    ///
    /// WARNING! no reference counting
    ///
    /// *Invariant:* the number of references is the number of hash-consed values plus one if the
    /// user stills holds the ref
    #[inline]
    fn copy(&self) -> Self {
        HashConser(self.0)
    }
}

impl<T> Drop for HashConser<T> where T: Eq + Hash {
    fn drop(&mut self) {
        debug!("del ref HashConser({:p}) ({} refs remaining)",
               self.0,
               self.map().len());
        if self.map().len() == 0 {
            debug!("del val HashConser({:p})", self.0);
            let b = unsafe { Box::from_raw(self.0) };
            drop(b);
        }
    }
}

impl<T> Debug for HashConser<T> where T: Eq + Hash + Debug {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(fmt.write_str("{"));
        for (i, k) in self.map().keys().enumerate() {
            if i != 0 {
                try!(fmt.write_str(", "));
            }
            try!(write!(fmt, "{:?} ({})", k.value(), k.refs()));
        }
        fmt.write_str("}")
    }
}

#[test]
fn it_works() {}
<commit_msg>Remove methods from HashConsed (avoid masking)<commit_after>//! Hash-consing with automated release of unused values

#[macro_use]
extern crate log;

use std::ops::{Deref, Drop};
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::fmt::{self, Debug};
use std::cell::UnsafeCell;

/// Box that encapsulates a value to hash-cons, a reference to the conser,
/// and a reference counter
struct HashConsedBox<T>
    where T: Eq + Hash
{
    value: T,
    conser: HashConser<T>,
    refs: usize,
}

/// Unsafed reference to a hash-consed value
///
/// It is simply a pointer to the hash-consed box that encapsulate the raw value,
/// a reference to the conser and the current number of references.
///
/// **N.B.:** An unsafed hash-consed value:
///
///   * may or may not be in the conser's map,
///
///   * should be `destroy()`-ed manually,
///
///   * does not update automatically the ref count,
///
///   * inherits PartialEq, Eq, and Hash from the raw value.
struct UnsafeRef<T>(*mut UnsafeCell<HashConsedBox<T>>) where T: Eq + Hash;

impl<T> UnsafeRef<T> where T: Eq + Hash {

    /// Make an unsafed reference to a owned hash-consed box
    #[inline]
    fn make(conser: &HashConser<T>, value: T) -> Self {
        UnsafeRef(Box::into_raw(Box::new(UnsafeCell::new(HashConsedBox {
            value: value,
            conser: conser.copy(),
            refs: 0,
        }))))
    }

    /// Destroy (drop) the underlying hash-consed box
    #[inline]
    fn destroy(&self) {
        drop(unsafe { Box::from_raw(self.0) });
    }

    /// Get pointer to conser
    #[inline]
    fn conser(&mut self) -> *mut HashConser<T> {
        unsafe { &mut (*self.as_ptr()).conser as *mut HashConser<T> }
    }

    #[inline]
    fn refs(&self) -> usize {
        unsafe { (*self.as_ptr()).refs }
    }

    #[inline]
    fn inc_refs(&self) {
        let refs = unsafe { &mut (*self.as_ptr()).refs };
        *refs += 1;
    }

    #[inline]
    fn dec_refs(&self) {
        let refs = unsafe { &mut (*self.as_ptr()).refs };
        *refs -= 1;
    }

    #[inline]
    fn value(&self) -> &T {
        unsafe { &(*self.as_ptr()).value }
    }

    #[inline]
    fn as_ptr(&self) -> *mut HashConsedBox<T> {
        unsafe { (*self.0).get() }
    }
}

/// Hash the underlying value
impl<T> Hash for UnsafeRef<T> where T: Eq + Hash {

    #[inline]
    fn hash<H>(&self, h: &mut H)
        where H: Hasher
    {
        self.value().hash(h);
    }

}

/// Compare the underlying values
impl<T> PartialEq<UnsafeRef<T>> for UnsafeRef<T> where T: Eq + Hash {

    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.value() == other.value()
    }

}

impl<T> Eq for UnsafeRef<T> where T: Eq + Hash {
}

/// Clone a new reference to the hash-consed value
impl<T> Clone for UnsafeRef<T> where T: Eq + Hash {

    #[inline]
    fn clone(&self) -> Self {
        UnsafeRef(self.0)
    }

}

impl<T> Copy for UnsafeRef<T> where T: Eq + Hash {}

/// Reference to a hash-consed value.
///
/// Built through a `HashConser`, it points to a single copy of the raw value existing in the
/// `HashConser`.
///
/// Uses fast pointer equality and hash.
pub struct HashConsed<T>(UnsafeRef<T>) where T: Eq + Hash;

impl<T> HashConsed<T> where T: Eq + Hash {

    /// Wrap an unsafe reference
    fn from_unsafe(u: &UnsafeRef<T>) -> Self {
        u.inc_refs();
        debug!("new ref {:p} ({} ref total)", u.value(), u.refs());
        HashConsed(*u)
    }

}

/// Get reference to the raw value
impl<T> Deref for HashConsed<T> where T: Eq + Hash {

    type Target = T;

    fn deref(&self) -> &T {
        return self.0.value();
    }

}

/// Fast hash (pointer-based)
///
/// Beware that it does not make any sense if the compared values where built through different
/// `HashConser`.
impl<T> Hash for HashConsed<T> where T: Eq + Hash {

    fn hash<H>(&self, h: &mut H)
        where H: Hasher
    {
        self.0.as_ptr().hash(h);
    }

}

/// Fast comparison (pointer-based)
///
/// Beware that it does not make any sense if the compared values where built through different
/// `HashConser`
impl<T> PartialEq<HashConsed<T>> for HashConsed<T> where T: Eq + Hash {

    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.0.as_ptr() == other.0.as_ptr()
    }

}

impl<T> Eq for HashConsed<T> where T: Eq + Hash {}

impl<T> Drop for HashConsed<T> where T: Eq + Hash {

    fn drop(&mut self) {
        self.0.dec_refs();
        debug!("del ref {:p} ({} refs remaining)",
               self.0.value(),
               self.0.refs());
        if self.0.refs() == 0 {
            debug!("del val {:p}", self.0.value());
            let conser = unsafe { &mut *self.0.conser() };
            conser.remove(&self.0);
            self.0.destroy();
        }
    }

}

impl<T> Debug for HashConsed<T> where T: Eq + Hash + Debug {

    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self.0.value(), fmt)
    }

}

/// Get a new reference to this hash-consed value.
impl<T> Clone for HashConsed<T> where T: Eq + Hash {
    fn clone(&self) -> Self {
        self.0.inc_refs();
        debug!("new ref {:p} (clone, {} refs total)",
               self.0.value(),
               self.0.refs());
        HashConsed(self.0)
    }
}

type HM<T> where T: Eq + Hash = HashMap<UnsafeRef<T>, UnsafeRef<T>>;

/// Hash-conser, i.e. hash-consed value factory and cache.
pub struct HashConser<T>(*mut UnsafeCell<HM<T>>) where T: Eq + Hash;

impl<T> HashConser<T> where T: Eq + Hash {

    /// Create a hash-conser.
    pub fn new() -> Self {
        HashConser(Box::into_raw(Box::new(UnsafeCell::new(HashMap::new()))))
    }

    #[inline]
    fn map(&self) -> &mut HM<T> {
        unsafe { &mut (*(*self.0).get()) }
    }

    /// Make a hash-consed value from an unwrapped value
    pub fn make(&mut self, obj: T) -> HashConsed<T> {
        debug!("h-cons  {:p} in {:p}", &obj, self);
        let input = UnsafeRef::make(self, obj);
        let map = self.map();
        let safe = match map.get(&input) {
            Some(output) => {
                debug!("recycle {:p} (already {} refs)",
                       output.value(),
                       output.refs());
                input.destroy();
                HashConsed::from_unsafe(output)
            }
            None => {
                debug!("new val {:p} in {:p}", input.value(), self);
                self.map().insert(input.clone(), input);
                HashConsed::from_unsafe(&input)
            }
        };
        debug!("/h-cons");
        safe
    }

    #[inline]
    fn remove(&mut self, hc: &UnsafeRef<T>) {
        self.map().remove(hc);
    }

    /// Private: get a new reference of the conference
    ///
    /// WARNING! no reference counting
    ///
    /// *Invariant:* the number of references is the number of hash-consed values plus one if the
    /// user stills holds the ref
    #[inline]
    fn copy(&self) -> Self {
        HashConser(self.0)
    }
}

impl<T> Drop for HashConser<T> where T: Eq + Hash {
    fn drop(&mut self) {
        debug!("del ref HashConser({:p}) ({} refs remaining)",
               self.0,
               self.map().len());
        if self.map().len() == 0 {
            debug!("del val HashConser({:p})", self.0);
            let b = unsafe { Box::from_raw(self.0) };
            drop(b);
        }
    }
}

impl<T> Debug for HashConser<T> where T: Eq + Hash + Debug {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(fmt.write_str("{"));
        for (i, k) in self.map().keys().enumerate() {
            if i != 0 {
                try!(fmt.write_str(", "));
            }
            try!(write!(fmt, "{:?} ({})", k.value(), k.refs()));
        }
        fmt.write_str("}")
    }
}

#[test]
fn it_works() {}
<|endoftext|>