<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate cgmath;
#[macro_use]
extern crate gfx;
extern crate gfx_core;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate gfx_gl as gl;
extern crate gfx_device_gl;

use cgmath::{SquareMatrix, Matrix, Point3, Vector3, Matrix3, Matrix4};
use cgmath::{Transform, Vector4};
pub use gfx::format::{DepthStencil, Rgba8 as ColorFormat};
//use glfw::Context;
use gl::Gl;
use gl::types::*;
use std::mem;
use std::ptr;
use std::str;
use std::env;
use std::str::FromStr;
use std::iter::repeat;
use std::ffi::CString;
use std::time::{Duration, Instant};
use gfx_device_gl::{Resources as R, CommandBuffer as CB};
use gfx_core::Device;

gfx_defines!{
    vertex Vertex {
        pos: [f32; 3] = "a_Pos",
    }

    pipeline pipe {
        vbuf: gfx::VertexBuffer<Vertex> = (),
        transform: gfx::Global<[[f32; 4]; 4]> = "u_Transform",
        out_color: gfx::RenderTarget<ColorFormat> = "o_Color",
    }
}

static VERTEX_SRC: &'static [u8] = b"
    #version 150 core
    in vec3 a_Pos;
    uniform mat4 u_Transform;

    void main() {
        gl_Position = u_Transform * vec4(a_Pos, 1.0);
   }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 150 core
    out vec4 o_Color;

    void main() {
        o_Color = vec4(1.0, 0.0, 0.0, 1.0);
    }
";

static VERTEX_DATA: &'static [Vertex] = &[
    Vertex { pos: [-1.0, 0.0, -1.0] },
    Vertex { pos: [ 1.0, 0.0, -1.0] },
    Vertex { pos: [-1.0, 0.0,  1.0] },
];

const CLEAR_COLOR: (f32, f32, f32, f32) = (0.3, 0.3, 0.3, 1.0);

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

fn transform(x: i16, y: i16, proj_view: &Matrix4<f32>) -> Matrix4<f32> {
    let mut model = Matrix4::from(Matrix3::identity() * 0.05);
    model.w = Vector4::new(x as f32 * 0.10,
                           0f32,
                           y as f32 * 0.10,
                           1f32);
    proj_view * model
}

trait Renderer: Drop {
    fn render(&mut self, proj_view: &Matrix4<f32>);
    fn window(&mut self) -> &glutin::Window;
}

struct GFX {
    dimension: i16,
    window: glutin::Window,
    device:gfx_device_gl::Device,
    encoder: gfx::Encoder<R,CB>,
    data: pipe::Data<R>,
    pso: gfx::PipelineState<R, pipe::Meta>,
    slice: gfx::Slice<R>,
}

struct GL {
    dimension: i16,
    window: glutin::Window,
    gl:Gl,
    trans_uniform:GLint,
    vs:GLuint,
    fs:GLuint,
    program:GLuint,
    vbo:GLuint,
    vao:GLuint,
}

impl GFX {
    fn new(builder: glutin::WindowBuilder, dimension: i16) -> Self {
        use gfx::traits::FactoryExt;

        let (window, device, mut factory, main_color, _) =
            gfx_window_glutin::init::<ColorFormat, DepthStencil>(builder);
        let encoder: gfx::Encoder<_,_> = factory.create_command_buffer().into();

        let pso = factory.create_pipeline_simple(
            VERTEX_SRC, FRAGMENT_SRC,
            pipe::new()
        ).unwrap();

        let (vbuf, slice) = factory.create_vertex_buffer_with_slice(VERTEX_DATA,());

        let data = pipe::Data {
            vbuf: vbuf,
            transform: cgmath::Matrix4::identity().into(),
            out_color: main_color,
        };

        GFX {
            window: window,
            dimension: dimension,
            device: device,
            encoder: encoder,
            data: data,
            pso: pso,
            slice: slice,
        }
    }
}

fn duration_to_f64(dur: Duration) -> f64 {
   dur.as_secs() as f64 + dur.subsec_nanos() as f64 / 1000_000_000.0
}

impl Renderer for GFX {
    fn render(&mut self, proj_view: &Matrix4<f32>) {
        let start = Instant::now();
        self.encoder.clear(&self.data.out_color, [CLEAR_COLOR.0,
                                                  CLEAR_COLOR.1,
                                                  CLEAR_COLOR.2,
                                                  CLEAR_COLOR.3]);

        for x in (-self.dimension) ..self.dimension {
            for y in (-self.dimension) ..self.dimension {
                self.data.transform = transform(x, y, proj_view).into();
                self.encoder.draw(&self.slice, &self.pso, &self.data);
            }
        }

        let pre_submit = start.elapsed();
        self.encoder.flush(&mut self.device);
        let post_submit = start.elapsed();
        self.window.swap_buffers().unwrap();
        self.device.cleanup();
        let swap = start.elapsed();

        println!("total time:\t\t{0:4.2}ms", duration_to_f64(swap));
        println!("\tcreate list:\t{0:4.2}ms", duration_to_f64(pre_submit));
        println!("\tsubmit:\t\t{0:4.2}ms", duration_to_f64(post_submit - pre_submit));
        println!("\tgpu wait:\t{0:4.2}ms", duration_to_f64(swap - post_submit));
    }
    fn window(&mut self) -> &glutin::Window { &self.window }
}

impl Drop for GFX {
    fn drop(&mut self) {
    }
}

impl GL {
    fn new(builder: glutin::WindowBuilder, dimension: i16) -> Self {
        fn compile_shader (gl:&Gl, src: &[u8], ty: GLenum) -> GLuint {
            unsafe {
                let shader = gl.CreateShader(ty);
                // Attempt to compile the shader
                gl.ShaderSource(shader, 1,
                                &(src.as_ptr() as *const i8),
                                &(src.len() as GLint));
                gl.CompileShader(shader);

                // Get the compile status
                let mut status = gl::FALSE as GLint;
                gl.GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

                // Fail on error
                if status != (gl::TRUE as GLint) {
                    let mut len: GLint = 0;
                    gl.GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);

                    // allocate a buffer of size (len - 1) to skip the trailing null character
                    let mut buf: Vec<u8> = repeat(0u8).take((len as usize).saturating_sub(1)).collect();
                    gl.GetShaderInfoLog(shader, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
                    panic!("{}", str::from_utf8(&buf).ok().expect("ShaderInfoLog not valid utf8"));
                }
                shader
            }
        };

        let window = builder.build().unwrap();
        unsafe { window.make_current().unwrap() };
        let gl = Gl::load_with(|s| window.get_proc_address(s) as *const _);

        // Create GLSL shaders
        let vs = compile_shader(&gl, VERTEX_SRC, gl::VERTEX_SHADER);
        let fs = compile_shader(&gl, FRAGMENT_SRC, gl::FRAGMENT_SHADER);

        // Link program
        let program;
        unsafe {
            program = gl.CreateProgram();
            gl.AttachShader(program, vs);
            gl.AttachShader(program, fs);
            gl.LinkProgram(program);
            // Get the link status
            let mut status = gl::FALSE as GLint;
            gl.GetProgramiv(program, gl::LINK_STATUS, &mut status);

            // Fail on error
            if status != (gl::TRUE as GLint) {
                let mut len: GLint = 0;
                gl.GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);

                // allocate a buffer of size (len - 1) to skip the trailing null character
                let mut buf: Vec<u8> = repeat(0u8).take((len as usize).saturating_sub(1)).collect();
                gl.GetProgramInfoLog(program, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
                panic!("{}", str::from_utf8(&buf).ok().expect("ProgramInfoLog not valid utf8"));
            }
        }

        let mut vao = 0;
        let mut vbo = 0;

        let trans_uniform;
        unsafe {
            // Create Vertex Array Object
            gl.GenVertexArrays(1, &mut vao);
            gl.BindVertexArray(vao);

            // Create a Vertex Buffer Object and copy the vertex data to it
            gl.GenBuffers(1, &mut vbo);
            gl.BindBuffer(gl::ARRAY_BUFFER, vbo);

            gl.BufferData(gl::ARRAY_BUFFER,
                          (VERTEX_DATA.len() * mem::size_of::<Vertex>()) as GLsizeiptr,
                          mem::transmute(&VERTEX_DATA[0]),
                          gl::STATIC_DRAW);

            // Use shader program
            gl.UseProgram(program);
            let o_color = CString::new("o_Color").unwrap();
            gl.BindFragDataLocation(program, 0, o_color.as_bytes_with_nul().as_ptr() as *const i8);

            // Specify the layout of the vertex data
            let a_pos = CString::new("a_Pos").unwrap();
            gl.BindFragDataLocation(program, 0, a_pos.as_bytes_with_nul().as_ptr() as *const i8);

            let pos_attr = gl.GetAttribLocation(program, a_pos.as_ptr());
            gl.EnableVertexAttribArray(pos_attr as GLuint);
            gl.VertexAttribPointer(pos_attr as GLuint, 3, gl::FLOAT,
                                   gl::FALSE as GLboolean, 0, ptr::null());

            let u_transform = CString::new("u_Transform").unwrap();
            trans_uniform = gl.GetUniformLocation(program, u_transform.as_bytes_with_nul().as_ptr() as *const i8)
        };

        GL {
            window: window,
            dimension: dimension,
            gl: gl,
            vs: vs,
            fs: fs,
            program: program,
            vbo: vbo,
            vao: vao,
            trans_uniform: trans_uniform,
        }
    }
}

fn duration_to_ms(dur: Duration) -> f64 {
    (dur.as_secs() * 1000) as f64 + dur.subsec_nanos() as f64 / 1000_000.0
}

impl Renderer for GL {
    fn render(&mut self, proj_view: &Matrix4<f32>) {
        let start = Instant::now();

        // Clear the screen to black
        unsafe {
            self.gl.ClearColor(CLEAR_COLOR.0, CLEAR_COLOR.1, CLEAR_COLOR.2, CLEAR_COLOR.3);
            self.gl.Clear(gl::COLOR_BUFFER_BIT);
        }

        for x in (-self.dimension) ..self.dimension {
            for y in (-self.dimension) ..self.dimension {
                let mat:Matrix4<f32> = transform(x, y, proj_view).into();

                unsafe {
                    self.gl.UniformMatrix4fv(self.trans_uniform,
                                             1,
                                             gl::FALSE,
                                             mat.as_ptr());
                    self.gl.DrawArrays(gl::TRIANGLES, 0, 3);
                }

            }
        }

        let submit = start.elapsed();

        // Swap buffers
        self.window.swap_buffers().unwrap();
        let swap = start.elapsed();

        println!("total time:\t\t{0:4.2}ms", duration_to_ms(swap));
        println!("\tsubmit:\t\t{0:4.2}ms", duration_to_ms(submit));
        println!("\tgpu wait:\t{0:4.2}ms", duration_to_ms(swap - submit));
    }
    fn window(&mut self) -> &glutin::Window { &self.window }
}

impl Drop for GL {
    fn drop(&mut self) {
        unsafe {
            self.gl.DeleteProgram(self.program);
            self.gl.DeleteShader(self.fs);
            self.gl.DeleteShader(self.vs);
            self.gl.DeleteBuffers(1, &self.vbo);
            self.gl.DeleteVertexArrays(1, &self.vao);
        }
    }
}

fn main() {
    let ref mut args = env::args();
    let args_count = env::args().count();
    if args_count == 1 {
        println!("gfx-perf [gl|gfx] <size>");
        return;
    }

    let mode = args.nth(1).unwrap();
    let count: i32 = if args_count == 3 {
        FromStr::from_str(&args.next().unwrap()).ok()
    } else {
        None
    }.unwrap_or(10000);

    let count = ((count as f64).sqrt() / 2.) as i16;

    let builder = glutin::WindowBuilder::new()
        .with_title("Performance example".to_string())
        .with_dimensions(800, 600)
        .with_vsync();

    let mut r: Box<Renderer>;
    match mode.as_ref() {
        "gfx" => r = Box::new(GFX::new(builder, count)),
        "gl" => r = Box::new(GL::new(builder, count)),
        x => {
            panic!("{} is not a known mode", x)
        }
    }

    let proj_view = {
        let view = Matrix4::look_at(
            Point3::new(0f32, 5.0, -5.0),
            Point3::new(0f32, 0.0, 0.0),
            Vector3::unit_z(),
        );

        let proj = {
            let aspect = {
                let (w, h) = r.window().get_inner_size().unwrap();
                w as f32 / h as f32
            };
            cgmath::perspective(cgmath::deg(45.0f32), aspect, 1.0, 10.0)
        };
        proj * view
    };

    println!("count is {}", count*count*4);

    'main: loop {
        for event in r.window().poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }
        r.render(&proj_view);
    }
}
<commit_msg>Auto merge of #1013 - Mattbazooka:patch-1, r=kvark<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate cgmath;
#[macro_use]
extern crate gfx;
extern crate gfx_core;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate gfx_gl as gl;
extern crate gfx_device_gl;

use cgmath::{SquareMatrix, Matrix, Point3, Vector3, Matrix3, Matrix4};
use cgmath::{Transform, Vector4};
pub use gfx::format::{DepthStencil, Rgba8 as ColorFormat};
//use glfw::Context;
use gl::Gl;
use gl::types::*;
use std::mem;
use std::ptr;
use std::str;
use std::env;
use std::str::FromStr;
use std::iter::repeat;
use std::ffi::CString;
use std::time::{Duration, Instant};
use gfx_device_gl::{Resources as R, CommandBuffer as CB};
use gfx_core::Device;

gfx_defines!{
    vertex Vertex {
        pos: [f32; 3] = "a_Pos",
    }

    pipeline pipe {
        vbuf: gfx::VertexBuffer<Vertex> = (),
        transform: gfx::Global<[[f32; 4]; 4]> = "u_Transform",
        out_color: gfx::RenderTarget<ColorFormat> = "o_Color",
    }
}

static VERTEX_SRC: &'static [u8] = b"
    #version 150 core
    in vec3 a_Pos;
    uniform mat4 u_Transform;

    void main() {
        gl_Position = u_Transform * vec4(a_Pos, 1.0);
   }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 150 core
    out vec4 o_Color;

    void main() {
        o_Color = vec4(1.0, 0.0, 0.0, 1.0);
    }
";

static VERTEX_DATA: &'static [Vertex] = &[
    Vertex { pos: [-1.0, 0.0, -1.0] },
    Vertex { pos: [ 1.0, 0.0, -1.0] },
    Vertex { pos: [-1.0, 0.0,  1.0] },
];

const CLEAR_COLOR: (f32, f32, f32, f32) = (0.3, 0.3, 0.3, 1.0);

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

fn transform(x: i16, y: i16, proj_view: &Matrix4<f32>) -> Matrix4<f32> {
    let mut model = Matrix4::from(Matrix3::identity() * 0.05);
    model.w = Vector4::new(x as f32 * 0.10,
                           0f32,
                           y as f32 * 0.10,
                           1f32);
    proj_view * model
}

trait Renderer: Drop {
    fn render(&mut self, proj_view: &Matrix4<f32>);
    fn window(&mut self) -> &glutin::Window;
}

struct GFX {
    dimension: i16,
    window: glutin::Window,
    device:gfx_device_gl::Device,
    encoder: gfx::Encoder<R,CB>,
    data: pipe::Data<R>,
    pso: gfx::PipelineState<R, pipe::Meta>,
    slice: gfx::Slice<R>,
}

struct GL {
    dimension: i16,
    window: glutin::Window,
    gl:Gl,
    trans_uniform:GLint,
    vs:GLuint,
    fs:GLuint,
    program:GLuint,
    vbo:GLuint,
    vao:GLuint,
}

impl GFX {
    fn new(builder: glutin::WindowBuilder, dimension: i16) -> Self {
        use gfx::traits::FactoryExt;

        let (window, device, mut factory, main_color, _) =
            gfx_window_glutin::init::<ColorFormat, DepthStencil>(builder);
        let encoder: gfx::Encoder<_,_> = factory.create_command_buffer().into();

        let pso = factory.create_pipeline_simple(
            VERTEX_SRC, FRAGMENT_SRC,
            pipe::new()
        ).unwrap();

        let (vbuf, slice) = factory.create_vertex_buffer_with_slice(VERTEX_DATA,());

        let data = pipe::Data {
            vbuf: vbuf,
            transform: cgmath::Matrix4::identity().into(),
            out_color: main_color,
        };

        GFX {
            window: window,
            dimension: dimension,
            device: device,
            encoder: encoder,
            data: data,
            pso: pso,
            slice: slice,
        }
    }
}

fn duration_to_f64(dur: Duration) -> f64 {
   dur.as_secs() as f64 + dur.subsec_nanos() as f64 / 1000_000_000.0
}

impl Renderer for GFX {
    fn render(&mut self, proj_view: &Matrix4<f32>) {
        let start = Instant::now();
        self.encoder.clear(&self.data.out_color, [CLEAR_COLOR.0,
                                                  CLEAR_COLOR.1,
                                                  CLEAR_COLOR.2,
                                                  CLEAR_COLOR.3]);

        for x in (-self.dimension) ..self.dimension {
            for y in (-self.dimension) ..self.dimension {
                self.data.transform = transform(x, y, proj_view).into();
                self.encoder.draw(&self.slice, &self.pso, &self.data);
            }
        }

        let pre_submit = start.elapsed();
        self.encoder.flush(&mut self.device);
        let post_submit = start.elapsed();
        self.window.swap_buffers().unwrap();
        self.device.cleanup();
        let swap = start.elapsed();

        println!("total time:\t\t{0:4.2}ms", duration_to_ms(swap));
        println!("\tcreate list:\t{0:4.2}ms", duration_to_ms(pre_submit));
        println!("\tsubmit:\t\t{0:4.2}ms", duration_to_ms(post_submit - pre_submit));
        println!("\tgpu wait:\t{0:4.2}ms", duration_to_ms(swap - post_submit));
    }
    fn window(&mut self) -> &glutin::Window { &self.window }
}

impl Drop for GFX {
    fn drop(&mut self) {
    }
}

impl GL {
    fn new(builder: glutin::WindowBuilder, dimension: i16) -> Self {
        fn compile_shader (gl:&Gl, src: &[u8], ty: GLenum) -> GLuint {
            unsafe {
                let shader = gl.CreateShader(ty);
                // Attempt to compile the shader
                gl.ShaderSource(shader, 1,
                                &(src.as_ptr() as *const i8),
                                &(src.len() as GLint));
                gl.CompileShader(shader);

                // Get the compile status
                let mut status = gl::FALSE as GLint;
                gl.GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

                // Fail on error
                if status != (gl::TRUE as GLint) {
                    let mut len: GLint = 0;
                    gl.GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);

                    // allocate a buffer of size (len - 1) to skip the trailing null character
                    let mut buf: Vec<u8> = repeat(0u8).take((len as usize).saturating_sub(1)).collect();
                    gl.GetShaderInfoLog(shader, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
                    panic!("{}", str::from_utf8(&buf).ok().expect("ShaderInfoLog not valid utf8"));
                }
                shader
            }
        };

        let window = builder.build().unwrap();
        unsafe { window.make_current().unwrap() };
        let gl = Gl::load_with(|s| window.get_proc_address(s) as *const _);

        // Create GLSL shaders
        let vs = compile_shader(&gl, VERTEX_SRC, gl::VERTEX_SHADER);
        let fs = compile_shader(&gl, FRAGMENT_SRC, gl::FRAGMENT_SHADER);

        // Link program
        let program;
        unsafe {
            program = gl.CreateProgram();
            gl.AttachShader(program, vs);
            gl.AttachShader(program, fs);
            gl.LinkProgram(program);
            // Get the link status
            let mut status = gl::FALSE as GLint;
            gl.GetProgramiv(program, gl::LINK_STATUS, &mut status);

            // Fail on error
            if status != (gl::TRUE as GLint) {
                let mut len: GLint = 0;
                gl.GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);

                // allocate a buffer of size (len - 1) to skip the trailing null character
                let mut buf: Vec<u8> = repeat(0u8).take((len as usize).saturating_sub(1)).collect();
                gl.GetProgramInfoLog(program, len, ptr::null_mut(), buf.as_mut_ptr() as *mut GLchar);
                panic!("{}", str::from_utf8(&buf).ok().expect("ProgramInfoLog not valid utf8"));
            }
        }

        let mut vao = 0;
        let mut vbo = 0;

        let trans_uniform;
        unsafe {
            // Create Vertex Array Object
            gl.GenVertexArrays(1, &mut vao);
            gl.BindVertexArray(vao);

            // Create a Vertex Buffer Object and copy the vertex data to it
            gl.GenBuffers(1, &mut vbo);
            gl.BindBuffer(gl::ARRAY_BUFFER, vbo);

            gl.BufferData(gl::ARRAY_BUFFER,
                          (VERTEX_DATA.len() * mem::size_of::<Vertex>()) as GLsizeiptr,
                          mem::transmute(&VERTEX_DATA[0]),
                          gl::STATIC_DRAW);

            // Use shader program
            gl.UseProgram(program);
            let o_color = CString::new("o_Color").unwrap();
            gl.BindFragDataLocation(program, 0, o_color.as_bytes_with_nul().as_ptr() as *const i8);

            // Specify the layout of the vertex data
            let a_pos = CString::new("a_Pos").unwrap();
            gl.BindFragDataLocation(program, 0, a_pos.as_bytes_with_nul().as_ptr() as *const i8);

            let pos_attr = gl.GetAttribLocation(program, a_pos.as_ptr());
            gl.EnableVertexAttribArray(pos_attr as GLuint);
            gl.VertexAttribPointer(pos_attr as GLuint, 3, gl::FLOAT,
                                   gl::FALSE as GLboolean, 0, ptr::null());

            let u_transform = CString::new("u_Transform").unwrap();
            trans_uniform = gl.GetUniformLocation(program, u_transform.as_bytes_with_nul().as_ptr() as *const i8)
        };

        GL {
            window: window,
            dimension: dimension,
            gl: gl,
            vs: vs,
            fs: fs,
            program: program,
            vbo: vbo,
            vao: vao,
            trans_uniform: trans_uniform,
        }
    }
}

fn duration_to_ms(dur: Duration) -> f64 {
    (dur.as_secs() * 1000) as f64 + dur.subsec_nanos() as f64 / 1000_000.0
}

impl Renderer for GL {
    fn render(&mut self, proj_view: &Matrix4<f32>) {
        let start = Instant::now();

        // Clear the screen to black
        unsafe {
            self.gl.ClearColor(CLEAR_COLOR.0, CLEAR_COLOR.1, CLEAR_COLOR.2, CLEAR_COLOR.3);
            self.gl.Clear(gl::COLOR_BUFFER_BIT);
        }

        for x in (-self.dimension) ..self.dimension {
            for y in (-self.dimension) ..self.dimension {
                let mat:Matrix4<f32> = transform(x, y, proj_view).into();

                unsafe {
                    self.gl.UniformMatrix4fv(self.trans_uniform,
                                             1,
                                             gl::FALSE,
                                             mat.as_ptr());
                    self.gl.DrawArrays(gl::TRIANGLES, 0, 3);
                }

            }
        }

        let submit = start.elapsed();

        // Swap buffers
        self.window.swap_buffers().unwrap();
        let swap = start.elapsed();

        println!("total time:\t\t{0:4.2}ms", duration_to_ms(swap));
        println!("\tsubmit:\t\t{0:4.2}ms", duration_to_ms(submit));
        println!("\tgpu wait:\t{0:4.2}ms", duration_to_ms(swap - submit));
    }
    fn window(&mut self) -> &glutin::Window { &self.window }
}

impl Drop for GL {
    fn drop(&mut self) {
        unsafe {
            self.gl.DeleteProgram(self.program);
            self.gl.DeleteShader(self.fs);
            self.gl.DeleteShader(self.vs);
            self.gl.DeleteBuffers(1, &self.vbo);
            self.gl.DeleteVertexArrays(1, &self.vao);
        }
    }
}

fn main() {
    let ref mut args = env::args();
    let args_count = env::args().count();
    if args_count == 1 {
        println!("gfx-perf [gl|gfx] <size>");
        return;
    }

    let mode = args.nth(1).unwrap();
    let count: i32 = if args_count == 3 {
        FromStr::from_str(&args.next().unwrap()).ok()
    } else {
        None
    }.unwrap_or(10000);

    let count = ((count as f64).sqrt() / 2.) as i16;

    let builder = glutin::WindowBuilder::new()
        .with_title("Performance example".to_string())
        .with_dimensions(800, 600)
        .with_vsync();

    let mut r: Box<Renderer>;
    match mode.as_ref() {
        "gfx" => r = Box::new(GFX::new(builder, count)),
        "gl" => r = Box::new(GL::new(builder, count)),
        x => {
            panic!("{} is not a known mode", x)
        }
    }

    let proj_view = {
        let view = Matrix4::look_at(
            Point3::new(0f32, 5.0, -5.0),
            Point3::new(0f32, 0.0, 0.0),
            Vector3::unit_z(),
        );

        let proj = {
            let aspect = {
                let (w, h) = r.window().get_inner_size().unwrap();
                w as f32 / h as f32
            };
            cgmath::perspective(cgmath::deg(45.0f32), aspect, 1.0, 10.0)
        };
        proj * view
    };

    println!("count is {}", count*count*4);

    'main: loop {
        for event in r.window().poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }
        r.render(&proj_view);
    }
}
<|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.

/*!
 * Methods for the various MIR types. These are intended for use after
 * building is complete.
 */

use mir::*;
use ty::subst::{Subst, Substs};
use ty::{self, AdtDef, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use hir;
use ty::util::IntTypeExt;

#[derive(Copy, Clone, Debug)]
pub enum LvalueTy<'tcx> {
    /// Normal type.
    Ty { ty: Ty<'tcx> },

    /// Downcast to a particular variant of an enum.
    Downcast { adt_def: &'tcx AdtDef,
               substs: &'tcx Substs<'tcx>,
               variant_index: usize },
}

impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
    pub fn from_ty(ty: Ty<'tcx>) -> LvalueTy<'tcx> {
        LvalueTy::Ty { ty: ty }
    }

    pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
        match *self {
            LvalueTy::Ty { ty } =>
                ty,
            LvalueTy::Downcast { adt_def, substs, variant_index: _ } =>
                tcx.mk_adt(adt_def, substs),
        }
    }

    pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                         elem: &LvalueElem<'tcx>)
                         -> LvalueTy<'tcx>
    {
        match *elem {
            ProjectionElem::Deref => {
                let ty = self.to_ty(tcx)
                             .builtin_deref(true, ty::LvaluePreference::NoPreference)
                             .unwrap_or_else(|| {
                                 bug!("deref projection of non-dereferencable ty {:?}", self)
                             })
                             .ty;
                LvalueTy::Ty {
                    ty,
                }
            }
            ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
                LvalueTy::Ty {
                    ty: self.to_ty(tcx).builtin_index().unwrap()
                },
            ProjectionElem::Subslice { from, to } => {
                let ty = self.to_ty(tcx);
                LvalueTy::Ty {
                    ty: match ty.sty {
                        ty::TyArray(inner, size) => {
                            tcx.mk_array(inner, size-(from as usize)-(to as usize))
                        }
                        ty::TySlice(..) => ty,
                        _ => {
                            bug!("cannot subslice non-array type: `{:?}`", self)
                        }
                    }
                }
            }
            ProjectionElem::Downcast(adt_def1, index) =>
                match self.to_ty(tcx).sty {
                    ty::TyAdt(adt_def, substs) => {
                        assert!(adt_def.is_enum());
                        assert!(index < adt_def.variants.len());
                        assert_eq!(adt_def, adt_def1);
                        LvalueTy::Downcast { adt_def,
                                             substs,
                                             variant_index: index }
                    }
                    _ => {
                        bug!("cannot downcast non-ADT type: `{:?}`", self)
                    }
                },
            ProjectionElem::Field(_, fty) => LvalueTy::Ty { ty: fty }
        }
    }
}

impl<'tcx> TypeFoldable<'tcx> for LvalueTy<'tcx> {
    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
        match *self {
            LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.fold_with(folder) },
            LvalueTy::Downcast { adt_def, substs, variant_index } => {
                LvalueTy::Downcast {
                    adt_def,
                    substs: substs.fold_with(folder),
                    variant_index,
                }
            }
        }
    }

    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
        match *self {
            LvalueTy::Ty { ty } => ty.visit_with(visitor),
            LvalueTy::Downcast { substs, .. } => substs.visit_with(visitor)
        }
    }
}

impl<'tcx> Lvalue<'tcx> {
    pub fn ty<'a, 'gcx, D: HasLocalDecls<'tcx>>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> LvalueTy<'tcx> {
        match *self {
            Lvalue::Local(index) =>
                LvalueTy::Ty { ty: local_decls.local_decls()[index].ty },
            Lvalue::Static(ref data) =>
                LvalueTy::Ty { ty: data.ty },
            Lvalue::Projection(ref proj) =>
                proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem),
        }
    }
}

impl<'tcx> Rvalue<'tcx> {
    pub fn ty<'a, 'gcx, D: HasLocalDecls<'tcx>>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>
    {
        match *self {
            Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
            Rvalue::Repeat(ref operand, ref count) => {
                let op_ty = operand.ty(local_decls, tcx);
                let count = count.as_u64(tcx.sess.target.uint_type);
                assert_eq!(count as usize as u64, count);
                tcx.mk_array(op_ty, count as usize)
            }
            Rvalue::Ref(reg, bk, ref lv) => {
                let lv_ty = lv.ty(local_decls, tcx).to_ty(tcx);
                tcx.mk_ref(reg,
                    ty::TypeAndMut {
                        ty: lv_ty,
                        mutbl: bk.to_mutbl_lossy()
                    }
                )
            }
            Rvalue::Len(..) => tcx.types.usize,
            Rvalue::Cast(.., ty) => ty,
            Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
                let lhs_ty = lhs.ty(local_decls, tcx);
                let rhs_ty = rhs.ty(local_decls, tcx);
                op.ty(tcx, lhs_ty, rhs_ty)
            }
            Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
                let lhs_ty = lhs.ty(local_decls, tcx);
                let rhs_ty = rhs.ty(local_decls, tcx);
                let ty = op.ty(tcx, lhs_ty, rhs_ty);
                tcx.intern_tup(&[ty, tcx.types.bool], false)
            }
            Rvalue::UnaryOp(UnOp::Not, ref operand) |
            Rvalue::UnaryOp(UnOp::Neg, ref operand) => {
                operand.ty(local_decls, tcx)
            }
            Rvalue::Discriminant(ref lval) => {
                let ty = lval.ty(local_decls, tcx).to_ty(tcx);
                if let ty::TyAdt(adt_def, _) = ty.sty {
                    adt_def.repr.discr_type().to_ty(tcx)
                } else {
                    // Undefined behaviour, bug for now; may want to return something for
                    // the `discriminant` intrinsic later.
                    bug!("Rvalue::Discriminant on Lvalue of type {:?}", ty);
                }
            }
            Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
            Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize,
            Rvalue::Aggregate(ref ak, ref ops) => {
                match **ak {
                    AggregateKind::Array(ty) => {
                        tcx.mk_array(ty, ops.len())
                    }
                    AggregateKind::Tuple => {
                        tcx.mk_tup(
                            ops.iter().map(|op| op.ty(local_decls, tcx)),
                            false
                        )
                    }
                    AggregateKind::Adt(def, _, substs, _) => {
                        tcx.type_of(def.did).subst(tcx, substs)
                    }
                    AggregateKind::Closure(did, substs) => {
                        tcx.mk_closure_from_closure_substs(did, substs)
                    }
                }
            }
        }
    }
}

impl<'tcx> Operand<'tcx> {
    pub fn ty<'a, 'gcx, D: HasLocalDecls<'tcx>>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
        match self {
            &Operand::Consume(ref l) => l.ty(local_decls, tcx).to_ty(tcx),
            &Operand::Constant(ref c) => c.ty,
        }
    }
}

impl<'tcx> BinOp {
      pub fn ty<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                    lhs_ty: Ty<'tcx>,
                    rhs_ty: Ty<'tcx>)
                    -> Ty<'tcx> {
        // FIXME: handle SIMD correctly
        match self {
            &BinOp::Add | &BinOp::Sub | &BinOp::Mul | &BinOp::Div | &BinOp::Rem |
            &BinOp::BitXor | &BinOp::BitAnd | &BinOp::BitOr => {
                // these should be integers or floats of the same size.
                assert_eq!(lhs_ty, rhs_ty);
                lhs_ty
            }
            &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => {
                lhs_ty // lhs_ty can be != rhs_ty
            }
            &BinOp::Eq | &BinOp::Lt | &BinOp::Le |
            &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
                tcx.types.bool
            }
        }
    }
}

impl BorrowKind {
    pub fn to_mutbl_lossy(self) -> hir::Mutability {
        match self {
            BorrowKind::Mut => hir::MutMutable,
            BorrowKind::Shared => hir::MutImmutable,

            // We have no type corresponding to a unique imm borrow, so
            // use `&mut`. It gives all the capabilities of an `&uniq`
            // and hence is a safe "over approximation".
            BorrowKind::Unique => hir::MutMutable,
        }
    }
}

impl BinOp {
    pub fn to_hir_binop(self) -> hir::BinOp_ {
        match self {
            BinOp::Add => hir::BinOp_::BiAdd,
            BinOp::Sub => hir::BinOp_::BiSub,
            BinOp::Mul => hir::BinOp_::BiMul,
            BinOp::Div => hir::BinOp_::BiDiv,
            BinOp::Rem => hir::BinOp_::BiRem,
            BinOp::BitXor => hir::BinOp_::BiBitXor,
            BinOp::BitAnd => hir::BinOp_::BiBitAnd,
            BinOp::BitOr => hir::BinOp_::BiBitOr,
            BinOp::Shl => hir::BinOp_::BiShl,
            BinOp::Shr => hir::BinOp_::BiShr,
            BinOp::Eq => hir::BinOp_::BiEq,
            BinOp::Ne => hir::BinOp_::BiNe,
            BinOp::Lt => hir::BinOp_::BiLt,
            BinOp::Gt => hir::BinOp_::BiGt,
            BinOp::Le => hir::BinOp_::BiLe,
            BinOp::Ge => hir::BinOp_::BiGe,
            BinOp::Offset => unreachable!()
        }
    }
}
<commit_msg>please tidy by shortening lines<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.

/*!
 * Methods for the various MIR types. These are intended for use after
 * building is complete.
 */

use mir::*;
use ty::subst::{Subst, Substs};
use ty::{self, AdtDef, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use hir;
use ty::util::IntTypeExt;

#[derive(Copy, Clone, Debug)]
pub enum LvalueTy<'tcx> {
    /// Normal type.
    Ty { ty: Ty<'tcx> },

    /// Downcast to a particular variant of an enum.
    Downcast { adt_def: &'tcx AdtDef,
               substs: &'tcx Substs<'tcx>,
               variant_index: usize },
}

impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
    pub fn from_ty(ty: Ty<'tcx>) -> LvalueTy<'tcx> {
        LvalueTy::Ty { ty: ty }
    }

    pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
        match *self {
            LvalueTy::Ty { ty } =>
                ty,
            LvalueTy::Downcast { adt_def, substs, variant_index: _ } =>
                tcx.mk_adt(adt_def, substs),
        }
    }

    pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                         elem: &LvalueElem<'tcx>)
                         -> LvalueTy<'tcx>
    {
        match *elem {
            ProjectionElem::Deref => {
                let ty = self.to_ty(tcx)
                             .builtin_deref(true, ty::LvaluePreference::NoPreference)
                             .unwrap_or_else(|| {
                                 bug!("deref projection of non-dereferencable ty {:?}", self)
                             })
                             .ty;
                LvalueTy::Ty {
                    ty,
                }
            }
            ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } =>
                LvalueTy::Ty {
                    ty: self.to_ty(tcx).builtin_index().unwrap()
                },
            ProjectionElem::Subslice { from, to } => {
                let ty = self.to_ty(tcx);
                LvalueTy::Ty {
                    ty: match ty.sty {
                        ty::TyArray(inner, size) => {
                            tcx.mk_array(inner, size-(from as usize)-(to as usize))
                        }
                        ty::TySlice(..) => ty,
                        _ => {
                            bug!("cannot subslice non-array type: `{:?}`", self)
                        }
                    }
                }
            }
            ProjectionElem::Downcast(adt_def1, index) =>
                match self.to_ty(tcx).sty {
                    ty::TyAdt(adt_def, substs) => {
                        assert!(adt_def.is_enum());
                        assert!(index < adt_def.variants.len());
                        assert_eq!(adt_def, adt_def1);
                        LvalueTy::Downcast { adt_def,
                                             substs,
                                             variant_index: index }
                    }
                    _ => {
                        bug!("cannot downcast non-ADT type: `{:?}`", self)
                    }
                },
            ProjectionElem::Field(_, fty) => LvalueTy::Ty { ty: fty }
        }
    }
}

impl<'tcx> TypeFoldable<'tcx> for LvalueTy<'tcx> {
    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
        match *self {
            LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.fold_with(folder) },
            LvalueTy::Downcast { adt_def, substs, variant_index } => {
                LvalueTy::Downcast {
                    adt_def,
                    substs: substs.fold_with(folder),
                    variant_index,
                }
            }
        }
    }

    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
        match *self {
            LvalueTy::Ty { ty } => ty.visit_with(visitor),
            LvalueTy::Downcast { substs, .. } => substs.visit_with(visitor)
        }
    }
}

impl<'tcx> Lvalue<'tcx> {
    pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> LvalueTy<'tcx>
        where D: HasLocalDecls<'tcx>
    {
        match *self {
            Lvalue::Local(index) =>
                LvalueTy::Ty { ty: local_decls.local_decls()[index].ty },
            Lvalue::Static(ref data) =>
                LvalueTy::Ty { ty: data.ty },
            Lvalue::Projection(ref proj) =>
                proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem),
        }
    }
}

impl<'tcx> Rvalue<'tcx> {
    pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>
        where D: HasLocalDecls<'tcx>
    {
        match *self {
            Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
            Rvalue::Repeat(ref operand, ref count) => {
                let op_ty = operand.ty(local_decls, tcx);
                let count = count.as_u64(tcx.sess.target.uint_type);
                assert_eq!(count as usize as u64, count);
                tcx.mk_array(op_ty, count as usize)
            }
            Rvalue::Ref(reg, bk, ref lv) => {
                let lv_ty = lv.ty(local_decls, tcx).to_ty(tcx);
                tcx.mk_ref(reg,
                    ty::TypeAndMut {
                        ty: lv_ty,
                        mutbl: bk.to_mutbl_lossy()
                    }
                )
            }
            Rvalue::Len(..) => tcx.types.usize,
            Rvalue::Cast(.., ty) => ty,
            Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
                let lhs_ty = lhs.ty(local_decls, tcx);
                let rhs_ty = rhs.ty(local_decls, tcx);
                op.ty(tcx, lhs_ty, rhs_ty)
            }
            Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
                let lhs_ty = lhs.ty(local_decls, tcx);
                let rhs_ty = rhs.ty(local_decls, tcx);
                let ty = op.ty(tcx, lhs_ty, rhs_ty);
                tcx.intern_tup(&[ty, tcx.types.bool], false)
            }
            Rvalue::UnaryOp(UnOp::Not, ref operand) |
            Rvalue::UnaryOp(UnOp::Neg, ref operand) => {
                operand.ty(local_decls, tcx)
            }
            Rvalue::Discriminant(ref lval) => {
                let ty = lval.ty(local_decls, tcx).to_ty(tcx);
                if let ty::TyAdt(adt_def, _) = ty.sty {
                    adt_def.repr.discr_type().to_ty(tcx)
                } else {
                    // Undefined behaviour, bug for now; may want to return something for
                    // the `discriminant` intrinsic later.
                    bug!("Rvalue::Discriminant on Lvalue of type {:?}", ty);
                }
            }
            Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
            Rvalue::NullaryOp(NullOp::SizeOf, _) => tcx.types.usize,
            Rvalue::Aggregate(ref ak, ref ops) => {
                match **ak {
                    AggregateKind::Array(ty) => {
                        tcx.mk_array(ty, ops.len())
                    }
                    AggregateKind::Tuple => {
                        tcx.mk_tup(
                            ops.iter().map(|op| op.ty(local_decls, tcx)),
                            false
                        )
                    }
                    AggregateKind::Adt(def, _, substs, _) => {
                        tcx.type_of(def.did).subst(tcx, substs)
                    }
                    AggregateKind::Closure(did, substs) => {
                        tcx.mk_closure_from_closure_substs(did, substs)
                    }
                }
            }
        }
    }
}

impl<'tcx> Operand<'tcx> {
    pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>
        where D: HasLocalDecls<'tcx>
    {
        match self {
            &Operand::Consume(ref l) => l.ty(local_decls, tcx).to_ty(tcx),
            &Operand::Constant(ref c) => c.ty,
        }
    }
}

impl<'tcx> BinOp {
      pub fn ty<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
                    lhs_ty: Ty<'tcx>,
                    rhs_ty: Ty<'tcx>)
                    -> Ty<'tcx> {
        // FIXME: handle SIMD correctly
        match self {
            &BinOp::Add | &BinOp::Sub | &BinOp::Mul | &BinOp::Div | &BinOp::Rem |
            &BinOp::BitXor | &BinOp::BitAnd | &BinOp::BitOr => {
                // these should be integers or floats of the same size.
                assert_eq!(lhs_ty, rhs_ty);
                lhs_ty
            }
            &BinOp::Shl | &BinOp::Shr | &BinOp::Offset => {
                lhs_ty // lhs_ty can be != rhs_ty
            }
            &BinOp::Eq | &BinOp::Lt | &BinOp::Le |
            &BinOp::Ne | &BinOp::Ge | &BinOp::Gt => {
                tcx.types.bool
            }
        }
    }
}

impl BorrowKind {
    pub fn to_mutbl_lossy(self) -> hir::Mutability {
        match self {
            BorrowKind::Mut => hir::MutMutable,
            BorrowKind::Shared => hir::MutImmutable,

            // We have no type corresponding to a unique imm borrow, so
            // use `&mut`. It gives all the capabilities of an `&uniq`
            // and hence is a safe "over approximation".
            BorrowKind::Unique => hir::MutMutable,
        }
    }
}

impl BinOp {
    pub fn to_hir_binop(self) -> hir::BinOp_ {
        match self {
            BinOp::Add => hir::BinOp_::BiAdd,
            BinOp::Sub => hir::BinOp_::BiSub,
            BinOp::Mul => hir::BinOp_::BiMul,
            BinOp::Div => hir::BinOp_::BiDiv,
            BinOp::Rem => hir::BinOp_::BiRem,
            BinOp::BitXor => hir::BinOp_::BiBitXor,
            BinOp::BitAnd => hir::BinOp_::BiBitAnd,
            BinOp::BitOr => hir::BinOp_::BiBitOr,
            BinOp::Shl => hir::BinOp_::BiShl,
            BinOp::Shr => hir::BinOp_::BiShr,
            BinOp::Eq => hir::BinOp_::BiEq,
            BinOp::Ne => hir::BinOp_::BiNe,
            BinOp::Lt => hir::BinOp_::BiLt,
            BinOp::Gt => hir::BinOp_::BiGt,
            BinOp::Le => hir::BinOp_::BiLe,
            BinOp::Ge => hir::BinOp_::BiGe,
            BinOp::Offset => unreachable!()
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Not sure this is an error but this doesn't compile; eol problem?<commit_after>

// țĝŖᚤ
// ĭǿưrƒͷᛄđ
/* ᚠƂǜ */ /* /* ŪŖŔWⱬ */  */ // .ǕĈⱰȠÙâ
/* /* /* /* ǱæļƽŢȥɋ¥ */  */  */  */ /* /* Ȏ */  */ // sɋĜ
/* /* /* ᚾᚷçᚴᚣȑ¶ */  */  */ /* /* /* ȵŌĲň */  */  */ /* ɁȧƏœɀğƬ */ // ǏᚩɁżAȸ(Īĥ
/* ƬǞJ */ // YɎPÎᚭƗáƣǭ
//

//
OⱰᛜã
  mod cvreuz {  mod okax {  }  }  mod pbsh5tu0q {  mod a_ {  mod iznremg9w6 {  mod qo_gmsdfq2 {  mod dh {  }  }  }  }  } // ƞⱿƂƨ(Ⱦ
 // ţŦMŰƒ
// ƖrŦųǤ
/*  */ /* ɉƸ */
	 mod aza6hu_jk {  }
<|endoftext|>


<commit_before>use core::ops::DerefMut;

use redox::*;

/* Magic Macros { */
static mut application: *mut Application = 0 as *mut Application;

macro_rules! exec {
    ($cmd:expr) => ({
        unsafe {
            (*application).on_command(&$cmd);
        }
    })
}
/* } Magic Macros */

pub struct Command {
    pub name: String,
    pub main: Box<Fn(&Vec<String>)>
}

impl Command {
    pub fn vec() -> Vec<Command> {
        let mut commands: Vec<Command> = Vec::new();

        commands.push(Command {
            name: "break".to_string(),
            main: box |args: &Vec<String>|{
                unsafe{
                    asm!("int 3" : : : : "intel");
                }
            }
        });

        commands.push(Command {
            name: "echo".to_string(),
            main: box |args: &Vec<String>|{
                let mut echo = String::new();
                let mut first = true;
                for i in 1..args.len() {
                    match args.get(i) {
                        Option::Some(arg) => {
                            if first {
                                first = false
                            }else{
                                echo = echo + " ";
                            }
                            echo = echo + arg;
                        },
                        Option::None => ()
                    }
                }
                println!(echo);
            }
        });

        commands.push(Command {
            name: "open".to_string(),
            main: box |args: &Vec<String>|{
                match args.get(1) {
                    Option::Some(arg) => OpenEvent{ url_string: arg.clone() }.trigger(),
                    Option::None => ()
                }
            }
        });

        commands.push(Command {
            name: "run".to_string(),
            main: box |args: &Vec<String>|{
                match args.get(1) {
                    Option::Some(arg) => {
                        let path = arg.clone();
                        println!("URL: ".to_string() + &path);

                        let mut resource = File::open(&path);

                        let mut vec: Vec<u8> = Vec::new();
                        resource.read_to_end(&mut vec);

                        let commands = String::from_utf8(&vec);
                        for command in commands.split("\n".to_string()) {
                            exec!(command);
                        }
                    },
                    Option::None => ()
                }
            }
        });

        commands.push(Command {
            name: "send".to_string(),
            main: box |args: &Vec<String>|{
                let path;
                match args.get(1) {
                    Option::Some(arg) => path = arg.clone(),
                    Option::None => path = String::new()
                }
                println!("URL: ".to_string() + &path);

                let mut resource = File::open(&path);

                let mut vec: Vec<u8> = Vec::new();
                for i in 2..args.len() {
                    match args.get(i) {
                        Option::Some(arg) => {
                            if i == 2 {
                                vec.push_all(&arg.to_utf8())
                            }else{
                                vec.push_all(&(" ".to_string() + arg).to_utf8())
                            }
                        },
                        Option::None => vec = Vec::new()
                    }
                }
                vec.push_all(&"\r\n\r\n".to_string().to_utf8());

                match resource.write(&vec.as_slice()) {
                    Option::Some(size) => println!("Wrote ".to_string() + size + " bytes"),
                    Option::None => println!("Failed to write".to_string())
                }

                vec = Vec::new();
                match resource.read_to_end(&mut vec) {
                    Option::Some(size) => println!(String::from_utf8(&vec)),
                    Option::None => println!("Failed to read".to_string())
                }
            }
        });

        commands.push(Command {
            name: "url".to_string(),
            main: box |args: &Vec<String>|{
                let path;
                match args.get(1) {
                    Option::Some(arg) => path = arg.clone(),
                    Option::None => path = String::new()
                }
                println!("URL: ".to_string() + &path);

                let mut resource = File::open(&path);

                let mut vec: Vec<u8> = Vec::new();
                match resource.read_to_end(&mut vec) {
                    Option::Some(_) => println!(String::from_utf8(&vec)),
                    Option::None => println!("Failed to read".to_string())
                }
            }
        });

        commands.push(Command {
            name: "url_hex".to_string(),
            main: box |args: &Vec<String>|{
                let path;
                match args.get(1) {
                    Option::Some(arg) => path = arg.clone(),
                    Option::None => path = String::new()
                }
                println!("URL: ".to_string() + &path);

                let mut resource = File::open(&path);

                let mut vec: Vec<u8> = Vec::new();
                match resource.read_to_end(&mut vec) {
                    Option::Some(_) => {
                        let mut line = "HEX:".to_string();
                        for byte in vec.iter() {
                            line = line + ' ' + String::from_num_radix(*byte as usize, 16);
                        }
                        println!(line);
                    },
                    Option::None => println!("Failed to read".to_string())
                }
            }
        });

        return commands;
    }
}

pub struct Variable {
    pub name: String,
    pub value: String
}

pub struct Mode {
    value: bool
}

pub struct Application {
    commands: Vec<Command>,
    variables: Vec<Variable>,
    modes: Vec<Mode>
}

impl Application {
    pub fn new() -> Application {
        return Application {
            commands: Command::vec(),
            variables: Vec::new(),
            modes: Vec::new()
        };
    }

    fn on_command(&mut self, command_string: &String){
        //Comment
        if command_string[0] == '#' {
            return;
        }

        //Show variables
        if *command_string == "$".to_string() {
            let mut variables = String::new();
            for variable in self.variables.iter() {
                variables = variables + '\n' + &variable.name + "=" + &variable.value;
            }
            println!(&variables);
            return;
        }

        //Explode into arguments, replace variables
        let mut args: Vec<String> = Vec::<String>::new();
        for arg in command_string.split(" ".to_string()) {
            if arg.len() > 0 {
                if arg[0] == '$' {
                    let name = arg.substr(1, arg.len() - 1);
                    for variable in self.variables.iter() {
                        if variable.name == name {
                            args.push(variable.value.clone());
                            break;
                        }
                    }
                }else{
                    args.push(arg);
                }
            }
        }

        //Execute commands
        match args.get(0) {
            Option::Some(cmd) => {
                if *cmd == "if".to_string() {
                    let mut value = false;

                    match args.get(1) {
                        Option::Some(left) => match args.get(2) {
                            Option::Some(cmp) => match args.get(3) {
                                Option::Some(right) => {
                                    if *cmp == "==".to_string() {
                                        value = *left == *right;
                                    }else if *cmp == "!=".to_string() {
                                        value = *left != *right;
                                    }else if *cmp == ">".to_string() {
                                        value = left.to_num_signed() > right.to_num_signed();
                                    }else if *cmp == ">=".to_string() {
                                        value = left.to_num_signed() >= right.to_num_signed();
                                    }else if *cmp == "<".to_string() {
                                        value = left.to_num_signed() < right.to_num_signed();
                                    }else if *cmp == "<=".to_string() {
                                        value = left.to_num_signed() <= right.to_num_signed();
                                    }else{
                                        println!(&("Unknown comparison: ".to_string() + cmp));
                                    }
                                },
                                Option::None => ()
                            },
                            Option::None => ()
                        },
                        Option::None => ()
                    }

                    self.modes.insert(0, Mode{
                        value: value
                    });
                    return;
                }

                if *cmd == "else".to_string() {
                    let mut syntax_error = false;
                    match self.modes.get(0) {
                        Option::Some(mode) => mode.value = !mode.value,
                        Option::None => syntax_error = true
                    }
                    if syntax_error {
                        println!(&"Syntax error: else found with no previous if".to_string());
                    }
                    return;
                }

                if *cmd == "fi".to_string() {
                    let mut syntax_error = false;
                    match self.modes.remove(0) {
                        Option::Some(_) => (),
                        Option::None => syntax_error = true
                    }
                    if syntax_error {
                        println!(&"Syntax error: fi found with no previous if".to_string());
                    }
                    return;
                }

                for mode in self.modes.iter() {
                    if ! mode.value {
                        return;
                    }
                }

                //Set variables
                match cmd.find("=".to_string()) {
                    Option::Some(i) => {
                        let name = cmd.substr(0, i);
                        let mut value = cmd.substr(i + 1, cmd.len() - i - 1);

                        if name.len() == 0 {
                            return;
                        }

                        for i in 1..args.len() {
                            match args.get(i) {
                                Option::Some(arg) => value = value + ' ' + arg.clone(),
                                Option::None => ()
                            }
                        }

                        if value.len() == 0 {
                            let mut remove = -1;
                            for i in 0..self.variables.len() {
                                match self.variables.get(i) {
                                    Option::Some(variable) => if variable.name == name {
                                        remove = i as isize;
                                        break;
                                    },
                                    Option::None => break
                                }
                            }

                            if remove >= 0 {
                                self.variables.remove(remove as usize);
                            }
                        }else{
                            for variable in self.variables.iter() {
                                if variable.name == name {
                                    variable.value = value;
                                    return;
                                }
                            }

                            self.variables.push(Variable{
                                name: name,
                                value: value
                            });
                        }
                        return;
                    },
                    Option::None => ()
                }

                //Commands
                for command in self.commands.iter() {
                    if command.name == *cmd {
                        (*command.main)(&args);
                        return;
                    }
                }

                let mut help = "Commands:".to_string();
                for command in self.commands.iter() {
                    help = help + ' ' + &command.name;
                }
                println!(&help);
            },
            Option::None => ()
        }
    }

    fn main(&mut self){
        console_title(&"Terminal".to_string());

        while let Option::Some(command) = readln!() {
            println!("# ".to_string() + &command);
            if command.len() > 0 {
                self.on_command(&command);
            }
        }
    }
}

pub fn main(){
    unsafe {
        let mut app = box Application::new();
        application = app.deref_mut();
        app.main();
    }
}
<commit_msg>Terminal will run given scripts<commit_after>use core::ops::DerefMut;

use redox::*;

/* Magic Macros { */
static mut application: *mut Application = 0 as *mut Application;

macro_rules! exec {
    ($cmd:expr) => ({
        unsafe {
            (*application).on_command(&$cmd);
        }
    })
}
/* } Magic Macros */

pub struct Command {
    pub name: String,
    pub main: Box<Fn(&Vec<String>)>
}

impl Command {
    pub fn vec() -> Vec<Command> {
        let mut commands: Vec<Command> = Vec::new();

        commands.push(Command {
            name: "break".to_string(),
            main: box |args: &Vec<String>|{
                unsafe{
                    asm!("int 3" : : : : "intel");
                }
            }
        });

        commands.push(Command {
            name: "echo".to_string(),
            main: box |args: &Vec<String>|{
                let mut echo = String::new();
                let mut first = true;
                for i in 1..args.len() {
                    match args.get(i) {
                        Option::Some(arg) => {
                            if first {
                                first = false
                            }else{
                                echo = echo + " ";
                            }
                            echo = echo + arg;
                        },
                        Option::None => ()
                    }
                }
                println!(echo);
            }
        });

        commands.push(Command {
            name: "open".to_string(),
            main: box |args: &Vec<String>|{
                match args.get(1) {
                    Option::Some(arg) => OpenEvent{ url_string: arg.clone() }.trigger(),
                    Option::None => ()
                }
            }
        });

        commands.push(Command {
            name: "run".to_string(),
            main: box |args: &Vec<String>|{
                match args.get(1) {
                    Option::Some(arg) => {
                        let path = arg.clone();
                        println!("URL: ".to_string() + &path);

                        let mut resource = File::open(&path);

                        let mut vec: Vec<u8> = Vec::new();
                        resource.read_to_end(&mut vec);

                        let commands = String::from_utf8(&vec);
                        for command in commands.split("\n".to_string()) {
                            exec!(command);
                        }
                    },
                    Option::None => ()
                }
            }
        });

        commands.push(Command {
            name: "send".to_string(),
            main: box |args: &Vec<String>|{
                let path;
                match args.get(1) {
                    Option::Some(arg) => path = arg.clone(),
                    Option::None => path = String::new()
                }
                println!("URL: ".to_string() + &path);

                let mut resource = File::open(&path);

                let mut vec: Vec<u8> = Vec::new();
                for i in 2..args.len() {
                    match args.get(i) {
                        Option::Some(arg) => {
                            if i == 2 {
                                vec.push_all(&arg.to_utf8())
                            }else{
                                vec.push_all(&(" ".to_string() + arg).to_utf8())
                            }
                        },
                        Option::None => vec = Vec::new()
                    }
                }
                vec.push_all(&"\r\n\r\n".to_string().to_utf8());

                match resource.write(&vec.as_slice()) {
                    Option::Some(size) => println!("Wrote ".to_string() + size + " bytes"),
                    Option::None => println!("Failed to write".to_string())
                }

                vec = Vec::new();
                match resource.read_to_end(&mut vec) {
                    Option::Some(size) => println!(String::from_utf8(&vec)),
                    Option::None => println!("Failed to read".to_string())
                }
            }
        });

        commands.push(Command {
            name: "url".to_string(),
            main: box |args: &Vec<String>|{
                let path;
                match args.get(1) {
                    Option::Some(arg) => path = arg.clone(),
                    Option::None => path = String::new()
                }
                println!("URL: ".to_string() + &path);

                let mut resource = File::open(&path);

                let mut vec: Vec<u8> = Vec::new();
                match resource.read_to_end(&mut vec) {
                    Option::Some(_) => println!(String::from_utf8(&vec)),
                    Option::None => println!("Failed to read".to_string())
                }
            }
        });

        commands.push(Command {
            name: "url_hex".to_string(),
            main: box |args: &Vec<String>|{
                let path;
                match args.get(1) {
                    Option::Some(arg) => path = arg.clone(),
                    Option::None => path = String::new()
                }
                println!("URL: ".to_string() + &path);

                let mut resource = File::open(&path);

                let mut vec: Vec<u8> = Vec::new();
                match resource.read_to_end(&mut vec) {
                    Option::Some(_) => {
                        let mut line = "HEX:".to_string();
                        for byte in vec.iter() {
                            line = line + ' ' + String::from_num_radix(*byte as usize, 16);
                        }
                        println!(line);
                    },
                    Option::None => println!("Failed to read".to_string())
                }
            }
        });

        return commands;
    }
}

pub struct Variable {
    pub name: String,
    pub value: String
}

pub struct Mode {
    value: bool
}

pub struct Application {
    commands: Vec<Command>,
    variables: Vec<Variable>,
    modes: Vec<Mode>
}

impl Application {
    pub fn new() -> Application {
        return Application {
            commands: Command::vec(),
            variables: Vec::new(),
            modes: Vec::new()
        };
    }

    fn on_command(&mut self, command_string: &String){
        //Comment
        if command_string[0] == '#' {
            return;
        }

        //Show variables
        if *command_string == "$".to_string() {
            let mut variables = String::new();
            for variable in self.variables.iter() {
                variables = variables + '\n' + &variable.name + "=" + &variable.value;
            }
            println!(&variables);
            return;
        }

        //Explode into arguments, replace variables
        let mut args: Vec<String> = Vec::<String>::new();
        for arg in command_string.split(" ".to_string()) {
            if arg.len() > 0 {
                if arg[0] == '$' {
                    let name = arg.substr(1, arg.len() - 1);
                    for variable in self.variables.iter() {
                        if variable.name == name {
                            args.push(variable.value.clone());
                            break;
                        }
                    }
                }else{
                    args.push(arg);
                }
            }
        }

        //Execute commands
        match args.get(0) {
            Option::Some(cmd) => {
                if *cmd == "if".to_string() {
                    let mut value = false;

                    match args.get(1) {
                        Option::Some(left) => match args.get(2) {
                            Option::Some(cmp) => match args.get(3) {
                                Option::Some(right) => {
                                    if *cmp == "==".to_string() {
                                        value = *left == *right;
                                    }else if *cmp == "!=".to_string() {
                                        value = *left != *right;
                                    }else if *cmp == ">".to_string() {
                                        value = left.to_num_signed() > right.to_num_signed();
                                    }else if *cmp == ">=".to_string() {
                                        value = left.to_num_signed() >= right.to_num_signed();
                                    }else if *cmp == "<".to_string() {
                                        value = left.to_num_signed() < right.to_num_signed();
                                    }else if *cmp == "<=".to_string() {
                                        value = left.to_num_signed() <= right.to_num_signed();
                                    }else{
                                        println!(&("Unknown comparison: ".to_string() + cmp));
                                    }
                                },
                                Option::None => ()
                            },
                            Option::None => ()
                        },
                        Option::None => ()
                    }

                    self.modes.insert(0, Mode{
                        value: value
                    });
                    return;
                }

                if *cmd == "else".to_string() {
                    let mut syntax_error = false;
                    match self.modes.get(0) {
                        Option::Some(mode) => mode.value = !mode.value,
                        Option::None => syntax_error = true
                    }
                    if syntax_error {
                        println!(&"Syntax error: else found with no previous if".to_string());
                    }
                    return;
                }

                if *cmd == "fi".to_string() {
                    let mut syntax_error = false;
                    match self.modes.remove(0) {
                        Option::Some(_) => (),
                        Option::None => syntax_error = true
                    }
                    if syntax_error {
                        println!(&"Syntax error: fi found with no previous if".to_string());
                    }
                    return;
                }

                for mode in self.modes.iter() {
                    if ! mode.value {
                        return;
                    }
                }

                //Set variables
                match cmd.find("=".to_string()) {
                    Option::Some(i) => {
                        let name = cmd.substr(0, i);
                        let mut value = cmd.substr(i + 1, cmd.len() - i - 1);

                        if name.len() == 0 {
                            return;
                        }

                        for i in 1..args.len() {
                            match args.get(i) {
                                Option::Some(arg) => value = value + ' ' + arg.clone(),
                                Option::None => ()
                            }
                        }

                        if value.len() == 0 {
                            let mut remove = -1;
                            for i in 0..self.variables.len() {
                                match self.variables.get(i) {
                                    Option::Some(variable) => if variable.name == name {
                                        remove = i as isize;
                                        break;
                                    },
                                    Option::None => break
                                }
                            }

                            if remove >= 0 {
                                self.variables.remove(remove as usize);
                            }
                        }else{
                            for variable in self.variables.iter() {
                                if variable.name == name {
                                    variable.value = value;
                                    return;
                                }
                            }

                            self.variables.push(Variable{
                                name: name,
                                value: value
                            });
                        }
                        return;
                    },
                    Option::None => ()
                }

                //Commands
                for command in self.commands.iter() {
                    if command.name == *cmd {
                        (*command.main)(&args);
                        return;
                    }
                }

                let mut help = "Commands:".to_string();
                for command in self.commands.iter() {
                    help = help + ' ' + &command.name;
                }
                println!(&help);
            },
            Option::None => ()
        }
    }

    fn main(&mut self){
        console_title(&"Terminal".to_string());

        if let Option::Some(arg) = args().get(1) {
            let command = "run ".to_string() + arg;
            println!("# ".to_string() + &command);
            self.on_command(&command);
        }

        while let Option::Some(command) = readln!() {
            println!("# ".to_string() + &command);
            if command.len() > 0 {
                self.on_command(&command);
            }
        }
    }
}

pub fn main(){
    unsafe {
        let mut app = box Application::new();
        application = app.deref_mut();
        app.main();
    }
}
<|endoftext|>


<commit_before><commit_msg>Missing import.<commit_after>use std::io;
use std::fs;
use std::path::Path;
use std::collections::HashMap;

use csv;
use itertools::Itertools;
use bio::alignment::distance;

#[derive(RustcDecodable)]
pub struct Record {
    pub feature: String,
    pub codeword: String,
    pub expressed: u8
}

pub struct Codebook {
    inner: HashMap<String, [u32; 4]>
}

impl Codebook {
    pub fn neighbors(&self, feature: &str, dist: u8) -> u32 {
        self.inner.get(feature)
                  .expect(&format!("Error: Feature {} not in codebook.", feature))[dist as usize - 1]
    }
}

pub struct Reader<R: io::Read> {
    inner: csv::Reader<R>,
    dist: u8
}

impl Reader<fs::File> {
    /// Read from a given file path.
    pub fn from_file<P: AsRef<Path>>(path: P, dist: u8) -> io::Result<Self> {
        fs::File::open(path).map(|f| Reader::from_reader(f, dist))
    }
}

impl<R: io::Read> Reader<R> {
    pub fn from_reader(rdr: R, dist: u8) -> Self {
        Reader {
            inner: csv::Reader::from_reader(rdr).delimiter(b'\t'),
            dist: dist
        }
    }

    pub fn codebook(&mut self) -> Codebook {
        let records = self.inner.decode::<Record>().map(|record| record.unwrap()).collect_vec();
        let mut inner = HashMap::new();
        for record in records.iter() {
            inner.insert(record.feature.clone(), [0; 4]);
        }
        for a in records.iter() {
            let codeword = a.codeword.as_bytes();
            let neighbors = inner.get_mut(&a.feature).unwrap();
            for b in records.iter() {
                if b.feature != a.feature {
                    let dist = distance::hamming(codeword, b.codeword.as_bytes()).unwrap();
                    assert!(dist >= self.dist as u32, "Unexpected hamming distance {} (>={} allowed).", dist, self.dist);
                    if dist <= 4 && b.expressed == 1 {
                        neighbors[(dist - 1) as usize] += 1;
                    }
                }
            }
        }
        Codebook { inner: inner }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 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.

//! Traits for dynamic typing of any `'static` type (through runtime reflection)
//!
//! This module implements the `Any` trait, which enables dynamic typing
//! of any `'static` type through runtime reflection.
//!
//! `Any` itself can be used to get a `TypeId`, and has more features when used
//! as a trait object. As `&Any` (a borrowed trait object), it has the `is` and
//! `as_ref` methods, to test if the contained value is of a given type, and to
//! get a reference to the inner value as a type. As`&mut Any`, there is also
//! the `as_mut` method, for getting a mutable reference to the inner value.
//! `Box<Any>` adds the `move` method, which will unwrap a `Box<T>` from the
//! object.  See the extension traits (`*Ext`) for the full details.
//!
//! Note that &Any is limited to testing whether a value is of a specified
//! concrete type, and cannot be used to test whether a type implements a trait.
//!
//! # Examples
//!
//! Consider a situation where we want to log out a value passed to a function.
//! We know the value we're working on implements Show, but we don't know its
//! concrete type.  We want to give special treatment to certain types: in this
//! case printing out the length of String values prior to their value.
//! We don't know the concrete type of our value at compile time, so we need to
//! use runtime reflection instead.
//!
//! ```rust
//! use std::fmt::Show;
//! use std::any::{Any, AnyRefExt};
//!
//! // Logger function for any type that implements Show.
//! fn log<T: Any+Show>(value: &T) {
//!     let value_any = value as &Any;
//!
//!     // try to convert our value to a String.  If successful, we want to
//!     // output the String's length as well as its value.  If not, it's a
//!     // different type: just print it out unadorned.
//!     match value_any.downcast_ref::<String>() {
//!         Some(as_string) => {
//!             println!("String ({}): {}", as_string.len(), as_string);
//!         }
//!         None => {
//!             println!("{}", value);
//!         }
//!     }
//! }
//!
//! // This function wants to log its parameter out prior to doing work with it.
//! fn do_work<T: Show+'static>(value: &T) {
//!     log(value);
//!     // ...do some other work
//! }
//!
//! fn main() {
//!     let my_string = "Hello World".to_string();
//!     do_work(&my_string);
//!
//!     let my_i8: i8 = 100;
//!     do_work(&my_i8);
//! }
//! ```

#![stable]

use mem::{transmute, transmute_copy};
use option::{Option, Some, None};
use raw::TraitObject;
use intrinsics::TypeId;

///////////////////////////////////////////////////////////////////////////////
// Any trait
///////////////////////////////////////////////////////////////////////////////

/// The `Any` trait is implemented by all `'static` types, and can be used for
/// dynamic typing
///
/// Every type with no non-`'static` references implements `Any`, so `Any` can
/// be used as a trait object to emulate the effects dynamic typing.
#[stable]
pub trait Any: 'static {
    /// Get the `TypeId` of `self`
    #[stable]
    fn get_type_id(&self) -> TypeId;
}

impl<T: 'static> Any for T {
    fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
}

///////////////////////////////////////////////////////////////////////////////
// Extension methods for Any trait objects.
// Implemented as three extension traits so that the methods can be generic.
///////////////////////////////////////////////////////////////////////////////

/// Extension methods for a referenced `Any` trait object
#[unstable = "this trait will not be necessary once DST lands, it will be a \
              part of `impl Any`"]
pub trait AnyRefExt<'a> {
    /// Returns true if the boxed type is the same as `T`
    #[stable]
    fn is<T: 'static>(self) -> bool;

    /// Returns some reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    #[unstable = "naming conventions around acquiring references may change"]
    fn downcast_ref<T: 'static>(self) -> Option<&'a T>;
}

#[stable]
impl<'a> AnyRefExt<'a> for &'a Any {
    #[inline]
    fn is<T: 'static>(self) -> bool {
        // Get TypeId of the type this function is instantiated with
        let t = TypeId::of::<T>();

        // Get TypeId of the type in the trait object
        let boxed = self.get_type_id();

        // Compare both TypeIds on equality
        t == boxed
    }

    #[inline]
    fn downcast_ref<T: 'static>(self) -> Option<&'a T> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject = transmute_copy(&self);

                // Extract the data pointer
                Some(transmute(to.data))
            }
        } else {
            None
        }
    }
}

/// Extension methods for a mutable referenced `Any` trait object
#[unstable = "this trait will not be necessary once DST lands, it will be a \
              part of `impl Any`"]
pub trait AnyMutRefExt<'a> {
    /// Returns some mutable reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    #[unstable = "naming conventions around acquiring references may change"]
    fn downcast_mut<T: 'static>(self) -> Option<&'a mut T>;
}

#[stable]
impl<'a> AnyMutRefExt<'a> for &'a mut Any {
    #[inline]
    fn downcast_mut<T: 'static>(self) -> Option<&'a mut T> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject = transmute_copy(&self);

                // Extract the data pointer
                Some(transmute(to.data))
            }
        } else {
            None
        }
    }
}
<commit_msg>Mark Any::get_type_id as experimental<commit_after>// Copyright 2013-2014 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.

//! Traits for dynamic typing of any `'static` type (through runtime reflection)
//!
//! This module implements the `Any` trait, which enables dynamic typing
//! of any `'static` type through runtime reflection.
//!
//! `Any` itself can be used to get a `TypeId`, and has more features when used
//! as a trait object. As `&Any` (a borrowed trait object), it has the `is` and
//! `as_ref` methods, to test if the contained value is of a given type, and to
//! get a reference to the inner value as a type. As`&mut Any`, there is also
//! the `as_mut` method, for getting a mutable reference to the inner value.
//! `Box<Any>` adds the `move` method, which will unwrap a `Box<T>` from the
//! object.  See the extension traits (`*Ext`) for the full details.
//!
//! Note that &Any is limited to testing whether a value is of a specified
//! concrete type, and cannot be used to test whether a type implements a trait.
//!
//! # Examples
//!
//! Consider a situation where we want to log out a value passed to a function.
//! We know the value we're working on implements Show, but we don't know its
//! concrete type.  We want to give special treatment to certain types: in this
//! case printing out the length of String values prior to their value.
//! We don't know the concrete type of our value at compile time, so we need to
//! use runtime reflection instead.
//!
//! ```rust
//! use std::fmt::Show;
//! use std::any::{Any, AnyRefExt};
//!
//! // Logger function for any type that implements Show.
//! fn log<T: Any+Show>(value: &T) {
//!     let value_any = value as &Any;
//!
//!     // try to convert our value to a String.  If successful, we want to
//!     // output the String's length as well as its value.  If not, it's a
//!     // different type: just print it out unadorned.
//!     match value_any.downcast_ref::<String>() {
//!         Some(as_string) => {
//!             println!("String ({}): {}", as_string.len(), as_string);
//!         }
//!         None => {
//!             println!("{}", value);
//!         }
//!     }
//! }
//!
//! // This function wants to log its parameter out prior to doing work with it.
//! fn do_work<T: Show+'static>(value: &T) {
//!     log(value);
//!     // ...do some other work
//! }
//!
//! fn main() {
//!     let my_string = "Hello World".to_string();
//!     do_work(&my_string);
//!
//!     let my_i8: i8 = 100;
//!     do_work(&my_i8);
//! }
//! ```

#![stable]

use mem::{transmute, transmute_copy};
use option::{Option, Some, None};
use raw::TraitObject;
use intrinsics::TypeId;

///////////////////////////////////////////////////////////////////////////////
// Any trait
///////////////////////////////////////////////////////////////////////////////

/// The `Any` trait is implemented by all `'static` types, and can be used for
/// dynamic typing
///
/// Every type with no non-`'static` references implements `Any`, so `Any` can
/// be used as a trait object to emulate the effects dynamic typing.
#[stable]
pub trait Any: 'static {
    /// Get the `TypeId` of `self`
    #[experimental = "this method will likely be replaced by an associated static"]
    fn get_type_id(&self) -> TypeId;
}

impl<T: 'static> Any for T {
    fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
}

///////////////////////////////////////////////////////////////////////////////
// Extension methods for Any trait objects.
// Implemented as three extension traits so that the methods can be generic.
///////////////////////////////////////////////////////////////////////////////

/// Extension methods for a referenced `Any` trait object
#[unstable = "this trait will not be necessary once DST lands, it will be a \
              part of `impl Any`"]
pub trait AnyRefExt<'a> {
    /// Returns true if the boxed type is the same as `T`
    #[stable]
    fn is<T: 'static>(self) -> bool;

    /// Returns some reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    #[unstable = "naming conventions around acquiring references may change"]
    fn downcast_ref<T: 'static>(self) -> Option<&'a T>;
}

#[stable]
impl<'a> AnyRefExt<'a> for &'a Any {
    #[inline]
    fn is<T: 'static>(self) -> bool {
        // Get TypeId of the type this function is instantiated with
        let t = TypeId::of::<T>();

        // Get TypeId of the type in the trait object
        let boxed = self.get_type_id();

        // Compare both TypeIds on equality
        t == boxed
    }

    #[inline]
    fn downcast_ref<T: 'static>(self) -> Option<&'a T> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject = transmute_copy(&self);

                // Extract the data pointer
                Some(transmute(to.data))
            }
        } else {
            None
        }
    }
}

/// Extension methods for a mutable referenced `Any` trait object
#[unstable = "this trait will not be necessary once DST lands, it will be a \
              part of `impl Any`"]
pub trait AnyMutRefExt<'a> {
    /// Returns some mutable reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    #[unstable = "naming conventions around acquiring references may change"]
    fn downcast_mut<T: 'static>(self) -> Option<&'a mut T>;
}

#[stable]
impl<'a> AnyMutRefExt<'a> for &'a mut Any {
    #[inline]
    fn downcast_mut<T: 'static>(self) -> Option<&'a mut T> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject = transmute_copy(&self);

                // Extract the data pointer
                Some(transmute(to.data))
            }
        } else {
            None
        }
    }
}
<|endoftext|>