<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)]
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 {
        if index < self.0.len() {
            &self.0[index]
        } else {
            &self.1[index - self.0.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.")
    }
    let max_triangles = points_count * 4;

    // Find the bounds of the space that contains our points.
    let mut min_point = points[0];
    let mut max_point = min_point;
    for point in points {
        if point.x > max_point.x {
            max_point.x = point.x;
        }
        if point.y > max_point.y {
            max_point.y = point.y;
        }
        if point.x < min_point.x {
            min_point.x = point.x;
        }
        if point.y < min_point.y {
            min_point.y = point.y;
        }
    }
    let delta_point = Point {
        x: max_point.x - min_point.x,
        y: max_point.y - min_point.y,
    };
    let delta_max = if delta_point.x > delta_point.y {
        delta_point.x
    } else {
        delta_point.y
    };
    let mid_point = Point {
        x: (max_point.x + min_point.x) * 0.5,
        y: (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();

        {
            let mut j = 0;
            while j < triangles.len() {
                if in_circle(all_points[i],
                             all_points[triangles[j].0],
                             all_points[triangles[j].1],
                             all_points[triangles[j].2]) {
                    edges.push(Edge(triangles[j].0, triangles[j].1));
                    edges.push(Edge(triangles[j].1, triangles[j].2));
                    edges.push(Edge(triangles[j].2, triangles[j].0));
                    triangles.remove(j);
                } else {
                    j += 1;
                }
            }
        }

        // Remove duplicate edges.
        if edges.len() > 1 {
            let mut j = edges.len() - 2;
            loop {
                let mut k = edges.len() - 1;
                while k >= j + 1 {
                    if edges[j] == edges[k] {
                        edges.remove(k);
                        edges.remove(j);
                        k -= 2;
                    } else {
                        k -= 1;
                    }
                }
                if j > 0 {
                    j -= 1;
                } else {
                    break;
                }
            }
        }

        // Form new triangles from the remaining edges. Edges are added in clockwise order.
        {
            let mut j = 0;
            while j < edges.len() {
                if triangles.len() >= max_triangles {
                    panic!("Exceeded maximum edges");
                }
                triangles.push(Triangle(edges[j].0, edges[j].1, i));
                j += 1;
            }
        }
    }

    // Remove triangles with supertriangle vertices
    let mut i = triangles.len() - 1;
    loop {
        if triangles[i].0 >= points_count || triangles[i].1 >= points_count ||
           triangles[i].2 >= points_count {
            triangles.remove(i);
        }
        if i > 0 {
            i -= 1;
        } else {
            break;
        }
    }

    triangles
}

/// Returns true if the first point lies inside (or on the edge of) the circumcircle made from the
/// three other points.
fn in_circle(p: Point, pc1: Point, pc2: Point, pc3: Point) -> bool {
    // Handle coincident points.
    if (pc1.y - pc2.y).abs() < std::f64::EPSILON && (pc2.y - pc3.y).abs() < std::f64::EPSILON {
        return false;
    }

    let m1: f64;
    let m2: f64;
    let mx1: f64;
    let mx2: f64;
    let my1: f64;
    let my2: f64;
    let xc: f64;
    let yc: f64;

    if (pc2.y - pc1.y).abs() < std::f64::EPSILON {
        m2 = 0.0 - (pc3.x - pc2.x) / (pc3.y - pc2.y);
        mx2 = (pc2.x + pc3.x) * 0.5;
        my2 = (pc2.y + pc3.y) * 0.5;
        xc = (pc2.x + pc1.x) * 0.5;
        yc = m2 * (xc - mx2) + my2;
    } else if (pc3.y - pc2.y).abs() < std::f64::EPSILON {
        m1 = 0.0 - (pc2.x - pc1.x) / (pc2.y - pc1.y);
        mx1 = (pc1.x + pc2.x) * 0.5;
        my1 = (pc1.y + pc2.y) * 0.5;
        xc = (pc3.x + pc2.x) * 0.5;
        yc = m1 * (xc - mx1) + my1;
    } else {
        m1 = 0.0 - (pc2.x - pc1.x) / (pc2.y - pc1.y);
        m2 = 0.0 - (pc3.x - pc2.x) / (pc3.y - pc2.y);
        mx1 = (pc1.x + pc2.x) * 0.5;
        mx2 = (pc2.x + pc3.x) * 0.5;
        my1 = (pc1.y + pc2.y) * 0.5;
        my2 = (pc2.y + pc3.y) * 0.5;
        xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
        yc = m1 * (xc - mx1) + my1;
    }

    let rsqr = (pc2.x - xc).powf(2.0) + (pc2.y - yc).powf(2.0);
    let drsqr = (p.x - xc).powf(2.0) + (p.y - yc).powf(2.0);

    drsqr <= rsqr
}

#[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>Made the removal of duplicate edges a bit cleaner.<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 {
        if index < self.0.len() {
            &self.0[index]
        } else {
            &self.1[index - self.0.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.")
    }
    let max_triangles = points_count * 4;

    // 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();

        {
            let mut j = 0;
            while j < triangles.len() {
                if in_circle(all_points[i],
                             all_points[triangles[j].0],
                             all_points[triangles[j].1],
                             all_points[triangles[j].2]) {
                    edges.push(Edge(triangles[j].0, triangles[j].1));
                    edges.push(Edge(triangles[j].1, triangles[j].2));
                    edges.push(Edge(triangles[j].2, triangles[j].0));
                    triangles.remove(j);
                } else {
                    j += 1;
                }
            }
        }

        // Remove duplicate edges.
        let mut to_remove: Vec<usize> = 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.push(k);
                    to_remove.push(j);
                    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.
        {
            let mut j = 0;
            while j < edges.len() {
                if triangles.len() >= max_triangles {
                    panic!("Exceeded maximum edges");
                }
                triangles.push(Triangle(edges[j].0, edges[j].1, i));
                j += 1;
            }
        }
    }

    // Remove triangles with supertriangle vertices
    let mut i = triangles.len() - 1;
    loop {
        if triangles[i].0 >= points_count || triangles[i].1 >= points_count ||
           triangles[i].2 >= points_count {
            triangles.remove(i);
        }
        if i > 0 {
            i -= 1;
        } else {
            break;
        }
    }

    triangles
}

/// Returns true if the first point lies inside (or on the edge of) the circumcircle made from the
/// three other points.
fn in_circle(p: Point, pc1: Point, pc2: Point, pc3: Point) -> bool {
    // Handle coincident points.
    if (pc1.y - pc2.y).abs() < std::f64::EPSILON && (pc2.y - pc3.y).abs() < std::f64::EPSILON {
        return false;
    }

    let m1: f64;
    let m2: f64;
    let mx1: f64;
    let mx2: f64;
    let my1: f64;
    let my2: f64;
    let xc: f64;
    let yc: f64;

    if (pc2.y - pc1.y).abs() < std::f64::EPSILON {
        m2 = 0.0 - (pc3.x - pc2.x) / (pc3.y - pc2.y);
        mx2 = (pc2.x + pc3.x) * 0.5;
        my2 = (pc2.y + pc3.y) * 0.5;
        xc = (pc2.x + pc1.x) * 0.5;
        yc = m2 * (xc - mx2) + my2;
    } else if (pc3.y - pc2.y).abs() < std::f64::EPSILON {
        m1 = 0.0 - (pc2.x - pc1.x) / (pc2.y - pc1.y);
        mx1 = (pc1.x + pc2.x) * 0.5;
        my1 = (pc1.y + pc2.y) * 0.5;
        xc = (pc3.x + pc2.x) * 0.5;
        yc = m1 * (xc - mx1) + my1;
    } else {
        m1 = 0.0 - (pc2.x - pc1.x) / (pc2.y - pc1.y);
        m2 = 0.0 - (pc3.x - pc2.x) / (pc3.y - pc2.y);
        mx1 = (pc1.x + pc2.x) * 0.5;
        mx2 = (pc2.x + pc3.x) * 0.5;
        my1 = (pc1.y + pc2.y) * 0.5;
        my2 = (pc2.y + pc3.y) * 0.5;
        xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
        yc = m1 * (xc - mx1) + my1;
    }

    let rsqr = (pc2.x - xc).powf(2.0) + (pc2.y - yc).powf(2.0);
    let drsqr = (p.x - xc).powf(2.0) + (p.y - yc).powf(2.0);

    drsqr <= rsqr
}

#[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[..]);
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! Bincode is a crate for encoding and decoding using a tiny binary
//! serialization strategy.  Using it, you can easily go from having
//! an object in memory, quickly serialize it to bytes, and then
//! deserialize it back just as fast!
//!
//! ### Using Basic Functions
//!
//! ```rust
//! extern crate bincode;
//! use bincode::{serialize, deserialize};
//! fn main() {
//!     // The object that we will serialize.
//!     let target: Option<String>  = Some("hello world".to_string());
//!
//!     let encoded: Vec<u8>        = serialize(&target).unwrap();
//!     let decoded: Option<String> = deserialize(&encoded[..]).unwrap();
//!     assert_eq!(target, decoded);
//! }
//! ```

#![crate_name = "bincode"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]

extern crate byteorder;
extern crate serde;

mod config;
mod ser;
mod error;
mod de;
mod internal;

pub use error::{Error, ErrorKind, Result};
pub use config::Config;
pub use de::read::{BincodeRead, IoReader, SliceReader};

/// An object that implements this trait can be passed a
/// serde::Deserializer without knowing its concrete type.
///
/// This trait should be used only for `with_deserializer` functions.
#[doc(hidden)]
pub trait DeserializerAcceptor<'a> {
    /// The return type for the accept method
    type Output;
    /// Accept a serde::Deserializer and do whatever you want with it.
    fn accept<T: serde::Deserializer<'a>>(self, T) -> Self::Output;
}

/// An object that implements this trait can be passed a
/// serde::Serializer without knowing its concrete type.
///
/// This trait should be used only for `with_serializer` functions.
#[doc(hidden)]
pub trait SerializerAcceptor {
    /// The return type for the accept method
    type Output;
    /// Accept a serde::Serializer and do whatever you want with it.
    fn accept<T: serde::Serializer>(self, T) -> Self::Output;
}

/// Get a default configuration object.
///
/// ### Default Configuration:
/// Byte limit: Unlimited
/// Endianness: Little
pub fn config() -> Config {
    Config::new()
}

/// Serializes an object directly into a `Writer` using the default configuration.
///
/// If the serialization would take more bytes than allowed by the size limit, an error
/// is returned and *no bytes* will be written into the `Writer`.
pub fn serialize_into<W, T: ?Sized, O>(writer: W, value: &T) -> Result<()>
where
    W: std::io::Write,
    T: serde::Serialize,
{
    config().serialize_into(writer, value)
}

/// Serializes a serializable object into a `Vec` of bytes using the default configuration.
pub fn serialize<T: ?Sized>(value: &T) -> Result<Vec<u8>>
where
    T: serde::Serialize,
{
    config().serialize(value)
}

/// Deserializes an object directly from a `Read`er using the default configuration.
///
/// If this returns an `Error`, `reader` may be in an invalid state.
pub fn deserialize_from<R, T>(reader: R) -> Result<T>
where
    R: std::io::Read,
    T: serde::de::DeserializeOwned,
{
    config().deserialize_from(reader)
}

/// Deserializes an object from a custom `BincodeRead`er using the default configuration.
/// It is highly recommended to use `deserialize_from` unless you need to implement
/// `BincodeRead` for performance reasons.
///
/// If this returns an `Error`, `reader` may be in an invalid state.
pub fn deserialize_from_custom<'a, R, T>(reader: R) -> Result<T>
where
    R: de::read::BincodeRead<'a>,
    T: serde::de::DeserializeOwned,
{
    config().deserialize_from_custom(reader)
}

/// TODO: document
#[doc(hidden)]
pub fn deserialize_in_place<'a, R, T>(reader: R, place: &mut T) -> Result<()>
where
    T: serde::de::Deserialize<'a>,
    R: BincodeRead<'a>
{
    config().deserialize_in_place(reader, place)
}

/// Deserializes a slice of bytes into an instance of `T` using the default configuration.
pub fn deserialize<'a, T>(bytes: &'a [u8]) -> Result<T>
where
    T: serde::de::Deserialize<'a>,
{
    config().deserialize(bytes)
}

/// Returns the size that an object would be if serialized using Bincode with the default configuration.
pub fn serialized_size<T: ?Sized>(value: &T) -> Result<u64>
where
    T: serde::Serialize,
{
    config().serialized_size(value)
}

/// Executes the acceptor with a serde::Deserializer instance.
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub fn with_deserializer<'a, A,  R>(reader: R, acceptor: A) -> A::Output
where A: DeserializerAcceptor<'a>,
        R: BincodeRead<'a>
{
    config().with_deserializer(reader, acceptor)
}

/// Executes the acceptor with a serde::Serializer instance.
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub fn with_serializer<A, W>(writer: W, acceptor: A) -> A::Output
where A: SerializerAcceptor,
    W: std::io::Write
{
    config().with_serializer(writer, acceptor)
}
<commit_msg>remove unused function type parameter<commit_after>#![deny(missing_docs)]

//! Bincode is a crate for encoding and decoding using a tiny binary
//! serialization strategy.  Using it, you can easily go from having
//! an object in memory, quickly serialize it to bytes, and then
//! deserialize it back just as fast!
//!
//! ### Using Basic Functions
//!
//! ```rust
//! extern crate bincode;
//! use bincode::{serialize, deserialize};
//! fn main() {
//!     // The object that we will serialize.
//!     let target: Option<String>  = Some("hello world".to_string());
//!
//!     let encoded: Vec<u8>        = serialize(&target).unwrap();
//!     let decoded: Option<String> = deserialize(&encoded[..]).unwrap();
//!     assert_eq!(target, decoded);
//! }
//! ```

#![crate_name = "bincode"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]

extern crate byteorder;
extern crate serde;

mod config;
mod ser;
mod error;
mod de;
mod internal;

pub use error::{Error, ErrorKind, Result};
pub use config::Config;
pub use de::read::{BincodeRead, IoReader, SliceReader};

/// An object that implements this trait can be passed a
/// serde::Deserializer without knowing its concrete type.
///
/// This trait should be used only for `with_deserializer` functions.
#[doc(hidden)]
pub trait DeserializerAcceptor<'a> {
    /// The return type for the accept method
    type Output;
    /// Accept a serde::Deserializer and do whatever you want with it.
    fn accept<T: serde::Deserializer<'a>>(self, T) -> Self::Output;
}

/// An object that implements this trait can be passed a
/// serde::Serializer without knowing its concrete type.
///
/// This trait should be used only for `with_serializer` functions.
#[doc(hidden)]
pub trait SerializerAcceptor {
    /// The return type for the accept method
    type Output;
    /// Accept a serde::Serializer and do whatever you want with it.
    fn accept<T: serde::Serializer>(self, T) -> Self::Output;
}

/// Get a default configuration object.
///
/// ### Default Configuration:
/// Byte limit: Unlimited
/// Endianness: Little
pub fn config() -> Config {
    Config::new()
}

/// Serializes an object directly into a `Writer` using the default configuration.
///
/// If the serialization would take more bytes than allowed by the size limit, an error
/// is returned and *no bytes* will be written into the `Writer`.
pub fn serialize_into<W, T: ?Sized>(writer: W, value: &T) -> Result<()>
where
    W: std::io::Write,
    T: serde::Serialize,
{
    config().serialize_into(writer, value)
}

/// Serializes a serializable object into a `Vec` of bytes using the default configuration.
pub fn serialize<T: ?Sized>(value: &T) -> Result<Vec<u8>>
where
    T: serde::Serialize,
{
    config().serialize(value)
}

/// Deserializes an object directly from a `Read`er using the default configuration.
///
/// If this returns an `Error`, `reader` may be in an invalid state.
pub fn deserialize_from<R, T>(reader: R) -> Result<T>
where
    R: std::io::Read,
    T: serde::de::DeserializeOwned,
{
    config().deserialize_from(reader)
}

/// Deserializes an object from a custom `BincodeRead`er using the default configuration.
/// It is highly recommended to use `deserialize_from` unless you need to implement
/// `BincodeRead` for performance reasons.
///
/// If this returns an `Error`, `reader` may be in an invalid state.
pub fn deserialize_from_custom<'a, R, T>(reader: R) -> Result<T>
where
    R: de::read::BincodeRead<'a>,
    T: serde::de::DeserializeOwned,
{
    config().deserialize_from_custom(reader)
}

/// TODO: document
#[doc(hidden)]
pub fn deserialize_in_place<'a, R, T>(reader: R, place: &mut T) -> Result<()>
where
    T: serde::de::Deserialize<'a>,
    R: BincodeRead<'a>
{
    config().deserialize_in_place(reader, place)
}

/// Deserializes a slice of bytes into an instance of `T` using the default configuration.
pub fn deserialize<'a, T>(bytes: &'a [u8]) -> Result<T>
where
    T: serde::de::Deserialize<'a>,
{
    config().deserialize(bytes)
}

/// Returns the size that an object would be if serialized using Bincode with the default configuration.
pub fn serialized_size<T: ?Sized>(value: &T) -> Result<u64>
where
    T: serde::Serialize,
{
    config().serialized_size(value)
}

/// Executes the acceptor with a serde::Deserializer instance.
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub fn with_deserializer<'a, A,  R>(reader: R, acceptor: A) -> A::Output
where A: DeserializerAcceptor<'a>,
        R: BincodeRead<'a>
{
    config().with_deserializer(reader, acceptor)
}

/// Executes the acceptor with a serde::Serializer instance.
/// NOT A PART OF THE STABLE PUBLIC API
#[doc(hidden)]
pub fn with_serializer<A, W>(writer: W, acceptor: A) -> A::Output
where A: SerializerAcceptor,
    W: std::io::Write
{
    config().with_serializer(writer, acceptor)
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! The official Piston window back-end for the Piston game engine

extern crate piston;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate graphics;
extern crate shader_version;
extern crate glutin_window;

use glutin_window::GlutinWindow;
pub use shader_version::OpenGL;
pub use graphics::*;
pub use piston::window::*;
pub use piston::event::*;
pub use piston::input::*;
pub use gfx_graphics::{ Texture, TextureSettings, Flip };

use std::cell::RefCell;
use std::rc::Rc;
use std::any::Any;

use gfx::traits::*;
use gfx_graphics::{ Gfx2d, GfxGraphics };

/// Actual gfx::Stream implementation carried by the window.
pub type GfxStream = gfx::OwnedStream<gfx_device_gl::Device, gfx_device_gl::Output>;
/// Glyph cache.
pub type Glyphs = gfx_graphics::GlyphCache<gfx_device_gl::Resources, gfx_device_gl::Factory>;
/// 2D graphics.
pub type G2d<'a> = GfxGraphics<'a, gfx_device_gl::Resources, gfx_device_gl::CommandBuffer, gfx_device_gl::Output>;

/// Contains everything required for controlling window, graphics, event loop.
pub struct PistonWindow<W: Window = GlutinWindow, T = ()> {
    /// The window.
    pub window: Rc<RefCell<W>>,
    /// GFX stream.
    pub stream: Rc<RefCell<GfxStream>>,
    /// GFX device.
    pub device: Rc<RefCell<gfx_device_gl::Device>>,
    /// Gfx2d.
    pub g2d: Rc<RefCell<Gfx2d<gfx_device_gl::Resources>>>,
    /// The event loop.
    pub events: Rc<RefCell<WindowEvents<W, Event<W::Event>>>>,
    /// The event.
    pub event: Option<Event<W::Event>>,
    /// Application structure.
    pub app: Rc<RefCell<T>>,
    /// The factory that was created along with the device.
    pub factory: Rc<RefCell<gfx_device_gl::Factory>>,
}

impl<T> From<WindowSettings> for PistonWindow<T>
    where T: Window + OpenGLWindow + From<WindowSettings>,
          T::Event: GenericEvent
{
    fn from(settings: WindowSettings) -> PistonWindow<T> {
        PistonWindow::new(Rc::new(RefCell::new(settings.into())), empty_app())
    }
}

impl<W, T> Clone for PistonWindow<W, T>
    where W: Window, W::Event: Clone
{
    fn clone(&self) -> Self {
        PistonWindow {
            window: self.window.clone(),
            stream: self.stream.clone(),
            device: self.device.clone(),
            g2d: self.g2d.clone(),
            events: self.events.clone(),
            event: self.event.clone(),
            app: self.app.clone(),
            factory: self.factory.clone(),
        }
    }
}

impl<W, T> PistonWindow<W, T>
    where W: Window, W::Event: GenericEvent
{
    /// Creates a new piston object.
    pub fn new(window: Rc<RefCell<W>>, app: Rc<RefCell<T>>) -> Self
        where W: OpenGLWindow
    {
        use piston::event::Events;
        use piston::window::{ OpenGLWindow, Window };

        let (device, mut factory) =
            gfx_device_gl::create(|s| window.borrow_mut().get_proc_address(s));

        let draw_size = window.borrow().draw_size();
        let output = factory.make_fake_output(draw_size.width as u16, draw_size.height as u16);

        let g2d = Gfx2d::new(&mut factory);

        let stream = factory.create_stream(output);

        PistonWindow {
            window: window.clone(),
            stream: Rc::new(RefCell::new(stream)),
            device: Rc::new(RefCell::new(device)),
            g2d: Rc::new(RefCell::new(g2d)),
            events: Rc::new(RefCell::new(window.events())),
            event: None,
            app: app,
            factory: Rc::new(RefCell::new(factory)),
        }
    }

    /// Changes application structure.
    pub fn app<U>(self, app: Rc<RefCell<U>>) -> PistonWindow<W, U> {
        PistonWindow {
            window: self.window,
            stream: self.stream,
            device: self.device,
            g2d: self.g2d,
            events: self.events,
            event: self.event,
            app: app,
            factory: self.factory,
        }
    }

    /// Renders 2D graphics.
    pub fn draw_2d<F>(&self, f: F) where
        F: FnMut(Context, &mut GfxGraphics<
            gfx_device_gl::Resources, gfx_device_gl::CommandBuffer,
            gfx_device_gl::Output>)
    {
        use piston::event::RenderEvent;

        if let Some(ref e) = self.event {
            if let Some(args) = e.render_args() {
                let mut stream = self.stream.borrow_mut();
                {
                    let (renderer, output) = stream.access();
                    self.g2d.borrow_mut().draw(renderer, output, args.viewport(), f);
                }
                stream.flush(&mut *self.device.borrow_mut());
            }
        }
    }

    /// Renders 3D graphics.
    pub fn draw_3d<F>(&self, mut f: F) where
        F: FnMut(&mut GfxStream)
    {
        use piston::event::RenderEvent;

        if let Some(ref e) = self.event {
            if let Some(_) = e.render_args() {
                let mut stream = self.stream.borrow_mut();
                f(&mut *stream);
                stream.flush(&mut *self.device.borrow_mut())
            }
        }
    }
}

impl<W, T> Iterator for PistonWindow<W, T>
    where W: Window, W::Event: GenericEvent
{
    type Item = PistonWindow<W, T>;

    fn next(&mut self) -> Option<PistonWindow<W, T>> {
        use piston::event::*;

        if let Some(e) = self.events.borrow_mut().next() {
            if let Some(_) = e.after_render_args() {
                // After swapping buffers.
                self.device.borrow_mut().cleanup();
            }

            if let Some(_) = e.resize_args() {
                let mut stream = self.stream.borrow_mut();
                let draw_size = self.window.borrow().draw_size();
                stream.out.width = draw_size.width as u16;
                stream.out.height = draw_size.height as u16;
            }

            Some(PistonWindow {
                window: self.window.clone(),
                stream: self.stream.clone(),
                device: self.device.clone(),
                g2d: self.g2d.clone(),
                events: self.events.clone(),
                event: Some(e),
                app: self.app.clone(),
                factory: self.factory.clone(),
            })
        } else { None }
    }
}

impl<W, T> GenericEvent for PistonWindow<W, T>
    where W: Window, W::Event: GenericEvent
{
    fn event_id(&self) -> EventId {
        match self.event {
            Some(ref e) => e.event_id(),
            None => EventId("")
        }
    }

    fn with_args<'a, F, U>(&'a self, f: F) -> U
       where F: FnMut(&Any) -> U
    {
        self.event.as_ref().unwrap().with_args(f)
    }

    fn from_args(event_id: EventId, any: &Any, old_event: &Self) -> Option<Self> {
        if let Some(ref e) = old_event.event {
            match GenericEvent::from_args(event_id, any, e) {
                Some(e) => {
                    Some(PistonWindow {
                        window: old_event.window.clone(),
                        stream: old_event.stream.clone(),
                        device: old_event.device.clone(),
                        g2d: old_event.g2d.clone(),
                        events: old_event.events.clone(),
                        event: Some(e),
                        app: old_event.app.clone(),
                        factory: old_event.factory.clone(),
                    })
                }
                None => None
            }
        } else { None }
    }
}

impl<W, T> Window for PistonWindow<W, T>
    where W: Window
{
    type Event = <W as Window>::Event;

    fn should_close(&self) -> bool { self.window.borrow().should_close() }
    fn size(&self) -> Size { self.window.borrow().size() }
    fn draw_size(&self) -> Size { self.window.borrow().draw_size() }
    fn swap_buffers(&mut self) { self.window.borrow_mut().swap_buffers() }
    fn poll_event(&mut self) -> Option<Self::Event> {
        Window::poll_event(&mut *self.window.borrow_mut())
    }
}

impl<W, T> AdvancedWindow for PistonWindow<W, T>
    where W: AdvancedWindow
{
    fn get_title(&self) -> String { self.window.borrow().get_title() }
    fn set_title(&mut self, title: String) {
        self.window.borrow_mut().set_title(title)
    }
    fn get_exit_on_esc(&self) -> bool { self.window.borrow().get_exit_on_esc() }
    fn set_exit_on_esc(&mut self, value: bool) {
        self.window.borrow_mut().set_exit_on_esc(value)
    }
    fn set_capture_cursor(&mut self, value: bool) {
        self.window.borrow_mut().set_capture_cursor(value)
    }
}

impl<W, T> EventLoop for PistonWindow<W, T>
    where W: Window
{
    fn set_ups(&mut self, frames: u64) {
        self.events.borrow_mut().set_ups(frames);
    }

    fn set_max_fps(&mut self, frames: u64) {
        self.events.borrow_mut().set_max_fps(frames);
    }

    fn set_swap_buffers(&mut self, enable: bool) {
        self.events.borrow_mut().set_swap_buffers(enable);
    }

    fn set_bench_mode(&mut self, enable: bool) {
        self.events.borrow_mut().set_bench_mode(enable);
    }
}

/// Creates a new empty application.
pub fn empty_app() -> Rc<RefCell<()>> { Rc::new(RefCell::new(())) }
<commit_msg>Make draw_2d take an FnOnce to match Gfx2d::draw<commit_after>#![deny(missing_docs)]

//! The official Piston window back-end for the Piston game engine

extern crate piston;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate graphics;
extern crate shader_version;
extern crate glutin_window;

use glutin_window::GlutinWindow;
pub use shader_version::OpenGL;
pub use graphics::*;
pub use piston::window::*;
pub use piston::event::*;
pub use piston::input::*;
pub use gfx_graphics::{ Texture, TextureSettings, Flip };

use std::cell::RefCell;
use std::rc::Rc;
use std::any::Any;

use gfx::traits::*;
use gfx_graphics::{ Gfx2d, GfxGraphics };

/// Actual gfx::Stream implementation carried by the window.
pub type GfxStream = gfx::OwnedStream<gfx_device_gl::Device, gfx_device_gl::Output>;
/// Glyph cache.
pub type Glyphs = gfx_graphics::GlyphCache<gfx_device_gl::Resources, gfx_device_gl::Factory>;
/// 2D graphics.
pub type G2d<'a> = GfxGraphics<'a, gfx_device_gl::Resources, gfx_device_gl::CommandBuffer, gfx_device_gl::Output>;

/// Contains everything required for controlling window, graphics, event loop.
pub struct PistonWindow<W: Window = GlutinWindow, T = ()> {
    /// The window.
    pub window: Rc<RefCell<W>>,
    /// GFX stream.
    pub stream: Rc<RefCell<GfxStream>>,
    /// GFX device.
    pub device: Rc<RefCell<gfx_device_gl::Device>>,
    /// Gfx2d.
    pub g2d: Rc<RefCell<Gfx2d<gfx_device_gl::Resources>>>,
    /// The event loop.
    pub events: Rc<RefCell<WindowEvents<W, Event<W::Event>>>>,
    /// The event.
    pub event: Option<Event<W::Event>>,
    /// Application structure.
    pub app: Rc<RefCell<T>>,
    /// The factory that was created along with the device.
    pub factory: Rc<RefCell<gfx_device_gl::Factory>>,
}

impl<T> From<WindowSettings> for PistonWindow<T>
    where T: Window + OpenGLWindow + From<WindowSettings>,
          T::Event: GenericEvent
{
    fn from(settings: WindowSettings) -> PistonWindow<T> {
        PistonWindow::new(Rc::new(RefCell::new(settings.into())), empty_app())
    }
}

impl<W, T> Clone for PistonWindow<W, T>
    where W: Window, W::Event: Clone
{
    fn clone(&self) -> Self {
        PistonWindow {
            window: self.window.clone(),
            stream: self.stream.clone(),
            device: self.device.clone(),
            g2d: self.g2d.clone(),
            events: self.events.clone(),
            event: self.event.clone(),
            app: self.app.clone(),
            factory: self.factory.clone(),
        }
    }
}

impl<W, T> PistonWindow<W, T>
    where W: Window, W::Event: GenericEvent
{
    /// Creates a new piston object.
    pub fn new(window: Rc<RefCell<W>>, app: Rc<RefCell<T>>) -> Self
        where W: OpenGLWindow
    {
        use piston::event::Events;
        use piston::window::{ OpenGLWindow, Window };

        let (device, mut factory) =
            gfx_device_gl::create(|s| window.borrow_mut().get_proc_address(s));

        let draw_size = window.borrow().draw_size();
        let output = factory.make_fake_output(draw_size.width as u16, draw_size.height as u16);

        let g2d = Gfx2d::new(&mut factory);

        let stream = factory.create_stream(output);

        PistonWindow {
            window: window.clone(),
            stream: Rc::new(RefCell::new(stream)),
            device: Rc::new(RefCell::new(device)),
            g2d: Rc::new(RefCell::new(g2d)),
            events: Rc::new(RefCell::new(window.events())),
            event: None,
            app: app,
            factory: Rc::new(RefCell::new(factory)),
        }
    }

    /// Changes application structure.
    pub fn app<U>(self, app: Rc<RefCell<U>>) -> PistonWindow<W, U> {
        PistonWindow {
            window: self.window,
            stream: self.stream,
            device: self.device,
            g2d: self.g2d,
            events: self.events,
            event: self.event,
            app: app,
            factory: self.factory,
        }
    }

    /// Renders 2D graphics.
    pub fn draw_2d<F>(&self, f: F) where
        F: FnOnce(Context, &mut GfxGraphics<
            gfx_device_gl::Resources, gfx_device_gl::CommandBuffer,
            gfx_device_gl::Output>)
    {
        use piston::event::RenderEvent;

        if let Some(ref e) = self.event {
            if let Some(args) = e.render_args() {
                let mut stream = self.stream.borrow_mut();
                {
                    let (renderer, output) = stream.access();
                    self.g2d.borrow_mut().draw(renderer, output, args.viewport(), f);
                }
                stream.flush(&mut *self.device.borrow_mut());
            }
        }
    }

    /// Renders 3D graphics.
    pub fn draw_3d<F>(&self, mut f: F) where
        F: FnMut(&mut GfxStream)
    {
        use piston::event::RenderEvent;

        if let Some(ref e) = self.event {
            if let Some(_) = e.render_args() {
                let mut stream = self.stream.borrow_mut();
                f(&mut *stream);
                stream.flush(&mut *self.device.borrow_mut())
            }
        }
    }
}

impl<W, T> Iterator for PistonWindow<W, T>
    where W: Window, W::Event: GenericEvent
{
    type Item = PistonWindow<W, T>;

    fn next(&mut self) -> Option<PistonWindow<W, T>> {
        use piston::event::*;

        if let Some(e) = self.events.borrow_mut().next() {
            if let Some(_) = e.after_render_args() {
                // After swapping buffers.
                self.device.borrow_mut().cleanup();
            }

            if let Some(_) = e.resize_args() {
                let mut stream = self.stream.borrow_mut();
                let draw_size = self.window.borrow().draw_size();
                stream.out.width = draw_size.width as u16;
                stream.out.height = draw_size.height as u16;
            }

            Some(PistonWindow {
                window: self.window.clone(),
                stream: self.stream.clone(),
                device: self.device.clone(),
                g2d: self.g2d.clone(),
                events: self.events.clone(),
                event: Some(e),
                app: self.app.clone(),
                factory: self.factory.clone(),
            })
        } else { None }
    }
}

impl<W, T> GenericEvent for PistonWindow<W, T>
    where W: Window, W::Event: GenericEvent
{
    fn event_id(&self) -> EventId {
        match self.event {
            Some(ref e) => e.event_id(),
            None => EventId("")
        }
    }

    fn with_args<'a, F, U>(&'a self, f: F) -> U
       where F: FnMut(&Any) -> U
    {
        self.event.as_ref().unwrap().with_args(f)
    }

    fn from_args(event_id: EventId, any: &Any, old_event: &Self) -> Option<Self> {
        if let Some(ref e) = old_event.event {
            match GenericEvent::from_args(event_id, any, e) {
                Some(e) => {
                    Some(PistonWindow {
                        window: old_event.window.clone(),
                        stream: old_event.stream.clone(),
                        device: old_event.device.clone(),
                        g2d: old_event.g2d.clone(),
                        events: old_event.events.clone(),
                        event: Some(e),
                        app: old_event.app.clone(),
                        factory: old_event.factory.clone(),
                    })
                }
                None => None
            }
        } else { None }
    }
}

impl<W, T> Window for PistonWindow<W, T>
    where W: Window
{
    type Event = <W as Window>::Event;

    fn should_close(&self) -> bool { self.window.borrow().should_close() }
    fn size(&self) -> Size { self.window.borrow().size() }
    fn draw_size(&self) -> Size { self.window.borrow().draw_size() }
    fn swap_buffers(&mut self) { self.window.borrow_mut().swap_buffers() }
    fn poll_event(&mut self) -> Option<Self::Event> {
        Window::poll_event(&mut *self.window.borrow_mut())
    }
}

impl<W, T> AdvancedWindow for PistonWindow<W, T>
    where W: AdvancedWindow
{
    fn get_title(&self) -> String { self.window.borrow().get_title() }
    fn set_title(&mut self, title: String) {
        self.window.borrow_mut().set_title(title)
    }
    fn get_exit_on_esc(&self) -> bool { self.window.borrow().get_exit_on_esc() }
    fn set_exit_on_esc(&mut self, value: bool) {
        self.window.borrow_mut().set_exit_on_esc(value)
    }
    fn set_capture_cursor(&mut self, value: bool) {
        self.window.borrow_mut().set_capture_cursor(value)
    }
}

impl<W, T> EventLoop for PistonWindow<W, T>
    where W: Window
{
    fn set_ups(&mut self, frames: u64) {
        self.events.borrow_mut().set_ups(frames);
    }

    fn set_max_fps(&mut self, frames: u64) {
        self.events.borrow_mut().set_max_fps(frames);
    }

    fn set_swap_buffers(&mut self, enable: bool) {
        self.events.borrow_mut().set_swap_buffers(enable);
    }

    fn set_bench_mode(&mut self, enable: bool) {
        self.events.borrow_mut().set_bench_mode(enable);
    }
}

/// Creates a new empty application.
pub fn empty_app() -> Rc<RefCell<()>> { Rc::new(RefCell::new(())) }
<|endoftext|>


<commit_before>extern crate socket;

use socket::{AF_INET, Socket, SOCK_DGRAM, IP_MULTICAST_TTL, IPPROTO_IP};
use std::io::{Error, ErrorKind, Result};
use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
use std::sync::{Arc, mpsc};
use std::thread;
use std::time::Instant;

#[derive(Debug)]
/// `Discover` type
///
/// Used for discovering sonos devices in the local network via the simple service discovery protocol (ssdp).
/// The ssd-protocol works via udp sockets. First a certain search-message is sent to the multicast address (239.255.255.250:1900).
///
/// All answer from upnp (universal plug and play) ready devices are processed and filtered ("Sonos" is in the reply).
pub struct Discover {
    /// Multicast address in the local network
    multicast_addr: SocketAddr,
    /// Socket implementation
    /// INFO: The socket type will likely change in the future due to cross platform compatability
    socket: Arc<Socket>
}

impl Discover {
    /// Creates a new `Discovery`. Uses the default socket on the default ipv4 multicast address (239.255.255.250:1900).
    ///
    /// # Examples
    ///
    /// ```
    /// use sonos_discovery::Discovery;
    ///
    /// let discovery: Discovery = Discovery::new().unwrap();
    /// ```
    pub fn new() -> Result<Self> {
        let multicast_address = match SocketAddr::from_str("239.255.255.250:1900") {
            Ok(address) => address,
            Err(_) => return Err(Error::new(ErrorKind::InvalidData, "Couldn't parse socket address"))
        };

        Discover::with_address(multicast_address)
    }

    /// Creates a new `Discovery` with a custom multicast address.
    pub fn with_address(address: SocketAddr) -> Result<Self> {
        let socket = Discover::create_default_socket()?;
        Ok(Discover {
            multicast_addr: address,
            socket
        })
    }

    /// Create a default socket
    /// socket option: AF_INET - SOCK_DGRAM - 0 // Automatically discover the protocol (IPPROTO_UDP)
    /// socket option: IPPROTO_IP - IP_MULTICAST_TTL - 4 // UPnP 1.0 needs a TTL of 4
    fn create_default_socket() -> Result<Arc<Socket>> {
        let socket_family = AF_INET;
        let socket_level = SOCK_DGRAM;
        let protocol = 0; // auto discover
        let socket_options = vec![(IPPROTO_IP, IP_MULTICAST_TTL, 4)];

        Discover::create_socket(socket_family, socket_level, protocol, &socket_options)
    }

    fn create_socket(socket_family: i32, socket_type: i32, protocol: i32, socket_options: &[(i32, i32, i32)]) -> Result<Arc<Socket>> {
        let socket = Socket::new(socket_family, socket_type, protocol)?;
        for socket_option in socket_options {
            // TODO: Use result, allow to fail, panic or return a result?
            socket.setsockopt(socket_option.0, socket_option.1, socket_option.2)?
        }

        Ok(Arc::new(socket))
    }

    /// Sends the search message to the defined socket.
    /// Message can't have leading/trailing whitespaces (\s).
    ///
    /// # Message
    /// ```
    /// M-SEARCH * HTTP/1.1
    /// HOST: 239.255.255.250:1900
    /// MAN: "ssdp:discover"
    /// MX: 1
    /// ST: urn:schemas-upnp-org:device:ZonePlayer:1```
    fn send_search(&self) -> Result<usize> {
        let player_search = br#"M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 1
ST: urn:schemas-upnp-org:device:ZonePlayer:1"#;

        self.socket.sendto(player_search, 0, &self.multicast_addr)
    }

    /// Start discovering devices.
    ///
    /// # Examples
    /// In this example the search will stop if3 devices have been discovered or the default timeout (5s) is reached.
    /// This is useful if you know the amount of speakers you have and want to reduce the search time.
    ///
    /// ```
    /// use sonos_discovery::Discovery;
    ///
    /// let devices: Vec<IpAddr> = Discovery::new().unwrap().start(None, Some(3)).unwrap();
    /// ```
    pub fn start(&self, timeout: Option<u32>, device_count: Option<usize>) -> Result<Vec<IpAddr>> {
        let timeout = timeout.unwrap_or(5);
        let device_count = device_count.unwrap_or(std::u32::MAX as usize);

        let time = Instant::now();

        self.send_search()?;
        let mut devices: Vec<IpAddr> = Vec::new();
        while time.elapsed().as_secs() < u64::from(timeout) && devices.len() < device_count {
            let socket = Arc::clone(&self.socket);
            let (sender, receiver) = mpsc::channel();
            thread::spawn(move ||
                {
                    if let Ok((__addr, _data)) = socket.recvfrom(1024, 0) {
                        // TODO: Add logging, fail on multiple send errors?
                        if sender.send((__addr, _data)).is_ok() {}
                    }
                }
            );

            // TODO: Add logging, change
            let (_addr, data) = match receiver.recv_timeout(std::time::Duration::new(0, 500_000_000)) {
                Ok((_addr, data)) => (_addr, data),
                Err(_) => continue
            };

            // Skip from_utf8_lossy
            // Due to the usual small size of `devices`, this is faster than decoding a potentially large response
            if data.is_empty() || devices.contains(&_addr.ip()) {
                println!("{:?}", &_addr.ip());
                continue
            }

            let data = String::from_utf8_lossy(&data);
            if data.contains("Sonos") {
                devices.push(_addr.ip())
            }
        }

        Ok(devices)
    }
}

/// Drop internal socket on going out of scope
impl Drop for Discover {
    fn drop(&mut self) {
        // Socket closes on drop automatically, better safe than sorry
        // Log failure for debugging
        let _ = self.socket.close();
    }
}
<commit_msg>Improve error type conversion<commit_after>extern crate socket;

use socket::{AF_INET, Socket, SOCK_DGRAM, IP_MULTICAST_TTL, IPPROTO_IP};
use std::io::{Error, ErrorKind, Result};
use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
use std::sync::{Arc, mpsc};
use std::thread;
use std::time::Instant;

#[derive(Debug)]
/// `Discover` type
///
/// Used for discovering sonos devices in the local network via the simple service discovery protocol (ssdp).
/// The ssd-protocol works via udp sockets. First a certain search-message is sent to the multicast address (239.255.255.250:1900).
///
/// All answer from upnp (universal plug and play) ready devices are processed and filtered ("Sonos" is in the reply).
pub struct Discover {
    /// Multicast address in the local network
    multicast_addr: SocketAddr,
    /// Socket implementation
    /// INFO: The socket type will likely change in the future due to cross platform compatability
    socket: Arc<Socket>
}

impl Discover {
    /// Creates a new `Discovery`. Uses the default socket on the default ipv4 multicast address (239.255.255.250:1900).
    ///
    /// # Examples
    ///
    /// ```
    /// use sonos_discovery::Discovery;
    ///
    /// let discovery: Discovery = Discovery::new().unwrap();
    /// ```
    pub fn new() -> Result<Self> {
        let multicast_address = SocketAddr::from_str("239.255.255.250:1900")
            .map_err(|_|
                Error::new(ErrorKind::InvalidData, "Couldn't parse socket address"))?;

        Discover::with_address(multicast_address)
    }

    /// Creates a new `Discovery` with a custom multicast address.
    pub fn with_address(address: SocketAddr) -> Result<Self> {
        let socket = Discover::create_default_socket()?;
        Ok(Discover {
            multicast_addr: address,
            socket
        })
    }

    /// Create a default socket
    /// socket option: AF_INET - SOCK_DGRAM - 0 // Automatically discover the protocol (IPPROTO_UDP)
    /// socket option: IPPROTO_IP - IP_MULTICAST_TTL - 4 // UPnP 1.0 needs a TTL of 4
    fn create_default_socket() -> Result<Arc<Socket>> {
        let socket_family = AF_INET;
        let socket_level = SOCK_DGRAM;
        let protocol = 0; // auto discover
        let socket_options = vec![(IPPROTO_IP, IP_MULTICAST_TTL, 4)];

        Discover::create_socket(socket_family, socket_level, protocol, &socket_options)
    }

    fn create_socket(socket_family: i32, socket_type: i32, protocol: i32, socket_options: &[(i32, i32, i32)]) -> Result<Arc<Socket>> {
        let socket = Socket::new(socket_family, socket_type, protocol)?;
        for socket_option in socket_options {
            // TODO: Use result, allow to fail, panic or return a result?
            socket.setsockopt(socket_option.0, socket_option.1, socket_option.2)?
        }

        Ok(Arc::new(socket))
    }

    /// Sends the search message to the defined socket.
    /// Message can't have leading/trailing whitespaces (\s).
    ///
    /// # Message
    /// ```
    /// M-SEARCH * HTTP/1.1
    /// HOST: 239.255.255.250:1900
    /// MAN: "ssdp:discover"
    /// MX: 1
    /// ST: urn:schemas-upnp-org:device:ZonePlayer:1```
    fn send_search(&self) -> Result<usize> {
        let player_search = br#"M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 1
ST: urn:schemas-upnp-org:device:ZonePlayer:1"#;

        self.socket.sendto(player_search, 0, &self.multicast_addr)
    }

    /// Start discovering devices.
    ///
    /// # Examples
    /// In this example the search will stop if3 devices have been discovered or the default timeout (5s) is reached.
    /// This is useful if you know the amount of speakers you have and want to reduce the search time.
    ///
    /// ```
    /// use sonos_discovery::Discovery;
    ///
    /// let devices: Vec<IpAddr> = Discovery::new().unwrap().start(None, Some(3)).unwrap();
    /// ```
    pub fn start(&self, timeout: Option<u32>, device_count: Option<usize>) -> Result<Vec<IpAddr>> {
        let timeout = timeout.unwrap_or(5);
        let device_count = device_count.unwrap_or(std::u32::MAX as usize);

        let time = Instant::now();

        self.send_search()?;
        let mut devices: Vec<IpAddr> = Vec::new();
        while time.elapsed().as_secs() < u64::from(timeout) && devices.len() < device_count {
            let socket = Arc::clone(&self.socket);
            let (sender, receiver) = mpsc::channel();
            thread::spawn(move ||
                {
                    if let Ok((__addr, _data)) = socket.recvfrom(1024, 0) {
                        // TODO: Add logging, fail on multiple send errors?
                        if sender.send((__addr, _data)).is_ok() {}
                    }
                }
            );

            // TODO: Add logging, change
            let (_addr, data) = match receiver.recv_timeout(std::time::Duration::new(0, 500_000_000)) {
                Ok((_addr, data)) => (_addr, data),
                Err(_) => continue
            };

            // Skip from_utf8_lossy
            // Due to the usual small size of `devices`, this is faster than decoding a potentially large response
            if data.is_empty() || devices.contains(&_addr.ip()) {
                println!("{:?}", &_addr.ip());
                continue
            }

            let data = String::from_utf8_lossy(&data);
            if data.contains("Sonos") {
                devices.push(_addr.ip())
            }
        }

        Ok(devices)
    }
}

/// Drop internal socket on going out of scope
impl Drop for Discover {
    fn drop(&mut self) {
        // Socket closes on drop automatically, better safe than sorry
        // Log failure for debugging
        let _ = self.socket.close();
    }
}
<|endoftext|>


<commit_before>#![feature(phase)]
extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate serialize;

use std::cell::RefCell;
use std::collections::HashMap;
use std::io::{BufferedReader, BufferedWriter, InvalidInput, IoError, IoResult, TcpStream};
use std::vec::Vec;
use conn::{Conn, Connection};
use data::{Config, IrcReader, IrcWriter, Message};

pub mod conn;
pub mod data;

pub trait Bot<'a> {
    fn send_nick(&self, nick: &str) -> IoResult<()>;
    fn send_user(&self, username: &str, real_name: &str) -> IoResult<()>;
    fn send_join(&self, chan: &str) -> IoResult<()>;
    fn send_mode(&self, chan: &str, mode: &str) -> IoResult<()>;
    fn send_topic(&self, chan: &str, topic: &str) -> IoResult<()>;
    fn send_invite(&self, person: &str, chan: &str) -> IoResult<()>;
    fn send_privmsg(&self, chan: &str, msg: &str) -> IoResult<()>;
    fn identify(&self) -> IoResult<()>;
    fn output(&mut self) -> IoResult<()>;
    fn config(&self) -> Config;
}

pub struct IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    pub conn: RefCell<Connection<T, U>>,
    pub config: Config,
    process: RefCell<|&IrcBot<T, U>, &str, &str, &[&str]|:'a -> IoResult<()>>,
    pub chanlists: HashMap<String, Vec<String>>,
}

impl<'a> IrcBot<'a, BufferedWriter<TcpStream>, TcpStream> {
    pub fn new(process: |&IrcBot<BufferedWriter<TcpStream>, TcpStream>, &str, &str, &[&str]|:'a -> IoResult<()>) -> IoResult<IrcBot<'a, BufferedWriter<TcpStream>, TcpStream>> {
        let config = try!(Config::load());
        let conn = try!(Connection::connect(config.server.as_slice(), config.port));
        Ok(IrcBot {
            conn: RefCell::new(conn),
            config: config,
            process: RefCell::new(process),
            chanlists: HashMap::new(),
        })
    }
}

impl<'a, T, U> Bot<'a> for IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    fn send_nick(&self, nick: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "NICK", [nick]))
    }

    fn send_user(&self, username: &str, real_name: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "USER", [username, "0", "*", real_name]))
    }

    fn send_join(&self, chan: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "JOIN", [chan.as_slice()]))
    }

    fn send_mode(&self, chan: &str, mode: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "MODE", [chan.as_slice(), mode.as_slice()]))
    }

    fn send_topic(&self, chan: &str, topic: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "TOPIC", [chan.as_slice(), topic.as_slice()]))
    }

    fn send_invite(&self, person: &str, chan: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "INVITE", [person.as_slice(), chan.as_slice()]))
    }

    fn send_privmsg(&self, chan: &str, msg: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "PRIVMSG", [chan.as_slice(), msg.as_slice()]))
    }

    fn identify(&self) -> IoResult<()> {
        try!(self.send_nick(self.config.nickname.as_slice()));
        self.send_user(self.config.username.as_slice(), self.config.realname.as_slice())
    }

    fn output(&mut self) -> IoResult<()> {
        let mut reader = match self.conn.borrow_mut().deref_mut() {
            &Conn(_, ref recv) => BufferedReader::new(recv.clone()),
        };
        for line in reader.lines() {
            match line {
                Ok(ln) => {
                    let (source, command, args) = try!(process(ln.as_slice()));
                    try!(self.handle_command(source, command, args.as_slice()));
                    println!("{}", ln)
                },
                Err(e) => println!("Shit, you're fucked! {}", e),
            }
        }
        Ok(())
    }

    fn config(&self) -> Config {
        self.config.clone()
    }
}

impl<'a, T, U> IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    fn handle_command(&mut self, source: &str, command: &str, args: &[&str]) -> IoResult<()> {
        match (command, args) {
            ("PING", [msg]) => {
                try!(Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "PONG", [msg])));
            },
            ("376", _) => { // End of MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("422", _) => { // Missing MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("353", [_, _, chan, users]) => { // /NAMES
                for user in users.split_str(" ") {
                    if !match self.chanlists.find_mut(&String::from_str(chan)) {
                        Some(vec) => {
                            vec.push(String::from_str(user));
                            true
                        },
                        None => false,
                    } {
                        self.chanlists.insert(String::from_str(chan), vec!(String::from_str(user)));
                    }
                }
            },
            ("JOIN", [chan]) => {
                match self.chanlists.find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => vec.push(String::from_str(source.slice_to(i))),
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            ("PART", [chan, _]) => {
                match self.chanlists.find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => {
                                match vec.as_slice().position_elem(&String::from_str(source.slice_to(i))) {
                                    Some(n) => {
                                        vec.swap_remove(n);
                                    },
                                    None => (),
                                };
                            },
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            _ => {
                try!((*self.process.borrow_mut().deref_mut())(self, source, command, args));
            },
        };
        Ok(())
    }
}

fn process(msg: &str) -> IoResult<(&str, &str, Vec<&str>)> {
    let reg = regex!(r"^(?::([^ ]+) )?([^ ]+)(.*)");
    let cap = match reg.captures(msg) {
        Some(x) => x,
        None => return Err(IoError {
            kind: InvalidInput,
            desc: "Failed to parse line",
            detail: None,
        }),
    };
    let source = cap.at(1);
    let command = cap.at(2);
    let args = parse_args(cap.at(3));
    Ok((source, command, args))
}

fn parse_args(line: &str) -> Vec<&str> {
    let reg = regex!(r" ([^: ]+)| :([^\r\n]*)[\r\n]*$");
    reg.captures_iter(line).map(|cap| {
        match cap.at(1) {
            "" => cap.at(2),
            x => x,
        }
    }).collect()
}

#[test]
fn process_line_test() {
    let res = process(":flare.to.ca.fyrechat.net 353 pickles = #pickles :pickles awe\r\n").unwrap();
    let (source, command, args) = res;
    assert_eq!(source, "flare.to.ca.fyrechat.net");
    assert_eq!(command, "353");
    assert_eq!(args, vec!["pickles", "=", "#pickles", "pickles awe"]);

    let res = process("PING :flare.to.ca.fyrechat.net\r\n").unwrap();
    let (source, command, args) = res;
    assert_eq!(source, "");
    assert_eq!(command, "PING");
    assert_eq!(args, vec!["flare.to.ca.fyrechat.net"]);
}

#[test]
fn process_args_test() {
    let res = parse_args("PRIVMSG #vana :hi");
    assert_eq!(res, vec!["#vana", "hi"])
}
<commit_msg>config(...) returns a reference instead of a copy of the value.<commit_after>#![feature(phase)]
extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate serialize;

use std::cell::RefCell;
use std::collections::HashMap;
use std::io::{BufferedReader, BufferedWriter, InvalidInput, IoError, IoResult, TcpStream};
use std::vec::Vec;
use conn::{Conn, Connection};
use data::{Config, IrcReader, IrcWriter, Message};

pub mod conn;
pub mod data;

pub trait Bot<'a> {
    fn send_nick(&self, nick: &str) -> IoResult<()>;
    fn send_user(&self, username: &str, real_name: &str) -> IoResult<()>;
    fn send_join(&self, chan: &str) -> IoResult<()>;
    fn send_mode(&self, chan: &str, mode: &str) -> IoResult<()>;
    fn send_topic(&self, chan: &str, topic: &str) -> IoResult<()>;
    fn send_invite(&self, person: &str, chan: &str) -> IoResult<()>;
    fn send_privmsg(&self, chan: &str, msg: &str) -> IoResult<()>;
    fn identify(&self) -> IoResult<()>;
    fn output(&mut self) -> IoResult<()>;
    fn config(&self) -> &Config;
}

pub struct IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    pub conn: RefCell<Connection<T, U>>,
    pub config: Config,
    process: RefCell<|&IrcBot<T, U>, &str, &str, &[&str]|:'a -> IoResult<()>>,
    pub chanlists: HashMap<String, Vec<String>>,
}

impl<'a> IrcBot<'a, BufferedWriter<TcpStream>, TcpStream> {
    pub fn new(process: |&IrcBot<BufferedWriter<TcpStream>, TcpStream>, &str, &str, &[&str]|:'a -> IoResult<()>) -> IoResult<IrcBot<'a, BufferedWriter<TcpStream>, TcpStream>> {
        let config = try!(Config::load());
        let conn = try!(Connection::connect(config.server.as_slice(), config.port));
        Ok(IrcBot {
            conn: RefCell::new(conn),
            config: config,
            process: RefCell::new(process),
            chanlists: HashMap::new(),
        })
    }
}

impl<'a, T, U> Bot<'a> for IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    fn send_nick(&self, nick: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "NICK", [nick]))
    }

    fn send_user(&self, username: &str, real_name: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "USER", [username, "0", "*", real_name]))
    }

    fn send_join(&self, chan: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "JOIN", [chan.as_slice()]))
    }

    fn send_mode(&self, chan: &str, mode: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "MODE", [chan.as_slice(), mode.as_slice()]))
    }

    fn send_topic(&self, chan: &str, topic: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "TOPIC", [chan.as_slice(), topic.as_slice()]))
    }

    fn send_invite(&self, person: &str, chan: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "INVITE", [person.as_slice(), chan.as_slice()]))
    }

    fn send_privmsg(&self, chan: &str, msg: &str) -> IoResult<()> {
        Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "PRIVMSG", [chan.as_slice(), msg.as_slice()]))
    }

    fn identify(&self) -> IoResult<()> {
        try!(self.send_nick(self.config.nickname.as_slice()));
        self.send_user(self.config.username.as_slice(), self.config.realname.as_slice())
    }

    fn output(&mut self) -> IoResult<()> {
        let mut reader = match self.conn.borrow_mut().deref_mut() {
            &Conn(_, ref recv) => BufferedReader::new(recv.clone()),
        };
        for line in reader.lines() {
            match line {
                Ok(ln) => {
                    let (source, command, args) = try!(process(ln.as_slice()));
                    try!(self.handle_command(source, command, args.as_slice()));
                    println!("{}", ln)
                },
                Err(e) => println!("Shit, you're fucked! {}", e),
            }
        }
        Ok(())
    }

    fn config(&self) -> &Config {
        &self.config
    }
}

impl<'a, T, U> IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    fn handle_command(&mut self, source: &str, command: &str, args: &[&str]) -> IoResult<()> {
        match (command, args) {
            ("PING", [msg]) => {
                try!(Connection::send(self.conn.borrow_mut().deref_mut(), Message::new(None, "PONG", [msg])));
            },
            ("376", _) => { // End of MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("422", _) => { // Missing MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("353", [_, _, chan, users]) => { // /NAMES
                for user in users.split_str(" ") {
                    if !match self.chanlists.find_mut(&String::from_str(chan)) {
                        Some(vec) => {
                            vec.push(String::from_str(user));
                            true
                        },
                        None => false,
                    } {
                        self.chanlists.insert(String::from_str(chan), vec!(String::from_str(user)));
                    }
                }
            },
            ("JOIN", [chan]) => {
                match self.chanlists.find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => vec.push(String::from_str(source.slice_to(i))),
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            ("PART", [chan, _]) => {
                match self.chanlists.find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => {
                                match vec.as_slice().position_elem(&String::from_str(source.slice_to(i))) {
                                    Some(n) => {
                                        vec.swap_remove(n);
                                    },
                                    None => (),
                                };
                            },
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            _ => {
                try!((*self.process.borrow_mut().deref_mut())(self, source, command, args));
            },
        };
        Ok(())
    }
}

fn process(msg: &str) -> IoResult<(&str, &str, Vec<&str>)> {
    let reg = regex!(r"^(?::([^ ]+) )?([^ ]+)(.*)");
    let cap = match reg.captures(msg) {
        Some(x) => x,
        None => return Err(IoError {
            kind: InvalidInput,
            desc: "Failed to parse line",
            detail: None,
        }),
    };
    let source = cap.at(1);
    let command = cap.at(2);
    let args = parse_args(cap.at(3));
    Ok((source, command, args))
}

fn parse_args(line: &str) -> Vec<&str> {
    let reg = regex!(r" ([^: ]+)| :([^\r\n]*)[\r\n]*$");
    reg.captures_iter(line).map(|cap| {
        match cap.at(1) {
            "" => cap.at(2),
            x => x,
        }
    }).collect()
}

#[test]
fn process_line_test() {
    let res = process(":flare.to.ca.fyrechat.net 353 pickles = #pickles :pickles awe\r\n").unwrap();
    let (source, command, args) = res;
    assert_eq!(source, "flare.to.ca.fyrechat.net");
    assert_eq!(command, "353");
    assert_eq!(args, vec!["pickles", "=", "#pickles", "pickles awe"]);

    let res = process("PING :flare.to.ca.fyrechat.net\r\n").unwrap();
    let (source, command, args) = res;
    assert_eq!(source, "");
    assert_eq!(command, "PING");
    assert_eq!(args, vec!["flare.to.ca.fyrechat.net"]);
}

#[test]
fn process_args_test() {
    let res = parse_args("PRIVMSG #vana :hi");
    assert_eq!(res, vec!["#vana", "hi"])
}
<|endoftext|>


<commit_before>#![cfg_attr(test, feature(test))]
#[cfg(test)]
extern crate test;

/// The sound table.
///
/// The first bit each describes a certain property of the phone:
///
/// | Position | Modifier | Property    | Phones   |
/// |----------|----------|-------------|----------|
/// | 1        | 1        | Nasal       | mn       |
/// | 2        | 2        | Plosive     | pbtdcgqk |
/// | 3        | 4        | Fricative   | fvsjxzhc |
/// | 4        | 8        | Approximant | vrhjwc   |
/// | 5        | 16       | Trill       | r        |
/// | 6        | 32       | Lateral     | l        |
/// | 7        | 64       | Type²       | mpbfv    |
/// | 8        | 128      | Confident¹  | lrxzq    |
///
/// ¹hard to misspell.
/// ²1 means labial or dorsal, 0 means apical.
const PHONES: [u64; LETTERS as usize] = [
    0, // a
    0b01000010, // b
    0b00001110, // c
    0b00000010, // d
    0, // e
    0b01000100, // f
    0b00000010, // g
    0b00001100, // h
    0, // i
    0b00001100, // j
    0b00000010, // k
    0b10100000, // l
    0b01000001, // m
    0b00000001, // n
    0, // o
    0b01000010, // p
    0b10000010, // q
    0b10011000, // r
    0b00000100, // s
    0b00000010, // t
    0, // u
    0b01001100, // v
    0b00001000, // w
    0b10000100, // x
    0, // y
    0b10000100, // z
];
const LETTERS: u8 =  26;

/// Phonetically, hash this string.
///
/// This hashing function is based upon a phonetic reduction algorithm, and is locality sensitive.
///
/// This will map the string a Soundex-esque value, although to similar sounding strings will not
/// necessarily be mapped to the same, but will map to nearby values (nearby in this case means the
/// XOR having a low Hamming weight).
///
/// This is two orders of magnitude faster than Soundex, and several orders of magnitude faster
/// than Levenshtein distance, making it feasible to run on large sets of strings in very short
/// time.
///
/// It is optimized for European languages as well.
///
/// A word containing too many non-duplicate consonants will overflow and possibly cause
/// unspecified behavior, although observations shows that it affect the result relatively little.
///
/// Each byte in the string will be mapped to a value from a table, such that similarly sounding
/// characters have many overlapping bits. This way you ensure that strings sounding alike will be
/// mapped nearby each other. Vowels and duplicates will be skipped.
///
/// The first byte, however, is skipped and left in the most significant place, making it most
/// influential to the hash.
///
/// Case has no effect.
pub fn hash(s: &str) -> u64 {
    let mut bytes = s.bytes();
    let first_byte = bytes.next().map_or(0, |x| {
        let phone = phone(x);
        if phone == 0 { x as u64 } else { phone }
    });
    let mut res = 0;

    for i in bytes {
        let x = phone(i);
        if x != 0 && res & 255 != x {
            res <<= 8;
            res |= x;
        }
    }

    res | (first_byte << 56)
}

/// Get the "sound" of this character.
///
/// This is designed such that similar sounding characters will have a low XOR. Vowels or skipgrams
/// will return 0.
#[inline(always)]
fn phone(b: u8) -> u64 {
    let entry = (b | 32).wrapping_sub(b'a');
    if entry < LETTERS {
        PHONES[entry as usize]
    } else { 0 }
}

/// Calculate the Eudex distance between two words.
///
/// This metric will only measure the bitwise distance between two strings, which is a XOR-like
/// metric, making it unfit for certain purposes.  Generally speaking, the lower this is, the more
/// similar are the two words, although each byte carries different weight (the first one carries
/// the most, and the following's weights are simply half the weight of the previous byte).
///
/// # Example
///
/// ```rust
/// let distance = eudex::distance("write", "right").count_ones();
/// // Hamming weight of the Eudex distance gives a "smoother" word metric.
///
/// assert_eq!(distance, 6);
/// ```
pub fn distance(a: &str, b: &str) -> u64 {
    hash(a) ^ hash(b)
}

/// Check if two sentences sound "similar".
pub fn similar(a: &str, b: &str) -> bool {
    distance(a, b) < 670000
}

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

    #[test]
    fn test_exact() {
        assert_eq!(hash("lal"), hash("lel"));
        assert_eq!(hash("rupert"), hash("ropert"));
        assert_eq!(hash("rrr"), hash("rraaaa"));
        assert_eq!(hash("random"), hash("rondom"));
        assert_eq!(hash("java"), hash("jiva"));
        assert_eq!(hash("JAva"), hash("jAva"));
        assert_eq!(hash("triggered"), hash("TRIGGERED"));
        assert_eq!(hash("comp-uter"), hash("computer"));
        assert_eq!(hash("comp@u#te?r"), hash("computer"));
        assert_eq!(hash("c0mp^tər"), hash("computer"));
    }

    #[test]
    fn test_mismatch() {
        assert!(hash("reddit") != hash("eddit"));
        assert!(hash("lol") != hash("lulz"));
        assert!(hash("ijava") != hash("java"));
        assert!(hash("jesus") != hash("iesus"));
        assert!(hash("aesus") != hash("iesus"));
    }

    #[test]
    fn test_distance() {
        assert!(distance("lizzard", "wizzard") > distance("rick", "rolled"));
        assert!(distance("bannana", "panana") >= distance("apple", "abple"));
        //assert!(distance("franco", "sranco") < distance("unicode", "ASCII"));
        assert!(distance("trump", "drumpf") < distance("gangam", "style"));
        assert!(distance("right", "write").count_zeros() > distance("write", "abdominohysterotomy").count_zeros());
    }

    #[test]
    fn test_reflexivity() {
        assert_eq!(distance("a", "b"), distance("b", "a"));
        assert_eq!(distance("youtube", "facebook"), distance("facebook", "youtube"));
        assert_eq!(distance("Rust", "Go"), distance("Go", "Rust"));
        assert_eq!(distance("rick", "rolled"), distance("rolled", "rick"));
    }

    #[test]
    fn test_similar() {
        // Similar.
        assert!(similar("yay", "yuy"));
        assert!(distance("crack", "crakk").count_ones() < 10);
        assert!(similar("what", "wat"));
        assert!(similar("jesus", "jeuses"));
        assert!(similar("", ""));
        assert!(similar("jumpo", "jumbo"));
        assert!(similar("lol", "lulz"));
        assert!(similar("goth", "god"));

        // Not similar.
        assert!(!similar("youtube", "reddit"));
        assert!(!similar("yet", "vet"));
        assert!(!similar("hacker", "4chan"));
        assert!(!similar("awesome", "me"));
        assert!(!similar("prisco", "vkisco"));
        assert!(!similar("no", "go"));
        assert!(!similar("horse", "norse"));
        assert!(!similar("nice", "mice"));
    }

    #[bench]
    fn bench_dict(b: &mut Bencher) {
        use std::fs;
        use std::io::{BufRead, BufReader};

        b.iter(|| {
            let dict = fs::File::open("/usr/share/dict/american-english").unwrap();
            let mut vec = Vec::new();

            for i in BufReader::new(dict).lines() {
                vec.push(hash(&i.unwrap()));
            }

            vec
        });
    }
}
<commit_msg>Improve docs<commit_after>//! Eudex is a Soundex-esque phonetic reduction/hashing algorithm, providing locality sensitive
//! "hashes" of words, based on the spelling and pronunciation.

#![cfg_attr(test, feature(test))]
#[cfg(test)]
extern crate test;

/// The sound table.
///
/// The first bit each describes a certain property of the phone:
///
/// | Position | Modifier | Property    | Phones   |
/// |----------|----------|-------------|----------|
/// | 1        | 1        | Nasal       | mn       |
/// | 2        | 2        | Plosive     | pbtdcgqk |
/// | 3        | 4        | Fricative   | fvsjxzhc |
/// | 4        | 8        | Approximant | vrhjwc   |
/// | 5        | 16       | Trill       | r        |
/// | 6        | 32       | Lateral     | l        |
/// | 7        | 64       | Type²       | mpbfv    |
/// | 8        | 128      | Confident¹  | lrxzq    |
///
/// ¹hard to misspell.
/// ²1 means labial or dorsal, 0 means apical.
const PHONES: [u64; LETTERS as usize] = [
    0, // a
    0b01000010, // b
    0b00001110, // c
    0b00000010, // d
    0, // e
    0b01000100, // f
    0b00000010, // g
    0b00001100, // h
    0, // i
    0b00001100, // j
    0b00000010, // k
    0b10100000, // l
    0b01000001, // m
    0b00000001, // n
    0, // o
    0b01000010, // p
    0b10000010, // q
    0b10011000, // r
    0b00000100, // s
    0b00000010, // t
    0, // u
    0b01001100, // v
    0b00001000, // w
    0b10000100, // x
    0, // y
    0b10000100, // z
];
const LETTERS: u8 =  26;

/// Phonetically hash this string.
///
/// This hashing function is based upon a phonetic reduction algorithm, and is locality sensitive.
///
/// This will map the string a Soundex-esque value, although to similar sounding strings will not
/// necessarily be mapped to the same, but will map to nearby values (nearby in this case means the
/// XOR having a low Hamming weight).
///
/// This is two orders of magnitude faster than Soundex, and several orders of magnitude faster
/// than Levenshtein distance, making it feasible to run on large sets of strings in very short
/// time.
///
/// A word containing too many non-duplicate consonants will overflow and possibly cause
/// unspecified behavior, although observations shows that it affect the end result relatively
/// little.
///
/// Each byte in the string will be mapped to a value from a table, such that similarly sounding
/// characters have many overlapping bits. This way you ensure that strings sounding alike will be
/// mapped nearby each other. Vowels and duplicates will be skipped.
///
/// The first byte, however, is skipped and left in the most significant place, making it most
/// influential to the hash.
///
/// Case has no effect.
pub fn hash(s: &str) -> u64 {
    let mut bytes = s.bytes();
    let first_byte = bytes.next().map_or(0, |x| {
        let phone = phone(x);
        if phone == 0 { x as u64 } else { phone }
    });
    let mut res = 0;

    for i in bytes {
        let x = phone(i);
        if x != 0 && res & 255 != x {
            res <<= 8;
            res |= x;
        }
    }

    res | (first_byte << 56)
}

/// Get the "sound" of this character.
///
/// This is designed such that similar sounding characters will have a low XOR. Vowels or skipgrams
/// will return 0.
#[inline(always)]
fn phone(b: u8) -> u64 {
    let entry = (b | 32).wrapping_sub(b'a');
    if entry < LETTERS {
        PHONES[entry as usize]
    } else { 0 }
}

/// Calculate the Eudex distance between two words.
///
/// This metric will only measure the bitwise distance between two strings, which is a XOR-like
/// metric, making it unfit for certain purposes.  Generally speaking, the lower this is, the more
/// similar are the two words, although each byte carries different weight (the first one carries
/// the most, and the following's weights are simply half the weight of the previous byte).
///
/// # Example
///
/// ```rust
/// let distance = eudex::distance("write", "right").count_ones();
/// // Hamming weight of the Eudex distance gives a "smoother" word metric.
///
/// assert_eq!(distance, 6);
/// ```
pub fn distance(a: &str, b: &str) -> u64 {
    hash(a) ^ hash(b)
}

/// Check if two sentences sound "similar".
pub fn similar(a: &str, b: &str) -> bool {
    distance(a, b) < 670000
}

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

    #[test]
    fn test_exact() {
        assert_eq!(hash("lal"), hash("lel"));
        assert_eq!(hash("rupert"), hash("ropert"));
        assert_eq!(hash("rrr"), hash("rraaaa"));
        assert_eq!(hash("random"), hash("rondom"));
        assert_eq!(hash("java"), hash("jiva"));
        assert_eq!(hash("JAva"), hash("jAva"));
        assert_eq!(hash("triggered"), hash("TRIGGERED"));
        assert_eq!(hash("comp-uter"), hash("computer"));
        assert_eq!(hash("comp@u#te?r"), hash("computer"));
        assert_eq!(hash("c0mp^tər"), hash("computer"));
    }

    #[test]
    fn test_mismatch() {
        assert!(hash("reddit") != hash("eddit"));
        assert!(hash("lol") != hash("lulz"));
        assert!(hash("ijava") != hash("java"));
        assert!(hash("jesus") != hash("iesus"));
        assert!(hash("aesus") != hash("iesus"));
    }

    #[test]
    fn test_distance() {
        assert!(distance("lizzard", "wizzard") > distance("rick", "rolled"));
        assert!(distance("bannana", "panana") >= distance("apple", "abple"));
        //assert!(distance("franco", "sranco") < distance("unicode", "ASCII"));
        assert!(distance("trump", "drumpf") < distance("gangam", "style"));
        assert!(distance("right", "write").count_zeros() > distance("write", "abdominohysterotomy").count_zeros());
    }

    #[test]
    fn test_reflexivity() {
        assert_eq!(distance("a", "b"), distance("b", "a"));
        assert_eq!(distance("youtube", "facebook"), distance("facebook", "youtube"));
        assert_eq!(distance("Rust", "Go"), distance("Go", "Rust"));
        assert_eq!(distance("rick", "rolled"), distance("rolled", "rick"));
    }

    #[test]
    fn test_similar() {
        // Similar.
        assert!(similar("yay", "yuy"));
        assert!(distance("crack", "crakk").count_ones() < 10);
        assert!(similar("what", "wat"));
        assert!(similar("jesus", "jeuses"));
        assert!(similar("", ""));
        assert!(similar("jumpo", "jumbo"));
        assert!(similar("lol", "lulz"));
        assert!(similar("goth", "god"));

        // Not similar.
        assert!(!similar("youtube", "reddit"));
        assert!(!similar("yet", "vet"));
        assert!(!similar("hacker", "4chan"));
        assert!(!similar("awesome", "me"));
        assert!(!similar("prisco", "vkisco"));
        assert!(!similar("no", "go"));
        assert!(!similar("horse", "norse"));
        assert!(!similar("nice", "mice"));
    }

    #[bench]
    fn bench_dict(b: &mut Bencher) {
        use std::fs;
        use std::io::{BufRead, BufReader};

        b.iter(|| {
            let dict = fs::File::open("/usr/share/dict/american-english").unwrap();
            let mut vec = Vec::new();

            for i in BufReader::new(dict).lines() {
                vec.push(hash(&i.unwrap()));
            }

            vec
        });
    }
}
<|endoftext|>