<commit_before>#![doc(html_logo_url = "https://cdn.rawgit.com/urschrei/polylabel-rs/7a07336e85572eb5faaf0657c2383d7de5620cd8/ell.svg",
       html_root_url = "https://urschrei.github.io/polylabel-rs/")]
//! This crate provides a Rust implementation of the [Polylabel](https://github.com/mapbox/polylabel) algorithm
use std::cmp::Ordering;
use std::collections::BinaryHeap;

extern crate num_traits;
use self::num_traits::{Float, FromPrimitive, Signed};

extern crate geo;
use self::geo::{Point, Polygon};
use self::geo::algorithm::boundingbox::BoundingBox;
use self::geo::algorithm::distance::Distance;
use self::geo::algorithm::area::Area;
use self::geo::algorithm::centroid::Centroid;
use self::geo::algorithm::contains::Contains;

mod ffi;
pub use ffi::{polylabel_ffi, Array, WrapperArray, Position};

#[doc(hidden)]
#[allow(dead_code)]
pub extern "C" fn spare() {
    println!("");
}

/// A helper struct for `polylabel`, representing one of four Quadtree cells
#[derive(Debug)]
struct Qcell<T>
where
    T: Float + Signed,
{
    // Centroid coordinates
    x: T,
    y: T,
    // Half the cell size
    h: T,
    // Distance from centroid to polygon
    distance: T,
    // Maximum distance to polygon within a cell
    max_distance: T,
}

impl<T> Qcell<T>
where
    T: Float + Signed,
{
    fn new(x: T, y: T, h: T, distance: T, max_distance: T) -> Qcell<T> {
        Qcell {
            x: x,
            y: y,
            h: h,
            distance: distance,
            max_distance: max_distance,
        }
    }
}

impl<T> Ord for Qcell<T>
where
    T: Float + Signed,
{
    fn cmp(&self, other: &Qcell<T>) -> std::cmp::Ordering {
        self.max_distance.partial_cmp(&other.max_distance).unwrap()
    }
}
impl<T> PartialOrd for Qcell<T>
where
    T: Float + Signed,
{
    fn partial_cmp(&self, other: &Qcell<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl<T> Eq for Qcell<T>
where
    T: Float + Signed,
{
}
impl<T> PartialEq for Qcell<T>
where
    T: Float + Signed,
{
    fn eq(&self, other: &Qcell<T>) -> bool
    where
        T: Float,
    {
        self.max_distance == other.max_distance
    }
}

/// Signed distance from a Cell's centroid to a Polygon's outline
/// Returned value is negative if the point is outside the polygon's exterior ring
fn signed_distance<T>(x: &T, y: &T, polygon: &Polygon<T>) -> T
where
    T: Float,
{
    let point = Point::new(*x, *y);
    let inside = polygon.contains(&point);
    // Use LineString distance, because Polygon distance returns 0.0 for inside
    let distance = point.distance(&polygon.exterior);
    if inside { distance } else { -distance }
}

/// Add a new Quadtree node made up of four `Cell`s to the binary heap
fn add_quad<T>(mpq: &mut BinaryHeap<Qcell<T>>, cell: &Qcell<T>, nh: &T, polygon: &Polygon<T>)
where
    T: Float + Signed,
{
    let two = T::one() + T::one();
    // 1
    let mut new_dist = signed_distance(&(cell.x - *nh), &(cell.y - *nh), polygon);
    mpq.push(Qcell::new(
        cell.x - *nh,
        cell.y - *nh,
        *nh,
        new_dist,
        new_dist + *nh * two.sqrt(),
    ));
    // 2
    new_dist = signed_distance(&(cell.x + *nh), &(cell.y - *nh), polygon);
    mpq.push(Qcell::new(
        cell.x + *nh,
        cell.y - *nh,
        *nh,
        new_dist,
        new_dist + *nh * two.sqrt(),
    ));
    // 3
    new_dist = signed_distance(&(cell.x - *nh), &(cell.y + *nh), polygon);
    mpq.push(Qcell::new(
        cell.x - *nh,
        cell.y + *nh,
        *nh,
        new_dist,
        new_dist + *nh * two.sqrt(),
    ));
    // 4
    new_dist = signed_distance(&(cell.x + *nh), &(cell.y + *nh), polygon);
    mpq.push(Qcell::new(
        cell.x + *nh,
        cell.y + *nh,
        *nh,
        new_dist,
        new_dist + *nh * two.sqrt(),
    ));
}

/// Calculate a Polygon's ideal label position by calculating its ✨pole of inaccessibility✨
///
/// The calculation uses an [iterative grid-based algorithm](https://github.com/mapbox/polylabel#how-the-algorithm-works).
///
/// # Examples
///
/// ```
/// use polylabel::polylabel;
/// extern crate geo;
/// use self::geo::{Point, LineString, Polygon};
///
/// // An approximate `L` shape
/// let coords = vec![
///    (0.0, 0.0),
///    (4.0, 0.0),
///    (4.0, 1.0),
///    (1.0, 1.0),
///    (1.0, 4.0),
///    (0.0, 4.0),
///    (0.0, 0.0)];
///
/// let poly = Polygon::new(coords.into(), vec![]);
///
/// // Its centroid lies outside the polygon
/// assert_eq!(poly.centroid(), Point::new(1.3571428571428572, 1.3571428571428572));
///
/// let label_position = polylabel(&poly, &1.0);
/// // Optimum label position is inside the polygon
/// assert_eq!(label_position, Point::new(0.5625, 0.5625));
/// ```
///
pub fn polylabel<T>(polygon: &Polygon<T>, tolerance: &T) -> Point<T>
where
    T: Float + FromPrimitive + Signed,
{
    // special case for degenerate polygons
    if polygon.area() == T::zero() {
        // best_cell = Cell {
        //     x: polygon.exterior.0[0].x(),
        //     y: polygon.exterior.0[0].y(),
        //     h: T::zero(),
        //     distance: distance,
        //     max_distance: max_distance
        // };
        return Point::new(T::zero(), T::zero());
    }
    let two = T::one() + T::one();
    // Initial best cell values
    let centroid = polygon.centroid().unwrap();
    let bbox = polygon.bbox().unwrap();
    let width = bbox.xmax - bbox.xmin;
    let height = bbox.ymax - bbox.ymin;
    let cell_size = width.min(height);
    // Special case for degenerate polygons
    if cell_size == T::zero() {
        return Point::new(bbox.xmin, bbox.ymin);
    }
    let mut h = cell_size / two;
    let distance = signed_distance(&centroid.x(), &centroid.y(), polygon);
    let max_distance = distance + T::zero() * two.sqrt();

    let mut best_cell = Qcell {
        x: centroid.x(),
        y: centroid.y(),
        h: T::zero(),
        distance: distance,
        max_distance: max_distance,
    };

    // special case for rectangular polygons
    let bbox_cell_dist = signed_distance(
        &(bbox.xmin + width / two),
        &(bbox.ymin + height / two),
        polygon,
    );
    let bbox_cell = Qcell {
        x: bbox.xmin + width / two,
        y: bbox.ymin + height / two,
        h: T::zero(),
        distance: bbox_cell_dist,
        max_distance: bbox_cell_dist + T::zero() * two.sqrt(),
    };

    if bbox_cell.distance > best_cell.distance {
        best_cell = bbox_cell;
    }

    // Priority queue
    let mut cell_queue: BinaryHeap<Qcell<T>> = BinaryHeap::new();
    // Build an initial quadtree node, which covers the Polygon
    let mut x = bbox.xmin;
    let mut y;
    while x < bbox.xmax {
        y = bbox.ymin;
        while y < bbox.ymax {
            let latest_dist = signed_distance(&(x + h), &(y + h), polygon);
            cell_queue.push(Qcell {
                x: x + h,
                y: y + h,
                h: h,
                distance: latest_dist,
                max_distance: latest_dist + h * two.sqrt(),
            });
            y = y + cell_size;
        }
        x = x + cell_size;
    }
    // Now try to find better solutions
    while !cell_queue.is_empty() {
        let cell = cell_queue.pop().unwrap();
        // Update the best cell if we find a cell with greater distance
        if cell.distance > best_cell.distance {
            best_cell.x = cell.x;
            best_cell.y = cell.y;
            best_cell.h = cell.h;
            best_cell.distance = cell.distance;
            best_cell.max_distance = cell.max_distance;
        }
        // Bail out of this iteration if we can't find a better solution
        if cell.max_distance - best_cell.distance <= *tolerance {
            continue;
        }
        // Otherwise, add a new quadtree node and start again
        h = cell.h / two;
        add_quad(&mut cell_queue, &cell, &h, polygon);
    }
    // We've exhausted the queue, so return the best solution we've found
    Point::new(best_cell.x, best_cell.y)
}

#[cfg(test)]
mod tests {
    use std::collections::BinaryHeap;
    use super::{polylabel, Qcell};
    use geo::{Point, Polygon};
    use geo::contains::Contains;
    #[test]
    // polygons are those used in Shapely's tests
    fn test_polylabel() {
        let coords = include!("poly1.rs");
        let poly = Polygon::new(coords.into(), vec![]);
        let res = polylabel(&poly, &10.000);
        assert_eq!(res, Point::new(59.35615556364569, 121.83919629746435));
    }
    #[test]
    // does a concave polygon contain the calculated point?
    // relevant because the centroid lies outside the polygon in this case
    fn test_concave() {
        let coords = include!("poly2.rs");
        let poly = Polygon::new(coords.into(), vec![]);
        let res = polylabel(&poly, &1.0);
        assert!(poly.contains(&res));
    }
    #[test]
    fn polygon_l_test() {
        // an L shape
        let coords = vec![
            (0.0, 0.0),
            (4.0, 0.0),
            (4.0, 1.0),
            (1.0, 1.0),
            (1.0, 4.0),
            (0.0, 4.0),
            (0.0, 0.0),
        ];
        let poly = Polygon::new(coords.into(), vec![]);
        let res = polylabel(&poly, &0.10);
        assert_eq!(res, Point::new(0.5625, 0.5625));
    }
    #[test]
    fn degenerate_polygon_test() {
        let a_coords = vec![(0.0, 0.0), (1.0, 0.0), (2.0, 0.0), (0.0, 0.0)];
        let a_poly = Polygon::new(a_coords.into(), vec![]);
        let a_res = polylabel(&a_poly, &1.0);
        assert_eq!(a_res, Point::new(0.0, 0.0));
    }
    #[test]
    fn degenerate_polygon_test_2() {
        let b_coords = vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)];
        let b_poly = Polygon::new(b_coords.into(), vec![]);
        let b_res = polylabel(&b_poly, &1.0);
        assert_eq!(b_res, Point::new(0.0, 0.0));
    }
    #[test]
    // Is our priority queue behaving as it should?
    fn test_queue() {
        let a = Qcell {
            x: 1.0,
            y: 2.0,
            h: 3.0,
            distance: 4.0,
            max_distance: 8.0,
        };
        let b = Qcell {
            x: 1.0,
            y: 2.0,
            h: 3.0,
            distance: 4.0,
            max_distance: 7.0,
        };
        let c = Qcell {
            x: 1.0,
            y: 2.0,
            h: 3.0,
            distance: 4.0,
            max_distance: 9.0,
        };
        let mut v = vec![];
        v.push(a);
        v.push(b);
        v.push(c);
        let mut q = BinaryHeap::from(v);
        assert_eq!(q.pop().unwrap().max_distance, 9.0);
        assert_eq!(q.pop().unwrap().max_distance, 8.0);
        assert_eq!(q.pop().unwrap().max_distance, 7.0);
    }
}
<commit_msg>Represent Qcell centroid using a Point<commit_after>#![doc(html_logo_url = "https://cdn.rawgit.com/urschrei/polylabel-rs/7a07336e85572eb5faaf0657c2383d7de5620cd8/ell.svg",
       html_root_url = "https://urschrei.github.io/polylabel-rs/")]
//! This crate provides a Rust implementation of the [Polylabel](https://github.com/mapbox/polylabel) algorithm
use std::cmp::Ordering;
use std::collections::BinaryHeap;

extern crate num_traits;
use self::num_traits::{Float, FromPrimitive, Signed};

extern crate geo;
use self::geo::{Point, Polygon};
use self::geo::algorithm::boundingbox::BoundingBox;
use self::geo::algorithm::distance::Distance;
use self::geo::algorithm::area::Area;
use self::geo::algorithm::centroid::Centroid;
use self::geo::algorithm::contains::Contains;

mod ffi;
pub use ffi::{polylabel_ffi, Array, WrapperArray, Position};

#[doc(hidden)]
#[allow(dead_code)]
pub extern "C" fn spare() {
    println!("");
}

/// Represention of a Quadtree cell
/// x and y represent the
#[derive(Debug)]
struct Qcell<T>
where
    T: Float + Signed,
{
    centroid: Point<T>,
    // Half the cell size
    h: T,
    // Distance from centroid to polygon
    distance: T,
    // Maximum distance to polygon within a cell
    max_distance: T,
}

impl<T> Qcell<T>
where
    T: Float + Signed,
{
    fn new(x: T, y: T, h: T, distance: T, max_distance: T) -> Qcell<T> {
        Qcell {
            centroid: Point::new(x, y),
            h: h,
            distance: distance,
            max_distance: max_distance,
        }
    }
}

impl<T> Ord for Qcell<T>
where
    T: Float + Signed,
{
    fn cmp(&self, other: &Qcell<T>) -> std::cmp::Ordering {
        self.max_distance.partial_cmp(&other.max_distance).unwrap()
    }
}
impl<T> PartialOrd for Qcell<T>
where
    T: Float + Signed,
{
    fn partial_cmp(&self, other: &Qcell<T>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl<T> Eq for Qcell<T>
where
    T: Float + Signed,
{
}
impl<T> PartialEq for Qcell<T>
where
    T: Float + Signed,
{
    fn eq(&self, other: &Qcell<T>) -> bool
    where
        T: Float,
    {
        self.max_distance == other.max_distance
    }
}

/// Signed distance from a Qcell's centroid to a Polygon's outline
/// Returned value is negative if the point is outside the polygon's exterior ring
fn signed_distance<T>(x: &T, y: &T, polygon: &Polygon<T>) -> T
where
    T: Float,
{
    let point = Point::new(*x, *y);
    let inside = polygon.contains(&point);
    // Use LineString distance, because Polygon distance returns 0.0 for inside
    let distance = point.distance(&polygon.exterior);
    if inside { distance } else { -distance }
}

/// Add a new Quadtree node made up of four `Qcell`s to the binary heap
fn add_quad<T>(mpq: &mut BinaryHeap<Qcell<T>>, cell: &Qcell<T>, nh: &T, polygon: &Polygon<T>)
where
    T: Float + Signed,
{
    let two = T::one() + T::one();
    // 1
    let mut new_dist = signed_distance(&(cell.centroid.x() - *nh), &(cell.centroid.y() - *nh), polygon);
    mpq.push(Qcell::new(
        cell.centroid.x() - *nh,
        cell.centroid.y() - *nh,
        *nh,
        new_dist,
        new_dist + *nh * two.sqrt(),
    ));
    // 2
    new_dist = signed_distance(&(cell.centroid.x() + *nh), &(cell.centroid.y() - *nh), polygon);
    mpq.push(Qcell::new(
        cell.centroid.x() + *nh,
        cell.centroid.y() - *nh,
        *nh,
        new_dist,
        new_dist + *nh * two.sqrt(),
    ));
    // 3
    new_dist = signed_distance(&(cell.centroid.x() - *nh), &(cell.centroid.y() + *nh), polygon);
    mpq.push(Qcell::new(
        cell.centroid.x() - *nh,
        cell.centroid.y() + *nh,
        *nh,
        new_dist,
        new_dist + *nh * two.sqrt(),
    ));
    // 4
    new_dist = signed_distance(&(cell.centroid.x() + *nh), &(cell.centroid.y() + *nh), polygon);
    mpq.push(Qcell::new(
        cell.centroid.x() + *nh,
        cell.centroid.y() + *nh,
        *nh,
        new_dist,
        new_dist + *nh * two.sqrt(),
    ));
}

/// Calculate a Polygon's ideal label position by calculating its ✨pole of inaccessibility✨
///
/// The calculation uses an [iterative grid-based algorithm](https://github.com/mapbox/polylabel#how-the-algorithm-works).
///
/// # Examples
///
/// ```
/// use polylabel::polylabel;
/// extern crate geo;
/// use self::geo::{Point, LineString, Polygon};
///
/// // An approximate `L` shape
/// let coords = vec![
///    (0.0, 0.0),
///    (4.0, 0.0),
///    (4.0, 1.0),
///    (1.0, 1.0),
///    (1.0, 4.0),
///    (0.0, 4.0),
///    (0.0, 0.0)];
///
/// let poly = Polygon::new(coords.into(), vec![]);
///
/// // Its centroid lies outside the polygon
/// assert_eq!(poly.centroid(), Point::new(1.3571428571428572, 1.3571428571428572));
///
/// let label_position = polylabel(&poly, &1.0);
/// // Optimum label position is inside the polygon
/// assert_eq!(label_position, Point::new(0.5625, 0.5625));
/// ```
///
pub fn polylabel<T>(polygon: &Polygon<T>, tolerance: &T) -> Point<T>
where
    T: Float + FromPrimitive + Signed,
{
    // special case for degenerate polygons
    if polygon.area() == T::zero() {
        // best_cell = Qcell {
        //     centroid = Point::new(polygon.exterior.0[0].x(), polygon.exterior.0[0].y())
        //     h: T::zero(),
        //     distance: distance,
        //     max_distance: max_distance
        // };
        return Point::new(T::zero(), T::zero());
    }
    let two = T::one() + T::one();
    // Initial best cell values
    let centroid = polygon.centroid().unwrap();
    let bbox = polygon.bbox().unwrap();
    let width = bbox.xmax - bbox.xmin;
    let height = bbox.ymax - bbox.ymin;
    let cell_size = width.min(height);
    // Special case for degenerate polygons
    if cell_size == T::zero() {
        return Point::new(bbox.xmin, bbox.ymin);
    }
    let mut h = cell_size / two;
    let distance = signed_distance(&centroid.x(), &centroid.y(), polygon);
    let max_distance = distance + T::zero() * two.sqrt();

    let mut best_cell = Qcell {
        centroid: Point::new(centroid.x(), centroid.y()),
        h: T::zero(),
        distance: distance,
        max_distance: max_distance,
    };

    // special case for rectangular polygons
    let bbox_cell_dist = signed_distance(
        &(bbox.xmin + width / two),
        &(bbox.ymin + height / two),
        polygon,
    );
    let bbox_cell = Qcell {
        centroid: Point::new(bbox.xmin + width / two, bbox.ymin + height / two),
        h: T::zero(),
        distance: bbox_cell_dist,
        max_distance: bbox_cell_dist + T::zero() * two.sqrt(),
    };

    if bbox_cell.distance > best_cell.distance {
        best_cell = bbox_cell;
    }

    // Priority queue
    let mut cell_queue: BinaryHeap<Qcell<T>> = BinaryHeap::new();
    // Build an initial quadtree node, which covers the Polygon
    let mut x = bbox.xmin;
    let mut y;
    while x < bbox.xmax {
        y = bbox.ymin;
        while y < bbox.ymax {
            let latest_dist = signed_distance(&(x + h), &(y + h), polygon);
            cell_queue.push(Qcell {
                centroid: Point::new(x + h, y + h),
                h: h,
                distance: latest_dist,
                max_distance: latest_dist + h * two.sqrt(),
            });
            y = y + cell_size;
        }
        x = x + cell_size;
    }
    // Now try to find better solutions
    while !cell_queue.is_empty() {
        let cell = cell_queue.pop().unwrap();
        // Update the best cell if we find a cell with greater distance
        if cell.distance > best_cell.distance {
            best_cell.centroid = Point::new(cell.centroid.x(), cell.centroid.y());
            best_cell.h = cell.h;
            best_cell.distance = cell.distance;
            best_cell.max_distance = cell.max_distance;
        }
        // Bail out of this iteration if we can't find a better solution
        if cell.max_distance - best_cell.distance <= *tolerance {
            continue;
        }
        // Otherwise, add a new quadtree node and start again
        h = cell.h / two;
        add_quad(&mut cell_queue, &cell, &h, polygon);
    }
    // We've exhausted the queue, so return the best solution we've found
    Point::new(best_cell.centroid.x(), best_cell.centroid.y())
}

#[cfg(test)]
mod tests {
    use std::collections::BinaryHeap;
    use super::{polylabel, Qcell};
    use geo::{Point, Polygon};
    use geo::contains::Contains;
    #[test]
    // polygons are those used in Shapely's tests
    fn test_polylabel() {
        let coords = include!("poly1.rs");
        let poly = Polygon::new(coords.into(), vec![]);
        let res = polylabel(&poly, &10.000);
        assert_eq!(res, Point::new(59.35615556364569, 121.83919629746435));
    }
    #[test]
    // does a concave polygon contain the calculated point?
    // relevant because the centroid lies outside the polygon in this case
    fn test_concave() {
        let coords = include!("poly2.rs");
        let poly = Polygon::new(coords.into(), vec![]);
        let res = polylabel(&poly, &1.0);
        assert!(poly.contains(&res));
    }
    #[test]
    fn polygon_l_test() {
        // an L shape
        let coords = vec![
            (0.0, 0.0),
            (4.0, 0.0),
            (4.0, 1.0),
            (1.0, 1.0),
            (1.0, 4.0),
            (0.0, 4.0),
            (0.0, 0.0),
        ];
        let poly = Polygon::new(coords.into(), vec![]);
        let res = polylabel(&poly, &0.10);
        assert_eq!(res, Point::new(0.5625, 0.5625));
    }
    #[test]
    fn degenerate_polygon_test() {
        let a_coords = vec![(0.0, 0.0), (1.0, 0.0), (2.0, 0.0), (0.0, 0.0)];
        let a_poly = Polygon::new(a_coords.into(), vec![]);
        let a_res = polylabel(&a_poly, &1.0);
        assert_eq!(a_res, Point::new(0.0, 0.0));
    }
    #[test]
    fn degenerate_polygon_test_2() {
        let b_coords = vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)];
        let b_poly = Polygon::new(b_coords.into(), vec![]);
        let b_res = polylabel(&b_poly, &1.0);
        assert_eq!(b_res, Point::new(0.0, 0.0));
    }
    #[test]
    // Is our priority queue behaving as it should?
    fn test_queue() {
        let a = Qcell {
            centroid: Point::new(1.0, 2.0),
            h: 3.0,
            distance: 4.0,
            max_distance: 8.0,
        };
        let b = Qcell {
            centroid: Point::new(1.0, 2.0),
            h: 3.0,
            distance: 4.0,
            max_distance: 7.0,
        };
        let c = Qcell {
            centroid: Point::new(1.0, 2.0),
            h: 3.0,
            distance: 4.0,
            max_distance: 9.0,
        };
        let mut v = vec![];
        v.push(a);
        v.push(b);
        v.push(c);
        let mut q = BinaryHeap::from(v);
        assert_eq!(q.pop().unwrap().max_distance, 9.0);
        assert_eq!(q.pop().unwrap().max_distance, 8.0);
        assert_eq!(q.pop().unwrap().max_distance, 7.0);
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate chrono;
extern crate uuid;

use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Receiver, Sender, SendError};
use std::thread::{Builder, JoinHandle};

use rustc_serialize::json::{Json, ToJson};
use uuid::Uuid;

pub struct Actor {
    join_handle: JoinHandle<()>,
    mailbox: Sender<Json>,
    name: String,
    uuid: Uuid,
}

impl Actor {
    fn new(
        join_handle: JoinHandle<()>,
        mailbox: Sender<Json>,
        name: String,
        uuid: Uuid,
    ) -> Actor {
        Actor {
            join_handle: join_handle,
            mailbox: mailbox,
            name: name,
            uuid: uuid,
        }
    }
}

pub struct Supervisor {
    actors: HashMap<Uuid, Actor>,
    name: String,
}

impl Supervisor {
    fn new(name: &str) -> Supervisor {
        Supervisor {
            actors: HashMap::new(),
            name: name.to_string(),
        }
    }

    fn join(&mut self, pid : Uuid) -> Result<(), String> {
        match self.actors.remove(&pid) {
            Some(actor) => {
                match actor.join_handle.join() {
                    Ok(_) => Ok(()),
                    Err(e) => Err("you really messed up".to_string()),
                }
            },
            None => Err(format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    fn send_message(&self, pid: Uuid, message: Json) -> Result<(), String> {
        match self.actors.get(&pid) {
            Some(actor) => {
                match actor.mailbox.send(message) {
                    Ok(_) => Ok(()),
                    Err(e) => { Err(e.to_string()) },
                }
            },
            None => Err(format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    fn spawn<F>(&mut self, actor_name: &str, body: F) -> Result<Uuid, &str>
        where F : 'static + Send + Fn(Receiver<Json>) -> () {
        let pid = Uuid::new_v4();
        let (mailbox_sender, mailbox_receiver) = channel();
        let arc_body = Arc::new(Mutex::new(body));

        let actor_handle_result = Builder::new().name(pid.to_string()).spawn(move || {
            arc_body.lock().unwrap()(mailbox_receiver);
        });

        match actor_handle_result {
            Ok(actor_handle) => {
                self.actors.insert(pid, Actor::new(
                    actor_handle,
                    mailbox_sender,
                    actor_name.to_string(),
                    pid,
                ))
            }
            Err(e) => return Err("boom"), // sigh
        };

        return Ok(pid);
    }
}

#[cfg(test)]
mod tests {
    use std::fs::{remove_file, File};
    use std::io::prelude::*;
    use std::sync::mpsc::{channel, Receiver, Sender};
    use std::thread;
    use chrono::*;
    use rustc_serialize::json::{Json, ToJson};
    use uuid::Uuid;
    use super::*;

    // spawn tests
    #[test]
    fn the_body_actor_callback_is_executed() {
        let mut supervisor = Supervisor::new("folks");
        let json_msg = "{\"hi\": \"friend\"}".to_json();
        let json_clone = json_msg.clone();
        let pid_bob: Uuid = supervisor.spawn(
            "Bob",
            |receiver| {
                let mut message_output_file = File::create("/tmp/bob-test.json").unwrap();
                message_output_file.write_all(receiver.recv().unwrap().to_string().as_bytes()).unwrap();
                ()
            }
        ).unwrap();

        supervisor.send_message(pid_bob, json_msg).unwrap();

        thread::sleep_ms(1001);
        let mut message_output_file = File::open("/tmp/bob-test.json").unwrap();
        let mut message_output = String::new();
        message_output_file.read_to_string(&mut message_output).unwrap();
        remove_file("/tmp/bob-test.json").unwrap();

        let actual_json = Json::from_str(&message_output).unwrap();
        assert_eq!(json_clone, actual_json);
    }

    // send_message tests
    #[test]
    fn error_is_returned_if_message_sent_for_pid_that_does_not_exist() {
        let mut supervisor = Supervisor::new("folks");
        let pid = Uuid::new_v4();

        let send_result = supervisor.send_message(pid, "{}".to_json());

        match send_result {
            Ok(_) => panic!("Message sent to non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    #[test]
    fn pid_can_be_used_to_send_message() {
        let mut supervisor = Supervisor::new("folks");
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { r.recv().unwrap(); () }
        ).unwrap();

        supervisor.send_message(pid, "{}".to_json()).unwrap();
    }

    // join tests
    #[test]
    fn pid_can_be_used_to_join_actor() {
        let mut supervisor = Supervisor::new("folks");
        let start_time = UTC::now();
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { thread::sleep_ms(1000); () }
        ).unwrap();
        assert!((start_time + Duration::milliseconds(1000)) > UTC::now());

        supervisor.join(pid).unwrap();

        assert!((start_time + Duration::milliseconds(1000)) < UTC::now());
    }

    #[test]
    fn joining_actor_makes_it_unreachable() {
        let mut supervisor = Supervisor::new("folks");
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { () }
        ).unwrap();
        supervisor.join(pid).unwrap();

        let send_result = supervisor.send_message(pid, "{}".to_json());

        match send_result {
            Ok(_) => panic!("Message sent to non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    #[test]
    fn error_is_returned_if_joining_actor_that_does_not_exist() {
        let mut supervisor = Supervisor::new("folks");
        let pid = Uuid::new_v4();

        let join_result = supervisor.join(pid);

        match join_result {
            Ok(_) => panic!("Actor joined for non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }
}
<commit_msg>Use internal mutability for actor pool in Supervisor<commit_after>extern crate rustc_serialize;
extern crate chrono;
extern crate uuid;

use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::mpsc::{channel, Receiver, Sender, SendError};
use std::thread::{Builder, JoinHandle};

use rustc_serialize::json::{Json, ToJson};
use uuid::Uuid;

pub struct Actor {
    join_handle: JoinHandle<()>,
    mailbox: Sender<Json>,
    name: String,
    uuid: Uuid,
}

impl Actor {
    fn new(
        join_handle: JoinHandle<()>,
        mailbox: Sender<Json>,
        name: String,
        uuid: Uuid,
    ) -> Actor {
        Actor {
            join_handle: join_handle,
            mailbox: mailbox,
            name: name,
            uuid: uuid,
        }
    }
}

pub struct Supervisor {
    actors: RwLock<HashMap<Uuid, Actor>>,
    name: String,
}

impl Supervisor {
    fn new(name: &str) -> Supervisor {
        Supervisor {
            actors: RwLock::new(HashMap::new()),
            name: name.to_string(),
        }
    }

    fn join(&self, pid : Uuid) -> Result<(), String> {
        match self.actors.write().unwrap().remove(&pid) {
            Some(actor) => {
                match actor.join_handle.join() {
                    Ok(_) => Ok(()),
                    Err(e) => Err("you really messed up".to_string()),
                }
            },
            None => Err(format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    fn send_message(&self, pid: Uuid, message: Json) -> Result<(), String> {
        match self.actors.read().unwrap().get(&pid) {
            Some(actor) => {
                match actor.mailbox.send(message) {
                    Ok(_) => Ok(()),
                    Err(e) => { Err(e.to_string()) },
                }
            },
            None => Err(format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    fn spawn<F>(&self, actor_name: &str, body: F) -> Result<Uuid, &str>
        where F : 'static + Send + Fn(Receiver<Json>) -> () {
        let pid = Uuid::new_v4();
        let (mailbox_sender, mailbox_receiver) = channel();
        let arc_body = Arc::new(Mutex::new(body));

        match self.actors.write() {
            Ok(mut actors) => {
                let actor_handle_result = Builder::new().name(pid.to_string()).spawn(move || {
                    arc_body.lock().unwrap()(mailbox_receiver);
                });

                match actor_handle_result {
                    Ok(actor_handle) => {
                        actors.insert(pid, Actor::new(
                            actor_handle,
                            mailbox_sender,
                            actor_name.to_string(),
                            pid,
                        ));

                        Ok(pid)
                    },
                    Err(e) => Err("boom"), // sigh
                }
            },
            Err(e) => Err("boom boom") // sigh
        }
    }
}

#[cfg(test)]
mod tests {
    use std::fs::{remove_file, File};
    use std::io::prelude::*;
    use std::sync::mpsc::{channel, Receiver, Sender};
    use std::thread;
    use chrono::*;
    use rustc_serialize::json::{Json, ToJson};
    use uuid::Uuid;
    use super::*;

    // spawn tests
    #[test]
    fn the_body_actor_callback_is_executed() {
        let supervisor = Supervisor::new("folks");
        let json_msg = "{\"hi\": \"friend\"}".to_json();
        let json_clone = json_msg.clone();
        let pid_bob: Uuid = supervisor.spawn(
            "Bob",
            |receiver| {
                let mut message_output_file = File::create("/tmp/bob-test.json").unwrap();
                message_output_file.write_all(receiver.recv().unwrap().to_string().as_bytes()).unwrap();
                ()
            }
        ).unwrap();

        supervisor.send_message(pid_bob, json_msg).unwrap();

        thread::sleep_ms(1001);
        let mut message_output_file = File::open("/tmp/bob-test.json").unwrap();
        let mut message_output = String::new();
        message_output_file.read_to_string(&mut message_output).unwrap();
        remove_file("/tmp/bob-test.json").unwrap();

        let actual_json = Json::from_str(&message_output).unwrap();
        assert_eq!(json_clone, actual_json);
    }

    // send_message tests
    #[test]
    fn error_is_returned_if_message_sent_for_pid_that_does_not_exist() {
        let supervisor = Supervisor::new("folks");
        let pid = Uuid::new_v4();

        let send_result = supervisor.send_message(pid, "{}".to_json());

        match send_result {
            Ok(_) => panic!("Message sent to non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    #[test]
    fn pid_can_be_used_to_send_message() {
        let supervisor = Supervisor::new("folks");
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { r.recv().unwrap(); () }
        ).unwrap();

        supervisor.send_message(pid, "{}".to_json()).unwrap();
    }

    // join tests
    #[test]
    fn pid_can_be_used_to_join_actor() {
        let supervisor = Supervisor::new("folks");
        let start_time = UTC::now();
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { thread::sleep_ms(1000); () }
        ).unwrap();
        assert!((start_time + Duration::milliseconds(1000)) > UTC::now());

        supervisor.join(pid).unwrap();

        assert!((start_time + Duration::milliseconds(1000)) < UTC::now());
    }

    #[test]
    fn joining_actor_makes_it_unreachable() {
        let supervisor = Supervisor::new("folks");
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { () }
        ).unwrap();
        supervisor.join(pid).unwrap();

        let send_result = supervisor.send_message(pid, "{}".to_json());

        match send_result {
            Ok(_) => panic!("Message sent to non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    #[test]
    fn error_is_returned_if_joining_actor_that_does_not_exist() {
        let supervisor = Supervisor::new("folks");
        let pid = Uuid::new_v4();

        let join_result = supervisor.join(pid);

        match join_result {
            Ok(_) => panic!("Actor joined for non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }
}
<|endoftext|>


<commit_before>
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy)]
pub struct f16(u16);<commit_msg>Basic floating point conversion<commit_after>
use std::mem;

#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, Default)]
pub struct f16(u16);

// TODO Endianness *should* be fine -- except in archs the differ on int/fp endianness

impl f16 {
    pub fn from_bits(bits: u16) -> f16 {
        f16(bits)
    }

    pub fn from_f32(value: f32) -> f16 {
        // Convert to raw bytes
        let x: u32 = unsafe { mem::transmute(value) };

        // Check for signed zero
        if x & 0x7FFFFFFFu32 == 0 {
            return f16::from_bits((x >> 16) as u16);
        }

        // Extract IEEE754 components
        let sign = x & 0x80000000u32;
        let exp  = x & 0x7F800000u32;
        let man  = x & 0x007FFFFFu32;

        // Denormals will underflow, so return signed zero
        if exp == 0 {
            return f16::from_bits(x as u16);
        }

        // Check for all exponent bits being set, which is Infinity or NaN
        if exp == 0x7F800000u32 {
            // A mantissa of zero is a signed Infinity
            if man == 0 {
                return f16::from_bits(((x >> 16) | 0x7C00u32) as u16);
            }
            // Otherwise, this is NaN
            return f16::from_bits(0xFE00u16);
        }

        // The number is normalized, start assembling half precision version
        let half_sign = sign >> 16;
        // Unbias the exponent, then bias for half precision
        let unbiased_exp = (exp >> 23) - 127;
        let half_exp = unbiased_exp + 15;

        // Check for exponent overflow, return +infinity
        if half_exp >= 0x1F {
            return f16::from_bits((half_sign | 0x7C00u32) as u16);
        }

        // Check for underflow
        if half_sign <= 0 {
            // Check mantissa for what we can do
            if 14 - half_exp > 24 {
                // No rounding possibility, so this is a full underflow, return signed zero
                return f16::from_bits(half_sign as u16);
            }
            // Don't forget about hidden leading mantissa bit when assembling mantissa
            let man = man | 0x00800000u32;
            let mut half_man = man >> (14 - half_exp);
            // Check for rounding
            if (man >> (13 - half_exp)) & 0x1u32 != 0 {
                half_man += 1;
            }
            // No exponent for denormals
            return f16::from_bits((half_sign | half_man) as u16);
        }

        // Rebias the exponent
        let half_exp = half_exp << 10;
        let half_man = man >> 13;
        // Check for rounding
        if man & 0x00001000u32 != 0 {
            // Round it
            f16::from_bits(((half_sign | half_exp | half_man) + 1) as u16)
        } else {
            f16::from_bits((half_sign | half_exp | half_man) as u16)
        }
    }

    pub fn from_f64(value: f64) -> f16 {
        // Convert to raw bytes, truncating the last 32-bits of mantissa; that precision will always
        // be lost on half-precision.
        let val: u64 = unsafe { mem::transmute(value) };
        let x = (val >> 32) as u32;

        // Check for signed zero
        if x & 0x7FFFFFFFu32 == 0 {
            return f16::from_bits((x >> 16) as u16);
        }

        // Extract IEEE754 components
        let sign = x & 0x80000000u32;
        let exp  = x & 0x7FF00000u32;
        let man  = x & 0x000FFFFFu32;

        // Denormals will underflow, so return signed zero
        if exp == 0 {
            return f16::from_bits(x as u16);
        }

        // Check for all exponent bits being set, which is Infinity or NaN
        if exp == 0x7FF00000u32 {
            // A mantissa of zero is a signed Infinity
            if man == 0 {
                return f16::from_bits(((x >> 16) | 0x7C00u32) as u16);
            }
            // Otherwise, this is NaN
            return f16::from_bits(0xFE00u16);
        }

        // The number is normalized, start assembling half precision version
        let half_sign = sign >> 16;
        // Unbias the exponent, then bias for half precision
        let unbiased_exp = (exp >> 20) - 1023;
        let half_exp = unbiased_exp + 15;

        // Check for exponent overflow, return +infinity
        if half_exp >= 0x1F {
            return f16::from_bits((half_sign | 0x7C00u32) as u16);
        }

        // Check for underflow
        if half_sign <= 0 {
            // Check mantissa for what we can do
            if 10 - half_exp > 21 {
                // No rounding possibility, so this is a full underflow, return signed zero
                return f16::from_bits(half_sign as u16);
            }
            // Don't forget about hidden leading mantissa bit when assembling mantissa
            let man = man | 0x00100000u32;
            let mut half_man = man >> (11 - half_exp);
            // Check for rounding
            if (man >> (10 - half_exp)) & 0x1u32 != 0 {
                half_man += 1;
            }
            // No exponent for denormals
            return f16::from_bits((half_sign | half_man) as u16);
        }

        // Rebias the exponent
        let half_exp = half_exp << 10;
        let half_man = man >> 10;
        // Check for rounding
        if man & 0x00000200u32 != 0 {
            // Round it
            f16::from_bits(((half_sign | half_exp | half_man) + 1) as u16)
        } else {
            f16::from_bits((half_sign | half_exp | half_man) as u16)
        }
    }

    pub fn as_bits(&self) -> u16 {
        self.0
    }

    pub fn to_f32(&self) -> f32 {
        // Check for signed zero
        if self.0 & 0x7FFFu16 == 0 {
            return unsafe { mem::transmute((self.0 as u32) << 16) };
        }

        let half_sign = (self.0 & 0x8000u16) as u32;
        let half_exp  = (self.0 & 0x7C00u16) as u32;
        let half_man  = (self.0 & 0x03FFu16) as u32;

        // Check for an infinity or NaN when all exponent bits set
        if half_exp == 0x7C00u32 {
            // Check for signed infinity if mantissa is zero
            if half_man == 0 {
                return unsafe { mem::transmute((half_sign << 16) | 0x7F800000u32) };
            } else {
                // NaN, only 1st mantissa bit is set
                return unsafe { mem::transmute(0xFFC00000u32) };
            }
        }

        // Calculate single-precision components with adjusted exponent
        let sign = half_sign << 16;
        // Unbias exponent
        let unbiased_exp = ((half_exp as i32) >> 10) - 15;
        let man = (half_man & 0x03FFu32) << 13;

        // Check for denormals, which will be normalized by adjusting exponent
        if half_exp == 0 {
            // Calculate how much to adjust the exponent by
            let e = {
                let mut e_adj = 0;
                let mut hm_adj = half_man << 1;
                while hm_adj & 0x0400u32 == 0 {
                    e_adj += 1;
                    hm_adj <<= 1;
                }
                e_adj
            };

            // Rebias and adjust exponent
            let exp = ((unbiased_exp + 127 - e) << 23) as u32;
            return unsafe { mem::transmute(sign | exp | man) };
        }

        // Rebias exponent for a normalized normal
        let exp = ((unbiased_exp + 127) << 23) as u32;
        unsafe { mem::transmute(sign | exp | man) }
    }

    pub fn to_f64(&self) -> f64 {
        // Check for signed zero
        if self.0 & 0x7FFFu16 == 0 {
            return unsafe { mem::transmute((self.0 as u64) << 48) };
        }

        let half_sign = (self.0 & 0x8000u16) as u64;
        let half_exp  = (self.0 & 0x7C00u16) as u64;
        let half_man  = (self.0 & 0x03FFu16) as u64;

        // Check for an infinity or NaN when all exponent bits set
        if half_exp == 0x7C00u64 {
            // Check for signed infinity if mantissa is zero
            if half_man == 0 {
                return unsafe { mem::transmute((half_sign << 48) | 0x7FF0000000000000u64) };
            } else {
                // NaN, only 1st mantissa bit is set
                return unsafe { mem::transmute(0xFFF8000000000000u64) };
            }
        }

        // Calculate double-precision components with adjusted exponent
        let sign = half_sign << 48;
        // Unbias exponent
        let unbiased_exp = ((half_exp as i64) >> 10) - 15;
        let man = (half_man & 0x03FFu64) << 42;

        // Check for denormals, which will be normalized by adjusting exponent
        if half_exp == 0 {
            // Calculate how much to adjust the exponent by
            let e = {
                let mut e_adj = 0;
                let mut hm_adj = half_man << 1;
                while hm_adj & 0x0400u64 == 0 {
                    e_adj += 1;
                    hm_adj <<= 1;
                }
                e_adj
            };

            // Rebias and adjust exponent
            let exp = ((unbiased_exp + 1023 - e) << 52) as u64;
            return unsafe { mem::transmute(sign | exp | man) };
        }

        // Rebias exponent for a normalized normal
        let exp = ((unbiased_exp + 1023) << 52) as u64;
        unsafe { mem::transmute(sign | exp | man) }
    }
}

//
impl From<f16> for f32 {
    fn from(x: f16) -> f32 {
        x.to_f32()
    }
}

impl From<f16> for f64 {
    fn from(x: f16) -> f64 {
        x.to_f64()
    }
}<|endoftext|>


<commit_before>extern crate curl;

use std::str;
use curl::http;

mod util;

pub struct Firebase {
    base_uri: String,
}

impl Firebase {
    pub fn new(base_uri: &str) -> Self {
        Firebase {
            base_uri: base_uri.to_string(),
        }
    }

    pub fn authenticated(base_uri: &str, auth_token: &str) -> Self {
        let uri = util::trim_right(base_uri, "/");
        Firebase {
            base_uri: format!("{}?auth={}", uri, auth_token),
        }
    }

    pub fn at(&self, path: &str) -> Self {
        let mut components = self.base_uri.split('?');

        let base = components.next().unwrap();
        let base = util::trim_right(base, ".json");
        let path = util::trim_right(path, "/");
        let path = util::add_right(path, ".json");
        let url  = util::join(base, &path, "/");

        let url = if let Some(args) = components.next() {
            url + "?" + args
        } else {
            url
        };

        Firebase {
            base_uri: url,
        }
    }

    pub fn get(&self) -> Response {
        self.request(Method::GET, None, None)
    }

    fn get_params(&self, params: String) -> Response {
        self.request(Method::GET, None, Some(params))
    }

    pub fn set(&self, data: &str) -> Response {
        self.request(Method::PUT, Some(data), None)
    }

    pub fn push(&self, data: &str) -> Response {
        self.request(Method::POST, Some(data), None)
    }

    pub fn update(&self, data: &str) -> Response {
        self.request(Method::PATCH, Some(data), None)
    }

    pub fn delete(&self) -> Response {
        self.request(Method::DELETE, None, None)
    }

    fn request(&self, method: Method, data: Option<&str>, params: Option<String>) -> Response {
        let url = if let Some(args) = params {
            if self.base_uri.find("?").is_some() {
                format!("{}&{}", &self.base_uri, args)
            } else {
                format!("{}?{}", &self.base_uri, args)
            }
        } else {
            // TODO: FIX SO THIS DOESN'T HAPPEN
            self.base_uri.clone()
        };

        let url: &str = &url;
        let mut handler = http::handle();

        let req = match method {
            Method::GET     => handler.get(url),
            Method::POST    => handler.post(url, data.unwrap()),
            Method::PUT     => handler.put(url, data.unwrap()),
            Method::PATCH   => handler.patch(url, data.unwrap()),
            Method::DELETE  => handler.delete(url)
        };
        let res = req.exec().unwrap();

        let body = match str::from_utf8(res.get_body()) {
            Ok(b) => b,
            Err(_) => "Unable to parse"
        };

        Response {
            body: body.to_string(),
            code: res.get_code(),
        }
    }

    pub fn get_url(&self) -> &str {
        return &self.base_uri;
    }

    pub fn orderBy(&self, key: &str) -> ParamsRequest {
        self.params_request(orderByStr(key))
    }

    pub fn limitToFirst(&self, count: u32) -> ParamsRequest {
        self.params_request(limitToFirstStr(count))
    }

    pub fn limitToLast(&self, count: u32) -> ParamsRequest {
        self.params_request(limitToLastStr(count))
    }

    pub fn startAt(&self, index: u32) -> ParamsRequest {
        self.params_request(startAtStr(index))
    }

    pub fn endAt(&self, index: u32) -> ParamsRequest {
        self.params_request(endAtStr(index))
    }

    pub fn equalTo(&self, value: u32) -> ParamsRequest {
        self.params_request(equalToStr(value))
    }

    pub fn shallow(&self, flag: bool) -> ParamsRequest {
        self.params_request(shallowStr(flag))
    }

    fn params_request(&self, param: String) -> ParamsRequest {
        ParamsRequest {
            firebase: &self,
            params: vec![param],
        }
    }
}

pub struct ParamsRequest<'l> {
    firebase: &'l Firebase,
    params: Vec<String>,
}

impl<'l> ParamsRequest<'l> {
    pub fn orderBy(&mut self, key: &str) -> &Self {
        self.params.push(orderByStr(key));
        self
    }

    pub fn limitToFirst(&mut self, count: u32) -> &Self {
        self.params.push(limitToFirstStr(count));
        self
    }

    pub fn limitToLast(&mut self, count: u32) -> &Self {
        self.params.push(limitToLastStr(count));
        self
    }

    pub fn startAt(&mut self, index: u32) -> &Self {
        self.params.push(startAtStr(index));
        self
    }

    pub fn endAt(&mut self, index: u32) -> &Self {
        self.params.push(endAtStr(index));
        self
    }

    pub fn equalTo(&mut self, value: u32) -> &Self {
        self.params.push(equalToStr(value));
        self
    }

    pub fn shallow(&mut self, flag: bool) -> &Self {
        self.params.push(shallowStr(flag));
        self
    }

    pub fn get(&self) -> Response {
        Firebase::get_params(self.firebase, self.params.connect("&"))
    }
}

fn orderByStr(key: &str) -> String {
    format!("orderBy={}", key)
}

fn limitToFirstStr(count: u32) -> String {
    format!("limitToFirst={}", count)
}

fn limitToLastStr(count: u32) -> String {
    format!("limitToLast={}", count)
}

fn startAtStr(index: u32) -> String {
    format!("startAt={}", index)
}

fn endAtStr(index: u32) -> String {
    format!("endAt={}", index)
}

fn equalToStr(value: u32) -> String {
    format!("equalTo={}", value)
}

fn shallowStr(flag: bool) -> String {
    format!("shallow={}", flag)
}

enum Method {
    GET,
    POST,
    PUT,
    PATCH,
    DELETE,
}

pub struct Response {
    pub body: String,
    pub code: u32,
}

impl Response {
    pub fn is_success(&self) -> bool {
        self.code < 400
    }
}
<commit_msg>Avoided unecessary cloning again!<commit_after>extern crate curl;

use std::str;
use curl::http;

mod util;

pub struct Firebase {
    base_uri: String,
}

impl Firebase {
    pub fn new(base_uri: &str) -> Self {
        Firebase {
            base_uri: base_uri.to_string(),
        }
    }

    pub fn authenticated(base_uri: &str, auth_token: &str) -> Self {
        let uri = util::trim_right(base_uri, "/");
        Firebase {
            base_uri: format!("{}?auth={}", uri, auth_token),
        }
    }

    pub fn at(&self, path: &str) -> Self {
        let mut components = self.base_uri.split('?');

        let base = components.next().unwrap();
        let base = util::trim_right(base, ".json");
        let path = util::trim_right(path, "/");
        let path = util::add_right(path, ".json");
        let url  = util::join(base, &path, "/");

        let url = if let Some(args) = components.next() {
            url + "?" + args
        } else {
            url
        };

        Firebase {
            base_uri: url,
        }
    }

    pub fn get(&self) -> Response {
        self.request(Method::GET, None)
    }

    fn get_params(&self, params: String) -> Response {
        let url = if self.base_uri.find("?").is_some() {
            format!("{}&{}", &self.base_uri, params)
        } else {
            format!("{}?{}", &self.base_uri, params)
        };

        Firebase::request_url(&url, Method::GET, None)
    }

    pub fn set(&self, data: &str) -> Response {
        self.request(Method::PUT, Some(data))
    }

    pub fn push(&self, data: &str) -> Response {
        self.request(Method::POST, Some(data))
    }

    pub fn update(&self, data: &str) -> Response {
        self.request(Method::PATCH, Some(data))
    }

    pub fn delete(&self) -> Response {
        self.request(Method::DELETE, None)
    }

    fn request(&self, method: Method, data: Option<&str>) -> Response {
        Firebase::request_url(&self.base_uri, method, data)
    }

    fn request_url(url: &str, method: Method, data: Option<&str>) -> Response {
        let mut handler = http::handle();

        let req = match method {
            Method::GET     => handler.get(url),
            Method::POST    => handler.post(url, data.unwrap()),
            Method::PUT     => handler.put(url, data.unwrap()),
            Method::PATCH   => handler.patch(url, data.unwrap()),
            Method::DELETE  => handler.delete(url)
        };
        let res = req.exec().unwrap();

        let body = match str::from_utf8(res.get_body()) {
            Ok(b) => b,
            Err(_) => "Unable to parse"
        };

        Response {
            body: body.to_string(),
            code: res.get_code(),
        }
    }

    pub fn get_url(&self) -> &str {
        return &self.base_uri;
    }

    pub fn orderBy(&self, key: &str) -> ParamsRequest {
        self.params_request(orderByStr(key))
    }

    pub fn limitToFirst(&self, count: u32) -> ParamsRequest {
        self.params_request(limitToFirstStr(count))
    }

    pub fn limitToLast(&self, count: u32) -> ParamsRequest {
        self.params_request(limitToLastStr(count))
    }

    pub fn startAt(&self, index: u32) -> ParamsRequest {
        self.params_request(startAtStr(index))
    }

    pub fn endAt(&self, index: u32) -> ParamsRequest {
        self.params_request(endAtStr(index))
    }

    pub fn equalTo(&self, value: u32) -> ParamsRequest {
        self.params_request(equalToStr(value))
    }

    pub fn shallow(&self, flag: bool) -> ParamsRequest {
        self.params_request(shallowStr(flag))
    }

    fn params_request(&self, param: String) -> ParamsRequest {
        ParamsRequest {
            firebase: &self,
            params: vec![param],
        }
    }
}

pub struct ParamsRequest<'l> {
    firebase: &'l Firebase,
    params: Vec<String>,
}

impl<'l> ParamsRequest<'l> {
    pub fn orderBy(&mut self, key: &str) -> &Self {
        self.params.push(orderByStr(key));
        self
    }

    pub fn limitToFirst(&mut self, count: u32) -> &Self {
        self.params.push(limitToFirstStr(count));
        self
    }

    pub fn limitToLast(&mut self, count: u32) -> &Self {
        self.params.push(limitToLastStr(count));
        self
    }

    pub fn startAt(&mut self, index: u32) -> &Self {
        self.params.push(startAtStr(index));
        self
    }

    pub fn endAt(&mut self, index: u32) -> &Self {
        self.params.push(endAtStr(index));
        self
    }

    pub fn equalTo(&mut self, value: u32) -> &Self {
        self.params.push(equalToStr(value));
        self
    }

    pub fn shallow(&mut self, flag: bool) -> &Self {
        self.params.push(shallowStr(flag));
        self
    }

    pub fn get(&self) -> Response {
        Firebase::get_params(self.firebase, self.params.connect("&"))
    }
}

fn orderByStr(key: &str) -> String {
    format!("orderBy={}", key)
}

fn limitToFirstStr(count: u32) -> String {
    format!("limitToFirst={}", count)
}

fn limitToLastStr(count: u32) -> String {
    format!("limitToLast={}", count)
}

fn startAtStr(index: u32) -> String {
    format!("startAt={}", index)
}

fn endAtStr(index: u32) -> String {
    format!("endAt={}", index)
}

fn equalToStr(value: u32) -> String {
    format!("equalTo={}", value)
}

fn shallowStr(flag: bool) -> String {
    format!("shallow={}", flag)
}

enum Method {
    GET,
    POST,
    PUT,
    PATCH,
    DELETE,
}

pub struct Response {
    pub body: String,
    pub code: u32,
}

impl Response {
    pub fn is_success(&self) -> bool {
        self.code < 400
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

#[macro_use] extern crate bitflags;
extern crate libc;

use std::io::{self, Error};
use std::os::unix::io::RawFd;

#[allow(non_camel_case_types)]
pub enum ControlOptions {
    /// Indicates an addition to the interest list.
    EPOLL_CTL_ADD = libc::EPOLL_CTL_ADD as isize,
    /// Indicates a modification of flags for an interest already in list.
    EPOLL_CTL_MOD = libc::EPOLL_CTL_MOD as isize,
    /// Indicates a removal of an interest from the list.
    EPOLL_CTL_DEL = libc::EPOLL_CTL_DEL as isize
}

bitflags! {
    pub struct Events: u32 {
        /// Sets the Edge Triggered behavior for the associated file descriptor.
        ///
        /// The default behavior for epoll is Level Triggered.
        const EPOLLET      = libc::EPOLLET as u32;
        /// The associated file is available for read operations.
        const EPOLLIN      = libc::EPOLLIN as u32;
        /// Error condition happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; is not necessary to set it in events.
        const EPOLLERR     = libc::EPOLLERR as u32;
        /// Hang up happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; it is not necessary to set it in events.
        /// Note that when reading from a channel such as a pipe or a stream socket, this event
        /// merely indicates that the peer closed its end of the channel. Subsequent reads from
        /// the channel will return 0 (end of file) only after all outstanding data in the
        /// channel has been consumed.
        const EPOLLHUP     = libc::EPOLLHUP as u32;
        /// The associated file is available for write operations.
        const EPOLLOUT     = libc::EPOLLOUT as u32;
        /// There is urgent data available for read operations.
        const EPOLLPRI     = libc::EPOLLPRI as u32;
        /// Stream socket peer closed connection, or shut down writing half of connection.
        ///
        /// This flag is especially useful for writing simple code to detect peer shutdown when
        /// using Edge Triggered monitoring.
        const EPOLLRDHUP   = libc::EPOLLRDHUP as u32;
        /// If `EPOLLONESHOT` and `EPOLLET` are clear and the process has the `CAP_BLOCK_SUSPEND`
        /// capability, ensure that the system does not enter "suspend" or "hibernate" while this
        /// event is pending or being processed.
        ///
        /// The event is considered as being "processed" from the time when it is returned by
        /// a call to `wait` until the next call to `wait` on the same `EpollInstance`
        /// descriptor, the closure of that file descriptor, the removal of the event file
        /// descriptor with `EPOLL_CTL_DEL`, or the clearing of `EPOLLWAKEUP` for the event file
        /// descriptor with `EPOLL_CTL_MOD`.
        const EPOLLWAKEUP  = libc::EPOLLWAKEUP as u32;
        /// Sets the one-shot behavior for the associated file descriptor.
        ///
        /// This means that after an event is pulled out with `wait` the associated file
        /// descriptor is internally disabled and no other events will be reported by the epoll
        /// interface.  The user must call `ctl` with `EPOLL_CTL_MOD` to rearm the file
        /// descriptor with a new event mask.
        const EPOLLONESHOT = libc::EPOLLONESHOT as u32;
    }
}

/// 'libc::epoll_event' equivalent.
#[repr(C)]
#[cfg_attr(target_arch = "x86_64", repr(packed))]
#[derive(Clone, Copy)]
pub struct Event {
    pub events: u32,
    pub data: u64
}

impl Event {
    pub fn new(events: Events, data: u64) -> Event {
        Event { events: events.bits(), data: data }
    }
}

/// Creates a new epoll file descriptor.
///
/// If `cloexec` is true, `FD_CLOEXEC` will be set on the returned file descriptor.
///
/// ## Notes
///
/// * `epoll_create1()` is the underlying syscall.
pub fn create(cloexec: bool) -> io::Result<RawFd> {
    let flags = if cloexec { libc::EPOLL_CLOEXEC } else { 0 };
    unsafe { cvt(libc::epoll_create1(flags)) }
}

/// Safe wrapper for `libc::epoll_ctl`
pub fn ctl(epfd: RawFd,
           op: ControlOptions,
           fd: RawFd,
           mut event: Event)
           -> io::Result<()>
{
    let e = &mut event as *mut _ as *mut libc::epoll_event;
    unsafe { try!(cvt(libc::epoll_ctl(epfd, op as i32, fd, e))) };
    Ok(())
}

/// Safe wrapper for `libc::epoll_wait`
///
/// ## Notes
///
/// * If `timeout` is negative, it will block until an event is received.
pub fn wait(epfd: RawFd,
            timeout: i32,
            buf: &mut [Event])
            -> io::Result<usize>
{
    let timeout = if timeout < -1 { -1 } else { timeout };
    let num_events = unsafe {
        try!(cvt(libc::epoll_wait(epfd,
                                  buf.as_mut_ptr() as *mut libc::epoll_event,
                                  buf.len() as i32,
                                  timeout))) as usize
    };
    Ok(num_events)
}

/// Safe wrapper for `libc::close`
pub fn close(epfd: RawFd) -> io::Result<()> {
    cvt(unsafe { libc::close(epfd) })?;
    Ok(())
}

fn cvt(result: libc::c_int) -> io::Result<libc::c_int> {
    if result < 0 { Err(Error::last_os_error()) } else { Ok(result) }
}
<commit_msg>Updates try macro to ?<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

#[macro_use] extern crate bitflags;
extern crate libc;

use std::io::{self, Error};
use std::os::unix::io::RawFd;

#[allow(non_camel_case_types)]
pub enum ControlOptions {
    /// Indicates an addition to the interest list.
    EPOLL_CTL_ADD = libc::EPOLL_CTL_ADD as isize,
    /// Indicates a modification of flags for an interest already in list.
    EPOLL_CTL_MOD = libc::EPOLL_CTL_MOD as isize,
    /// Indicates a removal of an interest from the list.
    EPOLL_CTL_DEL = libc::EPOLL_CTL_DEL as isize
}

bitflags! {
    pub struct Events: u32 {
        /// Sets the Edge Triggered behavior for the associated file descriptor.
        ///
        /// The default behavior for epoll is Level Triggered.
        const EPOLLET      = libc::EPOLLET as u32;
        /// The associated file is available for read operations.
        const EPOLLIN      = libc::EPOLLIN as u32;
        /// Error condition happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; is not necessary to set it in events.
        const EPOLLERR     = libc::EPOLLERR as u32;
        /// Hang up happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; it is not necessary to set it in events.
        /// Note that when reading from a channel such as a pipe or a stream socket, this event
        /// merely indicates that the peer closed its end of the channel. Subsequent reads from
        /// the channel will return 0 (end of file) only after all outstanding data in the
        /// channel has been consumed.
        const EPOLLHUP     = libc::EPOLLHUP as u32;
        /// The associated file is available for write operations.
        const EPOLLOUT     = libc::EPOLLOUT as u32;
        /// There is urgent data available for read operations.
        const EPOLLPRI     = libc::EPOLLPRI as u32;
        /// Stream socket peer closed connection, or shut down writing half of connection.
        ///
        /// This flag is especially useful for writing simple code to detect peer shutdown when
        /// using Edge Triggered monitoring.
        const EPOLLRDHUP   = libc::EPOLLRDHUP as u32;
        /// If `EPOLLONESHOT` and `EPOLLET` are clear and the process has the `CAP_BLOCK_SUSPEND`
        /// capability, ensure that the system does not enter "suspend" or "hibernate" while this
        /// event is pending or being processed.
        ///
        /// The event is considered as being "processed" from the time when it is returned by
        /// a call to `wait` until the next call to `wait` on the same `EpollInstance`
        /// descriptor, the closure of that file descriptor, the removal of the event file
        /// descriptor with `EPOLL_CTL_DEL`, or the clearing of `EPOLLWAKEUP` for the event file
        /// descriptor with `EPOLL_CTL_MOD`.
        const EPOLLWAKEUP  = libc::EPOLLWAKEUP as u32;
        /// Sets the one-shot behavior for the associated file descriptor.
        ///
        /// This means that after an event is pulled out with `wait` the associated file
        /// descriptor is internally disabled and no other events will be reported by the epoll
        /// interface.  The user must call `ctl` with `EPOLL_CTL_MOD` to rearm the file
        /// descriptor with a new event mask.
        const EPOLLONESHOT = libc::EPOLLONESHOT as u32;
    }
}

/// 'libc::epoll_event' equivalent.
#[repr(C)]
#[cfg_attr(target_arch = "x86_64", repr(packed))]
#[derive(Clone, Copy)]
pub struct Event {
    pub events: u32,
    pub data: u64
}

impl Event {
    pub fn new(events: Events, data: u64) -> Event {
        Event { events: events.bits(), data: data }
    }
}

/// Creates a new epoll file descriptor.
///
/// If `cloexec` is true, `FD_CLOEXEC` will be set on the returned file descriptor.
///
/// ## Notes
///
/// * `epoll_create1()` is the underlying syscall.
pub fn create(cloexec: bool) -> io::Result<RawFd> {
    let flags = if cloexec { libc::EPOLL_CLOEXEC } else { 0 };
    unsafe { cvt(libc::epoll_create1(flags)) }
}

/// Safe wrapper for `libc::epoll_ctl`
pub fn ctl(epfd: RawFd,
           op: ControlOptions,
           fd: RawFd,
           mut event: Event)
           -> io::Result<()>
{
    let e = &mut event as *mut _ as *mut libc::epoll_event;
    unsafe { cvt(libc::epoll_ctl(epfd, op as i32, fd, e))? };
    Ok(())
}

/// Safe wrapper for `libc::epoll_wait`
///
/// ## Notes
///
/// * If `timeout` is negative, it will block until an event is received.
pub fn wait(epfd: RawFd,
            timeout: i32,
            buf: &mut [Event])
            -> io::Result<usize>
{
    let timeout = if timeout < -1 { -1 } else { timeout };
    let num_events = unsafe {
        cvt(libc::epoll_wait(epfd,
                                  buf.as_mut_ptr() as *mut libc::epoll_event,
                                  buf.len() as i32,
                                  timeout))? as usize
    };
    Ok(num_events)
}

/// Safe wrapper for `libc::close`
pub fn close(epfd: RawFd) -> io::Result<()> {
    cvt(unsafe { libc::close(epfd) })?;
    Ok(())
}

fn cvt(result: libc::c_int) -> io::Result<libc::c_int> {
    if result < 0 { Err(Error::last_os_error()) } else { Ok(result) }
}
<|endoftext|>


<commit_before>//! Tiny OBJ loader, inspired by Syoyo's excellent [tinyobjloader](https://github.com/syoyo/tinyobjloader)

#![allow(dead_code)]

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::collections::HashMap;
use std::str::{FromStr, Split};

/// A mesh for some model containing its triangle geometry
/// This object could be a single polygon group or object within a file
/// that defines multiple groups/objects or be the only mesh within the file
/// if it only contains a single mesh
#[derive(Debug, Clone)]
pub struct Mesh {
    pub positions: Vec<f32>,
    pub normals: Vec<f32>,
    pub texcoords: Vec<f32>,
    pub faces: Vec<u32>,
}

impl Mesh {
    /// Create a new mesh specifying the geometry for the mesh
    pub fn new(pos: Vec<f32>, norm: Vec<f32>, tex: Vec<f32>, faces: Vec<u32>) -> Mesh {
        Mesh { positions: pos, normals: norm, texcoords: tex, faces: faces }
    }
    /// Create a new empty mesh
    pub fn empty() -> Mesh {
        Mesh { positions: Vec::new(), normals: Vec::new(), texcoords: Vec::new(), faces: Vec::new() }
    }
}

/// A named model within the file
/// This could be a group or object or the single model exported by the file
#[derive(Debug)]
pub struct Model {
    pub mesh: Mesh,
    pub name: String,
}

impl Model {
    /// Create a new model, associating a name with a mesh
    pub fn new(mesh: Mesh, name: String) -> Model {
        Model { mesh: mesh, name: name }
    }
}

/// TODO: Decide on various errors we'll return
#[derive(Debug)]
pub enum LoadError {
    OpenFileFailed,
    ReadError,
    UnrecognizedCharacter,
    PositionParseError,
    NormalParseError,
    TexcoordParseError,
    FaceParseError,
    InvalidObjectName,
    GenericFailure,
}

/// LoadResult is a result containing all the models loaded from the file or any
/// error that occured while loading
pub type LoadResult = Result<Vec<Model>, LoadError>;

/// Struct storing indices corresponding to the vertex
/// Some vertices may not have texcoords or normals, 0 is used to indicate this
/// as OBJ indices begin at 1
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Debug, Copy, Clone)]
struct VertexIndices {
    pub v: usize,
    pub vt: usize,
    pub vn: usize,
}

impl VertexIndices {
    /// Parse the vertex indices from the face string
    /// Valid face strings are those that are valid for a Wavefront OBJ file
    /// Returns None if the face string is invalid
    pub fn parse(face_str: &str) -> Option<VertexIndices> {
        println!("Parsing face string {}", face_str);
        let mut indices = [0; 3];
        for i in face_str.split('/').enumerate() {
            println!("Index: {}, element index: {}", i.1, i.0);
            // Catch case of v//vn where we'll find an empty string in one of our splits
            // since there are no texcoords for the mesh
            if !i.1.is_empty() {
                match usize::from_str(i.1) {
                    Ok(x) => indices[i.0] = x - 1,
                    Err(_) => return None,
                }
            }
        }
        Some(VertexIndices { v: indices[0], vt: indices[1], vn: indices[2] })
    }
}

/// Enum representing either a quad or triangle face, storing indices for the face vertices
#[derive(Debug)]
enum Face {
    Triangle(VertexIndices, VertexIndices, VertexIndices),
    Quad(VertexIndices, VertexIndices, VertexIndices, VertexIndices)
}

/// Parse the floatn information from the words, words is an iterator over the float strings
/// Returns false if parsing failed
fn parse_floatn(val_str: Split<char>, vals: &mut Vec<f32>, n: usize) -> bool {
    let sz = vals.len();
    for p in val_str {
        match FromStr::from_str(p) {
            Ok(x) => vals.push(x),
            Err(_) => return false,
        }
    }
    // Require that we found the desired number of floats
    sz + n == vals.len()
}

/// Parse vertex indices for a face and append it to the list of faces passed
/// returns false if an error occured parsing the face
fn parse_face(face_str: Split<char>, faces: &mut Vec<Face>) -> bool {
    let mut indices = Vec::new();
    for f in face_str {
        match VertexIndices::parse(f) {
            Some(v) => indices.push(v),
            None => return false,
        }
    }
    // Check if we read a triangle or a quad face and push it on
    match indices.len() {
        3 => faces.push(Face::Triangle(indices[0], indices[1], indices[2])),
        4 => faces.push(Face::Quad(indices[0], indices[1], indices[2], indices[3])),
        _ => return false,
    }
    true
}

/// Add a vertex to a mesh by either re-using an existing index (eg. it's in the index_map)
/// or appending the position, texcoord and normal as appropriate and creating a new vertex
fn add_vertex(mesh: &mut Mesh, index_map: &mut HashMap<VertexIndices, u32>, vert: &VertexIndices,
              pos: &Vec<f32>, texcoord: &Vec<f32>, normal: &Vec<f32>) {
    match index_map.get(vert){
        Some(&i) => mesh.faces.push(i),
        None => {
            // Add the vertex to the mesh
            mesh.positions.push(pos[vert.v * 3]);
            mesh.positions.push(pos[vert.v * 3 + 1]);
            mesh.positions.push(pos[vert.v * 3 + 2]);
            if !texcoord.is_empty() {
                mesh.texcoords.push(texcoord[vert.vt * 2]);
                mesh.texcoords.push(texcoord[vert.vt * 2 + 1]);
            }
            if !normal.is_empty() {
                mesh.normals.push(normal[vert.vn * 3]);
                mesh.normals.push(normal[vert.vn * 3 + 1]);
                mesh.normals.push(normal[vert.vn * 3 + 2]);
            }
            let next = index_map.len() as u32;
            mesh.faces.push(next);
            index_map.insert(*vert, next);
        }
    }
}

/// Export a list of faces to a mesh and return it, converting quads to tris
fn export_faces(pos: &Vec<f32>, texcoord: &Vec<f32>, normal: &Vec<f32>, faces: &Vec<Face>) -> Mesh {
    let mut index_map = HashMap::new();
    let mut mesh = Mesh::empty();
    // TODO: When drain becomes stable we should use that, since we clear `faces` later anyway
    for f in faces {
        match *f {
            Face::Triangle(ref a, ref b, ref c) => {
                add_vertex(&mut mesh, &mut index_map, a, pos, texcoord, normal);
                add_vertex(&mut mesh, &mut index_map, b, pos, texcoord, normal);
                add_vertex(&mut mesh, &mut index_map, c, pos, texcoord, normal);
            },
            Face::Quad(ref a, ref b, ref c, ref d) => {
                add_vertex(&mut mesh, &mut index_map, a, pos, texcoord, normal);
                add_vertex(&mut mesh, &mut index_map, b, pos, texcoord, normal);
                add_vertex(&mut mesh, &mut index_map, c, pos, texcoord, normal);

                add_vertex(&mut mesh, &mut index_map, b, pos, texcoord, normal);
                add_vertex(&mut mesh, &mut index_map, d, pos, texcoord, normal);
                add_vertex(&mut mesh, &mut index_map, c, pos, texcoord, normal);
            }
        }
    }
    mesh
}

/// Load the various meshes in an OBJ file
pub fn load_obj(file_name: &str) -> LoadResult {
    println!("Loading file {}", file_name);
    let file = match File::open(file_name) {
        Ok(f) => f,
        Err(e) => {
            println!("tobj::load_obj - failed to open {} due to {}", file_name, e);
            return Err(LoadError::OpenFileFailed);
        },
    };
    let mut reader = BufReader::new(file);
    load_obj_buf(&mut reader)
}

/// Load the various meshes in an OBJ buffer
pub fn load_obj_buf<B: BufRead>(reader: &mut B) -> LoadResult {
    let mut models = Vec::new();
    let mut tmp_pos = Vec::new();
    let mut tmp_texcoord = Vec::new();
    let mut tmp_normal = Vec::new();
    let mut tmp_faces: Vec<Face> = Vec::new();
    // name of the current object being parsed
    let mut name = String::new();
    // Next index for a new face we might find
    for line in reader.lines() {
        // We just need the line for debugging for a bit
        // TODO: Switch back to using `words` when it becomes stable
        let (line, mut words) = match line {
            Ok(ref line) => (&line[..], line[..].split(' ')),
            Err(e) => {
                println!("tobj::load_obj - failed to read line due to {}", e);
                return Err(LoadError::ReadError);
            },
        };
        match words.next() {
            Some("#") => { println!("Skipping comment"); continue; },
            Some("v") => {
                println!("Will parse vertex {}", line);
                if !parse_floatn(words, &mut tmp_pos, 3) {
                    return Err(LoadError::PositionParseError);
                }
            },
            Some("vt") => {
                println!("Will parse texcoord {}", line);
                if !parse_floatn(words, &mut tmp_texcoord, 2) {
                    return Err(LoadError::TexcoordParseError);
                }
            },
            Some("vn") => {
                println!("Will parse normal {}", line);
                if !parse_floatn(words, &mut tmp_normal, 3) {
                    return Err(LoadError::NormalParseError);
                }
            },
            Some("f") => {
                println!("Will parse face {}", line);
                if !parse_face(words, &mut tmp_faces) {
                    return Err(LoadError::FaceParseError);
                }
            },
            Some("o") => {
                // If we were already parsing an object then a new object name
                // signals the end of the current one, so push it onto our list of objects
                if !name.is_empty() && !tmp_faces.is_empty() {
                    models.push(Model::new(export_faces(&tmp_pos, &tmp_texcoord, &tmp_normal, &tmp_faces), name));
                    println!("Finished parsing {:?}", models[models.len() - 1]);
                    tmp_faces.clear();
                }
                match words.next() {
                    Some(n) => name = n.to_string(),
                    None => return Err(LoadError::InvalidObjectName),
                }
                println!("Beginning to parse new object: {}", name);
            },
            Some("g") => { println!("Will parse group {}", line); },
            Some("mtllib") => { println!("Will parse material lib {}", line); },
            Some("usemtl") => { println!("Will parse usemtl {}", line); },
            None => { println!("Skipping empty line"); continue; },
            // TODO: throw error on unrecognized character. Currently with split we get a newline
            // and incorrectly through so this is off temporarily. Blocked until `words` becomes
            // stable
            Some(c) => { println!("Unrecognized character: {}", c); /*return Err(LoadError::UnrecognizedCharacter) */ },
        }
    }
    // For the last object in the file we won't encounter another object name to tell us when it's
    // done, so if we're parsing an object push the last one on the list as well
    if !name.is_empty() {
        models.push(Model::new(export_faces(&tmp_pos, &tmp_texcoord, &tmp_normal, &tmp_faces), name));
    }
    for m in &models {
        println!("Parsed Model: {:?}", m);
    }
    Ok(models)
}

#[test]
fn test_tri(){
    assert!(load_obj("triangle.obj").is_ok());
}

#[test]
fn test_quad(){
    assert!(load_obj("quad.obj").is_ok());
}

<commit_msg>Use trim before splitting to clear up carriage returns on windows<commit_after>//! Tiny OBJ loader, inspired by Syoyo's excellent [tinyobjloader](https://github.com/syoyo/tinyobjloader)

#![allow(dead_code)]

use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::collections::HashMap;
use std::str::{FromStr, Split};

/// A mesh for some model containing its triangle geometry
/// This object could be a single polygon group or object within a file
/// that defines multiple groups/objects or be the only mesh within the file
/// if it only contains a single mesh
#[derive(Debug, Clone)]
pub struct Mesh {
    pub positions: Vec<f32>,
    pub normals: Vec<f32>,
    pub texcoords: Vec<f32>,
    pub faces: Vec<u32>,
}

impl Mesh {
    /// Create a new mesh specifying the geometry for the mesh
    pub fn new(pos: Vec<f32>, norm: Vec<f32>, tex: Vec<f32>, faces: Vec<u32>) -> Mesh {
        Mesh { positions: pos, normals: norm, texcoords: tex, faces: faces }
    }
    /// Create a new empty mesh
    pub fn empty() -> Mesh {
        Mesh { positions: Vec::new(), normals: Vec::new(), texcoords: Vec::new(), faces: Vec::new() }
    }
}

/// A named model within the file
/// This could be a group or object or the single model exported by the file
#[derive(Debug)]
pub struct Model {
    pub mesh: Mesh,
    pub name: String,
}

impl Model {
    /// Create a new model, associating a name with a mesh
    pub fn new(mesh: Mesh, name: String) -> Model {
        Model { mesh: mesh, name: name }
    }
}

/// TODO: Decide on various errors we'll return
#[derive(Debug)]
pub enum LoadError {
    OpenFileFailed,
    ReadError,
    UnrecognizedCharacter,
    PositionParseError,
    NormalParseError,
    TexcoordParseError,
    FaceParseError,
    InvalidObjectName,
    GenericFailure,
}

/// LoadResult is a result containing all the models loaded from the file or any
/// error that occured while loading
pub type LoadResult = Result<Vec<Model>, LoadError>;

/// Struct storing indices corresponding to the vertex
/// Some vertices may not have texcoords or normals, 0 is used to indicate this
/// as OBJ indices begin at 1
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Debug, Copy, Clone)]
struct VertexIndices {
    pub v: usize,
    pub vt: usize,
    pub vn: usize,
}

impl VertexIndices {
    /// Parse the vertex indices from the face string
    /// Valid face strings are those that are valid for a Wavefront OBJ file
    /// Returns None if the face string is invalid
    pub fn parse(face_str: &str) -> Option<VertexIndices> {
        println!("Parsing face string {}", face_str);
        let mut indices = [0; 3];
        for i in face_str.split('/').enumerate() {
            println!("Index: {}, element index: {}", i.1, i.0);
            // Catch case of v//vn where we'll find an empty string in one of our splits
            // since there are no texcoords for the mesh
            if !i.1.is_empty() {
                match usize::from_str(i.1) {
                    Ok(x) => indices[i.0] = x - 1,
                    Err(_) => return None,
                }
            }
        }
        Some(VertexIndices { v: indices[0], vt: indices[1], vn: indices[2] })
    }
}

/// Enum representing either a quad or triangle face, storing indices for the face vertices
#[derive(Debug)]
enum Face {
    Triangle(VertexIndices, VertexIndices, VertexIndices),
    Quad(VertexIndices, VertexIndices, VertexIndices, VertexIndices)
}

/// Parse the floatn information from the words, words is an iterator over the float strings
/// Returns false if parsing failed
fn parse_floatn(val_str: Split<char>, vals: &mut Vec<f32>, n: usize) -> bool {
    let sz = vals.len();
    for p in val_str {
        match FromStr::from_str(p) {
            Ok(x) => vals.push(x),
            Err(_) => return false,
        }
    }
    // Require that we found the desired number of floats
    sz + n == vals.len()
}

/// Parse vertex indices for a face and append it to the list of faces passed
/// returns false if an error occured parsing the face
fn parse_face(face_str: Split<char>, faces: &mut Vec<Face>) -> bool {
    let mut indices = Vec::new();
    for f in face_str {
        match VertexIndices::parse(f) {
            Some(v) => indices.push(v),
            None => return false,
        }
    }
    // Check if we read a triangle or a quad face and push it on
    match indices.len() {
        3 => faces.push(Face::Triangle(indices[0], indices[1], indices[2])),
        4 => faces.push(Face::Quad(indices[0], indices[1], indices[2], indices[3])),
        _ => return false,
    }
    true
}

/// Add a vertex to a mesh by either re-using an existing index (eg. it's in the index_map)
/// or appending the position, texcoord and normal as appropriate and creating a new vertex
fn add_vertex(mesh: &mut Mesh, index_map: &mut HashMap<VertexIndices, u32>, vert: &VertexIndices,
              pos: &Vec<f32>, texcoord: &Vec<f32>, normal: &Vec<f32>) {
    match index_map.get(vert){
        Some(&i) => mesh.faces.push(i),
        None => {
            // Add the vertex to the mesh
            mesh.positions.push(pos[vert.v * 3]);
            mesh.positions.push(pos[vert.v * 3 + 1]);
            mesh.positions.push(pos[vert.v * 3 + 2]);
            if !texcoord.is_empty() {
                mesh.texcoords.push(texcoord[vert.vt * 2]);
                mesh.texcoords.push(texcoord[vert.vt * 2 + 1]);
            }
            if !normal.is_empty() {
                mesh.normals.push(normal[vert.vn * 3]);
                mesh.normals.push(normal[vert.vn * 3 + 1]);
                mesh.normals.push(normal[vert.vn * 3 + 2]);
            }
            let next = index_map.len() as u32;
            mesh.faces.push(next);
            index_map.insert(*vert, next);
        }
    }
}

/// Export a list of faces to a mesh and return it, converting quads to tris
fn export_faces(pos: &Vec<f32>, texcoord: &Vec<f32>, normal: &Vec<f32>, faces: &Vec<Face>) -> Mesh {
    let mut index_map = HashMap::new();
    let mut mesh = Mesh::empty();
    // TODO: When drain becomes stable we should use that, since we clear `faces` later anyway
    for f in faces {
        match *f {
            Face::Triangle(ref a, ref b, ref c) => {
                add_vertex(&mut mesh, &mut index_map, a, pos, texcoord, normal);
                add_vertex(&mut mesh, &mut index_map, b, pos, texcoord, normal);
                add_vertex(&mut mesh, &mut index_map, c, pos, texcoord, normal);
            },
            Face::Quad(ref a, ref b, ref c, ref d) => {
                add_vertex(&mut mesh, &mut index_map, a, pos, texcoord, normal);
                add_vertex(&mut mesh, &mut index_map, b, pos, texcoord, normal);
                add_vertex(&mut mesh, &mut index_map, c, pos, texcoord, normal);

                add_vertex(&mut mesh, &mut index_map, b, pos, texcoord, normal);
                add_vertex(&mut mesh, &mut index_map, d, pos, texcoord, normal);
                add_vertex(&mut mesh, &mut index_map, c, pos, texcoord, normal);
            }
        }
    }
    mesh
}

/// Load the various meshes in an OBJ file
pub fn load_obj(file_name: &str) -> LoadResult {
    println!("Loading file {}", file_name);
    let file = match File::open(file_name) {
        Ok(f) => f,
        Err(e) => {
            println!("tobj::load_obj - failed to open {} due to {}", file_name, e);
            return Err(LoadError::OpenFileFailed);
        },
    };
    let mut reader = BufReader::new(file);
    load_obj_buf(&mut reader)
}

/// Load the various meshes in an OBJ buffer
pub fn load_obj_buf<B: BufRead>(reader: &mut B) -> LoadResult {
    let mut models = Vec::new();
    let mut tmp_pos = Vec::new();
    let mut tmp_texcoord = Vec::new();
    let mut tmp_normal = Vec::new();
    let mut tmp_faces: Vec<Face> = Vec::new();
    // name of the current object being parsed
    let mut name = String::new();
    // Next index for a new face we might find
    for line in reader.lines() {
        // We just need the line for debugging for a bit
        // TODO: Switch back to using `words` when it becomes stable
        let (line, mut words) = match line {
            Ok(ref line) => (&line[..], line[..].trim().split(' ')),
            Err(e) => {
                println!("tobj::load_obj - failed to read line due to {}", e);
                return Err(LoadError::ReadError);
            },
        };
        match words.next() {
            Some("#") => { println!("Skipping comment"); continue; },
            Some("v") => {
                println!("Will parse vertex {}", line);
                if !parse_floatn(words, &mut tmp_pos, 3) {
                    println!("Failed to parse 'v'");
                    return Err(LoadError::PositionParseError);
                }
            },
            Some("vt") => {
                println!("Will parse texcoord {}", line);
                if !parse_floatn(words, &mut tmp_texcoord, 2) {
                    return Err(LoadError::TexcoordParseError);
                }
            },
            Some("vn") => {
                println!("Will parse normal {}", line);
                if !parse_floatn(words, &mut tmp_normal, 3) {
                    return Err(LoadError::NormalParseError);
                }
            },
            Some("f") => {
                println!("Will parse face {}", line);
                if !parse_face(words, &mut tmp_faces) {
                    return Err(LoadError::FaceParseError);
                }
            },
            Some("o") => {
                // If we were already parsing an object then a new object name
                // signals the end of the current one, so push it onto our list of objects
                if !name.is_empty() && !tmp_faces.is_empty() {
                    models.push(Model::new(export_faces(&tmp_pos, &tmp_texcoord, &tmp_normal, &tmp_faces), name));
                    println!("Finished parsing {:?}", models[models.len() - 1]);
                    tmp_faces.clear();
                }
                match words.next() {
                    Some(n) => name = n.to_string(),
                    None => return Err(LoadError::InvalidObjectName),
                }
                println!("Beginning to parse new object: {}", name);
            },
            Some("g") => { println!("Will parse group {}", line); },
            Some("mtllib") => { println!("Will parse material lib {}", line); },
            Some("usemtl") => { println!("Will parse usemtl {}", line); },
            None => { println!("Skipping empty line"); continue; },
            // TODO: throw error on unrecognized character. Currently with split we get a newline
            // and incorrectly through so this is off temporarily. Blocked until `words` becomes
            // stable
            Some(c) => { println!("Unrecognized character: {}", c); /*return Err(LoadError::UnrecognizedCharacter) */ },
        }
    }
    // For the last object in the file we won't encounter another object name to tell us when it's
    // done, so if we're parsing an object push the last one on the list as well
    if !name.is_empty() {
        models.push(Model::new(export_faces(&tmp_pos, &tmp_texcoord, &tmp_normal, &tmp_faces), name));
    }
    for m in &models {
        println!("Parsed Model: {:?}", m);
    }
    Ok(models)
}

#[test]
fn test_tri(){
    assert!(load_obj("triangle.obj").is_ok());
}

#[test]
fn test_quad(){
    assert!(load_obj("quad.obj").is_ok());
}

<|endoftext|>