<commit_before><commit_msg>Added display example.<commit_after>use std::fmt; // Import `fmt`

// A structure holding two numbers. `Debug` will be derived so the results can
// be contrasted with `Display`.
#[derive(Debug)]
struct MinMax(i64, i64);

// Implement `Display` for `MinMax`.
impl fmt::Display for MinMax {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Use `self.number` to refer to each positional data point.
        write!(f, "({}, {})", self.0, self.1)
    }
}

// Define a structure where the fields are nameable for comparison.
#[derive(Debug)]
struct Point2 {
    x: f64,
    y: f64,
}

// Similarly, implement for Point2
impl fmt::Display for Point2 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Customize so only `x` and `y` are denoted.
        write!(f, "x: {}, y: {}", self.x, self.y)
    }
}

fn main() {
    let minmax = MinMax(0, 14);

    println!("Compare structures:");
    println!("Display: {}", minmax);
    println!("Debug: {:?}", minmax);

    let big_range =   MinMax(-300, 300);
    let small_range = MinMax(-3, 3);

    println!("The big range is {big} and the small is {small}",
             small = small_range,
             big = big_range);

    let point = Point2 { x: 3.3, y: 7.2 };

    println!("Compare points:");
    println!("Display: {}", point);
    println!("Debug: {:?}", point);

    // Error. Both `Debug` and `Display` were implemented but `{:b}`
    // requires `fmt::Binary` to be implemented. This will not work.
    // println!("What does Point2D look like in binary: {:b}?", point);
}
<|endoftext|>


<commit_before><commit_msg>error<commit_after><|endoftext|>


<commit_before>// xfail-pretty

fn id(x: bool) -> bool { x }

fn call_id() {
    let c <- fail;
    id(c);
}

fn call_id_2() { id(true) && id(ret); }

fn call_id_3() { id(ret) && id(ret); }

fn call_id_4() { while id(break) { } }

iter put_break() -> int {
    while true { put break; }
}

fn log_fail() { log_err fail; }

fn ret_ret() -> int { ret (ret 2) + 3; }

fn ret_guard() {
    alt 2 {
      x when (ret) { x; }
    }
}

fn fail_then_concat() {
    let x = [], y = [3];
    fail;
    x += y;
    "good" + "bye";
}

fn main() {}
<commit_msg>Add more unreachable-code tests. Closes #935<commit_after>// xfail-pretty

fn id(x: bool) -> bool { x }

fn call_id() {
    let c <- fail;
    id(c);
}

fn call_id_2() { id(true) && id(ret); }

fn call_id_3() { id(ret) && id(ret); }

fn call_id_4() { while id(break) { } }

iter put_break() -> int {
    while true { put break; }
}

fn log_fail() { log_err fail; }

fn log_ret() { log_err ret; }

fn log_break() { while true { log_err break; } }

fn log_cont() { do { log_err cont; } while false }

fn ret_ret() -> int { ret (ret 2) + 3; }

fn ret_guard() {
    alt 2 {
      x when (ret) { x; }
    }
}

fn fail_then_concat() {
    let x = [], y = [3];
    fail;
    x += y;
    "good" + "bye";
}

fn main() {}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use RawUniformValue;

use smallvec::SmallVec;

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

pub struct UniformsStorage {
    values: RefCell<SmallVec<[Option<RawUniformValue>; 16]>>,
    uniform_blocks: RefCell<SmallVec<[Option<gl::types::GLuint>; 4]>>,
    shader_storage_blocks: RefCell<SmallVec<[Option<gl::types::GLuint>; 4]>>,
}

impl UniformsStorage {
    /// Builds a new empty storage.
    #[inline]
    pub fn new() -> UniformsStorage {
        UniformsStorage {
            values: RefCell::new(SmallVec::new()),
            uniform_blocks: RefCell::new(SmallVec::new()),
            shader_storage_blocks: RefCell::new(SmallVec::new()),
        }
    }

    /// Compares `value` with the value stored in this object. If the values differ, updates
    /// the storage and calls `glUniform`.
    pub fn set_uniform_value(&self, ctxt: &mut CommandContext, program: Handle,
                             location: gl::types::GLint, value: &RawUniformValue)
    {
        let mut values = self.values.borrow_mut();

        if values.len() <= location as usize {
            for _ in (values.len() .. location as usize + 1) {
                values.push(None);
            }
        }

        // TODO: don't assume that, instead use DSA if the program is not current
        assert!(ctxt.state.program == program);

        macro_rules! uniform(
            ($ctxt:expr, $uniform:ident, $uniform_arb:ident, $($params:expr),+) => (
                unsafe {
                    if $ctxt.version >= &Version(Api::Gl, 1, 5) ||
                       $ctxt.version >= &Version(Api::GlEs, 2, 0)
                    {
                        $ctxt.gl.$uniform($($params),+)
                    } else {
                        assert!($ctxt.extensions.gl_arb_shader_objects);
                        $ctxt.gl.$uniform_arb($($params),+)
                    }
                }
            )
        );

        macro_rules! uniform64(
            ($ctxt:expr, $uniform:ident, $($params:expr),+) => (
                unsafe {
                    if $ctxt.extensions.gl_arb_gpu_shader_fp64 {
                        $ctxt.gl.$uniform($($params),+)
                    } else {
                        panic!("Double precision is not supported on this system.")
                    }
                }
            )
        );

        match (value, &mut values[location as usize]) {
            (&RawUniformValue::SignedInt(a), &mut Some(RawUniformValue::SignedInt(b))) if a == b => (),
            (&RawUniformValue::UnsignedInt(a), &mut Some(RawUniformValue::UnsignedInt(b))) if a == b => (),
            (&RawUniformValue::Float(a), &mut Some(RawUniformValue::Float(b))) if a == b => (),
            (&RawUniformValue::Mat2(a), &mut Some(RawUniformValue::Mat2(b))) if a == b => (),
            (&RawUniformValue::Mat3(a), &mut Some(RawUniformValue::Mat3(b))) if a == b => (),
            (&RawUniformValue::Mat4(a), &mut Some(RawUniformValue::Mat4(b))) if a == b => (),
            (&RawUniformValue::Vec2(a), &mut Some(RawUniformValue::Vec2(b))) if a == b => (),
            (&RawUniformValue::Vec3(a), &mut Some(RawUniformValue::Vec3(b))) if a == b => (),
            (&RawUniformValue::Vec4(a), &mut Some(RawUniformValue::Vec4(b))) if a == b => (),
            (&RawUniformValue::IntVec2(a), &mut Some(RawUniformValue::IntVec2(b))) if a == b => (),
            (&RawUniformValue::IntVec3(a), &mut Some(RawUniformValue::IntVec3(b))) if a == b => (),
            (&RawUniformValue::IntVec4(a), &mut Some(RawUniformValue::IntVec4(b))) if a == b => (),
            (&RawUniformValue::UnsignedIntVec2(a), &mut Some(RawUniformValue::UnsignedIntVec2(b))) if a == b => (),
            (&RawUniformValue::UnsignedIntVec3(a), &mut Some(RawUniformValue::UnsignedIntVec3(b))) if a == b => (),
            (&RawUniformValue::UnsignedIntVec4(a), &mut Some(RawUniformValue::UnsignedIntVec4(b))) if a == b => (),
            (&RawUniformValue::Double(a), &mut Some(RawUniformValue::Double(b))) if a == b => (),
            (&RawUniformValue::DoubleMat2(a), &mut Some(RawUniformValue::DoubleMat2(b))) if a == b => (),
            (&RawUniformValue::DoubleMat3(a), &mut Some(RawUniformValue::DoubleMat3(b))) if a == b => (),
            (&RawUniformValue::DoubleMat4(a), &mut Some(RawUniformValue::DoubleMat4(b))) if a == b => (),
            (&RawUniformValue::DoubleVec2(a), &mut Some(RawUniformValue::DoubleVec2(b))) if a == b => (),
            (&RawUniformValue::DoubleVec3(a), &mut Some(RawUniformValue::DoubleVec3(b))) if a == b => (),
            (&RawUniformValue::DoubleVec4(a), &mut Some(RawUniformValue::DoubleVec4(b))) if a == b => (),

            (&RawUniformValue::SignedInt(v), target) => {
                *target = Some(RawUniformValue::SignedInt(v));
                uniform!(ctxt, Uniform1i, Uniform1iARB, location, v);
            },

            (&RawUniformValue::UnsignedInt(v), target) => {
                *target = Some(RawUniformValue::UnsignedInt(v));

                // Uniform1uiARB doesn't exist
                unsafe {
                    if ctxt.version >= &Version(Api::Gl, 1, 5) ||
                       ctxt.version >= &Version(Api::GlEs, 2, 0)
                    {
                        ctxt.gl.Uniform1ui(location, v)
                    } else {
                        assert!(ctxt.extensions.gl_arb_shader_objects);
                        ctxt.gl.Uniform1iARB(location, v as gl::types::GLint)
                    }
                }
            },

            (&RawUniformValue::Float(v), target) => {
                *target = Some(RawUniformValue::Float(v));
                uniform!(ctxt, Uniform1f, Uniform1fARB, location, v);
            },

            (&RawUniformValue::Mat2(v), target) => {
                *target = Some(RawUniformValue::Mat2(v));
                uniform!(ctxt, UniformMatrix2fv, UniformMatrix2fvARB,
                         location, 1, gl::FALSE, v.as_ptr() as *const f32);
            },

            (&RawUniformValue::Mat3(v), target) => {
                *target = Some(RawUniformValue::Mat3(v));
                uniform!(ctxt, UniformMatrix3fv, UniformMatrix3fvARB,
                         location, 1, gl::FALSE, v.as_ptr() as *const f32);
            },

            (&RawUniformValue::Mat4(v), target) => {
                *target = Some(RawUniformValue::Mat4(v));
                uniform!(ctxt, UniformMatrix4fv, UniformMatrix4fvARB,
                         location, 1, gl::FALSE, v.as_ptr() as *const f32);
            },

            (&RawUniformValue::Vec2(v), target) => {
                *target = Some(RawUniformValue::Vec2(v));
                uniform!(ctxt, Uniform2fv, Uniform2fvARB, location, 1, v.as_ptr() as *const f32);
            },

            (&RawUniformValue::Vec3(v), target) => {
                *target = Some(RawUniformValue::Vec3(v));
                uniform!(ctxt, Uniform3fv, Uniform3fvARB, location, 1, v.as_ptr() as *const f32);
            },

            (&RawUniformValue::Vec4(v), target) => {
                *target = Some(RawUniformValue::Vec4(v));
                uniform!(ctxt, Uniform4fv, Uniform4fvARB, location, 1, v.as_ptr() as *const f32);
            },

            (&RawUniformValue::IntVec2(v), target) => {
                *target = Some(RawUniformValue::IntVec2(v));
                uniform!(ctxt, Uniform2iv, Uniform2ivARB, location, 1, v.as_ptr() as *const gl::types::GLint);
            },

            (&RawUniformValue::IntVec3(v), target) => {
                *target = Some(RawUniformValue::IntVec3(v));
                uniform!(ctxt, Uniform3iv, Uniform3ivARB, location, 1, v.as_ptr() as *const gl::types::GLint);
            },

            (&RawUniformValue::IntVec4(v), target) => {
                *target = Some(RawUniformValue::IntVec4(v));
                uniform!(ctxt, Uniform4iv, Uniform4ivARB, location, 1, v.as_ptr() as *const gl::types::GLint);
            },

            (&RawUniformValue::UnsignedIntVec2(v), target) => {
                *target = Some(RawUniformValue::UnsignedIntVec2(v));

                // Uniform2uivARB doesn't exist
                unsafe {
                    if ctxt.version >= &Version(Api::Gl, 1, 5) ||
                       ctxt.version >= &Version(Api::GlEs, 2, 0)
                    {
                        ctxt.gl.Uniform2uiv(location, 1, v.as_ptr() as *const gl::types::GLuint)
                    } else {
                        assert!(ctxt.extensions.gl_arb_shader_objects);
                        ctxt.gl.Uniform2ivARB(location, 1, v.as_ptr() as *const gl::types::GLint)
                    }
                }
            },

            (&RawUniformValue::UnsignedIntVec3(v), target) => {
                *target = Some(RawUniformValue::UnsignedIntVec3(v));

                // Uniform3uivARB doesn't exist
                unsafe {
                    if ctxt.version >= &Version(Api::Gl, 1, 5) ||
                       ctxt.version >= &Version(Api::GlEs, 2, 0)
                    {
                        ctxt.gl.Uniform3uiv(location, 1, v.as_ptr() as *const gl::types::GLuint)
                    } else {
                        assert!(ctxt.extensions.gl_arb_shader_objects);
                        ctxt.gl.Uniform3ivARB(location, 1, v.as_ptr() as *const gl::types::GLint)
                    }
                }
            },

            (&RawUniformValue::UnsignedIntVec4(v), target) => {
                *target = Some(RawUniformValue::UnsignedIntVec4(v));

                // Uniform4uivARB doesn't exist
                unsafe {
                    if ctxt.version >= &Version(Api::Gl, 1, 5) ||
                       ctxt.version >= &Version(Api::GlEs, 2, 0)
                    {
                        ctxt.gl.Uniform4uiv(location, 1, v.as_ptr() as *const gl::types::GLuint)
                    } else {
                        assert!(ctxt.extensions.gl_arb_shader_objects);
                        ctxt.gl.Uniform4ivARB(location, 1, v.as_ptr() as *const gl::types::GLint)
                    }
                }
            },
            (&RawUniformValue::Double(v), target) => {
                *target = Some(RawUniformValue::Double(v));
                uniform64!(ctxt, Uniform1d, location, v);
            },

            (&RawUniformValue::DoubleMat2(v), target) => {
                *target = Some(RawUniformValue::DoubleMat2(v));
                uniform64!(ctxt, UniformMatrix2dv,
                         location, 1, gl::FALSE, v.as_ptr() as *const gl::types::GLdouble);
            },

            (&RawUniformValue::DoubleMat3(v), target) => {
                *target = Some(RawUniformValue::DoubleMat3(v));
                uniform64!(ctxt, UniformMatrix3dv,
                         location, 1, gl::FALSE, v.as_ptr() as *const gl::types::GLdouble);
            },

            (&RawUniformValue::DoubleMat4(v), target) => {
                *target = Some(RawUniformValue::DoubleMat4(v));
                uniform64!(ctxt, UniformMatrix4dv,
                         location, 1, gl::FALSE, v.as_ptr() as *const gl::types::GLdouble);
            },

            (&RawUniformValue::DoubleVec2(v), target) => {
                *target = Some(RawUniformValue::DoubleVec2(v));
                uniform64!(ctxt, Uniform2dv, location, 1, v.as_ptr() as *const gl::types::GLdouble);
            },

            (&RawUniformValue::DoubleVec3(v), target) => {
                *target = Some(RawUniformValue::DoubleVec3(v));
                uniform64!(ctxt, Uniform3dv, location, 1, v.as_ptr() as *const gl::types::GLdouble);
            },

            (&RawUniformValue::DoubleVec4(v), target) => {
                *target = Some(RawUniformValue::DoubleVec4(v));
                uniform64!(ctxt, Uniform4dv, location, 1, v.as_ptr() as *const gl::types::GLdouble);
            },
        }
    }

    /// Compares `value` with the value stored in this object. If the values differ, updates
    /// the storage and calls `glUniformBlockBinding`.
    pub fn set_uniform_block_binding(&self, ctxt: &mut CommandContext, program: Handle,
                                     location: gl::types::GLuint, value: gl::types::GLuint)
    {
        let mut blocks = self.uniform_blocks.borrow_mut();

        if blocks.len() <= location as usize {
            for _ in (blocks.len() .. location as usize + 1) {
                blocks.push(None);
            }
        }

        // TODO: don't assume that, instead use DSA if the program is not current
        assert!(ctxt.state.program == program);

        match (value, &mut blocks[location as usize]) {
            (a, &mut Some(b)) if a == b => (),

            (a, target) => {
                *target = Some(a);
                match program {
                    Handle::Id(id) => unsafe {
                        ctxt.gl.UniformBlockBinding(id, location, value);
                    },
                    _ => unreachable!()
                }
            },
        }
    }

    /// Compares `value` with the value stored in this object. If the values differ, updates
    /// the storage and calls `glShaderStorageBlockBinding`.
    pub fn set_shader_storage_block_binding(&self, ctxt: &mut CommandContext, program: Handle,
                                            location: gl::types::GLuint, value: gl::types::GLuint)
    {
        let mut blocks = self.shader_storage_blocks.borrow_mut();

        if blocks.len() <= location as usize {
            for _ in (blocks.len() .. location as usize + 1) {
                blocks.push(None);
            }
        }

        // TODO: don't assume that, instead use DSA if the program is not current
        assert!(ctxt.state.program == program);

        match (value, &mut blocks[location as usize]) {
            (a, &mut Some(b)) if a == b => (),

            (a, target) => {
                *target = Some(a);
                match program {
                    Handle::Id(id) => unsafe {
                        ctxt.gl.ShaderStorageBlockBinding(id, location, value);
                    },
                    _ => unreachable!()
                }
            },
        }
    }
}
<commit_msg>Use a hashmap for the uniforms storage<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use RawUniformValue;

use smallvec::SmallVec;

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

pub struct UniformsStorage {
    values: RefCell<HashMap<gl::types::GLint, Option<RawUniformValue>>>,
    uniform_blocks: RefCell<SmallVec<[Option<gl::types::GLuint>; 4]>>,
    shader_storage_blocks: RefCell<SmallVec<[Option<gl::types::GLuint>; 4]>>,
}

impl UniformsStorage {
    /// Builds a new empty storage.
    #[inline]
    pub fn new() -> UniformsStorage {
        UniformsStorage {
            values: RefCell::new(HashMap::new()),
            uniform_blocks: RefCell::new(SmallVec::new()),
            shader_storage_blocks: RefCell::new(SmallVec::new()),
        }
    }

    /// Compares `value` with the value stored in this object. If the values differ, updates
    /// the storage and calls `glUniform`.
    pub fn set_uniform_value(&self, ctxt: &mut CommandContext, program: Handle,
                             location: gl::types::GLint, value: &RawUniformValue)
    {
        let mut values = self.values.borrow_mut();

        // TODO: don't assume that, instead use DSA if the program is not current
        assert!(ctxt.state.program == program);

        // TODO: more optimized
        if values.get(&location).is_none() {
            values.insert(location, None);
        }

        macro_rules! uniform(
            ($ctxt:expr, $uniform:ident, $uniform_arb:ident, $($params:expr),+) => (
                unsafe {
                    if $ctxt.version >= &Version(Api::Gl, 1, 5) ||
                       $ctxt.version >= &Version(Api::GlEs, 2, 0)
                    {
                        $ctxt.gl.$uniform($($params),+)
                    } else {
                        assert!($ctxt.extensions.gl_arb_shader_objects);
                        $ctxt.gl.$uniform_arb($($params),+)
                    }
                }
            )
        );

        macro_rules! uniform64(
            ($ctxt:expr, $uniform:ident, $($params:expr),+) => (
                unsafe {
                    if $ctxt.extensions.gl_arb_gpu_shader_fp64 {
                        $ctxt.gl.$uniform($($params),+)
                    } else {
                        panic!("Double precision is not supported on this system.")
                    }
                }
            )
        );

        match (value, values.get_mut(&location).unwrap()) {
            (&RawUniformValue::SignedInt(a), &mut Some(RawUniformValue::SignedInt(b))) if a == b => (),
            (&RawUniformValue::UnsignedInt(a), &mut Some(RawUniformValue::UnsignedInt(b))) if a == b => (),
            (&RawUniformValue::Float(a), &mut Some(RawUniformValue::Float(b))) if a == b => (),
            (&RawUniformValue::Mat2(a), &mut Some(RawUniformValue::Mat2(b))) if a == b => (),
            (&RawUniformValue::Mat3(a), &mut Some(RawUniformValue::Mat3(b))) if a == b => (),
            (&RawUniformValue::Mat4(a), &mut Some(RawUniformValue::Mat4(b))) if a == b => (),
            (&RawUniformValue::Vec2(a), &mut Some(RawUniformValue::Vec2(b))) if a == b => (),
            (&RawUniformValue::Vec3(a), &mut Some(RawUniformValue::Vec3(b))) if a == b => (),
            (&RawUniformValue::Vec4(a), &mut Some(RawUniformValue::Vec4(b))) if a == b => (),
            (&RawUniformValue::IntVec2(a), &mut Some(RawUniformValue::IntVec2(b))) if a == b => (),
            (&RawUniformValue::IntVec3(a), &mut Some(RawUniformValue::IntVec3(b))) if a == b => (),
            (&RawUniformValue::IntVec4(a), &mut Some(RawUniformValue::IntVec4(b))) if a == b => (),
            (&RawUniformValue::UnsignedIntVec2(a), &mut Some(RawUniformValue::UnsignedIntVec2(b))) if a == b => (),
            (&RawUniformValue::UnsignedIntVec3(a), &mut Some(RawUniformValue::UnsignedIntVec3(b))) if a == b => (),
            (&RawUniformValue::UnsignedIntVec4(a), &mut Some(RawUniformValue::UnsignedIntVec4(b))) if a == b => (),
            (&RawUniformValue::Double(a), &mut Some(RawUniformValue::Double(b))) if a == b => (),
            (&RawUniformValue::DoubleMat2(a), &mut Some(RawUniformValue::DoubleMat2(b))) if a == b => (),
            (&RawUniformValue::DoubleMat3(a), &mut Some(RawUniformValue::DoubleMat3(b))) if a == b => (),
            (&RawUniformValue::DoubleMat4(a), &mut Some(RawUniformValue::DoubleMat4(b))) if a == b => (),
            (&RawUniformValue::DoubleVec2(a), &mut Some(RawUniformValue::DoubleVec2(b))) if a == b => (),
            (&RawUniformValue::DoubleVec3(a), &mut Some(RawUniformValue::DoubleVec3(b))) if a == b => (),
            (&RawUniformValue::DoubleVec4(a), &mut Some(RawUniformValue::DoubleVec4(b))) if a == b => (),

            (&RawUniformValue::SignedInt(v), target) => {
                *target = Some(RawUniformValue::SignedInt(v));
                uniform!(ctxt, Uniform1i, Uniform1iARB, location, v);
            },

            (&RawUniformValue::UnsignedInt(v), target) => {
                *target = Some(RawUniformValue::UnsignedInt(v));

                // Uniform1uiARB doesn't exist
                unsafe {
                    if ctxt.version >= &Version(Api::Gl, 1, 5) ||
                       ctxt.version >= &Version(Api::GlEs, 2, 0)
                    {
                        ctxt.gl.Uniform1ui(location, v)
                    } else {
                        assert!(ctxt.extensions.gl_arb_shader_objects);
                        ctxt.gl.Uniform1iARB(location, v as gl::types::GLint)
                    }
                }
            },

            (&RawUniformValue::Float(v), target) => {
                *target = Some(RawUniformValue::Float(v));
                uniform!(ctxt, Uniform1f, Uniform1fARB, location, v);
            },

            (&RawUniformValue::Mat2(v), target) => {
                *target = Some(RawUniformValue::Mat2(v));
                uniform!(ctxt, UniformMatrix2fv, UniformMatrix2fvARB,
                         location, 1, gl::FALSE, v.as_ptr() as *const f32);
            },

            (&RawUniformValue::Mat3(v), target) => {
                *target = Some(RawUniformValue::Mat3(v));
                uniform!(ctxt, UniformMatrix3fv, UniformMatrix3fvARB,
                         location, 1, gl::FALSE, v.as_ptr() as *const f32);
            },

            (&RawUniformValue::Mat4(v), target) => {
                *target = Some(RawUniformValue::Mat4(v));
                uniform!(ctxt, UniformMatrix4fv, UniformMatrix4fvARB,
                         location, 1, gl::FALSE, v.as_ptr() as *const f32);
            },

            (&RawUniformValue::Vec2(v), target) => {
                *target = Some(RawUniformValue::Vec2(v));
                uniform!(ctxt, Uniform2fv, Uniform2fvARB, location, 1, v.as_ptr() as *const f32);
            },

            (&RawUniformValue::Vec3(v), target) => {
                *target = Some(RawUniformValue::Vec3(v));
                uniform!(ctxt, Uniform3fv, Uniform3fvARB, location, 1, v.as_ptr() as *const f32);
            },

            (&RawUniformValue::Vec4(v), target) => {
                *target = Some(RawUniformValue::Vec4(v));
                uniform!(ctxt, Uniform4fv, Uniform4fvARB, location, 1, v.as_ptr() as *const f32);
            },

            (&RawUniformValue::IntVec2(v), target) => {
                *target = Some(RawUniformValue::IntVec2(v));
                uniform!(ctxt, Uniform2iv, Uniform2ivARB, location, 1, v.as_ptr() as *const gl::types::GLint);
            },

            (&RawUniformValue::IntVec3(v), target) => {
                *target = Some(RawUniformValue::IntVec3(v));
                uniform!(ctxt, Uniform3iv, Uniform3ivARB, location, 1, v.as_ptr() as *const gl::types::GLint);
            },

            (&RawUniformValue::IntVec4(v), target) => {
                *target = Some(RawUniformValue::IntVec4(v));
                uniform!(ctxt, Uniform4iv, Uniform4ivARB, location, 1, v.as_ptr() as *const gl::types::GLint);
            },

            (&RawUniformValue::UnsignedIntVec2(v), target) => {
                *target = Some(RawUniformValue::UnsignedIntVec2(v));

                // Uniform2uivARB doesn't exist
                unsafe {
                    if ctxt.version >= &Version(Api::Gl, 1, 5) ||
                       ctxt.version >= &Version(Api::GlEs, 2, 0)
                    {
                        ctxt.gl.Uniform2uiv(location, 1, v.as_ptr() as *const gl::types::GLuint)
                    } else {
                        assert!(ctxt.extensions.gl_arb_shader_objects);
                        ctxt.gl.Uniform2ivARB(location, 1, v.as_ptr() as *const gl::types::GLint)
                    }
                }
            },

            (&RawUniformValue::UnsignedIntVec3(v), target) => {
                *target = Some(RawUniformValue::UnsignedIntVec3(v));

                // Uniform3uivARB doesn't exist
                unsafe {
                    if ctxt.version >= &Version(Api::Gl, 1, 5) ||
                       ctxt.version >= &Version(Api::GlEs, 2, 0)
                    {
                        ctxt.gl.Uniform3uiv(location, 1, v.as_ptr() as *const gl::types::GLuint)
                    } else {
                        assert!(ctxt.extensions.gl_arb_shader_objects);
                        ctxt.gl.Uniform3ivARB(location, 1, v.as_ptr() as *const gl::types::GLint)
                    }
                }
            },

            (&RawUniformValue::UnsignedIntVec4(v), target) => {
                *target = Some(RawUniformValue::UnsignedIntVec4(v));

                // Uniform4uivARB doesn't exist
                unsafe {
                    if ctxt.version >= &Version(Api::Gl, 1, 5) ||
                       ctxt.version >= &Version(Api::GlEs, 2, 0)
                    {
                        ctxt.gl.Uniform4uiv(location, 1, v.as_ptr() as *const gl::types::GLuint)
                    } else {
                        assert!(ctxt.extensions.gl_arb_shader_objects);
                        ctxt.gl.Uniform4ivARB(location, 1, v.as_ptr() as *const gl::types::GLint)
                    }
                }
            },
            (&RawUniformValue::Double(v), target) => {
                *target = Some(RawUniformValue::Double(v));
                uniform64!(ctxt, Uniform1d, location, v);
            },

            (&RawUniformValue::DoubleMat2(v), target) => {
                *target = Some(RawUniformValue::DoubleMat2(v));
                uniform64!(ctxt, UniformMatrix2dv,
                         location, 1, gl::FALSE, v.as_ptr() as *const gl::types::GLdouble);
            },

            (&RawUniformValue::DoubleMat3(v), target) => {
                *target = Some(RawUniformValue::DoubleMat3(v));
                uniform64!(ctxt, UniformMatrix3dv,
                         location, 1, gl::FALSE, v.as_ptr() as *const gl::types::GLdouble);
            },

            (&RawUniformValue::DoubleMat4(v), target) => {
                *target = Some(RawUniformValue::DoubleMat4(v));
                uniform64!(ctxt, UniformMatrix4dv,
                         location, 1, gl::FALSE, v.as_ptr() as *const gl::types::GLdouble);
            },

            (&RawUniformValue::DoubleVec2(v), target) => {
                *target = Some(RawUniformValue::DoubleVec2(v));
                uniform64!(ctxt, Uniform2dv, location, 1, v.as_ptr() as *const gl::types::GLdouble);
            },

            (&RawUniformValue::DoubleVec3(v), target) => {
                *target = Some(RawUniformValue::DoubleVec3(v));
                uniform64!(ctxt, Uniform3dv, location, 1, v.as_ptr() as *const gl::types::GLdouble);
            },

            (&RawUniformValue::DoubleVec4(v), target) => {
                *target = Some(RawUniformValue::DoubleVec4(v));
                uniform64!(ctxt, Uniform4dv, location, 1, v.as_ptr() as *const gl::types::GLdouble);
            },
        }
    }

    /// Compares `value` with the value stored in this object. If the values differ, updates
    /// the storage and calls `glUniformBlockBinding`.
    pub fn set_uniform_block_binding(&self, ctxt: &mut CommandContext, program: Handle,
                                     location: gl::types::GLuint, value: gl::types::GLuint)
    {
        let mut blocks = self.uniform_blocks.borrow_mut();

        if blocks.len() <= location as usize {
            for _ in (blocks.len() .. location as usize + 1) {
                blocks.push(None);
            }
        }

        // TODO: don't assume that, instead use DSA if the program is not current
        assert!(ctxt.state.program == program);

        match (value, &mut blocks[location as usize]) {
            (a, &mut Some(b)) if a == b => (),

            (a, target) => {
                *target = Some(a);
                match program {
                    Handle::Id(id) => unsafe {
                        ctxt.gl.UniformBlockBinding(id, location, value);
                    },
                    _ => unreachable!()
                }
            },
        }
    }

    /// Compares `value` with the value stored in this object. If the values differ, updates
    /// the storage and calls `glShaderStorageBlockBinding`.
    pub fn set_shader_storage_block_binding(&self, ctxt: &mut CommandContext, program: Handle,
                                            location: gl::types::GLuint, value: gl::types::GLuint)
    {
        let mut blocks = self.shader_storage_blocks.borrow_mut();

        if blocks.len() <= location as usize {
            for _ in (blocks.len() .. location as usize + 1) {
                blocks.push(None);
            }
        }

        // TODO: don't assume that, instead use DSA if the program is not current
        assert!(ctxt.state.program == program);

        match (value, &mut blocks[location as usize]) {
            (a, &mut Some(b)) if a == b => (),

            (a, target) => {
                *target = Some(a);
                match program {
                    Handle::Id(id) => unsafe {
                        ctxt.gl.ShaderStorageBlockBinding(id, location, value);
                    },
                    _ => unreachable!()
                }
            },
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate rustfmt;
extern crate diff;
extern crate regex;
extern crate term;

use std::collections::HashMap;
use std::fs;
use std::io::{self, Read, BufRead, BufReader};
use std::path::Path;

use rustfmt::*;
use rustfmt::filemap::write_system_newlines;
use rustfmt::config::{Config, ReportTactic, WriteMode};
use rustfmt::rustfmt_diff::*;

static DIFF_CONTEXT_SIZE: usize = 3;

fn get_path_string(dir_entry: io::Result<fs::DirEntry>) -> String {
    let path = dir_entry.ok().expect("Couldn't get DirEntry.").path();

    path.to_str().expect("Couldn't stringify path.").to_owned()
}

// Integration tests. The files in the tests/source are formatted and compared
// to their equivalent in tests/target. The target file and config can be
// overriden by annotations in the source file. The input and output must match
// exactly.
// FIXME(#28) would be good to check for error messages and fail on them, or at
// least report.
#[test]
fn system_tests() {
    // Get all files in the tests/source directory.
    let files = fs::read_dir("tests/source").ok().expect("Couldn't read source dir.");
    // Turn a DirEntry into a String that represents the relative path to the
    // file.
    let files = files.map(get_path_string);
    let (_reports, count, fails) = check_files(files, WriteMode::Default);

    // Display results.
    println!("Ran {} system tests.", count);
    assert!(fails == 0, "{} system tests failed", fails);
}

// Do the same for tests/coverage-source directory
// the only difference is the coverage mode
#[test]
fn coverage_tests() {
    let files = fs::read_dir("tests/coverage-source").ok().expect("Couldn't read source dir.");
    let files = files.map(get_path_string);
    let (_reports, count, fails) = check_files(files, WriteMode::Coverage);

    println!("Ran {} tests in coverage mode.", count);
    assert!(fails == 0, "{} tests failed", fails);
}

#[test]
fn checkstyle_test() {
    let filename = "tests/source/fn-single-line.rs".to_string();
    let expected = "tests/writemode/checkstyle.xml";

    let output = run_rustfmt(filename.clone(), WriteMode::Checkstyle);

    let mut expected_file = fs::File::open(&expected)
                                .ok()
                                .expect("Couldn't open target.");
    let mut expected_text = String::new();
    expected_file.read_to_string(&mut expected_text)
                 .ok()
                 .expect("Failed reading target.");

    let compare = make_diff(&expected_text, &output, DIFF_CONTEXT_SIZE);
    if compare.len() > 0 {
        let mut failures = HashMap::new();
        failures.insert(filename, compare);
        print_mismatches(failures);
        assert!(false, "Text does not match expected output");
    }
}

// Idempotence tests. Files in tests/target are checked to be unaltered by
// rustfmt.
#[test]
fn idempotence_tests() {
    // Get all files in the tests/target directory.
    let files = fs::read_dir("tests/target")
                    .ok()
                    .expect("Couldn't read target dir.")
                    .map(get_path_string);
    let (_reports, count, fails) = check_files(files, WriteMode::Default);

    // Display results.
    println!("Ran {} idempotent tests.", count);
    assert!(fails == 0, "{} idempotent tests failed", fails);
}

// Run rustfmt on itself. This operation must be idempotent. We also check that
// no warnings are emitted.
#[test]
fn self_tests() {
    let files = fs::read_dir("src/bin")
                    .ok()
                    .expect("Couldn't read src dir.")
                    .chain(fs::read_dir("tests").ok().expect("Couldn't read tests dir."))
                    .map(get_path_string);
    // Hack because there's no `IntoIterator` impl for `[T; N]`.
    let files = files.chain(Some("src/lib.rs".to_owned()).into_iter());

    let (reports, count, fails) = check_files(files, WriteMode::Default);
    let mut warnings = 0;

    // Display results.
    println!("Ran {} self tests.", count);
    assert!(fails == 0, "{} self tests failed", fails);

    for format_report in reports {
        println!("{}", format_report);
        warnings += format_report.warning_count();
    }

    assert!(warnings == 0,
            "Rustfmt's code generated {} warnings",
            warnings);
}

// For each file, run rustfmt and collect the output.
// Returns the number of files checked and the number of failures.
fn check_files<I>(files: I, write_mode: WriteMode) -> (Vec<FormatReport>, u32, u32)
    where I: Iterator<Item = String>
{
    let mut count = 0;
    let mut fails = 0;
    let mut reports = vec![];

    for file_name in files.filter(|f| f.ends_with(".rs")) {
        println!("Testing '{}'...", file_name);

        match idempotent_check(file_name, write_mode) {
            Ok(report) => reports.push(report),
            Err(msg) => {
                print_mismatches(msg);
                fails += 1;
            }
        }

        count += 1;
    }

    (reports, count, fails)
}

fn print_mismatches(result: HashMap<String, Vec<Mismatch>>) {
    let mut t = term::stdout().unwrap();

    for (file_name, diff) in result {
        print_diff(diff,
                   |line_num| format!("\nMismatch at {}:{}:", file_name, line_num));
    }

    assert!(t.reset().unwrap());
}

pub fn run_rustfmt(filename: String, write_mode: WriteMode) -> String {
    let sig_comments = read_significant_comments(&filename);
    let mut config = get_config(sig_comments.get("config").map(|x| &(*x)[..]));

    for (key, val) in &sig_comments {
        if key != "target" && key != "config" {
            config.override_value(key, val);
        }
    }

    // Don't generate warnings for to-do items.
    config.report_todo = ReportTactic::Never;

    // Simulate run()
    let mut out = Vec::new();
    let file_map = format(Path::new(&filename), &config, write_mode);
    let _ = filemap::write_all_files(&file_map, &mut out, write_mode, &config);
    String::from_utf8(out).unwrap()
}

pub fn idempotent_check(filename: String,
                        write_mode: WriteMode)
                        -> Result<FormatReport, HashMap<String, Vec<Mismatch>>> {
    let sig_comments = read_significant_comments(&filename);
    let mut config = get_config(sig_comments.get("config").map(|x| &(*x)[..]));

    for (key, val) in &sig_comments {
        if key != "target" && key != "config" {
            config.override_value(key, val);
        }
    }

    // Don't generate warnings for to-do items.
    config.report_todo = ReportTactic::Never;

    let mut file_map = format(Path::new(&filename), &config, write_mode);
    let format_report = fmt_lines(&mut file_map, &config);

    let mut write_result = HashMap::new();
    for (filename, text) in file_map.iter() {
        let mut v = Vec::new();
        // Won't panic, as we're not doing any IO.
        write_system_newlines(&mut v, text, &config).unwrap();
        // Won't panic, we are writing correct utf8.
        let one_result = String::from_utf8(v).unwrap();
        write_result.insert(filename.clone(), one_result);
    }

    let target = sig_comments.get("target").map(|x| &(*x)[..]);

    handle_result(write_result, target, write_mode).map(|_| format_report)
}

// Reads test config file from comments and reads its contents.
fn get_config(config_file: Option<&str>) -> Config {
    let config_file_name = match config_file {
        None => return Default::default(),
        Some(file_name) => {
            let mut full_path = "tests/config/".to_owned();
            full_path.push_str(&file_name);
            full_path
        }
    };

    let mut def_config_file = fs::File::open(config_file_name)
                                  .ok()
                                  .expect("Couldn't open config.");
    let mut def_config = String::new();
    def_config_file.read_to_string(&mut def_config).ok().expect("Couldn't read config.");

    Config::from_toml(&def_config)
}

// Reads significant comments of the form: // rustfmt-key: value
// into a hash map.
fn read_significant_comments(file_name: &str) -> HashMap<String, String> {
    let file = fs::File::open(file_name)
                   .ok()
                   .expect(&format!("Couldn't read file {}.", file_name));
    let reader = BufReader::new(file);
    let pattern = r"^\s*//\s*rustfmt-([^:]+):\s*(\S+)";
    let regex = regex::Regex::new(&pattern).ok().expect("Failed creating pattern 1.");

    // Matches lines containing significant comments or whitespace.
    let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)")
                         .ok()
                         .expect("Failed creating pattern 2.");

    reader.lines()
          .map(|line| line.ok().expect("Failed getting line."))
          .take_while(|line| line_regex.is_match(&line))
          .filter_map(|line| {
              regex.captures_iter(&line).next().map(|capture| {
                  (capture.at(1).expect("Couldn't unwrap capture.").to_owned(),
                   capture.at(2).expect("Couldn't unwrap capture.").to_owned())
              })
          })
          .collect()
}

// Compare output to input.
// TODO: needs a better name, more explanation.
fn handle_result(result: HashMap<String, String>,
                 target: Option<&str>,
                 write_mode: WriteMode)
                 -> Result<(), HashMap<String, Vec<Mismatch>>> {
    let mut failures = HashMap::new();

    for (file_name, fmt_text) in result {
        // If file is in tests/source, compare to file with same name in tests/target.
        let target = get_target(&file_name, target, write_mode);
        let mut f = fs::File::open(&target).ok().expect("Couldn't open target.");

        let mut text = String::new();
        f.read_to_string(&mut text).ok().expect("Failed reading target.");

        if fmt_text != text {
            let diff = make_diff(&text, &fmt_text, DIFF_CONTEXT_SIZE);
            failures.insert(file_name, diff);
        }
    }

    if failures.is_empty() {
        Ok(())
    } else {
        Err(failures)
    }
}

// Map source file paths to their target paths.
fn get_target(file_name: &str, target: Option<&str>, write_mode: WriteMode) -> String {
    let file_path = Path::new(file_name);
    let (source_path_prefix, target_path_prefix) = match write_mode {
        WriteMode::Coverage => {
            (Path::new("tests/coverage-source/"),
             "tests/coverage-target/")
        }
        _ => (Path::new("tests/source/"), "tests/target/"),
    };

    if file_path.starts_with(source_path_prefix) {
        let mut components = file_path.components();
        // Can't skip(2) as the resulting iterator can't as_path()
        components.next();
        components.next();

        let new_target = match components.as_path().to_str() {
            Some(string) => string,
            None => file_name,
        };
        let base = target.unwrap_or(new_target);

        format!("{}{}", target_path_prefix, base)
    } else {
        file_name.to_owned()
    }
}

#[test]
fn rustfmt_diff_make_diff_tests() {
    let diff = make_diff("a\nb\nc\nd", "a\ne\nc\nd", 3);
    assert_eq!(diff,
               vec![Mismatch {
                        line_number: 1,
                        lines: vec![DiffLine::Context("a".into()),
                                    DiffLine::Resulting("b".into()),
                                    DiffLine::Expected("e".into()),
                                    DiffLine::Context("c".into()),
                                    DiffLine::Context("d".into())],
                    }]);
}
<commit_msg>Extract helper functions for testing.<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate rustfmt;
extern crate diff;
extern crate regex;
extern crate term;

use std::collections::HashMap;
use std::fs;
use std::io::{self, Read, BufRead, BufReader};
use std::path::Path;

use rustfmt::*;
use rustfmt::filemap::{write_system_newlines, FileMap};
use rustfmt::config::{Config, ReportTactic, WriteMode};
use rustfmt::rustfmt_diff::*;

static DIFF_CONTEXT_SIZE: usize = 3;

fn get_path_string(dir_entry: io::Result<fs::DirEntry>) -> String {
    let path = dir_entry.ok().expect("Couldn't get DirEntry.").path();

    path.to_str().expect("Couldn't stringify path.").to_owned()
}

// Integration tests. The files in the tests/source are formatted and compared
// to their equivalent in tests/target. The target file and config can be
// overriden by annotations in the source file. The input and output must match
// exactly.
// FIXME(#28) would be good to check for error messages and fail on them, or at
// least report.
#[test]
fn system_tests() {
    // Get all files in the tests/source directory.
    let files = fs::read_dir("tests/source").ok().expect("Couldn't read source dir.");
    // Turn a DirEntry into a String that represents the relative path to the
    // file.
    let files = files.map(get_path_string);
    let (_reports, count, fails) = check_files(files, WriteMode::Default);

    // Display results.
    println!("Ran {} system tests.", count);
    assert!(fails == 0, "{} system tests failed", fails);
}

// Do the same for tests/coverage-source directory
// the only difference is the coverage mode
#[test]
fn coverage_tests() {
    let files = fs::read_dir("tests/coverage-source").ok().expect("Couldn't read source dir.");
    let files = files.map(get_path_string);
    let (_reports, count, fails) = check_files(files, WriteMode::Coverage);

    println!("Ran {} tests in coverage mode.", count);
    assert!(fails == 0, "{} tests failed", fails);
}

#[test]
fn checkstyle_test() {
    let filename = "tests/source/fn-single-line.rs";
    let expected_filename = "tests/writemode/checkstyle.xml";
    assert_output(filename, expected_filename, WriteMode::Checkstyle);
}

// Helper function for comparing the results of rustfmt
// to a known output file generated by one of the write modes.
fn assert_output(source: &str, expected_filename: &str, write_mode: WriteMode) {
    let config = read_config(&source);
    let file_map = run_rustfmt(source.to_string(), write_mode);

    // Populate output by writing to a vec.
    let mut out = vec![];
    let _ = filemap::write_all_files(&file_map, &mut out, write_mode, &config);
    let output = String::from_utf8(out).unwrap();

    let mut expected_file = fs::File::open(&expected_filename)
                                .ok()
                                .expect("Couldn't open target.");
    let mut expected_text = String::new();
    expected_file.read_to_string(&mut expected_text)
                 .ok()
                 .expect("Failed reading target.");

    let compare = make_diff(&expected_text, &output, DIFF_CONTEXT_SIZE);
    if compare.len() > 0 {
        let mut failures = HashMap::new();
        failures.insert(source.to_string(), compare);
        print_mismatches(failures);
        assert!(false, "Text does not match expected output");
    }
}

// Idempotence tests. Files in tests/target are checked to be unaltered by
// rustfmt.
#[test]
fn idempotence_tests() {
    // Get all files in the tests/target directory.
    let files = fs::read_dir("tests/target")
                    .ok()
                    .expect("Couldn't read target dir.")
                    .map(get_path_string);
    let (_reports, count, fails) = check_files(files, WriteMode::Default);

    // Display results.
    println!("Ran {} idempotent tests.", count);
    assert!(fails == 0, "{} idempotent tests failed", fails);
}

// Run rustfmt on itself. This operation must be idempotent. We also check that
// no warnings are emitted.
#[test]
fn self_tests() {
    let files = fs::read_dir("src/bin")
                    .ok()
                    .expect("Couldn't read src dir.")
                    .chain(fs::read_dir("tests").ok().expect("Couldn't read tests dir."))
                    .map(get_path_string);
    // Hack because there's no `IntoIterator` impl for `[T; N]`.
    let files = files.chain(Some("src/lib.rs".to_owned()).into_iter());

    let (reports, count, fails) = check_files(files, WriteMode::Default);
    let mut warnings = 0;

    // Display results.
    println!("Ran {} self tests.", count);
    assert!(fails == 0, "{} self tests failed", fails);

    for format_report in reports {
        println!("{}", format_report);
        warnings += format_report.warning_count();
    }

    assert!(warnings == 0,
            "Rustfmt's code generated {} warnings",
            warnings);
}

// For each file, run rustfmt and collect the output.
// Returns the number of files checked and the number of failures.
fn check_files<I>(files: I, write_mode: WriteMode) -> (Vec<FormatReport>, u32, u32)
    where I: Iterator<Item = String>
{
    let mut count = 0;
    let mut fails = 0;
    let mut reports = vec![];

    for file_name in files.filter(|f| f.ends_with(".rs")) {
        println!("Testing '{}'...", file_name);

        match idempotent_check(file_name, write_mode) {
            Ok(report) => reports.push(report),
            Err(msg) => {
                print_mismatches(msg);
                fails += 1;
            }
        }

        count += 1;
    }

    (reports, count, fails)
}

fn print_mismatches(result: HashMap<String, Vec<Mismatch>>) {
    let mut t = term::stdout().unwrap();

    for (file_name, diff) in result {
        print_diff(diff,
                   |line_num| format!("\nMismatch at {}:{}:", file_name, line_num));
    }

    assert!(t.reset().unwrap());
}

fn read_config(filename: &str) -> Config {
    let sig_comments = read_significant_comments(&filename);
    let mut config = get_config(sig_comments.get("config").map(|x| &(*x)[..]));

    for (key, val) in &sig_comments {
        if key != "target" && key != "config" {
            config.override_value(key, val);
        }
    }

    // Don't generate warnings for to-do items.
    config.report_todo = ReportTactic::Never;
    config
}

// Simulate run()
fn run_rustfmt(filename: String, write_mode: WriteMode) -> FileMap {
    let config = read_config(&filename);
    format(Path::new(&filename), &config, write_mode)
}

pub fn idempotent_check(filename: String,
                        write_mode: WriteMode)
                        -> Result<FormatReport, HashMap<String, Vec<Mismatch>>> {
    let sig_comments = read_significant_comments(&filename);
    let config = read_config(&filename);
    let mut file_map = run_rustfmt(filename, write_mode);
    let format_report = fmt_lines(&mut file_map, &config);

    let mut write_result = HashMap::new();
    for (filename, text) in file_map.iter() {
        let mut v = Vec::new();
        // Won't panic, as we're not doing any IO.
        write_system_newlines(&mut v, text, &config).unwrap();
        // Won't panic, we are writing correct utf8.
        let one_result = String::from_utf8(v).unwrap();
        write_result.insert(filename.clone(), one_result);
    }

    let target = sig_comments.get("target").map(|x| &(*x)[..]);

    handle_result(write_result, target, write_mode).map(|_| format_report)
}

// Reads test config file from comments and reads its contents.
fn get_config(config_file: Option<&str>) -> Config {
    let config_file_name = match config_file {
        None => return Default::default(),
        Some(file_name) => {
            let mut full_path = "tests/config/".to_owned();
            full_path.push_str(&file_name);
            full_path
        }
    };

    let mut def_config_file = fs::File::open(config_file_name)
                                  .ok()
                                  .expect("Couldn't open config.");
    let mut def_config = String::new();
    def_config_file.read_to_string(&mut def_config).ok().expect("Couldn't read config.");

    Config::from_toml(&def_config)
}

// Reads significant comments of the form: // rustfmt-key: value
// into a hash map.
fn read_significant_comments(file_name: &str) -> HashMap<String, String> {
    let file = fs::File::open(file_name)
                   .ok()
                   .expect(&format!("Couldn't read file {}.", file_name));
    let reader = BufReader::new(file);
    let pattern = r"^\s*//\s*rustfmt-([^:]+):\s*(\S+)";
    let regex = regex::Regex::new(&pattern).ok().expect("Failed creating pattern 1.");

    // Matches lines containing significant comments or whitespace.
    let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)")
                         .ok()
                         .expect("Failed creating pattern 2.");

    reader.lines()
          .map(|line| line.ok().expect("Failed getting line."))
          .take_while(|line| line_regex.is_match(&line))
          .filter_map(|line| {
              regex.captures_iter(&line).next().map(|capture| {
                  (capture.at(1).expect("Couldn't unwrap capture.").to_owned(),
                   capture.at(2).expect("Couldn't unwrap capture.").to_owned())
              })
          })
          .collect()
}

// Compare output to input.
// TODO: needs a better name, more explanation.
fn handle_result(result: HashMap<String, String>,
                 target: Option<&str>,
                 write_mode: WriteMode)
                 -> Result<(), HashMap<String, Vec<Mismatch>>> {
    let mut failures = HashMap::new();

    for (file_name, fmt_text) in result {
        // If file is in tests/source, compare to file with same name in tests/target.
        let target = get_target(&file_name, target, write_mode);
        let mut f = fs::File::open(&target).ok().expect("Couldn't open target.");

        let mut text = String::new();
        f.read_to_string(&mut text).ok().expect("Failed reading target.");

        if fmt_text != text {
            let diff = make_diff(&text, &fmt_text, DIFF_CONTEXT_SIZE);
            failures.insert(file_name, diff);
        }
    }

    if failures.is_empty() {
        Ok(())
    } else {
        Err(failures)
    }
}

// Map source file paths to their target paths.
fn get_target(file_name: &str, target: Option<&str>, write_mode: WriteMode) -> String {
    let file_path = Path::new(file_name);
    let (source_path_prefix, target_path_prefix) = match write_mode {
        WriteMode::Coverage => {
            (Path::new("tests/coverage-source/"),
             "tests/coverage-target/")
        }
        _ => (Path::new("tests/source/"), "tests/target/"),
    };

    if file_path.starts_with(source_path_prefix) {
        let mut components = file_path.components();
        // Can't skip(2) as the resulting iterator can't as_path()
        components.next();
        components.next();

        let new_target = match components.as_path().to_str() {
            Some(string) => string,
            None => file_name,
        };
        let base = target.unwrap_or(new_target);

        format!("{}{}", target_path_prefix, base)
    } else {
        file_name.to_owned()
    }
}

#[test]
fn rustfmt_diff_make_diff_tests() {
    let diff = make_diff("a\nb\nc\nd", "a\ne\nc\nd", 3);
    assert_eq!(diff,
               vec![Mismatch {
                        line_number: 1,
                        lines: vec![DiffLine::Context("a".into()),
                                    DiffLine::Resulting("b".into()),
                                    DiffLine::Expected("e".into()),
                                    DiffLine::Context("c".into()),
                                    DiffLine::Context("d".into())],
                    }]);
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Parsing of GCC-style Language-Specific Data Area (LSDA)
//! For details see:
//!   http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
//!   http://mentorembedded.github.io/cxx-abi/exceptions.pdf
//!   http://www.airs.com/blog/archives/460
//!   http://www.airs.com/blog/archives/464
//!
//! A reference implementation may be found in the GCC source tree
//! (<root>/libgcc/unwind-c.c as of this writing)

#![allow(non_upper_case_globals)]
#![allow(unused)]

use dwarf::DwarfReader;
use core::mem;

pub const DW_EH_PE_omit: u8 = 0xFF;
pub const DW_EH_PE_absptr: u8 = 0x00;

pub const DW_EH_PE_uleb128: u8 = 0x01;
pub const DW_EH_PE_udata2: u8 = 0x02;
pub const DW_EH_PE_udata4: u8 = 0x03;
pub const DW_EH_PE_udata8: u8 = 0x04;
pub const DW_EH_PE_sleb128: u8 = 0x09;
pub const DW_EH_PE_sdata2: u8 = 0x0A;
pub const DW_EH_PE_sdata4: u8 = 0x0B;
pub const DW_EH_PE_sdata8: u8 = 0x0C;

pub const DW_EH_PE_pcrel: u8 = 0x10;
pub const DW_EH_PE_textrel: u8 = 0x20;
pub const DW_EH_PE_datarel: u8 = 0x30;
pub const DW_EH_PE_funcrel: u8 = 0x40;
pub const DW_EH_PE_aligned: u8 = 0x50;

pub const DW_EH_PE_indirect: u8 = 0x80;

#[derive(Copy, Clone)]
pub struct EHContext<'a> {
    pub ip: usize, // Current instruction pointer
    pub func_start: usize, // Address of the current function
    pub get_text_start: &'a Fn() -> usize, // Get address of the code section
    pub get_data_start: &'a Fn() -> usize, // Get address of the data section
}

pub enum EHAction {
    None,
    Cleanup(usize),
    Catch(usize),
    Terminate,
}

pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));

pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
    if lsda.is_null() {
        return EHAction::None;
    }

    let func_start = context.func_start;
    let mut reader = DwarfReader::new(lsda);

    let start_encoding = reader.read::<u8>();
    // base address for landing pad offsets
    let lpad_base = if start_encoding != DW_EH_PE_omit {
        read_encoded_pointer(&mut reader, context, start_encoding)
    } else {
        func_start
    };

    let ttype_encoding = reader.read::<u8>();
    if ttype_encoding != DW_EH_PE_omit {
        // Rust doesn't analyze exception types, so we don't care about the type table
        reader.read_uleb128();
    }

    let call_site_encoding = reader.read::<u8>();
    let call_site_table_length = reader.read_uleb128();
    let action_table = reader.ptr.offset(call_site_table_length as isize);
    let ip = context.ip;

    if !USING_SJLJ_EXCEPTIONS {
        while reader.ptr < action_table {
            let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_action = reader.read_uleb128();
            // Callsite table is sorted by cs_start, so if we've passed the ip, we
            // may stop searching.
            if ip < func_start + cs_start {
                break;
            }
            if ip < func_start + cs_start + cs_len {
                if cs_lpad == 0 {
                    return EHAction::None;
                } else {
                    let lpad = lpad_base + cs_lpad;
                    return interpret_cs_action(cs_action, lpad);
                }
            }
        }
        // If ip is not present in the table, call terminate.  This is for
        // a destructor inside a cleanup, or a library routine the compiler
        // was not expecting to throw
        EHAction::Terminate
    } else {
        // SjLj version:
        // The "IP" is an index into the call-site table, with two exceptions:
        // -1 means 'no-action', and 0 means 'terminate'.
        match ip as isize {
           -1 => return EHAction::None,
            0 => return EHAction::Terminate,
            _ => (),
        }
        let mut idx = ip;
        loop {
            let cs_lpad = reader.read_uleb128();
            let cs_action = reader.read_uleb128();
            idx -= 1;
            if idx == 0 {
                // Can never have null landing pad for sjlj -- that would have
                // been indicated by a -1 call site index.
                let lpad = (cs_lpad + 1) as usize;
                return interpret_cs_action(cs_action, lpad);
            }
        }
    }
}

fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
    if cs_action == 0 {
        EHAction::Cleanup(lpad)
    } else {
        EHAction::Catch(lpad)
    }
}

#[inline]
fn round_up(unrounded: usize, align: usize) -> usize {
    assert!(align.is_power_of_two());
    (unrounded + align - 1) & !(align - 1)
}

unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
                               context: &EHContext,
                               encoding: u8)
                               -> usize {
    assert!(encoding != DW_EH_PE_omit);

    // DW_EH_PE_aligned implies it's an absolute pointer value
    if encoding == DW_EH_PE_aligned {
        reader.ptr = round_up(reader.ptr as usize, mem::size_of::<usize>()) as *const u8;
        return reader.read::<usize>();
    }

    let mut result = match encoding & 0x0F {
        DW_EH_PE_absptr => reader.read::<usize>(),
        DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
        DW_EH_PE_udata2 => reader.read::<u16>() as usize,
        DW_EH_PE_udata4 => reader.read::<u32>() as usize,
        DW_EH_PE_udata8 => reader.read::<u64>() as usize,
        DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
        DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
        DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
        DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
        _ => panic!(),
    };

    result += match encoding & 0x70 {
        DW_EH_PE_absptr => 0,
        // relative to address of the encoded value, despite the name
        DW_EH_PE_pcrel => reader.ptr as usize,
        DW_EH_PE_funcrel => {
            assert!(context.func_start != 0);
            context.func_start
        }
        DW_EH_PE_textrel => {
            (*context.get_text_start)()
        }
        DW_EH_PE_datarel => {
            (*context.get_data_start)()
        }
        _ => panic!(),
    };

    if encoding & DW_EH_PE_indirect != 0 {
        result = *(result as *const usize);
    }

    result
}
<commit_msg>Looser LSDA parsing<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Parsing of GCC-style Language-Specific Data Area (LSDA)
//! For details see:
//!   http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
//!   http://mentorembedded.github.io/cxx-abi/exceptions.pdf
//!   http://www.airs.com/blog/archives/460
//!   http://www.airs.com/blog/archives/464
//!
//! A reference implementation may be found in the GCC source tree
//! (<root>/libgcc/unwind-c.c as of this writing)

#![allow(non_upper_case_globals)]
#![allow(unused)]

use dwarf::DwarfReader;
use core::mem;

pub const DW_EH_PE_omit: u8 = 0xFF;
pub const DW_EH_PE_absptr: u8 = 0x00;

pub const DW_EH_PE_uleb128: u8 = 0x01;
pub const DW_EH_PE_udata2: u8 = 0x02;
pub const DW_EH_PE_udata4: u8 = 0x03;
pub const DW_EH_PE_udata8: u8 = 0x04;
pub const DW_EH_PE_sleb128: u8 = 0x09;
pub const DW_EH_PE_sdata2: u8 = 0x0A;
pub const DW_EH_PE_sdata4: u8 = 0x0B;
pub const DW_EH_PE_sdata8: u8 = 0x0C;

pub const DW_EH_PE_pcrel: u8 = 0x10;
pub const DW_EH_PE_textrel: u8 = 0x20;
pub const DW_EH_PE_datarel: u8 = 0x30;
pub const DW_EH_PE_funcrel: u8 = 0x40;
pub const DW_EH_PE_aligned: u8 = 0x50;

pub const DW_EH_PE_indirect: u8 = 0x80;

#[derive(Copy, Clone)]
pub struct EHContext<'a> {
    pub ip: usize, // Current instruction pointer
    pub func_start: usize, // Address of the current function
    pub get_text_start: &'a Fn() -> usize, // Get address of the code section
    pub get_data_start: &'a Fn() -> usize, // Get address of the data section
}

pub enum EHAction {
    None,
    Cleanup(usize),
    Catch(usize),
    Terminate,
}

pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));

pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction {
    if lsda.is_null() {
        return EHAction::None;
    }

    let func_start = context.func_start;
    let mut reader = DwarfReader::new(lsda);

    let start_encoding = reader.read::<u8>();
    // base address for landing pad offsets
    let lpad_base = if start_encoding != DW_EH_PE_omit {
        read_encoded_pointer(&mut reader, context, start_encoding)
    } else {
        func_start
    };

    let ttype_encoding = reader.read::<u8>();
    if ttype_encoding != DW_EH_PE_omit {
        // Rust doesn't analyze exception types, so we don't care about the type table
        reader.read_uleb128();
    }

    let call_site_encoding = reader.read::<u8>();
    let call_site_table_length = reader.read_uleb128();
    let action_table = reader.ptr.offset(call_site_table_length as isize);
    let ip = context.ip;

    if !USING_SJLJ_EXCEPTIONS {
        while reader.ptr < action_table {
            let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding);
            let cs_action = reader.read_uleb128();
            // Callsite table is sorted by cs_start, so if we've passed the ip, we
            // may stop searching.
            if ip < func_start + cs_start {
                break;
            }
            if ip < func_start + cs_start + cs_len {
                if cs_lpad == 0 {
                    return EHAction::None;
                } else {
                    let lpad = lpad_base + cs_lpad;
                    return interpret_cs_action(cs_action, lpad);
                }
            }
        }
        // Ip is not present in the table.  This should not hapen... but it does: issie #35011.
        // So rather than returning EHAction::Terminate, we do this.
        EHAction::None
    } else {
        // SjLj version:
        // The "IP" is an index into the call-site table, with two exceptions:
        // -1 means 'no-action', and 0 means 'terminate'.
        match ip as isize {
           -1 => return EHAction::None,
            0 => return EHAction::Terminate,
            _ => (),
        }
        let mut idx = ip;
        loop {
            let cs_lpad = reader.read_uleb128();
            let cs_action = reader.read_uleb128();
            idx -= 1;
            if idx == 0 {
                // Can never have null landing pad for sjlj -- that would have
                // been indicated by a -1 call site index.
                let lpad = (cs_lpad + 1) as usize;
                return interpret_cs_action(cs_action, lpad);
            }
        }
    }
}

fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
    if cs_action == 0 {
        EHAction::Cleanup(lpad)
    } else {
        EHAction::Catch(lpad)
    }
}

#[inline]
fn round_up(unrounded: usize, align: usize) -> usize {
    assert!(align.is_power_of_two());
    (unrounded + align - 1) & !(align - 1)
}

unsafe fn read_encoded_pointer(reader: &mut DwarfReader,
                               context: &EHContext,
                               encoding: u8)
                               -> usize {
    assert!(encoding != DW_EH_PE_omit);

    // DW_EH_PE_aligned implies it's an absolute pointer value
    if encoding == DW_EH_PE_aligned {
        reader.ptr = round_up(reader.ptr as usize, mem::size_of::<usize>()) as *const u8;
        return reader.read::<usize>();
    }

    let mut result = match encoding & 0x0F {
        DW_EH_PE_absptr => reader.read::<usize>(),
        DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
        DW_EH_PE_udata2 => reader.read::<u16>() as usize,
        DW_EH_PE_udata4 => reader.read::<u32>() as usize,
        DW_EH_PE_udata8 => reader.read::<u64>() as usize,
        DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
        DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
        DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
        DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
        _ => panic!(),
    };

    result += match encoding & 0x70 {
        DW_EH_PE_absptr => 0,
        // relative to address of the encoded value, despite the name
        DW_EH_PE_pcrel => reader.ptr as usize,
        DW_EH_PE_funcrel => {
            assert!(context.func_start != 0);
            context.func_start
        }
        DW_EH_PE_textrel => {
            (*context.get_text_start)()
        }
        DW_EH_PE_datarel => {
            (*context.get_data_start)()
        }
        _ => panic!(),
    };

    if encoding & DW_EH_PE_indirect != 0 {
        result = *(result as *const usize);
    }

    result
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::pio::*;

use schemes::KScheme;

/// PS2
pub struct Ps2 {
    /// The data
    data: Pio8,
    /// The command
    cmd: Pio8,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: isize,
    /// Mouse point y
    mouse_y: isize,
    /// Layout for keyboard
    layout: usize,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio8::new(0x60),
            cmd: Pio8::new(0x64),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
            layout: 0,
        };

        unsafe {
            module.keyboard_init();
            module.mouse_init();
        }

        module
    }

    unsafe fn wait0(&self) {
        while (self.cmd.read() & 1) == 0 {}
    }

    unsafe fn wait1(&self) {
        while (self.cmd.read() & 2) == 2 {}
    }

    unsafe fn keyboard_init(&mut self) {
        while (self.cmd.read() & 0x1) == 1 {
            self.data.read();
        }

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let flags = (self.data.read() & 0b00110111) | 1 | 0b10000;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(flags);

        // Set Defaults
        self.wait1();
        self.data.write(0xF6);
        self.wait0();
        self.data.read();

        // Set LEDS
        self.wait1();
        self.data.write(0xED);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(0);
        self.wait0();
        self.data.read();

        // Set Scancode Map:
        self.wait1();
        self.data.write(0xF0);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(1);
        self.wait0();
        self.data.read();
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let scancode = unsafe { self.data.read() };

        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        }

        let shift;
        if self.caps_lock {
            shift = !(self.lshift || self.rshift);
        } else {
            shift = self.lshift || self.rshift;
        }

        return Some(KeyEvent {
            character: char_for_scancode(scancode & 0x7F, shift, self.layout),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    unsafe fn mouse_cmd(&mut self, byte: u8) -> u8 {
        self.wait1();
        self.cmd.write(0xD4);
        self.wait1();
        self.data.write(byte);

        self.wait0();
        self.data.read()
    }

    /// Initialize mouse
    pub unsafe fn mouse_init(&mut self) {
        // The Init Dance
        self.wait1();
        self.cmd.write(0xA8);

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let status = self.data.read() | 2;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(status);

        // Set defaults
        self.mouse_cmd(0xF6);

        // Enable Streaming
        self.mouse_cmd(0xF4);
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = unsafe { self.data.read() };
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = self.mouse_packet[1] as isize -
                    (((self.mouse_packet[0] as isize) << 4) & 0x100);
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = (((self.mouse_packet[0] as isize) << 3) & 0x100) -
                    self.mouse_packet[2] as isize;
            } else {
                y = 0;
            }

            unsafe {
                self.mouse_x = cmp::max(0,
                                        cmp::min((*::console).display.width as isize,
                                                 self.mouse_x + x));
                self.mouse_y = cmp::max(0,
                                        cmp::min((*::console).display.height as isize,
                                                 self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }

    /// Function to change the layout of the keyboard
    pub fn change_layout(&mut self, layout: usize) {
        self.layout = layout;
    }

}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            self.on_poll();
        }
    }

    fn on_poll(&mut self) {
        loop {
            let status = unsafe { self.cmd.read() };
            if status & 0x21 == 1 {
                if let Some(key_event) = self.keyboard_interrupt() {
                    key_event.trigger();
                }
            } else if status & 0x21 == 0x21 {
                if let Some(mouse_event) = self.mouse_interrupt() {
                    mouse_event.trigger();
                }
            } else {
                break;
            }
        }
    }
}

/// Function to return the character associated with the scancode, and the layout
fn char_for_scancode(scancode: u8, shift: bool, layout: usize) -> char {
    if scancode >= 58 {
        '\x00'
    }
    let character =
        match layout {
            0 => SCANCODES_EN[scancode as usize],
            1 => SCANCODES_FR[scancode as usize],
        };
    if shift {
        character = characters[1]
    } else {
        character = characters[scancode as usize][0]
    }
}

static SCANCODES_EN: [[char; 2]; 58] = [['\0', '\0'],
                                     ['\x1B', '\x1B'],
                                     ['1', '!'],
                                     ['2', '@'],
                                     ['3', '#'],
                                     ['4', '$'],
                                     ['5', '%'],
                                     ['6', '^'],
                                     ['7', '&'],
                                     ['8', '*'],
                                     ['9', '('],
                                     ['0', ')'],
                                     ['-', '_'],
                                     ['=', '+'],
                                     ['\0', '\0'],
                                     ['\t', '\t'],
                                     ['q', 'Q'],
                                     ['w', 'W'],
                                     ['e', 'E'],
                                     ['r', 'R'],
                                     ['t', 'T'],
                                     ['y', 'Y'],
                                     ['u', 'U'],
                                     ['i', 'I'],
                                     ['o', 'O'],
                                     ['p', 'P'],
                                     ['[', '{'],
                                     [']', '}'],
                                     ['\n', '\n'],
                                     ['\0', '\0'],
                                     ['a', 'A'],
                                     ['s', 'S'],
                                     ['d', 'D'],
                                     ['f', 'F'],
                                     ['g', 'G'],
                                     ['h', 'H'],
                                     ['j', 'J'],
                                     ['k', 'K'],
                                     ['l', 'L'],
                                     [';', ':'],
                                     ['\'', '"'],
                                     ['`', '~'],
                                     ['\0', '\0'],
                                     ['\\', '|'],
                                     ['z', 'Z'],
                                     ['x', 'X'],
                                     ['c', 'C'],
                                     ['v', 'V'],
                                     ['b', 'B'],
                                     ['n', 'N'],
                                     ['m', 'M'],
                                     [',', '<'],
                                     ['.', '>'],
                                     ['/', '?'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     [' ', ' ']];

 static SCANCODES_FR: [[char; 2]; 58] = [['\0', '\0'],
                                      ['\x1B', '\x1B'],
                                      ['1', '&'],
                                      ['2', 'é'],
                                      ['3', '"'],
                                      ['4', '\''],
                                      ['5', '('],
                                      ['6', '-'],
                                      ['7', 'è'],
                                      ['8', '_'],
                                      ['9', 'ç'],
                                      ['0', 'à'],
                                      ['-', ')'],
                                      ['=', '='],
                                      ['\0', '\0'],
                                      ['\t', '\t'],
                                      ['a', 'A'],
                                      ['z', 'Z'],
                                      ['e', 'E'],
                                      ['r', 'R'],
                                      ['t', 'T'],
                                      ['y', 'Y'],
                                      ['u', 'U'],
                                      ['i', 'I'],
                                      ['o', 'O'],
                                      ['p', 'P'],
                                      ['^', '¨'],
                                      ['$', '£'],
                                      ['\n', '\n'],
                                      ['\0', '\0'],
                                      ['q', 'Q'],
                                      ['s', 'S'],
                                      ['d', 'D'],
                                      ['f', 'F'],
                                      ['g', 'G'],
                                      ['h', 'H'],
                                      ['j', 'J'],
                                      ['k', 'K'],
                                      ['l', 'L'],
                                      ['m', 'M'],
                                      ['ù', '%'],
                                      ['*', 'µ'],
                                      ['\0', '\0'],
                                      ['<', '>'],
                                      ['w', 'W'],
                                      ['x', 'X'],
                                      ['c', 'C'],
                                      ['v', 'V'],
                                      ['b', 'B'],
                                      ['n', 'N'],
                                      [',', '?'],
                                      [';', '.'],
                                      [':', '/'],
                                      ['!', '§'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      [' ', ' ']];
<commit_msg>debugging char_for_scancode<commit_after>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::pio::*;

use schemes::KScheme;

/// PS2
pub struct Ps2 {
    /// The data
    data: Pio8,
    /// The command
    cmd: Pio8,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: isize,
    /// Mouse point y
    mouse_y: isize,
    /// Layout for keyboard
    layout: usize,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio8::new(0x60),
            cmd: Pio8::new(0x64),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
            layout: 0,
        };

        unsafe {
            module.keyboard_init();
            module.mouse_init();
        }

        module
    }

    unsafe fn wait0(&self) {
        while (self.cmd.read() & 1) == 0 {}
    }

    unsafe fn wait1(&self) {
        while (self.cmd.read() & 2) == 2 {}
    }

    unsafe fn keyboard_init(&mut self) {
        while (self.cmd.read() & 0x1) == 1 {
            self.data.read();
        }

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let flags = (self.data.read() & 0b00110111) | 1 | 0b10000;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(flags);

        // Set Defaults
        self.wait1();
        self.data.write(0xF6);
        self.wait0();
        self.data.read();

        // Set LEDS
        self.wait1();
        self.data.write(0xED);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(0);
        self.wait0();
        self.data.read();

        // Set Scancode Map:
        self.wait1();
        self.data.write(0xF0);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(1);
        self.wait0();
        self.data.read();
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let scancode = unsafe { self.data.read() };

        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        }

        let shift;
        if self.caps_lock {
            shift = !(self.lshift || self.rshift);
        } else {
            shift = self.lshift || self.rshift;
        }

        return Some(KeyEvent {
            character: char_for_scancode(scancode & 0x7F, shift, self.layout),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    unsafe fn mouse_cmd(&mut self, byte: u8) -> u8 {
        self.wait1();
        self.cmd.write(0xD4);
        self.wait1();
        self.data.write(byte);

        self.wait0();
        self.data.read()
    }

    /// Initialize mouse
    pub unsafe fn mouse_init(&mut self) {
        // The Init Dance
        self.wait1();
        self.cmd.write(0xA8);

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let status = self.data.read() | 2;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(status);

        // Set defaults
        self.mouse_cmd(0xF6);

        // Enable Streaming
        self.mouse_cmd(0xF4);
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = unsafe { self.data.read() };
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = self.mouse_packet[1] as isize -
                    (((self.mouse_packet[0] as isize) << 4) & 0x100);
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = (((self.mouse_packet[0] as isize) << 3) & 0x100) -
                    self.mouse_packet[2] as isize;
            } else {
                y = 0;
            }

            unsafe {
                self.mouse_x = cmp::max(0,
                                        cmp::min((*::console).display.width as isize,
                                                 self.mouse_x + x));
                self.mouse_y = cmp::max(0,
                                        cmp::min((*::console).display.height as isize,
                                                 self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }

    /// Function to change the layout of the keyboard
    pub fn change_layout(&mut self, layout: usize) {
        self.layout = layout;
    }

}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            self.on_poll();
        }
    }

    fn on_poll(&mut self) {
        loop {
            let status = unsafe { self.cmd.read() };
            if status & 0x21 == 1 {
                if let Some(key_event) = self.keyboard_interrupt() {
                    key_event.trigger();
                }
            } else if status & 0x21 == 0x21 {
                if let Some(mouse_event) = self.mouse_interrupt() {
                    mouse_event.trigger();
                }
            } else {
                break;
            }
        }
    }
}

/// Function to return the character associated with the scancode, and the layout
fn char_for_scancode(scancode: u8, shift: bool, layout: usize) -> char {
    if scancode >= 58 {
        '\x00'
    }
    let characters =
        match layout {
            0 => SCANCODES_EN[scancode as usize],
            1 => SCANCODES_FR[scancode as usize],
        };
    if shift {
        character = characters[1]
    } else {
        character = characters[scancode as usize][0]
    }
}

static SCANCODES_EN: [[char; 2]; 58] = [['\0', '\0'],
                                     ['\x1B', '\x1B'],
                                     ['1', '!'],
                                     ['2', '@'],
                                     ['3', '#'],
                                     ['4', '$'],
                                     ['5', '%'],
                                     ['6', '^'],
                                     ['7', '&'],
                                     ['8', '*'],
                                     ['9', '('],
                                     ['0', ')'],
                                     ['-', '_'],
                                     ['=', '+'],
                                     ['\0', '\0'],
                                     ['\t', '\t'],
                                     ['q', 'Q'],
                                     ['w', 'W'],
                                     ['e', 'E'],
                                     ['r', 'R'],
                                     ['t', 'T'],
                                     ['y', 'Y'],
                                     ['u', 'U'],
                                     ['i', 'I'],
                                     ['o', 'O'],
                                     ['p', 'P'],
                                     ['[', '{'],
                                     [']', '}'],
                                     ['\n', '\n'],
                                     ['\0', '\0'],
                                     ['a', 'A'],
                                     ['s', 'S'],
                                     ['d', 'D'],
                                     ['f', 'F'],
                                     ['g', 'G'],
                                     ['h', 'H'],
                                     ['j', 'J'],
                                     ['k', 'K'],
                                     ['l', 'L'],
                                     [';', ':'],
                                     ['\'', '"'],
                                     ['`', '~'],
                                     ['\0', '\0'],
                                     ['\\', '|'],
                                     ['z', 'Z'],
                                     ['x', 'X'],
                                     ['c', 'C'],
                                     ['v', 'V'],
                                     ['b', 'B'],
                                     ['n', 'N'],
                                     ['m', 'M'],
                                     [',', '<'],
                                     ['.', '>'],
                                     ['/', '?'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     [' ', ' ']];

 static SCANCODES_FR: [[char; 2]; 58] = [['\0', '\0'],
                                      ['\x1B', '\x1B'],
                                      ['1', '&'],
                                      ['2', 'é'],
                                      ['3', '"'],
                                      ['4', '\''],
                                      ['5', '('],
                                      ['6', '-'],
                                      ['7', 'è'],
                                      ['8', '_'],
                                      ['9', 'ç'],
                                      ['0', 'à'],
                                      ['-', ')'],
                                      ['=', '='],
                                      ['\0', '\0'],
                                      ['\t', '\t'],
                                      ['a', 'A'],
                                      ['z', 'Z'],
                                      ['e', 'E'],
                                      ['r', 'R'],
                                      ['t', 'T'],
                                      ['y', 'Y'],
                                      ['u', 'U'],
                                      ['i', 'I'],
                                      ['o', 'O'],
                                      ['p', 'P'],
                                      ['^', '¨'],
                                      ['$', '£'],
                                      ['\n', '\n'],
                                      ['\0', '\0'],
                                      ['q', 'Q'],
                                      ['s', 'S'],
                                      ['d', 'D'],
                                      ['f', 'F'],
                                      ['g', 'G'],
                                      ['h', 'H'],
                                      ['j', 'J'],
                                      ['k', 'K'],
                                      ['l', 'L'],
                                      ['m', 'M'],
                                      ['ù', '%'],
                                      ['*', 'µ'],
                                      ['\0', '\0'],
                                      ['<', '>'],
                                      ['w', 'W'],
                                      ['x', 'X'],
                                      ['c', 'C'],
                                      ['v', 'V'],
                                      ['b', 'B'],
                                      ['n', 'N'],
                                      [',', '?'],
                                      [';', '.'],
                                      [':', '/'],
                                      ['!', '§'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      [' ', ' ']];
<|endoftext|>