<commit_before>use std::ptr;
use gl;
use gl::types::*;
use nalgebra::na::{Vec2, Vec3, Mat3, Mat4, Iso3};
use nalgebra::na;
use resource::Material;
use scene::ObjectData;
use light::{Light, Absolute, StickToCamera};
use camera::Camera;
use resource::{Mesh, Shader, ShaderAttribute, ShaderUniform};

#[path = "../error.rs"]
mod error;

/// The default material used to draw objects.
pub struct ObjectMaterial {
    shader:     Shader,
    pos:        ShaderAttribute<Vec3<f32>>,
    normal:     ShaderAttribute<Vec3<f32>>,
    tex_coord:  ShaderAttribute<Vec2<f32>>,
    light:      ShaderUniform<Vec3<f32>>,
    color:      ShaderUniform<Vec3<f32>>,
    transform:  ShaderUniform<Mat4<f32>>,
    scale:      ShaderUniform<Mat3<f32>>,
    ntransform: ShaderUniform<Mat3<f32>>,
    view:       ShaderUniform<Mat4<f32>>,
    tex:        ShaderUniform<GLuint>
}

impl ObjectMaterial {
    /// Creates a new `ObjectMaterial`.
    pub fn new() -> ObjectMaterial {
        // load the shader
        let mut shader = Shader::new_from_str(OBJECT_VERTEX_SRC, OBJECT_FRAGMENT_SRC);

        shader.use_program();

        // get the variables locations
        ObjectMaterial {
            pos:        shader.get_attrib("position").unwrap(),
            normal:     shader.get_attrib("normal").unwrap(),
            tex_coord:  shader.get_attrib("tex_coord_v").unwrap(),
            light:      shader.get_uniform("light_position").unwrap(),
            color:      shader.get_uniform("color").unwrap(),
            transform:  shader.get_uniform("transform").unwrap(),
            scale:      shader.get_uniform("scale").unwrap(),
            ntransform: shader.get_uniform("ntransform").unwrap(),
            view:       shader.get_uniform("view").unwrap(),
            tex:        shader.get_uniform("tex").unwrap(),
            shader:     shader
        }
    }

    fn activate(&mut self) {
        self.shader.use_program();
        self.pos.enable();
        self.normal.enable();
        self.tex_coord.enable();
    }

    fn deactivate(&mut self) {
        self.pos.disable();
        self.normal.disable();
        self.tex_coord.disable();
    }
}

impl Material for ObjectMaterial {
    fn render(&mut self,
              pass:      uint,
              transform: &Iso3<f32>,
              scale:     &Vec3<f32>,
              camera:    &mut Camera,
              light:     &Light,
              data:      &ObjectData,
              mesh:      &mut Mesh) {
        self.activate();

        /*
         *
         * Setup camera and light.
         *
         */
        camera.upload(pass, &mut self.view);

        let pos = match *light {
            Absolute(ref p) => p.clone(),
            StickToCamera   => camera.eye()
        };

        self.light.upload(&pos);

        /*
         *
         * Setup object-related stuffs.
         *
         */
        let formated_transform:  Mat4<f32> = na::to_homogeneous(transform);
        let formated_ntransform: Mat3<f32> = *transform.rotation.submat();
        let formated_scale:      Mat3<f32> = Mat3::new(scale.x, 0.0, 0.0, 0.0, scale.y, 0.0, 0.0, 0.0, scale.z);

        unsafe {
            self.transform.upload(&formated_transform);
            self.ntransform.upload(&formated_ntransform);
            self.scale.upload(&formated_scale);
            self.color.upload(data.color());

            mesh.bind(&mut self.pos, &mut self.normal, &mut self.tex_coord);

            verify!(gl::ActiveTexture(gl::TEXTURE0));
            verify!(gl::BindTexture(gl::TEXTURE_2D, data.texture().id()));

            if data.surface_rendering_active() {
                if data.backface_culling_enabled() {
                    verify!(gl::Enable(gl::CULL_FACE));
                }
                else {
                    verify!(gl::Disable(gl::CULL_FACE));
                }

                verify!(gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL));
                verify!(gl::DrawElements(
                            gl::POINTS,
                            mesh.num_pts() as GLint,
                            gl::UNSIGNED_INT,
                            ptr::null()));
            }

            if data.lines_width() != 0.0 {
                verify!(gl::Disable(gl::CULL_FACE));
                verify!(gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE));
                gl::LineWidth(data.lines_width());
                verify!(gl::DrawElements(
                            gl::TRIANGLES,
                            mesh.num_pts() as GLint,
                            gl::UNSIGNED_INT,
                            ptr::null()));
                gl::LineWidth(1.0);
            }

            if data.points_size() != 0.0 {
                verify!(gl::Disable(gl::CULL_FACE));
                verify!(gl::PolygonMode(gl::FRONT_AND_BACK, gl::POINT));
                gl::PointSize(data.points_size());
                verify!(gl::DrawElements(
                            gl::TRIANGLES,
                            mesh.num_pts() as GLint,
                            gl::UNSIGNED_INT,
                            ptr::null()));
                gl::PointSize(1.0);
            }
        }

        mesh.unbind();
        self.deactivate();
    }
}

/// Vertex shader of the default object material.
pub static OBJECT_VERTEX_SRC:   &'static str = A_VERY_LONG_STRING;
/// Fragment shader of the default object material.
pub static OBJECT_FRAGMENT_SRC: &'static str = ANOTHER_VERY_LONG_STRING;

static A_VERY_LONG_STRING: &'static str =
   "#version 120
    attribute vec3 position;
    attribute vec3 normal;
    attribute vec3 color;
    attribute vec2 tex_coord_v;
    varying vec3 ws_normal;
    varying vec3 ws_position;
    varying vec2 tex_coord;
    uniform mat4 view;
    uniform mat4 transform;
    uniform mat3 scale;
    uniform mat3 ntransform;
    void main() {
        mat4 scale4 = mat4(scale);
        vec4 pos4   = transform * scale4 * vec4(position, 1.0);
        tex_coord   = tex_coord_v;
        ws_position = pos4.xyz;
        gl_Position = view * pos4;
        ws_normal   = normalize(ntransform * scale * normal);
    }";

// phong lighting (heavily) inspired
// by http://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/lighting.php
static ANOTHER_VERY_LONG_STRING: &'static str =
   "#version 120
    uniform vec3      color;
    uniform vec3      light_position;
    uniform sampler2D tex;
    varying vec2      tex_coord;
    varying vec3      ws_normal;
    varying vec3      ws_position;
    void main() {
      vec3 L = normalize(light_position - ws_position);
      vec3 E = normalize(-ws_position);

      //calculate Ambient Term:
      vec4 Iamb = vec4(color, 1.0);

      //calculate Diffuse Term:
      vec4 Idiff1 = vec4(1.0, 1.0, 1.0, 1.0) * max(dot(ws_normal,L), 0.0);
      Idiff1 = clamp(Idiff1, 0.0, 1.0);

      // double sided lighting:
      vec4 Idiff2 = vec4(1.0, 1.0, 1.0, 1.0) * max(dot(-ws_normal,L), 0.0);
      Idiff2 = clamp(Idiff2, 0.0, 1.0);

      vec4 tex_color = texture2D(tex, tex_coord);
      gl_FragColor   = tex_color * (Iamb + (Idiff1 + Idiff2) / 2) / 2;
    }";
<commit_msg>Clear exeperiment<commit_after>use std::ptr;
use gl;
use gl::types::*;
use nalgebra::na::{Vec2, Vec3, Mat3, Mat4, Iso3};
use nalgebra::na;
use resource::Material;
use scene::ObjectData;
use light::{Light, Absolute, StickToCamera};
use camera::Camera;
use resource::{Mesh, Shader, ShaderAttribute, ShaderUniform};

#[path = "../error.rs"]
mod error;

/// The default material used to draw objects.
pub struct ObjectMaterial {
    shader:     Shader,
    pos:        ShaderAttribute<Vec3<f32>>,
    normal:     ShaderAttribute<Vec3<f32>>,
    tex_coord:  ShaderAttribute<Vec2<f32>>,
    light:      ShaderUniform<Vec3<f32>>,
    color:      ShaderUniform<Vec3<f32>>,
    transform:  ShaderUniform<Mat4<f32>>,
    scale:      ShaderUniform<Mat3<f32>>,
    ntransform: ShaderUniform<Mat3<f32>>,
    view:       ShaderUniform<Mat4<f32>>,
    tex:        ShaderUniform<GLuint>
}

impl ObjectMaterial {
    /// Creates a new `ObjectMaterial`.
    pub fn new() -> ObjectMaterial {
        // load the shader
        let mut shader = Shader::new_from_str(OBJECT_VERTEX_SRC, OBJECT_FRAGMENT_SRC);

        shader.use_program();

        // get the variables locations
        ObjectMaterial {
            pos:        shader.get_attrib("position").unwrap(),
            normal:     shader.get_attrib("normal").unwrap(),
            tex_coord:  shader.get_attrib("tex_coord_v").unwrap(),
            light:      shader.get_uniform("light_position").unwrap(),
            color:      shader.get_uniform("color").unwrap(),
            transform:  shader.get_uniform("transform").unwrap(),
            scale:      shader.get_uniform("scale").unwrap(),
            ntransform: shader.get_uniform("ntransform").unwrap(),
            view:       shader.get_uniform("view").unwrap(),
            tex:        shader.get_uniform("tex").unwrap(),
            shader:     shader
        }
    }

    fn activate(&mut self) {
        self.shader.use_program();
        self.pos.enable();
        self.normal.enable();
        self.tex_coord.enable();
    }

    fn deactivate(&mut self) {
        self.pos.disable();
        self.normal.disable();
        self.tex_coord.disable();
    }
}

impl Material for ObjectMaterial {
    fn render(&mut self,
              pass:      uint,
              transform: &Iso3<f32>,
              scale:     &Vec3<f32>,
              camera:    &mut Camera,
              light:     &Light,
              data:      &ObjectData,
              mesh:      &mut Mesh) {
        self.activate();

        /*
         *
         * Setup camera and light.
         *
         */
        camera.upload(pass, &mut self.view);

        let pos = match *light {
            Absolute(ref p) => p.clone(),
            StickToCamera   => camera.eye()
        };

        self.light.upload(&pos);

        /*
         *
         * Setup object-related stuffs.
         *
         */
        let formated_transform:  Mat4<f32> = na::to_homogeneous(transform);
        let formated_ntransform: Mat3<f32> = *transform.rotation.submat();
        let formated_scale:      Mat3<f32> = Mat3::new(scale.x, 0.0, 0.0, 0.0, scale.y, 0.0, 0.0, 0.0, scale.z);

        unsafe {
            self.transform.upload(&formated_transform);
            self.ntransform.upload(&formated_ntransform);
            self.scale.upload(&formated_scale);
            self.color.upload(data.color());

            mesh.bind(&mut self.pos, &mut self.normal, &mut self.tex_coord);

            verify!(gl::ActiveTexture(gl::TEXTURE0));
            verify!(gl::BindTexture(gl::TEXTURE_2D, data.texture().id()));

            if data.surface_rendering_active() {
                if data.backface_culling_enabled() {
                    verify!(gl::Enable(gl::CULL_FACE));
                }
                else {
                    verify!(gl::Disable(gl::CULL_FACE));
                }

                verify!(gl::PolygonMode(gl::FRONT_AND_BACK, gl::FILL));
                verify!(gl::DrawElements(
                            gl::TRIANGLES,
                            mesh.num_pts() as GLint,
                            gl::UNSIGNED_INT,
                            ptr::null()));
            }

            if data.lines_width() != 0.0 {
                verify!(gl::Disable(gl::CULL_FACE));
                verify!(gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE));
                gl::LineWidth(data.lines_width());
                verify!(gl::DrawElements(
                            gl::TRIANGLES,
                            mesh.num_pts() as GLint,
                            gl::UNSIGNED_INT,
                            ptr::null()));
                gl::LineWidth(1.0);
            }

            if data.points_size() != 0.0 {
                verify!(gl::Disable(gl::CULL_FACE));
                verify!(gl::PolygonMode(gl::FRONT_AND_BACK, gl::POINT));
                gl::PointSize(data.points_size());
                verify!(gl::DrawElements(
                            gl::TRIANGLES,
                            mesh.num_pts() as GLint,
                            gl::UNSIGNED_INT,
                            ptr::null()));
                gl::PointSize(1.0);
            }
        }

        mesh.unbind();
        self.deactivate();
    }
}

/// Vertex shader of the default object material.
pub static OBJECT_VERTEX_SRC:   &'static str = A_VERY_LONG_STRING;
/// Fragment shader of the default object material.
pub static OBJECT_FRAGMENT_SRC: &'static str = ANOTHER_VERY_LONG_STRING;

static A_VERY_LONG_STRING: &'static str =
   "#version 120
    attribute vec3 position;
    attribute vec3 normal;
    attribute vec3 color;
    attribute vec2 tex_coord_v;
    varying vec3 ws_normal;
    varying vec3 ws_position;
    varying vec2 tex_coord;
    uniform mat4 view;
    uniform mat4 transform;
    uniform mat3 scale;
    uniform mat3 ntransform;
    void main() {
        mat4 scale4 = mat4(scale);
        vec4 pos4   = transform * scale4 * vec4(position, 1.0);
        tex_coord   = tex_coord_v;
        ws_position = pos4.xyz;
        gl_Position = view * pos4;
        ws_normal   = normalize(ntransform * scale * normal);
    }";

// phong lighting (heavily) inspired
// by http://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/lighting.php
static ANOTHER_VERY_LONG_STRING: &'static str =
   "#version 120
    uniform vec3      color;
    uniform vec3      light_position;
    uniform sampler2D tex;
    varying vec2      tex_coord;
    varying vec3      ws_normal;
    varying vec3      ws_position;
    void main() {
      vec3 L = normalize(light_position - ws_position);
      vec3 E = normalize(-ws_position);

      //calculate Ambient Term:
      vec4 Iamb = vec4(color, 1.0);

      //calculate Diffuse Term:
      vec4 Idiff1 = vec4(1.0, 1.0, 1.0, 1.0) * max(dot(ws_normal,L), 0.0);
      Idiff1 = clamp(Idiff1, 0.0, 1.0);

      // double sided lighting:
      vec4 Idiff2 = vec4(1.0, 1.0, 1.0, 1.0) * max(dot(-ws_normal,L), 0.0);
      Idiff2 = clamp(Idiff2, 0.0, 1.0);

      vec4 tex_color = texture2D(tex, tex_coord);
      gl_FragColor   = tex_color * (Iamb + (Idiff1 + Idiff2) / 2) / 2;
    }";
<|endoftext|>


<commit_before>// Traits can have associated types:
#![feature(collections)]

use std::fmt::Debug;

// Help from @ogeon:
//   http://users.rust-lang.org/t/trait-objects-with-associated-types/746/19

trait T : Debug {
    type t;
    fn get (self:&Self) -> Self::t ;
    fn doit (self:&Self, Self::t ) -> String ;
}

trait Tabs : Debug {
    fn doit_abs (self:&Self) -> String ;
}

impl <A, B: T<t=A>> Tabs for B {
    fn doit_abs (self:&Self) -> String {
        self.doit ( self.get () )
    }
}

#[derive(Debug)]
pub enum Foo { Foo }

#[derive(Debug)]
pub enum Bar { Bar }

impl T for Foo {
    type t = String;
    fn get (self:&Self) -> String { String::from_str("foo") }
    fn doit (self:&Self, s:Self::t) -> String { s }
}

impl T for Bar {
    type t = u32;
    fn get (self:&Self) -> u32 { 0 }
    fn doit (self:&Self, _s:Self::t) -> String { String::from_str("bar") }
}

#[derive(Debug)]
struct Packed {
    two : (Box<Tabs>,Box<Tabs>)
}

pub fn main () {
    let a = Packed { two : (Box::new(Foo::Foo),
                            Box::new(Bar::Bar)) } ;
     println!("{:?}", a);
}
<commit_msg>help from @ogeon<commit_after>// Traits can have associated types:
#![feature(collections)]

use std::fmt::Debug;

// Help from @ogeon:
//   http://users.rust-lang.org/t/trait-objects-with-associated-types/746/19

trait T : Debug {
    type t;
    fn get (self:&Self) -> Self::t ;
    fn doit (self:&Self, Self::t ) -> String ;
}

trait S : Debug {
    fn doit_abs (self:&Self) -> String ;
}

#[derive(Debug)]
struct Packed {
    two : (Box<S>,Box<S>)
}

impl <A, B: T<t=A>> S for B {
    fn doit_abs (self:&Self) -> String {
        self.doit ( self.get () )
    }
}

// ----------------------------------------

#[derive(Debug)]
pub enum Foo { Foo }

#[derive(Debug)]
pub enum Bar { Bar }

impl T for Foo {
    type t = String;
    fn get (self:&Self) -> String { String::from_str("foo") }
    fn doit (self:&Self, s:Self::t) -> String { s }
}

impl T for Bar {
    type t = u32;
    fn get (self:&Self) -> u32 { 0 }
    fn doit (self:&Self, _s:Self::t) -> String { String::from_str("bar") }
}

pub fn main () {
    let a = Packed { two : (Box::new(Foo::Foo),
                            Box::new(Bar::Bar)) } ;
     println!("{:?}", a);
}
<|endoftext|>


<commit_before>// Claxon -- A FLAC decoding library in Rust
// Copyright (C) 2014-2015 Ruud van Asseldonk
//
// 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(unstable)]

extern crate claxon;

fn run_metaflac(fname: &Path) -> String {
    use std::old_io::Command;

    // Run metaflac on the specified file and print all streaminfo data.
    let mut child = Command::new("metaflac")
                        .arg("--show-min-blocksize")
                        .arg("--show-max-blocksize")
                        .arg("--show-min-framesize")
                        .arg("--show-max-framesize")
                        .arg("--show-sample-rate")
                        .arg("--show-channels")
                        .arg("--show-bps")
                        .arg("--show-total-samples")
                        .arg("--show-md5sum")
                        .arg(fname.as_str().expect("unsupported filename"))
                        .spawn().ok().expect("failed to run metaflac");

    assert!(child.wait().unwrap().success());

    let output = match child.stdout {
        Some(ref mut stdout) => stdout.read_to_string().ok()
                                      .expect("failed to read metaflac stdout"),
        None => panic!("failed to open metaflac stdout")
    };

    output
}

fn print_hex(seq: &[u8]) -> String {
    let vec: Vec<String> = seq.iter().map(|x| format!("{:0>2x}", *x)).collect();
    vec.concat()
}

fn read_streaminfo(fname: &Path) -> String {
    use std::old_io::fs::File;
    use std::old_io::BufferedReader;
    use claxon::FlacStream;

    // Use a buffered reader, this speeds up the test by 120%.
    let file = File::open(fname).unwrap();
    let mut reader = BufferedReader::new(file);
    let stream = FlacStream::new(&mut reader).unwrap();
    let streaminfo = stream.streaminfo();

    // Format the streaminfo in the same way that metaflac prints it.
    format!("{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n",
            streaminfo.min_block_size,
            streaminfo.max_block_size,
            streaminfo.min_frame_size.unwrap_or(0),
            streaminfo.max_frame_size.unwrap_or(0),
            streaminfo.sample_rate,
            streaminfo.n_channels,
            streaminfo.bits_per_sample,
            streaminfo.n_samples.unwrap_or(0),
            print_hex(&streaminfo.md5sum)) // TODO implement LowerHex for &[u8] and submit a PR.
}

fn compare_metaflac(fname: &Path) {
    let metaflac = run_metaflac(fname);
    let streaminfo = read_streaminfo(fname);
    let mut mf_lines = metaflac.lines_any();
    let mut si_lines = streaminfo.lines_any();
    while let (Some(mf), Some(si)) = (mf_lines.next(), si_lines.next()) {
        if mf != si {
            println!("metaflac\n--------\n{}", metaflac);
            println!("streaminfo\n----------\n{}", streaminfo);
            panic!("metaflac disagrees on parsed streaminfo");
        }
    };
}

#[test]
fn verify_streaminfo() {
    use std::old_io::fs::{readdir, PathExtensions};

    // Compare our streaminfo parsing with metaflac on all flac files in the
    // testsamples directory.
    let dir = readdir(&Path::new("testsamples")).ok().expect("failed to enumerate flac files");
    for path in dir.iter() {
        if path.is_file() && path.extension_str() == Some("flac") {
            print!("    comparing {} ...", path.as_str().expect("unsupported filename"));
            compare_metaflac(path);
            println!(" ok");
        }
    }
}
<commit_msg>silence warnings in tests for now<commit_after>// Claxon -- A FLAC decoding library in Rust
// Copyright (C) 2014-2015 Ruud van Asseldonk
//
// 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/>.

#![feature(io, path)]

extern crate claxon;

fn run_metaflac(fname: &Path) -> String {
    use std::old_io::Command;

    // Run metaflac on the specified file and print all streaminfo data.
    let mut child = Command::new("metaflac")
                        .arg("--show-min-blocksize")
                        .arg("--show-max-blocksize")
                        .arg("--show-min-framesize")
                        .arg("--show-max-framesize")
                        .arg("--show-sample-rate")
                        .arg("--show-channels")
                        .arg("--show-bps")
                        .arg("--show-total-samples")
                        .arg("--show-md5sum")
                        .arg(fname.as_str().expect("unsupported filename"))
                        .spawn().ok().expect("failed to run metaflac");

    assert!(child.wait().unwrap().success());

    let output = match child.stdout {
        Some(ref mut stdout) => stdout.read_to_string().ok()
                                      .expect("failed to read metaflac stdout"),
        None => panic!("failed to open metaflac stdout")
    };

    output
}

fn print_hex(seq: &[u8]) -> String {
    let vec: Vec<String> = seq.iter().map(|x| format!("{:0>2x}", *x)).collect();
    vec.concat()
}

fn read_streaminfo(fname: &Path) -> String {
    use std::old_io::fs::File;
    use std::old_io::BufferedReader;
    use claxon::FlacStream;

    // Use a buffered reader, this speeds up the test by 120%.
    let file = File::open(fname).unwrap();
    let mut reader = BufferedReader::new(file);
    let stream = FlacStream::new(&mut reader).unwrap();
    let streaminfo = stream.streaminfo();

    // Format the streaminfo in the same way that metaflac prints it.
    format!("{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n",
            streaminfo.min_block_size,
            streaminfo.max_block_size,
            streaminfo.min_frame_size.unwrap_or(0),
            streaminfo.max_frame_size.unwrap_or(0),
            streaminfo.sample_rate,
            streaminfo.n_channels,
            streaminfo.bits_per_sample,
            streaminfo.n_samples.unwrap_or(0),
            print_hex(&streaminfo.md5sum)) // TODO implement LowerHex for &[u8] and submit a PR.
}

fn compare_metaflac(fname: &Path) {
    let metaflac = run_metaflac(fname);
    let streaminfo = read_streaminfo(fname);
    let mut mf_lines = metaflac.lines_any();
    let mut si_lines = streaminfo.lines_any();
    while let (Some(mf), Some(si)) = (mf_lines.next(), si_lines.next()) {
        if mf != si {
            println!("metaflac\n--------\n{}", metaflac);
            println!("streaminfo\n----------\n{}", streaminfo);
            panic!("metaflac disagrees on parsed streaminfo");
        }
    };
}

#[test]
fn verify_streaminfo() {
    use std::old_io::fs::{readdir, PathExtensions};

    // Compare our streaminfo parsing with metaflac on all flac files in the
    // testsamples directory.
    let dir = readdir(&Path::new("testsamples")).ok().expect("failed to enumerate flac files");
    for path in dir.iter() {
        if path.is_file() && path.extension_str() == Some("flac") {
            print!("    comparing {} ...", path.as_str().expect("unsupported filename"));
            compare_metaflac(path);
            println!(" ok");
        }
    }
}
<|endoftext|>


<commit_before>//! All different implementation.

use ::{Constraint,PuzzleSearch,Val,VarToken};

pub struct AllDifferent {
    vars: Vec<VarToken>,
}

impl AllDifferent {
    /// Allocate a new All Different constraint.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut send_more_money = puzzle_solver::Puzzle::new();
    /// let vars = send_more_money.new_vars_with_candidates_1d(8,
    ///         &[0,1,2,3,4,5,6,7,8,9]);
    ///
    /// puzzle_solver::constraint::AllDifferent::new(&vars);
    /// ```
    pub fn new<'a, I>(vars: I) -> Self
            where I: IntoIterator<Item=&'a VarToken> {
        AllDifferent {
            vars: vars.into_iter().map(|&x| x).collect(),
        }
    }
}

impl Constraint for AllDifferent {
    fn vars<'a>(&'a self) -> Box<Iterator<Item=&'a VarToken> + 'a> {
        Box::new(self.vars.iter())
    }

    fn on_assigned(&self, search: &mut PuzzleSearch, _var: VarToken, val: Val)
            -> bool {
        for &var2 in self.vars.iter() {
            if !search.is_assigned(var2) {
                search.remove_candidate(var2, val);
            }
        }

        true
    }
}

#[cfg(test)]
mod tests {
    use ::{Puzzle,Val};

    #[test]
    fn test_contradiction() {
        let mut puzzle = Puzzle::new();
        let v0 = puzzle.new_var_with_candidates(&[1]);
        let v1 = puzzle.new_var_with_candidates(&[1]);

        puzzle.all_different(&[v0,v1]);

        let solution = puzzle.solve_any();
        assert!(solution.is_none());
    }

    #[test]
    fn test_elimination() {
        let mut puzzle = Puzzle::new();
        let v0 = puzzle.new_var_with_candidates(&[1]);
        let v1 = puzzle.new_var_with_candidates(&[1,2,3]);
        let v2 = puzzle.new_var_with_candidates(&[1,2,3]);

        puzzle.all_different(&[v0,v1,v2]);

        let search = puzzle.step().expect("contradiction");
        assert_eq!(search[v0], 1);
        assert_eq!(search.get_unassigned(v1).collect::<Vec<Val>>(), &[2,3]);
        assert_eq!(search.get_unassigned(v2).collect::<Vec<Val>>(), &[2,3]);
    }
}
<commit_msg>All Different: contradiction if more variables than candidates.<commit_after>//! All different implementation.

use std::collections::HashSet;

use ::{Constraint,PuzzleSearch,Val,VarToken};

pub struct AllDifferent {
    vars: Vec<VarToken>,
}

impl AllDifferent {
    /// Allocate a new All Different constraint.
    ///
    /// # Examples
    ///
    /// ```
    /// let mut send_more_money = puzzle_solver::Puzzle::new();
    /// let vars = send_more_money.new_vars_with_candidates_1d(8,
    ///         &[0,1,2,3,4,5,6,7,8,9]);
    ///
    /// puzzle_solver::constraint::AllDifferent::new(&vars);
    /// ```
    pub fn new<'a, I>(vars: I) -> Self
            where I: IntoIterator<Item=&'a VarToken> {
        AllDifferent {
            vars: vars.into_iter().map(|&x| x).collect(),
        }
    }
}

impl Constraint for AllDifferent {
    fn vars<'a>(&'a self) -> Box<Iterator<Item=&'a VarToken> + 'a> {
        Box::new(self.vars.iter())
    }

    fn on_assigned(&self, search: &mut PuzzleSearch, _var: VarToken, val: Val)
            -> bool {
        for &var2 in self.vars.iter() {
            if !search.is_assigned(var2) {
                search.remove_candidate(var2, val);
            }
        }

        true
    }

    fn on_updated(&self, search: &mut PuzzleSearch) -> bool {
        // Build a table of which values can be assigned to which variables.
        let mut num_unassigned = 0;
        let mut all_candidates = HashSet::new();

        for &var in self.vars.iter().filter(|&var| !search.is_assigned(*var)) {
            num_unassigned = num_unassigned + 1;
            for val in search.get_unassigned(var) {
                all_candidates.insert(val);
            }
        }

        if num_unassigned > all_candidates.len() {
            // More unassigned variables than candidates, contradiction.
            return false;
        }

        true
    }
}

#[cfg(test)]
mod tests {
    use ::{Puzzle,Val};

    #[test]
    fn test_contradiction() {
        let mut puzzle = Puzzle::new();
        let v0 = puzzle.new_var_with_candidates(&[1]);
        let v1 = puzzle.new_var_with_candidates(&[1]);
        let v2 = puzzle.new_var_with_candidates(&[1,2,3]);

        puzzle.all_different(&[v0,v1,v2]);

        let solution = puzzle.solve_any();
        assert!(solution.is_none());
    }

    #[test]
    fn test_elimination() {
        let mut puzzle = Puzzle::new();
        let v0 = puzzle.new_var_with_candidates(&[1]);
        let v1 = puzzle.new_var_with_candidates(&[1,2,3]);
        let v2 = puzzle.new_var_with_candidates(&[1,2,3]);

        puzzle.all_different(&[v0,v1,v2]);

        let search = puzzle.step().expect("contradiction");
        assert_eq!(search[v0], 1);
        assert_eq!(search.get_unassigned(v1).collect::<Vec<Val>>(), &[2,3]);
        assert_eq!(search.get_unassigned(v2).collect::<Vec<Val>>(), &[2,3]);
    }

    #[test]
    fn test_contradiction_by_length() {
        let mut puzzle = Puzzle::new();
        let v0 = puzzle.new_var_with_candidates(&[1,2]);
        let v1 = puzzle.new_var_with_candidates(&[1,2]);
        let v2 = puzzle.new_var_with_candidates(&[1,2]);

        puzzle.all_different(&[v0,v1,v2]);

        let search = puzzle.step();
        assert!(search.is_none());
    }
}
<|endoftext|>


<commit_before>extern crate twitter;

mod common;

use std::collections::HashSet;
use twitter::{user, Response};

//IMPORTANT: see common.rs for instructions on making sure this properly authenticates with
//Twitter.
fn main() {
    let config = common::Config::load();

    println!("");
    let friends = user::friends_ids(config.user_id, &config.con_token, &config.access_token).map(|r| r.unwrap()).collect::<Response<Vec<_>>>();
    let followers = user::followers_ids(config.user_id, &config.con_token, &config.access_token).map(|r| r.unwrap()).collect::<Response<Vec<_>>>();

    let friends_set = friends.response.iter().cloned().collect::<HashSet<i64>>();
    let followers_set = followers.response.iter().cloned().collect::<HashSet<i64>>();

    let reciprocals = friends_set.intersection(&followers_set).cloned().collect::<Vec<_>>();

    println!("{} accounts that you follow follow you back.", reciprocals.len());

    for user in user::lookup_ids(&reciprocals, &config.con_token, &config.access_token).unwrap().response {
        println!("{} (@{})", user.name, user.screen_name);
    }
}
<commit_msg>condense reciprocal<commit_after>extern crate twitter;

mod common;

use std::collections::HashSet;
use twitter::user;

//IMPORTANT: see common.rs for instructions on making sure this properly authenticates with
//Twitter.
fn main() {
    let config = common::Config::load();

    println!("");
    let friends =
        user::friends_ids(config.user_id, &config.con_token, &config.access_token)
              .map(|r| r.unwrap().response)
              .collect::<HashSet<i64>>();
    let followers =
        user::followers_ids(config.user_id, &config.con_token, &config.access_token)
              .map(|r| r.unwrap().response)
              .collect::<HashSet<i64>>();

    let reciprocals = friends.intersection(&followers).cloned().collect::<Vec<_>>();

    println!("{} accounts that you follow follow you back.", reciprocals.len());

    for user in user::lookup_ids(&reciprocals, &config.con_token, &config.access_token).unwrap().response {
        println!("{} (@{})", user.name, user.screen_name);
    }
}
<|endoftext|>


<commit_before>//
// OpenAOE: An open source reimplementation of Age of Empires (1997)
// Copyright (c) 2016 Kevin Fuller
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

use std::path::Path;
use std::io;
use std::io::prelude::*;
use std::io::SeekFrom;
use std::fs::File;
use std::string::FromUtf8Error;

use io_tools::ReadExt;

use flate2;
use flate2::Decompress;
use flate2::Flush;

const EXPECTED_FILE_VERSION: &'static str = "VER 3.7\0";
const DECOMPRESSION_CHUNK_SIZE: usize = 16 * 1024; // 16 kibibytes

quick_error! {
    #[derive(Debug)]
    pub enum EmpiresDbError {
        ReadError(err: io::Error) {
            from()
            display("failed to read empires.dat: {}", err)
        }
        CompressionError(err: flate2::DataError) {
            from()
            display("failed to decompress empires.dat: {}", err)
        }
        BadFile(reason: &'static str) {
            display("bad empires.dat: {}", reason)
        }
        EncodingError(err: FromUtf8Error) {
            from()
            display("invalid UTF-8 encoding in empires.dat: {}", err)
        }
    }
}

pub type EmpiresDbResult<T> = Result<T, EmpiresDbError>;

#[derive(Default, Debug)]
struct Graphic {
    name: String,
    short_name: String,
    slp_resource_id: i32,
    layer: u8,
}

impl Graphic {
    pub fn new() -> Graphic {
        Default::default()
    }
}

#[derive(Default, Debug)]
struct SoundEffect {
    file_name: String,
    resource_id: u32,
    probability: u16,
}

impl SoundEffect {
    pub fn new() -> SoundEffect {
        Default::default()
    }
}

#[derive(Default, Debug)]
struct SoundEffectGroup {
    id: u16,
    play_at_update_count: u16,
    cache_time: u32,
    sound_effects: Vec<SoundEffect>,
}

impl SoundEffectGroup {
    pub fn new() -> SoundEffectGroup {
        Default::default()
    }
}

#[derive(Default, Debug)]
struct PlayerColor {
    name: String,
    id: u16,
    palette_index: u8,
}

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

#[derive(Default, Debug)]
pub struct EmpiresDb {
    terrain_restriction_count: u16,
    terrain_count: u16,

    player_colors: Vec<PlayerColor>,
    sound_effect_groups: Vec<SoundEffectGroup>,
    graphics: Vec<Graphic>,
}

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

    pub fn read_from_file<P: AsRef<Path>>(file_name: P) -> EmpiresDbResult<EmpiresDb> {
        let data = try!(EmpiresDb::read_and_decompress(file_name.as_ref()));
        let mut cursor = io::Cursor::new(data);

        let mut db = EmpiresDb::new();
        try!(db.read_header(&mut cursor));
        try!(db.read_terrain_restrictions(&mut cursor));
        try!(db.read_player_colors(&mut cursor));
        try!(db.read_sounds(&mut cursor));
        try!(db.read_graphics(&mut cursor));
        Ok(db)
    }

    fn read_graphics<R: Read + Seek>(&mut self, cursor: &mut R) -> EmpiresDbResult<()> {
        let graphic_count = try!(cursor.read_u16());

        let mut graphic_pointers = Vec::new();
        for _ in 0..graphic_count {
            // No clue what these are pointing to (the numbers are too large to be file offsets),
            // but we need to skip a graphic if one of these pointers is zero
            graphic_pointers.push(try!(cursor.read_u32()));
        }

        for graphic_pointer in &graphic_pointers {
            if *graphic_pointer == 0 {
                continue;
            }

            let mut graphic = Graphic::new();
            graphic.name = try!(cursor.read_sized_str(21));
            graphic.short_name = try!(cursor.read_sized_str(13));
            graphic.slp_resource_id = try!(cursor.read_i32()); // slp_resource_id

            try!(cursor.seek(SeekFrom::Current(2))); // skip 2 unknown bytes
            graphic.layer = try!(cursor.read_byte()); // layer

            // TODO: Figure out what the rest of this data is for and save if necessary
            try!(cursor.read_byte()); // player_color?
            try!(cursor.read_byte()); // second player color?
            try!(cursor.read_byte()); // replay?

            try!(cursor.seek(SeekFrom::Current(8))); // skip 4 16-bit integer coordinates

            let delta_count = try!(cursor.read_u16());
            try!(cursor.read_u16()); // sound_id
            let attack_sound_used = try!(cursor.read_byte());
            try!(cursor.read_u16()); // frame_count
            let angle_count = try!(cursor.read_u16());
            try!(cursor.read_f32()); // new_speed
            try!(cursor.read_f32()); // frame_rate
            try!(cursor.read_f32()); // replay_delay
            try!(cursor.read_byte()); // sequence_type
            try!(cursor.read_u16()); // id
            try!(cursor.read_byte()); // mirror_mode

            for _ in 0..delta_count {
                try!(cursor.read_u16()); // graphic_id
                try!(cursor.seek(SeekFrom::Current(6))); // skip unknown bytes
                try!(cursor.read_u16()); // direction_x
                try!(cursor.read_u16()); // direction_y
                try!(cursor.read_u16()); // display_angle
                try!(cursor.seek(SeekFrom::Current(2))); // skip unknown bytes
            }

            if attack_sound_used != 0 {
                for _ in 0..angle_count {
                    // three sounds per angle
                    for _ in 0..3 {
                        try!(cursor.read_u16()); // sound_delay
                        try!(cursor.read_u16()); // sound_id
                    }
                }
            }
            self.graphics.push(graphic);
        }
        Ok(())
    }

    fn read_sounds<R: Read + Seek>(&mut self, cursor: &mut R) -> EmpiresDbResult<()> {
        let sound_count = try!(cursor.read_u16());
        for _ in 0..sound_count {
            let mut sound_group = SoundEffectGroup::new();
            sound_group.id = try!(cursor.read_u16());
            sound_group.play_at_update_count = try!(cursor.read_u16());

            let effect_count = try!(cursor.read_u16());
            sound_group.cache_time = try!(cursor.read_u32());

            for _ in 0..effect_count {
                let mut effect = SoundEffect::new();
                effect.file_name = try!(cursor.read_sized_str(13));
                effect.resource_id = try!(cursor.read_u32());
                effect.probability = try!(cursor.read_u16());
                sound_group.sound_effects.push(effect);
            }
            self.sound_effect_groups.push(sound_group);
        }
        Ok(())
    }

    fn read_player_colors<R: Read + Seek>(&mut self, cursor: &mut R) -> EmpiresDbResult<()> {
        let color_count = try!(cursor.read_u16());
        for _ in 0..color_count {
            let mut color = PlayerColor::new();
            color.name = try!(cursor.read_sized_str(30));
            color.id = try!(cursor.read_u16());
            try!(cursor.read_u16()); // unknown; skip

            color.palette_index = try!(cursor.read_byte());
            try!(cursor.read_byte()); // unknown byte

            self.player_colors.push(color);
        }

        Ok(())
    }

    fn read_terrain_restrictions<R: Read + Seek>(&mut self, cursor: &mut R) -> EmpiresDbResult<()> {
        self.terrain_restriction_count = try!(cursor.read_u16());
        self.terrain_count = try!(cursor.read_u16());

        let mut terrain_restriction_pointers = Vec::new();
        for _ in 0..self.terrain_restriction_count {
            terrain_restriction_pointers.push(cursor.read_u32());
        }

        // Don't know what any of the terrain restriction data is for yet, so read/skip for now
        for _ in 0..self.terrain_restriction_count {
            for _ in 0..self.terrain_count {
                try!(cursor.read_f32()); // passable/buildable/dmg multiplier?
            }
        }

        Ok(())
    }

    fn read_header<R: Read + Seek>(&mut self, cursor: &mut R) -> EmpiresDbResult<()> {
        let mut version = [0u8; 8];
        try!(cursor.read_exact(&mut version));
        if version != EXPECTED_FILE_VERSION.as_bytes() {
            return Err(EmpiresDbError::BadFile("unexpected file version"));
        }

        Ok(())
    }

    // The empires.dat is compressed with zlib without a header and 15 window bits
    fn read_and_decompress(file_name: &Path) -> EmpiresDbResult<Vec<u8>> {
        use flate2::Status;

        let mut file = try!(File::open(file_name));
        let mut compressed: Vec<u8> = Vec::new();
        try!(file.read_to_end(&mut compressed));

        let mut cursor = io::Cursor::new(&compressed[..]);

        // At time of implementation, the flate2 library didn't provide an easy way to
        // decompress a stream without a header, so it had to be manually implemented here
        let mut decompressed: Vec<u8> = Vec::new();
        let mut buffer = [0u8; DECOMPRESSION_CHUNK_SIZE];
        let mut decompressor = Decompress::new(false);
        loop {
            let last_out = decompressor.total_out();
            let last_in = decompressor.total_in();

            let (status, end_stream);
            {
                let input = try!(cursor.fill_buf());
                end_stream = input.is_empty();

                let flush_type = if end_stream { Flush::Finish } else { Flush::None };
                status = try!(decompressor.decompress(input, &mut buffer, flush_type));
            }

            let read = (decompressor.total_in() - last_in) as usize;
            let written = (decompressor.total_out() - last_out) as usize;

            decompressed.extend_from_slice(&buffer[0..written]);
            cursor.consume(read);

            match status {
                Status::Ok => { },
                Status::BufError if !end_stream && written == 0 => continue,
                Status::BufError | Status::StreamEnd => break,
            }
        }

        Ok(decompressed)
    }
}
<commit_msg>Save off graphic data for easier interpretation<commit_after>//
// OpenAOE: An open source reimplementation of Age of Empires (1997)
// Copyright (c) 2016 Kevin Fuller
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

use std::path::Path;
use std::io;
use std::io::prelude::*;
use std::io::SeekFrom;
use std::fs::File;
use std::string::FromUtf8Error;

use io_tools::ReadExt;

use flate2;
use flate2::Decompress;
use flate2::Flush;

const EXPECTED_FILE_VERSION: &'static str = "VER 3.7\0";
const DECOMPRESSION_CHUNK_SIZE: usize = 16 * 1024; // 16 kibibytes

quick_error! {
    #[derive(Debug)]
    pub enum EmpiresDbError {
        ReadError(err: io::Error) {
            from()
            display("failed to read empires.dat: {}", err)
        }
        CompressionError(err: flate2::DataError) {
            from()
            display("failed to decompress empires.dat: {}", err)
        }
        BadFile(reason: &'static str) {
            display("bad empires.dat: {}", reason)
        }
        EncodingError(err: FromUtf8Error) {
            from()
            display("invalid UTF-8 encoding in empires.dat: {}", err)
        }
    }
}

pub type EmpiresDbResult<T> = Result<T, EmpiresDbError>;

#[derive(Default, Debug)]
struct GraphicAttackSound {
    sound_delay: i16,
    sound_id: i16,
}

impl GraphicAttackSound {
    pub fn new() -> GraphicAttackSound {
        Default::default()
    }
}

#[derive(Default, Debug)]
struct GraphicDelta {
    graphic_id: i16,
    direction_x: u16,
    direction_y: u16,
    display_angle: i16,
}

impl GraphicDelta {
    pub fn new() -> GraphicDelta {
        Default::default()
    }
}

#[derive(Default, Debug)]
struct Graphic {
    name: String,
    short_name: String,
    slp_resource_id: i32,
    layer: u8,
    player_color: i8, // TODO: What is this for?
    second_player_color: i8, // TODO: What is this for?
    replay: u8, // TODO: What is this for?
    coordinates: [u16; 4], // TODO: What are these for?
    sound_id: i16,
    frame_count: u16,
    angle_count: u16,
    new_speed: f32, // TODO: What is this for?
    frame_rate: f32,
    replay_delay: f32,
    sequence_type: u8, // TODO: What is this for?
    id: u16, // TODO: What is this for?
    mirror_mode: u8, // TODO: What is this for?
    deltas: Vec<GraphicDelta>,
    attack_sounds: Vec<GraphicAttackSound>,
}

impl Graphic {
    pub fn new() -> Graphic {
        Default::default()
    }
}

#[derive(Default, Debug)]
struct SoundEffect {
    file_name: String,
    resource_id: i32,
    probability: u16,
}

impl SoundEffect {
    pub fn new() -> SoundEffect {
        Default::default()
    }
}

#[derive(Default, Debug)]
struct SoundEffectGroup {
    id: u16,
    play_at_update_count: u16,
    cache_time: u32,
    sound_effects: Vec<SoundEffect>,
}

impl SoundEffectGroup {
    pub fn new() -> SoundEffectGroup {
        Default::default()
    }
}

#[derive(Default, Debug)]
struct PlayerColor {
    name: String,
    id: u16,
    palette_index: u8,
}

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

#[derive(Default, Debug)]
pub struct EmpiresDb {
    terrain_restriction_count: u16,
    terrain_count: u16,

    player_colors: Vec<PlayerColor>,
    sound_effect_groups: Vec<SoundEffectGroup>,
    graphics: Vec<Graphic>,
}

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

    pub fn read_from_file<P: AsRef<Path>>(file_name: P) -> EmpiresDbResult<EmpiresDb> {
        let data = try!(EmpiresDb::read_and_decompress(file_name.as_ref()));
        let mut cursor = io::Cursor::new(data);

        let mut db = EmpiresDb::new();
        try!(db.read_header(&mut cursor));
        try!(db.read_terrain_restrictions(&mut cursor));
        try!(db.read_player_colors(&mut cursor));
        try!(db.read_sounds(&mut cursor));
        try!(db.read_graphics(&mut cursor));
        Ok(db)
    }

    fn read_graphics<R: Read + Seek>(&mut self, cursor: &mut R) -> EmpiresDbResult<()> {
        let graphic_count = try!(cursor.read_u16());

        let mut graphic_pointers = Vec::new();
        for _ in 0..graphic_count {
            // No clue what these are pointing to (the numbers are too large to be file offsets),
            // but we need to skip a graphic if one of these pointers is zero
            graphic_pointers.push(try!(cursor.read_u32()));
        }

        for graphic_pointer in &graphic_pointers {
            if *graphic_pointer == 0 {
                continue;
            }

            let mut graphic = Graphic::new();
            graphic.name = try!(cursor.read_sized_str(21));
            graphic.short_name = try!(cursor.read_sized_str(13));
            graphic.slp_resource_id = try!(cursor.read_i32());

            try!(cursor.seek(SeekFrom::Current(2))); // skip 2 unknown bytes
            graphic.layer = try!(cursor.read_byte());

            graphic.player_color = try!(cursor.read_byte()) as i8;
            graphic.second_player_color = try!(cursor.read_byte()) as i8;
            graphic.replay = try!(cursor.read_byte());

            for i in 0..4 {
                graphic.coordinates[i] = try!(cursor.read_u16());
            }

            let delta_count = try!(cursor.read_u16());
            graphic.sound_id = try!(cursor.read_i16());
            let attack_sound_used = try!(cursor.read_byte());
            graphic.frame_count = try!(cursor.read_u16());
            graphic.angle_count = try!(cursor.read_u16());
            graphic.new_speed = try!(cursor.read_f32());
            graphic.frame_rate = try!(cursor.read_f32());
            graphic.replay_delay = try!(cursor.read_f32());
            graphic.sequence_type = try!(cursor.read_byte());
            graphic.id = try!(cursor.read_u16());
            graphic.mirror_mode = try!(cursor.read_byte());

            for _ in 0..delta_count {
                let mut delta = GraphicDelta::new();
                delta.graphic_id = try!(cursor.read_i16());
                try!(cursor.seek(SeekFrom::Current(6))); // skip unknown bytes
                delta.direction_x = try!(cursor.read_u16());
                delta.direction_y = try!(cursor.read_u16());
                delta.display_angle = try!(cursor.read_i16());
                try!(cursor.seek(SeekFrom::Current(2))); // skip unknown bytes
                graphic.deltas.push(delta);
            }

            if attack_sound_used != 0 {
                for _ in 0..graphic.angle_count {
                    // three sounds per angle
                    for _ in 0..3 {
                        let mut attack_sound = GraphicAttackSound::new();
                        attack_sound.sound_delay = try!(cursor.read_i16());
                        attack_sound.sound_id = try!(cursor.read_i16());
                        graphic.attack_sounds.push(attack_sound);
                    }
                }
            }
            self.graphics.push(graphic);
        }
        Ok(())
    }

    fn read_sounds<R: Read + Seek>(&mut self, cursor: &mut R) -> EmpiresDbResult<()> {
        let sound_count = try!(cursor.read_u16());
        for _ in 0..sound_count {
            let mut sound_group = SoundEffectGroup::new();
            sound_group.id = try!(cursor.read_u16());
            sound_group.play_at_update_count = try!(cursor.read_u16());

            let effect_count = try!(cursor.read_u16());
            sound_group.cache_time = try!(cursor.read_u32());

            for _ in 0..effect_count {
                let mut effect = SoundEffect::new();
                effect.file_name = try!(cursor.read_sized_str(13));
                effect.resource_id = try!(cursor.read_i32());
                effect.probability = try!(cursor.read_u16());
                sound_group.sound_effects.push(effect);
            }
            self.sound_effect_groups.push(sound_group);
        }
        Ok(())
    }

    fn read_player_colors<R: Read + Seek>(&mut self, cursor: &mut R) -> EmpiresDbResult<()> {
        let color_count = try!(cursor.read_u16());
        for _ in 0..color_count {
            let mut color = PlayerColor::new();
            color.name = try!(cursor.read_sized_str(30));
            color.id = try!(cursor.read_u16());
            try!(cursor.read_u16()); // unknown; skip

            color.palette_index = try!(cursor.read_byte());
            try!(cursor.read_byte()); // unknown byte

            self.player_colors.push(color);
        }

        Ok(())
    }

    fn read_terrain_restrictions<R: Read + Seek>(&mut self, cursor: &mut R) -> EmpiresDbResult<()> {
        self.terrain_restriction_count = try!(cursor.read_u16());
        self.terrain_count = try!(cursor.read_u16());

        let mut terrain_restriction_pointers = Vec::new();
        for _ in 0..self.terrain_restriction_count {
            terrain_restriction_pointers.push(cursor.read_u32());
        }

        // Don't know what any of the terrain restriction data is for yet, so read/skip for now
        for _ in 0..self.terrain_restriction_count {
            for _ in 0..self.terrain_count {
                try!(cursor.read_f32()); // passable/buildable/dmg multiplier?
            }
        }

        Ok(())
    }

    fn read_header<R: Read + Seek>(&mut self, cursor: &mut R) -> EmpiresDbResult<()> {
        let mut version = [0u8; 8];
        try!(cursor.read_exact(&mut version));
        if version != EXPECTED_FILE_VERSION.as_bytes() {
            return Err(EmpiresDbError::BadFile("unexpected file version"));
        }

        Ok(())
    }

    // The empires.dat is compressed with zlib without a header and 15 window bits
    fn read_and_decompress(file_name: &Path) -> EmpiresDbResult<Vec<u8>> {
        use flate2::Status;

        let mut file = try!(File::open(file_name));
        let mut compressed: Vec<u8> = Vec::new();
        try!(file.read_to_end(&mut compressed));

        let mut cursor = io::Cursor::new(&compressed[..]);

        // At time of implementation, the flate2 library didn't provide an easy way to
        // decompress a stream without a header, so it had to be manually implemented here
        let mut decompressed: Vec<u8> = Vec::new();
        let mut buffer = [0u8; DECOMPRESSION_CHUNK_SIZE];
        let mut decompressor = Decompress::new(false);
        loop {
            let last_out = decompressor.total_out();
            let last_in = decompressor.total_in();

            let (status, end_stream);
            {
                let input = try!(cursor.fill_buf());
                end_stream = input.is_empty();

                let flush_type = if end_stream { Flush::Finish } else { Flush::None };
                status = try!(decompressor.decompress(input, &mut buffer, flush_type));
            }

            let read = (decompressor.total_in() - last_in) as usize;
            let written = (decompressor.total_out() - last_out) as usize;

            decompressed.extend_from_slice(&buffer[0..written]);
            cursor.consume(read);

            match status {
                Status::Ok => { },
                Status::BufError if !end_stream && written == 0 => continue,
                Status::BufError | Status::StreamEnd => break,
            }
        }

        Ok(decompressed)
    }
}
<|endoftext|>


<commit_before>// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details

use {ContextOps, StreamOps};
use cubeb_core::{ffi, DeviceCollectionRef, DeviceRef, DeviceType, StreamParams, StreamParamsRef};
use std::ffi::CStr;
use std::mem;
use std::os::raw::{c_char, c_int, c_void};

// Helper macro for unwrapping `Result` values from rust-api calls
// while returning early with a c-api error code if the value of the
// expression is `Err`.
macro_rules! _try(
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => return e.raw_code()
    })
);

macro_rules! as_opt_ref {
    ($e:expr) => {
        if $e.is_null() {
            None
        } else {
            Some(StreamParamsRef::from_ptr($e))
        }
    }
}

#[macro_export]
macro_rules! capi_new(
    ($ctx:ident, $stm:ident) => (
        Ops {
            init: Some($crate::capi::capi_init::<$ctx>),
            get_backend_id: Some($crate::capi::capi_get_backend_id::<$ctx>),
            get_max_channel_count: Some($crate::capi::capi_get_max_channel_count::<$ctx>),
            get_min_latency: Some($crate::capi::capi_get_min_latency::<$ctx>),
            get_preferred_sample_rate: Some($crate::capi::capi_get_preferred_sample_rate::<$ctx>),
            enumerate_devices: Some($crate::capi::capi_enumerate_devices::<$ctx>),
            device_collection_destroy: Some($crate::capi::capi_device_collection_destroy::<$ctx>),
            destroy: Some($crate::capi::capi_destroy::<$ctx>),
            stream_init: Some($crate::capi::capi_stream_init::<$ctx>),
            stream_destroy: Some($crate::capi::capi_stream_destroy::<$stm>),
            stream_start: Some($crate::capi::capi_stream_start::<$stm>),
            stream_stop: Some($crate::capi::capi_stream_stop::<$stm>),
            stream_reset_default_device:
                Some($crate::capi::capi_stream_reset_default_device::<$stm>),
            stream_get_position: Some($crate::capi::capi_stream_get_position::<$stm>),
            stream_get_latency: Some($crate::capi::capi_stream_get_latency::<$stm>),
            stream_set_volume: Some($crate::capi::capi_stream_set_volume::<$stm>),
            stream_set_panning: Some($crate::capi::capi_stream_set_panning::<$stm>),
            stream_get_current_device: Some($crate::capi::capi_stream_get_current_device::<$stm>),
            stream_device_destroy: Some($crate::capi::capi_stream_device_destroy::<$stm>),
            stream_register_device_changed_callback:
                Some($crate::capi::capi_stream_register_device_changed_callback::<$stm>),
            register_device_collection_changed:
                Some($crate::capi::capi_register_device_collection_changed::<$ctx>)
        }));

pub unsafe extern "C" fn capi_init<CTX: ContextOps>(
    c: *mut *mut ffi::cubeb,
    context_name: *const c_char,
) -> c_int {
    let anchor = &();
    let context_name = opt_cstr(anchor, context_name);
    let context = _try!(CTX::init(context_name));
    *c = context.as_ptr();
    // Leaking pointer across C FFI
    mem::forget(context);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_backend_id<CTX: ContextOps>(c: *mut ffi::cubeb) -> *const c_char {
    let ctx = &mut *(c as *mut CTX);
    ctx.backend_id().as_ptr()
}

pub unsafe extern "C" fn capi_get_max_channel_count<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    max_channels: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    *max_channels = _try!(ctx.max_channel_count());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_min_latency<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    param: ffi::cubeb_stream_params,
    latency_frames: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let param = StreamParams::from(param);
    *latency_frames = _try!(ctx.min_latency(param));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_preferred_sample_rate<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    rate: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    *rate = _try!(ctx.preferred_sample_rate());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_enumerate_devices<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    devtype: ffi::cubeb_device_type,
    collection: *mut ffi::cubeb_device_collection,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let devtype = DeviceType::from_bits_truncate(devtype);
    let collection = DeviceCollectionRef::from_ptr(collection);
    _try!(ctx.enumerate_devices(devtype, collection));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_device_collection_destroy<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    collection: *mut ffi::cubeb_device_collection,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let collection = DeviceCollectionRef::from_ptr_mut(collection);
    let _ = ctx.device_collection_destroy(collection);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_destroy<CTX>(c: *mut ffi::cubeb) {
    let _: Box<CTX> = Box::from_raw(c as *mut _);
}

pub unsafe extern "C" fn capi_stream_init<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    s: *mut *mut ffi::cubeb_stream,
    stream_name: *const c_char,
    input_device: ffi::cubeb_devid,
    input_stream_params: *mut ffi::cubeb_stream_params,
    output_device: ffi::cubeb_devid,
    output_stream_params: *mut ffi::cubeb_stream_params,
    latency_frames: u32,
    data_callback: ffi::cubeb_data_callback,
    state_callback: ffi::cubeb_state_callback,
    user_ptr: *mut c_void,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let anchor = &(); // for lifetime of stream_name as CStr

    let input_stream_params = as_opt_ref!(input_stream_params);
    let output_stream_params = as_opt_ref!(output_stream_params);

    let stream = _try!(ctx.stream_init(
        opt_cstr(anchor, stream_name),
        input_device,
        input_stream_params,
        output_device,
        output_stream_params,
        latency_frames,
        data_callback,
        state_callback,
        user_ptr
    ));
    *s = stream.as_ptr();
    // Leaking pointer across C FFI
    mem::forget(stream);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_destroy<STM>(s: *mut ffi::cubeb_stream) {
    let _ = Box::from_raw(s as *mut STM);
}

pub unsafe extern "C" fn capi_stream_start<STM: StreamOps>(s: *mut ffi::cubeb_stream) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.start());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_stop<STM: StreamOps>(s: *mut ffi::cubeb_stream) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.stop());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_reset_default_device<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.reset_default_device());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_position<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    position: *mut u64,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    *position = _try!(stm.position());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_latency<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    latency: *mut u32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    *latency = _try!(stm.latency());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_set_volume<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    volume: f32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.set_volume(volume));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_set_panning<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    panning: f32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.set_panning(panning));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_current_device<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    device: *mut *mut ffi::cubeb_device,
) -> i32 {
    let stm = &mut *(s as *mut STM);

    *device = _try!(stm.current_device()).as_ptr();
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_device_destroy<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    device: *mut ffi::cubeb_device,
) -> c_int {
    let stm = &mut *(s as *mut STM);
    let device = DeviceRef::from_ptr(device);
    let _ = stm.device_destroy(device);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_register_device_changed_callback<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    device_changed_callback: ffi::cubeb_device_changed_callback,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.register_device_changed_callback(device_changed_callback));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_register_device_collection_changed<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    devtype: ffi::cubeb_device_type,
    collection_changed_callback: ffi::cubeb_device_collection_changed_callback,
    user_ptr: *mut c_void,
) -> i32 {
    let ctx = &mut *(c as *mut CTX);
    let devtype = DeviceType::from_bits_truncate(devtype);
    _try!(ctx.register_device_collection_changed(devtype, collection_changed_callback, user_ptr));
    ffi::CUBEB_OK
}

fn opt_cstr<T>(_anchor: &T, ptr: *const c_char) -> Option<&CStr> {
    if ptr.is_null() {
        None
    } else {
        Some(unsafe { CStr::from_ptr(ptr) })
    }
}
<commit_msg>Return the result from the implementation of device_collection_destroy instead of returing CUBEB_OK all the time<commit_after>// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details

use {ContextOps, StreamOps};
use cubeb_core::{ffi, DeviceCollectionRef, DeviceRef, DeviceType, StreamParams, StreamParamsRef};
use std::ffi::CStr;
use std::mem;
use std::os::raw::{c_char, c_int, c_void};

// Helper macro for unwrapping `Result` values from rust-api calls
// while returning early with a c-api error code if the value of the
// expression is `Err`.
macro_rules! _try(
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => return e.raw_code()
    })
);

macro_rules! as_opt_ref {
    ($e:expr) => {
        if $e.is_null() {
            None
        } else {
            Some(StreamParamsRef::from_ptr($e))
        }
    }
}

#[macro_export]
macro_rules! capi_new(
    ($ctx:ident, $stm:ident) => (
        Ops {
            init: Some($crate::capi::capi_init::<$ctx>),
            get_backend_id: Some($crate::capi::capi_get_backend_id::<$ctx>),
            get_max_channel_count: Some($crate::capi::capi_get_max_channel_count::<$ctx>),
            get_min_latency: Some($crate::capi::capi_get_min_latency::<$ctx>),
            get_preferred_sample_rate: Some($crate::capi::capi_get_preferred_sample_rate::<$ctx>),
            enumerate_devices: Some($crate::capi::capi_enumerate_devices::<$ctx>),
            device_collection_destroy: Some($crate::capi::capi_device_collection_destroy::<$ctx>),
            destroy: Some($crate::capi::capi_destroy::<$ctx>),
            stream_init: Some($crate::capi::capi_stream_init::<$ctx>),
            stream_destroy: Some($crate::capi::capi_stream_destroy::<$stm>),
            stream_start: Some($crate::capi::capi_stream_start::<$stm>),
            stream_stop: Some($crate::capi::capi_stream_stop::<$stm>),
            stream_reset_default_device:
                Some($crate::capi::capi_stream_reset_default_device::<$stm>),
            stream_get_position: Some($crate::capi::capi_stream_get_position::<$stm>),
            stream_get_latency: Some($crate::capi::capi_stream_get_latency::<$stm>),
            stream_set_volume: Some($crate::capi::capi_stream_set_volume::<$stm>),
            stream_set_panning: Some($crate::capi::capi_stream_set_panning::<$stm>),
            stream_get_current_device: Some($crate::capi::capi_stream_get_current_device::<$stm>),
            stream_device_destroy: Some($crate::capi::capi_stream_device_destroy::<$stm>),
            stream_register_device_changed_callback:
                Some($crate::capi::capi_stream_register_device_changed_callback::<$stm>),
            register_device_collection_changed:
                Some($crate::capi::capi_register_device_collection_changed::<$ctx>)
        }));

pub unsafe extern "C" fn capi_init<CTX: ContextOps>(
    c: *mut *mut ffi::cubeb,
    context_name: *const c_char,
) -> c_int {
    let anchor = &();
    let context_name = opt_cstr(anchor, context_name);
    let context = _try!(CTX::init(context_name));
    *c = context.as_ptr();
    // Leaking pointer across C FFI
    mem::forget(context);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_backend_id<CTX: ContextOps>(c: *mut ffi::cubeb) -> *const c_char {
    let ctx = &mut *(c as *mut CTX);
    ctx.backend_id().as_ptr()
}

pub unsafe extern "C" fn capi_get_max_channel_count<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    max_channels: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    *max_channels = _try!(ctx.max_channel_count());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_min_latency<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    param: ffi::cubeb_stream_params,
    latency_frames: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let param = StreamParams::from(param);
    *latency_frames = _try!(ctx.min_latency(param));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_preferred_sample_rate<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    rate: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    *rate = _try!(ctx.preferred_sample_rate());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_enumerate_devices<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    devtype: ffi::cubeb_device_type,
    collection: *mut ffi::cubeb_device_collection,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let devtype = DeviceType::from_bits_truncate(devtype);
    let collection = DeviceCollectionRef::from_ptr(collection);
    _try!(ctx.enumerate_devices(devtype, collection));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_device_collection_destroy<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    collection: *mut ffi::cubeb_device_collection,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let collection = DeviceCollectionRef::from_ptr_mut(collection);
    _try!(ctx.device_collection_destroy(collection));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_destroy<CTX>(c: *mut ffi::cubeb) {
    let _: Box<CTX> = Box::from_raw(c as *mut _);
}

pub unsafe extern "C" fn capi_stream_init<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    s: *mut *mut ffi::cubeb_stream,
    stream_name: *const c_char,
    input_device: ffi::cubeb_devid,
    input_stream_params: *mut ffi::cubeb_stream_params,
    output_device: ffi::cubeb_devid,
    output_stream_params: *mut ffi::cubeb_stream_params,
    latency_frames: u32,
    data_callback: ffi::cubeb_data_callback,
    state_callback: ffi::cubeb_state_callback,
    user_ptr: *mut c_void,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let anchor = &(); // for lifetime of stream_name as CStr

    let input_stream_params = as_opt_ref!(input_stream_params);
    let output_stream_params = as_opt_ref!(output_stream_params);

    let stream = _try!(ctx.stream_init(
        opt_cstr(anchor, stream_name),
        input_device,
        input_stream_params,
        output_device,
        output_stream_params,
        latency_frames,
        data_callback,
        state_callback,
        user_ptr
    ));
    *s = stream.as_ptr();
    // Leaking pointer across C FFI
    mem::forget(stream);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_destroy<STM>(s: *mut ffi::cubeb_stream) {
    let _ = Box::from_raw(s as *mut STM);
}

pub unsafe extern "C" fn capi_stream_start<STM: StreamOps>(s: *mut ffi::cubeb_stream) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.start());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_stop<STM: StreamOps>(s: *mut ffi::cubeb_stream) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.stop());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_reset_default_device<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.reset_default_device());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_position<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    position: *mut u64,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    *position = _try!(stm.position());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_latency<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    latency: *mut u32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    *latency = _try!(stm.latency());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_set_volume<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    volume: f32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.set_volume(volume));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_set_panning<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    panning: f32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.set_panning(panning));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_current_device<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    device: *mut *mut ffi::cubeb_device,
) -> i32 {
    let stm = &mut *(s as *mut STM);

    *device = _try!(stm.current_device()).as_ptr();
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_device_destroy<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    device: *mut ffi::cubeb_device,
) -> c_int {
    let stm = &mut *(s as *mut STM);
    let device = DeviceRef::from_ptr(device);
    let _ = stm.device_destroy(device);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_register_device_changed_callback<STM: StreamOps>(
    s: *mut ffi::cubeb_stream,
    device_changed_callback: ffi::cubeb_device_changed_callback,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    _try!(stm.register_device_changed_callback(device_changed_callback));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_register_device_collection_changed<CTX: ContextOps>(
    c: *mut ffi::cubeb,
    devtype: ffi::cubeb_device_type,
    collection_changed_callback: ffi::cubeb_device_collection_changed_callback,
    user_ptr: *mut c_void,
) -> i32 {
    let ctx = &mut *(c as *mut CTX);
    let devtype = DeviceType::from_bits_truncate(devtype);
    _try!(ctx.register_device_collection_changed(devtype, collection_changed_callback, user_ptr));
    ffi::CUBEB_OK
}

fn opt_cstr<T>(_anchor: &T, ptr: *const c_char) -> Option<&CStr> {
    if ptr.is_null() {
        None
    } else {
        Some(unsafe { CStr::from_ptr(ptr) })
    }
}
<|endoftext|>


<commit_before>extern crate gurobi;
extern crate itertools;

use std::iter::repeat;
use gurobi::*;
use itertools::*;

fn main() {
  // Set of worker's names
  let workers = vec!["Amy", "Bob", "Cathy", "Dan", "Ed", "Fred", "Gu"];

  // Amount each worker is paid to to work per shift
  let pays = vec![10.0, 12.0, 10.0, 8.0, 8.0, 9.0, 11.0];

  // Set of shift labels
  let shifts = vec!["Mon1", "Tue2", "Wed3", "Thu4", "Fri5", "Sat6", "Sun7", "Mon8", "Tue9", "Wed10", "Thu11", "Fri12",
                    "Sat13", "Sun14"];

  // Number of workers required for each shift
  let shift_requirements = vec![3.0, 2.0, 4.0, 4.0, 5.0, 6.0, 5.0, 2.0, 2.0, 3.0, 4.0, 6.0, 7.0, 5.0];

  // Worker availability: 0 if the worker is unavailable for a shift
  let availability = vec![
     vec![ 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1 ],
     vec![ 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0 ],
     vec![ 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 ],
     vec![ 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 ],
     vec![ 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1 ],
     vec![ 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1 ],
     vec![ 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
   ];

  let env = Env::new("workforce1.log").unwrap();
  let mut model = env.new_model("assignment").unwrap();

  let mut x = Vec::new();
  for (worker, availability) in Zip::new((workers.iter(), availability.iter())) {

    let mut xshift = Vec::new();
    for (shift, &availability) in Zip::new((shifts.iter(), availability.iter())) {
      let vname = format!("{}.{}", worker, shift);
      let v = model.add_var(vname.as_str(), Continuous(-INFINITY, availability as f64)).unwrap();
      xshift.push(v);
    }

    x.push(xshift);
  }
  model.update().unwrap();

  let objterm = pays.iter().map(|pay| repeat(pay).take(shifts.len()));

  let objexpr = Zip::new((x.iter().flatten(), objterm.flatten())).fold(LinExpr::new(),
                                                                       |expr, (ref x, &c)| expr.term((*x).clone(), c));
  model.set_objective(objexpr, Minimize).unwrap();

  for (s, (shift, &requirement)) in shifts.iter().zip(shift_requirements.iter()).enumerate() {
    model.add_constr(format!("c.{}", shift).as_str(),
                  x.iter().map(|ref x| x[s].clone()).fold(LinExpr::new(), |expr, x| expr.term(x, 1.0)),
                  Equal,
                  requirement)
      .unwrap();
  }

  model.write("assignment.lp").unwrap();
  model.optimize().unwrap();

  let status = model.status().unwrap();
  if status == model::Status::Infeasible {
    // compute IIS.
    model.compute_iis().unwrap();
    model.write("assignment.ilp").unwrap();

    println!("The following constraint(s) cannot be satisfied:");
    let iis_constrs = model.get_constrs().filter_map(|c| {
      if c.get(&model, attr::IISConstr).unwrap() != 0 {
        Some(c)
      } else {
        None
      }
    });
    for c in iis_constrs {
      let cname = c.get(&model, attr::ConstrName).unwrap();
      println!("{}", cname);
    }
  }
}
<commit_msg>fix example<commit_after>extern crate gurobi;
extern crate itertools;

use std::iter::repeat;
use gurobi::*;
use itertools::*;

fn main() {
  // Set of worker's names
  let workers = vec!["Amy", "Bob", "Cathy", "Dan", "Ed", "Fred", "Gu"];

  // Amount each worker is paid to to work per shift
  let pays = vec![10.0, 12.0, 10.0, 8.0, 8.0, 9.0, 11.0];

  // Set of shift labels
  let shifts = vec!["Mon1", "Tue2", "Wed3", "Thu4", "Fri5", "Sat6", "Sun7", "Mon8", "Tue9", "Wed10", "Thu11", "Fri12",
                    "Sat13", "Sun14"];

  // Number of workers required for each shift
  let shift_requirements = vec![3.0, 2.0, 4.0, 4.0, 5.0, 6.0, 5.0, 2.0, 2.0, 3.0, 4.0, 6.0, 7.0, 5.0];

  // Worker availability: 0 if the worker is unavailable for a shift
  let availability = vec![
     vec![ 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1 ],
     vec![ 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0 ],
     vec![ 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 ],
     vec![ 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 ],
     vec![ 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1 ],
     vec![ 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1 ],
     vec![ 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
   ];

  let env = Env::new("workforce1.log").unwrap();
  let mut model = env.new_model("assignment").unwrap();

  let mut x = Vec::new();
  for (worker, availability) in Zip::new((workers.iter(), availability.iter())) {

    let mut xshift = Vec::new();
    for (shift, &availability) in Zip::new((shifts.iter(), availability.iter())) {
      let vname = format!("{}.{}", worker, shift);
      let v = model.add_var(vname.as_str(), Continuous(-INFINITY, availability as f64)).unwrap();
      xshift.push(v);
    }

    x.push(xshift);
  }
  model.update().unwrap();

  let objterm = pays.iter().map(|pay| repeat(pay).take(shifts.len()));

  let objexpr = Zip::new((x.iter().flatten(), objterm.flatten())).fold(LinExpr::new(),
                                                                       |expr, (ref x, &c)| expr.term((*x).clone(), c));
  model.set_objective(objexpr, Minimize).unwrap();

  for (s, (shift, &requirement)) in shifts.iter().zip(shift_requirements.iter()).enumerate() {
    model.add_constr(format!("c.{}", shift).as_str(),
                  x.iter().map(|ref x| x[s].clone()).fold(LinExpr::new(), |expr, x| expr.term(x, 1.0)),
                  Equal,
                  requirement)
      .unwrap();
  }

  model.write("assignment.lp").unwrap();
  model.optimize().unwrap();

  let status = model.status().unwrap();
  if status == model::Status::Infeasible {
    // compute IIS.
    model.compute_iis().unwrap();
    model.write("assignment.ilp").unwrap();

    println!("The following constraint(s) cannot be satisfied:");
    for c in model.get_constrs().filter(|c| c.get(&model, attr::IISConstr).unwrap() != 0) {
      let cname = c.get(&model, attr::ConstrName).unwrap();
      println!("{}", cname);
    }
  }
}
<|endoftext|>


<commit_before>///
/// This example parses, sorts and groups the iris dataset
/// and does some simple manipulations.
///
/// Iterators and itertools functionality are used throughout.
///
///

extern crate itertools;

use itertools::Itertools;
use std::collections::HashMap;
use std::iter::repeat;
use std::num::ParseFloatError;
use std::str::FromStr;

static DATA: &'static str = include_str!("iris.data");

#[derive(Clone, Debug)]
struct Iris {
    name: String,
    data: [f32; 4],
}

#[derive(Clone, Debug)]
enum ParseError {
    Numeric(ParseFloatError),
    Other(&'static str),
}

impl From<ParseFloatError> for ParseError {
    fn from(err: ParseFloatError) -> Self {
        ParseError::Numeric(err)
    }
}

/// Parse an Iris from a comma-separated line
impl FromStr for Iris {
    type Err = ParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut iris = Iris { name: "".into(), data: [0.; 4] };
        let mut parts = s.split(",").map(str::trim);

        // using Iterator::by_ref()
        for (index, part) in parts.by_ref().take(4).enumerate() {
            // We should just use try!() here, but this is a workaround for
            // some insane issue Rust 1.0 has
            iris.data[index] =
                try!(part.parse::<f32>().map_err(|_| ParseError::Other("Failed to parse f32")));
        }
        if let Some(name) = parts.next() {
            iris.name = name.into();
        } else {
            return Err(ParseError::Other("Missing name"))
        }
        Ok(iris)
    }
}

fn main() {
    // using Itertools::fold_results to create the result of parsing
    let irises = DATA.lines()
                     .map(str::parse)
                     .fold_results(Vec::new(), |mut v, iris: Iris| {
                         v.push(iris);
                         v
                     });
    let mut irises = match irises {
        Err(e) => {
            println!("Error parsing: {:?}", e);
            std::process::exit(1);
        }
        Ok(data) => data,
    };

    // Sort them and group them
    irises.sort_by(|a, b| Ord::cmp(&a.name, &b.name));

    // using Iterator::cycle()
    let mut plot_symbols = "+ox".chars().cycle();
    let mut symbolmap = HashMap::new();

    // using Itertools::group_by_lazy
    for (species, species_group) in &irises.iter().group_by_lazy(|iris| &iris.name) {
        // assign a plot symbol
        symbolmap.entry(species).or_insert_with(|| {
            plot_symbols.next().unwrap()
        });
        println!("{} (symbol={})", species, symbolmap[species]);

        for iris in species_group {
            // using Itertools::format for lazy formatting
            println!("{}",
                     iris.data.iter()
                     .format(", ", |elt, f| f(&format_args!("{:>3.1}", elt))));
        }

    }

    // Look at all combinations of the four columns
    //
    // See https://en.wikipedia.org/wiki/Iris_flower_data_set
    //
    let n = 30; // plot size
    let mut plot = vec![' '; n * n];

    // using Itertools::combinations
    for (a, b) in (0..4).combinations() {
        println!("Column {} vs {}:", a, b);

        // Clear plot
        //
        // using std::iter::repeat;
        // using Itertools::set_from
        plot.iter_mut().set_from(repeat(' '));

        // using Itertools::fold1
        let min_max = |data: &[Iris], col| {
            data.iter()
                .map(|iris| iris.data[col])
                .map(|x| (x, x))
                .fold1(|(min, max), (elt, _)|
                    (f32::min(min, elt), f32::max(max, elt))
                ).expect("Can't find min/max of empty iterator")
        };
        let (min_x, max_x) = min_max(&irises, a);
        let (min_y, max_y) = min_max(&irises, b);

        // Plot the data points
        let round_to_grid = |x, min, max| ((x - min) / (max - min) * ((n - 1) as f32)) as usize;
        let flip = |ix| n - 1 - ix; // reverse axis direction

        for iris in &irises {
            let ix = round_to_grid(iris.data[a], min_x, max_x);
            let iy = flip(round_to_grid(iris.data[b], min_y, max_y));
            plot[n * iy + ix] = symbolmap[&iris.name];
        }

        // render plot
        //
        // using Itertools::join
        for line in plot.chunks(n) {
            println!("{}", line.iter().join(" "))
        }
    }
}
<commit_msg>Fix iris example for Rust 1.1 or later.<commit_after>///
/// This example parses, sorts and groups the iris dataset
/// and does some simple manipulations.
///
/// Iterators and itertools functionality are used throughout.
///
///

extern crate itertools;

use itertools::Itertools;
use std::collections::HashMap;
use std::iter::repeat;
use std::num::ParseFloatError;
use std::str::FromStr;

static DATA: &'static str = include_str!("iris.data");

#[derive(Clone, Debug)]
struct Iris {
    name: String,
    data: [f32; 4],
}

#[derive(Clone, Debug)]
enum ParseError {
    Numeric(ParseFloatError),
    Other(&'static str),
}

impl From<ParseFloatError> for ParseError {
    fn from(err: ParseFloatError) -> Self {
        ParseError::Numeric(err)
    }
}

/// Parse an Iris from a comma-separated line
impl FromStr for Iris {
    type Err = ParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut iris = Iris { name: "".into(), data: [0.; 4] };
        let mut parts = s.split(",").map(str::trim);

        // using Iterator::by_ref()
        for (index, part) in parts.by_ref().take(4).enumerate() {
            iris.data[index] = try!(part.parse::<f32>());
        }
        if let Some(name) = parts.next() {
            iris.name = name.into();
        } else {
            return Err(ParseError::Other("Missing name"))
        }
        Ok(iris)
    }
}

fn main() {
    // using Itertools::fold_results to create the result of parsing
    let irises = DATA.lines()
                     .map(str::parse)
                     .fold_results(Vec::new(), |mut v, iris: Iris| {
                         v.push(iris);
                         v
                     });
    let mut irises = match irises {
        Err(e) => {
            println!("Error parsing: {:?}", e);
            std::process::exit(1);
        }
        Ok(data) => data,
    };

    // Sort them and group them
    irises.sort_by(|a, b| Ord::cmp(&a.name, &b.name));

    // using Iterator::cycle()
    let mut plot_symbols = "+ox".chars().cycle();
    let mut symbolmap = HashMap::new();

    // using Itertools::group_by_lazy
    for (species, species_group) in &irises.iter().group_by_lazy(|iris| &iris.name) {
        // assign a plot symbol
        symbolmap.entry(species).or_insert_with(|| {
            plot_symbols.next().unwrap()
        });
        println!("{} (symbol={})", species, symbolmap[species]);

        for iris in species_group {
            // using Itertools::format for lazy formatting
            println!("{}",
                     iris.data.iter()
                     .format(", ", |elt, f| f(&format_args!("{:>3.1}", elt))));
        }

    }

    // Look at all combinations of the four columns
    //
    // See https://en.wikipedia.org/wiki/Iris_flower_data_set
    //
    let n = 30; // plot size
    let mut plot = vec![' '; n * n];

    // using Itertools::combinations
    for (a, b) in (0..4).combinations() {
        println!("Column {} vs {}:", a, b);

        // Clear plot
        //
        // using std::iter::repeat;
        // using Itertools::set_from
        plot.iter_mut().set_from(repeat(' '));

        // using Itertools::fold1
        let min_max = |data: &[Iris], col| {
            data.iter()
                .map(|iris| iris.data[col])
                .map(|x| (x, x))
                .fold1(|(min, max), (elt, _)|
                    (f32::min(min, elt), f32::max(max, elt))
                ).expect("Can't find min/max of empty iterator")
        };
        let (min_x, max_x) = min_max(&irises, a);
        let (min_y, max_y) = min_max(&irises, b);

        // Plot the data points
        let round_to_grid = |x, min, max| ((x - min) / (max - min) * ((n - 1) as f32)) as usize;
        let flip = |ix| n - 1 - ix; // reverse axis direction

        for iris in &irises {
            let ix = round_to_grid(iris.data[a], min_x, max_x);
            let iy = flip(round_to_grid(iris.data[b], min_y, max_y));
            plot[n * iy + ix] = symbolmap[&iris.name];
        }

        // render plot
        //
        // using Itertools::join
        for line in plot.chunks(n) {
            println!("{}", line.iter().join(" "))
        }
    }
}
<|endoftext|>