<commit_before>// Copyright 2014-2015 The GeoRust Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// TODO
// generic number instead of f64 for position?

extern crate "rustc-serialize" as rustc_serialize;

use std::collections::BTreeMap;
use rustc_serialize::json::{self, ToJson, Json};

// /// ToGeoJson
// pub trait ToGeoJson {
//     // TODO: change this to return a generic GeoJSON object
//     fn to_geojson(&self) -> Geometry;
// }

/// Pos (alias for Positions)
///
/// [GeoJSON Format Specification § 2.1.1](http://geojson.org/geojson-spec.html#positions)
#[derive(RustcEncodable, Clone)]
pub struct Pos(pub Vec<f64>);

impl ToJson for Pos {
    fn to_json(&self) -> json::Json {
        match self.clone() {
            Pos(v) => {
                v.to_json()
            }
        }
    }
}

/// Ring
#[derive(RustcEncodable, Clone)]
pub struct Ring(pub Vec<Pos>);

impl ToJson for Ring {
    fn to_json(&self) -> json::Json {
        match self.clone() {
            Ring(v) => {
                v.to_json()
            }
        }
    }
}

/// Poly  (alias for Polygon)
#[derive(RustcEncodable, Clone)]
pub struct Poly(pub Vec<Ring>);

impl ToJson for Poly {
    fn to_json(&self) -> json::Json {
        match self.clone() {
            Poly(v) => {
                v.to_json()
            }
        }
    }
}

/// Point
///
/// [GeoJSON Format Specification § 2.1.2](http://geojson.org/geojson-spec.html#point)
#[derive(RustcEncodable, Clone)]
pub struct Point {
    pub coordinates: Pos,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "Point".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}
#[test]
fn test_point_tojson() {
    let point = Point {coordinates: Pos(vec![1., 2., 3.])};
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"coordinates\":[1.0,2.0,3.0],\"type\":\"Point\"}", json_string);
}

/// MultiPoint
///
/// [GeoJSON Format Specification § 2.1.3](http://geojson.org/geojson-spec.html#multipoint)
#[derive(RustcEncodable, Clone)]
pub struct MultiPoint {
    pub coordinates: Vec<Pos>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "MultiPoint".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}
#[test]
fn test_multi_point_tojson() {
    let point = MultiPoint {coordinates: vec![Pos(vec![1., 2., 3.])]};
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"coordinates\":[[1.0,2.0,3.0]],\"type\":\"MultiPoint\"}", json_string);
}

/// LineString
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
#[derive(RustcEncodable, Clone)]
pub struct LineString {
    pub coordinates: Ring,
}

impl ToJson for LineString {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "LineString".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}

#[test]
fn test_line_string_tojson() {
    let point = LineString {coordinates: Ring(vec![Pos(vec![1., 2., 3.]), Pos(vec![2., 4., 3.])])};
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"coordinates\":[[1.0,2.0,3.0],[2.0,4.0,3.0]],\"type\":\"LineString\"}", json_string);
}
/// MultiLineString
///
/// [GeoJSON Format Specification § 2.1.5](http://geojson.org/geojson-spec.html#multilinestring)
#[derive(RustcEncodable, Clone)]
pub struct MultiLineString {
    pub coordinates: Vec<Ring>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "MultiLineString".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}
#[test]
fn test_multi_line_string_tojson() {
    let point = MultiLineString {coordinates: vec![
        Ring(vec![Pos(vec![1., 2., 3.]), Pos(vec![2., 4., 3.])]),
        Ring(vec![Pos(vec![3., 2., 3.]), Pos(vec![2., 4., 3.])])
        ]};
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"coordinates\":[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]],\"type\":\"MultiLineString\"}", json_string);
}

/// Polygon
///
/// [GeoJSON Format Specification § 2.1.6](http://geojson.org/geojson-spec.html#polygon)
#[derive(RustcEncodable, Clone)]
pub struct Polygon {
    pub coordinates: Poly
}
impl ToJson for Polygon {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "Polygon".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}
#[test]
fn test_polygon_string_tojson() {
    let point = Polygon {coordinates: Poly(vec![
        Ring(vec![Pos(vec![1., 2., 3.]), Pos(vec![2., 4., 3.])]),
        Ring(vec![Pos(vec![3., 2., 3.]), Pos(vec![2., 4., 3.])])
        ])};
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"coordinates\":[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]],\"type\":\"Polygon\"}", json_string);
}

/// MultiPolygon
///
/// [GeoJSON Format Specification § 2.1.7](http://geojson.org/geojson-spec.html#multipolygon)
#[derive(RustcEncodable, Clone)]
pub struct MultiPolygon {
    pub coordinates: Vec<Poly>,
}

impl ToJson for MultiPolygon {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "MultiPolygon".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}
#[test]
fn test_multi_polygon_string_tojson() {
    let point = MultiPolygon {coordinates: vec![Poly(vec![
        Ring(vec![Pos(vec![1., 2., 3.]), Pos(vec![2., 4., 3.])]),
        Ring(vec![Pos(vec![3., 2., 3.]), Pos(vec![2., 4., 3.])])
        ])]};
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"coordinates\":[[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]]],\"type\":\"MultiPolygon\"}", json_string);
}

/// Geometry
#[derive(RustcEncodable, Clone)]
pub enum Geometry {
    Point(Point),
    MultiPoint(MultiPoint),
    LineString(LineString),
    MultiLineString(MultiLineString),
    Polygon(Polygon),
    MultiPolygon(MultiPolygon),
    GeometryCollection(GeometryCollection),
}

impl ToJson for Geometry {
    fn to_json(&self) -> json::Json {
        match *self {
            Geometry::Point(ref geom) => geom.to_json(),
            Geometry::MultiPoint(ref geom) => geom.to_json(),
            Geometry::LineString(ref geom) => geom.to_json(),
            Geometry::MultiLineString(ref geom) => geom.to_json(),
            Geometry::Polygon(ref geom) => geom.to_json(),
            Geometry::MultiPolygon(ref geom) => geom.to_json(),
            Geometry::GeometryCollection(ref geom) => geom.to_json(),
        }
    }
}
/// GeometryCollection
///
/// [GeoJSON Format Specification § 2.1.8](http://geojson.org/geojson-spec.html#geometry-collection)
#[derive(RustcEncodable, Clone)]
pub struct GeometryCollection {
    geometries: Vec<Geometry>,
}

impl ToJson for GeometryCollection {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "GeometryCollection".to_json());
        d.insert(format!("geometries"), self.geometries.to_json());
        d.to_json()
    }
}
#[test]
fn test_geometry_collection_string_tojson() {
    let point = GeometryCollection {
        geometries: vec![Geometry::MultiPolygon(MultiPolygon {
                    coordinates: vec![
                        Poly(vec![
                            Ring(vec![
                                Pos(vec![1., 2., 3.]),
                                Pos(vec![2., 4., 3.])
                            ]),
                            Ring(vec![
                                Pos(vec![3., 2., 3.]),
                                Pos(vec![2., 4., 3.])
                            ])
                        ])
                    ]
                })
        ]
    };
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"geometries\":[{\"coordinates\":[[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]]],\"type\":\"MultiPolygon\"}],\"type\":\"GeometryCollection\"}", json_string);
}
/// Feature
///
/// [GeoJSON Format Specification § 2.2](http://geojson.org/geojson-spec.html#feature-objects)
pub struct Feature {
    geometry: Geometry,
    properties: json::Json,
}

impl ToJson for Feature {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "Feature".to_json());
        d.insert(format!("geometry"), self.geometry.to_json());
        d.insert(format!("properties"), self.properties.to_json());
        d.to_json()
    }
}
#[test]
fn test_feature_string_tojson() {
    let mut map = BTreeMap::new();
    map.insert(format!("hi"), "there".to_json());
    let point = Feature {
        geometry: Geometry::MultiPolygon(MultiPolygon {
                coordinates: vec![
                    Poly(vec![
                        Ring(vec![
                            Pos(vec![1., 2., 3.]),
                            Pos(vec![2., 4., 3.])
                        ]),
                        Ring(vec![
                            Pos(vec![3., 2., 3.]),
                            Pos(vec![2., 4., 3.])
                        ])
                    ])
                ]
            }),
    properties: map.to_json()

    };
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"geometry\":{\"coordinates\":[[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]]],\"type\":\"MultiPolygon\"},\"properties\":{\"hi\":\"there\"},\"type\":\"Feature\"}", json_string);
}
/// FeatureCollection
///
/// [GeoJSON Format Specification § 2.3](http://geojson.org/geojson-spec.html#feature-collection-objects)
pub struct FeatureCollection {
    features: Vec<Feature>,
}

impl ToJson for FeatureCollection {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "FeatureCollection".to_json());
        d.insert(format!("features"), self.features.to_json());
        d.to_json()
    }
}
#[test]
fn test_feature_collection_string_tojson() {
    let mut map = BTreeMap::new();
    map.insert(format!("hi"), "there".to_json());
    let point = FeatureCollection {
        features:vec![
          Feature {
            geometry: Geometry::MultiPolygon(MultiPolygon {
                coordinates: vec![
                    Poly(vec![
                        Ring(vec![
                            Pos(vec![1., 2., 3.]),
                            Pos(vec![2., 4., 3.])
                        ]),
                        Ring(vec![
                            Pos(vec![3., 2., 3.]),
                            Pos(vec![2., 4., 3.])
                        ])
                    ])
                ]
            }),
            properties: map.to_json()
        }
    ]};
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"features\":[{\"geometry\":{\"coordinates\":[[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]]],\"type\":\"MultiPolygon\"},\"properties\":{\"hi\":\"there\"},\"type\":\"Feature\"}],\"type\":\"FeatureCollection\"}", json_string);
}

<commit_msg>use ref instead of match<commit_after>// Copyright 2014-2015 The GeoRust Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// TODO
// generic number instead of f64 for position?

extern crate "rustc-serialize" as rustc_serialize;

use std::collections::BTreeMap;
use rustc_serialize::json::{self, ToJson, Json};

// /// ToGeoJson
// pub trait ToGeoJson {
//     // TODO: change this to return a generic GeoJSON object
//     fn to_geojson(&self) -> Geometry;
// }

/// Pos (alias for Positions)
///
/// [GeoJSON Format Specification § 2.1.1](http://geojson.org/geojson-spec.html#positions)
#[derive(RustcEncodable, Clone)]
pub struct Pos(pub Vec<f64>);

impl ToJson for Pos {
    fn to_json(&self) -> json::Json {
        let &Pos(ref nums) = self;
        nums.to_json()
    }
}

/// Ring
#[derive(RustcEncodable, Clone)]
pub struct Ring(pub Vec<Pos>);

impl ToJson for Ring {
    fn to_json(&self) -> json::Json {
       let &Ring(ref points) = self;
        points.to_json()
    }
}

/// Poly  (alias for Polygon)
#[derive(RustcEncodable, Clone)]
pub struct Poly(pub Vec<Ring>);

impl ToJson for Poly {
    fn to_json(&self) -> json::Json {
        let &Poly(ref rings) = self;
        rings.to_json()
    }
}

/// Point
///
/// [GeoJSON Format Specification § 2.1.2](http://geojson.org/geojson-spec.html#point)
#[derive(RustcEncodable, Clone)]
pub struct Point {
    pub coordinates: Pos,
}

impl ToJson for Point {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "Point".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}
#[test]
fn test_point_tojson() {
    let point = Point {coordinates: Pos(vec![1., 2., 3.])};
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"coordinates\":[1.0,2.0,3.0],\"type\":\"Point\"}", json_string);
}

/// MultiPoint
///
/// [GeoJSON Format Specification § 2.1.3](http://geojson.org/geojson-spec.html#multipoint)
#[derive(RustcEncodable, Clone)]
pub struct MultiPoint {
    pub coordinates: Vec<Pos>,
}

impl ToJson for MultiPoint {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "MultiPoint".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}
#[test]
fn test_multi_point_tojson() {
    let point = MultiPoint {coordinates: vec![Pos(vec![1., 2., 3.])]};
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"coordinates\":[[1.0,2.0,3.0]],\"type\":\"MultiPoint\"}", json_string);
}

/// LineString
///
/// [GeoJSON Format Specification § 2.1.4](http://geojson.org/geojson-spec.html#linestring)
#[derive(RustcEncodable, Clone)]
pub struct LineString {
    pub coordinates: Ring,
}

impl ToJson for LineString {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "LineString".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}

#[test]
fn test_line_string_tojson() {
    let point = LineString {coordinates: Ring(vec![Pos(vec![1., 2., 3.]), Pos(vec![2., 4., 3.])])};
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"coordinates\":[[1.0,2.0,3.0],[2.0,4.0,3.0]],\"type\":\"LineString\"}", json_string);
}
/// MultiLineString
///
/// [GeoJSON Format Specification § 2.1.5](http://geojson.org/geojson-spec.html#multilinestring)
#[derive(RustcEncodable, Clone)]
pub struct MultiLineString {
    pub coordinates: Vec<Ring>,
}

impl ToJson for MultiLineString {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "MultiLineString".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}
#[test]
fn test_multi_line_string_tojson() {
    let point = MultiLineString {coordinates: vec![
        Ring(vec![Pos(vec![1., 2., 3.]), Pos(vec![2., 4., 3.])]),
        Ring(vec![Pos(vec![3., 2., 3.]), Pos(vec![2., 4., 3.])])
        ]};
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"coordinates\":[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]],\"type\":\"MultiLineString\"}", json_string);
}

/// Polygon
///
/// [GeoJSON Format Specification § 2.1.6](http://geojson.org/geojson-spec.html#polygon)
#[derive(RustcEncodable, Clone)]
pub struct Polygon {
    pub coordinates: Poly
}
impl ToJson for Polygon {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "Polygon".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}
#[test]
fn test_polygon_string_tojson() {
    let point = Polygon {coordinates: Poly(vec![
        Ring(vec![Pos(vec![1., 2., 3.]), Pos(vec![2., 4., 3.])]),
        Ring(vec![Pos(vec![3., 2., 3.]), Pos(vec![2., 4., 3.])])
        ])};
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"coordinates\":[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]],\"type\":\"Polygon\"}", json_string);
}

/// MultiPolygon
///
/// [GeoJSON Format Specification § 2.1.7](http://geojson.org/geojson-spec.html#multipolygon)
#[derive(RustcEncodable, Clone)]
pub struct MultiPolygon {
    pub coordinates: Vec<Poly>,
}

impl ToJson for MultiPolygon {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "MultiPolygon".to_json());
        d.insert(format!("coordinates"), self.coordinates.to_json());
        d.to_json()
    }
}
#[test]
fn test_multi_polygon_string_tojson() {
    let point = MultiPolygon {coordinates: vec![Poly(vec![
        Ring(vec![Pos(vec![1., 2., 3.]), Pos(vec![2., 4., 3.])]),
        Ring(vec![Pos(vec![3., 2., 3.]), Pos(vec![2., 4., 3.])])
        ])]};
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"coordinates\":[[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]]],\"type\":\"MultiPolygon\"}", json_string);
}

/// Geometry
#[derive(RustcEncodable, Clone)]
pub enum Geometry {
    Point(Point),
    MultiPoint(MultiPoint),
    LineString(LineString),
    MultiLineString(MultiLineString),
    Polygon(Polygon),
    MultiPolygon(MultiPolygon),
    GeometryCollection(GeometryCollection),
}

impl ToJson for Geometry {
    fn to_json(&self) -> json::Json {
        match *self {
            Geometry::Point(ref geom) => geom.to_json(),
            Geometry::MultiPoint(ref geom) => geom.to_json(),
            Geometry::LineString(ref geom) => geom.to_json(),
            Geometry::MultiLineString(ref geom) => geom.to_json(),
            Geometry::Polygon(ref geom) => geom.to_json(),
            Geometry::MultiPolygon(ref geom) => geom.to_json(),
            Geometry::GeometryCollection(ref geom) => geom.to_json(),
        }
    }
}
/// GeometryCollection
///
/// [GeoJSON Format Specification § 2.1.8](http://geojson.org/geojson-spec.html#geometry-collection)
#[derive(RustcEncodable, Clone)]
pub struct GeometryCollection {
    geometries: Vec<Geometry>,
}

impl ToJson for GeometryCollection {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "GeometryCollection".to_json());
        d.insert(format!("geometries"), self.geometries.to_json());
        d.to_json()
    }
}
#[test]
fn test_geometry_collection_string_tojson() {
    let point = GeometryCollection {
        geometries: vec![Geometry::MultiPolygon(MultiPolygon {
                    coordinates: vec![
                        Poly(vec![
                            Ring(vec![
                                Pos(vec![1., 2., 3.]),
                                Pos(vec![2., 4., 3.])
                            ]),
                            Ring(vec![
                                Pos(vec![3., 2., 3.]),
                                Pos(vec![2., 4., 3.])
                            ])
                        ])
                    ]
                })
        ]
    };
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"geometries\":[{\"coordinates\":[[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]]],\"type\":\"MultiPolygon\"}],\"type\":\"GeometryCollection\"}", json_string);
}
/// Feature
///
/// [GeoJSON Format Specification § 2.2](http://geojson.org/geojson-spec.html#feature-objects)
pub struct Feature {
    geometry: Geometry,
    properties: json::Json,
}

impl ToJson for Feature {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "Feature".to_json());
        d.insert(format!("geometry"), self.geometry.to_json());
        d.insert(format!("properties"), self.properties.to_json());
        d.to_json()
    }
}
#[test]
fn test_feature_string_tojson() {
    let mut map = BTreeMap::new();
    map.insert(format!("hi"), "there".to_json());
    let point = Feature {
        geometry: Geometry::MultiPolygon(MultiPolygon {
                coordinates: vec![
                    Poly(vec![
                        Ring(vec![
                            Pos(vec![1., 2., 3.]),
                            Pos(vec![2., 4., 3.])
                        ]),
                        Ring(vec![
                            Pos(vec![3., 2., 3.]),
                            Pos(vec![2., 4., 3.])
                        ])
                    ])
                ]
            }),
    properties: map.to_json()

    };
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"geometry\":{\"coordinates\":[[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]]],\"type\":\"MultiPolygon\"},\"properties\":{\"hi\":\"there\"},\"type\":\"Feature\"}", json_string);
}
/// FeatureCollection
///
/// [GeoJSON Format Specification § 2.3](http://geojson.org/geojson-spec.html#feature-collection-objects)
pub struct FeatureCollection {
    features: Vec<Feature>,
}

impl ToJson for FeatureCollection {
    fn to_json(&self) -> json::Json {
        let mut d = BTreeMap::new();
        d.insert(format!("type"), "FeatureCollection".to_json());
        d.insert(format!("features"), self.features.to_json());
        d.to_json()
    }
}
#[test]
fn test_feature_collection_string_tojson() {
    let mut map = BTreeMap::new();
    map.insert(format!("hi"), "there".to_json());
    let point = FeatureCollection {
        features:vec![
          Feature {
            geometry: Geometry::MultiPolygon(MultiPolygon {
                coordinates: vec![
                    Poly(vec![
                        Ring(vec![
                            Pos(vec![1., 2., 3.]),
                            Pos(vec![2., 4., 3.])
                        ]),
                        Ring(vec![
                            Pos(vec![3., 2., 3.]),
                            Pos(vec![2., 4., 3.])
                        ])
                    ])
                ]
            }),
            properties: map.to_json()
        }
    ]};
    let json_string = format!("{}",point.to_json());
    assert_eq!("{\"features\":[{\"geometry\":{\"coordinates\":[[[[1.0,2.0,3.0],[2.0,4.0,3.0]],[[3.0,2.0,3.0],[2.0,4.0,3.0]]]],\"type\":\"MultiPolygon\"},\"properties\":{\"hi\":\"there\"},\"type\":\"Feature\"}],\"type\":\"FeatureCollection\"}", json_string);
}

<|endoftext|>


<commit_before>#![crate_name="linenoise"]
#![crate_type="lib"]

//! This is a library that interfaces with the linenoise library.
//! [Linenoise](https://github.com/antirez/linenoise) is a library implemented by Antirez, the Redis creator as a
//! replacement for readline.
//!
//! This library is just a binding to this library.
//!
//! ```rust
//! extern crate linenoise;
//! fn callback(input: &str) -> Vec<String> {
//!   let mut ret : Vec<&str>;
//!    if input.starts_with("s") {
//!     ret = vec!["suggestion", "suggestion2", "suggestion-three"];
//!   } else {
//!     ret = vec!["wot"];
//!   }
//!
//!     return ret.iter().map(|s| s.to_string()).collect();
//! }
//!
//! fn main() {
//!   linenoise::set_callback(callback);
//!
//!     loop {
//!       let val = linenoise::input("hello > ");
//!         match val {
//!             None => { break }
//!             Some(input) => {
//!                 println!("> {}", input);
//!                 linenoise::history_add(input.as_slice());
//!                 if input.as_slice() == "clear" {
//!                   linenoise::clear_screen();
//!                 }
//!             }
//!         }
//!     }
//! }
//! ```

extern crate libc;

use std::ffi::CString;
use std::ffi::CStr;
use std::str;

pub mod ffi;

pub type Completions = ffi::Struct_linenoiseCompletions;
type Callback = ffi::linenoiseCompletionCallback;

pub type CompletionCallback = fn(&str) -> Vec<String>;
static mut USER_COMPLETION: Option<CompletionCallback> = None;

/// Sets the callback when tab is pressed
pub fn set_callback(rust_cb: CompletionCallback ) {
    unsafe {
        USER_COMPLETION = Some(rust_cb);
        let ca = internal_callback as *mut _;
        ffi::linenoiseSetCompletionCallback(ca);
    }
}

/// Shows the prompt with your prompt as prefix
/// Retuns the typed string or None is nothing or EOF
pub fn input(prompt: &str) -> Option<String> {
    let cprompt = CString::new(prompt.as_bytes()).unwrap();

    unsafe {
        let cs = cprompt.as_ptr();
        let rret = ffi::linenoise(cs);

        let rval = if rret != 0 as *mut i8 {
            let ptr = rret as *const i8;
            let cast = str::from_utf8(CStr::from_ptr(ptr).to_bytes()).unwrap().to_string();
            Some(cast)
        } else {
            None
        };
        return rval;
    }
}

/// Add this string to the history
pub fn history_add(line: &str) -> i32 {
    let cs = CString::new(line).unwrap().as_ptr();
    let ret: i32;
    unsafe {
        ret = ffi::linenoiseHistoryAdd(cs);
    }
    ret
}

/// Set max length history
pub fn history_set_max_len(len: i32) -> i32 {
    let ret: i32;
    unsafe {
        ret = ffi::linenoiseHistorySetMaxLen(len);
    }
    ret
}

/// Save the history on disk
pub fn history_save(file: &str) -> i32 {
    let fname = CString::new(file).unwrap().as_ptr();
    let ret: i32;
    unsafe {
        ret = ffi::linenoiseHistorySave(fname);
    }
    ret
}

/// Load the history on disk
pub fn history_load(file: &str) -> i32 {
    let fname = CString::new(file).unwrap().as_ptr();
    let ret: i32;
    unsafe {
        ret = ffi::linenoiseHistoryLoad(fname);
    }
    ret
}

///Clears the screen
pub fn clear_screen() {
    unsafe {
        ffi::linenoiseClearScreen();
    }
}

pub fn set_multiline(ml: i32) {
    unsafe {
        ffi::linenoiseSetMultiLine(ml);
    }
}

pub fn print_key_codes() {
    unsafe {
        ffi::linenoisePrintKeyCodes();
    }
}

/// Add a completion to the current list of completions.
pub fn add_completion(c: *mut Completions, s: &str) {
    unsafe {
        ffi::linenoiseAddCompletion(c, CString::new(s).unwrap().as_ptr());
    }
}

fn internal_callback(cs: *mut libc::c_char, lc:*mut Completions ) {
    unsafe {
        (*lc).len = 0;
    }
    let cr = cs as *const _;

    unsafe {
        let input = str::from_utf8(CStr::from_ptr(cr).to_bytes()).unwrap();
        for external_callback in USER_COMPLETION.iter() {
            let ret = (*external_callback)(input);
            for x in ret.iter() {
                add_completion(lc, x.as_ref());
            }
        }
    }
}
<commit_msg>Free pointer returned from linenoise() with libc::free().<commit_after>#![crate_name="linenoise"]
#![crate_type="lib"]

//! This is a library that interfaces with the linenoise library.
//! [Linenoise](https://github.com/antirez/linenoise) is a library implemented by Antirez, the Redis creator as a
//! replacement for readline.
//!
//! This library is just a binding to this library.
//!
//! ```rust
//! extern crate linenoise;
//! fn callback(input: &str) -> Vec<String> {
//!   let mut ret : Vec<&str>;
//!    if input.starts_with("s") {
//!     ret = vec!["suggestion", "suggestion2", "suggestion-three"];
//!   } else {
//!     ret = vec!["wot"];
//!   }
//!
//!     return ret.iter().map(|s| s.to_string()).collect();
//! }
//!
//! fn main() {
//!   linenoise::set_callback(callback);
//!
//!     loop {
//!       let val = linenoise::input("hello > ");
//!         match val {
//!             None => { break }
//!             Some(input) => {
//!                 println!("> {}", input);
//!                 linenoise::history_add(input.as_slice());
//!                 if input.as_slice() == "clear" {
//!                   linenoise::clear_screen();
//!                 }
//!             }
//!         }
//!     }
//! }
//! ```

extern crate libc;

use std::ffi::CString;
use std::ffi::CStr;
use std::str;

pub mod ffi;

pub type Completions = ffi::Struct_linenoiseCompletions;
type Callback = ffi::linenoiseCompletionCallback;

pub type CompletionCallback = fn(&str) -> Vec<String>;
static mut USER_COMPLETION: Option<CompletionCallback> = None;

/// Sets the callback when tab is pressed
pub fn set_callback(rust_cb: CompletionCallback ) {
    unsafe {
        USER_COMPLETION = Some(rust_cb);
        let ca = internal_callback as *mut _;
        ffi::linenoiseSetCompletionCallback(ca);
    }
}

/// Shows the prompt with your prompt as prefix
/// Retuns the typed string or None is nothing or EOF
pub fn input(prompt: &str) -> Option<String> {
    let cprompt = CString::new(prompt.as_bytes()).unwrap();

    unsafe {
        let cs = cprompt.as_ptr();
        let rret = ffi::linenoise(cs);

        let rval = if rret != 0 as *mut i8 {
            let ptr = rret as *const i8;
            let cast = str::from_utf8(CStr::from_ptr(ptr).to_bytes()).unwrap().to_string();
            libc::free(ptr as *mut libc::c_void);
            Some(cast)
        } else {
            None
        };
        return rval;
    }
}

/// Add this string to the history
pub fn history_add(line: &str) -> i32 {
    let cs = CString::new(line).unwrap().as_ptr();
    let ret: i32;
    unsafe {
        ret = ffi::linenoiseHistoryAdd(cs);
    }
    ret
}

/// Set max length history
pub fn history_set_max_len(len: i32) -> i32 {
    let ret: i32;
    unsafe {
        ret = ffi::linenoiseHistorySetMaxLen(len);
    }
    ret
}

/// Save the history on disk
pub fn history_save(file: &str) -> i32 {
    let fname = CString::new(file).unwrap().as_ptr();
    let ret: i32;
    unsafe {
        ret = ffi::linenoiseHistorySave(fname);
    }
    ret
}

/// Load the history on disk
pub fn history_load(file: &str) -> i32 {
    let fname = CString::new(file).unwrap().as_ptr();
    let ret: i32;
    unsafe {
        ret = ffi::linenoiseHistoryLoad(fname);
    }
    ret
}

///Clears the screen
pub fn clear_screen() {
    unsafe {
        ffi::linenoiseClearScreen();
    }
}

pub fn set_multiline(ml: i32) {
    unsafe {
        ffi::linenoiseSetMultiLine(ml);
    }
}

pub fn print_key_codes() {
    unsafe {
        ffi::linenoisePrintKeyCodes();
    }
}

/// Add a completion to the current list of completions.
pub fn add_completion(c: *mut Completions, s: &str) {
    unsafe {
        ffi::linenoiseAddCompletion(c, CString::new(s).unwrap().as_ptr());
    }
}

fn internal_callback(cs: *mut libc::c_char, lc:*mut Completions ) {
    unsafe {
        (*lc).len = 0;
    }
    let cr = cs as *const _;

    unsafe {
        let input = str::from_utf8(CStr::from_ptr(cr).to_bytes()).unwrap();
        for external_callback in USER_COMPLETION.iter() {
            let ret = (*external_callback)(input);
            for x in ret.iter() {
                add_completion(lc, x.as_ref());
            }
        }
    }
}
<|endoftext|>


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

extern crate chrono;
extern crate uuid;

use chrono::{ NaiveDate, NaiveTime, Datelike };
use chrono::Weekday as ChronoWeekday;

use uuid::Uuid;

use std::fmt::{ Show, Formatter, FormatError };

mod validate;

pub struct LeagueSpec {
    pub teams: Vec<IdAndName>,
    pub locations: Vec<IdAndName>,
    pub start_date: Date,
    pub end_date: Date,
    pub game_weekday: GameWeekday
}

#[deriving(Show, Clone)]
pub struct IdAndName {
    pub id: String,
    pub name: String
}

#[deriving(Show, Clone)]
pub struct Time {
    pub hour: u8,
    pub min: u8
}

impl Time {
    fn to_naive_time_opt(self) -> Option<NaiveTime> {
        NaiveTime::from_hms_opt(self.hour as u32, self.min as u32, 0)
    }
}

#[deriving(Show, Eq, PartialEq, Clone)]
pub struct Date {
    pub day: u8,
    pub month: u8,
    pub year: u16
}

impl Date {
    fn to_naive_date_opt(self) -> Option<NaiveDate> {
        NaiveDate::from_ymd_opt(
            self.year as i32,
            self.month as u32,
            self.day as u32
        )
    }

    fn from_naive_date(naive_date: &NaiveDate) -> Date {
        Date {
            year: naive_date.year() as u16,
            month: naive_date.month() as u8,
            day: naive_date.day() as u8
        }
    }
}

pub struct GameWeekday {
    pub day: Weekday,
    pub game_times: Vec<GameTime>
}

pub struct GameTime {
    pub time: Time,
    pub location_ids: Vec<String>
}

pub enum Weekday {
    Sunday,
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday
}

impl Weekday {

    pub fn to_chrono_weekday(&self) -> ChronoWeekday {
        match *self {
            Sunday => chrono::Sun,
            Monday => chrono::Mon,
            Tuesday => chrono::Tue,
            Wednesday => chrono::Wed,
            Thursday => chrono::Thu,
            Friday => chrono::Fri,
            Saturday => chrono::Sat
        }
    }

    pub fn from_chrono_weekday(chrono_weekday: ChronoWeekday) -> Weekday {
        match chrono_weekday {
            chrono::Sun => Sunday,
            chrono::Mon => Monday,
            chrono::Tue => Tuesday,
            chrono::Wed => Wednesday,
            chrono::Thu => Thursday,
            chrono::Fri => Friday,
            chrono::Sat => Saturday
        }
    }
}

#[deriving(Clone)]
pub struct GameShell {
    pub date: Date,
    pub time: Time,
    pub location: IdAndName
}

impl Show for GameShell {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
        write!(f, "{}:{:02} {:04}-{:02}-{:02} at {} (id: {})",
            self.time.hour, self.time.min,
            self.date.year, self.date.month, self.date.day,
            self.location.name, self.location.id)
    }
}

pub enum TeamEvent {
    Game(IdAndName, IdAndName, Date, Time, IdAndName),
    Bye(IdAndName, Date)
}

pub fn generate_games(spec: &LeagueSpec) -> Result<Vec<TeamEvent>, Vec<&'static str>> {
    let errors = validate::validate(spec);
    if errors.len() > 0 {
        return Err(errors);
    }

    let game_shells = generate_shells(spec);

    // Create a new list of teams which includes our fake bye team if needed
    let mut teams = spec.teams.clone();
    let mut bye_id: Option<String> = None;
    let generated_uuid = Uuid::new_v4().to_hyphenated_string();
    if teams.len() % 2 == 1 {
        bye_id = Some(generated_uuid.clone());
        teams.push(IdAndName {
            name: String::from_str("Bye team"),
            id: generated_uuid
        });
    }
    let teams = teams;
    let bye_id = bye_id;

    let round_robin = generate_round_robin(&teams);

    println!("thing: {0}", game_shells.len());

    for rotation in game_shells.as_slice().chunks((teams.len() - 1) * (spec.teams.len() / 2)) {
        println!("rotation size: {0}", rotation.len());
        println!("New Rotation");
        for round in rotation.as_slice().chunks(spec.teams.len() / 2) {
            println!("\tNew Round");
            for shell in round.iter() {
                println!("\t\t{0}", shell);
            }
        }
    }

    Ok(vec!())
}

fn generate_round_robin(teams: &Vec<IdAndName>) -> Vec<Vec<(&IdAndName, &IdAndName)>> {
    let static_team: &IdAndName = &teams[0];
    let mut other_teams: Vec<&IdAndName> = teams.iter().skip(1).collect();

    let mut result: Vec<Vec<(&IdAndName, &IdAndName)>> = Vec::new();

    for _ in range(0u, teams.len() - 1) {
        let mut session: Vec<(&IdAndName, &IdAndName)> = Vec::new();
        session.push((other_teams[0], static_team));
        for i in range(0u, (other_teams.len() - 1) / 2) {
            let team_1: &IdAndName = other_teams[i+1];
            let team_2: &IdAndName = other_teams[other_teams.len() - 1 - i];
            session.push((team_1, team_2));
        }

        // Rotate other_teams
        let temp = other_teams[0];
        for i in range(0u, other_teams.len() - 1) {
            other_teams[i] = other_teams[i + 1];
        }
        other_teams[other_teams.len() - 1] = temp;

        result.push(session)
    }

    result
}

fn generate_shells(spec: &LeagueSpec) -> Vec<GameShell> {
    let games_per_night = spec.teams.len() as u8 / 2;

    let mut result: Vec<GameShell> = vec![];

    let start_date = spec.start_date.to_naive_date_opt().unwrap();
    let end_date = spec.end_date.to_naive_date_opt().unwrap();

    let mut i_date = start_date.clone();
    while i_date != end_date.succ() {
        if spec.game_weekday.day.to_chrono_weekday() == i_date.weekday() {
            let mut num_games = 0u8;
            for time in spec.game_weekday.game_times.iter() {
                for location in time.location_ids.iter() {
                    if num_games != games_per_night {
                        result.push( GameShell {
                            date: Date::from_naive_date(&i_date),
                            time: time.time,
                            location: spec.locations.iter().find(|loc| loc.id == *location).unwrap().clone()
                        });
                        num_games += 1;
                    }
                }
            }
        }
        i_date = i_date.succ();
    }

    result
}
<commit_msg>made it work! FRANKENSTEIN<commit_after>#![crate_name = "schedule_gen"]

extern crate chrono;
extern crate uuid;

use chrono::{ NaiveDate, NaiveTime, Datelike };
use chrono::Weekday as ChronoWeekday;

use uuid::Uuid;

use std::fmt::{ Show, Formatter, FormatError };
use std::rand::{task_rng, Rng};

mod validate;

pub struct LeagueSpec {
    pub teams: Vec<IdAndName>,
    pub locations: Vec<IdAndName>,
    pub start_date: Date,
    pub end_date: Date,
    pub game_weekday: GameWeekday
}

#[deriving(Show, Clone)]
pub struct IdAndName {
    pub id: String,
    pub name: String
}

#[deriving(Show, Clone)]
pub struct Time {
    pub hour: u8,
    pub min: u8
}

impl Time {
    fn to_naive_time_opt(self) -> Option<NaiveTime> {
        NaiveTime::from_hms_opt(self.hour as u32, self.min as u32, 0)
    }
}

#[deriving(Show, Eq, PartialEq, Clone)]
pub struct Date {
    pub day: u8,
    pub month: u8,
    pub year: u16
}

impl Date {
    fn to_naive_date_opt(self) -> Option<NaiveDate> {
        NaiveDate::from_ymd_opt(
            self.year as i32,
            self.month as u32,
            self.day as u32
        )
    }

    fn from_naive_date(naive_date: &NaiveDate) -> Date {
        Date {
            year: naive_date.year() as u16,
            month: naive_date.month() as u8,
            day: naive_date.day() as u8
        }
    }
}

pub struct GameWeekday {
    pub day: Weekday,
    pub game_times: Vec<GameTime>
}

pub struct GameTime {
    pub time: Time,
    pub location_ids: Vec<String>
}

pub enum Weekday {
    Sunday,
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday
}

impl Weekday {

    pub fn to_chrono_weekday(&self) -> ChronoWeekday {
        match *self {
            Sunday => chrono::Sun,
            Monday => chrono::Mon,
            Tuesday => chrono::Tue,
            Wednesday => chrono::Wed,
            Thursday => chrono::Thu,
            Friday => chrono::Fri,
            Saturday => chrono::Sat
        }
    }

    pub fn from_chrono_weekday(chrono_weekday: ChronoWeekday) -> Weekday {
        match chrono_weekday {
            chrono::Sun => Sunday,
            chrono::Mon => Monday,
            chrono::Tue => Tuesday,
            chrono::Wed => Wednesday,
            chrono::Thu => Thursday,
            chrono::Fri => Friday,
            chrono::Sat => Saturday
        }
    }
}

#[deriving(Clone)]
pub struct GameShell {
    pub date: Date,
    pub time: Time,
    pub location: IdAndName
}

impl Show for GameShell {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> {
        write!(f, "{}:{:02} {:04}-{:02}-{:02} at {} (id: {})",
            self.time.hour, self.time.min,
            self.date.year, self.date.month, self.date.day,
            self.location.name, self.location.id)
    }
}

pub enum TeamEvent {
    Game(IdAndName, IdAndName, Date, Time, IdAndName),
    Bye(IdAndName, Date)
}

pub fn generate_games(spec: &LeagueSpec) -> Result<Vec<TeamEvent>, Vec<&'static str>> {
    let errors = validate::validate(spec);
    if errors.len() > 0 {
        return Err(errors);
    }

    let game_shells = generate_shells(spec);

    // Create a new list of teams which includes our fake bye team if needed
    let mut teams = spec.teams.clone();
    let mut bye_id_opt: Option<String> = None;
    let generated_uuid = Uuid::new_v4().to_hyphenated_string();
    if teams.len() % 2 == 1 {
        bye_id_opt = Some(generated_uuid.clone());
        teams.push(IdAndName {
            name: String::from_str("Bye team"),
            id: generated_uuid
        });
    }
    let teams = teams;
    let bye_id_opt: Option<String> = bye_id_opt;

    let mut round_robin = generate_round_robin(&teams);
    let mut rng = task_rng();

    for rotation in game_shells.as_slice().chunks((teams.len() - 1) * (spec.teams.len() / 2)) {
        println!("New Rotation");
        rng.shuffle(round_robin.as_mut_slice());
        for shells_teams in rotation.as_slice().chunks(spec.teams.len() / 2).zip(round_robin.iter_mut()) {
            let (shells, teams) = shells_teams;
            rng.shuffle(teams.as_mut_slice());
            println!("\tNew Week");
            let non_byes = match bye_id_opt {
                Some(ref bye_id) => {
                    let bye_pair = teams.iter().find(|pair| pair.val0().id == *bye_id || pair.val1().id == *bye_id).unwrap();
                    if bye_pair.val0().id == *bye_id {
                        println!("\t\t{0} has bye", bye_pair.val1());
                    } else {
                        println!("\t\t{0} has bye", bye_pair.val0());
                    }
                    teams.iter().filter(|pair| pair.val0().id != *bye_id && pair.val1().id != *bye_id).collect::<Vec<_>>()
                }
                None => teams.iter().collect::<Vec<_>>()
            };
            for shell_team in shells.iter().zip(non_byes.iter()) {
                let (shell, team) = shell_team;
                println!("\t\t{0}|{1}", shell, team)
            }
        }
    }

    Ok(vec!())
}

fn generate_round_robin(teams: &Vec<IdAndName>) -> Vec<Vec<(&IdAndName, &IdAndName)>> {
    let static_team: &IdAndName = &teams[0];
    let mut other_teams: Vec<&IdAndName> = teams.iter().skip(1).collect();

    let mut result: Vec<Vec<(&IdAndName, &IdAndName)>> = Vec::new();

    for _ in range(0u, teams.len() - 1) {
        let mut session: Vec<(&IdAndName, &IdAndName)> = Vec::new();
        session.push((other_teams[0], static_team));
        for i in range(0u, (other_teams.len() - 1) / 2) {
            let team_1: &IdAndName = other_teams[i+1];
            let team_2: &IdAndName = other_teams[other_teams.len() - 1 - i];
            session.push((team_1, team_2));
        }

        // Rotate other_teams
        let temp = other_teams[0];
        for i in range(0u, other_teams.len() - 1) {
            other_teams[i] = other_teams[i + 1];
        }
        let other_teams_len = other_teams.len() - 1;
        other_teams[other_teams_len] = temp;

        result.push(session)
    }

    result
}

fn generate_shells(spec: &LeagueSpec) -> Vec<GameShell> {
    let games_per_night = spec.teams.len() as u8 / 2;

    let mut result: Vec<GameShell> = vec![];

    let start_date = spec.start_date.to_naive_date_opt().unwrap();
    let end_date = spec.end_date.to_naive_date_opt().unwrap();

    let mut i_date = start_date.clone();
    while i_date != end_date.succ() {
        if spec.game_weekday.day.to_chrono_weekday() == i_date.weekday() {
            let mut num_games = 0u8;
            for time in spec.game_weekday.game_times.iter() {
                for location in time.location_ids.iter() {
                    if num_games != games_per_night {
                        result.push( GameShell {
                            date: Date::from_naive_date(&i_date),
                            time: time.time,
                            location: spec.locations.iter().find(|loc| loc.id == *location).unwrap().clone()
                        });
                        num_games += 1;
                    }
                }
            }
        }
        i_date = i_date.succ();
    }

    result
}
<|endoftext|>


<commit_before>#![crate_name = "gtk"]
#![allow(non_camel_case_types)]

extern crate libc;

use std::ffi as r_ffi;
use std::mem;
use std::ptr;
use std::str;

use ffi::*;

pub mod ffi;

unsafe fn init_something_with_args(args: Vec<String>,
        f: unsafe extern "C" fn(*mut libc::c_int, *mut *mut *mut i8)) -> Vec<String> {
    // This vec is used to store the CStrings while we make them available to the ffi
    // for parsing.
    let c_args: Vec<r_ffi::CString> =
        args.iter().map(|s| { r_ffi::CString::from_slice(s.as_bytes()) }).collect();
    let mut args_n: i32 = args.len() as i32;
    let mut args_v =
        libc::malloc((std::mem::size_of::<*mut i8>() * args.len() + 1) as libc::size_t)
        as *mut *mut libc::c_char;

    for i in 0..args_n {
        // This is so unsafe... but we know that the c_args array
        // lives longer than the containing args_vec backing memory
        *args_v.offset(i as isize) = c_args[i as usize].as_slice_with_nul().as_ptr() as *mut _;
    }

    f(&mut args_n, &mut args_v);

    let mut new_args = Vec::new();
    {
        for i in 0..args_n {
            let arg = *args_v.offset(i as isize) as *const libc::c_char;
            let slice = r_ffi::c_str_to_bytes(&arg);
            new_args.push(str::from_utf8(slice).unwrap().to_string());
        }
    }

    libc::free(mem::transmute(args_v));

    new_args.into_iter().collect()
}

/// Returns the modified command line arguments
pub unsafe fn gtk_init_with_args_2(args: Vec<String>) -> Vec<String> {
    init_something_with_args(args, gtk_init)
}

pub unsafe fn gst_init_with_args(args: Vec<String>) -> Vec<String> {
    // clang deficiency, doesn't correctly encode `**argv[]` params
    init_something_with_args(args, gst_init)
}

pub unsafe fn g_signal_connect(instance: gpointer, detailed_signal: *const gchar,
                               c_handler: GCallback, data: gpointer) -> gulong {
    g_signal_connect_data(instance, detailed_signal, c_handler,
                          data, None, 0)
}

pub struct GListIterator<'a> {
    current: Option<&'a Struct__GList>,
}

impl <'a> GListIterator<'a> {
    pub fn new(glist: &'a GList) -> GListIterator<'a> {
        GListIterator {
            current: Some(glist)
        }
    }
}

impl <'a> Iterator for GListIterator<'a> {
    type Item = gpointer;

    fn next(&mut self) -> Option<gpointer> {
        if self.current.is_none() {
            return None;
        }

        let next = self.current.unwrap().next;
        if next != ptr::null_mut() {
            unsafe {
                self.current = mem::transmute(next);
                Some((*next).data)
            }
        } else {
            self.current = None;
            None
        }
    }
}
<commit_msg>update for cstring changes<commit_after>#![crate_name = "gtk"]
#![allow(non_camel_case_types)]

extern crate libc;

use std::ffi as r_ffi;
use std::mem;
use std::ptr;
use std::str;

use ffi::*;

pub mod ffi;

unsafe fn init_something_with_args(args: Vec<String>,
        f: unsafe extern "C" fn(*mut libc::c_int, *mut *mut *mut i8)) -> Vec<String> {
    // This vec is used to store the CStrings while we make them available to the ffi
    // for parsing.
    let c_args: Vec<r_ffi::CString> =
        args.iter().map(|s| { r_ffi::CString::new(s.as_bytes()).unwrap() }).collect();
    let mut args_n: i32 = args.len() as i32;
    let mut args_v =
        libc::malloc((std::mem::size_of::<*mut i8>() * args.len() + 1) as libc::size_t)
        as *mut *mut libc::c_char;

    for i in 0..args_n {
        // This is so unsafe... but we know that the c_args array
        // lives longer than the containing args_vec backing memory
        *args_v.offset(i as isize) = c_args[i as usize].as_bytes_with_nul().as_ptr() as *mut _;
    }

    f(&mut args_n, &mut args_v);

    let mut new_args = Vec::new();
    for i in 0..args_n {
        let arg = *args_v.offset(i as isize) as *const libc::c_char;
        let slice = r_ffi::CStr::from_ptr(arg).to_bytes();
        new_args.push(str::from_utf8(slice).unwrap().to_string());
    }

    libc::free(mem::transmute(args_v));

    new_args.into_iter().collect()
}

/// Returns the modified command line arguments
pub unsafe fn gtk_init_with_args_2(args: Vec<String>) -> Vec<String> {
    init_something_with_args(args, gtk_init)
}

pub unsafe fn gst_init_with_args(args: Vec<String>) -> Vec<String> {
    // clang deficiency, doesn't correctly encode `**argv[]` params
    init_something_with_args(args, gst_init)
}

pub unsafe fn g_signal_connect(instance: gpointer, detailed_signal: *const gchar,
                               c_handler: GCallback, data: gpointer) -> gulong {
    g_signal_connect_data(instance, detailed_signal, c_handler,
                          data, None, 0)
}

pub struct GListIterator<'a> {
    current: Option<&'a Struct__GList>,
}

impl <'a> GListIterator<'a> {
    pub fn new(glist: &'a GList) -> GListIterator<'a> {
        GListIterator {
            current: Some(glist)
        }
    }
}

impl <'a> Iterator for GListIterator<'a> {
    type Item = gpointer;

    fn next(&mut self) -> Option<gpointer> {
        if self.current.is_none() {
            return None;
        }

        let next = self.current.unwrap().next;
        if next != ptr::null_mut() {
            unsafe {
                self.current = mem::transmute(next);
                Some((*next).data)
            }
        } else {
            self.current = None;
            None
        }
    }
}
<|endoftext|>


<commit_before>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;
use std::hash::Hash;
use std::fmt::Show;

pub use self::typemap::TypeMap;
mod typemap;

#[deriving(PartialEq, Show, Clone)]
pub enum Scheme {
    Http,
    Https
}

#[deriving(PartialEq, Show, Clone)]
pub enum Host<'a> {
    Name(&'a str),
    Ip(IpAddr)
}

#[deriving(PartialEq, Hash, Eq, Show, Clone)]
pub enum Method {
    Get,
    Post,
    Put,
    Delete,
    Head,
    Connect,
    Options,
    Trace,

    // RFC-5789
    Patch,
    Purge,

    // WebDAV, Subversion, UPNP
    Other(&'static str)
}

/// A Dictionary for extensions provided by the server or middleware
pub type Extensions = TypeMap;

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method(&self) -> Method;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// The request's headers, as conduit::Headers.
    fn headers<'a>(&'a self) -> &'a Headers;

    /// A Reader for the body of the request
    fn body<'a>(&'a mut self) -> &'a mut Reader;

    /// A readable map of extensions
    fn extensions<'a>(&'a self) -> &'a Extensions;

    /// A mutable map of extensions
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions;
}

pub trait Headers {
    /// Find the value of a given header. Multi-line headers are represented
    /// as an array.
    fn find(&self, key: &str) -> Option<Vec<&str>>;

    /// Returns true if a particular header exists
    fn has(&self, key: &str) -> bool;

    /// Iterate over all of the available headers.
    fn all(&self) -> Vec<(&str, Vec<&str>)>;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, Vec<String>>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

/// A Handler takes a request and returns a response or an error.
/// By default, a bare function implements `Handler`.
pub trait Handler : Sync + Send {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show + 'static>>;
}

impl<T: Send + Sync + Show> Handler for fn(&mut Request) -> Result<Response, T> {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show + 'static>> {
        { (*self)(request) }.map_err(|e| box e as Box<Show + 'static>)
    }
}
<commit_msg>Update to rust master<commit_after>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;
use std::hash::Hash;
use std::fmt::Show;

pub use self::typemap::TypeMap;
mod typemap;

#[deriving(PartialEq, Show, Clone, Copy)]
pub enum Scheme {
    Http,
    Https
}

#[deriving(PartialEq, Show, Clone, Copy)]
pub enum Host<'a> {
    Name(&'a str),
    Ip(IpAddr)
}

#[deriving(PartialEq, Hash, Eq, Show, Clone, Copy)]
pub enum Method {
    Get,
    Post,
    Put,
    Delete,
    Head,
    Connect,
    Options,
    Trace,

    // RFC-5789
    Patch,
    Purge,

    // WebDAV, Subversion, UPNP
    Other(&'static str)
}

/// A Dictionary for extensions provided by the server or middleware
pub type Extensions = TypeMap;

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method(&self) -> Method;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// The request's headers, as conduit::Headers.
    fn headers<'a>(&'a self) -> &'a Headers;

    /// A Reader for the body of the request
    fn body<'a>(&'a mut self) -> &'a mut Reader;

    /// A readable map of extensions
    fn extensions<'a>(&'a self) -> &'a Extensions;

    /// A mutable map of extensions
    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions;
}

pub trait Headers {
    /// Find the value of a given header. Multi-line headers are represented
    /// as an array.
    fn find(&self, key: &str) -> Option<Vec<&str>>;

    /// Returns true if a particular header exists
    fn has(&self, key: &str) -> bool;

    /// Iterate over all of the available headers.
    fn all(&self) -> Vec<(&str, Vec<&str>)>;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, Vec<String>>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

/// A Handler takes a request and returns a response or an error.
/// By default, a bare function implements `Handler`.
pub trait Handler : Sync + Send {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show + 'static>>;
}

impl<T: Send + Sync + Show> Handler for fn(&mut Request) -> Result<Response, T> {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show + 'static>> {
        { (*self)(request) }.map_err(|e| box e as Box<Show + 'static>)
    }
}
<|endoftext|>


<commit_before>//! Fluent test assertions in Rust
//!
//! Spectral is a testing framework designed to make your assertions read like plain English.
//! This allows you to more easily expose the intent of your test, rather than having it shrouded by
//! assertions which work, but are opaque on their meaning.
//!
//! Methods available to assert with are dependent upon the type of the subject under test.
//! Assertions are available for some basic types, but there is still a great deal missing from the
//! standard library.
//!
//! ## Usage
//!
//! Add the dependency to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! spectral = "0.2.0"
//! ```
//!
//! Then add this to your crate:
//!
//! ```rust
//! extern crate spectral;
//! ```
//!
//! If you want macro support, include `#[macro_use]` to the declaration:
//!
//! ```rust,ignore
//! #[macro_use]
//! extern crate spectral;
//! ```
//!
//! To quickly start using assertions, `use` the prelude module:
//!
//! ```rust
//! use spectral::prelude::*;
//! ```
//!
//! ## Example
//!
//! We're going to make a few assertions on a `String` we create. Normally you would
//! want to assert on the output of something, but we'll just pretend that something created it.
//!
//! First, we'll create a new test with our `String`.
//!
//! ```rust
//! #[test]
//! pub fn should_be_the_correct_string() {
//!     let subject = "Hello World!";
//! }
//! ```
//!
//! Note that it is good practice to make sure that you name your test in a way that actually
//! explains what it is trying to test. When you have a number of tests, and one of them fails,
//! something like this is easier to understand:
//!
//! ```rust,ignore
//! #[test]
//! pub fn should_return_false_if_condition_does_not_hold() {
//!     ...
//! }
//! ```
//!
//! Rather than if you have a test like this:
//!
//! ```rust,ignore
//! #[test]
//! pub fn should_work() {
//!     ...
//! }
//! ```
//!
//! Unfortunately, our test isn't named very well at the moment, but given the lack of context,
//! it'll have to do for now.
//!
//! Now that we have something to test, we need to actually start asserting on it. The first part
//! to that is to provide it to the `assert_that` function. Note that we need to provide it as a
//! reference.
//!
//! ```rust
//! #[test]
//! pub fn should_be_the_correct_string() {
//!     let subject = "Hello World!";
//!     assert_that(&subject);
//! }
//! ```
//!
//! If we run that with `cargo test`, we'll see the following output:
//!
//! ```bash
//! running 1 test
//! test should_be_the_correct_string ... ok
//! ```
//!
//! Our test compiles and passes, but we still haven't made any assertions. Let's make a simple one
//! to start with. We'll check to see that it starts with the letter 'H'.
//!
//! ```rust
//! #[test]
//! pub fn should_be_the_correct_string() {
//!     let subject = "Hello World!";
//!     assert_that(&subject).starts_with(&"H");
//! }
//! ```
//!
//! Once you run this, you'll notice that the test still passes. That's because we've just proven
//! something that was already true. Usually you'll want to start with a failing test, and then
//! change your code to make it pass, rather than writing the test after the implementation.
//!
//! But for the purpose of exploration, let's break the actual value. We'll change "Hello World!"
//! to be "ello World!".
//!
//! ```rust
//! #[test]
//! pub fn should_be_the_correct_string() {
//!     let subject = "ello World!";
//!     assert_that(&subject).starts_with(&"H");
//! }
//! ```
//!
//! This time, we see that the test fails, and we also get some output from our assertion to tell
//! us what it was, and what it was expected to be:
//!
//! ```bash
//! running 1 test
//! test should_be_the_correct_string ... FAILED
//!
//! failures:
//!
//! ---- should_be_the_correct_string stdout ----
//!     thread 'should_be_the_correct_string' panicked at 'expected string starting with <"H"> but
//!     was <"ello World!">', src/lib.rs:204
//! ```
//!
//! Great! So we've just encountered a failing test. This particular case is quite easy to fix up
//! (just add the letter 'H' back to the start of the `String`), but we can also see that the panic
//! message tells us enough information to work that out as well.
//!
//! Now, this was just a simple example, and there's a number of features not demonstrated, but
//! hopefully it's enough to start you off with writing assertions in your tests using Spectral.

use std::cmp::PartialEq;
use std::fmt::Debug;

pub mod numeric;
pub mod option;
pub mod prelude;
pub mod result;
pub mod string;
pub mod vec;
pub mod iter;

#[macro_export]
macro_rules! assert_that {
    (&$subject:ident$(.$additional_subject:ident)*) => {
        assert_that!($subject$(.$additional_subject)*)
    };
    ($subject:ident$(.$additional_subject:ident)*) => {
        assert_that(&$subject$(.$additional_subject)*)
    };
}

/// A description for an assertion.
///
/// This is created by the `asserting` function.
#[derive(Debug)]
pub struct SpecDescription<'r> {
    value: &'r str,
}

/// An assertion.
///
/// This is created by either the `assert_that` function, or by calling `that` on a
/// `SpecDescription`.
#[derive(Debug)]
pub struct Spec<'s, S: 's> {
    pub subject: &'s S,
    description: Option<&'s str>,
    expected: Option<String>,
    actual: Option<String>,
}

/// Wraps a subject in a `Spec` to provide assertions against it.
///
/// The subject must be a reference.
pub fn assert_that<'s, S>(subject: &'s S) -> Spec<'s, S> {
    Spec {
        subject: subject,
        description: None,
        expected: None,
        actual: None,
    }
}

/// Describes an assertion.
pub fn asserting<'r>(description: &'r str) -> SpecDescription {
    SpecDescription { value: description }
}

impl<'r> SpecDescription<'r> {
    /// Creates a new assertion, passing through its description.
    pub fn that<S>(self, subject: &'r S) -> Spec<'r, S> {
        Spec {
            subject: subject,
            description: Some(self.value),
            expected: None,
            actual: None,
        }
    }
}

impl<'s, S> Spec<'s, S> {
    /// Builder method to add the expected value for the panic message.
    pub fn with_expected(&mut self, expected: String) -> &mut Self {
        let mut spec = self;
        spec.expected = Some(expected);
        spec
    }

    /// Builder method to add the actual value for the panic message.
    pub fn with_actual(&mut self, actual: String) -> &mut Self {
        let mut spec = self;
        spec.actual = Some(actual);
        spec
    }

    /// Builds the failure message with a description (if present), the expected value,
    /// and the actual value and then calls `panic` with the created message.
    pub fn fail(&mut self) {
        if !self.expected.is_some() || !self.actual.is_some() {
            panic!("invalid assertion");
        }

        match self.description {
            Some(description) => {
                panic!(format!("\n\t{}:\n\texpected: {}\n\t but was: {}\n",
                               description,
                               self.expected.clone().unwrap(),
                               self.actual.clone().unwrap()))
            }
            None => {
                panic!(format!("\n\texpected: {}\n\t but was: {}\n",
                               self.expected.clone().unwrap(),
                               self.actual.clone().unwrap()))
            }
        }
    }

    /// Calls `panic` with the provided message, prepending the assertion description
    /// if present.
    fn fail_with_message(&mut self, message: String) {
        match self.description {
            Some(description) => panic!(format!("\n\t{}:\n\t{}\n", description, message)),
            None => panic!(format!("\n\t{}", message)),
        }
    }
}

impl<'s, S> Spec<'s, S>
    where S: Debug + PartialEq
{
    /// Asserts that the actual value and the expected value are equal. The value type must
    /// implement `PartialEq`.
    ///
    /// ```rust,ignore
    /// assert_that(&"hello").is_equal_to(&"hello");
    /// ```
    pub fn is_equal_to(&mut self, expected: &S) -> &mut Self {
        let subject = self.subject;

        if !subject.eq(expected) {
            self.with_expected(format!("<{:?}>", expected))
                .with_actual(format!("<{:?}>", subject))
                .fail();
        }

        self
    }
}

impl<'s, S> Spec<'s, S>
    where S: Debug
{
    /// Accepts a function accepting the value type which returns a bool. Returning false will
    /// cause the assertion to fail.
    ///
    /// NOTE: The resultant panic message will only state the actual value. It's recommended that
    /// you write your own assertion rather than relying upon this.
    ///
    /// ```rust,ignore
    /// assert_that(&"hello").matches(|x| x.eq(&"hello"));
    /// ```
    pub fn matches<F>(&mut self, matching_function: F) -> &mut Self
        where F: Fn(&'s S) -> bool
    {
        let subject = self.subject;

        if !matching_function(subject) {
            self.fail_with_message(format!("expectation failed for value <{:?}>", subject));
        }

        self
    }

    /// Transforms the subject of the `Spec` by passing it through to the provided mapping
    /// function.
    ///
    /// ```rust,ignore
    /// let test_struct = TestStruct { value: 5 };
    /// assert_that(&test_struct).map(|val| &val.value).is_equal_to(&5);
    /// ```
    pub fn map<F, T>(self, mapping_function: F) -> Spec<'s, T>
        where F: Fn(&'s S) -> &'s T
    {
        Spec {
            subject: mapping_function(self.subject),
            description: self.description,
            expected: self.expected,
            actual: self.actual,
        }
    }
}

#[cfg(test)]
mod tests {

    use super::prelude::*;

    #[test]
    fn should_be_able_to_use_macro_form_with_deliberate_reference() {
        let test_vec = vec![1, 2, 3, 4, 5];

        assert_that!(&test_vec)
            .has_length(5)
            .contains(&3)
            .contains(&5)
            .mapped_contains(|val| val * 2, &6);
    }

    #[test]
    fn should_be_able_to_use_macro_form_without_deliberate_reference() {
        let test_vec = vec![1, 2, 3, 4, 5];

        assert_that!(test_vec)
            .has_length(5)
            .contains(&3)
            .contains(&5)
            .mapped_contains(|val| val * 2, &6);
    }

    #[test]
    fn should_be_able_to_chain_assertions() {
        assert_that(&vec![1, 2, 3, 4, 5])
            .has_length(5)
            .contains(&3)
            .contains(&5)
            .mapped_contains(|val| val * 2, &6);
    }

    #[test]
    #[should_panic(expected = "\n\ttest condition:\n\texpected: <2>\n\t but was: <1>")]
    fn should_contain_assertion_description_in_panic() {
        asserting(&"test condition").that(&1).is_equal_to(&2);
    }

    #[test]
    #[should_panic(expected = "\n\tclosure:\n\texpectation failed for value <\"Hello\">")]
    fn should_contain_assertion_description_if_message_is_provided() {
        let value = "Hello";
        asserting(&"closure").that(&value).matches(|val| val.eq(&"Hi"));
    }

    #[test]
    fn should_not_panic_on_equal_subjects() {
        assert_that(&1).is_equal_to(&1);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: <2>\n\t but was: <1>")]
    fn should_panic_on_unequal_subjects() {
        assert_that(&1).is_equal_to(&2);
    }

    #[test]
    fn should_not_panic_if_value_matches() {
        let value = "Hello";
        assert_that(&value).matches(|val| val.eq(&"Hello"));
    }

    #[test]
    #[should_panic(expected = "\n\texpectation failed for value <\"Hello\">")]
    fn should_panic_if_value_does_not_match() {
        let value = "Hello";
        assert_that(&value).matches(|val| val.eq(&"Hi"));
    }

    #[test]
    fn should_be_able_to_map_to_inner_field_of_struct_when_matching() {
        let test_struct = TestStruct { value: 5 };
        assert_that(&test_struct).map(|val| &val.value).is_equal_to(&5);
    }

    #[derive(Debug, PartialEq)]
    struct TestStruct {
        pub value: u8,
    }

}
<commit_msg>Use colours when displaying a failure message<commit_after>//! Fluent test assertions in Rust
//!
//! Spectral is a testing framework designed to make your assertions read like plain English.
//! This allows you to more easily expose the intent of your test, rather than having it shrouded by
//! assertions which work, but are opaque on their meaning.
//!
//! Methods available to assert with are dependent upon the type of the subject under test.
//! Assertions are available for some basic types, but there is still a great deal missing from the
//! standard library.
//!
//! ## Usage
//!
//! Add the dependency to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! spectral = "0.2.0"
//! ```
//!
//! Then add this to your crate:
//!
//! ```rust
//! extern crate spectral;
//! ```
//!
//! If you want macro support, include `#[macro_use]` to the declaration:
//!
//! ```rust,ignore
//! #[macro_use]
//! extern crate spectral;
//! ```
//!
//! To quickly start using assertions, `use` the prelude module:
//!
//! ```rust
//! use spectral::prelude::*;
//! ```
//!
//! ## Example
//!
//! We're going to make a few assertions on a `String` we create. Normally you would
//! want to assert on the output of something, but we'll just pretend that something created it.
//!
//! First, we'll create a new test with our `String`.
//!
//! ```rust
//! #[test]
//! pub fn should_be_the_correct_string() {
//!     let subject = "Hello World!";
//! }
//! ```
//!
//! Note that it is good practice to make sure that you name your test in a way that actually
//! explains what it is trying to test. When you have a number of tests, and one of them fails,
//! something like this is easier to understand:
//!
//! ```rust,ignore
//! #[test]
//! pub fn should_return_false_if_condition_does_not_hold() {
//!     ...
//! }
//! ```
//!
//! Rather than if you have a test like this:
//!
//! ```rust,ignore
//! #[test]
//! pub fn should_work() {
//!     ...
//! }
//! ```
//!
//! Unfortunately, our test isn't named very well at the moment, but given the lack of context,
//! it'll have to do for now.
//!
//! Now that we have something to test, we need to actually start asserting on it. The first part
//! to that is to provide it to the `assert_that` function. Note that we need to provide it as a
//! reference.
//!
//! ```rust
//! #[test]
//! pub fn should_be_the_correct_string() {
//!     let subject = "Hello World!";
//!     assert_that(&subject);
//! }
//! ```
//!
//! If we run that with `cargo test`, we'll see the following output:
//!
//! ```bash
//! running 1 test
//! test should_be_the_correct_string ... ok
//! ```
//!
//! Our test compiles and passes, but we still haven't made any assertions. Let's make a simple one
//! to start with. We'll check to see that it starts with the letter 'H'.
//!
//! ```rust
//! #[test]
//! pub fn should_be_the_correct_string() {
//!     let subject = "Hello World!";
//!     assert_that(&subject).starts_with(&"H");
//! }
//! ```
//!
//! Once you run this, you'll notice that the test still passes. That's because we've just proven
//! something that was already true. Usually you'll want to start with a failing test, and then
//! change your code to make it pass, rather than writing the test after the implementation.
//!
//! But for the purpose of exploration, let's break the actual value. We'll change "Hello World!"
//! to be "ello World!".
//!
//! ```rust
//! #[test]
//! pub fn should_be_the_correct_string() {
//!     let subject = "ello World!";
//!     assert_that(&subject).starts_with(&"H");
//! }
//! ```
//!
//! This time, we see that the test fails, and we also get some output from our assertion to tell
//! us what it was, and what it was expected to be:
//!
//! ```bash
//! running 1 test
//! test should_be_the_correct_string ... FAILED
//!
//! failures:
//!
//! ---- should_be_the_correct_string stdout ----
//!     thread 'should_be_the_correct_string' panicked at 'expected string starting with <"H"> but
//!     was <"ello World!">', src/lib.rs:204
//! ```
//!
//! Great! So we've just encountered a failing test. This particular case is quite easy to fix up
//! (just add the letter 'H' back to the start of the `String`), but we can also see that the panic
//! message tells us enough information to work that out as well.
//!
//! Now, this was just a simple example, and there's a number of features not demonstrated, but
//! hopefully it's enough to start you off with writing assertions in your tests using Spectral.

use std::cmp::PartialEq;
use std::fmt::Debug;

use colours::{TERM_RED, TERM_BOLD, TERM_RESET};

pub mod numeric;
pub mod option;
pub mod prelude;
pub mod result;
pub mod string;
pub mod vec;
pub mod iter;

// Disable colours during tests, otherwise trying to assert on the panic message becomes
// significantly more annoying.
#[cfg(not(test))]
mod colours {
    pub const TERM_RED: &'static str = "\x1B[31m";
    pub const TERM_BOLD: &'static str = "\x1B[1m";
    pub const TERM_RESET: &'static str = "\x1B[0m";
}

#[cfg(test)]
mod colours {
    pub const TERM_RED: &'static str = "";
    pub const TERM_BOLD: &'static str = "";
    pub const TERM_RESET: &'static str = "";
}

#[macro_export]
macro_rules! assert_that {
    (&$subject:ident$(.$additional_subject:ident)*) => {
        assert_that!($subject$(.$additional_subject)*)
    };
    ($subject:ident$(.$additional_subject:ident)*) => {
        assert_that(&$subject$(.$additional_subject)*)
    };
}

/// A description for an assertion.
///
/// This is created by the `asserting` function.
#[derive(Debug)]
pub struct SpecDescription<'r> {
    value: &'r str,
}

/// An assertion.
///
/// This is created by either the `assert_that` function, or by calling `that` on a
/// `SpecDescription`.
#[derive(Debug)]
pub struct Spec<'s, S: 's> {
    pub subject: &'s S,
    description: Option<&'s str>,
    expected: Option<String>,
    actual: Option<String>,
}

/// Wraps a subject in a `Spec` to provide assertions against it.
///
/// The subject must be a reference.
pub fn assert_that<'s, S>(subject: &'s S) -> Spec<'s, S> {
    Spec {
        subject: subject,
        description: None,
        expected: None,
        actual: None,
    }
}

/// Describes an assertion.
pub fn asserting<'r>(description: &'r str) -> SpecDescription {
    SpecDescription { value: description }
}

impl<'r> SpecDescription<'r> {
    /// Creates a new assertion, passing through its description.
    pub fn that<S>(self, subject: &'r S) -> Spec<'r, S> {
        Spec {
            subject: subject,
            description: Some(self.value),
            expected: None,
            actual: None,
        }
    }
}

impl<'s, S> Spec<'s, S> {
    /// Builder method to add the expected value for the panic message.
    pub fn with_expected(&mut self, expected: String) -> &mut Self {
        let mut spec = self;
        spec.expected = Some(expected);
        spec
    }

    /// Builder method to add the actual value for the panic message.
    pub fn with_actual(&mut self, actual: String) -> &mut Self {
        let mut spec = self;
        spec.actual = Some(actual);
        spec
    }

    /// Builds the failure message with a description (if present), the expected value,
    /// and the actual value and then calls `panic` with the created message.
    pub fn fail(&mut self) {
        if !self.expected.is_some() || !self.actual.is_some() {
            panic!("invalid assertion");
        }

        match self.description {
            Some(description) => {
                panic!(format!("\n\t{}{}:{}\n\t{}expected: {}\n\t but was: {}{}\n",
                               TERM_BOLD,
                               description,
                               TERM_RESET,
                               TERM_RED,
                               self.expected.clone().unwrap(),
                               self.actual.clone().unwrap(),
                               TERM_RESET))
            }
            None => {
                panic!(format!("\n\t{}expected: {}\n\t but was: {}{}\n",
                               TERM_RED,
                               self.expected.clone().unwrap(),
                               self.actual.clone().unwrap(),
                               TERM_RESET))
            }
        }
    }

    /// Calls `panic` with the provided message, prepending the assertion description
    /// if present.
    fn fail_with_message(&mut self, message: String) {
        match self.description {
            Some(description) => {
                panic!(format!("\n\t{}{}:{}\n\t{}{}{}\n",
                               TERM_BOLD,
                               description,
                               TERM_RESET,
                               TERM_RED,
                               message,
                               TERM_RESET))
            }
            None => panic!(format!("\n\t{}{}{}\n", TERM_RED, message, TERM_RESET)),
        }
    }
}

impl<'s, S> Spec<'s, S>
    where S: Debug + PartialEq
{
    /// Asserts that the actual value and the expected value are equal. The value type must
    /// implement `PartialEq`.
    ///
    /// ```rust,ignore
    /// assert_that(&"hello").is_equal_to(&"hello");
    /// ```
    pub fn is_equal_to(&mut self, expected: &S) -> &mut Self {
        let subject = self.subject;

        if !subject.eq(expected) {
            self.with_expected(format!("<{:?}>", expected))
                .with_actual(format!("<{:?}>", subject))
                .fail();
        }

        self
    }
}

impl<'s, S> Spec<'s, S>
    where S: Debug
{
    /// Accepts a function accepting the value type which returns a bool. Returning false will
    /// cause the assertion to fail.
    ///
    /// NOTE: The resultant panic message will only state the actual value. It's recommended that
    /// you write your own assertion rather than relying upon this.
    ///
    /// ```rust,ignore
    /// assert_that(&"hello").matches(|x| x.eq(&"hello"));
    /// ```
    pub fn matches<F>(&mut self, matching_function: F) -> &mut Self
        where F: Fn(&'s S) -> bool
    {
        let subject = self.subject;

        if !matching_function(subject) {
            self.fail_with_message(format!("expectation failed for value <{:?}>", subject));
        }

        self
    }

    /// Transforms the subject of the `Spec` by passing it through to the provided mapping
    /// function.
    ///
    /// ```rust,ignore
    /// let test_struct = TestStruct { value: 5 };
    /// assert_that(&test_struct).map(|val| &val.value).is_equal_to(&5);
    /// ```
    pub fn map<F, T>(self, mapping_function: F) -> Spec<'s, T>
        where F: Fn(&'s S) -> &'s T
    {
        Spec {
            subject: mapping_function(self.subject),
            description: self.description,
            expected: self.expected,
            actual: self.actual,
        }
    }
}

#[cfg(test)]
mod tests {

    use super::prelude::*;

    #[test]
    fn should_be_able_to_use_macro_form_with_deliberate_reference() {
        let test_vec = vec![1, 2, 3, 4, 5];

        assert_that!(&test_vec)
            .has_length(5)
            .contains(&3)
            .contains(&5)
            .mapped_contains(|val| val * 2, &6);
    }

    #[test]
    fn should_be_able_to_use_macro_form_without_deliberate_reference() {
        let test_vec = vec![1, 2, 3, 4, 5];

        assert_that!(test_vec)
            .has_length(5)
            .contains(&3)
            .contains(&5)
            .mapped_contains(|val| val * 2, &6);
    }

    #[test]
    fn should_be_able_to_chain_assertions() {
        assert_that(&vec![1, 2, 3, 4, 5])
            .has_length(5)
            .contains(&3)
            .contains(&5)
            .mapped_contains(|val| val * 2, &6);
    }

    #[test]
    #[should_panic(expected = "\n\ttest condition:\n\texpected: <2>\n\t but was: <1>")]
    fn should_contain_assertion_description_in_panic() {
        asserting(&"test condition").that(&1).is_equal_to(&2);
    }

    #[test]
    #[should_panic(expected = "\n\tclosure:\n\texpectation failed for value <\"Hello\">")]
    fn should_contain_assertion_description_if_message_is_provided() {
        let value = "Hello";
        asserting(&"closure").that(&value).matches(|val| val.eq(&"Hi"));
    }

    #[test]
    fn should_not_panic_on_equal_subjects() {
        assert_that(&1).is_equal_to(&1);
    }

    #[test]
    #[should_panic(expected = "\n\texpected: <2>\n\t but was: <1>")]
    fn should_panic_on_unequal_subjects() {
        assert_that(&1).is_equal_to(&2);
    }

    #[test]
    fn should_not_panic_if_value_matches() {
        let value = "Hello";
        assert_that(&value).matches(|val| val.eq(&"Hello"));
    }

    #[test]
    #[should_panic(expected = "\n\texpectation failed for value <\"Hello\">")]
    fn should_panic_if_value_does_not_match() {
        let value = "Hello";
        assert_that(&value).matches(|val| val.eq(&"Hi"));
    }

    #[test]
    fn should_be_able_to_map_to_inner_field_of_struct_when_matching() {
        let test_struct = TestStruct { value: 5 };
        assert_that(&test_struct).map(|val| &val.value).is_equal_to(&5);
    }

    #[derive(Debug, PartialEq)]
    struct TestStruct {
        pub value: u8,
    }

}
<|endoftext|>