<commit_before>//! Logger.

use chrono::{Datelike, Local, Timelike};
use std::fmt::Arguments;

/// Trait use to log activity.
pub trait Logger {
  /// Log some information.
  fn info(&mut self, args: Arguments);
  /// Log some debug information.
  fn debug(&mut self, args: Arguments);
  /// Log some warnings.
  fn warn(&mut self, args: Arguments);
  /// Log some errors.
  fn error(&mut self, args: Arguments);
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct StdoutLogger;

impl Logger for StdoutLogger {
  fn info(&mut self, args: Arguments) {
    println!("\x1b[90m{} \x1b[34m> {}\x1b[0m", now(), args);
  }

  fn debug(&mut self, args: Arguments) {
    println!("\x1b[90m{} \x1b[34m> {}\x1b[0m", now(), args);
  }

  fn warn(&mut self, args: Arguments) {
    println!("\x1b[90m{} \x1b[33m> {}\x1b[0m", now(), args);
  }

  fn error(&mut self, args: Arguments) {
    println!("\x1b[90m{} \x1b[31m> {}\x1b[0m", now(), args);
  }
}

fn now() -> String {
  let t = Local::now();

  format!("{month:0>2}/{day:0>2}/{year} {hour:0>2}:{min:0>2}:{secs:0>2}:{nsecs:0>9}",
          month = t.month(),
          day = t.day(),
          year = t.year(),
          hour = t.hour(),
          min = t.minute(),
          secs = t.second(),
          nsecs = t.nanosecond())
}

#[macro_export]
macro_rules! info {
  ($logger:expr, $s:expr $(, $r:tt)*) => {{
    use $crate::logger::Logger;
    $logger.info(format_args!($s $(, $r)*));
  }}
}

#[macro_export]
macro_rules! debug {
  ($logger:expr, $s:expr $(, $r:tt)*) => {
    use $crate::logger::Logger;
    $logger.debug(format_args!($s $(, $r)*));
  }
}

#[macro_export]
macro_rules! warn {
  ($logger:expr, $s:expr $(, $r:tt)*) => {
    use $crate::logger::Logger;
    $logger.warn(format_args!($s, $($r)*));
  }
}

#[macro_export]
macro_rules! error {
  ($logger:expr, $s:expr, $($r:tt),*) => {
    use $crate::logger::Logger;
    $logger.error(format_args!($s, $($r),*));
  }
}
<commit_msg>impl Default for StdoutLogger.<commit_after>//! Logger.

use chrono::{Datelike, Local, Timelike};
use std::fmt::Arguments;

/// Trait use to log activity.
pub trait Logger {
  /// Log some information.
  fn info(&mut self, args: Arguments);
  /// Log some debug information.
  fn debug(&mut self, args: Arguments);
  /// Log some warnings.
  fn warn(&mut self, args: Arguments);
  /// Log some errors.
  fn error(&mut self, args: Arguments);
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct StdoutLogger;

impl Default for StdoutLogger {
  fn default() -> Self {
    StdoutLogger
  }
}

impl Logger for StdoutLogger {
  fn info(&mut self, args: Arguments) {
    println!("\x1b[90m{} \x1b[34m> {}\x1b[0m", now(), args);
  }

  fn debug(&mut self, args: Arguments) {
    println!("\x1b[90m{} \x1b[34m> {}\x1b[0m", now(), args);
  }

  fn warn(&mut self, args: Arguments) {
    println!("\x1b[90m{} \x1b[33m> {}\x1b[0m", now(), args);
  }

  fn error(&mut self, args: Arguments) {
    println!("\x1b[90m{} \x1b[31m> {}\x1b[0m", now(), args);
  }
}

fn now() -> String {
  let t = Local::now();

  format!("{month:0>2}/{day:0>2}/{year} {hour:0>2}:{min:0>2}:{secs:0>2}:{nsecs:0>9}",
          month = t.month(),
          day = t.day(),
          year = t.year(),
          hour = t.hour(),
          min = t.minute(),
          secs = t.second(),
          nsecs = t.nanosecond())
}

#[macro_export]
macro_rules! info {
  ($logger:expr, $s:expr $(, $r:tt)*) => {{
    use $crate::logger::Logger;
    $logger.info(format_args!($s $(, $r)*));
  }}
}

#[macro_export]
macro_rules! debug {
  ($logger:expr, $s:expr $(, $r:tt)*) => {
    use $crate::logger::Logger;
    $logger.debug(format_args!($s $(, $r)*));
  }
}

#[macro_export]
macro_rules! warn {
  ($logger:expr, $s:expr $(, $r:tt)*) => {
    use $crate::logger::Logger;
    $logger.warn(format_args!($s, $($r)*));
  }
}

#[macro_export]
macro_rules! error {
  ($logger:expr, $s:expr, $($r:tt),*) => {
    use $crate::logger::Logger;
    $logger.error(format_args!($s, $($r),*));
  }
}
<|endoftext|>


<commit_before>use num::Float;
use num::traits::FloatConst;
use std::cmp;
use std::marker::PhantomData;

use generate::generate::{IndexedPolygonGenerator, PolygonGenerator, SpatialPolygonGenerator,
                         SpatialVertexGenerator, VertexGenerator};
use generate::topology::{Polygon, Quad, Triangle};

#[derive(Clone)]
pub struct UVSphere<T>
where
    T: Float + FloatConst,
{
    nu: usize, // Meridians.
    nv: usize, // Parallels.
    phantom: PhantomData<T>,
}

impl<T> UVSphere<T>
where
    T: Float + FloatConst,
{
    pub fn with_unit_radius(nu: usize, nv: usize) -> Self {
        let nu = cmp::max(3, nu);
        let nv = cmp::max(2, nv);
        UVSphere {
            nu: nu,
            nv: nv,
            phantom: PhantomData,
        }
    }

    fn spatial_vertex(&self, u: usize, v: usize) -> (T, T, T) {
        let u = (T::from(u).unwrap() / T::from(self.nu).unwrap()) * T::PI() * (T::one() + T::one());
        let v = (T::from(v).unwrap() / T::from(self.nv).unwrap()) * T::PI();
        (u.cos() * v.sin(), u.sin() * v.sin(), v.cos())
    }

    fn indexed_vertex(&self, u: usize, v: usize) -> usize {
        if v == 0 {
            0
        }
        else if v == self.nv {
            ((self.nv - 1) * self.nu) + 1
        }
        else {
            ((v - 1) * self.nu) + (u % self.nu) + 1
        }
    }

    fn map_polygon_index(&self, index: usize) -> (usize, usize) {
        (index % self.nu, index / self.nu)
    }
}

impl<T> VertexGenerator for UVSphere<T>
where
    T: Float + FloatConst,
{
    fn vertex_count(&self) -> usize {
        (self.nv - 1) * self.nu + 2
    }
}

impl<T> SpatialVertexGenerator for UVSphere<T>
where
    T: Float + FloatConst,
{
    type Output = (T, T, T);

    fn spatial_vertex(&self, index: usize) -> Self::Output {
        if index == 0 {
            self.spatial_vertex(0, 0)
        }
        else if index == self.vertex_count() - 1 {
            self.spatial_vertex(0, self.nv)
        }
        else {
            let index = index - 1;
            self.spatial_vertex(index % self.nu, (index / self.nu) + 1)
        }
    }
}

impl<T> PolygonGenerator for UVSphere<T>
where
    T: Float + FloatConst,
{
    fn polygon_count(&self) -> usize {
        self.nu * self.nv
    }
}

impl<T> SpatialPolygonGenerator for UVSphere<T>
where
    T: Float + FloatConst,
{
    type Output = Polygon<(T, T, T)>;

    fn spatial_polygon(&self, index: usize) -> Self::Output {
        // Prevent floating point rounding errors by wrapping the incremented
        // values for `(u, v)` into `(p, q)`. This is important for indexing
        // geometry, because small differences in the computation of spatial
        // vertices will produce unique output vertices.
        let (u, v) = self.map_polygon_index(index);
        let (p, q) = (u + 1, (v + 1) % self.nv);

        // Generate the vertices at the requested meridian and parallel. The
        // upper and lower bounds of (u, v) are always used, so generate them
        // in advance (`low` and `high`). Emit triangles at the poles,
        // otherwise quads.
        let low = self.spatial_vertex(u, v);
        let high = self.spatial_vertex(p, q);
        if v == 0 {
            Polygon::Triangle(Triangle::new(low, self.spatial_vertex(u, q), high))
        }
        else if v == self.nv - 1 {
            Polygon::Triangle(Triangle::new(high, self.spatial_vertex(p, v), low))
        }
        else {
            Polygon::Quad(Quad::new(
                low,
                self.spatial_vertex(u, q),
                high,
                self.spatial_vertex(p, v),
            ))
        }
    }
}

impl<T> IndexedPolygonGenerator for UVSphere<T>
where
    T: Float + FloatConst,
{
    type Output = Polygon<usize>;

    fn indexed_polygon(&self, index: usize) -> <Self as IndexedPolygonGenerator>::Output {
        let (u, v) = self.map_polygon_index(index);
        let (p, q) = (u + 1, v + 1);

        let low = self.indexed_vertex(u, v);
        let high = self.indexed_vertex(p, q);
        if v == 0 {
            Polygon::Triangle(Triangle::new(low, self.indexed_vertex(u, q), high))
        }
        else if v == self.nv - 1 {
            Polygon::Triangle(Triangle::new(high, self.indexed_vertex(p, v), low))
        }
        else {
            Polygon::Quad(Quad::new(
                low,
                self.indexed_vertex(u, q),
                high,
                self.indexed_vertex(p, v),
            ))
        }
    }
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeSet;
    use std::iter::FromIterator;

    use super::super::*;

    #[test]
    fn vertex_count() {
        assert_eq!(
            5,
            sphere::UVSphere::<f32>::with_unit_radius(3, 2)
                .spatial_vertices() // 5 conjoint vertices.
                .count()
        );
    }

    #[test]
    fn polygon_vertex_count() {
        assert_eq!(
            18,
            sphere::UVSphere::<f32>::with_unit_radius(3, 2)
                .spatial_polygons() // 6 triangles, 18 vertices.
                .vertices()
                .count()
        );
    }

    #[test]
    fn index_to_vertex_mapping() {
        assert_eq!(
            5,
            BTreeSet::from_iter(
                sphere::UVSphere::<f32>::with_unit_radius(3, 2)
                    .indexed_polygons() // 18 vertices, 5 indeces.
                    .vertices()
            ).len()
        )
    }
}
<commit_msg>Use `Unit` trait for `UVSphere` and provide `with_unit_width`.<commit_after>use num::Float;
use num::traits::FloatConst;
use std::cmp;
use std::marker::PhantomData;

use generate::generate::{IndexedPolygonGenerator, PolygonGenerator, SpatialPolygonGenerator,
                         SpatialVertexGenerator, VertexGenerator};
use generate::geometry::Unit;
use generate::topology::{Polygon, Quad, Triangle};

#[derive(Clone)]
pub struct UVSphere<T>
where
    T: Float + FloatConst + Unit,
{
    nu: usize, // Meridians.
    nv: usize, // Parallels.
    unit: T,
    phantom: PhantomData<T>,
}

impl<T> UVSphere<T>
where
    T: Float + FloatConst + Unit,
{
    fn new(nu: usize, nv: usize, upper: T) -> Self {
        let nu = cmp::max(3, nu);
        let nv = cmp::max(2, nv);
        UVSphere {
            nu: nu,
            nv: nv,
            unit: upper,
            phantom: PhantomData,
        }
    }

    pub fn with_unit_radius(nu: usize, nv: usize) -> Self {
        Self::new(nu, nv, T::unit_radius().1)
    }

    pub fn with_unit_width(nu: usize, nv: usize) -> Self {
        Self::new(nu, nv, T::unit_width().1)
    }

    fn spatial_vertex(&self, u: usize, v: usize) -> (T, T, T) {
        let u = (T::from(u).unwrap() / T::from(self.nu).unwrap()) * T::PI() * (T::one() + T::one());
        let v = (T::from(v).unwrap() / T::from(self.nv).unwrap()) * T::PI();
        (
            self.unit * u.cos() * v.sin(),
            self.unit * u.sin() * v.sin(),
            self.unit * v.cos(),
        )
    }

    fn indexed_vertex(&self, u: usize, v: usize) -> usize {
        if v == 0 {
            0
        }
        else if v == self.nv {
            ((self.nv - 1) * self.nu) + 1
        }
        else {
            ((v - 1) * self.nu) + (u % self.nu) + 1
        }
    }

    fn map_polygon_index(&self, index: usize) -> (usize, usize) {
        (index % self.nu, index / self.nu)
    }
}

impl<T> VertexGenerator for UVSphere<T>
where
    T: Float + FloatConst + Unit,
{
    fn vertex_count(&self) -> usize {
        (self.nv - 1) * self.nu + 2
    }
}

impl<T> SpatialVertexGenerator for UVSphere<T>
where
    T: Float + FloatConst + Unit,
{
    type Output = (T, T, T);

    fn spatial_vertex(&self, index: usize) -> Self::Output {
        if index == 0 {
            self.spatial_vertex(0, 0)
        }
        else if index == self.vertex_count() - 1 {
            self.spatial_vertex(0, self.nv)
        }
        else {
            let index = index - 1;
            self.spatial_vertex(index % self.nu, (index / self.nu) + 1)
        }
    }
}

impl<T> PolygonGenerator for UVSphere<T>
where
    T: Float + FloatConst + Unit,
{
    fn polygon_count(&self) -> usize {
        self.nu * self.nv
    }
}

impl<T> SpatialPolygonGenerator for UVSphere<T>
where
    T: Float + FloatConst + Unit,
{
    type Output = Polygon<(T, T, T)>;

    fn spatial_polygon(&self, index: usize) -> Self::Output {
        // Prevent floating point rounding errors by wrapping the incremented
        // values for `(u, v)` into `(p, q)`. This is important for indexing
        // geometry, because small differences in the computation of spatial
        // vertices will produce unique output vertices.
        let (u, v) = self.map_polygon_index(index);
        let (p, q) = (u + 1, (v + 1) % self.nv);

        // Generate the vertices at the requested meridian and parallel. The
        // upper and lower bounds of (u, v) are always used, so generate them
        // in advance (`low` and `high`). Emit triangles at the poles,
        // otherwise quads.
        let low = self.spatial_vertex(u, v);
        let high = self.spatial_vertex(p, q);
        if v == 0 {
            Polygon::Triangle(Triangle::new(low, self.spatial_vertex(u, q), high))
        }
        else if v == self.nv - 1 {
            Polygon::Triangle(Triangle::new(high, self.spatial_vertex(p, v), low))
        }
        else {
            Polygon::Quad(Quad::new(
                low,
                self.spatial_vertex(u, q),
                high,
                self.spatial_vertex(p, v),
            ))
        }
    }
}

impl<T> IndexedPolygonGenerator for UVSphere<T>
where
    T: Float + FloatConst + Unit,
{
    type Output = Polygon<usize>;

    fn indexed_polygon(&self, index: usize) -> <Self as IndexedPolygonGenerator>::Output {
        let (u, v) = self.map_polygon_index(index);
        let (p, q) = (u + 1, v + 1);

        let low = self.indexed_vertex(u, v);
        let high = self.indexed_vertex(p, q);
        if v == 0 {
            Polygon::Triangle(Triangle::new(low, self.indexed_vertex(u, q), high))
        }
        else if v == self.nv - 1 {
            Polygon::Triangle(Triangle::new(high, self.indexed_vertex(p, v), low))
        }
        else {
            Polygon::Quad(Quad::new(
                low,
                self.indexed_vertex(u, q),
                high,
                self.indexed_vertex(p, v),
            ))
        }
    }
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeSet;
    use std::iter::FromIterator;

    use super::super::*;

    #[test]
    fn vertex_count() {
        assert_eq!(
            5,
            sphere::UVSphere::<f32>::with_unit_radius(3, 2)
                .spatial_vertices() // 5 conjoint vertices.
                .count()
        );
    }

    #[test]
    fn polygon_vertex_count() {
        assert_eq!(
            18,
            sphere::UVSphere::<f32>::with_unit_radius(3, 2)
                .spatial_polygons() // 6 triangles, 18 vertices.
                .vertices()
                .count()
        );
    }

    #[test]
    fn index_to_vertex_mapping() {
        assert_eq!(
            5,
            BTreeSet::from_iter(
                sphere::UVSphere::<f32>::with_unit_radius(3, 2)
                    .indexed_polygons() // 18 vertices, 5 indeces.
                    .vertices()
            ).len()
        )
    }
}
<|endoftext|>


<commit_before>use gl;

use context::CommandContext;
use version::Version;
use version::Api;

use backend::Facade;
use CapabilitiesSource;

use std::fmt;
use std::error::Error;
use std::collections::hash_map::{self, HashMap};

use GlObject;
use ProgramExt;
use Handle;
use RawUniformValue;

use program::{COMPILER_GLOBAL_LOCK, ProgramCreationInput, ProgramCreationError, Binary};
use program::GetBinaryError;

use program::reflection::{Uniform, UniformBlock, OutputPrimitives};
use program::reflection::{Attribute, TransformFeedbackBuffer};
use program::reflection::{SubroutineData, ShaderStage};
use program::shader::build_shader;

use program::raw::RawProgram;

use vertex::VertexFormat;

/// A combination of shaders linked together.
pub struct Program {
    raw: RawProgram,
    outputs_srgb: bool,
    uses_point_size: bool,
}

impl Program {
    /// Builds a new program.
    pub fn new<'a, F, I>(facade: &F, input: I) -> Result<Program, ProgramCreationError>
                         where I: Into<ProgramCreationInput<'a>>, F: Facade
    {
        let input = input.into();

        let (raw, outputs_srgb, uses_point_size) = match input {
            ProgramCreationInput::SourceCode { vertex_shader, tessellation_control_shader,
                                               tessellation_evaluation_shader, geometry_shader,
                                               fragment_shader, transform_feedback_varyings,
                                               outputs_srgb, uses_point_size } =>
            {
                let mut has_geometry_shader = false;
                let mut has_tessellation_control_shader = false;
                let mut has_tessellation_evaluation_shader = false;

                let mut shaders = vec![
                    (vertex_shader, gl::VERTEX_SHADER),
                    (fragment_shader, gl::FRAGMENT_SHADER)
                ];

                if let Some(gs) = geometry_shader {
                    shaders.push((gs, gl::GEOMETRY_SHADER));
                    has_geometry_shader = true;
                }

                if let Some(ts) = tessellation_control_shader {
                    shaders.push((ts, gl::TESS_CONTROL_SHADER));
                    has_tessellation_control_shader = true;
                }

                if let Some(ts) = tessellation_evaluation_shader {
                    shaders.push((ts, gl::TESS_EVALUATION_SHADER));
                    has_tessellation_evaluation_shader = true;
                }

                // TODO: move somewhere else
                if transform_feedback_varyings.is_some() &&
                    (facade.get_context().get_version() >= &Version(Api::Gl, 3, 0) ||
                        !facade.get_context().get_extensions().gl_ext_transform_feedback)
                {
                    return Err(ProgramCreationError::TransformFeedbackNotSupported);
                }

                if uses_point_size && !(facade.get_context().get_version() >= &Version(Api::Gl, 3, 0)) {
                    return Err(ProgramCreationError::PointSizeNotSupported);
                }

                let _lock = COMPILER_GLOBAL_LOCK.lock();

                let shaders_store = {
                    let mut shaders_store = Vec::new();
                    for (src, ty) in shaders.into_iter() {
                        shaders_store.push(try!(build_shader(facade, ty, src)));
                    }
                    shaders_store
                };

                (try!(RawProgram::from_shaders(facade, &shaders_store, has_geometry_shader,
                                               has_tessellation_control_shader, has_tessellation_evaluation_shader,
                                               transform_feedback_varyings)),
                 outputs_srgb, uses_point_size)
            },

            ProgramCreationInput::Binary { data, outputs_srgb, uses_point_size } => {
                if uses_point_size && !(facade.get_context().get_version() >= &Version(Api::Gl, 3, 0)) {
                    return Err(ProgramCreationError::PointSizeNotSupported);
                }

                (try!(RawProgram::from_binary(facade, data)), outputs_srgb, uses_point_size)
            },
        };
        Ok(Program {
            raw: raw,
            outputs_srgb: outputs_srgb,
            uses_point_size: uses_point_size,
        })
    }

    /// Builds a new program from GLSL source code.
    ///
    /// A program is a group of shaders linked together.
    ///
    /// # Parameters
    ///
    /// - `vertex_shader`: Source code of the vertex shader.
    /// - `fragment_shader`: Source code of the fragment shader.
    /// - `geometry_shader`: Source code of the geometry shader.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # let display: glium::Display = unsafe { std::mem::uninitialized() };
    /// # let vertex_source = ""; let fragment_source = ""; let geometry_source = "";
    /// let program = glium::Program::from_source(&display, vertex_source, fragment_source,
    ///     Some(geometry_source));
    /// ```
    ///
    #[inline]
    pub fn from_source<'a, F>(facade: &F, vertex_shader: &'a str, fragment_shader: &'a str,
                              geometry_shader: Option<&'a str>)
                              -> Result<Program, ProgramCreationError> where F: Facade
    {
        Program::new(facade, ProgramCreationInput::SourceCode {
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            geometry_shader: geometry_shader,
            tessellation_control_shader: None,
            tessellation_evaluation_shader: None,
            transform_feedback_varyings: None,
            outputs_srgb: false,
            uses_point_size: false,
        })
    }

    /// Returns the program's compiled binary.
    ///
    /// You can store the result in a file, then reload it later. This avoids having to compile
    /// the source code every time.
    #[inline]
    pub fn get_binary(&self) -> Result<Binary, GetBinaryError> {
        self.raw.get_binary()
    }

    /// Returns the *location* of an output fragment, if it exists.
    ///
    /// The *location* is low-level information that is used internally by glium.
    /// You probably don't need to call this function.
    ///
    /// You can declare output fragments in your shaders by writing:
    ///
    /// ```notrust
    /// out vec4 foo;
    /// ```
    ///
    #[inline]
    pub fn get_frag_data_location(&self, name: &str) -> Option<u32> {
        self.raw.get_frag_data_location(name)
    }

    /// Returns informations about a uniform variable, if it exists.
    #[inline]
    pub fn get_uniform(&self, name: &str) -> Option<&Uniform> {
        self.raw.get_uniform(name)
    }

    /// Returns an iterator to the list of uniforms.
    ///
    /// ## Example
    ///
    /// ```no_run
    /// # let program: glium::Program = unsafe { std::mem::uninitialized() };
    /// for (name, uniform) in program.uniforms() {
    ///     println!("Name: {} - Type: {:?}", name, uniform.ty);
    /// }
    /// ```
    #[inline]
    pub fn uniforms(&self) -> hash_map::Iter<String, Uniform> {
        self.raw.uniforms()
    }

    /// Returns a list of uniform blocks.
    ///
    /// ## Example
    ///
    /// ```no_run
    /// # let program: glium::Program = unsafe { std::mem::uninitialized() };
    /// for (name, uniform) in program.get_uniform_blocks() {
    ///     println!("Name: {}", name);
    /// }
    /// ```
    #[inline]
    pub fn get_uniform_blocks(&self) -> &HashMap<String, UniformBlock> {
        self.raw.get_uniform_blocks()
    }

    /// Returns the list of transform feedback varyings.
    #[inline]
    pub fn get_transform_feedback_buffers(&self) -> &[TransformFeedbackBuffer] {
        self.raw.get_transform_feedback_buffers()
    }

    /// True if the transform feedback output of this program matches the specified `VertexFormat`
    /// and `stride`.
    ///
    /// The `stride` is the number of bytes between two vertices.
    #[inline]
    pub fn transform_feedback_matches(&self, format: &VertexFormat, stride: usize) -> bool {
        self.raw.transform_feedback_matches(format, stride)
    }

    /// Returns the type of geometry that transform feedback would generate, or `None` if it
    /// depends on the vertex/index data passed when drawing.
    ///
    /// This corresponds to `GL_GEOMETRY_OUTPUT_TYPE` or `GL_TESS_GEN_MODE`. If the program doesn't
    /// contain either a geometry shader or a tessellation evaluation shader, returns `None`.
    #[inline]
    pub fn get_output_primitives(&self) -> Option<OutputPrimitives> {
        self.raw.get_output_primitives()
    }

    /// Returns true if the program contains a tessellation stage.
    #[inline]
    pub fn has_tessellation_shaders(&self) -> bool {
        self.raw.has_tessellation_shaders()
    }

    /// Returns true if the program contains a tessellation control stage.
    #[inline]
    pub fn has_tessellation_control_shader(&self) -> bool {
        self.raw.has_tessellation_control_shader()
    }

    /// Returns true if the program contains a tessellation evaluation stage.
    #[inline]
    pub fn has_tessellation_evaluation_shader(&self) -> bool {
        self.raw.has_tessellation_evaluation_shader()
    }

    /// Returns true if the program contains a geometry shader.
    #[inline]
    pub fn has_geometry_shader(&self) -> bool {
        self.raw.has_geometry_shader()
    }

    /// Returns informations about an attribute, if it exists.
    #[inline]
    pub fn get_attribute(&self, name: &str) -> Option<&Attribute> {
        self.raw.get_attribute(name)
    }

    /// Returns an iterator to the list of attributes.
    ///
    /// ## Example
    ///
    /// ```no_run
    /// # let program: glium::Program = unsafe { std::mem::uninitialized() };
    /// for (name, attribute) in program.attributes() {
    ///     println!("Name: {} - Type: {:?}", name, attribute.ty);
    /// }
    /// ```
    #[inline]
    pub fn attributes(&self) -> hash_map::Iter<String, Attribute> {
        self.raw.attributes()
    }

    /// Returns true if the program has been configured to output sRGB instead of RGB.
    #[inline]
    pub fn has_srgb_output(&self) -> bool {
        self.outputs_srgb
    }

    /// Returns the list of shader storage blocks.
    ///
    /// ## Example
    ///
    /// ```no_run
    /// # let program: glium::Program = unsafe { std::mem::uninitialized() };
    /// for (name, uniform) in program.get_shader_storage_blocks() {
    ///     println!("Name: {}", name);
    /// }
    /// ```
    #[inline]
    pub fn get_shader_storage_blocks(&self) -> &HashMap<String, UniformBlock> {
        self.raw.get_shader_storage_blocks()
    }

    /// Returns true if the program has been configured to use the `gl_PointSize` variable.
    ///
    /// If the program uses `gl_PointSize` without having been configured appropriately, then
    /// setting the value of `gl_PointSize` will have no effect.
    #[inline]
    pub fn uses_point_size(&self) -> bool {
      self.uses_point_size
    }
}

impl fmt::Debug for Program {
    #[inline]
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(formatter, "{:?}", self.raw)
    }
}

impl GlObject for Program {
    type Id = Handle;

    #[inline]
    fn get_id(&self) -> Handle {
        self.raw.get_id()
    }
}

impl ProgramExt for Program {
    fn use_program(&self, ctxt: &mut CommandContext) {
        // compatibility was checked at program creation
        if self.uses_point_size && !ctxt.state.enabled_program_point_size {
            unsafe { ctxt.gl.Enable(gl::PROGRAM_POINT_SIZE); }
        } else if !self.uses_point_size && ctxt.state.enabled_program_point_size {
            unsafe { ctxt.gl.Disable(gl::PROGRAM_POINT_SIZE); }
        }

        if ctxt.version >= &Version(Api::Gl, 3, 0) || ctxt.extensions.gl_arb_framebuffer_srgb ||
           ctxt.extensions.gl_ext_framebuffer_srgb || ctxt.extensions.gl_ext_srgb_write_control
        {
            if ctxt.state.enabled_framebuffer_srgb == self.outputs_srgb {
                ctxt.state.enabled_framebuffer_srgb = !self.outputs_srgb;

                if self.outputs_srgb {
                    unsafe { ctxt.gl.Disable(gl::FRAMEBUFFER_SRGB) };
                } else {
                    unsafe { ctxt.gl.Enable(gl::FRAMEBUFFER_SRGB) };
                }
            }
        }

        self.raw.use_program(ctxt)
    }

    #[inline]
    fn set_uniform(&self, ctxt: &mut CommandContext, uniform_location: gl::types::GLint,
                   value: &RawUniformValue)
    {
        self.raw.set_uniform(ctxt, uniform_location, value)
    }

    #[inline]
    fn set_uniform_block_binding(&self, ctxt: &mut CommandContext, block_location: gl::types::GLuint,
                                 value: gl::types::GLuint)
    {
        self.raw.set_uniform_block_binding(ctxt, block_location, value)
    }

    #[inline]
    fn set_shader_storage_block_binding(&self, ctxt: &mut CommandContext,
                                        block_location: gl::types::GLuint,
                                        value: gl::types::GLuint)
    {
        self.raw.set_shader_storage_block_binding(ctxt, block_location, value)
    }

    #[inline]
    fn set_subroutine_uniforms_for_stage(&self, ctxt: &mut CommandContext,
                                         stage: ShaderStage,
                                         indices: &[gl::types::GLuint])
    {
        self.raw.set_subroutine_uniforms_for_stage(ctxt, stage, indices);
    }

    #[inline]
    fn get_uniform(&self, name: &str) -> Option<&Uniform> {
        self.raw.get_uniform(name)
    }

    #[inline]
    fn get_uniform_blocks(&self) -> &HashMap<String, UniformBlock> {
        self.raw.get_uniform_blocks()
    }

    #[inline]
    fn get_shader_storage_blocks(&self) -> &HashMap<String, UniformBlock> {
        self.raw.get_shader_storage_blocks()
    }

    #[inline]
    fn get_subroutine_data(&self) -> &SubroutineData {
        self.raw.get_subroutine_data()
    }
}
<commit_msg>Expose `Program::get_subroutine_uniforms()`  so the user can query this data<commit_after>use gl;

use context::CommandContext;
use version::Version;
use version::Api;

use backend::Facade;
use CapabilitiesSource;

use std::fmt;
use std::error::Error;
use std::collections::hash_map::{self, HashMap};

use GlObject;
use ProgramExt;
use Handle;
use RawUniformValue;

use program::{COMPILER_GLOBAL_LOCK, ProgramCreationInput, ProgramCreationError, Binary};
use program::GetBinaryError;

use program::reflection::{Uniform, UniformBlock, OutputPrimitives};
use program::reflection::{Attribute, TransformFeedbackBuffer};
use program::reflection::{SubroutineData, ShaderStage, SubroutineUniform};
use program::shader::build_shader;

use program::raw::RawProgram;

use vertex::VertexFormat;

/// A combination of shaders linked together.
pub struct Program {
    raw: RawProgram,
    outputs_srgb: bool,
    uses_point_size: bool,
}

impl Program {
    /// Builds a new program.
    pub fn new<'a, F, I>(facade: &F, input: I) -> Result<Program, ProgramCreationError>
                         where I: Into<ProgramCreationInput<'a>>, F: Facade
    {
        let input = input.into();

        let (raw, outputs_srgb, uses_point_size) = match input {
            ProgramCreationInput::SourceCode { vertex_shader, tessellation_control_shader,
                                               tessellation_evaluation_shader, geometry_shader,
                                               fragment_shader, transform_feedback_varyings,
                                               outputs_srgb, uses_point_size } =>
            {
                let mut has_geometry_shader = false;
                let mut has_tessellation_control_shader = false;
                let mut has_tessellation_evaluation_shader = false;

                let mut shaders = vec![
                    (vertex_shader, gl::VERTEX_SHADER),
                    (fragment_shader, gl::FRAGMENT_SHADER)
                ];

                if let Some(gs) = geometry_shader {
                    shaders.push((gs, gl::GEOMETRY_SHADER));
                    has_geometry_shader = true;
                }

                if let Some(ts) = tessellation_control_shader {
                    shaders.push((ts, gl::TESS_CONTROL_SHADER));
                    has_tessellation_control_shader = true;
                }

                if let Some(ts) = tessellation_evaluation_shader {
                    shaders.push((ts, gl::TESS_EVALUATION_SHADER));
                    has_tessellation_evaluation_shader = true;
                }

                // TODO: move somewhere else
                if transform_feedback_varyings.is_some() &&
                    (facade.get_context().get_version() >= &Version(Api::Gl, 3, 0) ||
                        !facade.get_context().get_extensions().gl_ext_transform_feedback)
                {
                    return Err(ProgramCreationError::TransformFeedbackNotSupported);
                }

                if uses_point_size && !(facade.get_context().get_version() >= &Version(Api::Gl, 3, 0)) {
                    return Err(ProgramCreationError::PointSizeNotSupported);
                }

                let _lock = COMPILER_GLOBAL_LOCK.lock();

                let shaders_store = {
                    let mut shaders_store = Vec::new();
                    for (src, ty) in shaders.into_iter() {
                        shaders_store.push(try!(build_shader(facade, ty, src)));
                    }
                    shaders_store
                };

                (try!(RawProgram::from_shaders(facade, &shaders_store, has_geometry_shader,
                                               has_tessellation_control_shader, has_tessellation_evaluation_shader,
                                               transform_feedback_varyings)),
                 outputs_srgb, uses_point_size)
            },

            ProgramCreationInput::Binary { data, outputs_srgb, uses_point_size } => {
                if uses_point_size && !(facade.get_context().get_version() >= &Version(Api::Gl, 3, 0)) {
                    return Err(ProgramCreationError::PointSizeNotSupported);
                }

                (try!(RawProgram::from_binary(facade, data)), outputs_srgb, uses_point_size)
            },
        };
        Ok(Program {
            raw: raw,
            outputs_srgb: outputs_srgb,
            uses_point_size: uses_point_size,
        })
    }

    /// Builds a new program from GLSL source code.
    ///
    /// A program is a group of shaders linked together.
    ///
    /// # Parameters
    ///
    /// - `vertex_shader`: Source code of the vertex shader.
    /// - `fragment_shader`: Source code of the fragment shader.
    /// - `geometry_shader`: Source code of the geometry shader.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # let display: glium::Display = unsafe { std::mem::uninitialized() };
    /// # let vertex_source = ""; let fragment_source = ""; let geometry_source = "";
    /// let program = glium::Program::from_source(&display, vertex_source, fragment_source,
    ///     Some(geometry_source));
    /// ```
    ///
    #[inline]
    pub fn from_source<'a, F>(facade: &F, vertex_shader: &'a str, fragment_shader: &'a str,
                              geometry_shader: Option<&'a str>)
                              -> Result<Program, ProgramCreationError> where F: Facade
    {
        Program::new(facade, ProgramCreationInput::SourceCode {
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            geometry_shader: geometry_shader,
            tessellation_control_shader: None,
            tessellation_evaluation_shader: None,
            transform_feedback_varyings: None,
            outputs_srgb: false,
            uses_point_size: false,
        })
    }

    /// Returns the program's compiled binary.
    ///
    /// You can store the result in a file, then reload it later. This avoids having to compile
    /// the source code every time.
    #[inline]
    pub fn get_binary(&self) -> Result<Binary, GetBinaryError> {
        self.raw.get_binary()
    }

    /// Returns the *location* of an output fragment, if it exists.
    ///
    /// The *location* is low-level information that is used internally by glium.
    /// You probably don't need to call this function.
    ///
    /// You can declare output fragments in your shaders by writing:
    ///
    /// ```notrust
    /// out vec4 foo;
    /// ```
    ///
    #[inline]
    pub fn get_frag_data_location(&self, name: &str) -> Option<u32> {
        self.raw.get_frag_data_location(name)
    }

    /// Returns informations about a uniform variable, if it exists.
    #[inline]
    pub fn get_uniform(&self, name: &str) -> Option<&Uniform> {
        self.raw.get_uniform(name)
    }

    /// Returns an iterator to the list of uniforms.
    ///
    /// ## Example
    ///
    /// ```no_run
    /// # let program: glium::Program = unsafe { std::mem::uninitialized() };
    /// for (name, uniform) in program.uniforms() {
    ///     println!("Name: {} - Type: {:?}", name, uniform.ty);
    /// }
    /// ```
    #[inline]
    pub fn uniforms(&self) -> hash_map::Iter<String, Uniform> {
        self.raw.uniforms()
    }

    /// Returns a list of uniform blocks.
    ///
    /// ## Example
    ///
    /// ```no_run
    /// # let program: glium::Program = unsafe { std::mem::uninitialized() };
    /// for (name, uniform) in program.get_uniform_blocks() {
    ///     println!("Name: {}", name);
    /// }
    /// ```
    #[inline]
    pub fn get_uniform_blocks(&self) -> &HashMap<String, UniformBlock> {
        self.raw.get_uniform_blocks()
    }

    /// Returns the list of transform feedback varyings.
    #[inline]
    pub fn get_transform_feedback_buffers(&self) -> &[TransformFeedbackBuffer] {
        self.raw.get_transform_feedback_buffers()
    }

    /// True if the transform feedback output of this program matches the specified `VertexFormat`
    /// and `stride`.
    ///
    /// The `stride` is the number of bytes between two vertices.
    #[inline]
    pub fn transform_feedback_matches(&self, format: &VertexFormat, stride: usize) -> bool {
        self.raw.transform_feedback_matches(format, stride)
    }

    /// Returns the type of geometry that transform feedback would generate, or `None` if it
    /// depends on the vertex/index data passed when drawing.
    ///
    /// This corresponds to `GL_GEOMETRY_OUTPUT_TYPE` or `GL_TESS_GEN_MODE`. If the program doesn't
    /// contain either a geometry shader or a tessellation evaluation shader, returns `None`.
    #[inline]
    pub fn get_output_primitives(&self) -> Option<OutputPrimitives> {
        self.raw.get_output_primitives()
    }

    /// Returns true if the program contains a tessellation stage.
    #[inline]
    pub fn has_tessellation_shaders(&self) -> bool {
        self.raw.has_tessellation_shaders()
    }

    /// Returns true if the program contains a tessellation control stage.
    #[inline]
    pub fn has_tessellation_control_shader(&self) -> bool {
        self.raw.has_tessellation_control_shader()
    }

    /// Returns true if the program contains a tessellation evaluation stage.
    #[inline]
    pub fn has_tessellation_evaluation_shader(&self) -> bool {
        self.raw.has_tessellation_evaluation_shader()
    }

    /// Returns true if the program contains a geometry shader.
    #[inline]
    pub fn has_geometry_shader(&self) -> bool {
        self.raw.has_geometry_shader()
    }

    /// Returns informations about an attribute, if it exists.
    #[inline]
    pub fn get_attribute(&self, name: &str) -> Option<&Attribute> {
        self.raw.get_attribute(name)
    }

    /// Returns an iterator to the list of attributes.
    ///
    /// ## Example
    ///
    /// ```no_run
    /// # let program: glium::Program = unsafe { std::mem::uninitialized() };
    /// for (name, attribute) in program.attributes() {
    ///     println!("Name: {} - Type: {:?}", name, attribute.ty);
    /// }
    /// ```
    #[inline]
    pub fn attributes(&self) -> hash_map::Iter<String, Attribute> {
        self.raw.attributes()
    }

    /// Returns true if the program has been configured to output sRGB instead of RGB.
    #[inline]
    pub fn has_srgb_output(&self) -> bool {
        self.outputs_srgb
    }

    /// Returns the list of shader storage blocks.
    ///
    /// ## Example
    ///
    /// ```no_run
    /// # let program: glium::Program = unsafe { std::mem::uninitialized() };
    /// for (name, uniform) in program.get_shader_storage_blocks() {
    ///     println!("Name: {}", name);
    /// }
    /// ```
    #[inline]
    pub fn get_shader_storage_blocks(&self) -> &HashMap<String, UniformBlock> {
        self.raw.get_shader_storage_blocks()
    }

    /// Returns the subroutine uniforms of this program.
    ///
    /// Since subroutine uniforms are unique per shader and *not* per program,
    /// the keys of the `HashMap` are in the format `("subroutine_name", ShaderStage)`.
    /// ## Example
    ///
    /// ```no_run
    /// # let program: glium::Program = unsafe { std::mem::uninitialized() };
    /// for (&(ref name, shader), uniform) in program.get_subroutine_uniforms() {
    ///     println!("Name: {}", name);
    /// }
    /// ```
    #[inline]
    pub fn get_subroutine_uniforms(&self) -> &HashMap<(String, ShaderStage), SubroutineUniform> {
        &self.raw.get_subroutine_data().subroutine_uniforms
    }

    /// Returns true if the program has been configured to use the `gl_PointSize` variable.
    ///
    /// If the program uses `gl_PointSize` without having been configured appropriately, then
    /// setting the value of `gl_PointSize` will have no effect.
    #[inline]
    pub fn uses_point_size(&self) -> bool {
      self.uses_point_size
    }
}

impl fmt::Debug for Program {
    #[inline]
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(formatter, "{:?}", self.raw)
    }
}

impl GlObject for Program {
    type Id = Handle;

    #[inline]
    fn get_id(&self) -> Handle {
        self.raw.get_id()
    }
}

impl ProgramExt for Program {
    fn use_program(&self, ctxt: &mut CommandContext) {
        // compatibility was checked at program creation
        if self.uses_point_size && !ctxt.state.enabled_program_point_size {
            unsafe { ctxt.gl.Enable(gl::PROGRAM_POINT_SIZE); }
        } else if !self.uses_point_size && ctxt.state.enabled_program_point_size {
            unsafe { ctxt.gl.Disable(gl::PROGRAM_POINT_SIZE); }
        }

        if ctxt.version >= &Version(Api::Gl, 3, 0) || ctxt.extensions.gl_arb_framebuffer_srgb ||
           ctxt.extensions.gl_ext_framebuffer_srgb || ctxt.extensions.gl_ext_srgb_write_control
        {
            if ctxt.state.enabled_framebuffer_srgb == self.outputs_srgb {
                ctxt.state.enabled_framebuffer_srgb = !self.outputs_srgb;

                if self.outputs_srgb {
                    unsafe { ctxt.gl.Disable(gl::FRAMEBUFFER_SRGB) };
                } else {
                    unsafe { ctxt.gl.Enable(gl::FRAMEBUFFER_SRGB) };
                }
            }
        }

        self.raw.use_program(ctxt)
    }

    #[inline]
    fn set_uniform(&self, ctxt: &mut CommandContext, uniform_location: gl::types::GLint,
                   value: &RawUniformValue)
    {
        self.raw.set_uniform(ctxt, uniform_location, value)
    }

    #[inline]
    fn set_uniform_block_binding(&self, ctxt: &mut CommandContext, block_location: gl::types::GLuint,
                                 value: gl::types::GLuint)
    {
        self.raw.set_uniform_block_binding(ctxt, block_location, value)
    }

    #[inline]
    fn set_shader_storage_block_binding(&self, ctxt: &mut CommandContext,
                                        block_location: gl::types::GLuint,
                                        value: gl::types::GLuint)
    {
        self.raw.set_shader_storage_block_binding(ctxt, block_location, value)
    }

    #[inline]
    fn set_subroutine_uniforms_for_stage(&self, ctxt: &mut CommandContext,
                                         stage: ShaderStage,
                                         indices: &[gl::types::GLuint])
    {
        self.raw.set_subroutine_uniforms_for_stage(ctxt, stage, indices);
    }

    #[inline]
    fn get_uniform(&self, name: &str) -> Option<&Uniform> {
        self.raw.get_uniform(name)
    }

    #[inline]
    fn get_uniform_blocks(&self) -> &HashMap<String, UniformBlock> {
        self.raw.get_uniform_blocks()
    }

    #[inline]
    fn get_shader_storage_blocks(&self) -> &HashMap<String, UniformBlock> {
        self.raw.get_shader_storage_blocks()
    }

    #[inline]
    fn get_subroutine_data(&self) -> &SubroutineData {
        self.raw.get_subroutine_data()
    }
}
<|endoftext|>


<commit_before>use super::bound_file::BoundFile;
use super::watcher::BindrsWatcher;
use regex::RegexSet;
use slog::Logger;
use std::io::{Read, Write, BufWriter, BufReader};
use std::marker::Send;
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::thread;
use time;

pub fn start<R: Read + Send + 'static, W: Write + Send + 'static>(log: &Logger,
                                                                  base_dir: String,
                                                                  ignores: RegexSet,
                                                                  reader: R,
                                                                  writer: W) {
    let lock: Arc<Mutex<Vec<(String, i64, i32)>>> = Arc::new(Mutex::new(vec![]));
    let lock_clone = lock.clone();

    let base_dir_clone = base_dir.clone();
    let log_clone = log.clone();
    let child_1 = thread::spawn(move || {
        run_local_watcher(&log_clone, base_dir_clone, ignores, writer, lock_clone);
    });

    let base_dir_clone = base_dir.clone();
    let log_clone = log.clone();
    let child_2 =
        thread::spawn(move || { run_remote_listener(&log_clone, base_dir_clone, reader, lock); });

    let _ = child_1.join().unwrap();
    let _ = child_2.join().unwrap();
    info!(log, "BindRS Stopping");
}

fn run_local_watcher<W: Write>(log: &Logger,
                               base_dir: String,
                               ingores: RegexSet,
                               writer: W,
                               lock: Arc<Mutex<Vec<(String, i64, i32)>>>) {
    let mut writer = BufWriter::new(writer);
    let mut watcher = BindrsWatcher::new(&base_dir, &ingores);
    watcher.watch();
    let rx = watcher.rx.unwrap();
    loop {
        let (a, p) = rx.recv().unwrap();
        let full_str_path = format!("{}{}", base_dir, p);
        let full_path = Path::new(&full_str_path);
        let file_exists = full_path.exists();

        if file_exists && full_path.is_dir() {
            continue;
        }

        let p_clone = p.clone();

        {
            let mut recent_files = lock.lock().unwrap();
            let (now_s, now_ns) = {
                let now_spec = time::now().to_timespec();
                (now_spec.sec, now_spec.nsec)
            };

            recent_files.retain(|&(_, ref time_s, ref time_ns)| if now_s - time_s > 1 {
                false
            } else if now_s - time_s == 1 {
                now_ns - time_ns + 1000000000 /* 1e9 */ < 500000000 // 5e8
            } else {
                now_ns - time_ns < 500000000 // 5e8
            });

            if recent_files.iter().map(|&(ref path, _, _)| path).any(|&ref path| &p_clone == path) {
                continue;
            }
        }

        let bf = BoundFile::build_from_path_action(&base_dir, p, a);
        let _guard = lock.lock().unwrap();
        debug!(log, "Sending {} to remote", bf.path);
        bf.to_writer(&mut writer);
    }
}

fn run_remote_listener<R: Read>(log: &Logger,
                                base_dir: String,
                                reader: R,
                                lock: Arc<Mutex<Vec<(String, i64, i32)>>>) {
    let mut reader = BufReader::new(reader);
    loop {
        let bf = BoundFile::from_reader(&mut reader);
        let mut recent_files = lock.lock().unwrap();
        debug!(log, "Receiving {} from remote", bf.path);
        bf.save_to_disk(&base_dir);

        let (now_s, now_ns) = {
            let now_spec = time::now().to_timespec();
            (now_spec.sec, now_spec.nsec)
        };
        recent_files.push((bf.path, now_s, now_ns));
    }
}
<commit_msg>Fix bad path generation, which caused a crash on send<commit_after>use super::bound_file::BoundFile;
use super::watcher::BindrsWatcher;
use regex::RegexSet;
use slog::Logger;
use std::io::{Read, Write, BufWriter, BufReader};
use std::marker::Send;
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::thread;
use time;

pub fn start<R: Read + Send + 'static, W: Write + Send + 'static>(log: &Logger,
                                                                  base_dir: String,
                                                                  ignores: RegexSet,
                                                                  reader: R,
                                                                  writer: W) {
    let lock: Arc<Mutex<Vec<(String, i64, i32)>>> = Arc::new(Mutex::new(vec![]));
    let lock_clone = lock.clone();

    let base_dir_clone = base_dir.clone();
    let log_clone = log.clone();
    let child_1 = thread::spawn(move || {
        run_local_watcher(&log_clone, base_dir_clone, ignores, writer, lock_clone);
    });

    let base_dir_clone = base_dir.clone();
    let log_clone = log.clone();
    let child_2 =
        thread::spawn(move || { run_remote_listener(&log_clone, base_dir_clone, reader, lock); });

    let _ = child_1.join().unwrap();
    let _ = child_2.join().unwrap();
    info!(log, "BindRS Stopping");
}

fn run_local_watcher<W: Write>(log: &Logger,
                               base_dir: String,
                               ingores: RegexSet,
                               writer: W,
                               lock: Arc<Mutex<Vec<(String, i64, i32)>>>) {
    let mut writer = BufWriter::new(writer);
    let mut watcher = BindrsWatcher::new(&base_dir, &ingores);
    watcher.watch();
    let rx = watcher.rx.unwrap();
    loop {
        let (a, p) = rx.recv().unwrap();
        let full_str_path = format!("{}/{}", base_dir, p);
        let full_path = Path::new(&full_str_path);
        let file_exists = full_path.exists();

        if file_exists && full_path.is_dir() {
            continue;
        }

        let p_clone = p.clone();

        {
            let mut recent_files = lock.lock().unwrap();
            let (now_s, now_ns) = {
                let now_spec = time::now().to_timespec();
                (now_spec.sec, now_spec.nsec)
            };

            recent_files.retain(|&(_, ref time_s, ref time_ns)| if now_s - time_s > 1 {
                false
            } else if now_s - time_s == 1 {
                now_ns - time_ns + 1000000000 /* 1e9 */ < 500000000 // 5e8
            } else {
                now_ns - time_ns < 500000000 // 5e8
            });

            if recent_files.iter().map(|&(ref path, _, _)| path).any(|&ref path| &p_clone == path) {
                continue;
            }
        }

        let bf = BoundFile::build_from_path_action(&base_dir, p, a);
        let _guard = lock.lock().unwrap();
        debug!(log, "Sending {} to remote", bf.path);
        bf.to_writer(&mut writer);
    }
}

fn run_remote_listener<R: Read>(log: &Logger,
                                base_dir: String,
                                reader: R,
                                lock: Arc<Mutex<Vec<(String, i64, i32)>>>) {
    let mut reader = BufReader::new(reader);
    loop {
        let bf = BoundFile::from_reader(&mut reader);
        let mut recent_files = lock.lock().unwrap();
        debug!(log, "Receiving {} from remote", bf.path);
        bf.save_to_disk(&base_dir);

        let (now_s, now_ns) = {
            let now_spec = time::now().to_timespec();
            (now_spec.sec, now_spec.nsec)
        };
        recent_files.push((bf.path, now_s, now_ns));
    }
}
<|endoftext|>


<commit_before>//! Connection pooling via r2d2.
//!
//! Note: This module requires enabling the `r2d2` feature

extern crate r2d2;

pub use self::r2d2::*;

/// A re-export of [`r2d2::Error`], which is only used by methods on [`r2d2::Pool`].
///
/// [`r2d2::Error`]: ../../r2d2/struct.Error.html
/// [`r2d2::Pool`]: ../../r2d2/struct.Pool.html
pub type PoolError = self::r2d2::Error;

use std::convert::Into;
use std::fmt;
use std::marker::PhantomData;

use crate::backend::UsesAnsiSavepointSyntax;
use crate::connection::{AnsiTransactionManager, SimpleConnection};
use crate::deserialize::{Queryable, QueryableByName};
use crate::prelude::*;
use crate::query_builder::{AsQuery, QueryFragment, QueryId};
use crate::sql_types::HasSqlType;

/// An r2d2 connection manager for use with Diesel.
///
/// See the [r2d2 documentation] for usage examples.
///
/// [r2d2 documentation]: ../../r2d2
#[derive(Debug, Clone)]
pub struct ConnectionManager<T> {
    database_url: String,
    _marker: PhantomData<T>,
}

unsafe impl<T: Send + 'static> Sync for ConnectionManager<T> {}

impl<T> ConnectionManager<T> {
    /// Returns a new connection manager,
    /// which establishes connections to the given database URL.
    pub fn new<S: Into<String>>(database_url: S) -> Self {
        ConnectionManager {
            database_url: database_url.into(),
            _marker: PhantomData,
        }
    }
}

/// The error used when managing connections with `r2d2`.
#[derive(Debug)]
pub enum Error {
    /// An error occurred establishing the connection
    ConnectionError(ConnectionError),

    /// An error occurred pinging the database
    QueryError(crate::result::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::ConnectionError(ref e) => e.fmt(f),
            Error::QueryError(ref e) => e.fmt(f),
        }
    }
}

impl ::std::error::Error for Error {}

/// A trait indicating a connection could be used inside a r2d2 pool
pub trait R2D2Connection: Connection {
    /// Check if a connection is still valid
    fn ping(&self) -> QueryResult<()>;
}

#[cfg(feature = "postgres")]
impl R2D2Connection for crate::pg::PgConnection {
    fn ping(&self) -> QueryResult<()> {
        self.execute("SELECT 1").map(|_| ())
    }
}

#[cfg(feature = "mysql")]
impl R2D2Connection for crate::mysql::MysqlConnection {
    fn ping(&self) -> QueryResult<()> {
        self.execute("SELECT 1").map(|_| ())
    }
}

#[cfg(feature = "sqlite")]
impl R2D2Connection for crate::sqlite::SqliteConnection {
    fn ping(&self) -> QueryResult<()> {
        self.execute("SELECT 1").map(|_| ())
    }
}

impl<T> ManageConnection for ConnectionManager<T>
where
    T: R2D2Connection + Send + 'static,
{
    type Connection = T;
    type Error = Error;

    fn connect(&self) -> Result<T, Error> {
        T::establish(&self.database_url).map_err(Error::ConnectionError)
    }

    fn is_valid(&self, conn: &mut T) -> Result<(), Error> {
        conn.ping().map_err(Error::QueryError)
    }

    fn has_broken(&self, _conn: &mut T) -> bool {
        false
    }
}

impl<M> SimpleConnection for PooledConnection<M>
where
    M: ManageConnection,
    M::Connection: R2D2Connection + Send + 'static,
{
    fn batch_execute(&self, query: &str) -> QueryResult<()> {
        (&**self).batch_execute(query)
    }
}

impl<M> Connection for PooledConnection<M>
where
    M: ManageConnection,
    M::Connection:
        Connection<TransactionManager = AnsiTransactionManager> + R2D2Connection + Send + 'static,
    <M::Connection as Connection>::Backend: UsesAnsiSavepointSyntax,
{
    type Backend = <M::Connection as Connection>::Backend;
    type TransactionManager = <M::Connection as Connection>::TransactionManager;

    fn establish(_: &str) -> ConnectionResult<Self> {
        Err(ConnectionError::BadConnection(String::from(
            "Cannot directly establish a pooled connection",
        )))
    }

    fn execute(&self, query: &str) -> QueryResult<usize> {
        (&**self).execute(query)
    }

    fn query_by_index<T, U>(&self, source: T) -> QueryResult<Vec<U>>
    where
        T: AsQuery,
        T::Query: QueryFragment<Self::Backend> + QueryId,
        Self::Backend: HasSqlType<T::SqlType>,
        U: Queryable<T::SqlType, Self::Backend>,
    {
        (&**self).query_by_index(source)
    }

    fn query_by_name<T, U>(&self, source: &T) -> QueryResult<Vec<U>>
    where
        T: QueryFragment<Self::Backend> + QueryId,
        U: QueryableByName<Self::Backend>,
    {
        (&**self).query_by_name(source)
    }

    fn execute_returning_count<T>(&self, source: &T) -> QueryResult<usize>
    where
        T: QueryFragment<Self::Backend> + QueryId,
    {
        (&**self).execute_returning_count(source)
    }

    fn transaction_manager(&self) -> &Self::TransactionManager {
        (&**self).transaction_manager()
    }
}

#[cfg(test)]
mod tests {
    use std::sync::mpsc;
    use std::sync::Arc;
    use std::thread;

    use crate::r2d2::*;
    use crate::test_helpers::*;

    #[test]
    fn establish_basic_connection() {
        let manager = ConnectionManager::<TestConnection>::new(database_url());
        let pool = Arc::new(Pool::builder().max_size(2).build(manager).unwrap());

        let (s1, r1) = mpsc::channel();
        let (s2, r2) = mpsc::channel();

        let pool1 = Arc::clone(&pool);
        let t1 = thread::spawn(move || {
            let conn = pool1.get().unwrap();
            s1.send(()).unwrap();
            r2.recv().unwrap();
            drop(conn);
        });

        let pool2 = Arc::clone(&pool);
        let t2 = thread::spawn(move || {
            let conn = pool2.get().unwrap();
            s2.send(()).unwrap();
            r1.recv().unwrap();
            drop(conn);
        });

        t1.join().unwrap();
        t2.join().unwrap();

        pool.get().unwrap();
    }

    #[test]
    fn is_valid() {
        let manager = ConnectionManager::<TestConnection>::new(database_url());
        let pool = Pool::builder()
            .max_size(1)
            .test_on_check_out(true)
            .build(manager)
            .unwrap();

        pool.get().unwrap();
    }

    #[test]
    fn pooled_connection_impls_connection() {
        use crate::select;
        use crate::sql_types::Text;

        let manager = ConnectionManager::<TestConnection>::new(database_url());
        let pool = Pool::builder()
            .max_size(1)
            .test_on_check_out(true)
            .build(manager)
            .unwrap();
        let conn = pool.get().unwrap();

        let query = select("foo".into_sql::<Text>());
        assert_eq!("foo", query.get_result::<String>(&conn).unwrap());
    }
}
<commit_msg>Make `r2d2::PooledConnection` more generic<commit_after>//! Connection pooling via r2d2.
//!
//! Note: This module requires enabling the `r2d2` feature

extern crate r2d2;

pub use self::r2d2::*;

/// A re-export of [`r2d2::Error`], which is only used by methods on [`r2d2::Pool`].
///
/// [`r2d2::Error`]: ../../r2d2/struct.Error.html
/// [`r2d2::Pool`]: ../../r2d2/struct.Pool.html
pub type PoolError = self::r2d2::Error;

use std::convert::Into;
use std::fmt;
use std::marker::PhantomData;

use crate::connection::{SimpleConnection, TransactionManager};
use crate::deserialize::{Queryable, QueryableByName};
use crate::prelude::*;
use crate::query_builder::{AsQuery, QueryFragment, QueryId};
use crate::sql_types::HasSqlType;

/// An r2d2 connection manager for use with Diesel.
///
/// See the [r2d2 documentation] for usage examples.
///
/// [r2d2 documentation]: ../../r2d2
#[derive(Debug, Clone)]
pub struct ConnectionManager<T> {
    database_url: String,
    _marker: PhantomData<T>,
}

unsafe impl<T: Send + 'static> Sync for ConnectionManager<T> {}

impl<T> ConnectionManager<T> {
    /// Returns a new connection manager,
    /// which establishes connections to the given database URL.
    pub fn new<S: Into<String>>(database_url: S) -> Self {
        ConnectionManager {
            database_url: database_url.into(),
            _marker: PhantomData,
        }
    }
}

/// The error used when managing connections with `r2d2`.
#[derive(Debug)]
pub enum Error {
    /// An error occurred establishing the connection
    ConnectionError(ConnectionError),

    /// An error occurred pinging the database
    QueryError(crate::result::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::ConnectionError(ref e) => e.fmt(f),
            Error::QueryError(ref e) => e.fmt(f),
        }
    }
}

impl ::std::error::Error for Error {}

/// A trait indicating a connection could be used inside a r2d2 pool
pub trait R2D2Connection: Connection {
    /// Check if a connection is still valid
    fn ping(&self) -> QueryResult<()>;
}

#[cfg(feature = "postgres")]
impl R2D2Connection for crate::pg::PgConnection {
    fn ping(&self) -> QueryResult<()> {
        self.execute("SELECT 1").map(|_| ())
    }
}

#[cfg(feature = "mysql")]
impl R2D2Connection for crate::mysql::MysqlConnection {
    fn ping(&self) -> QueryResult<()> {
        self.execute("SELECT 1").map(|_| ())
    }
}

#[cfg(feature = "sqlite")]
impl R2D2Connection for crate::sqlite::SqliteConnection {
    fn ping(&self) -> QueryResult<()> {
        self.execute("SELECT 1").map(|_| ())
    }
}

impl<T> ManageConnection for ConnectionManager<T>
where
    T: R2D2Connection + Send + 'static,
{
    type Connection = T;
    type Error = Error;

    fn connect(&self) -> Result<T, Error> {
        T::establish(&self.database_url).map_err(Error::ConnectionError)
    }

    fn is_valid(&self, conn: &mut T) -> Result<(), Error> {
        conn.ping().map_err(Error::QueryError)
    }

    fn has_broken(&self, _conn: &mut T) -> bool {
        false
    }
}

impl<M> SimpleConnection for PooledConnection<M>
where
    M: ManageConnection,
    M::Connection: R2D2Connection + Send + 'static,
{
    fn batch_execute(&self, query: &str) -> QueryResult<()> {
        (&**self).batch_execute(query)
    }
}

impl<M> Connection for PooledConnection<M>
where
    M: ManageConnection,
    M::Connection: Connection + R2D2Connection + Send + 'static,
{
    type Backend = <M::Connection as Connection>::Backend;
    type TransactionManager = PooledConnectionTransactionManager<M>;

    fn establish(_: &str) -> ConnectionResult<Self> {
        Err(ConnectionError::BadConnection(String::from(
            "Cannot directly establish a pooled connection",
        )))
    }

    fn execute(&self, query: &str) -> QueryResult<usize> {
        (&**self).execute(query)
    }

    fn query_by_index<T, U>(&self, source: T) -> QueryResult<Vec<U>>
    where
        T: AsQuery,
        T::Query: QueryFragment<Self::Backend> + QueryId,
        Self::Backend: HasSqlType<T::SqlType>,
        U: Queryable<T::SqlType, Self::Backend>,
    {
        (&**self).query_by_index(source)
    }

    fn query_by_name<T, U>(&self, source: &T) -> QueryResult<Vec<U>>
    where
        T: QueryFragment<Self::Backend> + QueryId,
        U: QueryableByName<Self::Backend>,
    {
        (&**self).query_by_name(source)
    }

    fn execute_returning_count<T>(&self, source: &T) -> QueryResult<usize>
    where
        T: QueryFragment<Self::Backend> + QueryId,
    {
        (&**self).execute_returning_count(source)
    }

    fn transaction_manager(&self) -> &Self::TransactionManager {
        // This is actually fine because we have an #[repr(transparent)]
        // on LoggingTransactionManager, which means the layout is the same
        // as the inner type
        // See the ref-cast crate for a longer version: https://github.com/dtolnay/ref-cast
        unsafe {
            &*((&**self).transaction_manager() as *const _ as *const Self::TransactionManager)
        }
    }
}

#[doc(hidden)]
#[repr(transparent)]
#[allow(missing_debug_implementations)]
pub struct PooledConnectionTransactionManager<M>
where
    M: ManageConnection,
    M::Connection: Connection,
{
    inner: <M::Connection as Connection>::TransactionManager,
}

impl<M> TransactionManager<PooledConnection<M>> for PooledConnectionTransactionManager<M>
where
    M: ManageConnection,
    PooledConnection<M>: Connection,
    M::Connection: Connection,
{
    fn begin_transaction(&self, conn: &PooledConnection<M>) -> QueryResult<()> {
        self.inner.begin_transaction(&**conn)
    }

    fn rollback_transaction(&self, conn: &PooledConnection<M>) -> QueryResult<()> {
        self.inner.rollback_transaction(&**conn)
    }

    fn commit_transaction(&self, conn: &PooledConnection<M>) -> QueryResult<()> {
        self.inner.commit_transaction(&**conn)
    }

    fn get_transaction_depth(&self) -> u32 {
        self.inner.get_transaction_depth()
    }
}

#[cfg(test)]
mod tests {
    use std::sync::mpsc;
    use std::sync::Arc;
    use std::thread;

    use crate::r2d2::*;
    use crate::test_helpers::*;

    #[test]
    fn establish_basic_connection() {
        let manager = ConnectionManager::<TestConnection>::new(database_url());
        let pool = Arc::new(Pool::builder().max_size(2).build(manager).unwrap());

        let (s1, r1) = mpsc::channel();
        let (s2, r2) = mpsc::channel();

        let pool1 = Arc::clone(&pool);
        let t1 = thread::spawn(move || {
            let conn = pool1.get().unwrap();
            s1.send(()).unwrap();
            r2.recv().unwrap();
            drop(conn);
        });

        let pool2 = Arc::clone(&pool);
        let t2 = thread::spawn(move || {
            let conn = pool2.get().unwrap();
            s2.send(()).unwrap();
            r1.recv().unwrap();
            drop(conn);
        });

        t1.join().unwrap();
        t2.join().unwrap();

        pool.get().unwrap();
    }

    #[test]
    fn is_valid() {
        let manager = ConnectionManager::<TestConnection>::new(database_url());
        let pool = Pool::builder()
            .max_size(1)
            .test_on_check_out(true)
            .build(manager)
            .unwrap();

        pool.get().unwrap();
    }

    #[test]
    fn pooled_connection_impls_connection() {
        use crate::select;
        use crate::sql_types::Text;

        let manager = ConnectionManager::<TestConnection>::new(database_url());
        let pool = Pool::builder()
            .max_size(1)
            .test_on_check_out(true)
            .build(manager)
            .unwrap();
        let conn = pool.get().unwrap();

        let query = select("foo".into_sql::<Text>());
        assert_eq!("foo", query.get_result::<String>(&conn).unwrap());
    }
}
<|endoftext|>


<commit_before>use {Event, Input, Motion};

/// Stores the touch state.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub enum Touch {
    /// The start of touch, for example
    /// a finger pressed down on a touch screen.
    Start,
    /// The move of touch, for example
    /// a finger moving while touching a touch screen.
    Move,
    /// The end of touch, for example
    /// taking a finger away from a touch screen.
    End,
    /// The cancel of touch, for example
    /// the window loses focus.
    Cancel,
}

/// Touch arguments
///
/// The `id` might be reused for different touches that do not overlap in time.
///
/// - Coordinates are normalized to support both touch screens and trackpads
/// - Supports both 2D and 3D touch
/// - The pressure direction vector should have maximum length 1
///
/// For 2D touch the pressure is pointed the z direction.
/// Use `.pressure()` to get the pressure magnitude.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, PartialOrd, Debug)]
pub struct TouchArgs {
    /// A unique identifier for touch device.
    pub device: i64,
    /// A unique identifier for touch event.
    pub id: i64,
    /// The x coordinate of the touch position, normalized 0..1.
    pub x: f64,
    /// The y coordinate of the touch position, normalized 0..1.
    pub y: f64,
    /// The z coordinate of the touch position, normalized 0..1.
    pub z: f64,
    /// The x coordinate of the touch pressure direction.
    pub px: f64,
    /// The y coordinate of the touch pressure direction.
    pub py: f64,
    /// The z coordinate of the touch pressure direction.
    pub pz: f64,
    /// Whether the touch is in 3D.
    pub is_3d: bool,
    /// The touch state.
    pub touch: Touch,
}

impl TouchArgs {
    /// Creates arguments for 2D touch.
    pub fn new(device: i64, id: i64, pos: [f64; 2], pressure: f64, touch: Touch) -> TouchArgs {
        TouchArgs {
            device: device,
            id: id,
            x: pos[0],
            y: pos[1],
            z: 0.0,
            is_3d: false,
            px: 0.0,
            py: 0.0,
            pz: pressure,
            touch: touch,
        }
    }

    /// Creates arguments for 3D touch.
    ///
    /// The pressure direction vector should have maximum length 1.
    pub fn new_3d(device: i64,
                  id: i64,
                  pos: [f64; 3],
                  pressure: [f64; 3],
                  touch: Touch)
                  -> TouchArgs {
        TouchArgs {
            device: device,
            id: id,
            x: pos[0],
            y: pos[1],
            z: pos[2],
            is_3d: true,
            px: pressure[0],
            py: pressure[1],
            pz: pressure[2],
            touch: touch,
        }
    }

    /// The position of the touch in 2D.
    pub fn position(&self) -> [f64; 2] {
        [self.x, self.y]
    }

    /// The position of the touch in 3D.
    pub fn position_3d(&self) -> [f64; 3] {
        [self.x, self.y, self.z]
    }

    /// The pressure magnitude, normalized 0..1.
    pub fn pressure(&self) -> f64 {
        (self.px * self.px + self.py * self.py + self.pz * self.pz).sqrt()
    }

    /// The pressure vector in 3D.
    pub fn pressure_3d(&self) -> [f64; 3] {
        [self.px, self.py, self.pz]
    }
}

/// When a touch is started, moved, ended or cancelled.
pub trait TouchEvent: Sized {
    /// Creates a touch event.
    ///
    /// Preserves time stamp from original input event, if any.
    fn from_touch_args(args: &TouchArgs, old_event: &Self) -> Option<Self>;
    /// Calls closure if this is a touch event.
    fn touch<U, F>(&self, f: F) -> Option<U> where F: FnMut(&TouchArgs) -> U;
    /// Returns touch arguments.
    fn touch_args(&self) -> Option<TouchArgs> {
        self.touch(|args| args.clone())
    }
}

impl TouchEvent for Event {
    fn from_touch_args(args: &TouchArgs, old_event: &Self) -> Option<Self> {
        let timestamp = if let Event::Input(_, x) = old_event {*x} else {None};
        Some(Event::Input(Input::Move(Motion::Touch(*args)), timestamp))
    }

    fn touch<U, F>(&self, mut f: F) -> Option<U>
        where F: FnMut(&TouchArgs) -> U
    {
        match *self {
            Event::Input(Input::Move(Motion::Touch(ref args)), _) => Some(f(args)),
            _ => None,
        }
    }
}

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

    #[test]
    fn test_input_touch() {
        let pos = [0.0; 2];
        let e: Event = TouchArgs::new(0, 0, pos, 1.0, Touch::Start).into();
        let a: Option<Event> =
            TouchEvent::from_touch_args(&TouchArgs::new(0, 0, pos, 1.0, Touch::Start), &e);
        let b: Option<Event> = a.clone()
            .unwrap()
            .touch(|t| {
                TouchEvent::from_touch_args(&TouchArgs::new(t.device,
                                                            t.id,
                                                            t.position(),
                                                            t.pressure(),
                                                            Touch::Start),
                                            a.as_ref().unwrap())
            })
            .unwrap();
        assert_eq!(a, b);
    }

    #[test]
    fn test_input_touch_3d() {
        use super::super::Event;

        let pos = [0.0; 3];
        let pressure = [0.0, 0.0, 1.0];
        let e: Event = TouchArgs::new_3d(0, 0, pos, pressure, Touch::Start).into();
        let a: Option<Event> =
            TouchEvent::from_touch_args(&TouchArgs::new_3d(0, 0, pos, pressure, Touch::Start), &e);
        let b: Option<Event> = a.clone()
            .unwrap()
            .touch(|t| {
                TouchEvent::from_touch_args(&TouchArgs::new_3d(t.device,
                                                               t.id,
                                                               t.position_3d(),
                                                               t.pressure_3d(),
                                                               Touch::Start),
                                            a.as_ref().unwrap())
            })
            .unwrap();
        assert_eq!(a, b);
    }
}
<commit_msg>Use `[f64; 3]` in `TouchArgs`<commit_after>use {Event, Input, Motion};

/// Stores the touch state.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub enum Touch {
    /// The start of touch, for example
    /// a finger pressed down on a touch screen.
    Start,
    /// The move of touch, for example
    /// a finger moving while touching a touch screen.
    Move,
    /// The end of touch, for example
    /// taking a finger away from a touch screen.
    End,
    /// The cancel of touch, for example
    /// the window loses focus.
    Cancel,
}

/// Touch arguments
///
/// The `id` might be reused for different touches that do not overlap in time.
///
/// - Coordinates are normalized to support both touch screens and trackpads
/// - Supports both 2D and 3D touch
/// - The pressure direction vector should have maximum length 1
///
/// For 2D touch the pressure is pointed in the z direction.
/// Use `.pressure()` to get the pressure magnitude.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, PartialOrd, Debug)]
pub struct TouchArgs {
    /// A unique identifier for touch device.
    pub device: i64,
    /// A unique identifier for touch event.
    pub id: i64,
    /// The touch position, normalized 0..1.
    pub position_3d: [f64; 3],
    /// The touch pressure vector, normalized 0..1.
    pub pressure_3d: [f64; 3],
    /// Whether the touch is in 3D.
    pub is_3d: bool,
    /// The touch state.
    pub touch: Touch,
}

impl TouchArgs {
    /// Creates arguments for 2D touch.
    pub fn new(device: i64, id: i64, position: [f64; 2], pressure: f64, touch: Touch) -> TouchArgs {
        TouchArgs {
            device: device,
            id: id,
            position_3d: [position[0], position[1], 0.0],
            pressure_3d: [0.0, 0.0, pressure],
            is_3d: false,
            touch: touch,
        }
    }

    /// Creates arguments for 3D touch.
    ///
    /// The pressure direction vector should have maximum length 1.
    pub fn new_3d(device: i64,
                  id: i64,
                  position_3d: [f64; 3],
                  pressure_3d: [f64; 3],
                  touch: Touch)
                  -> TouchArgs {
        TouchArgs {
            device: device,
            id: id,
            position_3d,
            pressure_3d,
            is_3d: true,
            touch: touch,
        }
    }

    /// The position of the touch in 2D.
    pub fn position(&self) -> [f64; 2] {
        [self.position_3d[0], self.position_3d[1]]
    }

    /// The position of the touch in 3D.
    pub fn position_3d(&self) -> [f64; 3] {self.position_3d}

    /// The pressure magnitude, normalized 0..1.
    pub fn pressure(&self) -> f64 {
        let px = self.pressure_3d[0];
        let py = self.pressure_3d[1];
        let pz = self.pressure_3d[2];
        (px * px + py * py + pz * pz).sqrt()
    }

    /// The pressure vector in 3D.
    pub fn pressure_3d(&self) -> [f64; 3] {self.pressure_3d}
}

/// When a touch is started, moved, ended or cancelled.
pub trait TouchEvent: Sized {
    /// Creates a touch event.
    ///
    /// Preserves time stamp from original input event, if any.
    fn from_touch_args(args: &TouchArgs, old_event: &Self) -> Option<Self>;
    /// Calls closure if this is a touch event.
    fn touch<U, F>(&self, f: F) -> Option<U> where F: FnMut(&TouchArgs) -> U;
    /// Returns touch arguments.
    fn touch_args(&self) -> Option<TouchArgs> {
        self.touch(|args| args.clone())
    }
}

impl TouchEvent for Event {
    fn from_touch_args(args: &TouchArgs, old_event: &Self) -> Option<Self> {
        let timestamp = if let Event::Input(_, x) = old_event {*x} else {None};
        Some(Event::Input(Input::Move(Motion::Touch(*args)), timestamp))
    }

    fn touch<U, F>(&self, mut f: F) -> Option<U>
        where F: FnMut(&TouchArgs) -> U
    {
        match *self {
            Event::Input(Input::Move(Motion::Touch(ref args)), _) => Some(f(args)),
            _ => None,
        }
    }
}

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

    #[test]
    fn test_input_touch() {
        let pos = [0.0; 2];
        let e: Event = TouchArgs::new(0, 0, pos, 1.0, Touch::Start).into();
        let a: Option<Event> =
            TouchEvent::from_touch_args(&TouchArgs::new(0, 0, pos, 1.0, Touch::Start), &e);
        let b: Option<Event> = a.clone()
            .unwrap()
            .touch(|t| {
                TouchEvent::from_touch_args(&TouchArgs::new(t.device,
                                                            t.id,
                                                            t.position(),
                                                            t.pressure(),
                                                            Touch::Start),
                                            a.as_ref().unwrap())
            })
            .unwrap();
        assert_eq!(a, b);
    }

    #[test]
    fn test_input_touch_3d() {
        use super::super::Event;

        let pos = [0.0; 3];
        let pressure = [0.0, 0.0, 1.0];
        let e: Event = TouchArgs::new_3d(0, 0, pos, pressure, Touch::Start).into();
        let a: Option<Event> =
            TouchEvent::from_touch_args(&TouchArgs::new_3d(0, 0, pos, pressure, Touch::Start), &e);
        let b: Option<Event> = a.clone()
            .unwrap()
            .touch(|t| {
                TouchEvent::from_touch_args(&TouchArgs::new_3d(t.device,
                                                               t.id,
                                                               t.position_3d(),
                                                               t.pressure_3d(),
                                                               Touch::Start),
                                            a.as_ref().unwrap())
            })
            .unwrap();
        assert_eq!(a, b);
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult = Result<(), StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
}

impl StorageBackend {

    pub fn new(basepath: String) -> StorageBackend {
        StorageBackend {
            basepath: basepath,
        }
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self) -> Option<Vec<FileID>> {
        debug!("Getting files from {}", self.basepath);
        let list = glob(&self.basepath[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    pub fn iter_ids(&self, m: &Module) -> Option<IntoIter<FileID>>
    {
        glob(&self.prefix_of_files_for_module(m)[..]).and_then(|globlist| {
            let v = globlist.filter_map(Result::ok)
                            .map(|pbuf| from_pathbuf(&pbuf))
                            .collect::<Vec<FileID>>()
                            .into_iter();
            Ok(v)
        }).ok()
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Option<IntoIter<File<'a>>>
        where HP: FileHeaderParser
    {
        self.iter_ids(m).and_then(|ids| {
            Some(ids.filter_map(|id| self.get_file_by_id(m, &id, p))
                    .collect::<Vec<File>>()
                    .into_iter())
        })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = write_with_parser(&f, p);
        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|mut file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write_all()",
                            "Could not write out File contents",
                            None
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::create()",
                "Creating file on disk failed",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, m: &'a Module, id: &FileID, p: &Parser<HP>) -> Option<File<'a>>
        where HP: FileHeaderParser
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(m, id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(id, h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::build(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.owner(), f.id())
    }

    fn build_filepath_with_id(&self, owner: &Module, id: FileID) -> String {
        debug!("Building filepath with id");
        debug!("  basepath: '{}'", self.basepath);
        debug!(" storepath: '{}'", self.storepath);
        debug!("  id      : '{}'", id);
        self.prefix_of_files_for_module(owner) + "-" + &id[..] + ".imag"
    }

    fn prefix_of_files_for_module(&self, m: &Module) -> String {
        self.storepath.clone() + m.name()
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }

    fn build(action: &'static str,
             desc:   &'static str,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            dataDump:       data,
            caused_by:      None,
        }
    }

}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::build(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}
<commit_msg>BackendOperationResult: Add optional type parameter<commit_after>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult<T = ()> = Result<T, StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
}

impl StorageBackend {

    pub fn new(basepath: String) -> StorageBackend {
        StorageBackend {
            basepath: basepath,
        }
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self) -> Option<Vec<FileID>> {
        debug!("Getting files from {}", self.basepath);
        let list = glob(&self.basepath[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    pub fn iter_ids(&self, m: &Module) -> Option<IntoIter<FileID>>
    {
        glob(&self.prefix_of_files_for_module(m)[..]).and_then(|globlist| {
            let v = globlist.filter_map(Result::ok)
                            .map(|pbuf| from_pathbuf(&pbuf))
                            .collect::<Vec<FileID>>()
                            .into_iter();
            Ok(v)
        }).ok()
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Option<IntoIter<File<'a>>>
        where HP: FileHeaderParser
    {
        self.iter_ids(m).and_then(|ids| {
            Some(ids.filter_map(|id| self.get_file_by_id(m, &id, p))
                    .collect::<Vec<File>>()
                    .into_iter())
        })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = write_with_parser(&f, p);
        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|mut file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write_all()",
                            "Could not write out File contents",
                            None
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::create()",
                "Creating file on disk failed",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, m: &'a Module, id: &FileID, p: &Parser<HP>) -> Option<File<'a>>
        where HP: FileHeaderParser
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(m, id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(id, h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::build(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.owner(), f.id())
    }

    fn build_filepath_with_id(&self, owner: &Module, id: FileID) -> String {
        debug!("Building filepath with id");
        debug!("  basepath: '{}'", self.basepath);
        debug!(" storepath: '{}'", self.storepath);
        debug!("  id      : '{}'", id);
        self.prefix_of_files_for_module(owner) + "-" + &id[..] + ".imag"
    }

    fn prefix_of_files_for_module(&self, m: &Module) -> String {
        self.storepath.clone() + m.name()
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }

    fn build(action: &'static str,
             desc:   &'static str,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            dataDump:       data,
            caused_by:      None,
        }
    }

}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::build(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}
<|endoftext|>