<commit_before>use regex::Regex;
use std::collections::HashMap;
use std::fs;
use std::io::{Error, ErrorKind, Read};
use std::path::Path;
use toml;

#[derive(Debug)]
pub struct Benchmark {
    pub name: String,
    pub cmd: String,
    pub args: Vec<String>,
    pub result_expr: Vec<Regex>,
    pub lower_is_better: bool,
    pub improvement_threshold: f64,
    pub regression_threshold: f64,
}

pub struct Config {
    pub benchmarks: Vec<Benchmark>,
    pub slack_aliases: HashMap<String, String>,
    pub version: Option<i64>,
}

pub fn parse_config(
    cfg: &Path,
    def_imp_threshold: f64,
    def_reg_threshold: f64,
) -> Result<Config, Error> {
    let mut f = try!(fs::File::open(cfg));
    let mut buf = String::new();
    try!(f.read_to_string(&mut buf));

    let value = match toml::Parser::new(&buf).parse() {
        None => {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                "failed to parse taster config!",
            ))
        }
        Some(v) => v,
    };

    let to_bench = |t: (&String, &toml::Value)| {
        Benchmark {
            name: t.0.clone(),
            cmd: String::from(t.1.lookup("command").unwrap().as_str().unwrap()),
            args: t.1.as_table().unwrap()["args"]
                .as_slice()
                .unwrap()
                .iter()
                .map(|a| String::from(a.as_str().unwrap()))
                .collect(),
            result_expr: t.1
                .lookup("regexs")
                .unwrap()
                .as_slice()
                .unwrap()
                .iter()
                .map(|r| Regex::new(r.as_str().unwrap()).unwrap())
                .collect(),
            lower_is_better: match t.1.lookup("lower_better") {
                None => false,
                Some(v) => v.as_bool().unwrap(),
            },
            improvement_threshold: match t.1.lookup("improvement_threshold") {
                None => def_imp_threshold,
                Some(ref it) => it.as_float().unwrap(),
            },
            regression_threshold: match t.1.lookup("regression_threshold") {
                None => def_reg_threshold,
                Some(ref rt) => rt.as_float().unwrap(),
            },
        }
    };

    // Github <-> Slack username mappings
    let slack_aliases = value
        .iter()
        .filter(|t| t.0 == "slack-aliases")
        .flat_map(|t| {
            t.1
                .as_table()
                .unwrap()
                .iter()
                .map(|(k, v)| (k.clone(), String::from(v.as_str().unwrap())))
        })
        .collect::<HashMap<_, _>>();

    // Taster config version
    let version = value["version"].as_integer();

    // Benchmark definitions
    let benchmarks = value
        .iter()
        .filter(|t| t.0 != "slack-aliases" && t.0 != "version")
        .map(|t| to_bench(t))
        .collect();

    Ok(Config {
        benchmarks: benchmarks,
        slack_aliases: slack_aliases,
        version: version,
    })
}
<commit_msg>Correctly handle taster configs without a version<commit_after>use regex::Regex;
use std::collections::HashMap;
use std::fs;
use std::io::{Error, ErrorKind, Read};
use std::path::Path;
use toml;

#[derive(Debug)]
pub struct Benchmark {
    pub name: String,
    pub cmd: String,
    pub args: Vec<String>,
    pub result_expr: Vec<Regex>,
    pub lower_is_better: bool,
    pub improvement_threshold: f64,
    pub regression_threshold: f64,
}

pub struct Config {
    pub benchmarks: Vec<Benchmark>,
    pub slack_aliases: HashMap<String, String>,
    pub version: Option<i64>,
}

pub fn parse_config(
    cfg: &Path,
    def_imp_threshold: f64,
    def_reg_threshold: f64,
) -> Result<Config, Error> {
    let mut f = try!(fs::File::open(cfg));
    let mut buf = String::new();
    try!(f.read_to_string(&mut buf));

    let value = match toml::Parser::new(&buf).parse() {
        None => {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                "failed to parse taster config!",
            ))
        }
        Some(v) => v,
    };

    let to_bench = |t: (&String, &toml::Value)| {
        Benchmark {
            name: t.0.clone(),
            cmd: String::from(t.1.lookup("command").unwrap().as_str().unwrap()),
            args: t.1.as_table().unwrap()["args"]
                .as_slice()
                .unwrap()
                .iter()
                .map(|a| String::from(a.as_str().unwrap()))
                .collect(),
            result_expr: t.1
                .lookup("regexs")
                .unwrap()
                .as_slice()
                .unwrap()
                .iter()
                .map(|r| Regex::new(r.as_str().unwrap()).unwrap())
                .collect(),
            lower_is_better: match t.1.lookup("lower_better") {
                None => false,
                Some(v) => v.as_bool().unwrap(),
            },
            improvement_threshold: match t.1.lookup("improvement_threshold") {
                None => def_imp_threshold,
                Some(ref it) => it.as_float().unwrap(),
            },
            regression_threshold: match t.1.lookup("regression_threshold") {
                None => def_reg_threshold,
                Some(ref rt) => rt.as_float().unwrap(),
            },
        }
    };

    // Github <-> Slack username mappings
    let slack_aliases = value
        .iter()
        .filter(|t| t.0 == "slack-aliases")
        .flat_map(|t| {
            t.1
                .as_table()
                .unwrap()
                .iter()
                .map(|(k, v)| (k.clone(), String::from(v.as_str().unwrap())))
        })
        .collect::<HashMap<_, _>>();

    // Taster config version
    let version = match value.get("version") {
        None => None,
        Some(v) => Some(v.as_integer().unwrap()),
    };

    // Benchmark definitions
    let benchmarks = value
        .iter()
        .filter(|t| t.0 != "slack-aliases" && t.0 != "version")
        .map(|t| to_bench(t))
        .collect();

    Ok(Config {
        benchmarks: benchmarks,
        slack_aliases: slack_aliases,
        version: version,
    })
}
<|endoftext|>


<commit_before>use num::Num;

#[inline(always)]
pub fn create<T: Num>(m11: T, m12: T, m13: T, m21: T, m22: T, m23: T) -> [T; 6] {
    [m11, m12, m13, m21, m22, m23]
}
#[test]
fn test_create() {
    let m = create(
        1, 0, 0,
        0, 1, 0
    );
    assert!(m == [
        1, 0, 0,
        0, 1, 0
    ]);
}

#[inline(always)]
pub fn clone<T: Num>(m: [T; 6]) -> [T; 6] {create(m[0], m[1], m[2], m[3], m[4], m[5])}

#[inline(always)]
pub fn copy<T: Num>(out: &mut [T; 6], a: [T; 6]) -> &mut [T; 6] {
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    out[4] = a[4];
    out[5] = a[5];
    out
}
#[test]
fn test_copy() {
    let mut v = [0, 0, 0, 0, 0, 0];
    copy(&mut v, [1, 2, 3, 4, 5, 6]);
    assert!(v == [1, 2, 3, 4, 5, 6]);
}
<commit_msg>updates<commit_after>use num::Num;

#[inline(always)]
pub fn create<T: Num>(m11: T, m12: T, m13: T, m21: T, m22: T, m23: T) -> [T; 6] {
    [m11, m12, m13, m21, m22, m23]
}
#[test]
fn test_create() {
    let m = create(
        1, 0, 0,
        0, 1, 0
    );
    assert!(m == [
        1, 0, 0,
        0, 1, 0
    ]);
}

#[inline(always)]
pub fn create_identity<T: Num>() -> [T; 6] {
    create(
        T::one(), T::zero(), T::zero(),
        T::zero(), T::one(), T::zero()
    )
}
#[inline(always)]
pub fn create_zero<T: Num>() -> [T; 6] {
    create(
        T::zero(), T::zero(), T::zero(),
        T::zero(), T::zero(), T::zero()
    )
}

#[inline(always)]
pub fn clone<T: Num>(m: [T; 6]) -> [T; 6] {create(m[0], m[1], m[2], m[3], m[4], m[5])}

#[inline(always)]
pub fn copy<T: Num>(out: &mut [T; 6], a: [T; 6]) -> &mut [T; 6] {
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    out[4] = a[4];
    out[5] = a[5];
    out
}
#[test]
fn test_copy() {
    let mut v = [0, 0, 0, 0, 0, 0];
    copy(&mut v, [1, 2, 3, 4, 5, 6]);
    assert!(v == [1, 2, 3, 4, 5, 6]);
}
<|endoftext|>


<commit_before>//! A module for constructing cuboid shapes.

extern crate cgmath;
extern crate glium;

use cgmath::*;
use errors::ShapeCreationError;
use vertex::Vertex;

/// A polygonal `Cuboid` object.
///
/// This object is constructed using a `CuboidBuilder` object.
pub struct Cuboid {
    vertices: glium::vertex::VertexBufferAny
}

/// Allows a `Cuboid` object to be passed as a source of vertices.
impl<'a> glium::vertex::IntoVerticesSource<'a> for &'a Cuboid {
    fn into_vertices_source(self) -> glium::vertex::VerticesSource<'a> {
        return self.vertices.into_vertices_source();
    }
}

/// Allows a `Cuboid` object to be passed as a source of indices.
impl<'a> Into<glium::index::IndicesSource<'a>> for &'a Cuboid {
    fn into(self) -> glium::index::IndicesSource<'a> {
        return glium::index::IndicesSource::NoIndices{
            primitives: glium::index::PrimitiveType::TrianglesList
        };
    }
}

/// Responsible for building and returning a `Cuboid` object.
///
/// By default, the cuboid is defined as a unit-cube with its centre-of-mass
/// located at the origin. This can be overriden using the transformation
/// methods on this object.
///
/// The resultant geometry is constructed to suit OpenGL defaults - assuming
/// a right-handed coordinate system, front-facing polygons are defined in
/// counter-clock-wise order. Vertex normals point in the direction of their
/// respective face (such that the cuboid appears faceted when lit). Vertex
/// texture coordinates define a planar-projection on each face.
pub struct CuboidBuilder {
    matrix: cgmath::Matrix4<f32>
}

impl Default for CuboidBuilder {
    fn default() -> Self {
        CuboidBuilder {
            matrix: cgmath::Matrix4::<f32>::identity()
        }
    }
}

impl CuboidBuilder {

    /// Create a new `CuboidBuilder` object.
    pub fn new() -> CuboidBuilder {
        Default::default()
    }

    /// Apply a scaling transformation to the shape.
    ///
    /// The `scale`, `translate`, and `rotate` functions accumulate, and are
    /// not commutative. The transformation functions are intended to provide
    /// flexibility in model-space. For per-instance world-space transformations,
    /// one should prefer to share as few shapes as possible across multiple
    /// instances, and instead rely on uniform constants in the shader and/or
    /// instanced drawing.
    pub fn scale(mut self, x: f32, y: f32, z: f32) -> Self {
        self.matrix = cgmath::Matrix4::from_nonuniform_scale(x, y, z) * self.matrix;
        return self;
    }

    /// Apply a translation transformation to the shape.
    ///
    /// The `scale`, `translate`, and `rotate` functions accumulate, and are
    /// not commutative. The transformation functions are intended to provide
    /// flexibility in model-space. For per-instance world-space transformations,
    /// one should prefer to share as few shapes as possible across multiple
    /// instances, and instead rely on uniform constants in the shader and/or
    /// instanced drawing.
    pub fn translate(mut self, x: f32, y:f32, z: f32) -> Self {
        self.matrix = cgmath::Matrix4::from_translation([x, y, z].into()) * self.matrix;
        return self;
    }

    /// Apply a rotation transformation to the shape about the x-axis.
    ///
    /// The `scale`, `translate`, and `rotate` functions accumulate, and are
    /// not commutative. The transformation functions are intended to provide
    /// flexibility in model-space. For per-instance world-space transformations,
    /// one should prefer to share as few shapes as possible across multiple
    /// instances, and instead rely on uniform constants in the shader and/or
    /// instanced drawing.
    pub fn rotate_x(mut self, radians: f32) -> Self {
        self.matrix = cgmath::Matrix4::<f32>::from(
            cgmath::Matrix3::<f32>::from_angle_x(
                cgmath::Rad::<f32>::new(radians)
            )
        ) * self.matrix;
        return self;
    }

    /// Apply a rotation transformation to the shape about the y-axis.
    ///
    /// The `scale`, `translate`, and `rotate` functions accumulate, and are
    /// not commutative. The transformation functions are intended to provide
    /// flexibility in model-space. For per-instance world-space transformations,
    /// one should prefer to share as few shapes as possible across multiple
    /// instances, and instead rely on uniform constants in the shader and/or
    /// instanced drawing.
    pub fn rotate_y(mut self, radians: f32) -> Self {
        self.matrix = cgmath::Matrix4::<f32>::from(
            cgmath::Matrix3::<f32>::from_angle_y(
                cgmath::Rad::<f32>::new(radians)
            )
        ) * self.matrix;
        return self;
    }

    /// Apply a rotation transformation to the shape about the z-axis.
    ///
    /// The `scale`, `translate`, and `rotate` functions accumulate, and are
    /// not commutative. The transformation functions are intended to provide
    /// flexibility in model-space. For per-instance world-space transformations,
    /// one should prefer to share as few shapes as possible across multiple
    /// instances, and instead rely on uniform constants in the shader and/or
    /// instanced drawing.
    pub fn rotate_z(mut self, radians: f32) -> Self {
        self.matrix = cgmath::Matrix4::<f32>::from(
            cgmath::Matrix3::<f32>::from_angle_z(
                cgmath::Rad::<f32>::new(radians)
            )
        ) * self.matrix;
        return self;
    }

    /// Build a new `Cuboid` object.
    pub fn build<F>(self, display: &F) -> Result<Cuboid, ShapeCreationError>
    where F:glium::backend::Facade {
        let vertices = try!(glium::vertex::VertexBuffer::<Vertex>::new(
            display, &try!(self.build_vertices())
        ));

        Ok(Cuboid {
            vertices: glium::vertex::VertexBufferAny::from(vertices),
        })
    }

    /// Build the cube vertices and return them in a vector.
    ///
    /// Useful if you wish to do other things with the vertices besides constructing
    /// a `Cuboid` object (e.g. unit testing, further processing, etc).
    pub fn build_vertices(&self) -> Result<Vec<Vertex>, ShapeCreationError> {

        // Define lookup-tables used during construction of the cuboid geometry
        let index_lut = [
            0, 4, 1, 5,
            6, 2, 7, 3,
            0, 2, 4, 6,
            5, 7, 1, 3,
            2, 0, 3, 1,
            4, 6, 5, 7,
        ];
        let poly_lut = [0, 1, 2, 2, 1, 3];
        let num_sides = 6;
        let verts_per_side = 6;

        // Compute the normal transformation matrix.
        let normal_matrix = Matrix3::<f32>::from_cols(
            self.matrix.x.truncate(),
            self.matrix.y.truncate(),
            self.matrix.z.truncate()
        ).invert().unwrap_or(Matrix3::<f32>::identity()).transpose();

        // Generate cuboid vertices.
        let mut vertices = Vec::<Vertex>::with_capacity(
            verts_per_side * num_sides
        );

        for side in 0..num_sides {

            // Compute side normal.
            let mut normal = Vector3::<f32>::new(0.0, 0.0, 0.0);
            normal[ side / 2 ] = ( ( ( side % 2 ) * 2 ) as f32 ) - 1.0;

            // Build side vertices.
            for vert in 0..verts_per_side {

                let coord = index_lut[ poly_lut[ vert ] + ( side * 4 ) ];
                vertices.push(Vertex{
                    position: Point3::<f32>::from_homogeneous(self.matrix * Vector4::<f32>::new(
                        (((coord & 2) - 1) as f32) * 0.5,
                        (((coord & 1) * 2 - 1) as f32) * 0.5,
                        ((((coord >> 1) & 2) - 1) as f32) * 0.5,
                        1.0
                    )).into(),
                    normal: (normal_matrix * normal).normalize().into(),
                    texcoord: [
                        ( poly_lut[ vert ] % 2 ) as f32,
                        ( poly_lut[ vert ] / 2 ) as f32,
                    ],
                });
            }
        }

        return Ok(vertices);
    }
}

#[test]
pub fn ensure_default_cuboid_has_unit_dimensions() {
    let vertices = CuboidBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for ref vertex in vertices {
        assert_eq!(vertex.position[0].abs(), 0.5);
        assert_eq!(vertex.position[1].abs(), 0.5);
        assert_eq!(vertex.position[2].abs(), 0.5);
    }
}

#[test]
pub fn ensure_default_cuboid_has_centroid_at_origin() {
    let vertices = CuboidBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    let mut sum = Vector3::<f32>::zero();
    for ref vertex in vertices {
        sum = sum + Vector3::<f32>::from(vertex.position);
    }
    assert_eq!(sum, Vector3::<f32>::zero());
}

#[test]
pub fn ensure_default_cuboid_has_outward_facing_normals() {
    let vertices = CuboidBuilder::new()
                   .scale(2.0, 2.0, 2.0)
                   .build_vertices()
                   .expect("Failed to build vertices");
    for ref vertex in vertices {
        let position = Vector3::<f32>::from(vertex.position);
        let normal = Vector3::<f32>::from(vertex.normal);
        let outside = position + normal;
        assert!(outside.x.abs() >= position.x.abs());
        assert!(outside.y.abs() >= position.y.abs());
        assert!(outside.z.abs() >= position.z.abs());
    }
}

#[test]
pub fn ensure_default_cuboid_has_uvs_in_unit_range() {
    let vertices = CuboidBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for ref vertex in vertices {
        assert!(vertex.texcoord[0] >= 0.0);
        assert!(vertex.texcoord[1] >= 0.0);
        assert!(vertex.texcoord[0] <= 1.0);
        assert!(vertex.texcoord[1] <= 1.0);
    }
}

#[test]
pub fn ensure_default_cuboid_has_ccw_triangles() {
    let vertices = CuboidBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for chunk in vertices.chunks(3) {
        let v0 = Vector3::<f32>::from(chunk[0].position);
        let v1 = Vector3::<f32>::from(chunk[1].position);
        let v2 = Vector3::<f32>::from(chunk[2].position);
        let e0 = v1 - v0;
        let e1 = v2 - v0;
        let n = e0.cross(e1);
        assert!(n.dot(v0) > 0.0);
        assert!(n.dot(v1) > 0.0);
        assert!(n.dot(v2) > 0.0);
    }
}

#[test]
pub fn ensure_default_cuboid_has_faceted_normals() {
    let vertices = CuboidBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for chunk in vertices.chunks(3) {
        let v0 = Vector3::<f32>::from(chunk[0].position);
        let v1 = Vector3::<f32>::from(chunk[1].position);
        let v2 = Vector3::<f32>::from(chunk[2].position);
        let n0 = Vector3::<f32>::from(chunk[0].normal);
        let n1 = Vector3::<f32>::from(chunk[1].normal);
        let n2 = Vector3::<f32>::from(chunk[2].normal);
        let e0 = v1 - v0;
        let e1 = v2 - v0;
        let n = e0.cross(e1);
        assert_eq!(n, n0);
        assert_eq!(n, n1);
        assert_eq!(n, n2);
    }
}
<commit_msg>Make documentation comments in cuboid shape slightly more generic.<commit_after>//! A module for constructing cuboid shapes.

extern crate cgmath;
extern crate glium;

use cgmath::*;
use errors::ShapeCreationError;
use vertex::Vertex;

/// A polygonal `Cuboid` object.
///
/// This object is constructed using a `CuboidBuilder` object.
pub struct Cuboid {
    vertices: glium::vertex::VertexBufferAny
}

/// Allows a `Cuboid` object to be passed as a source of vertices.
impl<'a> glium::vertex::IntoVerticesSource<'a> for &'a Cuboid {
    fn into_vertices_source(self) -> glium::vertex::VerticesSource<'a> {
        return self.vertices.into_vertices_source();
    }
}

/// Allows a `Cuboid` object to be passed as a source of indices.
impl<'a> Into<glium::index::IndicesSource<'a>> for &'a Cuboid {
    fn into(self) -> glium::index::IndicesSource<'a> {
        return glium::index::IndicesSource::NoIndices{
            primitives: glium::index::PrimitiveType::TrianglesList
        };
    }
}

/// Responsible for building and returning a `Cuboid` object.
///
/// By default, the cuboid is defined as a unit-cube with its centre-of-mass
/// located at the origin. This can be overriden using the transformation
/// methods on this object.
///
/// The resultant geometry is constructed to suit OpenGL defaults - assuming
/// a right-handed coordinate system, front-facing polygons are defined in
/// counter-clock-wise order. Vertex normals point in the direction of their
/// respective face (such that the shape appears faceted when lit). Vertex
/// texture coordinates define a planar-projection on each face.
pub struct CuboidBuilder {
    matrix: cgmath::Matrix4<f32>
}

impl Default for CuboidBuilder {
    fn default() -> Self {
        CuboidBuilder {
            matrix: cgmath::Matrix4::<f32>::identity()
        }
    }
}

impl CuboidBuilder {

    /// Create a new `CuboidBuilder` object.
    pub fn new() -> CuboidBuilder {
        Default::default()
    }

    /// Apply a scaling transformation to the shape.
    ///
    /// The `scale`, `translate`, and `rotate` functions accumulate, and are
    /// not commutative. The transformation functions are intended to provide
    /// flexibility in model-space. For per-instance world-space transformations,
    /// one should prefer to share as few shapes as possible across multiple
    /// instances, and instead rely on uniform constants in the shader and/or
    /// instanced drawing.
    pub fn scale(mut self, x: f32, y: f32, z: f32) -> Self {
        self.matrix = cgmath::Matrix4::from_nonuniform_scale(x, y, z) * self.matrix;
        return self;
    }

    /// Apply a translation transformation to the shape.
    ///
    /// The `scale`, `translate`, and `rotate` functions accumulate, and are
    /// not commutative. The transformation functions are intended to provide
    /// flexibility in model-space. For per-instance world-space transformations,
    /// one should prefer to share as few shapes as possible across multiple
    /// instances, and instead rely on uniform constants in the shader and/or
    /// instanced drawing.
    pub fn translate(mut self, x: f32, y:f32, z: f32) -> Self {
        self.matrix = cgmath::Matrix4::from_translation([x, y, z].into()) * self.matrix;
        return self;
    }

    /// Apply a rotation transformation to the shape about the x-axis.
    ///
    /// The `scale`, `translate`, and `rotate` functions accumulate, and are
    /// not commutative. The transformation functions are intended to provide
    /// flexibility in model-space. For per-instance world-space transformations,
    /// one should prefer to share as few shapes as possible across multiple
    /// instances, and instead rely on uniform constants in the shader and/or
    /// instanced drawing.
    pub fn rotate_x(mut self, radians: f32) -> Self {
        self.matrix = cgmath::Matrix4::<f32>::from(
            cgmath::Matrix3::<f32>::from_angle_x(
                cgmath::Rad::<f32>::new(radians)
            )
        ) * self.matrix;
        return self;
    }

    /// Apply a rotation transformation to the shape about the y-axis.
    ///
    /// The `scale`, `translate`, and `rotate` functions accumulate, and are
    /// not commutative. The transformation functions are intended to provide
    /// flexibility in model-space. For per-instance world-space transformations,
    /// one should prefer to share as few shapes as possible across multiple
    /// instances, and instead rely on uniform constants in the shader and/or
    /// instanced drawing.
    pub fn rotate_y(mut self, radians: f32) -> Self {
        self.matrix = cgmath::Matrix4::<f32>::from(
            cgmath::Matrix3::<f32>::from_angle_y(
                cgmath::Rad::<f32>::new(radians)
            )
        ) * self.matrix;
        return self;
    }

    /// Apply a rotation transformation to the shape about the z-axis.
    ///
    /// The `scale`, `translate`, and `rotate` functions accumulate, and are
    /// not commutative. The transformation functions are intended to provide
    /// flexibility in model-space. For per-instance world-space transformations,
    /// one should prefer to share as few shapes as possible across multiple
    /// instances, and instead rely on uniform constants in the shader and/or
    /// instanced drawing.
    pub fn rotate_z(mut self, radians: f32) -> Self {
        self.matrix = cgmath::Matrix4::<f32>::from(
            cgmath::Matrix3::<f32>::from_angle_z(
                cgmath::Rad::<f32>::new(radians)
            )
        ) * self.matrix;
        return self;
    }

    /// Build a new `Cuboid` object.
    pub fn build<F>(self, display: &F) -> Result<Cuboid, ShapeCreationError>
    where F:glium::backend::Facade {
        let vertices = try!(glium::vertex::VertexBuffer::<Vertex>::new(
            display, &try!(self.build_vertices())
        ));

        Ok(Cuboid {
            vertices: glium::vertex::VertexBufferAny::from(vertices),
        })
    }

    /// Build the shape vertices and return them in a vector.
    ///
    /// Useful if you wish to do other things with the vertices besides constructing
    /// a `Cuboid` object (e.g. unit testing, further processing, etc).
    pub fn build_vertices(&self) -> Result<Vec<Vertex>, ShapeCreationError> {

        // Define lookup-tables used during construction of the cuboid geometry
        let index_lut = [
            0, 4, 1, 5,
            6, 2, 7, 3,
            0, 2, 4, 6,
            5, 7, 1, 3,
            2, 0, 3, 1,
            4, 6, 5, 7,
        ];
        let poly_lut = [0, 1, 2, 2, 1, 3];
        let num_sides = 6;
        let verts_per_side = 6;

        // Compute the normal transformation matrix.
        let normal_matrix = Matrix3::<f32>::from_cols(
            self.matrix.x.truncate(),
            self.matrix.y.truncate(),
            self.matrix.z.truncate()
        ).invert().unwrap_or(Matrix3::<f32>::identity()).transpose();

        // Generate cuboid vertices.
        let mut vertices = Vec::<Vertex>::with_capacity(
            verts_per_side * num_sides
        );

        for side in 0..num_sides {

            // Compute side normal.
            let mut normal = Vector3::<f32>::new(0.0, 0.0, 0.0);
            normal[ side / 2 ] = ( ( ( side % 2 ) * 2 ) as f32 ) - 1.0;

            // Build side vertices.
            for vert in 0..verts_per_side {

                let coord = index_lut[ poly_lut[ vert ] + ( side * 4 ) ];
                vertices.push(Vertex{
                    position: Point3::<f32>::from_homogeneous(self.matrix * Vector4::<f32>::new(
                        (((coord & 2) - 1) as f32) * 0.5,
                        (((coord & 1) * 2 - 1) as f32) * 0.5,
                        ((((coord >> 1) & 2) - 1) as f32) * 0.5,
                        1.0
                    )).into(),
                    normal: (normal_matrix * normal).normalize().into(),
                    texcoord: [
                        ( poly_lut[ vert ] % 2 ) as f32,
                        ( poly_lut[ vert ] / 2 ) as f32,
                    ],
                });
            }
        }

        return Ok(vertices);
    }
}

#[test]
pub fn ensure_default_cuboid_has_unit_dimensions() {
    let vertices = CuboidBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for ref vertex in vertices {
        assert_eq!(vertex.position[0].abs(), 0.5);
        assert_eq!(vertex.position[1].abs(), 0.5);
        assert_eq!(vertex.position[2].abs(), 0.5);
    }
}

#[test]
pub fn ensure_default_cuboid_has_centroid_at_origin() {
    let vertices = CuboidBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    let mut sum = Vector3::<f32>::zero();
    for ref vertex in vertices {
        sum = sum + Vector3::<f32>::from(vertex.position);
    }
    assert_eq!(sum, Vector3::<f32>::zero());
}

#[test]
pub fn ensure_default_cuboid_has_outward_facing_normals() {
    let vertices = CuboidBuilder::new()
                   .scale(2.0, 2.0, 2.0)
                   .build_vertices()
                   .expect("Failed to build vertices");
    for ref vertex in vertices {
        let position = Vector3::<f32>::from(vertex.position);
        let normal = Vector3::<f32>::from(vertex.normal);
        let outside = position + normal;
        assert!(outside.x.abs() >= position.x.abs());
        assert!(outside.y.abs() >= position.y.abs());
        assert!(outside.z.abs() >= position.z.abs());
    }
}

#[test]
pub fn ensure_default_cuboid_has_uvs_in_unit_range() {
    let vertices = CuboidBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for ref vertex in vertices {
        assert!(vertex.texcoord[0] >= 0.0);
        assert!(vertex.texcoord[1] >= 0.0);
        assert!(vertex.texcoord[0] <= 1.0);
        assert!(vertex.texcoord[1] <= 1.0);
    }
}

#[test]
pub fn ensure_default_cuboid_has_ccw_triangles() {
    let vertices = CuboidBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for chunk in vertices.chunks(3) {
        let v0 = Vector3::<f32>::from(chunk[0].position);
        let v1 = Vector3::<f32>::from(chunk[1].position);
        let v2 = Vector3::<f32>::from(chunk[2].position);
        let e0 = v1 - v0;
        let e1 = v2 - v0;
        let n = e0.cross(e1);
        assert!(n.dot(v0) > 0.0);
        assert!(n.dot(v1) > 0.0);
        assert!(n.dot(v2) > 0.0);
    }
}

#[test]
pub fn ensure_default_cuboid_has_faceted_normals() {
    let vertices = CuboidBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for chunk in vertices.chunks(3) {
        let v0 = Vector3::<f32>::from(chunk[0].position);
        let v1 = Vector3::<f32>::from(chunk[1].position);
        let v2 = Vector3::<f32>::from(chunk[2].position);
        let n0 = Vector3::<f32>::from(chunk[0].normal);
        let n1 = Vector3::<f32>::from(chunk[1].normal);
        let n2 = Vector3::<f32>::from(chunk[2].normal);
        let e0 = v1 - v0;
        let e1 = v2 - v0;
        let n = e0.cross(e1);
        assert_eq!(n, n0);
        assert_eq!(n, n1);
        assert_eq!(n, n2);
    }
}
<|endoftext|>


<commit_before>use super::{Tokenizer, Whitespace};
use super::{ScanError, OtherScanError};

use std::str::CharRange;

pub trait ScanCursor<'scanee>: Clone + Eq {
	fn expect_tok(&self, s: &str) -> Result<Self, ScanError>;
	fn consumed(&self) -> uint;
	fn pop_token(&self) -> Option<(&'scanee str, Self)>;
	fn pop_ws(&self) -> Self;
	fn slice_from(&self, from: uint) -> Self;
	fn str_slice_to(&self, to: uint) -> &'scanee str;
	fn tail_str(&self) -> &'scanee str;
	fn is_empty(&self) -> bool;

	fn expect_eof(&self) -> Result<(), ScanError> {
		if self.pop_token().is_some() {
			Err(self.expected_eof())
		} else {
			Ok(())
		}
	}

	fn expected(&self, desc: &str) -> ScanError {
		let msg = match self.pop_token() {
			Some((got, _)) => format!("expected {}, got `{}`", desc, got),
			None => format!("expected {}, got end of input", desc)
		};

		OtherScanError(msg, self.consumed())
	}

	fn expected_tok(&self, tok: &str) -> ScanError {
		let toks = [tok];
		self.expected_one_of(&toks)
	}

	fn expected_eof(&self) -> ScanError {
		self.expected_one_of(&[])
	}

	fn expected_one_of(&self, toks: &[&str]) -> ScanError {
		let mut toks = toks.iter().map(|s| format!("`{}`", s));
		let toks = {
			let first = toks.next();
			first.map(|first| toks.fold(first, |a,b| format!("{}, {}", a, b)))
		};

		let msg = match (toks, self.pop_token()) {
			(Some(exp), Some((got, _))) => format!("expected {}, got `{}`", exp, got),
			(Some(exp), None) => format!("expected {}, got end of input", exp),
			(None, Some((got, _))) => format!("expected end of input, got `{}`", got),
			(None, None) => "expected end of input".into_string()
		};

		OtherScanError(msg, self.consumed())
	}

	fn expected_min_repeats(&self, min: uint, got: uint) -> ScanError {
		OtherScanError(format!("expected at least {} repeats, got {}", min, got), self.consumed())
	}
}

#[deriving(Clone, Eq, PartialEq, Show)]
pub struct Cursor<'a, Tok: Tokenizer, Sp: Whitespace> {
	slice: &'a str,
	offset: uint,
	tc: Tok,
	sp: Sp,
}

impl<'a, Tok: Tokenizer, Sp: Whitespace> Cursor<'a, Tok, Sp> {
	pub fn new<'b>(s: &'b str, tc: Tok, sp: Sp) -> Cursor<'b, Tok, Sp> {
		Cursor {
			slice: s,
			offset: 0,
			tc: tc,
			sp: sp,
		}
	}
}

impl<'a, Tok: Tokenizer, Sp: Whitespace> ScanCursor<'a> for Cursor<'a, Tok, Sp> {
	fn expect_tok(&self, s: &str) -> Result<Cursor<'a, Tok, Sp>, ScanError> {
		debug!("{}.expect_tok({})", self, s);
		match self.pop_token() {
			Some((tok, ref cur)) if eq_ignore_case(s, tok) => Ok(cur.clone()),
			_ => Err(self.expected_tok(s))
		}
	}

	fn consumed(&self) -> uint {
		self.offset
	}

	fn pop_token(&self) -> Option<(&'a str, Cursor<'a, Tok, Sp>)> {
		debug!("{}.pop_token()", self);
		let cur = self;

		// First, check to see if there is a whitespace token.  This allows the space policy to do things like ignore most whitespace, but turn line breaks into explicit tokens.
		match self.sp.token_len(cur.tail_str()) {
			Some(end) => return Some((cur.str_slice_to(end), cur.slice_from(end))),
			None => ()
		}

		// If that didn't work, strip out leading whitespace.
		let cur = self.pop_ws();

		// Do not assume that empty input means we can't match a token; the token class might, for example, turn end-of-input into an explicit token.
		let tail_str = cur.tail_str();
		match self.tc.token_len(tail_str) {
			Some(end) => Some((cur.str_slice_to(end), cur.slice_from(end))),
			None => {
				// One of two things: either we have some input left and will thus return a single-character token, or there is nothing left whereby we return None.
				if cur.is_empty() {
					return None;
				} else {
					let CharRange { ch: _, next } = tail_str.char_range_at(0);
					Some((cur.str_slice_to(next), cur.slice_from(next)))
				}
			},
		}
	}

	fn pop_ws(&self) -> Cursor<'a, Tok, Sp> {
		debug!("{}.pop_ws()", self);

		self.slice_from(self.sp.strip_len(self.tail_str()))
	}

	fn slice_from(&self, from: uint) -> Cursor<'a, Tok, Sp> {
		Cursor {
			offset: ::std::cmp::min(self.slice.len(), self.offset + from),
			..self.clone()
		}
	}

	fn str_slice_to(&self, to: uint) -> &'a str {
		self.tail_str().slice_to(to)
	}

	fn tail_str(&self) -> &'a str {
		self.slice.slice_from(self.offset)
	}

	fn is_empty(&self) -> bool {
		self.offset == self.slice.len()
	}
}

fn eq_ignore_case<S: Str, T: Str>(left: S, right: T) -> bool {
	let left = left.as_slice();
	let right = right.as_slice();

	(left.len() == right.len()
		&& (left.chars().zip(right.chars())
			.all(|(l,r)| l.to_lowercase() == r.to_lowercase())))
}
<commit_msg>Added ScanCursor::str_slice_to_cur.<commit_after>use super::{Tokenizer, Whitespace};
use super::{ScanError, OtherScanError};

use std::str::CharRange;

pub trait ScanCursor<'scanee>: Clone + Eq {
	fn expect_tok(&self, s: &str) -> Result<Self, ScanError>;
	fn consumed(&self) -> uint;
	fn pop_token(&self) -> Option<(&'scanee str, Self)>;
	fn pop_ws(&self) -> Self;
	fn slice_from(&self, from: uint) -> Self;
	fn str_slice_to(&self, to: uint) -> &'scanee str;
	fn str_slice_to_cur(&self, to: &Self) -> &'scanee str;
	fn tail_str(&self) -> &'scanee str;
	fn is_empty(&self) -> bool;

	fn expect_eof(&self) -> Result<(), ScanError> {
		if self.pop_token().is_some() {
			Err(self.expected_eof())
		} else {
			Ok(())
		}
	}

	fn expected(&self, desc: &str) -> ScanError {
		let msg = match self.pop_token() {
			Some((got, _)) => format!("expected {}, got `{}`", desc, got),
			None => format!("expected {}, got end of input", desc)
		};

		OtherScanError(msg, self.consumed())
	}

	fn expected_tok(&self, tok: &str) -> ScanError {
		let toks = [tok];
		self.expected_one_of(&toks)
	}

	fn expected_eof(&self) -> ScanError {
		self.expected_one_of(&[])
	}

	fn expected_one_of(&self, toks: &[&str]) -> ScanError {
		let mut toks = toks.iter().map(|s| format!("`{}`", s));
		let toks = {
			let first = toks.next();
			first.map(|first| toks.fold(first, |a,b| format!("{}, {}", a, b)))
		};

		let msg = match (toks, self.pop_token()) {
			(Some(exp), Some((got, _))) => format!("expected {}, got `{}`", exp, got),
			(Some(exp), None) => format!("expected {}, got end of input", exp),
			(None, Some((got, _))) => format!("expected end of input, got `{}`", got),
			(None, None) => "expected end of input".into_string()
		};

		OtherScanError(msg, self.consumed())
	}

	fn expected_min_repeats(&self, min: uint, got: uint) -> ScanError {
		OtherScanError(format!("expected at least {} repeats, got {}", min, got), self.consumed())
	}
}

#[deriving(Clone, Eq, PartialEq, Show)]
pub struct Cursor<'a, Tok: Tokenizer, Sp: Whitespace> {
	slice: &'a str,
	offset: uint,
	tc: Tok,
	sp: Sp,
}

impl<'a, Tok: Tokenizer, Sp: Whitespace> Cursor<'a, Tok, Sp> {
	pub fn new<'b>(s: &'b str, tc: Tok, sp: Sp) -> Cursor<'b, Tok, Sp> {
		Cursor {
			slice: s,
			offset: 0,
			tc: tc,
			sp: sp,
		}
	}
}

impl<'a, Tok: Tokenizer, Sp: Whitespace> ScanCursor<'a> for Cursor<'a, Tok, Sp> {
	fn expect_tok(&self, s: &str) -> Result<Cursor<'a, Tok, Sp>, ScanError> {
		debug!("{}.expect_tok({})", self, s);
		match self.pop_token() {
			Some((tok, ref cur)) if eq_ignore_case(s, tok) => Ok(cur.clone()),
			_ => Err(self.expected_tok(s))
		}
	}

	fn consumed(&self) -> uint {
		self.offset
	}

	fn pop_token(&self) -> Option<(&'a str, Cursor<'a, Tok, Sp>)> {
		debug!("{}.pop_token()", self);
		let cur = self;

		// First, check to see if there is a whitespace token.  This allows the space policy to do things like ignore most whitespace, but turn line breaks into explicit tokens.
		match self.sp.token_len(cur.tail_str()) {
			Some(end) => return Some((cur.str_slice_to(end), cur.slice_from(end))),
			None => ()
		}

		// If that didn't work, strip out leading whitespace.
		let cur = self.pop_ws();

		// Do not assume that empty input means we can't match a token; the token class might, for example, turn end-of-input into an explicit token.
		let tail_str = cur.tail_str();
		match self.tc.token_len(tail_str) {
			Some(end) => Some((cur.str_slice_to(end), cur.slice_from(end))),
			None => {
				// One of two things: either we have some input left and will thus return a single-character token, or there is nothing left whereby we return None.
				if cur.is_empty() {
					return None;
				} else {
					let CharRange { ch: _, next } = tail_str.char_range_at(0);
					Some((cur.str_slice_to(next), cur.slice_from(next)))
				}
			},
		}
	}

	fn pop_ws(&self) -> Cursor<'a, Tok, Sp> {
		debug!("{}.pop_ws()", self);

		self.slice_from(self.sp.strip_len(self.tail_str()))
	}

	fn slice_from(&self, from: uint) -> Cursor<'a, Tok, Sp> {
		Cursor {
			offset: ::std::cmp::min(self.slice.len(), self.offset + from),
			..self.clone()
		}
	}

	fn str_slice_to(&self, to: uint) -> &'a str {
		self.tail_str().slice_to(to)
	}

	fn str_slice_to_cur(&self, to: &Cursor<'a, Tok, Sp>) -> &'a str {
		self.slice.slice(self.offset, to.offset)
	}

	fn tail_str(&self) -> &'a str {
		self.slice.slice_from(self.offset)
	}

	fn is_empty(&self) -> bool {
		self.offset == self.slice.len()
	}
}

fn eq_ignore_case<S: Str, T: Str>(left: S, right: T) -> bool {
	let left = left.as_slice();
	let right = right.as_slice();

	(left.len() == right.len()
		&& (left.chars().zip(right.chars())
			.all(|(l,r)| l.to_lowercase() == r.to_lowercase())))
}
<|endoftext|>


<commit_before>#[derive(Debug,Clone,RustcEncodable)]
pub struct Image {
    pub id: i32,
    pub name: String,
    pub tags: Vec<String>,
    pub got_from: Option<String>,
    pub original_link: Option<String>,
    pub uploader: Option<String>,
    pub rating: Option<char>,
    pub score: i32
}

/// Image voting error
pub enum VoteImageError {
    /// Voting up/down twice
    Already,
    /// No such image
    NoImage
}

/// Partial tags, e.g. `Some*`
#[derive(Debug,Clone)]
enum AnyWith {
    After(String),
    Before(String)
}

/// Ascending/descending sort
#[derive(Debug,Clone)]
enum AscDesc {
    Asc,
    Desc
}

/// Sorting, e.g. `sort:asc/desc:id/score`
#[derive(Debug,Clone)]
enum OrderBy {
    Id,
    Score
}

#[derive(Debug,Clone)]
enum Tag {
    /// Just a tag
    Include(String),
    /// Exlude tag
    Exclude(String),
    /// Rating, e.g. rating:s for safe
    Rating(Vec<String>),
    /// Partial tag
    AnyWith(AnyWith),
    /// from:derpibooru,konachan etc.
    From(Vec<String>),
    /// Uploader search
    Uploader(Vec<String>),
    /// Sorting
    OrderBy(OrderBy, AscDesc)
}

/// `pub` is used to switch DBs, though only postgres works TODO: fix sqlite sometime
pub mod postgres;
mod sqlite;

#[cfg(feature = "sqlite")]
pub use self::sqlite::Db;

#[cfg(feature = "postgresql")]
pub use self::postgres::Db;

/// Tag parsing
fn parse_tag(tag: &str) -> Tag {
    let all = tag.split(':').collect::<Vec<_>>();
    match all.len() {
        1 => {
            let tag = all[0];
            if tag.starts_with('-') {
                Tag::Exclude(tag[1..].to_string())
            } else if tag.starts_with('*') {
                Tag::AnyWith(AnyWith::After(tag[1..].to_string()))
            } else if tag.ends_with('*') {
                let mut n = tag.to_string();
                n.pop();
                Tag::AnyWith(AnyWith::Before(n))
            } else {
                Tag::Include(tag.to_string())
            }
        },
        2 => {
            let kind = all[0];
            let values = all[1].split(',').map(String::from).collect::<Vec<_>>();
            match kind {
                "rating"    => Tag::Rating(values),
                "from"      => Tag::From(values),
                "uploader"  => Tag::Uploader(values),
                _           => Tag::Include(tag.to_string()) // Probably shouldn't be anything there?
            }
        },
        3 => { // Probably sort, but should check
            if all[0] == "sort" {
                let aod = match all[1] {
                    "asc" => AscDesc::Asc, // - -> +
                    "desc" | _ => AscDesc::Desc, // + -> -
                };
                let by = match all[2] {
                    "score" => OrderBy::Score,
                    "id" | _ => OrderBy::Id,
                };

                Tag::OrderBy(by, aod)
            } else {
                Tag::Include(tag.to_string())
            }
        },
        _   => { // Shouldn't happen
            Tag::Include(tag.to_string())
        }
    }
}

/// Strcture to ease image addition
pub struct ImageBuilder {
    name: String,
    tags: Vec<String>,
    got_from: Option<String>,
    original_link: Option<String>,
    uploader: Option<String>,
    score: i32,
    rating: Option<char>
}

impl ImageBuilder {
    pub fn new(name: &str, tags: &[String]) -> Self {
        ImageBuilder{
            name: name.to_string(),
            tags: tags.to_owned(),
            got_from: None,
            original_link: None,
            uploader: None,
            score: 0,
            rating: None
        }
    }

    pub fn got_from(mut self, got_from: &str) -> Self {
        self.got_from = Some(got_from.to_string());
        self
    }

    pub fn original_link(mut self, original_link: &str) -> Self {
        self.original_link = Some(original_link.to_string());
        self
    }

    pub fn uploader(mut self, uploader: &str) -> Self {
        self.uploader = Some(uploader.to_string());
        self
    }

    pub fn score(mut self, score: i32) -> Self {
        self.score = score;
        self
    }

    pub fn rating(mut self, rating: char) -> Self {
        self.rating = Some(rating);
        self
    }

    pub fn finalize(self) -> Self { self }
}
<commit_msg>Probably should escape symbols<commit_after>#[derive(Debug,Clone,RustcEncodable)]
pub struct Image {
    pub id: i32,
    pub name: String,
    pub tags: Vec<String>,
    pub got_from: Option<String>,
    pub original_link: Option<String>,
    pub uploader: Option<String>,
    pub rating: Option<char>,
    pub score: i32
}

/// Image voting error
pub enum VoteImageError {
    /// Voting up/down twice
    Already,
    /// No such image
    NoImage
}

/// Partial tags, e.g. `Some*`
#[derive(Debug,Clone)]
enum AnyWith {
    After(String),
    Before(String)
}

/// Ascending/descending sort
#[derive(Debug,Clone)]
enum AscDesc {
    Asc,
    Desc
}

/// Sorting, e.g. `sort:asc/desc:id/score`
#[derive(Debug,Clone)]
enum OrderBy {
    Id,
    Score
}

#[derive(Debug,Clone)]
enum Tag {
    /// Just a tag
    Include(String),
    /// Exlude tag
    Exclude(String),
    /// Rating, e.g. rating:s for safe
    Rating(Vec<String>),
    /// Partial tag
    AnyWith(AnyWith),
    /// from:derpibooru,konachan etc.
    From(Vec<String>),
    /// Uploader search
    Uploader(Vec<String>),
    /// Sorting
    OrderBy(OrderBy, AscDesc)
}

/// `pub` is used to switch DBs, though only postgres works TODO: fix sqlite sometime
pub mod postgres;
mod sqlite;

#[cfg(feature = "sqlite")]
pub use self::sqlite::Db;

#[cfg(feature = "postgresql")]
pub use self::postgres::Db;

/// Tag parsing
fn parse_tag(tag: &str) -> Tag {
    let tag = tag.replace('\'', "''").replace(r'\\', r"\\");
    let all = tag.split(':').collect::<Vec<_>>();
    match all.len() {
        1 => {
            let tag = all[0];
            if tag.starts_with('-') {
                Tag::Exclude(tag[1..].to_string())
            } else if tag.starts_with('*') {
                Tag::AnyWith(AnyWith::After(tag[1..].to_string()))
            } else if tag.ends_with('*') {
                let mut n = tag.to_string();
                n.pop();
                Tag::AnyWith(AnyWith::Before(n))
            } else {
                Tag::Include(tag.to_string())
            }
        },
        2 => {
            let kind = all[0];
            let values = all[1].split(',').map(String::from).collect::<Vec<_>>();
            match kind {
                "rating"    => Tag::Rating(values),
                "from"      => Tag::From(values),
                "uploader"  => Tag::Uploader(values),
                _           => Tag::Include(tag.to_string()) // Probably shouldn't be anything there?
            }
        },
        3 => { // Probably sort, but should check
            if all[0] == "sort" {
                let aod = match all[1] {
                    "asc" => AscDesc::Asc, // - -> +
                    "desc" | _ => AscDesc::Desc, // + -> -
                };
                let by = match all[2] {
                    "score" => OrderBy::Score,
                    "id" | _ => OrderBy::Id,
                };

                Tag::OrderBy(by, aod)
            } else {
                Tag::Include(tag.to_string())
            }
        },
        _   => { // Shouldn't happen
            Tag::Include(tag.to_string())
        }
    }
}

/// Strcture to ease image addition
pub struct ImageBuilder {
    name: String,
    tags: Vec<String>,
    got_from: Option<String>,
    original_link: Option<String>,
    uploader: Option<String>,
    score: i32,
    rating: Option<char>
}

impl ImageBuilder {
    pub fn new(name: &str, tags: &[String]) -> Self {
        ImageBuilder{
            name: name.to_string(),
            tags: tags.to_owned(),
            got_from: None,
            original_link: None,
            uploader: None,
            score: 0,
            rating: None
        }
    }

    pub fn got_from(mut self, got_from: &str) -> Self {
        self.got_from = Some(got_from.to_string());
        self
    }

    pub fn original_link(mut self, original_link: &str) -> Self {
        self.original_link = Some(original_link.to_string());
        self
    }

    pub fn uploader(mut self, uploader: &str) -> Self {
        self.uploader = Some(uploader.to_string());
        self
    }

    pub fn score(mut self, score: i32) -> Self {
        self.score = score;
        self
    }

    pub fn rating(mut self, rating: char) -> Self {
        self.rating = Some(rating);
        self
    }

    pub fn finalize(self) -> Self { self }
}
<|endoftext|>


<commit_before>use error_chain::ChainedError;
use ffmpeg;
use std::sync::Mutex;

use errors::*;

lazy_static! {
    static ref VIDEO_ENCODER: Mutex<Option<ffmpeg::codec::Video>> = Mutex::new(None);
}

/// Initialize the encoding stuff. Should be called once.
pub fn initialize() -> Result<()> {
    ffmpeg::init().chain_err(|| "error initializing ffmpeg")?;

    Ok(())
}

command!(cap_set_video_encoder, |engine| {
    let mut args = engine.args();

    if args.len() != 2 {
        let mut buf = String::new();

        buf.push_str("Usage:\n");
        buf.push_str("    cap_set_video_encoder <encoder>\n");
        buf.push_str("     - Set the video encoder by name.\n");
        buf.push_str("Example:\n");
        buf.push_str("    cap_set_video_encoder libx264\n");

        engine.con_print(&buf);
        return;
    }

    let encoder_name = args.nth(1).unwrap();

    if let Some(encoder) = ffmpeg::encoder::find_by_name(&encoder_name) {
        if let Ok(video) = encoder.video() {
            let mut buf = String::new();

            buf.push_str(&format!("Selected encoder: {}\n", encoder_name));
            buf.push_str(&format!("Description: {}\n", encoder.description()));
            buf.push_str("Pixel formats: ");

            if let Some(formats) = video.formats() {
                buf.push_str(&format!("{:?}\n", formats.collect::<Vec<_>>()));
            } else {
                buf.push_str("any\n");
            }

            engine.con_print(&buf);

            *VIDEO_ENCODER.lock().unwrap() = Some(video);
        } else {
            engine.con_print(&format!("Invalid encoder type '{}'\n", encoder_name));
        }
    } else {
        engine.con_print(&format!("Unknown encoder '{}'\n", encoder_name));
    }
});

command!(cap_test_video_output, |engine| {
    if VIDEO_ENCODER.lock().unwrap().is_none() {
        engine.con_print("Please set the video encoder with cap_set_video_encoder.\n");
        return;
    }

    if let Err(ref e) = test_video_output().chain_err(|| "error in test_video_output()") {
        engine.con_print(&format!("{}", e.display()));
        return;
    }

    engine.con_print("Done!\n");
});

fn test_video_output() -> Result<()> {
    let codec = VIDEO_ENCODER.lock().unwrap();

    ensure!(codec.is_some(), "video encoder was not set");

    let codec = codec.unwrap();

    let mut context = ffmpeg::format::output(&"/home/yalter/test.mp4")
        .chain_err(|| "could not create the output context")?;

    let mut encoder = {
        let mut stream = context.add_stream(codec)
            .chain_err(|| "could not add the video stream")?;

        let mut encoder = stream.codec().encoder().video()
            .chain_err(|| "could not retrieve the video encoder")?;

        encoder.set_width(640);
        encoder.set_height(360);
        encoder.set_time_base((1, 60));

        if let Some(mut formats) = codec.formats() {
            encoder.set_format(formats.next().unwrap());
        } else {
            encoder.set_format(ffmpeg::format::Pixel::YUV420P);
        }

        let encoder = encoder.open_as(codec).chain_err(|| "could not open the video encoder")?;
        stream.set_parameters(&encoder);

        stream.set_time_base((1, 60));

        encoder
    };

    context.write_header()
        .chain_err(|| "could not write the header")?;

    let stream_time_base = context.stream(0).unwrap().time_base();

    let mut converter = ffmpeg::software::converter((640, 360),
                                                ffmpeg::format::Pixel::RGB24,
                                                encoder.format())
        .chain_err(|| "could not get the color conversion context")?;

    {
        let mut frame = ffmpeg::frame::Video::new(ffmpeg::format::Pixel::RGB24, 640, 360);
        let mut output_frame = ffmpeg::frame::Video::new(encoder.format(), 640, 360);

        for i in 0..255 {
            {
                let mut y = frame.plane_mut::<(u8, u8, u8)>(0);

                for j in 0..y.len() {
                    y[j] = (255, i as u8, 255 - i as u8);
                }
            }

            converter.run(&frame, &mut output_frame)
                .chain_err(|| "could not convert the frame to the correct format")?;

            output_frame.set_pts(Some(i));

            let mut packet = ffmpeg::Packet::empty();
            if encoder.encode(&output_frame, &mut packet).chain_err(|| "could not encode the frame")? {
                packet.rescale_ts((1, 60), stream_time_base);

                packet.write_interleaved(&mut context)
                    .chain_err(|| "could not write the packet")?;
            }
        }

        let mut packet = ffmpeg::Packet::empty();
        while encoder.flush(&mut packet).chain_err(|| "could not get the packet")? {
            packet.rescale_ts((1, 60), stream_time_base);

            packet.write_interleaved(&mut context)
                .chain_err(|| "could not write the packet")?;
        }
    }

    context.write_trailer()
        .chain_err(|| "could not write the trailer")?;

    Ok(())
}
<commit_msg>Encapsulate all encoding stuff into an Encoder<commit_after>use error_chain::ChainedError;
use ffmpeg;
use std::sync::Mutex;

use errors::*;

lazy_static! {
    static ref VIDEO_ENCODER: Mutex<Option<ffmpeg::codec::Video>> = Mutex::new(None);
}

struct Encoder {
    converter: ffmpeg::software::scaling::Context,
    context: ffmpeg::format::context::Output,
    encoder: ffmpeg::codec::encoder::Video,
    output_frame: ffmpeg::util::frame::Video,
    packet: ffmpeg::Packet,

    time_base: ffmpeg::Rational,
    stream_time_base: ffmpeg::Rational,

    pts: i64,
}

impl Encoder {
    fn start(filename: &str,
             codec: ffmpeg::codec::Video,
             (width, height): (u32, u32),
             time_base: ffmpeg::Rational) -> Result<Self> {
        let mut context = ffmpeg::format::output(&filename)
            .chain_err(|| "could not create the output context")?;

        let encoder = {
            let mut stream = context.add_stream(codec)
                .chain_err(|| "could not add the video stream")?;

            let mut encoder = stream.codec().encoder().video()
                .chain_err(|| "could not retrieve the video encoder")?;

            encoder.set_width(width);
            encoder.set_height(height);
            encoder.set_time_base(time_base);

            if let Some(mut formats) = codec.formats() {
                encoder.set_format(formats.next().unwrap());
            } else {
                encoder.set_format(ffmpeg::format::Pixel::YUV420P);
            }

            let encoder = encoder.open_as(codec)
                .chain_err(|| "could not open the video encoder")?;
            stream.set_parameters(&encoder);

            stream.set_time_base(time_base);

            encoder
        };

        context.write_header()
            .chain_err(|| "could not write the header")?;

        let stream_time_base = context.stream(0).unwrap().time_base();

        let converter = ffmpeg::software::converter((width, height),
                                                    ffmpeg::format::Pixel::RGB24,
                                                    encoder.format())
            .chain_err(|| "could not get the color conversion context")?;

        let output_frame = ffmpeg::frame::Video::new(encoder.format(), width, height);

        let packet = ffmpeg::Packet::empty();

        Ok(Self {
            converter,
            context,
            encoder,
            output_frame,
            packet,

            time_base,
            stream_time_base,

            pts: 0,
        })
    }

    fn encode(&mut self, frame: &ffmpeg::frame::Video) -> Result<()> {
        self.converter.run(&frame, &mut self.output_frame)
            .chain_err(|| "could not convert the frame to the correct format")?;

        self.output_frame.set_pts(Some(self.pts));
        self.pts += 1;

        if self.encoder.encode(&self.output_frame, &mut self.packet)
            .chain_err(|| "could not encode the frame")? {
            self.packet.rescale_ts(self.time_base, self.stream_time_base);

            self.packet.write_interleaved(&mut self.context)
                .chain_err(|| "could not write the packet")?;
        }

        Ok(())
    }

    fn flush(&mut self) -> Result<()> {
        while self.encoder.flush(&mut self.packet)
            .chain_err(|| "could not get the packet")? {
            self.packet.rescale_ts(self.time_base, self.stream_time_base);

            self.packet.write_interleaved(&mut self.context)
                .chain_err(|| "could not write the packet")?;
        }

        Ok(())
    }
}

impl Drop for Encoder {
    fn drop(&mut self) {
        self.flush();
        self.context.write_trailer();
    }
}

/// Initialize the encoding stuff. Should be called once.
pub fn initialize() -> Result<()> {
    ffmpeg::init().chain_err(|| "error initializing ffmpeg")?;

    Ok(())
}

command!(cap_set_video_encoder, |engine| {
    let mut args = engine.args();

    if args.len() != 2 {
        let mut buf = String::new();

        buf.push_str("Usage:\n");
        buf.push_str("    cap_set_video_encoder <encoder>\n");
        buf.push_str("     - Set the video encoder by name.\n");
        buf.push_str("Example:\n");
        buf.push_str("    cap_set_video_encoder libx264\n");

        engine.con_print(&buf);
        return;
    }

    let encoder_name = args.nth(1).unwrap();

    if let Some(encoder) = ffmpeg::encoder::find_by_name(&encoder_name) {
        if let Ok(video) = encoder.video() {
            let mut buf = String::new();

            buf.push_str(&format!("Selected encoder: {}\n", encoder_name));
            buf.push_str(&format!("Description: {}\n", encoder.description()));
            buf.push_str("Pixel formats: ");

            if let Some(formats) = video.formats() {
                buf.push_str(&format!("{:?}\n", formats.collect::<Vec<_>>()));
            } else {
                buf.push_str("any\n");
            }

            engine.con_print(&buf);

            *VIDEO_ENCODER.lock().unwrap() = Some(video);
        } else {
            engine.con_print(&format!("Invalid encoder type '{}'\n", encoder_name));
        }
    } else {
        engine.con_print(&format!("Unknown encoder '{}'\n", encoder_name));
    }
});

command!(cap_test_video_output, |engine| {
    if VIDEO_ENCODER.lock().unwrap().is_none() {
        engine.con_print("Please set the video encoder with cap_set_video_encoder.\n");
        return;
    }

    if let Err(ref e) = test_video_output().chain_err(|| "error in test_video_output()") {
        engine.con_print(&format!("{}", e.display()));
        return;
    }

    engine.con_print("Done!\n");
});

fn test_video_output() -> Result<()> {
    let codec = VIDEO_ENCODER.lock().unwrap();

    ensure!(codec.is_some(), "video encoder was not set");

    let codec = codec.unwrap();

    let mut encoder = Encoder::start("/home/yalter/test.mkv",
                                     codec,
                                     (1280, 720),
                                     (1, 60).into())
        .chain_err(|| "could not create the encoder")?;

    let mut frame = ffmpeg::frame::Video::new(ffmpeg::format::Pixel::RGB24, 1280, 720);

    {
        let mut data = frame.plane_mut::<(u8, u8, u8)>(0);
        for i in 0..data.len() {
            data[i] = (0, 255, 0);
        }
    }

    for f in 0..240 {
        {
            let mut data = frame.plane_mut::<(u8, u8, u8)>(0);
            for y in 0..720 {
                data[y * 1280 + f * 2] = (255, 0, 0);
                data[y * 1280 + f * 2 + 1] = (255, 0, 0);
            }
        }

        encoder.encode(&frame)
            .chain_err(|| "could not encode a frame")?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::fmt;
use rustc_serialize;

#[derive(Clone, Copy, Debug)]
pub enum EncoderError {
    Format(fmt::Error),
    Expectation(Expect),
}

impl From<fmt::Error> for EncoderError {
    fn from(err: fmt::Error) -> EncoderError {
        EncoderError::Format(err)
    }
}

enum EncodingFormat<'a> {
    Compact,
    Pretty {
        indent: &'a str,
    },
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Expect {
    Constant,
    Element,
}

struct EncodingState {
    expect: Expect,
    indent: u32,
    start_line: bool,
}

/// A structure for implementing serialization to RON.
pub struct Encoder<'a> {
    writer: &'a mut (fmt::Write+'a),
    format : EncodingFormat<'a>,
    state: EncodingState,
}

impl<'a> Encoder<'a> {
    /// Creates a new encoder whose output will be written in compact
    /// RON to the specified writer
    pub fn new(writer: &'a mut fmt::Write) -> Encoder<'a> {
        Encoder {
            writer: writer,
            format: EncodingFormat::Compact,
            state: EncodingState {
                expect: Expect::Element,
                indent: 0,
                start_line: false,
            },
        }
    }

    /// Creates a new encoder whose output will be written in pretty
    /// RON to the specified writer
    pub fn new_pretty(writer: &'a mut fmt::Write, indent: &'a str) -> Encoder<'a> {
        Encoder {
            writer: writer,
            format: EncodingFormat::Pretty {
                indent: indent,
            },
            state: EncodingState {
                expect: Expect::Element,
                indent: 0,
                start_line: false,
            },
        }
    }

    fn emit_constant<T: fmt::Display>(&mut self, v: T) -> EncodeResult {
        match self.state.expect {
            Expect::Element | Expect::Constant => {
                try!(write!(self.writer, "{}", v));
                Ok(())
            },
            //_ => Err(EncoderError::Expectation(self.state.expect)),
        }
    }

    fn emit_escape<T: fmt::Display>(&mut self, v: T, escape: char) -> EncodeResult {
        match self.state.expect {
            Expect::Constant | Expect::Element => {
                try!(write!(self.writer, "{}{}{}", escape, v, escape));
                Ok(())
            },
            //_ => Err(EncoderError::Expectation(self.state.expect)),
        }
    }

    fn new_line(&mut self) -> Result<(), fmt::Error> {
        if let EncodingFormat::Pretty { indent } = self.format {
            try!(write!(self.writer, "\n"));
            for _ in 0 .. self.state.indent {
                try!(write!(self.writer, "{}", indent));
            }
        }
        Ok(())
    }

    fn get_space(&self) -> &'static str {
        match self.format {
            EncodingFormat::Pretty{..} => " ",
            EncodingFormat::Compact => "",
        }
    }
}

/// A shortcut to encoding result.
pub type EncodeResult = Result<(), EncoderError>;

impl<'a> rustc_serialize::Encoder for Encoder<'a> {
    type Error = EncoderError;

    fn emit_nil(&mut self) -> EncodeResult {
        match self.state.expect {
            Expect::Element => {
                try!(write!(self.writer, "()"));
                Ok(())
            },
            _ => Err(EncoderError::Expectation(self.state.expect)),
        }
    }

    fn emit_usize(&mut self, v: usize)  -> EncodeResult { self.emit_constant(v) }
    fn emit_u64(&mut self, v: u64)      -> EncodeResult { self.emit_constant(v) }
    fn emit_u32(&mut self, v: u32)      -> EncodeResult { self.emit_constant(v) }
    fn emit_u16(&mut self, v: u16)      -> EncodeResult { self.emit_constant(v) }
    fn emit_u8(&mut self, v: u8)        -> EncodeResult { self.emit_constant(v) }

    fn emit_isize(&mut self, v: isize)  -> EncodeResult { self.emit_constant(v) }
    fn emit_i64(&mut self, v: i64)      -> EncodeResult { self.emit_constant(v) }
    fn emit_i32(&mut self, v: i32)      -> EncodeResult { self.emit_constant(v) }
    fn emit_i16(&mut self, v: i16)      -> EncodeResult { self.emit_constant(v) }
    fn emit_i8(&mut self, v: i8)        -> EncodeResult { self.emit_constant(v) }

    fn emit_bool(&mut self, v: bool)    -> EncodeResult { self.emit_constant(v) }
    fn emit_f64(&mut self, v: f64)      -> EncodeResult { self.emit_constant(v) }
    fn emit_f32(&mut self, v: f32)      -> EncodeResult { self.emit_constant(v) }

    fn emit_char(&mut self, v: char)    -> EncodeResult { self.emit_escape(v, '\'') }
    fn emit_str(&mut self, v: &str)     -> EncodeResult { self.emit_escape(v, '\"') }

    fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        if self.state.expect == Expect::Element {
            f(self)
        } else {
            Err(EncoderError::Expectation(self.state.expect))
        }
    }

    fn emit_enum_variant<F>(&mut self, name: &str, _id: usize, cnt: usize, f: F)
                         -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_struct(name, cnt, f)
    }

    fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_tuple_arg(idx, f)
    }

    fn emit_enum_struct_variant<F>(&mut self, name: &str, _id: usize, _cnt: usize, f: F)
                                -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        try!(write!(self.writer, "{}{{", name));
        self.state.indent += 1;
        try!(f(self));
        self.state.indent -= 1;
        try!(self.new_line());
        try!(write!(self.writer, "}}"));
        Ok(())
    }

    fn emit_enum_struct_variant_field<F>(&mut self, name: &str, idx: usize, f: F)
                                      -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_struct_field(name, idx, f)
    }

    fn emit_struct<F>(&mut self, name: &str, len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        if self.state.expect != Expect::Element {
            return Err(EncoderError::Expectation(self.state.expect))
        }
        if len == 0 {
            try!(write!(self.writer, "{}", name));
        } else {
            try!(write!(self.writer, "{}(", name));
            if len > 1 {
            	self.state.start_line = true;
                self.state.indent += 1;
                try!(f(self));
                self.state.indent -= 1;
                try!(self.new_line());
            } else {
            	self.state.start_line = false;
                try!(f(self));
            }
            try!(write!(self.writer, ")"));
        }
        Ok(())
    }

    fn emit_struct_field<F>(&mut self, name: &str, _idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        try!(self.new_line());
        let space = self.get_space();
        try!(write!(self.writer, "{}:{}", name, space));
        try!(f(self));
        try!(write!(self.writer, ","));
        Ok(())
    }

    fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_struct("", len, f)
    }

    fn emit_tuple_arg<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
    	if self.state.start_line {
        	try!(self.new_line());
        	try!(f(self));
        	try!(write!(self.writer, ","));
        	Ok(())
        } else {
        	f(self)
        }
    }

    fn emit_tuple_struct<F>(&mut self, name: &str, len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_struct(name, len, f)
    }

    fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_tuple_arg(idx, f)
    }

    fn emit_option<F>(&mut self, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_enum("", f)
    }

    fn emit_option_none(&mut self) -> EncodeResult {
        try!(write!(self.writer, "None"));
        Ok(())
    }

    fn emit_option_some<F>(&mut self, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_struct("Some", 1, f)
    }

    fn emit_seq<F>(&mut self, len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        if self.state.expect != Expect::Element {
            return Err(EncoderError::Expectation(self.state.expect))
        }
        if len == 0 {
            try!(write!(self.writer, "[]"));
        } else {
        	self.state.start_line = true;
            try!(write!(self.writer, "["));
            self.state.indent += 1;
            try!(f(self));
            self.state.indent -= 1;
            try!(self.new_line());
            try!(write!(self.writer, "]"));
        }
        Ok(())
    }

    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_tuple_arg(idx, f)
    }

    fn emit_map<F>(&mut self, len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        if self.state.expect != Expect::Element {
            return Err(EncoderError::Expectation(self.state.expect))
        }
        if len == 0 {
            try!(write!(self.writer, "{{}}"));
        } else {
            try!(write!(self.writer, "{{"));
            self.state.indent += 1;
            try!(f(self));
            self.state.indent -= 1;
            try!(self.new_line());
            try!(write!(self.writer, "}}"));
        }
        Ok(())
    }

    fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        try!(self.new_line());
        let expect = self.state.expect;
        self.state.expect = Expect::Constant;
        try!(f(self));
        try!(write!(self.writer, ","));
        self.state.expect = expect;
        Ok(())
    }

    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        let space = self.get_space();
        try!(write!(self.writer, ":{}", space));
        let expect = self.state.expect;
        self.state.expect = Expect::Element;
        try!(f(self));
        self.state.expect = expect;
        Ok(())
    }
}
<commit_msg>Refactored incoding type names<commit_after>use std::fmt;
use rustc_serialize;

#[derive(Clone, Copy, Debug)]
pub enum Error {
    Format(fmt::Error),
    Expectation(Expect),
}

impl From<fmt::Error> for Error {
    fn from(err: fmt::Error) -> Error {
        Error::Format(err)
    }
}

enum Format<'a> {
    Compact,
    Pretty {
        indent: &'a str,
    },
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Expect {
    Constant,
    Element,
}

struct State {
    expect: Expect,
    indent: u32,
    start_line: bool,
}

/// A structure for implementing serialization to RON.
pub struct Encoder<'a> {
    writer: &'a mut (fmt::Write+'a),
    format : Format<'a>,
    state: State,
}

impl<'a> Encoder<'a> {
    /// Creates a new encoder whose output will be written in compact
    /// RON to the specified writer
    pub fn new(writer: &'a mut fmt::Write) -> Encoder<'a> {
        Encoder {
            writer: writer,
            format: Format::Compact,
            state: State {
                expect: Expect::Element,
                indent: 0,
                start_line: false,
            },
        }
    }

    /// Creates a new encoder whose output will be written in pretty
    /// RON to the specified writer
    pub fn new_pretty(writer: &'a mut fmt::Write, indent: &'a str) -> Encoder<'a> {
        Encoder {
            writer: writer,
            format: Format::Pretty {
                indent: indent,
            },
            state: State {
                expect: Expect::Element,
                indent: 0,
                start_line: false,
            },
        }
    }

    fn emit_constant<T: fmt::Display>(&mut self, v: T) -> Result<(), Error> {
        match self.state.expect {
            Expect::Element | Expect::Constant => {
                try!(write!(self.writer, "{}", v));
                Ok(())
            },
            //_ => Err(Error::Expectation(self.state.expect)),
        }
    }

    fn emit_escape<T: fmt::Display>(&mut self, v: T, escape: char) -> Result<(), Error> {
        match self.state.expect {
            Expect::Constant | Expect::Element => {
                try!(write!(self.writer, "{}{}{}", escape, v, escape));
                Ok(())
            },
            //_ => Err(Error::Expectation(self.state.expect)),
        }
    }

    fn new_line(&mut self) -> Result<(), fmt::Error> {
        if let Format::Pretty { indent } = self.format {
            try!(write!(self.writer, "\n"));
            for _ in 0 .. self.state.indent {
                try!(write!(self.writer, "{}", indent));
            }
        }
        Ok(())
    }

    fn get_space(&self) -> &'static str {
        match self.format {
            Format::Pretty{..} => " ",
            Format::Compact => "",
        }
    }
}

impl<'a> rustc_serialize::Encoder for Encoder<'a> {
    type Error = Error;

    fn emit_nil(&mut self) -> Result<(), Error> {
        match self.state.expect {
            Expect::Element => {
                try!(write!(self.writer, "()"));
                Ok(())
            },
            _ => Err(Error::Expectation(self.state.expect)),
        }
    }

    fn emit_usize(&mut self, v: usize)  -> Result<(), Error> { self.emit_constant(v) }
    fn emit_u64(&mut self, v: u64)      -> Result<(), Error> { self.emit_constant(v) }
    fn emit_u32(&mut self, v: u32)      -> Result<(), Error> { self.emit_constant(v) }
    fn emit_u16(&mut self, v: u16)      -> Result<(), Error> { self.emit_constant(v) }
    fn emit_u8(&mut self, v: u8)        -> Result<(), Error> { self.emit_constant(v) }

    fn emit_isize(&mut self, v: isize)  -> Result<(), Error> { self.emit_constant(v) }
    fn emit_i64(&mut self, v: i64)      -> Result<(), Error> { self.emit_constant(v) }
    fn emit_i32(&mut self, v: i32)      -> Result<(), Error> { self.emit_constant(v) }
    fn emit_i16(&mut self, v: i16)      -> Result<(), Error> { self.emit_constant(v) }
    fn emit_i8(&mut self, v: i8)        -> Result<(), Error> { self.emit_constant(v) }

    fn emit_bool(&mut self, v: bool)    -> Result<(), Error> { self.emit_constant(v) }
    fn emit_f64(&mut self, v: f64)      -> Result<(), Error> { self.emit_constant(v) }
    fn emit_f32(&mut self, v: f32)      -> Result<(), Error> { self.emit_constant(v) }

    fn emit_char(&mut self, v: char)    -> Result<(), Error> { self.emit_escape(v, '\'') }
    fn emit_str(&mut self, v: &str)     -> Result<(), Error> { self.emit_escape(v, '\"') }

    fn emit_enum<F>(&mut self, _name: &str, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        if self.state.expect == Expect::Element {
            f(self)
        } else {
            Err(Error::Expectation(self.state.expect))
        }
    }

    fn emit_enum_variant<F>(&mut self, name: &str, _id: usize, cnt: usize, f: F)
                         -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        self.emit_struct(name, cnt, f)
    }

    fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        self.emit_tuple_arg(idx, f)
    }

    fn emit_enum_struct_variant<F>(&mut self, name: &str, _id: usize, _cnt: usize, f: F)
                                -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        try!(write!(self.writer, "{}{{", name));
        self.state.indent += 1;
        try!(f(self));
        self.state.indent -= 1;
        try!(self.new_line());
        try!(write!(self.writer, "}}"));
        Ok(())
    }

    fn emit_enum_struct_variant_field<F>(&mut self, name: &str, idx: usize, f: F)
                                      -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        self.emit_struct_field(name, idx, f)
    }

    fn emit_struct<F>(&mut self, name: &str, len: usize, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        if self.state.expect != Expect::Element {
            return Err(Error::Expectation(self.state.expect))
        }
        if len == 0 {
            try!(write!(self.writer, "{}", name));
        } else {
            try!(write!(self.writer, "{}(", name));
            if len > 1 {
                self.state.start_line = true;
                self.state.indent += 1;
                try!(f(self));
                self.state.indent -= 1;
                try!(self.new_line());
            } else {
                self.state.start_line = false;
                try!(f(self));
            }
            try!(write!(self.writer, ")"));
        }
        Ok(())
    }

    fn emit_struct_field<F>(&mut self, name: &str, _idx: usize, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        try!(self.new_line());
        let space = self.get_space();
        try!(write!(self.writer, "{}:{}", name, space));
        try!(f(self));
        try!(write!(self.writer, ","));
        Ok(())
    }

    fn emit_tuple<F>(&mut self, len: usize, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        self.emit_struct("", len, f)
    }

    fn emit_tuple_arg<F>(&mut self, _idx: usize, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        if self.state.start_line {
            try!(self.new_line());
            try!(f(self));
            try!(write!(self.writer, ","));
            Ok(())
        } else {
            f(self)
        }
    }

    fn emit_tuple_struct<F>(&mut self, name: &str, len: usize, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        self.emit_struct(name, len, f)
    }

    fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        self.emit_tuple_arg(idx, f)
    }

    fn emit_option<F>(&mut self, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        self.emit_enum("", f)
    }

    fn emit_option_none(&mut self) -> Result<(), Error> {
        try!(write!(self.writer, "None"));
        Ok(())
    }

    fn emit_option_some<F>(&mut self, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        self.emit_struct("Some", 1, f)
    }

    fn emit_seq<F>(&mut self, len: usize, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        if self.state.expect != Expect::Element {
            return Err(Error::Expectation(self.state.expect))
        }
        if len == 0 {
            try!(write!(self.writer, "[]"));
        } else {
            self.state.start_line = true;
            try!(write!(self.writer, "["));
            self.state.indent += 1;
            try!(f(self));
            self.state.indent -= 1;
            try!(self.new_line());
            try!(write!(self.writer, "]"));
        }
        Ok(())
    }

    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        self.emit_tuple_arg(idx, f)
    }

    fn emit_map<F>(&mut self, len: usize, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        if self.state.expect != Expect::Element {
            return Err(Error::Expectation(self.state.expect))
        }
        if len == 0 {
            try!(write!(self.writer, "{{}}"));
        } else {
            try!(write!(self.writer, "{{"));
            self.state.indent += 1;
            try!(f(self));
            self.state.indent -= 1;
            try!(self.new_line());
            try!(write!(self.writer, "}}"));
        }
        Ok(())
    }

    fn emit_map_elt_key<F>(&mut self, _idx: usize, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        try!(self.new_line());
        let expect = self.state.expect;
        self.state.expect = Expect::Constant;
        try!(f(self));
        try!(write!(self.writer, ","));
        self.state.expect = expect;
        Ok(())
    }

    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> Result<(), Error> where
        F: FnOnce(&mut Encoder<'a>) -> Result<(), Error>,
    {
        let space = self.get_space();
        try!(write!(self.writer, ":{}", space));
        let expect = self.state.expect;
        self.state.expect = Expect::Element;
        try!(f(self));
        self.state.expect = expect;
        Ok(())
    }
}
<|endoftext|>