<commit_before>//! Draw Line

use internal;
use triangulation;
use Graphics;
use Color;
use math::Matrix2d;
use DrawState;

/// The shape of the line
#[derive(Copy, Clone)]
pub enum Shape {
    /// Square edges
    Square,
    /// Round edges
    Round,
    /// Bevel edges
    Bevel,
}

/// The line border width
#[derive(Copy, Clone)]
pub struct Width(pub internal::Width);

/// A colored line with a default border radius
#[derive(Copy, Clone)]
pub struct Line {
    /// The line color
    pub color: internal::Color,
    /// The line radius
    pub radius: internal::Radius,
    /// The line shape
    pub shape: Shape,
}

impl Line {
    /// Creates a new line
    pub fn new(color: internal::Color, radius: internal::Radius) -> Line {
        Line {
            color: color,
            radius: radius,
            shape: Shape::Square,
        }
    }

    /// Creates a new line
    pub fn round(color: internal::Color, radius: internal::Radius) -> Line {
        Line {
            color: color,
            radius: radius,
            shape: Shape::Round,
        }
    }

    /// Draw the line.
    pub fn draw<G>(
        &self,
        line: internal::Line,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G
    )
        where G: Graphics
    {
        match self.shape {
            Shape::Square => {
                g.tri_list(
                    draw_state,
                    &self.color,
                    |f|
                triangulation::with_round_border_line_tri_list(
                    2,
                    transform,
                    line,
                    self.radius,
                    |vertices| f(vertices)
                ));
            }
            Shape::Round => {
                g.tri_list(
                    draw_state,
                    &self.color,
                    |f|
                triangulation::with_round_border_line_tri_list(
                    64,
                    transform,
                    line,
                    self.radius,
                    |vertices| f(vertices)
                ));
            }
            Shape::Bevel => {
                g.tri_list(
                    draw_state,
                    &self.color,
                    |f|
                triangulation::with_round_border_line_tri_list(
                    3,
                    transform,
                    line,
                    self.radius,
                    |vertices| f(vertices)
                ));
            }
        }
    }

    /// Draws an arrow
    ///
    /// Head size is the sides of the triangle
    /// between the arrow hooks and the line
    pub fn draw_arrow<G>(
        &self,
        line: internal::Line,
        head_size: internal::Scalar,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G
    )
        where G: Graphics
    {
        use Transformed;

        self.draw(line, draw_state, transform, g);
        let diff = [line[2] - line[0], line[3] - line[1]];
        let arrow_head = transform
            .trans(line[2], line[3])
            .orient(diff[0], diff[1]);
        self.draw([-head_size, head_size, 0.0, 0.0], draw_state, arrow_head, g);
        self.draw([-head_size, -head_size, 0.0, 0.0], draw_state, arrow_head, g);
    }
}

/*
quack! {
    set:
        fn (val: Color) [] { l.color = val.0 }
        fn (val: Radius) [] { l.radius = val.0 }
        fn (val: Width) [] { l.radius = 0.5 * val.0 }
        fn (val: Shape) [] { l.shape = val }
    action:
}
*/

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

    #[test]
    fn test_line() {
        use Colored;

        let _line = Line::new([0.0; 4], 3.0)
            .set(Color([1.0; 4]))
            .set(Radius(3.0))
            .set(Shape::Round)
            .hue_deg(1.0);
        let Color(_) = _line.get();
    }
}
<commit_msg>Removed `line::Width`<commit_after>//! Draw Line

use internal;
use triangulation;
use Graphics;
use Color;
use math::Matrix2d;
use DrawState;

/// The shape of the line
#[derive(Copy, Clone)]
pub enum Shape {
    /// Square edges
    Square,
    /// Round edges
    Round,
    /// Bevel edges
    Bevel,
}

/// A colored line with a default border radius
#[derive(Copy, Clone)]
pub struct Line {
    /// The line color
    pub color: internal::Color,
    /// The line radius
    pub radius: internal::Radius,
    /// The line shape
    pub shape: Shape,
}

impl Line {
    /// Creates a new line
    pub fn new(color: internal::Color, radius: internal::Radius) -> Line {
        Line {
            color: color,
            radius: radius,
            shape: Shape::Square,
        }
    }

    /// Creates a new line
    pub fn round(color: internal::Color, radius: internal::Radius) -> Line {
        Line {
            color: color,
            radius: radius,
            shape: Shape::Round,
        }
    }

    /// Draw the line.
    pub fn draw<G>(
        &self,
        line: internal::Line,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G
    )
        where G: Graphics
    {
        match self.shape {
            Shape::Square => {
                g.tri_list(
                    draw_state,
                    &self.color,
                    |f|
                triangulation::with_round_border_line_tri_list(
                    2,
                    transform,
                    line,
                    self.radius,
                    |vertices| f(vertices)
                ));
            }
            Shape::Round => {
                g.tri_list(
                    draw_state,
                    &self.color,
                    |f|
                triangulation::with_round_border_line_tri_list(
                    64,
                    transform,
                    line,
                    self.radius,
                    |vertices| f(vertices)
                ));
            }
            Shape::Bevel => {
                g.tri_list(
                    draw_state,
                    &self.color,
                    |f|
                triangulation::with_round_border_line_tri_list(
                    3,
                    transform,
                    line,
                    self.radius,
                    |vertices| f(vertices)
                ));
            }
        }
    }

    /// Draws an arrow
    ///
    /// Head size is the sides of the triangle
    /// between the arrow hooks and the line
    pub fn draw_arrow<G>(
        &self,
        line: internal::Line,
        head_size: internal::Scalar,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G
    )
        where G: Graphics
    {
        use Transformed;

        self.draw(line, draw_state, transform, g);
        let diff = [line[2] - line[0], line[3] - line[1]];
        let arrow_head = transform
            .trans(line[2], line[3])
            .orient(diff[0], diff[1]);
        self.draw([-head_size, head_size, 0.0, 0.0], draw_state, arrow_head, g);
        self.draw([-head_size, -head_size, 0.0, 0.0], draw_state, arrow_head, g);
    }
}

/*
quack! {
    set:
        fn (val: Color) [] { l.color = val.0 }
        fn (val: Radius) [] { l.radius = val.0 }
        fn (val: Width) [] { l.radius = 0.5 * val.0 }
        fn (val: Shape) [] { l.shape = val }
    action:
}
*/

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

    #[test]
    fn test_line() {
        use Colored;

        let _line = Line::new([0.0; 4], 3.0)
            .set(Color([1.0; 4]))
            .set(Radius(3.0))
            .set(Shape::Round)
            .hue_deg(1.0);
        let Color(_) = _line.get();
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::borrow::Cow;

use escape::Escaped;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Attribute<'a> {
    pub name: Cow<'a, str>,
    pub value: Cow<'a, str>,
}

impl<'a> Attribute<'a> {
    pub fn new<N, V>(name: N, value: V) -> Attribute<'a>
        where N: Into<Cow<'a, str>>,
              V: Into<Cow<'a, str>>
    {
        Attribute {
            name: name.into(),
            value: value.into(),
        }
    }
}

impl<'a> fmt::Display for Attribute<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.value == "" {
            write!(f, "{}", self.name)
        } else {
            write!(f, "{}=\"{}\"", self.name.as_ref(), Escaped(&self.value))
        }
    }
}

#[derive(Clone, Debug)]
/// Prefer `attr_set!` macro over manual construction
pub struct AttributeSet<'a>(pub Cow<'a, [Attribute<'a>]>);

impl<'a> AttributeSet<'a> {
    pub fn get_attr<S>(&self, name: S) -> Option<&Attribute<'a>>
        where S: AsRef<str>
    {
        self.0.iter().find(|attr| attr.name == name.as_ref())
    }

    pub fn get_attr_mut<S>(&mut self, name: S) -> Option<&mut Attribute<'a>>
        where S: AsRef<str>
    {
        self.0.to_mut().iter_mut().find(|attr| attr.name == name.as_ref())
    }

    pub fn set_attr<N, V>(&mut self, name: N, value: V)
        where N: Into<Cow<'a, str>>,
              V: Into<Cow<'a, str>>
    {
        let (name, value) = (name.into(), value.into());
        let attrs = self.0.to_mut();

        if let Some(pos) = attrs.iter().position(|attr| attr.name == name) {
            attrs[pos].value = value;
        } else {
            attrs.push(Attribute::new(name, value));
        }
    }
}

impl<'a> fmt::Display for AttributeSet<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for attr in self.0.iter() {
            try!(write!(f, " {}", attr));
        }
        Ok(())
    }
}
<commit_msg>Add documentation for Attribute and AttributeSet<commit_after>use std::fmt;
use std::borrow::Cow;

use escape::Escaped;

/// An [HTML attribute](https://www.w3.org/TR/html/syntax.html#attributes-0).
///
/// The name for the attribute will not be validated, you must ensure it meets
/// the requirements specified in the spec yourself.
///
/// The value for the attribute will be escaped automatically. If it is an
/// empty string then the attribute will be written with the 'Empty attribute
/// syntax'.
///
/// # Examples
///
/// ```rust
/// let attr = hamlet::Attribute::new("id", "foo");
/// assert_eq!(format!("{}", attr), "id=\"foo\"");
/// ```
///
/// ```rust
/// let attr = hamlet::Attribute::new("id", "bar & baz");
/// assert_eq!(format!("{}", attr), "id=\"bar & baz\"");
/// ```
///
/// ```rust
/// let attr = hamlet::Attribute::new("invalid=id", "foo");
/// assert_eq!(format!("{}", attr), "invalid=id=\"foo\"");
/// ```
///
/// ```rust
/// let attr = hamlet::Attribute::new("checked", "");
/// assert_eq!(format!("{}", attr), "checked");
/// ```
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Attribute<'a> {
    pub name: Cow<'a, str>,
    pub value: Cow<'a, str>,
}

impl<'a> Attribute<'a> {
    /// Create an attribute, useful to avoid having to convert strings to
    /// `Cow<str>` yourself.
    ///
    /// Generally this shouldn't be used directly by end users, it's likely
    /// that there are builder APIs or macros available that make attribute
    /// construction easier, for example the modification methods on
    /// [`AttributeSet`](struct.AttributeSet.html#methods) or the
    /// [`attr_set!`](macro.attr_set!.html) macro.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::borrow::Cow;
    /// let foo = "foo".to_owned();
    /// let foo2 = foo.clone();
    /// assert_eq!(
    ///     hamlet::Attribute::new("id", foo),
    ///     hamlet::Attribute {
    ///         name: Cow::Borrowed("id"),
    ///         value: Cow::Owned(foo2),
    ///     });
    /// ```
    pub fn new<N, V>(name: N, value: V) -> Attribute<'a>
        where N: Into<Cow<'a, str>>,
              V: Into<Cow<'a, str>>
    {
        Attribute {
            name: name.into(),
            value: value.into(),
        }
    }
}

impl<'a> fmt::Display for Attribute<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.value == "" {
            write!(f, "{}", self.name)
        } else {
            write!(f, "{}=\"{}\"", self.name.as_ref(), Escaped(&self.value))
        }
    }
}

#[derive(Clone, Debug)]
/// A set of [`Attribute`s](./struct.Attribute.html).
///
/// This is stored as a plain slice instead of a set as in most cases it will
/// be a small collection over which linear search will be more efficient.
///
/// Generally end users shouldn't construct this struct directly, it's expected
/// that there will be builder APIs or macros available to make construction
/// easier, for example the provided [`attr_set!`](macro.attr_set!.html) macro.
pub struct AttributeSet<'a>(pub Cow<'a, [Attribute<'a>]>);

impl<'a> AttributeSet<'a> {
    /// Try and get a reference to an existing attribute.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let attrs = attr_set!(id = "foo");
    /// assert_eq!(
    ///     attrs.get_attr("id"),
    ///     Some(&hamlet::Attribute::new("id", "foo")));
    /// # }
    /// ```
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let attrs = attr_set!(id = "foo");
    /// assert_eq!(
    ///     attrs.get_attr("class"),
    ///     None);
    /// # }
    /// ```
    pub fn get_attr<S>(&self, name: S) -> Option<&Attribute<'a>>
        where S: AsRef<str>
    {
        self.0.iter().find(|attr| attr.name == name.as_ref())
    }

    /// Try and get a mutable reference to an existing attribute.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let mut attrs = attr_set!(id = "foo");
    ///
    /// if let Some(attr) = attrs.get_attr_mut("id") {
    ///     attr.value = "bar".into();
    /// }
    ///
    /// assert_eq!(
    ///     attrs.get_attr("id"),
    ///     Some(&hamlet::Attribute::new("id", "bar")));
    /// # }
    /// ```
    pub fn get_attr_mut<S>(&mut self, name: S) -> Option<&mut Attribute<'a>>
        where S: AsRef<str>
    {
        self.0.to_mut().iter_mut().find(|attr| attr.name == name.as_ref())
    }

    /// Unconditionally set an attribute to a value. If the attribute already
    /// exists in the set will update its value, otherwise will add a new
    /// attribute to the set.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let mut attrs = attr_set!(id = "foo");
    ///
    /// attrs.set_attr("id", "bar");
    ///
    /// assert_eq!(
    ///     attrs.get_attr("id"),
    ///     Some(&hamlet::Attribute::new("id", "bar")));
    /// # }
    /// ```
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let mut attrs = attr_set!(id = "foo");
    ///
    /// attrs.set_attr("class", "bar");
    ///
    /// assert_eq!(
    ///     attrs.get_attr("class"),
    ///     Some(&hamlet::Attribute::new("class", "bar")));
    /// # }
    /// ```
    pub fn set_attr<N, V>(&mut self, name: N, value: V)
        where N: Into<Cow<'a, str>>,
              V: Into<Cow<'a, str>>
    {
        let (name, value) = (name.into(), value.into());
        let attrs = self.0.to_mut();

        if let Some(pos) = attrs.iter().position(|attr| attr.name == name) {
            attrs[pos].value = value;
        } else {
            attrs.push(Attribute::new(name, value));
        }
    }
}

impl<'a> fmt::Display for AttributeSet<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for attr in self.0.iter() {
            try!(write!(f, " {}", attr));
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! A module for constructing axes locator shapes.

extern crate cgmath;
extern crate glium;

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

/// A set of orthogonal `Axes` lines.
///
/// This object is constructed using a `AxesBuilder` object.
pub struct Axes {
    vertices: glium::vertex::VertexBufferAny
}

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

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

/// Responsible for building and returning an `Axes` object.
///
/// By default, each orthogonal axis line is 1 unit in length, with the
/// centre point 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. Vertex normals define the normalised
/// direction of their respective axis line. Vertex texture coordinates encode
/// end point in the U coordinate (a value of 0 or 1), and the axis number in
/// the V coordinate (a value of 0, 1, or 2).
pub struct AxesBuilder {
    matrix: cgmath::Matrix4<f32>
}

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

impl AxesBuilder {

    /// Create a new `AxesBuilder` object.
    pub fn new() -> AxesBuilder {
        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 `Axes` object.
    pub fn build<F>(self, display: &F) -> Result<Axes, ShapeCreationError>
    where F:glium::backend::Facade {
        let vertices = try!(glium::vertex::VertexBuffer::<Vertex>::new(
            display, &try!(self.build_vertices())
        ));

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

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

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

        // Build the vertices.
        let num_axes = 3;
        let verts_per_axis = 2;
        let mut vertices = Vec::<Vertex>::with_capacity(
            verts_per_axis * num_axes
        );

        for axis in 0..num_axes {
            for vert in 0..verts_per_axis {
                let mut normal = Vector3::<f32>::new(0.0, 0.0, 0.0);
                normal[axis] = 1.0;
                let position = (normal * Vector3::<f32>::from_value(vert as f32)).extend(1.0);
                vertices.push(Vertex{
                    position: Point3::<f32>::from_homogeneous(self.matrix * position).into(),
                    normal: (normal_matrix * normal).normalize().into(),
                    texcoord: [
                        vert as f32,
                        axis as f32,
                    ],
                });
            }
        }

        return Ok(vertices);
    }
}

#[test]
pub fn ensure_default_axes_has_unit_dimensions() {
    let vertices = AxesBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for ref vertex in vertices {
        let pos = Vector3::<f32>::from(vertex.position);
        assert!(pos.x >= 0.0);
        assert!(pos.x <= 1.0);
        assert!(pos.y >= 0.0);
        assert!(pos.y <= 1.0);
        assert!(pos.z >= 0.0);
        assert!(pos.z <= 1.0);
    }
}

#[test]
pub fn ensure_default_axes_are_placed_at_origin() {
    let vertices = AxesBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for chunk in vertices.chunks(2) {
        assert_eq!(Vector3::<f32>::from(chunk[0].position), Vector3::<f32>::zero());
    }
}

#[test]
pub fn ensure_default_axes_are_orthogonal() {
    let vertices = AxesBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    let chunks = vertices.chunks(2);
    let axes: Vec<Vector3<f32>> = chunks.map(
        |chunk| Vector3::<f32>::from(chunk[1].position) - Vector3::<f32>::from(chunk[0].position)
    ).collect();
    assert_eq!(axes[0].cross(axes[1]), axes[2]);
}

#[test]
pub fn ensure_axes_are_axis_aligned() {
    let vertices = AxesBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for chunk in vertices.chunks(2) {
        let p0 = Vector3::<f32>::from(chunk[0].position);
        let p1 = Vector3::<f32>::from(chunk[1].position);
        let dir = p1 - p0;
        assert!(dir[0] == 1.0 || dir[1] == 1.0 || dir[2] == 1.0);
        assert_eq!(dir.length(), 1.0);
    }
}

#[test]
pub fn ensure_axes_normals_define_axis_direction() {
    let vertices = AxesBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for chunk in vertices.chunks(2) {
        let p0 = Vector3::<f32>::from(chunk[0].position);
        let p1 = Vector3::<f32>::from(chunk[1].position);
        let dir = p1 - p0;
        assert_eq!(dir, Vector3::<f32>::from(chunk[0].normal));
        assert_eq!(dir, Vector3::<f32>::from(chunk[1].normal));
    }
}
<commit_msg>Compatibility fixes for new cgmath version.<commit_after>//! A module for constructing axes locator shapes.

extern crate cgmath;
extern crate glium;

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

/// A set of orthogonal `Axes` lines.
///
/// This object is constructed using a `AxesBuilder` object.
pub struct Axes {
    vertices: glium::vertex::VertexBufferAny
}

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

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

/// Responsible for building and returning an `Axes` object.
///
/// By default, each orthogonal axis line is 1 unit in length, with the
/// centre point 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. Vertex normals define the normalised
/// direction of their respective axis line. Vertex texture coordinates encode
/// end point in the U coordinate (a value of 0 or 1), and the axis number in
/// the V coordinate (a value of 0, 1, or 2).
pub struct AxesBuilder {
    matrix: cgmath::Matrix4<f32>
}

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

impl AxesBuilder {

    /// Create a new `AxesBuilder` object.
    pub fn new() -> AxesBuilder {
        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 `Axes` object.
    pub fn build<F>(self, display: &F) -> Result<Axes, ShapeCreationError>
    where F:glium::backend::Facade {
        let vertices = try!(glium::vertex::VertexBuffer::<Vertex>::new(
            display, &try!(self.build_vertices())
        ));

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

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

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

        // Build the vertices.
        let num_axes = 3;
        let verts_per_axis = 2;
        let mut vertices = Vec::<Vertex>::with_capacity(
            verts_per_axis * num_axes
        );

        for axis in 0..num_axes {
            for vert in 0..verts_per_axis {
                let mut normal = Vector3::<f32>::new(0.0, 0.0, 0.0);
                normal[axis] = 1.0;
                let position = (normal * (vert as f32)).extend(1.0);
                vertices.push(Vertex{
                    position: Point3::<f32>::from_homogeneous(self.matrix * position).into(),
                    normal: (normal_matrix * normal).normalize().into(),
                    texcoord: [
                        vert as f32,
                        axis as f32,
                    ],
                });
            }
        }

        return Ok(vertices);
    }
}

#[test]
pub fn ensure_default_axes_has_unit_dimensions() {
    let vertices = AxesBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for ref vertex in vertices {
        let pos = Vector3::<f32>::from(vertex.position);
        assert!(pos.x >= 0.0);
        assert!(pos.x <= 1.0);
        assert!(pos.y >= 0.0);
        assert!(pos.y <= 1.0);
        assert!(pos.z >= 0.0);
        assert!(pos.z <= 1.0);
    }
}

#[test]
pub fn ensure_default_axes_are_placed_at_origin() {
    let vertices = AxesBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for chunk in vertices.chunks(2) {
        assert_eq!(Vector3::<f32>::from(chunk[0].position), Vector3::<f32>::zero());
    }
}

#[test]
pub fn ensure_default_axes_are_orthogonal() {
    let vertices = AxesBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    let chunks = vertices.chunks(2);
    let axes: Vec<Vector3<f32>> = chunks.map(
        |chunk| Vector3::<f32>::from(chunk[1].position) - Vector3::<f32>::from(chunk[0].position)
    ).collect();
    assert_eq!(axes[0].cross(axes[1]), axes[2]);
}

#[test]
pub fn ensure_axes_are_axis_aligned() {
    let vertices = AxesBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for chunk in vertices.chunks(2) {
        let p0 = Vector3::<f32>::from(chunk[0].position);
        let p1 = Vector3::<f32>::from(chunk[1].position);
        let dir = p1 - p0;
        assert!(dir[0] == 1.0 || dir[1] == 1.0 || dir[2] == 1.0);
        assert_eq!(dir.magnitude(), 1.0);
    }
}

#[test]
pub fn ensure_axes_normals_define_axis_direction() {
    let vertices = AxesBuilder::new()
                   .build_vertices()
                   .expect("Failed to build vertices");
    for chunk in vertices.chunks(2) {
        let p0 = Vector3::<f32>::from(chunk[0].position);
        let p1 = Vector3::<f32>::from(chunk[1].position);
        let dir = p1 - p0;
        assert_eq!(dir, Vector3::<f32>::from(chunk[0].normal));
        assert_eq!(dir, Vector3::<f32>::from(chunk[1].normal));
    }
}
<|endoftext|>


<commit_before>use primitives::{Consumed, Parser, ParseError, ParseResult, Error, State, Stream};
use combinator::{Expected, skip_many, SkipMany, ParserExt, With};
use std::borrow::IntoCow;

macro_rules! impl_char_parser {
    ($name: ident ($($ty_var: ident),*), $inner_type: ty) => {
    #[derive(Clone)]
    pub struct $name<I $(,$ty_var)*>($inner_type)
        where I: Stream<Item=char> $(, $ty_var : Parser<Input=I>)*;
    impl <I $(,$ty_var)*> Parser for $name<I $(,$ty_var)*>
        where I: Stream<Item=char> $(, $ty_var : Parser<Input=I>)* {
        type Input = I;
        type Output = <$inner_type as Parser>::Output;
        fn parse_state(&mut self, input: State<<Self as Parser>::Input>) -> ParseResult<<Self as Parser>::Output, <Self as Parser>::Input> {
            self.0.parse_state(input)
        }
    }
}
}

///Parses any character
pub fn any_char<I>(input: State<I>) -> ParseResult<char, I>
    where I: Stream<Item=char> {
    input.uncons_char()
}

#[derive(Clone)]
pub struct Satisfy<I, Pred> { pred: Pred }

impl <I, Pred> Parser for Satisfy<I, Pred>
    where I: Stream<Item=char>, Pred: FnMut(char) -> bool {

    type Input = I;
    type Output = char;
    fn parse_state(&mut self, input: State<I>) -> ParseResult<char, I> {
        match input.clone().uncons_char() {
            Ok((c, s)) => {
                if (self.pred)(c) { Ok((c, s)) }
                else {
                    Err(Consumed::Empty(ParseError::new(input.position, Error::Unexpected(c))))
                }
            }
            Err(err) => Err(err)
        }
    }
}

///Parses a character and succeeds depending on the result of `pred`
///
/// ```
/// # extern crate "parser-combinators" as pc;
/// # use pc::*;
/// # fn main() {
/// let result = satisfy(|c| c == '!')
///     .parse("!")
///     .map(|x| x.0);
/// assert_eq!(result, Ok('!'));
/// # }
/// ```
pub fn satisfy<I, Pred>(pred: Pred) -> Satisfy<I, Pred>
    where I: Stream<Item=char>, Pred: FnMut(char) -> bool {
    Satisfy { pred: pred }
}

impl_char_parser! { Digit(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses a digit from a stream containing characters
pub fn digit<I>() -> Digit<I>
    where I: Stream<Item=char> {
    Digit(satisfy(static_fn!((c, char) -> bool { c.is_digit(10) }))
         .expected("digit"))
}

impl_char_parser! { Space(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses whitespace
pub fn space<I>() -> Space<I>
    where I: Stream<Item=char> {
    Space(satisfy(CharExt::is_whitespace as fn (char) -> bool)
        .expected("whitespace"))
}
impl_char_parser! { Spaces(), Expected<SkipMany<Space<I>>> }
///Skips over zero or more spaces
pub fn spaces<I>() -> Spaces<I>
    where I: Stream<Item=char> {
    Spaces(skip_many(space())
          .expected("whitespaces"))
}

impl_char_parser! { NewLine(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses a newline character
pub fn newline<I>() -> NewLine<I>
    where I: Stream<Item=char> {
    NewLine(satisfy(static_fn!((ch, char) -> bool { ch == '\n' }))
           .expected("lf newline"))
}

impl_char_parser! { CrLf(), Expected<With<Satisfy<I, fn (char) -> bool>, NewLine<I>>> }
///Parses carriage return and newline, returning the newline character.
pub fn crlf<I>() -> CrLf<I>
    where I: Stream<Item=char> {
    CrLf(satisfy(static_fn!((ch, char) -> bool { ch == '\r' }))
        .with(newline())
        .expected("crlf newline"))
}

impl_char_parser! { Tab(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses a tab character
pub fn tab<I>() -> Tab<I>
    where I: Stream<Item=char> {
    Tab(satisfy(static_fn!((ch, char) -> bool { ch == '\t' }))
       .expected("tab"))
}

impl_char_parser! { Upper(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses an uppercase letter
pub fn upper<I>() -> Upper<I>
    where I: Stream<Item=char> {
    Upper(satisfy(static_fn!((ch, char) -> bool { ch.is_uppercase()}))
         .expected("uppercase letter"))
}

impl_char_parser! { Lower(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses an uppercase letter
pub fn lower<I>() -> Lower<I>
    where I: Stream<Item=char> {
    Lower(satisfy(static_fn!((ch, char) -> bool { ch.is_lowercase() }))
         .expected("lowercase letter"))
}

impl_char_parser! { AlphaNum(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses either an alphabet letter or digit
pub fn alpha_num<I>() -> AlphaNum<I>
    where I: Stream<Item=char> {
    AlphaNum(satisfy(static_fn!((ch, char) -> bool { ch.is_alphanumeric() }))
            .expected("letter or digit"))
}

impl_char_parser! { Letter(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses an alphabet letter
pub fn letter<I>() -> Letter<I>
    where I: Stream<Item=char> {
    Letter(satisfy(static_fn!((ch, char) -> bool { ch.is_alphabetic() }))
          .expected("letter"))
}

impl_char_parser! { OctDigit(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses an octal digit
pub fn oct_digit<I>() -> OctDigit<I>
    where I: Stream<Item=char> {
    OctDigit(satisfy(static_fn!((ch, char) -> bool { ch.is_digit(8) }))
            .expected("octal digit"))
}

impl_char_parser! { HexDigit(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses a hexdecimal digit with uppercase and lowercase
pub fn hex_digit<I>() -> HexDigit<I>
    where I: Stream<Item=char> {
    HexDigit(satisfy(static_fn!((ch, char) -> bool { ch.is_digit(0x10) }))
            .expected("hexadecimal digit"))
}

#[derive(Clone)]
pub struct String<I>(&'static str);
impl <I> Parser for String<I>
    where I: Stream<Item=char> {
    type Input = I;
    type Output = &'static str;
    fn parse_state(&mut self, input: State<I>) -> ParseResult<&'static str, I> {
        let start = input.position;
        let mut input = Consumed::Empty(input);
        for c in self.0.chars() {
            match input.combine(|input| input.uncons_char()) {
                Ok((other, rest)) => {
                    if c != other {
                        let error = ParseError::new(start, Error::Expected(self.0.into_cow()));
                        return Err(rest.map(|_| error))
                    }
                    input = rest;
                }
                Err(error) => {
                    return Err(error.map(move |mut error| {
                        error.position = start;
                        error
                    }))
                }
            }
        }
        Ok((self.0, input))
    }
}

///Parses the string `s`
///
/// ```
/// # extern crate "parser-combinators" as pc;
/// # use pc::*;
/// # fn main() {
/// let result = string("rust")
///     .parse("rust")
///     .map(|x| x.0);
/// assert_eq!(result, Ok("rust"));
/// # }
/// ```
pub fn string<I>(s: &'static str) -> String<I>
    where I: Stream<Item=char> {
    String(s)
}

#[cfg(test)]
mod tests {
    use super::space;
    use primitives::{Error, Parser};
    use std::borrow::IntoCow;

    #[test]
    fn space_error() {
        let result = space()
            .parse("");
        assert!(result.is_err());
        assert_eq!(result.unwrap_err().errors, vec![Error::Message("End of input".into_cow()), Error::Expected("whitespace".into_cow())]);

    }
}
<commit_msg>Fix bug in new strings implementation regarding the consumed state<commit_after>use primitives::{Consumed, Parser, ParseError, ParseResult, Error, State, Stream};
use combinator::{Expected, skip_many, SkipMany, ParserExt, With};
use std::borrow::IntoCow;

macro_rules! impl_char_parser {
    ($name: ident ($($ty_var: ident),*), $inner_type: ty) => {
    #[derive(Clone)]
    pub struct $name<I $(,$ty_var)*>($inner_type)
        where I: Stream<Item=char> $(, $ty_var : Parser<Input=I>)*;
    impl <I $(,$ty_var)*> Parser for $name<I $(,$ty_var)*>
        where I: Stream<Item=char> $(, $ty_var : Parser<Input=I>)* {
        type Input = I;
        type Output = <$inner_type as Parser>::Output;
        fn parse_state(&mut self, input: State<<Self as Parser>::Input>) -> ParseResult<<Self as Parser>::Output, <Self as Parser>::Input> {
            self.0.parse_state(input)
        }
    }
}
}

///Parses any character
pub fn any_char<I>(input: State<I>) -> ParseResult<char, I>
    where I: Stream<Item=char> {
    input.uncons_char()
}

#[derive(Clone)]
pub struct Satisfy<I, Pred> { pred: Pred }

impl <I, Pred> Parser for Satisfy<I, Pred>
    where I: Stream<Item=char>, Pred: FnMut(char) -> bool {

    type Input = I;
    type Output = char;
    fn parse_state(&mut self, input: State<I>) -> ParseResult<char, I> {
        match input.clone().uncons_char() {
            Ok((c, s)) => {
                if (self.pred)(c) { Ok((c, s)) }
                else {
                    Err(Consumed::Empty(ParseError::new(input.position, Error::Unexpected(c))))
                }
            }
            Err(err) => Err(err)
        }
    }
}

///Parses a character and succeeds depending on the result of `pred`
///
/// ```
/// # extern crate "parser-combinators" as pc;
/// # use pc::*;
/// # fn main() {
/// let result = satisfy(|c| c == '!')
///     .parse("!")
///     .map(|x| x.0);
/// assert_eq!(result, Ok('!'));
/// # }
/// ```
pub fn satisfy<I, Pred>(pred: Pred) -> Satisfy<I, Pred>
    where I: Stream<Item=char>, Pred: FnMut(char) -> bool {
    Satisfy { pred: pred }
}

impl_char_parser! { Digit(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses a digit from a stream containing characters
pub fn digit<I>() -> Digit<I>
    where I: Stream<Item=char> {
    Digit(satisfy(static_fn!((c, char) -> bool { c.is_digit(10) }))
         .expected("digit"))
}

impl_char_parser! { Space(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses whitespace
pub fn space<I>() -> Space<I>
    where I: Stream<Item=char> {
    Space(satisfy(CharExt::is_whitespace as fn (char) -> bool)
        .expected("whitespace"))
}
impl_char_parser! { Spaces(), Expected<SkipMany<Space<I>>> }
///Skips over zero or more spaces
pub fn spaces<I>() -> Spaces<I>
    where I: Stream<Item=char> {
    Spaces(skip_many(space())
          .expected("whitespaces"))
}

impl_char_parser! { NewLine(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses a newline character
pub fn newline<I>() -> NewLine<I>
    where I: Stream<Item=char> {
    NewLine(satisfy(static_fn!((ch, char) -> bool { ch == '\n' }))
           .expected("lf newline"))
}

impl_char_parser! { CrLf(), Expected<With<Satisfy<I, fn (char) -> bool>, NewLine<I>>> }
///Parses carriage return and newline, returning the newline character.
pub fn crlf<I>() -> CrLf<I>
    where I: Stream<Item=char> {
    CrLf(satisfy(static_fn!((ch, char) -> bool { ch == '\r' }))
        .with(newline())
        .expected("crlf newline"))
}

impl_char_parser! { Tab(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses a tab character
pub fn tab<I>() -> Tab<I>
    where I: Stream<Item=char> {
    Tab(satisfy(static_fn!((ch, char) -> bool { ch == '\t' }))
       .expected("tab"))
}

impl_char_parser! { Upper(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses an uppercase letter
pub fn upper<I>() -> Upper<I>
    where I: Stream<Item=char> {
    Upper(satisfy(static_fn!((ch, char) -> bool { ch.is_uppercase()}))
         .expected("uppercase letter"))
}

impl_char_parser! { Lower(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses an uppercase letter
pub fn lower<I>() -> Lower<I>
    where I: Stream<Item=char> {
    Lower(satisfy(static_fn!((ch, char) -> bool { ch.is_lowercase() }))
         .expected("lowercase letter"))
}

impl_char_parser! { AlphaNum(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses either an alphabet letter or digit
pub fn alpha_num<I>() -> AlphaNum<I>
    where I: Stream<Item=char> {
    AlphaNum(satisfy(static_fn!((ch, char) -> bool { ch.is_alphanumeric() }))
            .expected("letter or digit"))
}

impl_char_parser! { Letter(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses an alphabet letter
pub fn letter<I>() -> Letter<I>
    where I: Stream<Item=char> {
    Letter(satisfy(static_fn!((ch, char) -> bool { ch.is_alphabetic() }))
          .expected("letter"))
}

impl_char_parser! { OctDigit(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses an octal digit
pub fn oct_digit<I>() -> OctDigit<I>
    where I: Stream<Item=char> {
    OctDigit(satisfy(static_fn!((ch, char) -> bool { ch.is_digit(8) }))
            .expected("octal digit"))
}

impl_char_parser! { HexDigit(), Expected<Satisfy<I, fn (char) -> bool>> }
///Parses a hexdecimal digit with uppercase and lowercase
pub fn hex_digit<I>() -> HexDigit<I>
    where I: Stream<Item=char> {
    HexDigit(satisfy(static_fn!((ch, char) -> bool { ch.is_digit(0x10) }))
            .expected("hexadecimal digit"))
}

#[derive(Clone)]
pub struct String<I>(&'static str);
impl <I> Parser for String<I>
    where I: Stream<Item=char> {
    type Input = I;
    type Output = &'static str;
    fn parse_state(&mut self, mut input: State<I>) -> ParseResult<&'static str, I> {
        let start = input.position;
        let mut consumed = false;
        for c in self.0.chars() {
            match input.uncons_char() {
                Ok((other, rest)) => {
                    if c != other {
                        let error = ParseError::new(start, Error::Expected(self.0.into_cow()));
                        return Err(if consumed { Consumed::Consumed(error) } else { Consumed::Empty(error) })
                    }
                    consumed = true;
                    input = rest;
                }
                Err(mut error) => {
                    error.position = start;
                    return Err(if consumed { Consumed::Consumed(error) } else { Consumed::Empty(error) })
                }
            }
        }
        Ok((self.0, input))
    }
}

///Parses the string `s`
///
/// ```
/// # extern crate "parser-combinators" as pc;
/// # use pc::*;
/// # fn main() {
/// let result = string("rust")
///     .parse("rust")
///     .map(|x| x.0);
/// assert_eq!(result, Ok("rust"));
/// # }
/// ```
pub fn string<I>(s: &'static str) -> String<I>
    where I: Stream<Item=char> {
    String(s)
}

#[cfg(test)]
mod tests {
    use super::*;
    use primitives::{Error, Parser, SourcePosition};
    use std::borrow::IntoCow;

    #[test]
    fn space_error() {
        let result = space()
            .parse("");
        assert!(result.is_err());
        assert_eq!(result.unwrap_err().errors, vec![Error::Message("End of input".into_cow()), Error::Expected("whitespace".into_cow())]);

    }

    #[test]
    fn string_consumed() {
        let result = string("a").parse("b");
        assert!(result.is_err());
        assert_eq!(result.unwrap_err().position, SourcePosition { line: 1, column: 1 });
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate nalgebra as na;
#[macro_use]
extern crate serde_derive;
extern crate serde;
#[macro_use]
extern crate log;
mod input;
mod structs;
mod nn;
mod logging;

use input::config;
use std::env;
use structs::Data;
use structs::flower::Flower;

// number of data sets used for evaluation purposes only
const TEST_DATA_SIZE: usize = 20;

fn main() {

    // read command line arguments
    let config: config::GlobalConfig<Flower> = input::read_arguments();

    // initialize the global logger --> we can use info!(), debug!(), etc. from here on
    logging::init_logger(config.verbosity);

    info!("Starting_up...");
    info!("Running with Logging Level: {:?}", config.verbosity);

    let flower_data = true;
    // Program logic starts here
    if let Some(learn_cfg) = config.learn_config {
        // learn
        // TODO: sort out Type parameter
        // Lukas, we should make this work together:
        //
        if flower_data {
            //TODO: remove unwrap
            learn(&learn_cfg, input::util::into_data_vec(config.data.unwrap()));
        } else {
            unimplemented!();
        }
    } else {
        // classify
        // TODO: implement classify
        unimplemented!();
    }
}

fn learn(learn_cfg: &config::LearningConfig, mut data: Vec<Data>) {

    // we got the input data from the parse_commands() invocation above
    //let mut input_data = data.unwrap();

    // split data into training and test data
    let (training_data, test_data) = input::util::split_data(&mut data, TEST_DATA_SIZE);

    info!("Initialising network...");

    debug!("{:?}", learn_cfg.init_vec);

    // create the network
    let mut nn = nn::Network::new(&learn_cfg.init_vec).unwrap();
    // learn!
    nn::learning::sgd(&mut nn,
                      training_data,
                      learn_cfg.epochs,
                      learn_cfg.batch_size,
                      learn_cfg.learning_rate,
                      test_data);
}
<commit_msg>does this really work?<commit_after>extern crate rand;
extern crate nalgebra as na;
#[macro_use]
extern crate serde_derive;
extern crate serde;
#[macro_use]
extern crate log;
mod input;
mod structs;
mod nn;
mod logging;

use input::config;
use std::env;
use structs::Data;
use structs::flower::Flower;

// number of data sets used for evaluation purposes only
const TEST_DATA_SIZE: usize = 20;

fn main() {

    // read command line arguments
    let cfg = input::read_arguments();
    // let s: String = "flower".to_string();
    let dtype = cfg.datatype.to_string();
    let config = match dtype.as_str() {
        "flower" => cfg as config::GlobalConfig<Flower>,
        _ => unreachable!(),
    };

    // initialize the global logger --> we can use info!(), debug!(), etc. from here on
    logging::init_logger(config.verbosity);

    info!("Starting_up...");
    info!("Running with Logging Level: {:?}", config.verbosity);

    let flower_data = true;
    // Program logic starts here
    if let Some(learn_cfg) = config.learn_config {
        // learn
        // TODO: sort out Type parameter
        // Lukas, we should make this work together:
        //
        if flower_data {
            //TODO: remove unwrap
            learn(&learn_cfg, input::util::into_data_vec(config.data.unwrap()));
        } else {
            unimplemented!();
        }
    } else {
        // classify
        // TODO: implement classify
        unimplemented!();
    }
}

fn learn(learn_cfg: &config::LearningConfig, mut data: Vec<Data>) {

    // split data into training and test data
    let (training_data, test_data) = input::util::split_data(&mut data, TEST_DATA_SIZE);

    info!("Initialising network...");

    // create the network
    let mut nn = nn::Network::new(&learn_cfg.init_vec).unwrap();
    // learn!
    nn::learning::sgd(&mut nn,
                      training_data,
                      learn_cfg.epochs,
                      learn_cfg.batch_size,
                      learn_cfg.learning_rate,
                      test_data);
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;
extern crate rand;

pub mod tetris;

use piston::window::WindowSettings;
use piston::event::*;
use glutin_window::GlutinWindow as Glutin_Window;
use opengl_graphics::{ GlGraphics, OpenGL };
use opengl_graphics::glyph_cache::GlyphCache;
use graphics::{ Transformed };
use piston::input::Button::{ Keyboard };
use piston::input::Input;
use piston::input::keyboard::Key;
use std::path::Path;

use tetris::*;

struct App {
    gl: GlGraphics,
    tetris: Tetris,
    elapsed_time: f64,
    cache: GlyphCache<'static>,
    should_redraw: bool
}

const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
const DARK_GRAY: [f32; 4] = [0.1, 0.1, 0.1, 1.0];
const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
const CYAN: [f32; 4] = [0.0, 1.0, 1.0, 1.0];
const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0];
const ORANGE: [f32; 4] = [1.0, 0.5, 0.0, 1.0];
const YELLOW: [f32; 4] = [1.0, 1.0, 0.0, 1.0];
const PURPLE: [f32; 4] = [0.5, 0.0, 1.0, 1.0];

fn get_shape_color(shape_index: i32) -> [f32; 4] {
    match shape_index {
        0 => PURPLE,
        1 => YELLOW,
        2 => RED,
        3 => GREEN,
        4 => ORANGE,
        5 => BLUE,
        6 => CYAN,
        _ => {
            BLACK
        }
    }
}

impl App {
    fn render(&mut self, args: &RenderArgs) {
        self.should_redraw = false;

        const CELL_SIZE: f64 = 30.0;
        const LEFT_MARGIN: f64 = 20f64;
        const TOP_MARGIN: f64 = 30f64;

        const STATUS_LEFT_MARGIN: f64 = 400f64;
        const STATUS_TOP_MARGIN: f64 = 100f64;
        const LINE_HEIGHT: f64 = 40f64;
        const STATUS_PREVIEW_GRID_HEIGHT: f64 = CELL_SIZE * 6f64;

        // so that we can access inside clojure
        let use_cache = &mut self.cache;
        let use_tetris = &mut self.tetris;

        self.gl.draw(args.viewport(), |c, gl| {
            // clear the viewport
            graphics::clear(BLACK, gl);

            // render the current score and level
            let mut text = graphics::Text::new(22);
            text.color = ORANGE;
            let mut transform = c.trans(STATUS_LEFT_MARGIN, STATUS_TOP_MARGIN);
            text.draw(&format!("Level: {}", use_tetris.get_level()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            text.draw(&format!("Score: {}", use_tetris.get_score()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            // render the next shape as a preview of what's coming next
            for point in use_tetris.get_next_shape().iter() {
                let square = graphics::rectangle::square(0f64, 0f64, CELL_SIZE);
                let color = get_shape_color(use_tetris.get_next_shape_index() as i32);
                // render the shape at col 2 and row 2
                let (x, y) = ((2 as i16 + point.x) as f64 * CELL_SIZE,
                    (2 as i16 + point.y) as f64 * CELL_SIZE);
                graphics::rectangle(color, square, transform.trans(x, y).transform, gl);
                let tetromino_border = graphics::Rectangle::new_border(DARK_GRAY, 1.0);
                tetromino_border.draw([0f64, 0f64, CELL_SIZE, CELL_SIZE], &c.draw_state,
                    transform.trans(x, y).transform, gl);
            }
            transform = transform.trans(0f64, STATUS_PREVIEW_GRID_HEIGHT);

            // render GAME OVER text if necessary
            if use_tetris.get_game_over() {
                text.draw(&"GAME OVER", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Press 'N' for a new game", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Use arrow keys to move and rotate", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Press spacebar to drop", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&format!("Press 'K' to decrease starting level ({})", use_tetris.get_starting_level()),
                    use_cache, &c.draw_state, transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Press 'L' to increase starting level",
                    use_cache, &c.draw_state, transform.transform, gl);
                // uncomment if drawing additional text in the status area
                //transform = transform.trans(0f64, LINE_HEIGHT);
            }

            // draw a white border around the game board
            let rect_border = graphics::Rectangle::new_border(WHITE, 1.5);
            rect_border.draw([
                LEFT_MARGIN,
                TOP_MARGIN,
                (CELL_SIZE * COL_COUNT as f64) + 1f64,
                (CELL_SIZE * ROW_COUNT as f64) + 1f64,
            ], &c.draw_state, c.transform, gl);

            // render each cell in the game board
            for col in 0..COL_COUNT as i32 {
                for row in 0..ROW_COUNT as i32 {
                    let cell = use_tetris.get_grid_cell(col, row);
                    if cell.cell_type != GridCellType::Void {
                        let (x, y) = (col as f64 * CELL_SIZE, row as f64 * CELL_SIZE);
                        let square = graphics::rectangle::square(0.0f64, 0.0f64, CELL_SIZE);
                        let color = match cell.cell_type {
                            GridCellType::Shape => get_shape_color(cell.shape_index),
                            GridCellType::Fixed => get_shape_color(cell.shape_index),
                            GridCellType::Ghost => DARK_GRAY,
                            _ => {
                                assert!(false);
                                BLACK
                            }
                        };
                        let transform = c.transform.trans(LEFT_MARGIN, TOP_MARGIN).trans(x, y);
                        graphics::rectangle(color, square, transform, gl);
                        let tetromino_border = graphics::Rectangle::new_border(DARK_GRAY, 1.0);
                        tetromino_border.draw([0f64, 0f64, CELL_SIZE, CELL_SIZE], &c.draw_state, transform, gl);
                    }
                }
            }
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        if self.tetris.get_game_over() {
            self.elapsed_time = 0.0;
        } else {
            // Here we increment the time elapsed between update()'s
            self.elapsed_time += args.dt;
            // if the elapsed time is now greater than the time allotted between ticks, then invoke tetris.tick()
            if self.elapsed_time > self.tetris.get_tick_time() as f64 {
                self.elapsed_time = 0.0;
                self.tetris.tick();
                self.should_redraw = true;
            }
        }
    }

    fn handle_input(&mut self, i: Input) {
        let prev_should_redraw = self.should_redraw;
        self.should_redraw = true;
        match i {
            Input::Press(Keyboard(Key::Left)) => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col - 1);
            },

            Input::Press(Keyboard(Key::Right)) => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col + 1);
            },

            Input::Press(Keyboard(Key::Up)) => {
                self.tetris.rotate(true);
            },

            Input::Press(Keyboard(Key::Down)) => {
                let row: i32 = self.tetris.get_row() + 1;
                self.tetris.set_row(row);
            },

            Input::Press(Keyboard(Key::Space)) => {
                let mut row: i32 = self.tetris.get_row() + 1;
                while self.tetris.set_row(row) {
                    row += 1;
                }
                // hard drop immediately spawns next shape
                self.tetris.tick();
            },

            Input::Press(Keyboard(Key::N)) => {
                self.tetris.start_game();
            },

            Input::Press(Keyboard(Key::K)) => {
                if self.tetris.get_starting_level() > 0 {
                    let new_level: u32 = self.tetris.get_starting_level() - 1;
                    self.tetris.set_starting_level(new_level);
                }
            },

            Input::Press(Keyboard(Key::L)) => {
                if self.tetris.get_starting_level() < 30 {
                    let new_level: u32 = self.tetris.get_starting_level() + 1;
                    self.tetris.set_starting_level(new_level);
                }
            },

            _ => {
                self.should_redraw = prev_should_redraw;
            }
        }
    }
}

fn main() {
    start_app();
}

fn start_app() {
    let opengl = OpenGL::_3_2;

    let window = Glutin_Window::new(
        opengl,
        WindowSettings::new("Piston Tetris", [1024, 768])
                       .exit_on_esc(true)
                       .vsync(true)
                       .samples(1)
    );

    let font_path = Path::new("FiraMono-Bold.ttf");

    let mut app = App {
        gl: GlGraphics::new(opengl),
        tetris: Tetris::new(),
        elapsed_time: 0.0,
        cache: GlyphCache::new(font_path).unwrap(),
        should_redraw: true,
    };

    for e in window.events().max_fps(60).ups(120) {
        match e {
            Event::Input(i) => {
                app.handle_input(i);
            }

            Event::Render(args) if app.should_redraw => {
                app.render(&args);
            }

            Event::Update(args) => {
                app.update(&args);
            }

            _ => {}
        }
    }
}<commit_msg>drawing rounded corners on tetrominos<commit_after>extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;
extern crate rand;

pub mod tetris;

use piston::window::WindowSettings;
use piston::event::*;
use glutin_window::GlutinWindow as Glutin_Window;
use opengl_graphics::{ GlGraphics, OpenGL };
use opengl_graphics::glyph_cache::GlyphCache;
use graphics::{ Transformed };
use piston::input::Button::{ Keyboard };
use piston::input::Input;
use piston::input::keyboard::Key;
use std::path::Path;

use tetris::*;

struct App {
    gl: GlGraphics,
    tetris: Tetris,
    elapsed_time: f64,
    cache: GlyphCache<'static>,
    should_redraw: bool
}

const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
const DARK_GRAY: [f32; 4] = [0.1, 0.1, 0.1, 1.0];
const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
const CYAN: [f32; 4] = [0.0, 1.0, 1.0, 1.0];
const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0];
const ORANGE: [f32; 4] = [1.0, 0.5, 0.0, 1.0];
const YELLOW: [f32; 4] = [1.0, 1.0, 0.0, 1.0];
const PURPLE: [f32; 4] = [0.5, 0.0, 1.0, 1.0];

fn get_shape_color(shape_index: i32) -> [f32; 4] {
    match shape_index {
        0 => PURPLE,
        1 => YELLOW,
        2 => RED,
        3 => GREEN,
        4 => ORANGE,
        5 => BLUE,
        6 => CYAN,
        _ => {
            BLACK
        }
    }
}

impl App {
    fn render(&mut self, args: &RenderArgs) {
        self.should_redraw = false;

        const CELL_SIZE: f64 = 30.0;
        const LEFT_MARGIN: f64 = 20f64;
        const TOP_MARGIN: f64 = 30f64;

        const STATUS_LEFT_MARGIN: f64 = 400f64;
        const STATUS_TOP_MARGIN: f64 = 100f64;
        const LINE_HEIGHT: f64 = 40f64;
        const STATUS_PREVIEW_GRID_HEIGHT: f64 = CELL_SIZE * 6f64;

        // so that we can access inside clojure
        let use_cache = &mut self.cache;
        let use_tetris = &mut self.tetris;

        self.gl.draw(args.viewport(), |c, gl| {
            // clear the viewport
            graphics::clear(BLACK, gl);

            // render the current score and level
            let mut text = graphics::Text::new(22);
            text.color = ORANGE;
            let mut transform = c.trans(STATUS_LEFT_MARGIN, STATUS_TOP_MARGIN);
            text.draw(&format!("Level: {}", use_tetris.get_level()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            text.draw(&format!("Score: {}", use_tetris.get_score()), use_cache, &c.draw_state,
                transform.transform, gl);
            transform = transform.trans(0f64, LINE_HEIGHT);

            // render the next shape as a preview of what's coming next
            for point in use_tetris.get_next_shape().iter() {
                let square = graphics::rectangle::square(0f64, 0f64, CELL_SIZE - 1f64);
                let color = get_shape_color(use_tetris.get_next_shape_index() as i32);
                // render the shape at col 2 and row 2
                let (x, y) = ((2 as i16 + point.x) as f64 * CELL_SIZE,
                    (2 as i16 + point.y) as f64 * CELL_SIZE);
                //graphics::rectangle(color, square, transform.trans(x, y).transform, gl);
                let mut rectangle = graphics::Rectangle::new(color);
                rectangle.shape = graphics::rectangle::Shape::Round(4.0, 16);
                rectangle.draw(square, &c.draw_state, transform.trans(x, y).transform, gl);
            }
            transform = transform.trans(0f64, STATUS_PREVIEW_GRID_HEIGHT);

            // render GAME OVER text if necessary
            if use_tetris.get_game_over() {
                text.draw(&"GAME OVER", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Press 'N' for a new game", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Use arrow keys to move and rotate", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Press spacebar to drop", use_cache, &c.draw_state,
                    transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&format!("Press 'K' to decrease starting level ({})", use_tetris.get_starting_level()),
                    use_cache, &c.draw_state, transform.transform, gl);
                transform = transform.trans(0f64, LINE_HEIGHT);

                text.draw(&"Press 'L' to increase starting level",
                    use_cache, &c.draw_state, transform.transform, gl);
                // uncomment if drawing additional text in the status area
                //transform = transform.trans(0f64, LINE_HEIGHT);
            }

            // draw a white border around the game board
            let rect_border = graphics::Rectangle::new_border(WHITE, 1.5);
            rect_border.draw([
                LEFT_MARGIN,
                TOP_MARGIN,
                (CELL_SIZE * COL_COUNT as f64) + 1f64,
                (CELL_SIZE * ROW_COUNT as f64) + 1f64,
            ], &c.draw_state, c.transform, gl);

            // render each cell in the game board
            for col in 0..COL_COUNT as i32 {
                for row in 0..ROW_COUNT as i32 {
                    let cell = use_tetris.get_grid_cell(col, row);
                    if cell.cell_type != GridCellType::Void {
                        let (x, y) = (col as f64 * CELL_SIZE, row as f64 * CELL_SIZE);
                        let square = graphics::rectangle::square(0.0f64, 0.0f64, CELL_SIZE - 1f64);
                        let color = match cell.cell_type {
                            GridCellType::Shape => get_shape_color(cell.shape_index),
                            GridCellType::Fixed => get_shape_color(cell.shape_index),
                            GridCellType::Ghost => DARK_GRAY,
                            _ => {
                                assert!(false);
                                BLACK
                            }
                        };
                        let transform = c.transform.trans(LEFT_MARGIN, TOP_MARGIN).trans(x, y);

                        //graphics::rectangle(color, square, transform, gl);

                        let mut rectangle = graphics::Rectangle::new(color);
                        rectangle.shape = graphics::rectangle::Shape::Round(4.0, 16);
                        rectangle.draw(square, &c.draw_state, transform, gl);
                    }
                }
            }
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        if self.tetris.get_game_over() {
            self.elapsed_time = 0.0;
        } else {
            // Here we increment the time elapsed between update()'s
            self.elapsed_time += args.dt;
            // if the elapsed time is now greater than the time allotted between ticks, then invoke tetris.tick()
            if self.elapsed_time > self.tetris.get_tick_time() as f64 {
                self.elapsed_time = 0.0;
                self.tetris.tick();
                self.should_redraw = true;
            }
        }
    }

    fn handle_input(&mut self, i: Input) {
        let prev_should_redraw = self.should_redraw;
        self.should_redraw = true;
        match i {
            Input::Press(Keyboard(Key::Left)) => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col - 1);
            },

            Input::Press(Keyboard(Key::Right)) => {
                let col: i32 = self.tetris.get_col();
                self.tetris.set_col(col + 1);
            },

            Input::Press(Keyboard(Key::Up)) => {
                self.tetris.rotate(true);
            },

            Input::Press(Keyboard(Key::Down)) => {
                let row: i32 = self.tetris.get_row() + 1;
                self.tetris.set_row(row);
            },

            Input::Press(Keyboard(Key::Space)) => {
                let mut row: i32 = self.tetris.get_row() + 1;
                while self.tetris.set_row(row) {
                    row += 1;
                }
                // hard drop immediately spawns next shape
                self.tetris.tick();
            },

            Input::Press(Keyboard(Key::N)) => {
                self.tetris.start_game();
            },

            Input::Press(Keyboard(Key::K)) => {
                if self.tetris.get_starting_level() > 0 {
                    let new_level: u32 = self.tetris.get_starting_level() - 1;
                    self.tetris.set_starting_level(new_level);
                }
            },

            Input::Press(Keyboard(Key::L)) => {
                if self.tetris.get_starting_level() < 30 {
                    let new_level: u32 = self.tetris.get_starting_level() + 1;
                    self.tetris.set_starting_level(new_level);
                }
            },

            _ => {
                self.should_redraw = prev_should_redraw;
            }
        }
    }
}

fn main() {
    start_app();
}

fn start_app() {
    let opengl = OpenGL::_3_2;

    let window = Glutin_Window::new(
        opengl,
        WindowSettings::new("Piston Tetris", [1024, 768])
                       .exit_on_esc(true)
                       .vsync(true)
                       //TODO causes error on ubuntu
                       //.samples(1)
    );

    let font_path = Path::new("FiraMono-Bold.ttf");

    let mut app = App {
        gl: GlGraphics::new(opengl),
        tetris: Tetris::new(),
        elapsed_time: 0.0,
        cache: GlyphCache::new(font_path).unwrap(),
        should_redraw: true,
    };

    for e in window.events().max_fps(60).ups(120) {
        match e {
            Event::Input(i) => {
                app.handle_input(i);
            }

            Event::Render(args) if app.should_redraw => {
                app.render(&args);
            }

            Event::Update(args) => {
                app.update(&args);
            }

            _ => {}
        }
    }
}<|endoftext|>


<commit_before>extern crate hkg;
extern crate termion;
extern crate rustc_serialize;
extern crate kuchiki;
extern crate chrono;
extern crate cancellation;

#[macro_use]
extern crate log;
extern crate log4rs;

use std::io::{stdout, stdin, Write};
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex};
use rustc_serialize::json;
use termion::input::TermRead;
use termion::raw::IntoRawMode;
use hkg::status::*;
use hkg::model::IconItem;
use hkg::state_manager::*;
use hkg::screen_manager::*;
use hkg::resources::*;
use hkg::web::*;
use hkg::responser::*;

fn main() {

    // Initialize
    log4rs::init_file("config/log4rs.yaml", Default::default()).expect("fail to init log4rs");

    // Clear the screen.
    hkg::screen::common::clear_screen();

    let _stdout = stdout();

    // web background services
    let (tx_req, rx_req) = channel::<ChannelItem>();
    let (tx_res, rx_res) = channel::<ChannelItem>();

    let mut app = {

        let stdout = {
            Box::new(_stdout.lock().into_raw_mode().expect("fail to lock stdout"))
        };

        let icon_collection: Box<Vec<IconItem>> = {
            let icon_manifest_string = hkg::utility::readfile(String::from("data/icon.manifest.json"));
            Box::new(json::decode(&icon_manifest_string).expect("fail to lock stdout"))
        };

        hkg::App {
            index_builder: hkg::builders::index::Index::new(),
            show_builder: hkg::builders::show::Show::new(),
            state_manager: StateManager::new(),
            screen_manager: ScreenManager::new(),

            // initialize empty page
            list_topic_items: Default::default(),
            show_item: Default::default(),

            status_bar: hkg::screen::status_bar::StatusBar::new(),
            index: hkg::screen::index::Index::new(),
            show: hkg::screen::show::Show::new(icon_collection),

            image_request_count_lock: Arc::new(Mutex::new(0)),
            tx_req: &tx_req,
            rx_res: &rx_res,

            stdout: stdout
        }
    };

    Requester::new(rx_req, tx_res);

    let respsoner = Responser::new();

    let mut index_control = hkg::control::index::Index::new();
    let mut show_control = hkg::control::show::Show::new();

    // topics request
    let status_message = list_page(&mut app.state_manager, &tx_req);
    app.status_bar.append(&app.screen_manager, &status_message);

    loop {

        respsoner.try_recv(&mut app);

        print_screen(&mut app);

        if !app.state_manager.is_web_request() {

            let stdin = stdin();

            for c in stdin.keys() {

                if app.screen_manager.is_width_changed() {
                    hkg::screen::common::clear_screen();
                }

                match app.state_manager.get_state() {
                    Status::Startup => {}
                    Status::List => {
                        match index_control.handle(c.ok().expect("fail to get stdin keys"), &mut app) {
                            Some(i) => if i == 0 { return } else { break },
                            None => {}
                        }
                    }
                    Status::Show => {
                        match show_control.handle(c.ok().expect("fail to get stdin keys"), &mut app) {
                            Some(i) => if i == 0 { return } else { break },
                            None => {}
                        }
                    }
                }

            }
        }
    }
}

fn list_page(state_manager: &mut StateManager, tx_req: &Sender<ChannelItem>) -> String {

    let ci = ChannelItem {
        extra: ChannelItemType::Index(ChannelIndexItem {}),
        result: String::from(""),
    };

    let status_message = match tx_req.send(ci) {
        Ok(()) => {
            state_manager.set_web_request(true);    // *is_web_requesting = true;
            "SOK".to_string()
        }
        Err(e) => format!("{}:{}", "SFAIL", e).to_string(),
    };

    status_message
}

fn print_screen(app: &mut hkg::App) {
    match app.state_manager.get_state() {
        Status::Startup => {}
        Status::List => {
            app.index.print(&mut app.stdout, &app.list_topic_items);
        }
        Status::Show => {
            app.show.print(&mut app.stdout, &app.show_item);
        }
    }

    app.status_bar.print(&app.screen_manager);

    app.stdout.flush().expect("fail to flush the stdout");
}
<commit_msg>put stdin in other thread<commit_after>extern crate hkg;
extern crate termion;
extern crate rustc_serialize;
extern crate kuchiki;
extern crate chrono;
extern crate cancellation;

#[macro_use]
extern crate log;
extern crate log4rs;

use std::io::{stdout, stdin, Write};
use std::io::{self, Read};
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex};
use rustc_serialize::json;
use termion::input::TermRead;
use termion::raw::IntoRawMode;
use hkg::status::*;
use hkg::model::IconItem;
use hkg::state_manager::*;
use hkg::screen_manager::*;
use hkg::resources::*;
use hkg::web::*;
use hkg::responser::*;
use std::thread;

fn main() {

    // Initialize
    log4rs::init_file("config/log4rs.yaml", Default::default()).expect("fail to init log4rs");

    // Clear the screen.
    hkg::screen::common::clear_screen();

    let _stdout = stdout();

    // web background services
    let (tx_req, rx_req) = channel::<ChannelItem>();
    let (tx_res, rx_res) = channel::<ChannelItem>();

    let mut app = {

        let stdout = {
            Box::new(_stdout.lock().into_raw_mode().expect("fail to lock stdout"))
        };

        let icon_collection: Box<Vec<IconItem>> = {
            let icon_manifest_string = hkg::utility::readfile(String::from("data/icon.manifest.json"));
            Box::new(json::decode(&icon_manifest_string).expect("fail to lock stdout"))
        };

        hkg::App {
            index_builder: hkg::builders::index::Index::new(),
            show_builder: hkg::builders::show::Show::new(),
            state_manager: StateManager::new(),
            screen_manager: ScreenManager::new(),

            // initialize empty page
            list_topic_items: Default::default(),
            show_item: Default::default(),

            status_bar: hkg::screen::status_bar::StatusBar::new(),
            index: hkg::screen::index::Index::new(),
            show: hkg::screen::show::Show::new(icon_collection),

            image_request_count_lock: Arc::new(Mutex::new(0)),
            tx_req: &tx_req,
            rx_res: &rx_res,

            stdout: stdout,
        }
    };

    Requester::new(rx_req, tx_res);

    let respsoner = Responser::new();

    let mut index_control = hkg::control::index::Index::new();
    let mut show_control = hkg::control::show::Show::new();

    // topics request
    let status_message = list_page(&mut app.state_manager, &tx_req);
    app.status_bar.append(&app.screen_manager, &status_message);

    let (tx_in, rx_in) = channel::<::termion::event::Key>();

    thread::spawn(move || {
        loop {

            let stdin = stdin();

            for c in stdin.keys() {
                // println!("{:?}", c);
                tx_in.send(c.ok().unwrap()).unwrap();

            }
        }
    });

    loop {

        respsoner.try_recv(&mut app);

        match rx_in.try_recv() {
            Ok(c) => {
                info!("receive input!!! {:?}", c);
                if !app.state_manager.is_web_request() {

                    match app.state_manager.get_state() {
                        Status::Startup => {}
                        Status::List => {
                            match index_control.handle(c, &mut app) {
                                Some(i) => {
                                    if i == 0 {
                                        return;
                                    }
                                }
                                None => {}
                            }
                        }
                        Status::Show => {
                            match show_control.handle(c, &mut app) {
                                Some(i) => {
                                    if i == 0 {
                                        return;
                                    }
                                }
                                None => {}
                            }
                        }
                    }
                }
            }
            Err(e) => {}
        };

        if app.screen_manager.is_width_changed() {
            hkg::screen::common::clear_screen();
        }

        match app.state_manager.get_state() {
            Status::Startup => {}
            Status::List => {
                print_screen(&mut app);
            }
            Status::Show => {
                print_screen(&mut app);
            }
        }

        thread::sleep(std::time::Duration::from_millis(50));
    }
}

fn list_page(state_manager: &mut StateManager, tx_req: &Sender<ChannelItem>) -> String {

    let ci = ChannelItem {
        extra: ChannelItemType::Index(ChannelIndexItem {}),
        result: String::from(""),
    };

    let status_message = match tx_req.send(ci) {
        Ok(()) => {
            state_manager.set_web_request(true);    // *is_web_requesting = true;
            "SOK".to_string()
        }
        Err(e) => format!("{}:{}", "SFAIL", e).to_string(),
    };

    status_message
}

fn print_screen(app: &mut hkg::App) {
    match app.state_manager.get_state() {
        Status::Startup => {}
        Status::List => {
            app.index.print(&mut app.stdout, &app.list_topic_items);
        }
        Status::Show => {
            app.show.print(&mut app.stdout, &app.show_item);
        }
    }

    app.status_bar.print(&app.screen_manager);

    app.stdout.flush().expect("fail to flush the stdout");
}
<|endoftext|>