<commit_before>use RealNumber;
use multicore_support::Complexity;
use simd_extensions::Simd;
use super::{
    TransRes, ErrorReason,
    Owner, ToRealResult,
    Buffer,
    DspVec, ToSliceMut,
    Domain, ComplexNumberSpace, RededicateForceOps
};

/// Defines all operations which are valid on complex data and result in real data.
/// # Failures
/// All operations in this trait fail with `VectorMustBeComplex` if the vector isn't in the complex number space.
pub trait ComplexToRealTransformsOps<S, T, B> : ToRealResult
    where S: ToSliceMut<T>,
          T: RealNumber,
          B: Buffer<S, T> {

    /// Gets the absolute value, magnitude or norm of all vector elements.
    /// # Example
    ///
    /// ```
    /// # extern crate num;
    /// # extern crate basic_dsp_vector;
    /// use basic_dsp_vector::vector_types2::*;
    /// # fn main() {
    /// let vector = vec!(3.0, -4.0, -3.0, 4.0).to_complex_time_vec();
    /// let mut buffer = SingleBuffer::new();
    /// let result = vector.magnitude(&mut buffer).expect("Ignoring error handling in examples");
    /// assert_eq!([5.0, 5.0], result[0..]);
    /// # }
    /// ```
    fn magnitude(self, buffer: &mut B) -> TransRes<Self::RealResult>;

    /// Gets the square root of the absolute value of all vector elements.
    /// # Example
    ///
    /// ```
    /// # extern crate num;
    /// # extern crate basic_dsp_vector;
    /// use basic_dsp_vector::vector_types2::*;
    /// # fn main() {
    /// let vector = vec!(3.0, -4.0, -3.0, 4.0).to_complex_time_vec();
    /// let mut buffer = SingleBuffer::new();
    /// let result = vector.magnitude_squared(&mut buffer).expect("Ignoring error handling in examples");
    /// assert_eq!([25.0, 25.0], result[0..]);
    /// # }
    /// ```
    fn magnitude_squared(self, buffer: &mut B) -> TransRes<Self::RealResult>;

    /// Gets all real elements.
    /// # Example
    ///
    /// ```
    /// # extern crate num;
    /// # extern crate basic_dsp_vector;
    /// use basic_dsp_vector::vector_types2::*;
    /// # fn main() {
    /// let vector = vec!(1.0, 2.0, 3.0, 4.0).to_complex_time_vec();
    /// let mut buffer = SingleBuffer::new();
    /// let result = vector.to_real(&mut buffer).expect("Ignoring error handling in examples");
    /// assert_eq!([1.0, 3.0], result[0..]);
    /// # }
    /// ```
    fn to_real(self, buffer: &mut B) -> TransRes<Self::RealResult>;

    /// Gets all imag elements.
    /// # Example
    ///
    /// ```
    /// # extern crate num;
    /// # extern crate basic_dsp_vector;
    /// use basic_dsp_vector::vector_types2::*;
    /// # fn main() {
    /// let vector = vec!(1.0, 2.0, 3.0, 4.0).to_complex_time_vec();
    /// let mut buffer = SingleBuffer::new();
    /// let result = vector.to_imag(&mut buffer).expect("Ignoring error handling in examples");
    /// assert_eq!([2.0, 4.0], result[0..]);
    /// # }
    /// ```
    fn to_imag(self, buffer: &mut B) -> TransRes<Self::RealResult>;

    /// Gets the phase of all elements in [rad].
    /// # Example
    ///
    /// ```
    /// # extern crate num;
    /// # extern crate basic_dsp_vector;
    /// use basic_dsp_vector::vector_types2::*;
    /// # fn main() {
    /// let data: Vec<f32> = vec!(1.0, 0.0, 0.0, 4.0, -2.0, 0.0, 0.0, -3.0, 1.0, 1.0);
    /// let vector = data.to_complex_time_vec();
    /// let mut buffer = SingleBuffer::new();
    /// let result = vector.phase(&mut buffer).expect("Ignoring error handling in examples");
    /// assert_eq!([0.0, 1.5707964, 3.1415927, -1.5707964, 0.7853982], result[0..]);
    /// # }
    /// ```
    fn phase(self, buffer: &mut B) -> TransRes<Self::RealResult>;
}

macro_rules! assert_complex {
    ($self_: ident) => {
        if !$self_.is_complex() {
            $self_.number_space.to_real();
            $self_.valid_len = 0;
            return Err((ErrorReason::InputMustBeComplex, Self::RealResult::rededicate_from_force($self_)));
        }
    }
}

impl<S, T, N, D, B> ComplexToRealTransformsOps<S, T, B> for DspVec<S, T, N, D>
    where DspVec<S, T, N, D>: ToRealResult,
          <DspVec<S, T, N, D> as ToRealResult>::RealResult: RededicateForceOps<DspVec<S, T, N, D>>,
          S: ToSliceMut<T> + Owner,
          T: RealNumber,
          N: ComplexNumberSpace,
          D: Domain,
          B: Buffer<S, T> {
    fn magnitude(mut self, buffer: &mut B) -> TransRes<Self::RealResult> {
        assert_complex!(self);
        self.simd_complex_to_real_operation(buffer, |x,_arg| x.complex_abs(), |x,_arg| x.norm(), (), Complexity::Small);
        self.number_space.to_real();
        Ok(Self::RealResult::rededicate_from_force(self))
    }

    fn magnitude_squared(mut self, buffer: &mut B) -> TransRes<Self::RealResult> {
        assert_complex!(self);
        self.simd_complex_to_real_operation(buffer, |x,_arg| x.complex_abs_squared(), |x,_arg| x.re * x.re + x.im * x.im, (), Complexity::Small);
        self.number_space.to_real();
        Ok(Self::RealResult::rededicate_from_force(self))
    }

    fn to_real(mut self, buffer: &mut B) -> TransRes<Self::RealResult> {
        assert_complex!(self);
        self.pure_complex_to_real_operation(buffer, |x,_arg|x.re, (), Complexity::Small);
        self.number_space.to_real();
        Ok(Self::RealResult::rededicate_from_force(self))
    }

    fn to_imag(mut self, buffer: &mut B) -> TransRes<Self::RealResult> {
        assert_complex!(self);
        self.pure_complex_to_real_operation(buffer, |x,_arg|x.im, (), Complexity::Small);
        self.number_space.to_real();
        Ok(Self::RealResult::rededicate_from_force(self))
    }

    fn phase(mut self, buffer: &mut B) -> TransRes<Self::RealResult> {
        assert_complex!(self);
        self.pure_complex_to_real_operation(buffer, |x,_arg|x.arg(), (), Complexity::Small);
        self.number_space.to_real();
        Ok(Self::RealResult::rededicate_from_force(self))
    }
}
<commit_msg>Moved buffer type param to method level<commit_after>use RealNumber;
use multicore_support::Complexity;
use simd_extensions::Simd;
use super::{
    TransRes, ErrorReason,
    Owner, ToRealResult,
    Buffer,
    DspVec, ToSliceMut,
    Domain, ComplexNumberSpace, RededicateForceOps
};

/// Defines all operations which are valid on complex data and result in real data.
/// # Failures
/// All operations in this trait fail with `VectorMustBeComplex` if the vector isn't in the complex number space.
pub trait ComplexToRealTransformsOps<S, T> : ToRealResult
    where S: ToSliceMut<T>,
          T: RealNumber {

    /// Gets the absolute value, magnitude or norm of all vector elements.
    /// # Example
    ///
    /// ```
    /// # extern crate num;
    /// # extern crate basic_dsp_vector;
    /// use basic_dsp_vector::vector_types2::*;
    /// # fn main() {
    /// let vector = vec!(3.0, -4.0, -3.0, 4.0).to_complex_time_vec();
    /// let mut buffer = SingleBuffer::new();
    /// let result = vector.magnitude(&mut buffer).expect("Ignoring error handling in examples");
    /// assert_eq!([5.0, 5.0], result[0..]);
    /// # }
    /// ```
    fn magnitude<B>(self, buffer: &mut B) -> TransRes<Self::RealResult>
        where B: Buffer<S, T>;

    /// Gets the square root of the absolute value of all vector elements.
    /// # Example
    ///
    /// ```
    /// # extern crate num;
    /// # extern crate basic_dsp_vector;
    /// use basic_dsp_vector::vector_types2::*;
    /// # fn main() {
    /// let vector = vec!(3.0, -4.0, -3.0, 4.0).to_complex_time_vec();
    /// let mut buffer = SingleBuffer::new();
    /// let result = vector.magnitude_squared(&mut buffer).expect("Ignoring error handling in examples");
    /// assert_eq!([25.0, 25.0], result[0..]);
    /// # }
    /// ```
    fn magnitude_squared<B>(self, buffer: &mut B) -> TransRes<Self::RealResult>
        where B: Buffer<S, T>;

    /// Gets all real elements.
    /// # Example
    ///
    /// ```
    /// # extern crate num;
    /// # extern crate basic_dsp_vector;
    /// use basic_dsp_vector::vector_types2::*;
    /// # fn main() {
    /// let vector = vec!(1.0, 2.0, 3.0, 4.0).to_complex_time_vec();
    /// let mut buffer = SingleBuffer::new();
    /// let result = vector.to_real(&mut buffer).expect("Ignoring error handling in examples");
    /// assert_eq!([1.0, 3.0], result[0..]);
    /// # }
    /// ```
    fn to_real<B>(self, buffer: &mut B) -> TransRes<Self::RealResult>
        where B: Buffer<S, T>;

    /// Gets all imag elements.
    /// # Example
    ///
    /// ```
    /// # extern crate num;
    /// # extern crate basic_dsp_vector;
    /// use basic_dsp_vector::vector_types2::*;
    /// # fn main() {
    /// let vector = vec!(1.0, 2.0, 3.0, 4.0).to_complex_time_vec();
    /// let mut buffer = SingleBuffer::new();
    /// let result = vector.to_imag(&mut buffer).expect("Ignoring error handling in examples");
    /// assert_eq!([2.0, 4.0], result[0..]);
    /// # }
    /// ```
    fn to_imag<B>(self, buffer: &mut B) -> TransRes<Self::RealResult>
        where B: Buffer<S, T>;

    /// Gets the phase of all elements in [rad].
    /// # Example
    ///
    /// ```
    /// # extern crate num;
    /// # extern crate basic_dsp_vector;
    /// use basic_dsp_vector::vector_types2::*;
    /// # fn main() {
    /// let data: Vec<f32> = vec!(1.0, 0.0, 0.0, 4.0, -2.0, 0.0, 0.0, -3.0, 1.0, 1.0);
    /// let vector = data.to_complex_time_vec();
    /// let mut buffer = SingleBuffer::new();
    /// let result = vector.phase(&mut buffer).expect("Ignoring error handling in examples");
    /// assert_eq!([0.0, 1.5707964, 3.1415927, -1.5707964, 0.7853982], result[0..]);
    /// # }
    /// ```
    fn phase<B>(self, buffer: &mut B) -> TransRes<Self::RealResult>
        where B: Buffer<S, T>;
}

macro_rules! assert_complex {
    ($self_: ident) => {
        if !$self_.is_complex() {
            $self_.number_space.to_real();
            $self_.valid_len = 0;
            return Err((ErrorReason::InputMustBeComplex, Self::RealResult::rededicate_from_force($self_)));
        }
    }
}

impl<S, T, N, D> ComplexToRealTransformsOps<S, T> for DspVec<S, T, N, D>
    where DspVec<S, T, N, D>: ToRealResult,
          <DspVec<S, T, N, D> as ToRealResult>::RealResult: RededicateForceOps<DspVec<S, T, N, D>>,
          S: ToSliceMut<T> + Owner,
          T: RealNumber,
          N: ComplexNumberSpace,
          D: Domain {
    fn magnitude<B>(mut self, buffer: &mut B) -> TransRes<Self::RealResult>
        where B: Buffer<S, T> {
        assert_complex!(self);
        self.simd_complex_to_real_operation(buffer, |x,_arg| x.complex_abs(), |x,_arg| x.norm(), (), Complexity::Small);
        self.number_space.to_real();
        Ok(Self::RealResult::rededicate_from_force(self))
    }

    fn magnitude_squared<B>(mut self, buffer: &mut B) -> TransRes<Self::RealResult>
        where B: Buffer<S, T> {
        assert_complex!(self);
        self.simd_complex_to_real_operation(buffer, |x,_arg| x.complex_abs_squared(), |x,_arg| x.re * x.re + x.im * x.im, (), Complexity::Small);
        self.number_space.to_real();
        Ok(Self::RealResult::rededicate_from_force(self))
    }

    fn to_real<B>(mut self, buffer: &mut B) -> TransRes<Self::RealResult>
        where B: Buffer<S, T> {
        assert_complex!(self);
        self.pure_complex_to_real_operation(buffer, |x,_arg|x.re, (), Complexity::Small);
        self.number_space.to_real();
        Ok(Self::RealResult::rededicate_from_force(self))
    }

    fn to_imag<B>(mut self, buffer: &mut B) -> TransRes<Self::RealResult>
        where B: Buffer<S, T> {
        assert_complex!(self);
        self.pure_complex_to_real_operation(buffer, |x,_arg|x.im, (), Complexity::Small);
        self.number_space.to_real();
        Ok(Self::RealResult::rededicate_from_force(self))
    }

    fn phase<B>(mut self, buffer: &mut B) -> TransRes<Self::RealResult>
        where B: Buffer<S, T> {
        assert_complex!(self);
        self.pure_complex_to_real_operation(buffer, |x,_arg|x.arg(), (), Complexity::Small);
        self.number_space.to_real();
        Ok(Self::RealResult::rededicate_from_force(self))
    }
}
<|endoftext|>


<commit_before>use master_smasher::drawable::{Asset, Drawable};
use master_smasher::shape::{Circle, Intersect};
use super::world_assets::WorldAssets;
use super::collidable::Collidable;
use super::level_data::{PlanetData, PlanetKind};

use glm::{self, GenNum};
use glm::ext::normalize_to;
use num_traits::Zero;

use std::cmp;
use std::time::Duration;

struct Ring {
    radius: f64,
    strength: f64,
    asset: Asset,
    zoom: f64,
}

impl Ring {
    pub fn new(radius: f64, strength: f64, asset: Asset) -> Self {
        Ring {
            radius: radius,
            strength: strength,
            asset: asset.clone(),
            zoom: 1.,
        }
    }

    pub fn animate(&mut self, delta: Duration) {
        let moving_radius = self.asset.dims().x as f64 * self.zoom / 2.;
        let pull = glm::length(self.pull_vector(glm::dvec2(moving_radius, 0.), 0.));
        let zoom = 1. / 2_f64.powf(pull / 500.);
        self.zoom *= zoom;
    }

    pub fn drawables(&self) -> Vec<Drawable> {
        let mut moving = self.asset.clone();
        moving.zoom(glm::DVec2::from_s(self.zoom));
        vec![Drawable::Asset(self.asset), Drawable::Asset(moving)]
    }

    pub fn pull_vector(&self, dist: glm::DVec2, radius: f64) -> glm::DVec2 {
        let len = glm::length(dist);
        if len > (self.radius + radius) {
            glm::DVec2::zero()
        } else {
            let force = self.strength / (len.powf(0.8));
            normalize_to(dist, force)
        }
    }
}

pub struct Planet {
    body: Circle,
    asset: Asset,
    ring: Option<Ring>,
}

impl Planet {
    pub fn new(data: &PlanetData, textures: &WorldAssets) -> Self {
        let (asset, ring) = Self::load_assets(data, textures);
        let dims = asset.dims();
        let radius = cmp::min(dims.x, dims.y) as f64 / 2.;
        let center = glm::dvec2(data.x as f64, data.y as f64);
        let body = Circle {
            center: center,
            radius: radius,
        };

        Planet {
            body: body,
            asset: asset,
            ring: ring,
        }
    }

    pub fn animate(&mut self, delta: Duration) {
        if let Some(ref mut r) = self.ring {
            if r.asset.dims().x as f64 * r.zoom / 2. < self.body.radius {
                r.zoom = 1.;
            }
            r.animate(delta)
        }
    }

    pub fn pull_vector(&self, point: glm::DVec2, radius: f64) -> glm::DVec2 {
        self.ring.as_ref().map_or(glm::DVec2::zero(),
                                  |r| r.pull_vector(self.body.center - point, radius))
    }

    pub fn drawables(&self) -> Vec<Drawable> {
        let mut drawables = self.ring.as_ref().map_or(vec![], |r| r.drawables());
        drawables.push(Drawable::Asset(self.asset));
        drawables
    }

    fn load_assets(data: &PlanetData, textures: &WorldAssets) -> (Asset, Option<Ring>) {
        let center = glm::ivec2(data.x, data.y);
        let (planet, ring) = match data.kind {
            PlanetKind::RED { ring, strength } => {
                (textures.red_planet, Some((textures.red_ring, ring, strength)))
            }
            PlanetKind::BLUE { ring, strength } => {
                (textures.blue_planet, Some((textures.blue_ring, ring, strength)))
            }
            PlanetKind::WHITE { ring, strength } => {
                (textures.white_planet, Some((textures.white_ring, ring, strength)))
            }
            PlanetKind::DEAD => (textures.dead_planet, None),
        };

        let planet = Asset::from_texture(&planet, center);
        let ring = ring.map(|(t, r, s)| {
            let dims = glm::UVec2::from_s((r * 2.) as u32);
            let asset = Asset::centered_on(t.id, center, dims);
            Ring::new(r, s, asset)
        });

        (planet, ring)
    }
}

impl<I: Intersect<Circle>> Collidable<Circle, I> for Planet {
    fn collides(&self, shape: &I) -> bool {
        shape.intersects(&self.body)
    }
}
<commit_msg>use delta as a way to scale how fast the ring animation moves<commit_after>use master_smasher::drawable::{Asset, Drawable};
use master_smasher::shape::{Circle, Intersect};
use super::world_assets::WorldAssets;
use super::collidable::Collidable;
use super::level_data::{PlanetData, PlanetKind};

use glm::{self, GenNum};
use glm::ext::normalize_to;
use num_traits::Zero;

use std::cmp;
use std::time::Duration;

struct Ring {
    radius: f64,
    strength: f64,
    asset: Asset,
    zoom: f64,
}

impl Ring {
    pub fn new(radius: f64, strength: f64, asset: Asset) -> Self {
        Ring {
            radius: radius,
            strength: strength,
            asset: asset.clone(),
            zoom: 1.,
        }
    }

    pub fn animate(&mut self, delta: Duration) {
        const K: f64 = 0.166;
        let moving_radius = self.asset.dims().x as f64 * self.zoom / 2.;
        let pull = glm::length(self.pull_vector(glm::dvec2(moving_radius, 0.), 0.));
        let time = delta.as_secs() as f64 + delta.subsec_nanos() as f64 / 1000000000.;
        self.zoom *= 1. / 2_f64.powf(K * pull * time);
    }

    pub fn drawables(&self) -> Vec<Drawable> {
        let mut moving = self.asset.clone();
        moving.zoom(glm::DVec2::from_s(self.zoom));
        vec![Drawable::Asset(self.asset), Drawable::Asset(moving)]
    }

    pub fn pull_vector(&self, dist: glm::DVec2, radius: f64) -> glm::DVec2 {
        let len = glm::length(dist);
        if len > (self.radius + radius) {
            glm::DVec2::zero()
        } else {
            let force = self.strength / (len.powf(0.8));
            normalize_to(dist, force)
        }
    }
}

pub struct Planet {
    body: Circle,
    asset: Asset,
    ring: Option<Ring>,
}

impl Planet {
    pub fn new(data: &PlanetData, textures: &WorldAssets) -> Self {
        let (asset, ring) = Self::load_assets(data, textures);
        let dims = asset.dims();
        let radius = cmp::min(dims.x, dims.y) as f64 / 2.;
        let center = glm::dvec2(data.x as f64, data.y as f64);
        let body = Circle {
            center: center,
            radius: radius,
        };

        Planet {
            body: body,
            asset: asset,
            ring: ring,
        }
    }

    pub fn animate(&mut self, delta: Duration) {
        if let Some(ref mut r) = self.ring {
            if r.asset.dims().x as f64 * r.zoom / 2. < self.body.radius {
                r.zoom = 1.;
            }
            r.animate(delta)
        }
    }

    pub fn pull_vector(&self, point: glm::DVec2, radius: f64) -> glm::DVec2 {
        self.ring.as_ref().map_or(glm::DVec2::zero(),
                                  |r| r.pull_vector(self.body.center - point, radius))
    }

    pub fn drawables(&self) -> Vec<Drawable> {
        let mut drawables = self.ring.as_ref().map_or(vec![], |r| r.drawables());
        drawables.push(Drawable::Asset(self.asset));
        drawables
    }

    fn load_assets(data: &PlanetData, textures: &WorldAssets) -> (Asset, Option<Ring>) {
        let center = glm::ivec2(data.x, data.y);
        let (planet, ring) = match data.kind {
            PlanetKind::RED { ring, strength } => {
                (textures.red_planet, Some((textures.red_ring, ring, strength)))
            }
            PlanetKind::BLUE { ring, strength } => {
                (textures.blue_planet, Some((textures.blue_ring, ring, strength)))
            }
            PlanetKind::WHITE { ring, strength } => {
                (textures.white_planet, Some((textures.white_ring, ring, strength)))
            }
            PlanetKind::DEAD => (textures.dead_planet, None),
        };

        let planet = Asset::from_texture(&planet, center);
        let ring = ring.map(|(t, r, s)| {
            let dims = glm::UVec2::from_s((r * 2.) as u32);
            let asset = Asset::centered_on(t.id, center, dims);
            Ring::new(r, s, asset)
        });

        (planet, ring)
    }
}

impl<I: Intersect<Circle>> Collidable<Circle, I> for Planet {
    fn collides(&self, shape: &I) -> bool {
        shape.intersects(&self.body)
    }
}
<|endoftext|>


<commit_before>use gfx;
use gfx::traits::{IntoCanvas, Factory, FactoryExt, Stream};
use gfx::device::handle::Texture;
use gfx::extra::canvas::Canvas;
use gfx_device_gl as dgl;
use gfx_window_glutin as gfxw;
use glutin::{CreationError, Window, WindowBuilder};
use glutin::Event::{Closed, KeyboardInput};
use glutin::ElementState::Pressed;
use glutin::VirtualKeyCode as Key;
use ::ivf;
use ::vpx;

pub type Error = CreationError;

#[vertex_format]
#[derive(Clone, Copy)]
struct Vertex {
    #[as_float]
    #[name = "a_Pos"]
    pos: [i8; 2],
    #[as_float]
    #[name = "a_TexCoord"]
    tex: [u8; 2],
}

#[shader_param]
struct ShaderParams<R: gfx::Resources> {
    #[name = "t_Color"]
    color: gfx::shade::TextureParam<R>,
}

static VERTEX_SRC: &'static [u8] = b"
    #version 120

    attribute vec4 a_Pos;
    attribute vec2 a_TexCoord;
    varying vec2 v_TexCoord;

    void main() {
        v_TexCoord = a_TexCoord;
        gl_Position = a_Pos;
    }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 120

    varying vec2 v_TexCoord;
    uniform sampler2D t_Color;

    void main() {
        gl_FragColor = texture2D(t_Color, v_TexCoord);
    }
";

const VERTEX_DATA: &'static [Vertex] = &[
    // 1
    // |\
    // | \
    // 2--3
    Vertex {pos: [-1,  1], tex: [0, 0]},
    Vertex {pos: [-1, -1], tex: [0, 1]},
    Vertex {pos: [ 1, -1], tex: [1, 1]},
    // 1--3
    //  \ |
    //   \|
    //    2
    Vertex {pos: [-1,  1], tex: [0, 0]},
    Vertex {pos: [ 1, -1], tex: [1, 1]},
    Vertex {pos: [ 1,  1], tex: [1, 0]},
];

// TODO(Kagami): Process all errors.
// TODO(Kagami): Fullscreen.
pub fn run(reader: &mut ivf::Reader, decoder: &mut vpx::Decoder) -> Result<(), Error> {
    let mut canvas = {
        let window = try!(WindowBuilder::new()
            .with_dimensions(reader.get_width() as u32, reader.get_height() as u32)
            // Use simple initial title to allow to match the window in tiling
            // window managers.
            .with_title(format!("vpxview"))
            .build());
        gfxw::init(window).into_canvas()
    };
    let batch = {
        let mesh = canvas.factory.create_mesh(VERTEX_DATA);
        let program = canvas.factory.link_program(VERTEX_SRC, FRAGMENT_SRC).unwrap();
        let texture = canvas.factory.create_texture_rgba8(
            reader.get_width(),
            reader.get_height()).unwrap();
        let param = ShaderParams {color: (texture, None)};
        gfx::batch::OwnedBatch::new(mesh, program, param).unwrap()
    };
    let texture = &batch.param.color.0;

    show_frame(reader, decoder, &mut canvas, texture);
    loop {
        // Skip all pending events except the first because in some cases frame
        // decoding may take too long so interface will be brozen because of
        // big events queue.
        let maybe_event = {
            let mut iter = canvas.output.window.poll_events();
            let ev = iter.next();
            iter.count();  // Consume entire iterator
            ev
        };
        match maybe_event {
            Some(Closed) => break,
            Some(KeyboardInput(Pressed, _, Some(Key::Escape))) => break,
            Some(KeyboardInput(Pressed, _, Some(Key::Q))) => break,
            Some(KeyboardInput(Pressed, _, Some(Key::Left))) => {
                // TODO(Kagami).
            },
            Some(KeyboardInput(Pressed, _, Some(Key::Right))) => {
                show_frame(reader, decoder, &mut canvas, texture);
            },
            _ => {},
        }
        canvas.clear(gfx::ClearData {color: [0.0, 0.0, 0.0, 1.0], depth: 1.0, stencil: 0});
        match canvas.draw(&batch) {
            Err(err) => printerr!("Error occured while drawing the frame: {:?}", err),
            Ok(_) => {},
        }
        canvas.present();
    }
    Ok(())
}

type CanvasT = Canvas<gfxw::Output<dgl::Resources>, dgl::Device, dgl::Factory>;
type TextureT = Texture<dgl::Resources>;

fn show_frame(reader: &mut ivf::Reader,
              decoder: &mut vpx::Decoder,
              canvas: &mut CanvasT,
              texture: &TextureT) {
    let maybe_frame = reader.next();
    update_title(reader, &canvas.output.window);
    let ivf_frame = try_print!(maybe_frame, "End of file");
    match decoder.decode_many(&ivf_frame) {
        Ok(mut iter) => {
            let image = try_print!(iter.next(), "No VPx frames in this IVF frame");
            // TODO(Kagami): IVF frame may consist of several VPx frames, we
            // correctly display only 1 IVF <-> 1 VPx case as for now.
            let remaining = iter.count();
            if remaining != 0 {
                printerr!("Skipping {} other VPx frames", remaining);
            }
            // TODO(Kagami): Dimensions of decoded VPx image can vary from
            // frame to frame, we can adjust texture size accordingly.
            assert_eq!(image.get_display_width(), texture.get_info().width);
            assert_eq!(image.get_display_height(), texture.get_info().height);
            canvas.factory.update_texture_raw(
                texture,
                &texture.get_info().to_image_info(),
                &image.get_rgba8(),
                None).unwrap();
        },
        Err(err) => {
            printerr!("Cannot decode IVF frame: {}", err);
        },
    };
}

fn update_title(reader: &ivf::Reader, window: &Window) {
    let frame_count = reader.get_frame_count()
                            .map_or_else(|| "?".to_string(), |v| v.to_string());
    let title = format!("vpxview - {} - {}/{}",
                        reader.get_filename(),
                        reader.get_frame_pos(),
                        frame_count);
    println!("Frame {}/{}", reader.get_frame_pos(), frame_count);
    window.set_title(&title);
}
<commit_msg>Mute unused import warning<commit_after>use gfx;
use gfx::traits::{IntoCanvas, Factory, FactoryExt, Stream};
use gfx::device::handle::Texture;
use gfx::extra::canvas::Canvas;
use gfx_device_gl as dgl;
use gfx_window_glutin as gfxw;
use glutin::{CreationError, Window, WindowBuilder};
use glutin::Event::{Closed, KeyboardInput};
use glutin::ElementState::Pressed;
use glutin::VirtualKeyCode as Key;
use ::ivf;
use ::vpx;

pub type Error = CreationError;

#[vertex_format]
#[derive(Clone, Copy)]
struct Vertex {
    #[as_float]
    #[name = "a_Pos"]
    pos: [i8; 2],
    #[as_float]
    #[name = "a_TexCoord"]
    tex: [u8; 2],
}

#[shader_param]
struct ShaderParams<R: gfx::Resources> {
    #[name = "t_Color"]
    color: gfx::shade::TextureParam<R>,
    // XXX(Kagami): mute unused ToUniform import warning.
    _t: i32,
}

static VERTEX_SRC: &'static [u8] = b"
    #version 120

    attribute vec4 a_Pos;
    attribute vec2 a_TexCoord;
    varying vec2 v_TexCoord;

    void main() {
        v_TexCoord = a_TexCoord;
        gl_Position = a_Pos;
    }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 120

    varying vec2 v_TexCoord;
    uniform sampler2D t_Color;

    void main() {
        gl_FragColor = texture2D(t_Color, v_TexCoord);
    }
";

const VERTEX_DATA: &'static [Vertex] = &[
    // 1
    // |\
    // | \
    // 2--3
    Vertex {pos: [-1,  1], tex: [0, 0]},
    Vertex {pos: [-1, -1], tex: [0, 1]},
    Vertex {pos: [ 1, -1], tex: [1, 1]},
    // 1--3
    //  \ |
    //   \|
    //    2
    Vertex {pos: [-1,  1], tex: [0, 0]},
    Vertex {pos: [ 1, -1], tex: [1, 1]},
    Vertex {pos: [ 1,  1], tex: [1, 0]},
];

// TODO(Kagami): Process all errors.
// TODO(Kagami): Fullscreen.
pub fn run(reader: &mut ivf::Reader, decoder: &mut vpx::Decoder) -> Result<(), Error> {
    let mut canvas = {
        let window = try!(WindowBuilder::new()
            .with_dimensions(reader.get_width() as u32, reader.get_height() as u32)
            // Use simple initial title to allow to match the window in tiling
            // window managers.
            .with_title(format!("vpxview"))
            .build());
        gfxw::init(window).into_canvas()
    };
    let batch = {
        let mesh = canvas.factory.create_mesh(VERTEX_DATA);
        let program = canvas.factory.link_program(VERTEX_SRC, FRAGMENT_SRC).unwrap();
        let texture = canvas.factory.create_texture_rgba8(
            reader.get_width(),
            reader.get_height()).unwrap();
        let param = ShaderParams {color: (texture, None), _t: 0};
        gfx::batch::OwnedBatch::new(mesh, program, param).unwrap()
    };
    let texture = &batch.param.color.0;

    show_frame(reader, decoder, &mut canvas, texture);
    loop {
        // Skip all pending events except the first because in some cases frame
        // decoding may take too long so interface will be brozen because of
        // big events queue.
        let maybe_event = {
            let mut iter = canvas.output.window.poll_events();
            let ev = iter.next();
            iter.count();  // Consume entire iterator
            ev
        };
        match maybe_event {
            Some(Closed) => break,
            Some(KeyboardInput(Pressed, _, Some(Key::Escape))) => break,
            Some(KeyboardInput(Pressed, _, Some(Key::Q))) => break,
            Some(KeyboardInput(Pressed, _, Some(Key::Left))) => {
                // TODO(Kagami).
            },
            Some(KeyboardInput(Pressed, _, Some(Key::Right))) => {
                show_frame(reader, decoder, &mut canvas, texture);
            },
            _ => {},
        }
        canvas.clear(gfx::ClearData {color: [0.0, 0.0, 0.0, 1.0], depth: 1.0, stencil: 0});
        match canvas.draw(&batch) {
            Err(err) => printerr!("Error occured while drawing the frame: {:?}", err),
            Ok(_) => {},
        }
        canvas.present();
    }
    Ok(())
}

type CanvasT = Canvas<gfxw::Output<dgl::Resources>, dgl::Device, dgl::Factory>;
type TextureT = Texture<dgl::Resources>;

fn show_frame(reader: &mut ivf::Reader,
              decoder: &mut vpx::Decoder,
              canvas: &mut CanvasT,
              texture: &TextureT) {
    let maybe_frame = reader.next();
    update_title(reader, &canvas.output.window);
    let ivf_frame = try_print!(maybe_frame, "End of file");
    match decoder.decode_many(&ivf_frame) {
        Ok(mut iter) => {
            let image = try_print!(iter.next(), "No VPx frames in this IVF frame");
            // TODO(Kagami): IVF frame may consist of several VPx frames, we
            // correctly display only 1 IVF <-> 1 VPx case as for now.
            let remaining = iter.count();
            if remaining != 0 {
                printerr!("Skipping {} other VPx frames", remaining);
            }
            // TODO(Kagami): Dimensions of decoded VPx image can vary from
            // frame to frame, we can adjust texture size accordingly.
            assert_eq!(image.get_display_width(), texture.get_info().width);
            assert_eq!(image.get_display_height(), texture.get_info().height);
            canvas.factory.update_texture_raw(
                texture,
                &texture.get_info().to_image_info(),
                &image.get_rgba8(),
                None).unwrap();
        },
        Err(err) => {
            printerr!("Cannot decode IVF frame: {}", err);
        },
    };
}

fn update_title(reader: &ivf::Reader, window: &Window) {
    let frame_count = reader.get_frame_count()
                            .map_or_else(|| "?".to_string(), |v| v.to_string());
    let title = format!("vpxview - {} - {}/{}",
                        reader.get_filename(),
                        reader.get_frame_pos(),
                        frame_count);
    println!("Frame {}/{}", reader.get_frame_pos(), frame_count);
    window.set_title(&title);
}
<|endoftext|>


<commit_before>extern crate image;

use image::Rgb;

pub struct HSL {
    hue: f32,
    sat: f32,
    lum: f32,
}

impl HSL {
    pub fn new(hue: f32, sat: f32, lum: f32) -> HSL {
        HSL {
            hue: hue,
            sat: sat,
            lum: lum,
        }
    }

    // http://www.w3.org/TR/css3-color/#hsl-color
    pub fn rgb(&self) -> Rgb<u8> {
        let hue = self.hue / 360.0;
        let sat = self.sat / 100.0;
        let lum = self.lum / 100.0;

        let b = if lum <= 0.5 {
            lum * (sat + 1.0)
        } else {
            lum + sat - lum * sat
        };
        let a = lum * 2.0 - b;

        let r = HSL::hue_to_rgb(a, b, hue + 1.0 / 3.0);
        let g = HSL::hue_to_rgb(a, b, hue);
        let b = HSL::hue_to_rgb(a, b, hue - 1.0 / 3.0);

        Rgb([(r * 255.0).round() as u8, (g * 255.0).round() as u8, (b * 255.0).round() as u8])
    }

    fn hue_to_rgb(a: f32, b: f32, hue: f32) -> f32 {
        let h = if hue < 0.0 {
            hue + 1.0
        } else if hue > 1.0 {
            hue - 1.0
        } else {
            hue
        };

        if h < 1.0 / 6.0 {
            return a + (b - a) * 6.0 * h;
        }

        if h < 1.0 / 2.0 {
            return b;
        }

        if h < 2.0 / 3.0 {
            return a + (b - a) * (2.0 / 3.0 - h) * 6.0;
        }

        a
    }
}
<commit_msg>Add HSL to RGB conversion tests<commit_after>extern crate image;

use image::Rgb;

pub struct HSL {
    hue: f32,
    sat: f32,
    lum: f32,
}

impl HSL {
    pub fn new(hue: f32, sat: f32, lum: f32) -> HSL {
        HSL {
            hue: hue,
            sat: sat,
            lum: lum,
        }
    }

    // http://www.w3.org/TR/css3-color/#hsl-color
    pub fn rgb(&self) -> Rgb<u8> {
        let hue = self.hue / 360.0;
        let sat = self.sat / 100.0;
        let lum = self.lum / 100.0;

        let b = if lum <= 0.5 {
            lum * (sat + 1.0)
        } else {
            lum + sat - lum * sat
        };
        let a = lum * 2.0 - b;

        let r = HSL::hue_to_rgb(a, b, hue + 1.0 / 3.0);
        let g = HSL::hue_to_rgb(a, b, hue);
        let b = HSL::hue_to_rgb(a, b, hue - 1.0 / 3.0);

        Rgb([(r * 255.0).round() as u8, (g * 255.0).round() as u8, (b * 255.0).round() as u8])
    }

    fn hue_to_rgb(a: f32, b: f32, hue: f32) -> f32 {
        let h = if hue < 0.0 {
            hue + 1.0
        } else if hue > 1.0 {
            hue - 1.0
        } else {
            hue
        };

        if h < 1.0 / 6.0 {
            return a + (b - a) * 6.0 * h;
        }

        if h < 1.0 / 2.0 {
            return b;
        }

        if h < 2.0 / 3.0 {
            return a + (b - a) * (2.0 / 3.0 - h) * 6.0;
        }

        a
    }
}

#[cfg(test)]
mod tests {
    use super::HSL;
    use image::Rgb;

    #[test]
    fn it_converts_black() {
        let black = Rgb([0, 0, 0]);
        let rgb = HSL::new(0.0, 0.0, 0.0).rgb();
        assert_eq!(black, rgb);
    }

    #[test]
    fn it_converts_white() {
        let white = Rgb([255, 255, 255]);
        let rgb = HSL::new(0.0, 0.0, 100.0).rgb();
        assert_eq!(white, rgb);
    }

    #[test]
    fn it_converts_red() {
        let red = Rgb([255, 0, 0]);
        let rgb = HSL::new(0.0, 100.0, 50.0).rgb();
        assert_eq!(red, rgb);
    }

    #[test]
    fn it_converts_green() {
        let green = Rgb([0, 255, 0]);
        let rgb = HSL::new(120.0, 100.0, 50.0).rgb();
        assert_eq!(green, rgb);
    }

    #[test]
    fn it_converts_blue() {
        let blue = Rgb([0, 0, 255]);
        let rgb = HSL::new(240.0, 100.0, 50.0).rgb();
        assert_eq!(blue, rgb);
    }
}
<|endoftext|>


<commit_before>//! Implements basic arithmetic operations in GF(2^8).

/// Multiply two elements of GF(2^8).
pub fn mul(lhs: u8, rhs: u8) -> u8 {
    // This algorithm is constant-time, allowing us to perform GF256 arithmetic over secret values
    // without leaking information about the values via timing.
    let mut aa = lhs;
    let mut bb = rhs;
    let mut r = 0;
    // Loop over all 8 bits, regardless of whether or not it's required. aa != 0 is the usual loop
    // condition, but here it's folded into the per-round bitmask.
    for _ in 0..8 {
        // Perform r ^= bb iff aa & 1 == 0 && aa != 0.
        r ^= bb & ((aa & 1 != 0) as u8 * 0xff) & ((aa != 0) as u8 * 0xff);
        let t = bb & 0x80;
        bb <<= 1;
        // Perform bb ^= 0x1b iff t != 0 && aa != 0.
        bb ^= 0x1b & ((t != 0) as u8 * 0xff) & ((aa != 0) as u8 * 0xff);
        aa >>= 1;
    }
    r
}

/// Divide one element of GF(2^8) by another.
pub fn div(lhs: u8, rhs: u8) -> u8 {
    if rhs == 0 {
        panic!("Divide by zero: {} / {}", lhs, rhs)
    }

    // Again, this algorithm is constant-time. First, we find the multiplicative inverse of `a` by
    // iterating over all possible values, and using a bitmask to accumulate only that value which,
    // when multiplied by `a`, is `1`.
    let mut inv = 0;
    for i in 0x00..=0xff {
        inv += i & ((mul(i, rhs) == 1) as u8 * 0xff);
    }

    // Finally, we multiply `e` by the multiplicative inverse of `a`.
    mul(inv, lhs)
}

#[cfg(test)]
mod test {
    extern crate proptest;

    use super::*;

    use self::proptest::prelude::*;

    proptest! {
        #[test]
        fn div_is_inverse_of_mul(a in 0u8..=255, b in 1u8..=255) {
            assert_eq!(mul(div(a, b), b), a);
        }

        #[test]
        fn mul_is_inverse_of_div(a in 0u8..=255, b in 1u8..=255) {
            assert_eq!(div(mul(a, b), b), a);
        }

        #[test]
        fn mul_is_commutative(a in 0u8..=255, b in 0u8..=255) {
            assert_eq!(mul(a, b), mul(b, a));
        }
    }

    #[test]
    fn test_mul() {
        assert_eq!(mul(90, 21), 254);
        assert_eq!(mul(133, 5), 167);
    }

    #[test]
    fn test_mul_zero() {
        assert_eq!(mul(0, 21), 0);
    }

    #[test]
    fn test_div() {
        assert_eq!(div(90, 21), 189);
        assert_eq!(div(6, 55), 151);
        assert_eq!(div(22, 192), 138);
    }

    #[test]
    fn test_div_zero() {
        assert_eq!(div(0, 21), 0);
    }
}
<commit_msg>Extract out the bool-to-mask trick.<commit_after>//! Implements basic arithmetic operations in GF(2^8).

/// Multiply two elements of GF(2^8).
pub fn mul(lhs: u8, rhs: u8) -> u8 {
    // This algorithm is constant-time, allowing us to perform GF256 arithmetic over secret values
    // without leaking information about the values via timing.
    let mut aa = lhs;
    let mut bb = rhs;
    let mut r = 0;
    // Loop over all 8 bits, regardless of whether or not it's required. aa != 0 is the usual loop
    // condition, but here it's folded into the per-round bitmask.
    for _ in 0..8 {
        // Perform r ^= bb iff aa & 1 == 0 && aa != 0.
        let loop_live = bool_to_mask(aa != 0);
        r ^= bb & bool_to_mask(aa & 1 != 0) & loop_live;
        let t = bb & 0x80;
        bb <<= 1;
        // Perform bb ^= 0x1b iff t != 0 && aa != 0.
        bb ^= 0x1b & bool_to_mask(t != 0) & loop_live;
        aa >>= 1;
    }
    r
}

/// Divide one element of GF(2^8) by another.
pub fn div(lhs: u8, rhs: u8) -> u8 {
    if rhs == 0 {
        panic!("Divide by zero: {} / {}", lhs, rhs)
    }

    // Again, this algorithm is constant-time. First, we find the multiplicative inverse of `a` by
    // iterating over all possible values, and using a bitmask to accumulate only that value which,
    // when multiplied by `a`, is `1`.
    let mut inv = 0;
    for i in 0x00..=0xff {
        inv += i & bool_to_mask(mul(i, rhs) == 1);
    }

    // Finally, we multiply `e` by the multiplicative inverse of `a`.
    mul(inv, lhs)
}

// If b is true, return 0xff, otherwise, return 0x00. Constant-time implementation.
#[inline(always)]
fn bool_to_mask(b: bool) -> u8 {
    (b as u8) * 0xff
}

#[cfg(test)]
mod test {
    extern crate proptest;

    use super::*;

    use self::proptest::prelude::*;

    proptest! {
        #[test]
        fn div_is_inverse_of_mul(a in 0u8..=255, b in 1u8..=255) {
            assert_eq!(mul(div(a, b), b), a);
        }

        #[test]
        fn mul_is_inverse_of_div(a in 0u8..=255, b in 1u8..=255) {
            assert_eq!(div(mul(a, b), b), a);
        }

        #[test]
        fn mul_is_commutative(a in 0u8..=255, b in 0u8..=255) {
            assert_eq!(mul(a, b), mul(b, a));
        }
    }

    #[test]
    fn test_mul() {
        assert_eq!(mul(90, 21), 254);
        assert_eq!(mul(133, 5), 167);
    }

    #[test]
    fn test_mul_zero() {
        assert_eq!(mul(0, 21), 0);
    }

    #[test]
    fn test_div() {
        assert_eq!(div(90, 21), 189);
        assert_eq!(div(6, 55), 151);
        assert_eq!(div(22, 192), 138);
    }

    #[test]
    fn test_div_zero() {
        assert_eq!(div(0, 21), 0);
    }
}
<|endoftext|>


<commit_before>//! Read and write Elasto Mania level files.

use std::io::{ Read };
use std::fs::File;
use byteorder::{ ByteOrder, ReadBytesExt, LittleEndian };
use super::{ Position, trim_string };

// Magic arbitrary number; signifies end-of-data. Followed by Top10 lists.
const EOD: i32 = 0x0067103A;
// Magic arbitrary number; signifies end-of-file.
const EOF: i32 = 0x00845D52;

/// Game version.
#[derive(Debug, PartialEq)]
pub enum Version {
    Across,
    Elma
}

impl Default for Version {
    fn default() -> Version { Version::Elma }
}

/// Type of object.
#[derive(Debug, PartialEq)]
pub enum ObjectType {
    Apple { gravity: Direction, animation: u8 },
    Exit,
    Killer,
    Player
}

impl Default for ObjectType {
    fn default() -> ObjectType { ObjectType::Apple { gravity: Direction::default(), animation: 1 } }
}

/// Apple direction object.
#[derive(Debug, PartialEq)]
pub enum Direction {
    Normal,
    Up,
    Down,
    Left,
    Right
}

impl Default for Direction {
    fn default() -> Direction { Direction::Normal }
}

/// Object struct. Every level requires one `ObjectType::Player` Object and at least one `ObjectType::Exit` Object.
#[derive(Debug, Default, PartialEq)]
pub struct Object {
    /// Position. See `Position` struct.
    pub position: Position<f64>,
    /// Type of Object, see `ObjectType`.
    pub object_type: ObjectType
}

/// Polygon struct.
#[derive(Debug, Default, PartialEq)]
pub struct Polygon {
    /// Grass polygon.
    pub grass: bool,
    /// Vector with all vertices, see Position struct.
    pub vertices: Vec<Position<f64>>
}

impl Polygon {
    pub fn new () -> Self {
        Polygon {
            grass: false,
            vertices: vec![]
        }
    }
}

/// Picture clipping.
#[derive(Debug, PartialEq)]
pub enum Clip {
    Unclipped,
    Ground,
    Sky
}

impl Default for Clip {
    fn default() -> Clip { Clip::Ground }
}

/// Picture struct.
#[derive(Debug, Default, PartialEq)]
pub struct Picture {
    /// Picture name.
    pub name: String,
    /// Texture name.
    pub texture: String,
    /// Mask name.
    pub mask: String,
    /// Position. See Position struct.
    pub position: Position<f64>,
    /// Z-distance
    pub distance: i32,
    /// Clipping.
    pub clip: Clip
}

/// Top10 list entry struct.
#[derive(Debug, Default, PartialEq)]
pub struct ListEntry {
    /// Player 1 name.
    pub name_1: String,
    /// Player 2 name.
    pub name_2: String,
    /// Time.
    pub time: i32
}

/// Level struct that contains all level information.
#[derive(Debug, PartialEq)]
pub struct Level {
    /// Raw binary data of a loaded or finalized constructed level.
    raw: Vec<u8>,
    /// Elma or Across level.
    pub version: Version,
    /// Random number that links level file to replay files.
    pub link: i32,
    /// Contains four integrity checks (See calculate_integrity_sums()).
    pub integrity: [f64; 4],
    /// Level name.
    pub name: String,
    /// LGR file name.
    pub lgr: String,
    /// Ground texture name.
    pub ground: String,
    /// Sky texture name.
    pub sky: String,
    /// Vector with all polygons (See Polygon).
    pub polygons: Vec<Polygon>,
    /// Vector with all objects (See Object).
    pub objects: Vec<Object>,
    /// Vector with all pictures (See Picture).
    pub pictures: Vec<Picture>,
    /// Vector of Top10 single-player names and times.
    pub top10_single: Vec<ListEntry>,
    /// Vector of Top10 multi-player names and times.
    pub top10_multi: Vec<ListEntry>
}

impl Default for Level {
    fn default() -> Level { Level::new() }
}

impl Level {
    /// Returns a new Level struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::new();
    /// ```
    pub fn new () -> Self {
        Level {
            raw: vec![],
            version: Version::Elma,
            link: 0,
            integrity: [0f64; 4],
            name: String::new(),
            lgr: String::from("default"),
            ground: String::from("ground"),
            sky: String::from("sky"),
            polygons: vec![],
            objects: vec![],
            pictures: vec![],
            top10_single: vec![],
            top10_multi: vec![]
        }
    }

    /// Loads a level file and returns a Level struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::load_level("tests/test_1.lev");
    /// ```
    pub fn load_level (filename: &str) -> Self {
        let mut level = Level::new();
        let mut file = File::open(filename).unwrap();
        let mut buffer = vec![];
        file.read_to_end(&mut buffer).unwrap();
        level.raw = buffer;
        level.parse_level();
        level
    }

    /// Parses the raw binary data into Level struct fields.
    fn parse_level (&mut self) {
        let remaining = self.raw.as_slice();

        // POT06 = Across, POT14 = Elma.
        let (version, remaining) = remaining.split_at(5);
        self.version = match version {
            [80, 79, 84, 49, 52] => Version::Elma,
            [80, 79, 84, 48, 54] => Version::Across,
            _ => panic!("Not a valid level file.")
        };

        // Link.
        let (_, mut remaining) = remaining.split_at(2); // Never used
        self.link = remaining.read_i32::<LittleEndian>().unwrap();

        // Integrity checksums.
        for i in 0..4 {
            self.integrity[i] = remaining.read_f64::<LittleEndian>().unwrap();
        }

        // Level name.
        let (name, remaining) = remaining.split_at(51);
        self.name = trim_string(name).unwrap();
        // LGR name.
        let (lgr, remaining) = remaining.split_at(16);
        self.lgr = trim_string(lgr).unwrap();
        // Ground texture name.
        let (ground, remaining) = remaining.split_at(10);
        self.ground = trim_string(ground).unwrap();
        // Sky texture name.
        let (sky, mut remaining) = remaining.split_at(10);
        self.sky = trim_string(sky).unwrap();

        // Polygons.
        let poly_count = (remaining.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as usize;
        for _ in 0..poly_count {
            let grass = remaining.read_i32::<LittleEndian>().unwrap() > 0;
            let vertex_count = remaining.read_i32::<LittleEndian>().unwrap();
            let mut vertices: Vec<Position<f64>> = vec![];
            for _ in 0..vertex_count {
                let x = remaining.read_f64::<LittleEndian>().unwrap();
                let y = remaining.read_f64::<LittleEndian>().unwrap();
                vertices.push(Position {
                    x: x,
                    y: y
                });
            }
            self.polygons.push(Polygon {
                grass: grass,
                vertices: vertices
            });
        }

        // Objects.
        let object_count = (remaining.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as usize;
        for _ in 0..object_count {
            let x = remaining.read_f64::<LittleEndian>().unwrap();
            let y = remaining.read_f64::<LittleEndian>().unwrap();
            let position = Position { x: x, y: y };
            let object_type = remaining.read_i32::<LittleEndian>().unwrap();
            let gravity = remaining.read_i32::<LittleEndian>().unwrap();
            let gravity_direction = match gravity {
                0 => Direction::Normal,
                1 => Direction::Up,
                2 => Direction::Down,
                3 => Direction::Left,
                4 => Direction::Right,
                _ => panic!("Not a valid gravity direction: {:?}", gravity)
            };
            let animation = (remaining.read_i32::<LittleEndian>().unwrap() + 1) as u8;
            let object = match object_type {
                1 => ObjectType::Exit,
                2 => ObjectType::Apple { gravity: gravity_direction, animation: animation },
                3 => ObjectType::Killer,
                4 => ObjectType::Player,
                _ => panic!("Not a valid object type: {:?}", object_type)
            };

            self.objects.push(Object {
                position: position,
                object_type: object
            });
        }

        // Pictures.
        let picture_count = (remaining.read_f64::<LittleEndian>().unwrap() - 0.2345672).round() as usize;
        for _ in 0..picture_count {
            let (name, temp_remaining) = remaining.split_at(10);
            let name = trim_string(name).unwrap();
            let (texture, temp_remaining) = temp_remaining.split_at(10);
            let texture = trim_string(texture).unwrap();
            let (mask, temp_remaining) = temp_remaining.split_at(10);
            let mask = trim_string(mask).unwrap();
            remaining = temp_remaining;
            let x = remaining.read_f64::<LittleEndian>().unwrap();
            let y = remaining.read_f64::<LittleEndian>().unwrap();
            let distance = remaining.read_i32::<LittleEndian>().unwrap();
            let clipping = remaining.read_i32::<LittleEndian>().unwrap();
            let clip = match clipping {
                0 => Clip::Unclipped,
                1 => Clip::Ground,
                2 => Clip::Sky,
                _ => panic!("Not valid clipping data: {:?}", clipping)
            };

            self.pictures.push(Picture {
                name: name,
                texture: texture,
                mask: mask,
                position: Position { x: x, y: y },
                distance: distance,
                clip: clip
            });
        }

        // EOD marker expected at this point.
        let expected = remaining.read_i32::<LittleEndian>().unwrap();
        if expected != EOD { panic!("EOD marker mismatch: x0{:x} != x0{:x}", expected, EOD); }

        // First decrypt the top10 blocks.
        let (top10, mut remaining) = remaining.split_at(688);
        let decrypted_top10_data = crypt_top10(top10);

        // Single-player list.
        let single = &decrypted_top10_data[0..344];
        self.top10_single = parse_top10(single);

        // Multi-player list.
        let multi = &decrypted_top10_data[344..688];
        self.top10_multi = parse_top10(multi);

        // EOF marker expected at this point.
        let expected = remaining.read_i32::<LittleEndian>().unwrap();
        if expected != EOF { panic!("EOF marker mismatch: x0{:x} != x0{:x}", expected, EOF); }
    }

    /// Combines the Level struct fields to generate the raw binary data,
    /// and calculate integrity sums.
    fn update (&self) {
        self.calculate_integrity_sums();
        unimplemented!();
    }

    fn calculate_integrity_sums (&self) {
        unimplemented!();
    }

    /// Converts all struct fields into raw binary form and returns it.
    pub fn get_raw (self) -> Vec<u8> {
        self.update();
        self.raw
    }

    /// Saves level as a file. This will write new empty Top10 lists.
    pub fn save (&self, _filename: &str) {
        self.update();
        // let file = File::create(&filename).unwrap();
        unimplemented!();
    }

    /// Saves level as a file, without emptying Top10 lists.
    pub fn save_with_top10 (&self, _filename: &str) {
        self.update();
        unimplemented!();
    }
}

/// Decrypt and encrypt top10 list data. Same algorithm for both.
pub fn crypt_top10 (top10_data: &[u8]) -> Vec<u8> {
    let mut top10: Vec<u8> = Vec::with_capacity(688);
    top10.extend_from_slice(top10_data);

    // Some variables to match the original c/asm code?
    let mut ebp8: i16 = 0x15;
    let mut ebp10: i16 = 0x2637;

    for mut t in top10.iter_mut().take(688) {
        *t ^= (ebp8 & 0xFF) as u8;
        ebp10 = ebp10.wrapping_add((ebp8.wrapping_rem(0xD3D)).wrapping_mul(0xD3D));
        ebp8 = ebp10.wrapping_mul(0x1F).wrapping_add(0xD3D);
    }

    top10
}

/// Parse top10 lists and return a vector of `ListEntry`s
pub fn parse_top10 (top10: &[u8]) -> Vec<ListEntry> {
    let mut list: Vec<ListEntry> = vec![];
    let times = LittleEndian::read_i32(&top10[0..4]);
    for n in 0..times {
        let time_offset = (4 + n * 4) as usize;
        let time_end = time_offset + 4;
        let name_1_offset = (44 + n * 15) as usize;
        let name_1_end = name_1_offset + 15;
        let name_2_offset = (194 + n * 15) as usize;
        let name_2_end = name_2_offset + 15;

        let name_1 = &top10[name_1_offset..name_1_end];
        let name_2 = &top10[name_2_offset..name_2_end];
        let time = &top10[time_offset..time_end];
        list.push(ListEntry {
            time: LittleEndian::read_i32(time),
            name_1: trim_string(name_1).unwrap(),
            name_2: trim_string(name_2).unwrap()
        });
    }
    list
}
<commit_msg>Add placeholder topology check function<commit_after>//! Read and write Elasto Mania level files.

use std::io::{ Read };
use std::fs::File;
use byteorder::{ ByteOrder, ReadBytesExt, LittleEndian };
use super::{ Position, trim_string };

// Magic arbitrary number; signifies end-of-data. Followed by Top10 lists.
const EOD: i32 = 0x0067103A;
// Magic arbitrary number; signifies end-of-file.
const EOF: i32 = 0x00845D52;

/// Game version.
#[derive(Debug, PartialEq)]
pub enum Version {
    Across,
    Elma
}

impl Default for Version {
    fn default() -> Version { Version::Elma }
}

/// Type of object.
#[derive(Debug, PartialEq)]
pub enum ObjectType {
    Apple { gravity: Direction, animation: u8 },
    Exit,
    Killer,
    Player
}

impl Default for ObjectType {
    fn default() -> ObjectType { ObjectType::Apple { gravity: Direction::default(), animation: 1 } }
}

/// Apple direction object.
#[derive(Debug, PartialEq)]
pub enum Direction {
    Normal,
    Up,
    Down,
    Left,
    Right
}

impl Default for Direction {
    fn default() -> Direction { Direction::Normal }
}

/// Object struct. Every level requires one `ObjectType::Player` Object and at least one `ObjectType::Exit` Object.
#[derive(Debug, Default, PartialEq)]
pub struct Object {
    /// Position. See `Position` struct.
    pub position: Position<f64>,
    /// Type of Object, see `ObjectType`.
    pub object_type: ObjectType
}

/// Polygon struct.
#[derive(Debug, Default, PartialEq)]
pub struct Polygon {
    /// Grass polygon.
    pub grass: bool,
    /// Vector with all vertices, see `Position` struct.
    pub vertices: Vec<Position<f64>>
}

impl Polygon {
    pub fn new () -> Self {
        Polygon {
            grass: false,
            vertices: vec![]
        }
    }
}

/// Picture clipping.
#[derive(Debug, PartialEq)]
pub enum Clip {
    Unclipped,
    Ground,
    Sky
}

impl Default for Clip {
    fn default() -> Clip { Clip::Ground }
}

/// Picture struct.
#[derive(Debug, Default, PartialEq)]
pub struct Picture {
    /// Picture name.
    pub name: String,
    /// Texture name.
    pub texture: String,
    /// Mask name.
    pub mask: String,
    /// Position. See `Position` struct.
    pub position: Position<f64>,
    /// Z-distance
    pub distance: i32,
    /// Clipping.
    pub clip: Clip
}

/// Top10 list entry struct.
#[derive(Debug, Default, PartialEq)]
pub struct ListEntry {
    /// Player 1 name.
    pub name_1: String,
    /// Player 2 name.
    pub name_2: String,
    /// Time.
    pub time: i32
}

/// Level struct that contains all level information.
#[derive(Debug, PartialEq)]
pub struct Level {
    /// Raw binary data of a loaded or finalized constructed level.
    raw: Vec<u8>,
    /// Elma or Across level.
    pub version: Version,
    /// Random number that links level file to replay files.
    pub link: i32,
    /// Contains four integrity checks.
    pub integrity: [f64; 4],
    /// Level name.
    pub name: String,
    /// LGR file name.
    pub lgr: String,
    /// Ground texture name.
    pub ground: String,
    /// Sky texture name.
    pub sky: String,
    /// Vector with all polygons (See `Polygon`).
    pub polygons: Vec<Polygon>,
    /// Vector with all objects (See `Object`).
    pub objects: Vec<Object>,
    /// Vector with all pictures (See `Picture`).
    pub pictures: Vec<Picture>,
    /// Vector of Top10 single-player names and times.
    pub top10_single: Vec<ListEntry>,
    /// Vector of Top10 multi-player names and times.
    pub top10_multi: Vec<ListEntry>
}

impl Default for Level {
    fn default() -> Level { Level::new() }
}

impl Level {
    /// Returns a new `Level` struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::new();
    /// ```
    pub fn new () -> Self {
        Level {
            raw: vec![],
            version: Version::Elma,
            link: 0,
            integrity: [0f64; 4],
            name: String::new(),
            lgr: String::from("default"),
            ground: String::from("ground"),
            sky: String::from("sky"),
            polygons: vec![],
            objects: vec![],
            pictures: vec![],
            top10_single: vec![],
            top10_multi: vec![]
        }
    }

    /// Loads a level file and returns a `Level` struct.
    ///
    /// # Examples
    ///
    /// ```
    /// let level = elma::lev::Level::load_level("tests/test_1.lev");
    /// ```
    pub fn load_level (filename: &str) -> Self {
        let mut level = Level::new();
        let mut file = File::open(filename).unwrap();
        let mut buffer = vec![];
        file.read_to_end(&mut buffer).unwrap();
        level.raw = buffer;
        level.parse_level();
        level
    }

    /// Parses the raw binary data into `Level` struct fields.
    fn parse_level (&mut self) {
        let remaining = self.raw.as_slice();

        // POT06 = Across, POT14 = Elma.
        let (version, remaining) = remaining.split_at(5);
        self.version = match version {
            [80, 79, 84, 49, 52] => Version::Elma,
            [80, 79, 84, 48, 54] => Version::Across,
            _ => panic!("Not a valid level file.")
        };

        // Link.
        let (_, mut remaining) = remaining.split_at(2); // Never used
        self.link = remaining.read_i32::<LittleEndian>().unwrap();

        // Integrity checksums.
        for i in 0..4 {
            self.integrity[i] = remaining.read_f64::<LittleEndian>().unwrap();
        }

        // Level name.
        let (name, remaining) = remaining.split_at(51);
        self.name = trim_string(name).unwrap();
        // LGR name.
        let (lgr, remaining) = remaining.split_at(16);
        self.lgr = trim_string(lgr).unwrap();
        // Ground texture name.
        let (ground, remaining) = remaining.split_at(10);
        self.ground = trim_string(ground).unwrap();
        // Sky texture name.
        let (sky, mut remaining) = remaining.split_at(10);
        self.sky = trim_string(sky).unwrap();

        // Polygons.
        let poly_count = (remaining.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as usize;
        for _ in 0..poly_count {
            let grass = remaining.read_i32::<LittleEndian>().unwrap() > 0;
            let vertex_count = remaining.read_i32::<LittleEndian>().unwrap();
            let mut vertices: Vec<Position<f64>> = vec![];
            for _ in 0..vertex_count {
                let x = remaining.read_f64::<LittleEndian>().unwrap();
                let y = remaining.read_f64::<LittleEndian>().unwrap();
                vertices.push(Position {
                    x: x,
                    y: y
                });
            }
            self.polygons.push(Polygon {
                grass: grass,
                vertices: vertices
            });
        }

        // Objects.
        let object_count = (remaining.read_f64::<LittleEndian>().unwrap() - 0.4643643).round() as usize;
        for _ in 0..object_count {
            let x = remaining.read_f64::<LittleEndian>().unwrap();
            let y = remaining.read_f64::<LittleEndian>().unwrap();
            let position = Position { x: x, y: y };
            let object_type = remaining.read_i32::<LittleEndian>().unwrap();
            let gravity = remaining.read_i32::<LittleEndian>().unwrap();
            let gravity_direction = match gravity {
                0 => Direction::Normal,
                1 => Direction::Up,
                2 => Direction::Down,
                3 => Direction::Left,
                4 => Direction::Right,
                _ => panic!("Not a valid gravity direction: {:?}", gravity)
            };
            let animation = (remaining.read_i32::<LittleEndian>().unwrap() + 1) as u8;
            let object = match object_type {
                1 => ObjectType::Exit,
                2 => ObjectType::Apple { gravity: gravity_direction, animation: animation },
                3 => ObjectType::Killer,
                4 => ObjectType::Player,
                _ => panic!("Not a valid object type: {:?}", object_type)
            };

            self.objects.push(Object {
                position: position,
                object_type: object
            });
        }

        // Pictures.
        let picture_count = (remaining.read_f64::<LittleEndian>().unwrap() - 0.2345672).round() as usize;
        for _ in 0..picture_count {
            let (name, temp_remaining) = remaining.split_at(10);
            let name = trim_string(name).unwrap();
            let (texture, temp_remaining) = temp_remaining.split_at(10);
            let texture = trim_string(texture).unwrap();
            let (mask, temp_remaining) = temp_remaining.split_at(10);
            let mask = trim_string(mask).unwrap();
            remaining = temp_remaining;
            let x = remaining.read_f64::<LittleEndian>().unwrap();
            let y = remaining.read_f64::<LittleEndian>().unwrap();
            let distance = remaining.read_i32::<LittleEndian>().unwrap();
            let clipping = remaining.read_i32::<LittleEndian>().unwrap();
            let clip = match clipping {
                0 => Clip::Unclipped,
                1 => Clip::Ground,
                2 => Clip::Sky,
                _ => panic!("Not valid clipping data: {:?}", clipping)
            };

            self.pictures.push(Picture {
                name: name,
                texture: texture,
                mask: mask,
                position: Position { x: x, y: y },
                distance: distance,
                clip: clip
            });
        }

        // EOD marker expected at this point.
        let expected = remaining.read_i32::<LittleEndian>().unwrap();
        if expected != EOD { panic!("EOD marker mismatch: x0{:x} != x0{:x}", expected, EOD); }

        // First decrypt the top10 blocks.
        let (top10, mut remaining) = remaining.split_at(688);
        let decrypted_top10_data = crypt_top10(top10);

        // Single-player list.
        let single = &decrypted_top10_data[0..344];
        self.top10_single = parse_top10(single);

        // Multi-player list.
        let multi = &decrypted_top10_data[344..688];
        self.top10_multi = parse_top10(multi);

        // EOF marker expected at this point.
        let expected = remaining.read_i32::<LittleEndian>().unwrap();
        if expected != EOF { panic!("EOF marker mismatch: x0{:x} != x0{:x}", expected, EOF); }
    }

    /// Combines the `Level` struct fields to generate the raw binary data,
    /// and calculate integrity sums.
    fn update (&self) {
        self.calculate_integrity_sums();
        unimplemented!();
    }

    fn calculate_integrity_sums (&self) {
        unimplemented!();
    }

    /// Check topology of level.
    // TODO: make this return a Result with problematic polygons/vertices.
    pub fn topology_check (&self) -> bool {
        unimplemented!();
    }

    /// Converts all struct fields into raw binary form and returns it.
    pub fn get_raw (self) -> Vec<u8> {
        self.update();
        self.raw
    }

    /// Saves level as a file. This will write new empty Top10 lists.
    pub fn save (&self, _filename: &str) {
        self.update();
        // let file = File::create(&filename).unwrap();
        unimplemented!();
    }

    /// Saves level as a file, without emptying Top10 lists.
    pub fn save_with_top10 (&self, _filename: &str) {
        self.update();
        unimplemented!();
    }
}

/// Decrypt and encrypt top10 list data. Same algorithm for both.
pub fn crypt_top10 (top10_data: &[u8]) -> Vec<u8> {
    let mut top10: Vec<u8> = Vec::with_capacity(688);
    top10.extend_from_slice(top10_data);

    // Some variables to match the original c/asm code?
    let mut ebp8: i16 = 0x15;
    let mut ebp10: i16 = 0x2637;

    for mut t in top10.iter_mut().take(688) {
        *t ^= (ebp8 & 0xFF) as u8;
        ebp10 = ebp10.wrapping_add((ebp8.wrapping_rem(0xD3D)).wrapping_mul(0xD3D));
        ebp8 = ebp10.wrapping_mul(0x1F).wrapping_add(0xD3D);
    }

    top10
}

/// Parse top10 lists and return a vector of `ListEntry`s
pub fn parse_top10 (top10: &[u8]) -> Vec<ListEntry> {
    let mut list: Vec<ListEntry> = vec![];
    let times = LittleEndian::read_i32(&top10[0..4]);
    for n in 0..times {
        let time_offset = (4 + n * 4) as usize;
        let time_end = time_offset + 4;
        let name_1_offset = (44 + n * 15) as usize;
        let name_1_end = name_1_offset + 15;
        let name_2_offset = (194 + n * 15) as usize;
        let name_2_end = name_2_offset + 15;

        let name_1 = &top10[name_1_offset..name_1_end];
        let name_2 = &top10[name_2_offset..name_2_end];
        let time = &top10[time_offset..time_end];
        list.push(ListEntry {
            time: LittleEndian::read_i32(time),
            name_1: trim_string(name_1).unwrap(),
            name_2: trim_string(name_2).unwrap()
        });
    }
    list
}
<|endoftext|>


<commit_before>//! Generic worst-case-linear-time sorting and partitioning algorithms based on
//! [discrim][1][inators][2].  Partially a port of the [Haskell library of the
//! same name][3].
//!
//! [1]:http://www.diku.dk/hjemmesider/ansatte/henglein/papers/henglein2011a.pdf
//! [2]:http://www.diku.dk/hjemmesider/ansatte/henglein/papers/henglein2011c.pdf
//! [3]:https://github.com/ekmett/discrimination

#![cfg_attr(feature = "no_std", no_std)]
#[cfg(feature = "no_std")]
use core as std;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>Eliminate `no_std`<commit_after>//! Generic worst-case-linear-time sorting and partitioning algorithms based on
//! [discrim][1][inators][2].  Partially a port of the [Haskell library of the
//! same name][3].
//!
//! [1]:http://www.diku.dk/hjemmesider/ansatte/henglein/papers/henglein2011a.pdf
//! [2]:http://www.diku.dk/hjemmesider/ansatte/henglein/papers/henglein2011c.pdf
//! [3]:https://github.com/ekmett/discrimination

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>//! Use this library to open a path or URL using the program configured on the system.
//!
//! # Usage
//!
//! The following should open the given URL in a web browser
//!
//! ```test_harness,no_run
//! extern crate open;
//!
//! # #[test]
//! # fn doit() {
//! open::that("http://rust-lang.org").unwrap();
//! # }
//! ```
//! Alternatively, specify the program to open something with. It should expect to receive the path or URL as first argument.
//! ```test_harness,no_run
//! extern crate open;
//!
//! # #[test]
//! # fn doit() {
//! open::with("http://rust-lang.org", "firefox").unwrap();
//! # }
//! ```
//!
//! # Notes
//!
//! As an operating system program is used, chances are that the open operation fails.
//! Therefore, you are advised to at least check the result with `.is_err()` and
//! behave accordingly, e.g. by letting the user know what you tried to open, and failed.
//!
//! ```
//! # fn doit() {
//! match open::that("http://rust-lang.org") {
//!     Ok(exit_status) => {
//!         if exit_status.success() {
//!             println!("Look at your browser!");
//!         } else {
//!             if let Some(code) = exit_status.code() {
//!                 println!("Command returned non-zero exit status {}!", code);
//!             } else {
//!                 println!("Command returned with unknown exit status!");
//!             }
//!         }
//!     }
//!     Err(why) => println!("Failure to execute command: {}", why),
//! }
//! # }
//! ```

use std::{ffi::OsStr, io, process::ExitStatus, thread};

#[cfg(target_os = "windows")]
pub use windows::{that, with};

#[cfg(target_os = "macos")]
pub use macos::{that, with};

#[cfg(any(
    target_os = "linux",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
pub use unix::{that, with};

/// Convenience function for opening the passed path in a new thread.
/// See documentation of `that(...)` for more details.
pub fn that_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    thread::spawn(|| that(path))
}

pub fn with_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
    app: impl Into<String>,
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    let app = app.into();
    thread::spawn(|| with(path, app))
}

#[cfg(windows)]
mod windows {
    use std::{
        ffi::OsStr,
        io,
        os::windows::{ffi::OsStrExt, process::ExitStatusExt},
        process::ExitStatus,
        ptr
    };

    use winapi::ctypes::c_int;
    use winapi::um::shellapi::ShellExecuteW;

    fn convert_path(path: &OsStr) -> io::Result<Vec<u16>> {
        let mut maybe_result: Vec<_> = path.encode_wide().collect();
        if maybe_result.iter().any(|&u| u == 0) {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "path contains NUL byte(s)",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
        const SW_SHOW: c_int = 5;

        let path = convert_path(path.as_ref())?;
        let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
        let result = unsafe {
            ShellExecuteW(
                ptr::null_mut(),
                operation.as_ptr(),
                path.as_ptr(),
                ptr::null(),
                ptr::null(),
                SW_SHOW,
            )
        };
        if result as c_int > 32 {
            Ok(ExitStatus::from_raw(0))
        } else {
            Err(io::Error::last_os_error())
        }
    }

    pub fn with<T: AsRef<OsStr> + Sized>(
        path: T,
        app: impl Into<String>,
    ) -> io::Result<ExitStatus> {
        const SW_SHOW: c_int = 5;

        let path = convert_path(path.as_ref())?;
        let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
        let app_name: Vec<u16> = OsStr::new(&format!("{}\0", app.into()))
            .encode_wide()
            .collect();
        let result = unsafe {
            ShellExecuteW(
                ptr::null_mut(),
                operation.as_ptr(),
                app_name.as_ptr(),
                path.as_ptr(),
                ptr::null(),
                SW_SHOW,
            )
        };
        if result as c_int > 32 {
            Ok(ExitStatus::from_raw(0))
        } else {
            Err(io::Error::last_os_error())
        }
    }
}

#[cfg(target_os = "macos")]
mod macos {
    use std::{
        ffi::OsStr,
        io::Result,
        process::{Command, ExitStatus, Stdio},
    };

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result<ExitStatus> {
        Command::new("open")
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .arg(path.as_ref())
            .spawn()?
            .wait()
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result<ExitStatus> {
        Command::new("open")
            .arg(path.as_ref())
            .arg("-a")
            .arg(app.into())
            .spawn()?
            .wait()
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
mod unix {
    use std::{
        ffi::OsStr,
        io::{Error, Result},
        process::{Command, ExitStatus, Stdio},
    };

    use which::which;

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result<ExitStatus> {
        ["xdg-open", "gnome-open", "kde-open", "wslview"] // Open handlers
            .iter()
            .find(|it| which(it).is_ok()) // find the first handler that exists
            .ok_or(Error::from_raw_os_error(0)) // If not found, return err
            .and_then(|program| {
                // If found run the handler
                Command::new(program)
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .arg(path.as_ref())
                    .spawn()?
                    .wait()
            })
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result<ExitStatus> {
        Command::new(app.into()).arg(path.as_ref()).spawn()?.wait()
    }
}
<commit_msg>run cargo-fmt<commit_after>//! Use this library to open a path or URL using the program configured on the system.
//!
//! # Usage
//!
//! The following should open the given URL in a web browser
//!
//! ```test_harness,no_run
//! extern crate open;
//!
//! # #[test]
//! # fn doit() {
//! open::that("http://rust-lang.org").unwrap();
//! # }
//! ```
//! Alternatively, specify the program to open something with. It should expect to receive the path or URL as first argument.
//! ```test_harness,no_run
//! extern crate open;
//!
//! # #[test]
//! # fn doit() {
//! open::with("http://rust-lang.org", "firefox").unwrap();
//! # }
//! ```
//!
//! # Notes
//!
//! As an operating system program is used, chances are that the open operation fails.
//! Therefore, you are advised to at least check the result with `.is_err()` and
//! behave accordingly, e.g. by letting the user know what you tried to open, and failed.
//!
//! ```
//! # fn doit() {
//! match open::that("http://rust-lang.org") {
//!     Ok(exit_status) => {
//!         if exit_status.success() {
//!             println!("Look at your browser!");
//!         } else {
//!             if let Some(code) = exit_status.code() {
//!                 println!("Command returned non-zero exit status {}!", code);
//!             } else {
//!                 println!("Command returned with unknown exit status!");
//!             }
//!         }
//!     }
//!     Err(why) => println!("Failure to execute command: {}", why),
//! }
//! # }
//! ```

use std::{ffi::OsStr, io, process::ExitStatus, thread};

#[cfg(target_os = "windows")]
pub use windows::{that, with};

#[cfg(target_os = "macos")]
pub use macos::{that, with};

#[cfg(any(
    target_os = "linux",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
pub use unix::{that, with};

/// Convenience function for opening the passed path in a new thread.
/// See documentation of `that(...)` for more details.
pub fn that_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    thread::spawn(|| that(path))
}

pub fn with_in_background<T: AsRef<OsStr> + Sized>(
    path: T,
    app: impl Into<String>,
) -> thread::JoinHandle<io::Result<ExitStatus>> {
    let path = path.as_ref().to_os_string();
    let app = app.into();
    thread::spawn(|| with(path, app))
}

#[cfg(windows)]
mod windows {
    use std::{
        ffi::OsStr,
        io,
        os::windows::{ffi::OsStrExt, process::ExitStatusExt},
        process::ExitStatus,
        ptr,
    };

    use winapi::ctypes::c_int;
    use winapi::um::shellapi::ShellExecuteW;

    fn convert_path(path: &OsStr) -> io::Result<Vec<u16>> {
        let mut maybe_result: Vec<_> = path.encode_wide().collect();
        if maybe_result.iter().any(|&u| u == 0) {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "path contains NUL byte(s)",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> io::Result<ExitStatus> {
        const SW_SHOW: c_int = 5;

        let path = convert_path(path.as_ref())?;
        let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
        let result = unsafe {
            ShellExecuteW(
                ptr::null_mut(),
                operation.as_ptr(),
                path.as_ptr(),
                ptr::null(),
                ptr::null(),
                SW_SHOW,
            )
        };
        if result as c_int > 32 {
            Ok(ExitStatus::from_raw(0))
        } else {
            Err(io::Error::last_os_error())
        }
    }

    pub fn with<T: AsRef<OsStr> + Sized>(
        path: T,
        app: impl Into<String>,
    ) -> io::Result<ExitStatus> {
        const SW_SHOW: c_int = 5;

        let path = convert_path(path.as_ref())?;
        let operation: Vec<u16> = OsStr::new("open\0").encode_wide().collect();
        let app_name: Vec<u16> = OsStr::new(&format!("{}\0", app.into()))
            .encode_wide()
            .collect();
        let result = unsafe {
            ShellExecuteW(
                ptr::null_mut(),
                operation.as_ptr(),
                app_name.as_ptr(),
                path.as_ptr(),
                ptr::null(),
                SW_SHOW,
            )
        };
        if result as c_int > 32 {
            Ok(ExitStatus::from_raw(0))
        } else {
            Err(io::Error::last_os_error())
        }
    }
}

#[cfg(target_os = "macos")]
mod macos {
    use std::{
        ffi::OsStr,
        io::Result,
        process::{Command, ExitStatus, Stdio},
    };

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result<ExitStatus> {
        Command::new("open")
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .arg(path.as_ref())
            .spawn()?
            .wait()
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result<ExitStatus> {
        Command::new("open")
            .arg(path.as_ref())
            .arg("-a")
            .arg(app.into())
            .spawn()?
            .wait()
    }
}

#[cfg(any(
    target_os = "linux",
    target_os = "freebsd",
    target_os = "dragonfly",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "solaris"
))]
mod unix {
    use std::{
        ffi::OsStr,
        io::{Error, Result},
        process::{Command, ExitStatus, Stdio},
    };

    use which::which;

    pub fn that<T: AsRef<OsStr> + Sized>(path: T) -> Result<ExitStatus> {
        ["xdg-open", "gnome-open", "kde-open", "wslview"] // Open handlers
            .iter()
            .find(|it| which(it).is_ok()) // find the first handler that exists
            .ok_or(Error::from_raw_os_error(0)) // If not found, return err
            .and_then(|program| {
                // If found run the handler
                Command::new(program)
                    .stdout(Stdio::null())
                    .stderr(Stdio::null())
                    .arg(path.as_ref())
                    .spawn()?
                    .wait()
            })
    }

    pub fn with<T: AsRef<OsStr> + Sized>(path: T, app: impl Into<String>) -> Result<ExitStatus> {
        Command::new(app.into()).arg(path.as_ref()).spawn()?.wait()
    }
}
<|endoftext|>


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

#![feature(collections, core, linkage, libc, hash, os, std_misc)]
#![allow(non_camel_case_types)]

#[macro_use]
extern crate bitflags;

extern crate libc;
extern crate core;

#[cfg(test)]
extern crate "nix-test" as nixtest;

// Re-export some libc constants
pub use libc::{c_int, c_void};

mod nix;
pub use nix::{NixResult, NixError, NixPath, from_ffi};

#[cfg(unix)]
pub mod errno;

#[cfg(unix)]
pub mod features;

#[cfg(unix)]
pub mod fcntl;

#[cfg(target_os = "linux")]
pub mod mount;

#[cfg(target_os = "linux")]
pub mod sched;

#[cfg(unix)]
pub mod sys;

#[cfg(target_os = "linux")]
pub mod syscall;

#[cfg(unix)]
pub mod unistd;
<commit_msg>Remove hash feature declaration<commit_after>#![crate_name = "nix"]

#![feature(collections, core, linkage, libc, os, std_misc)]
#![allow(non_camel_case_types)]

#[macro_use]
extern crate bitflags;

extern crate libc;
extern crate core;

#[cfg(test)]
extern crate "nix-test" as nixtest;

// Re-export some libc constants
pub use libc::{c_int, c_void};

mod nix;
pub use nix::{NixResult, NixError, NixPath, from_ffi};

#[cfg(unix)]
pub mod errno;

#[cfg(unix)]
pub mod features;

#[cfg(unix)]
pub mod fcntl;

#[cfg(target_os = "linux")]
pub mod mount;

#[cfg(target_os = "linux")]
pub mod sched;

#[cfg(unix)]
pub mod sys;

#[cfg(target_os = "linux")]
pub mod syscall;

#[cfg(unix)]
pub mod unistd;
<|endoftext|>


<commit_before>/*!
    A very high level native gui library for Windows.
*/
/*
    Copyright (C) 2016  Gabriel Dubé

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#![allow(unused_variables)]

extern crate winapi;
extern crate user32;
extern crate kernel32;
extern crate comctl32;

pub mod controls;
pub mod events;
pub mod constants;
pub mod actions;

use std::ptr;
use std::mem;
use std::hash::Hash;
use std::collections::HashMap;

use controls::ControlTemplate;
use constants::Error;

use winapi::{MSG, HWND};
use user32::{GetMessageW, DispatchMessageW, TranslateMessage};

pub type ActionEvaluator<ID> = Box<Fn(&Ui<ID>, &ID, HWND, actions::Action<ID>) -> actions::ActionReturn<ID>>;
type ControlCollection<ID> = HashMap<ID, (HWND, ActionEvaluator<ID>) >;
type CallbackCollection<ID> = HashMap<events::Event, Vec<(ID, events::EventCallback<ID>)>>;

/**
    Structure stored in every window.
*/
struct WindowData<ID: Eq+Clone+Hash > {
    pub id: ID,
    pub _type: constants::ControlType,
    pub controls: *mut ControlCollection<ID>,
    pub callbacks: CallbackCollection<ID>
}

/**
    A single threaded window manager.
*/
pub struct Ui<ID: Eq+Clone+Hash > {
    controls: *mut ControlCollection<ID>
}

impl<ID: Eq+Clone+Hash> Ui<ID> {

    /**
        Creates a new `Ui` that will manage the interface on the
        current thread.
    */
    pub fn new() -> Ui<ID> {
        let controls = ControlCollection::<ID>::new();
        let controls_raw = Box::into_raw(Box::new(controls));

        unsafe { ::controls::base::enable_visual_styles(); }

        Ui{controls: controls_raw}
    }

    /**
        Create a new control in the ui manager from the provided template
        and associate it with the ID provided by the user.

        If the control creation succeeded, return the id used by the user.

        If the control creation somehow failed return `Err`
    */
    pub fn new_control<T:ControlTemplate<ID>>(&mut self, cont: ID, template: T) -> Result<ID, Error> {
        let controls: &mut ControlCollection<ID> = unsafe{ &mut *self.controls };

        if !controls.contains_key(&cont) {
            let handle: HWND;
            match template.create(self, cont.clone()) {
                Ok(h) => handle = h,
                Err(_) => {
                    return Err(Error::TEMPLATE_CREATION);  // TODO propagate details about the error
                }
            }

            // Store the window data
            let mut callbacks = HashMap::new();
            for e in template.supported_events() {
                callbacks.insert(e, Vec::new());
            }

            let data = WindowData {
                id: cont.clone(),
                _type: template.control_type(),
                controls: self.controls,
                callbacks: callbacks,
            };
            controls::set_handle_data(handle, data);

            controls.insert(cont.clone(), (handle, template.evaluator()) );

            Ok(cont)
        } else {
            Err(Error::CONTROL_EXISTS) // Error: A widget with this id already exists
        }

    }

    /**
        Remove the control and ALL its children from the gui.
        If successful, return a vector of all deleted IDS.

        The control destruction is delayed.

        Return an error if the control was not found.
    */
    pub fn remove_control(&mut self, cont: ID) -> Result<Vec<ID>, Error> {
        let mut deleted_controls: Vec<ID>;
        let controls: &mut ControlCollection<ID> = unsafe{ &mut *self.controls };
        if let Some((handle, exec)) = controls.remove(&cont) {
            if let actions::ActionReturn::Children(c) = exec(self, &cont, handle, actions::Action::GetDescendants) {
                deleted_controls = *c;
            } else {
                deleted_controls = Vec::with_capacity(1); // Control can't have children
            }

            // Free the control and the control children's handle data.
            controls::free_handle::<ID>(handle);
        } else {
            return Err(Error::CONTROL_NOT_FOUND);
        }

        for id in deleted_controls.iter() {
            controls.remove(id).unwrap();
        }

        deleted_controls.push(cont);
        Ok(deleted_controls)
    }

    /**
        Add a callback to a control. Return Ok if the callback was added
        successfully, Err(reason) if `cont` was not found in ui.

        * cont : ID of the control to add the event to
        * name : Name of the event (used for unbinding)
        * cb   : The callback
    */
    pub fn bind(&self, cont: ID, name: ID, cb: events::EventCallback<ID>) -> Result<(), Error> {
        let controls: &mut ControlCollection<ID> = unsafe{ &mut *self.controls };
        if let Some(&(handle, _)) = controls.get(&cont) {
            let event = events::map_callback(&cb);
            let data: &mut WindowData<ID> = controls::get_handle_data(handle);
            if let Some(functions) = data.callbacks.get_mut(&event) {
                if functions.iter().any(|&(ref id, _)| hash(id) == hash(&name)) {
                    Err(Error::CALLBACK_ID_EXISTS)
                } else {
                    functions.push((name, cb));
                    Ok(())
                }
            } else {
                Err(Error::CALLBACK_NOT_SUPPORTED)
            }
        } else {
            Err(Error::CONTROL_NOT_FOUND)
        }
    }

    /**
        Remove a callback from a control. Return Ok if the callback was added
        successfully, Err(reason) if `cont` or `name` were not found in ui.

        * cont  : ID of the control to remove the event from
        * name  : Name of the event to unbind
        * event : Event type to unbind
    */
    pub fn unbind(&self, cont: ID, name: ID, event: events::Event) -> Result<(), Error> {
        let controls: &mut ControlCollection<ID> = unsafe{ &mut *self.controls };
        let _hash = hash(&name);
        if let Some(&(handle, _)) = controls.get(&cont) {
            let data: &mut WindowData<ID> = controls::get_handle_data(handle);
            if let Some(functions) = data.callbacks.get_mut(&event) {
                if let Some(pos) = functions.iter().position(|&(ref id, _)| hash(id) == _hash) {
                    functions.remove(pos);
                    Ok(())
                } else {
                    Err(Error::CALLBACK_ID_NOT_FOUND)
                }
            } else {
                Err(Error::CALLBACK_NOT_SUPPORTED)
            }
        } else {
            Err(Error::CONTROL_NOT_FOUND)
        }
    }

    /**
        Execute an action on the specified control
    */
    pub fn exec(&self, cont: ID, action: actions::Action<ID>) -> Result<actions::ActionReturn<ID>, Error> {
        let controls: &mut ControlCollection<ID> = unsafe{ &mut *self.controls };
        if let Some(&(handle, ref exec)) = controls.get(&cont) {
            Ok(exec(self, &cont, handle, action))
        } else {
            Err(Error::CONTROL_NOT_FOUND)
        }
    }

}

impl<ID: Eq+Clone+Hash> Drop for Ui<ID> {
    fn drop(&mut self) {
        let controls: &mut ControlCollection<ID> = unsafe{ &mut *self.controls };
        let handles: Vec<ID> = controls.keys().map(|k| k.clone()).collect();
        let mut handles_clone = handles.into_iter();

        // While there are still controls, call remove_control, because remove_control
        // also remove the children, handles_clone may pass controls that were freed
        // we can safely ignore them
        while !controls.is_empty() {
            if let Some(next_handle) = handles_clone.next() {
                match self.remove_control(next_handle) {_=>{}} // Ignore the ID not found while cleaning the controls
            } else {
                break;
            }
        }

        unsafe { Box::from_raw(self.controls); }
    }
}

impl<ID: Eq+Clone+Hash> !Send for Ui<ID> {}
impl<ID: Eq+Clone+Hash> !Sync for Ui<ID> {}

/**
    Wait for system events and dispatch them
*/
pub fn dispatch_events() { unsafe{
    let mut msg: MSG = mem::uninitialized();
    while GetMessageW(&mut msg, ptr::null_mut(), 0, 0) != 0 {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }
}}

/**
    Hash a single parameter. Used to compare events name, which do not use a hashmap.
*/
fn hash<T: Hash>(t: &T) -> u64 {
    use std::hash::Hasher;
    use std::collections::hash_map::DefaultHasher;
    let mut s = DefaultHasher::new();
    t.hash(&mut s);
    s.finish()
}
<commit_msg>remove !sync !send cuz its not stable yet<commit_after>/*!
    A very high level native gui library for Windows.
*/
/*
    Copyright (C) 2016  Gabriel Dubé

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#![allow(unused_variables)]

extern crate winapi;
extern crate user32;
extern crate kernel32;
extern crate comctl32;

pub mod controls;
pub mod events;
pub mod constants;
pub mod actions;

use std::ptr;
use std::mem;
use std::hash::Hash;
use std::collections::HashMap;

use controls::ControlTemplate;
use constants::Error;

use winapi::{MSG, HWND};
use user32::{GetMessageW, DispatchMessageW, TranslateMessage};

pub type ActionEvaluator<ID> = Box<Fn(&Ui<ID>, &ID, HWND, actions::Action<ID>) -> actions::ActionReturn<ID>>;
type ControlCollection<ID> = HashMap<ID, (HWND, ActionEvaluator<ID>) >;
type CallbackCollection<ID> = HashMap<events::Event, Vec<(ID, events::EventCallback<ID>)>>;

/**
    Structure stored in every window.
*/
struct WindowData<ID: Eq+Clone+Hash > {
    pub id: ID,
    pub _type: constants::ControlType,
    pub controls: *mut ControlCollection<ID>,
    pub callbacks: CallbackCollection<ID>
}

/**
    A single threaded window manager.
*/
pub struct Ui<ID: Eq+Clone+Hash > {
    controls: *mut ControlCollection<ID>
}

impl<ID: Eq+Clone+Hash> Ui<ID> {

    /**
        Creates a new `Ui` that will manage the interface on the
        current thread.
    */
    pub fn new() -> Ui<ID> {
        let controls = ControlCollection::<ID>::new();
        let controls_raw = Box::into_raw(Box::new(controls));

        unsafe { ::controls::base::enable_visual_styles(); }

        Ui{controls: controls_raw}
    }

    /**
        Create a new control in the ui manager from the provided template
        and associate it with the ID provided by the user.

        If the control creation succeeded, return the id used by the user.

        If the control creation somehow failed return `Err`
    */
    pub fn new_control<T:ControlTemplate<ID>>(&mut self, cont: ID, template: T) -> Result<ID, Error> {
        let controls: &mut ControlCollection<ID> = unsafe{ &mut *self.controls };

        if !controls.contains_key(&cont) {
            let handle: HWND;
            match template.create(self, cont.clone()) {
                Ok(h) => handle = h,
                Err(_) => {
                    return Err(Error::TEMPLATE_CREATION);  // TODO propagate details about the error
                }
            }

            // Store the window data
            let mut callbacks = HashMap::new();
            for e in template.supported_events() {
                callbacks.insert(e, Vec::new());
            }

            let data = WindowData {
                id: cont.clone(),
                _type: template.control_type(),
                controls: self.controls,
                callbacks: callbacks,
            };
            controls::set_handle_data(handle, data);

            controls.insert(cont.clone(), (handle, template.evaluator()) );

            Ok(cont)
        } else {
            Err(Error::CONTROL_EXISTS) // Error: A widget with this id already exists
        }

    }

    /**
        Remove the control and ALL its children from the gui.
        If successful, return a vector of all deleted IDS.

        The control destruction is delayed.

        Return an error if the control was not found.
    */
    pub fn remove_control(&mut self, cont: ID) -> Result<Vec<ID>, Error> {
        let mut deleted_controls: Vec<ID>;
        let controls: &mut ControlCollection<ID> = unsafe{ &mut *self.controls };
        if let Some((handle, exec)) = controls.remove(&cont) {
            if let actions::ActionReturn::Children(c) = exec(self, &cont, handle, actions::Action::GetDescendants) {
                deleted_controls = *c;
            } else {
                deleted_controls = Vec::with_capacity(1); // Control can't have children
            }

            // Free the control and the control children's handle data.
            controls::free_handle::<ID>(handle);
        } else {
            return Err(Error::CONTROL_NOT_FOUND);
        }

        for id in deleted_controls.iter() {
            controls.remove(id).unwrap();
        }

        deleted_controls.push(cont);
        Ok(deleted_controls)
    }

    /**
        Add a callback to a control. Return Ok if the callback was added
        successfully, Err(reason) if `cont` was not found in ui.

        * cont : ID of the control to add the event to
        * name : Name of the event (used for unbinding)
        * cb   : The callback
    */
    pub fn bind(&self, cont: ID, name: ID, cb: events::EventCallback<ID>) -> Result<(), Error> {
        let controls: &mut ControlCollection<ID> = unsafe{ &mut *self.controls };
        if let Some(&(handle, _)) = controls.get(&cont) {
            let event = events::map_callback(&cb);
            let data: &mut WindowData<ID> = controls::get_handle_data(handle);
            if let Some(functions) = data.callbacks.get_mut(&event) {
                if functions.iter().any(|&(ref id, _)| hash(id) == hash(&name)) {
                    Err(Error::CALLBACK_ID_EXISTS)
                } else {
                    functions.push((name, cb));
                    Ok(())
                }
            } else {
                Err(Error::CALLBACK_NOT_SUPPORTED)
            }
        } else {
            Err(Error::CONTROL_NOT_FOUND)
        }
    }

    /**
        Remove a callback from a control. Return Ok if the callback was added
        successfully, Err(reason) if `cont` or `name` were not found in ui.

        * cont  : ID of the control to remove the event from
        * name  : Name of the event to unbind
        * event : Event type to unbind
    */
    pub fn unbind(&self, cont: ID, name: ID, event: events::Event) -> Result<(), Error> {
        let controls: &mut ControlCollection<ID> = unsafe{ &mut *self.controls };
        let _hash = hash(&name);
        if let Some(&(handle, _)) = controls.get(&cont) {
            let data: &mut WindowData<ID> = controls::get_handle_data(handle);
            if let Some(functions) = data.callbacks.get_mut(&event) {
                if let Some(pos) = functions.iter().position(|&(ref id, _)| hash(id) == _hash) {
                    functions.remove(pos);
                    Ok(())
                } else {
                    Err(Error::CALLBACK_ID_NOT_FOUND)
                }
            } else {
                Err(Error::CALLBACK_NOT_SUPPORTED)
            }
        } else {
            Err(Error::CONTROL_NOT_FOUND)
        }
    }

    /**
        Execute an action on the specified control
    */
    pub fn exec(&self, cont: ID, action: actions::Action<ID>) -> Result<actions::ActionReturn<ID>, Error> {
        let controls: &mut ControlCollection<ID> = unsafe{ &mut *self.controls };
        if let Some(&(handle, ref exec)) = controls.get(&cont) {
            Ok(exec(self, &cont, handle, action))
        } else {
            Err(Error::CONTROL_NOT_FOUND)
        }
    }

}

impl<ID: Eq+Clone+Hash> Drop for Ui<ID> {
    fn drop(&mut self) {
        let controls: &mut ControlCollection<ID> = unsafe{ &mut *self.controls };
        let handles: Vec<ID> = controls.keys().map(|k| k.clone()).collect();
        let mut handles_clone = handles.into_iter();

        // While there are still controls, call remove_control, because remove_control
        // also remove the children, handles_clone may pass controls that were freed
        // we can safely ignore them
        while !controls.is_empty() {
            if let Some(next_handle) = handles_clone.next() {
                match self.remove_control(next_handle) {_=>{}} // Ignore the ID not found while cleaning the controls
            } else {
                break;
            }
        }

        unsafe { Box::from_raw(self.controls); }
    }
}

/**
    Wait for system events and dispatch them
*/
pub fn dispatch_events() { unsafe{
    let mut msg: MSG = mem::uninitialized();
    while GetMessageW(&mut msg, ptr::null_mut(), 0, 0) != 0 {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }
}}

/**
    Hash a single parameter. Used to compare events name, which do not use a hashmap.
*/
fn hash<T: Hash>(t: &T) -> u64 {
    use std::hash::Hasher;
    use std::collections::hash_map::DefaultHasher;
    let mut s = DefaultHasher::new();
    t.hash(&mut s);
    s.finish()
}
<|endoftext|>