<commit_before>#[cfg(feature = "hotload")]
extern crate dynamic_reload;

extern crate sdl2;
extern crate cgmath;

//#[cfg(not(feature = "hotload"))]
//extern crate minigame;

#[cfg(feature = "hotload")]
use dynamic_reload::{DynamicReload, Lib, Symbol, Search, PlatformName, UpdateState};
#[cfg(feature = "hotload")]
use std::rc::Rc;
use std::time::Duration;
use std::thread;
use std::str;
use std::ffi::CString;
use std::ptr;
use std::mem;
use std::path::Path;
use std::cell::RefCell;
use sdl2::image::{LoadTexture, INIT_PNG, INIT_JPG};
use sdl2::pixels::Color as SdlColor;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::render::TextureCreator;
use sdl2::render::Texture as SdlTexture;
use sdl2::video::WindowContext;
#[cfg(not(feature = "hotload"))]
use test_shared::shared_fun;

use spritebatch::SpriteBatch;
use spritebatch::SpriteSortMode;
use color::Color;
use texture::Texture;
use texturemanager::TextureManager;
use shader::Shader;
use self::cgmath::Vector2;
use self::cgmath::Matrix4;
use self::cgmath::One;

pub mod gl {
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
use self::gl::types::*;

#[cfg(feature = "hotload")]
struct Plugins {
    plugins: Vec<Rc<Lib>>,
}

#[cfg(feature = "hotload")]
impl Plugins {
    fn add_plugin(&mut self, plugin: &Rc<Lib>) {
        self.plugins.push(plugin.clone());
    }

    fn unload_plugins(&mut self, lib: &Rc<Lib>) {
        for i in (0..self.plugins.len()).rev() {
            if &self.plugins[i] == lib {
                self.plugins.swap_remove(i);
            }
        }
    }

    fn reload_plugin(&mut self, lib: &Rc<Lib>) {
        Self::add_plugin(self, lib);
    }

    // called when a lib needs to be reloaded.
    fn reload_callback(&mut self, state: UpdateState, lib: Option<&Rc<Lib>>) {
        match state {
            UpdateState::Before => Self::unload_plugins(self, lib.unwrap()),
            UpdateState::After => Self::reload_plugin(self, lib.unwrap()),
            UpdateState::ReloadFailed(_) => println!("Failed to reload"),
        }
    }
}

fn find_sdl_gl_driver() -> Option<u32> {
    for (index, item) in sdl2::render::drivers().enumerate() {
        sdl2::log::log(item.name);
        if item.name.contains("opengl") {
            sdl2::log::log("Driver chosen follows");
            sdl2::log::log(item.name);
            return Some(index as u32);
        }
    }
    sdl2::log::log("No OpenGL driver chosen");
    None
}

// Vertex data
static VERTEX_DATA: [GLfloat; 6] = [0.0, 0.5, 0.5, -0.5, -0.5, -0.5];

// Shader sources
#[cfg(any(target_os="android", target_os="ios"))]
fn precision() -> String {
    String::from("precision mediump float;\n")
}

#[cfg(not(any(target_os="android", target_os="ios")))]
fn precision() -> String {
    String::from("")
}

static VS_SRC: &'static str = "\n\
    attribute vec2 position;\n\
    varying vec4 color;\n\
    void main() {\n\
       gl_Position = vec4(position, 0.0, 1.0);\n\
       color = vec4(1.0, 1.0, 1.0, 1.0);\n\
       gl_PointSize = 1.0;\n\
    }";

static FS_SRC: &'static str = "\n\
    varying vec4 color;\n\
    void main() {\n\
       gl_FragColor = color;\n\
    }";

pub fn foo() {

}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader;
    unsafe {
        shader = gl::CreateShader(ty);
        // Attempt to compile the shader
        let c_str = CString::new(src.as_bytes()).unwrap();
        gl::ShaderSource(shader, 1, &c_str.as_ptr(), ptr::null());
        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 = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::with_capacity(len as usize);
            buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
            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
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    unsafe {
        let 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);
            let mut buf = Vec::with_capacity(len as usize);
            buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
            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"));
        }
        program
    }
}

#[cfg(feature = "hotload")]
fn plugin_load<'a>() -> (Plugins, DynamicReload<'a>) {
    // Setup the reload handler. A temporary directory will be created inside the target/debug
    // where plugins will be loaded from. That is because on some OS:es loading a shared lib
    // will lock the file so we can't overwrite it so this works around that issue.
    let mut reload_handler = DynamicReload::new(Some(vec!["target/debug"]),
                                                Some("target/debug"),
                                                Search::Default);
    let mut plugs = Plugins { plugins: Vec::new() };

    // test_shared is generated in build.rs
    match reload_handler.add_library("test_shared", PlatformName::Yes) {
        Ok(lib) => plugs.add_plugin(&lib),
        Err(e) => {
            println!("Unable to load dynamic lib, err {:?}", e);
            return (plugs, reload_handler);
        }
    }

    (plugs, reload_handler)
}

#[cfg(not(feature = "hotload"))]
fn plugin_load() -> (i32, i32) {
    (0, 0)
}

#[cfg(feature = "hotload")]
fn plugin_update<'a>(mut plugs: &mut Plugins, mut reload_handler: &mut DynamicReload<'a>) {
        reload_handler.update(Plugins::reload_callback, &mut plugs);

        if plugs.plugins.len() > 0 {
            // In a real program you want to cache the symbol and not do it every time if your
            // application is performance critical
            let fun: Symbol<extern "C" fn() -> i32> =
                unsafe { plugs.plugins[0].lib.get(b"shared_fun\0").unwrap() };

            println!("Value {}", fun());
        }
}

#[cfg(not(feature = "hotload"))]
fn plugin_update(mut plugs: &mut i32, mut reload_handler: &mut i32) {
    println!("Value {}", shared_fun());
}

//#[cfg(feature = "hotload")]
pub fn run_loop() {
    let (mut plugs, mut reload_handler) = plugin_load();
    /*
    let mut plugs = Plugins { plugins: Vec::new() };

    // Setup the reload handler. A temporary directory will be created inside the target/debug
    // where plugins will be loaded from. That is because on some OS:es loading a shared lib
    // will lock the file so we can't overwrite it so this works around that issue.
    let mut reload_handler = DynamicReload::new(Some(vec!["target/debug"]),
                                                Some("target/debug"),
                                                Search::Default);
    */
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem
        .window("rust-sdl2 demo: Video", 800, 600)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    sdl2::log::log("Looking for OpenGL drivers");
    let mut canvas = window
    .into_canvas()
    .index(find_sdl_gl_driver().unwrap())
    .build()
    .unwrap();

    sdl2::log::log("Loading GL extensions");
    gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as *const _);
    sdl2::log::log("Setting current GL context");
    canvas.window().gl_set_context_to_current();

    // Create GLSL shaders
    sdl2::log::log("Compiling vertex shader");
    let vs_src = precision()+VS_SRC;
    let vs = compile_shader(&vs_src, gl::VERTEX_SHADER);
    sdl2::log::log("Compiling fragment shader");
    let fs_src = precision()+FS_SRC;
    let fs = compile_shader(&fs_src, gl::FRAGMENT_SHADER);
    sdl2::log::log("Linking shaders");
    let program = link_program(vs, fs);

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

    unsafe {
        // Use shader program
        gl::UseProgram(program);

        //let col_attr = gl::GetAttribLocation(program, CString::new("color").unwrap().as_ptr());

        // Specify the layout of the vertex data
        let pos_attr = gl::GetAttribLocation(program, CString::new("position").unwrap().as_ptr());
        gl::EnableVertexAttribArray(pos_attr as GLuint);
        gl::VertexAttribPointer(pos_attr as GLuint,
                                2,
                                gl::FLOAT,
                                gl::FALSE as GLboolean,
                                0,
                                mem::transmute(&VERTEX_DATA[0]));
    }

    let mut event_pump = sdl_context.event_pump().unwrap();

    /*
    // test_shared is generated in build.rs
    match reload_handler.add_library("test_shared", PlatformName::Yes) {
        Ok(lib) => plugs.add_plugin(&lib),
        Err(e) => {
            println!("Unable to load dynamic lib, err {:?}", e);
            return;
        }
    }
    */

    let texture_creator = canvas.texture_creator();
    let mut tm = TextureManager::new(&texture_creator);
    tm.load(String::from("wabbit"), Path::new("assets/wabbit_alpha.png"));
    let wabbit = tm.get(&String::from("wabbit"));

    //
    // While this is running (printing a number) change return value in file src/test_shared.rs
    // build the project with cargo build and notice that this code will now return the new value
    //
    'running: loop {
        plugin_update(&mut plugs, &mut reload_handler);

        /*
        reload_handler.update(Plugins::reload_callback, &mut plugs);

        if plugs.plugins.len() > 0 {
            // In a real program you want to cache the symbol and not do it every time if your
            // application is performance critical
            let fun: Symbol<extern "C" fn() -> i32> =
                unsafe { plugs.plugins[0].lib.get(b"shared_fun\0").unwrap() };

            println!("Value {}", fun());
        }
        */

        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. } |
                Event::KeyDown { keycode: Some(Keycode::Escape), .. } => break 'running,
                _ => {}
            }
        }

        canvas.set_draw_color(SdlColor::RGB(255, 0, 0));
        canvas.clear();

        /*
        sdl2::log::log("Drawing triangle");
        unsafe {
            gl::DrawArrays(gl::TRIANGLES, 0, 3);
        }
        */

        {
            let mut sb = SpriteBatch::new(&canvas);
            let position = Vector2::new(0.0, 0.0);
            let matrix: Matrix4<f32> = Matrix4::one();
            let mut shader = Shader::new();
            shader.load_default();
            sb.begin(SpriteSortMode::SpriteSortModeDeferred, Some(&shader), Some(matrix));
            sb.draw(&wabbit, Some(position), None, None, None, 0.0, None, Color::white(), 0.0);
            sb.end();
        }

        canvas.present();

        ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
        // The rest of the game loop goes here...

        // Wait for 0.5 sec
        thread::sleep(Duration::from_millis(500));
    }

     // Cleanup
    unsafe {
        gl::DeleteProgram(program);
        gl::DeleteShader(fs);
        gl::DeleteShader(vs);
        gl::DeleteBuffers(1, &vbo);
    }
}
<commit_msg>Fixes the order of scoped variables in the test loop<commit_after>#[cfg(feature = "hotload")]
extern crate dynamic_reload;

extern crate sdl2;
extern crate cgmath;

//#[cfg(not(feature = "hotload"))]
//extern crate minigame;

#[cfg(feature = "hotload")]
use dynamic_reload::{DynamicReload, Lib, Symbol, Search, PlatformName, UpdateState};
#[cfg(feature = "hotload")]
use std::rc::Rc;
use std::time::Duration;
use std::thread;
use std::str;
use std::ffi::CString;
use std::ptr;
use std::mem;
use std::path::Path;
use std::cell::RefCell;
use sdl2::image::{LoadTexture, INIT_PNG, INIT_JPG};
use sdl2::pixels::Color as SdlColor;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::render::TextureCreator;
use sdl2::render::Texture as SdlTexture;
use sdl2::video::WindowContext;
#[cfg(not(feature = "hotload"))]
use test_shared::shared_fun;

use spritebatch::SpriteBatch;
use spritebatch::SpriteSortMode;
use color::Color;
use texture::Texture;
use texturemanager::TextureManager;
use shader::Shader;
use self::cgmath::Vector2;
use self::cgmath::Matrix4;
use self::cgmath::One;

pub mod gl {
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
use self::gl::types::*;

#[cfg(feature = "hotload")]
struct Plugins {
    plugins: Vec<Rc<Lib>>,
}

#[cfg(feature = "hotload")]
impl Plugins {
    fn add_plugin(&mut self, plugin: &Rc<Lib>) {
        self.plugins.push(plugin.clone());
    }

    fn unload_plugins(&mut self, lib: &Rc<Lib>) {
        for i in (0..self.plugins.len()).rev() {
            if &self.plugins[i] == lib {
                self.plugins.swap_remove(i);
            }
        }
    }

    fn reload_plugin(&mut self, lib: &Rc<Lib>) {
        Self::add_plugin(self, lib);
    }

    // called when a lib needs to be reloaded.
    fn reload_callback(&mut self, state: UpdateState, lib: Option<&Rc<Lib>>) {
        match state {
            UpdateState::Before => Self::unload_plugins(self, lib.unwrap()),
            UpdateState::After => Self::reload_plugin(self, lib.unwrap()),
            UpdateState::ReloadFailed(_) => println!("Failed to reload"),
        }
    }
}

fn find_sdl_gl_driver() -> Option<u32> {
    for (index, item) in sdl2::render::drivers().enumerate() {
        sdl2::log::log(item.name);
        if item.name.contains("opengl") {
            sdl2::log::log("Driver chosen follows");
            sdl2::log::log(item.name);
            return Some(index as u32);
        }
    }
    sdl2::log::log("No OpenGL driver chosen");
    None
}

// Vertex data
static VERTEX_DATA: [GLfloat; 6] = [0.0, 0.5, 0.5, -0.5, -0.5, -0.5];

// Shader sources
#[cfg(any(target_os="android", target_os="ios"))]
fn precision() -> String {
    String::from("precision mediump float;\n")
}

#[cfg(not(any(target_os="android", target_os="ios")))]
fn precision() -> String {
    String::from("")
}

static VS_SRC: &'static str = "\n\
    attribute vec2 position;\n\
    varying vec4 color;\n\
    void main() {\n\
       gl_Position = vec4(position, 0.0, 1.0);\n\
       color = vec4(1.0, 1.0, 1.0, 1.0);\n\
       gl_PointSize = 1.0;\n\
    }";

static FS_SRC: &'static str = "\n\
    varying vec4 color;\n\
    void main() {\n\
       gl_FragColor = color;\n\
    }";

pub fn foo() {

}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader;
    unsafe {
        shader = gl::CreateShader(ty);
        // Attempt to compile the shader
        let c_str = CString::new(src.as_bytes()).unwrap();
        gl::ShaderSource(shader, 1, &c_str.as_ptr(), ptr::null());
        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 = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::with_capacity(len as usize);
            buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
            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
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    unsafe {
        let 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);
            let mut buf = Vec::with_capacity(len as usize);
            buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
            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"));
        }
        program
    }
}

#[cfg(feature = "hotload")]
fn plugin_load<'a>() -> (Plugins, DynamicReload<'a>) {
    // Setup the reload handler. A temporary directory will be created inside the target/debug
    // where plugins will be loaded from. That is because on some OS:es loading a shared lib
    // will lock the file so we can't overwrite it so this works around that issue.
    let mut reload_handler = DynamicReload::new(Some(vec!["target/debug"]),
                                                Some("target/debug"),
                                                Search::Default);
    let mut plugs = Plugins { plugins: Vec::new() };

    // test_shared is generated in build.rs
    match reload_handler.add_library("test_shared", PlatformName::Yes) {
        Ok(lib) => plugs.add_plugin(&lib),
        Err(e) => {
            println!("Unable to load dynamic lib, err {:?}", e);
            return (plugs, reload_handler);
        }
    }

    (plugs, reload_handler)
}

#[cfg(not(feature = "hotload"))]
fn plugin_load() -> (i32, i32) {
    (0, 0)
}

#[cfg(feature = "hotload")]
fn plugin_update<'a>(mut plugs: &mut Plugins, mut reload_handler: &mut DynamicReload<'a>) {
        reload_handler.update(Plugins::reload_callback, &mut plugs);

        if plugs.plugins.len() > 0 {
            // In a real program you want to cache the symbol and not do it every time if your
            // application is performance critical
            let fun: Symbol<extern "C" fn() -> i32> =
                unsafe { plugs.plugins[0].lib.get(b"shared_fun\0").unwrap() };

            println!("Value {}", fun());
        }
}

#[cfg(not(feature = "hotload"))]
fn plugin_update(mut plugs: &mut i32, mut reload_handler: &mut i32) {
    println!("Value {}", shared_fun());
}

//#[cfg(feature = "hotload")]
pub fn run_loop() {
    let (mut plugs, mut reload_handler) = plugin_load();
    /*
    let mut plugs = Plugins { plugins: Vec::new() };

    // Setup the reload handler. A temporary directory will be created inside the target/debug
    // where plugins will be loaded from. That is because on some OS:es loading a shared lib
    // will lock the file so we can't overwrite it so this works around that issue.
    let mut reload_handler = DynamicReload::new(Some(vec!["target/debug"]),
                                                Some("target/debug"),
                                                Search::Default);
    */
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem
        .window("rust-sdl2 demo: Video", 800, 600)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    sdl2::log::log("Looking for OpenGL drivers");
    let mut canvas = window
    .into_canvas()
    .index(find_sdl_gl_driver().unwrap())
    .build()
    .unwrap();

    sdl2::log::log("Loading GL extensions");
    gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as *const _);
    sdl2::log::log("Setting current GL context");
    canvas.window().gl_set_context_to_current();

    // Create GLSL shaders
    sdl2::log::log("Compiling vertex shader");
    let vs_src = precision()+VS_SRC;
    let vs = compile_shader(&vs_src, gl::VERTEX_SHADER);
    sdl2::log::log("Compiling fragment shader");
    let fs_src = precision()+FS_SRC;
    let fs = compile_shader(&fs_src, gl::FRAGMENT_SHADER);
    sdl2::log::log("Linking shaders");
    let program = link_program(vs, fs);

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

    unsafe {
        // Use shader program
        gl::UseProgram(program);

        //let col_attr = gl::GetAttribLocation(program, CString::new("color").unwrap().as_ptr());

        // Specify the layout of the vertex data
        let pos_attr = gl::GetAttribLocation(program, CString::new("position").unwrap().as_ptr());
        gl::EnableVertexAttribArray(pos_attr as GLuint);
        gl::VertexAttribPointer(pos_attr as GLuint,
                                2,
                                gl::FLOAT,
                                gl::FALSE as GLboolean,
                                0,
                                mem::transmute(&VERTEX_DATA[0]));
    }

    let mut event_pump = sdl_context.event_pump().unwrap();

    /*
    // test_shared is generated in build.rs
    match reload_handler.add_library("test_shared", PlatformName::Yes) {
        Ok(lib) => plugs.add_plugin(&lib),
        Err(e) => {
            println!("Unable to load dynamic lib, err {:?}", e);
            return;
        }
    }
    */

    let texture_creator = canvas.texture_creator();
    let mut tm = TextureManager::new(&texture_creator);
    tm.load(String::from("wabbit"), Path::new("assets/wabbit_alpha.png"));
    let wabbit = tm.get(&String::from("wabbit"));

    //
    // While this is running (printing a number) change return value in file src/test_shared.rs
    // build the project with cargo build and notice that this code will now return the new value
    //
    'running: loop {
        plugin_update(&mut plugs, &mut reload_handler);

        /*
        reload_handler.update(Plugins::reload_callback, &mut plugs);

        if plugs.plugins.len() > 0 {
            // In a real program you want to cache the symbol and not do it every time if your
            // application is performance critical
            let fun: Symbol<extern "C" fn() -> i32> =
                unsafe { plugs.plugins[0].lib.get(b"shared_fun\0").unwrap() };

            println!("Value {}", fun());
        }
        */

        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. } |
                Event::KeyDown { keycode: Some(Keycode::Escape), .. } => break 'running,
                _ => {}
            }
        }

        canvas.set_draw_color(SdlColor::RGB(255, 0, 0));
        canvas.clear();

        /*
        sdl2::log::log("Drawing triangle");
        unsafe {
            gl::DrawArrays(gl::TRIANGLES, 0, 3);
        }
        */

        {
            let mut shader = Shader::new();
            shader.load_default();
            let mut sb = SpriteBatch::new(&canvas);
            let position = Vector2::new(0.0, 0.0);
            let matrix: Matrix4<f32> = Matrix4::one();
            sb.begin(SpriteSortMode::SpriteSortModeDeferred, Some(&shader), Some(matrix));
            sb.draw(&wabbit, Some(position), None, None, None, 0.0, None, Color::white(), 0.0);
            sb.end();
        }

        canvas.present();

        ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
        // The rest of the game loop goes here...

        // Wait for 0.5 sec
        thread::sleep(Duration::from_millis(500));
    }

     // Cleanup
    unsafe {
        gl::DeleteProgram(program);
        gl::DeleteShader(fs);
        gl::DeleteShader(vs);
        gl::DeleteBuffers(1, &vbo);
    }
}
<|endoftext|>


<commit_before>use std::io::Error as IoError;
use hyper::Error as HttpError;
use hyper::status::StatusCode;
use serde_json::error::Error as SerdeError;
use super::Errors;

/// an enumeration over potential errors
/// that may happen when sending a request to jira
#[derive(Debug)]
pub enum Error {
    /// error associated with http request
    Http(HttpError),
    /// error associated IO
    IO(IoError),
    /// error associated with parsing or serializing
    Serde(SerdeError),
    /// client request errors
    Fault { code: StatusCode, errors: Errors },
}

impl From<SerdeError> for Error {
    fn from(error: SerdeError) -> Error {
        Error::Serde(error)
    }
}

impl From<HttpError> for Error {
    fn from(error: HttpError) -> Error {
        Error::Http(error)
    }
}

impl From<IoError> for Error {
    fn from(error: IoError) -> Error {
        Error::IO(error)
    }
}
<commit_msg>add unauthorized as special type of client err<commit_after>use std::io::Error as IoError;
use hyper::Error as HttpError;
use hyper::status::StatusCode;
use serde_json::error::Error as SerdeError;
use super::Errors;

/// an enumeration over potential errors
/// that may happen when sending a request to jira
#[derive(Debug)]
pub enum Error {
    /// error associated with http request
    Http(HttpError),
    /// error associated IO
    IO(IoError),
    /// error associated with parsing or serializing
    Serde(SerdeError),
    /// client request errors
    Fault { code: StatusCode, errors: Errors },
    /// invalid credentials
    Unauthorized
}

impl From<SerdeError> for Error {
    fn from(error: SerdeError) -> Error {
        Error::Serde(error)
    }
}

impl From<HttpError> for Error {
    fn from(error: HttpError) -> Error {
        Error::Http(error)
    }
}

impl From<IoError> for Error {
    fn from(error: IoError) -> Error {
        Error::IO(error)
    }
}
<|endoftext|>


<commit_before>//! Formatting helpers for the logger middleware.

use std::default::Default;
use std::str::Chars;
use std::iter::Peekable;

use self::FormatText::{Method, URI, Status, ResponseTime, RemoteAddr, RequestTime};

/// A formatting style for the `Logger`, consisting of multiple
/// `FormatUnit`s concatenated into one line.
#[derive(Clone)]
pub struct Format(pub Vec<FormatUnit>);

impl Default for Format {
    /// Return the default formatting style for the `Logger`:
    ///
    /// ```ignore
    /// {method} {uri} -> {status} ({response-time})
    /// // This will be written as: {method} {uri} -> {status} ({response-time})
    /// ```
    fn default() -> Format {
        Format::new("{method} {uri} {status} ({response-time})").unwrap()
    }
}

impl Format {
    /// Create a `Format` from a format string, which can contain the fields
    /// `{method}`, `{uri}`, `{status}`, `{response-time}`, `{ip-addr}` and
    /// `{request-time}`.
    ///
    /// Returns `None` if the format string syntax is incorrect.
    pub fn new(s: &str) -> Option<Format> {

        let parser = FormatParser::new(s.chars().peekable());

        let mut results = Vec::new();

        for unit in parser {
            match unit {
                Some(unit) => results.push(unit),
                None => return None
            }
        }

        Some(Format(results))
    }
}

struct FormatParser<'a> {
    // The characters of the format string.
    chars: Peekable<Chars<'a>>,

    // A reusable buffer for parsing style attributes.
    object_buffer: String,

    // A queue of waiting format units to avoid full-on
    // state-machine parsing.
    waitqueue: Vec<FormatUnit>,

    finished: bool
}

impl<'a> FormatParser<'a> {
    fn new(chars: Peekable<Chars>) -> FormatParser {
        FormatParser {
            chars: chars,

            // No attributes are longer than 14 characters, so we can avoid reallocating.
            object_buffer: String::with_capacity(14),

            waitqueue: vec![],
            finished: false
        }
    }
}

// Some(None) means there was a parse error and this FormatParser should be abandoned.
impl<'a> Iterator for FormatParser<'a> {
    type Item = Option<FormatUnit>;

    fn next(&mut self) -> Option<Option<FormatUnit>> {
        // If the parser has been cancelled or errored for some reason.
        if self.finished { return None }

        if self.waitqueue.len() != 0 {
            return Some(Some(self.waitqueue.remove(0)));
        }

        // Try to parse a new FormatUnit.
        match self.chars.next() {
            // Parse a recognized object.
            //
            // The allowed forms are:
            //   - {method}
            //   - {uri}
            //   - {status}
            //   - {response-time}
            //   - {ip-addr}
            //   - {request-time}
            Some('{') => {
                self.object_buffer.clear();

                let mut chr = self.chars.next();
                while chr != None {
                    match chr.unwrap() {
                        // Finished parsing, parse buffer.
                        '}' => break,
                        c => self.object_buffer.push(c.clone())
                    }

                    chr = self.chars.next();
                }

                let text = match self.object_buffer.as_ref() {
                    "method" => Method,
                    "uri" => URI,
                    "status" => Status,
                    "response-time" => ResponseTime,
                    "request-time" => RequestTime,
                    "ip-addr" => RemoteAddr,
                    _ => {
                        // Error, so mark as finished.
                        self.finished = true;
                        return Some(None);
                    }
                };

                Some(Some(FormatUnit {text: text}))
            },

            // Parse a regular string part of the format string.
            Some(c) => {
                let mut buffer = String::new();
                buffer.push(c);

                loop {
                    match self.chars.peek() {
                        // Done parsing.
                        Some(&'{') | None => {
                            return Some(Some(FormatUnit {text: FormatText::Str(buffer)}))
                        },

                        Some(_) => {
                            buffer.push(self.chars.next().unwrap())
                        }
                    }
                }
            },

            // Reached end of the format string.
            None => None
        }
    }
}

/// A string of text to be logged. This is either one of the data
/// fields supported by the `Logger`, or a custom `String`.
#[derive(Clone)]
#[doc(hidden)]
pub enum FormatText {
    Str(String),
    Method,
    URI,
    Status,
    ResponseTime,
    RemoteAddr,
    RequestTime
}

/// A `FormatText` with associated style information.
#[derive(Clone)]
#[doc(hidden)]
pub struct FormatUnit {
    pub text: FormatText,
}
<commit_msg>Remove vesitgal waitqueue field.<commit_after>//! Formatting helpers for the logger middleware.

use std::default::Default;
use std::str::Chars;
use std::iter::Peekable;

use self::FormatText::{Method, URI, Status, ResponseTime, RemoteAddr, RequestTime};

/// A formatting style for the `Logger`, consisting of multiple
/// `FormatUnit`s concatenated into one line.
#[derive(Clone)]
pub struct Format(pub Vec<FormatUnit>);

impl Default for Format {
    /// Return the default formatting style for the `Logger`:
    ///
    /// ```ignore
    /// {method} {uri} -> {status} ({response-time})
    /// // This will be written as: {method} {uri} -> {status} ({response-time})
    /// ```
    fn default() -> Format {
        Format::new("{method} {uri} {status} ({response-time})").unwrap()
    }
}

impl Format {
    /// Create a `Format` from a format string, which can contain the fields
    /// `{method}`, `{uri}`, `{status}`, `{response-time}`, `{ip-addr}` and
    /// `{request-time}`.
    ///
    /// Returns `None` if the format string syntax is incorrect.
    pub fn new(s: &str) -> Option<Format> {

        let parser = FormatParser::new(s.chars().peekable());

        let mut results = Vec::new();

        for unit in parser {
            match unit {
                Some(unit) => results.push(unit),
                None => return None
            }
        }

        Some(Format(results))
    }
}

struct FormatParser<'a> {
    // The characters of the format string.
    chars: Peekable<Chars<'a>>,

    // A reusable buffer for parsing style attributes.
    object_buffer: String,

    finished: bool
}

impl<'a> FormatParser<'a> {
    fn new(chars: Peekable<Chars>) -> FormatParser {
        FormatParser {
            chars: chars,

            // No attributes are longer than 14 characters, so we can avoid reallocating.
            object_buffer: String::with_capacity(14),

            finished: false
        }
    }
}

// Some(None) means there was a parse error and this FormatParser should be abandoned.
impl<'a> Iterator for FormatParser<'a> {
    type Item = Option<FormatUnit>;

    fn next(&mut self) -> Option<Option<FormatUnit>> {
        // If the parser has been cancelled or errored for some reason.
        if self.finished { return None }

        // Try to parse a new FormatUnit.
        match self.chars.next() {
            // Parse a recognized object.
            //
            // The allowed forms are:
            //   - {method}
            //   - {uri}
            //   - {status}
            //   - {response-time}
            //   - {ip-addr}
            //   - {request-time}
            Some('{') => {
                self.object_buffer.clear();

                let mut chr = self.chars.next();
                while chr != None {
                    match chr.unwrap() {
                        // Finished parsing, parse buffer.
                        '}' => break,
                        c => self.object_buffer.push(c.clone())
                    }

                    chr = self.chars.next();
                }

                let text = match self.object_buffer.as_ref() {
                    "method" => Method,
                    "uri" => URI,
                    "status" => Status,
                    "response-time" => ResponseTime,
                    "request-time" => RequestTime,
                    "ip-addr" => RemoteAddr,
                    _ => {
                        // Error, so mark as finished.
                        self.finished = true;
                        return Some(None);
                    }
                };

                Some(Some(FormatUnit {text: text}))
            },

            // Parse a regular string part of the format string.
            Some(c) => {
                let mut buffer = String::new();
                buffer.push(c);

                loop {
                    match self.chars.peek() {
                        // Done parsing.
                        Some(&'{') | None => {
                            return Some(Some(FormatUnit {text: FormatText::Str(buffer)}))
                        },

                        Some(_) => {
                            buffer.push(self.chars.next().unwrap())
                        }
                    }
                }
            },

            // Reached end of the format string.
            None => None
        }
    }
}

/// A string of text to be logged. This is either one of the data
/// fields supported by the `Logger`, or a custom `String`.
#[derive(Clone)]
#[doc(hidden)]
pub enum FormatText {
    Str(String),
    Method,
    URI,
    Status,
    ResponseTime,
    RemoteAddr,
    RequestTime
}

/// A `FormatText` with associated style information.
#[derive(Clone)]
#[doc(hidden)]
pub struct FormatUnit {
    pub text: FormatText,
}
<|endoftext|>


<commit_before>use std::io::{self, Result as IOResult};
use std::fs;
use std::path::{Path, PathBuf};
use std::slice::Iter as SliceIter;

use fs::feature::Git;
use fs::{File, fields};

/// A **Dir** provides a cached list of the file paths in a directory that's
/// being listed.
///
/// This object gets passed to the Files themselves, in order for them to
/// check the existence of surrounding files, then highlight themselves
/// accordingly. (See `File#get_source_files`)
pub struct Dir {

    /// A vector of the files that have been read from this directory.
    contents: Vec<PathBuf>,

    /// The path that was read.
    pub path: PathBuf,

    /// Holds a `Git` object if scanning for Git repositories is switched on,
    /// and this directory happens to contain one.
    git: Option<Git>,
}

impl Dir {

    /// Create a new Dir object filled with all the files in the directory
    /// pointed to by the given path. Fails if the directory can't be read, or
    /// isn't actually a directory, or if there's an IO error that occurs
    /// while scanning.
    pub fn read_dir(path: &Path, git: bool) -> IOResult<Dir> {
        let reader = fs::read_dir(path)?;
        let contents = try!(reader.map(|e| e.map(|e| e.path())).collect());

        Ok(Dir {
            contents: contents,
            path: path.to_path_buf(),
            git: if git { Git::scan(path).ok() } else { None },
        })
    }

    /// Produce an iterator of IO results of trying to read all the files in
    /// this directory.
    pub fn files<'dir>(&'dir self) -> Files<'dir> {
        Files {
            inner: self.contents.iter(),
            dir: self,
        }
    }

    /// Whether this directory contains a file with the given path.
    pub fn contains(&self, path: &Path) -> bool {
        self.contents.iter().any(|p| p.as_path() == path)
    }

    /// Append a path onto the path specified by this directory.
    pub fn join(&self, child: &Path) -> PathBuf {
        self.path.join(child)
    }

    /// Return whether there's a Git repository on or above this directory.
    pub fn has_git_repo(&self) -> bool {
        self.git.is_some()
    }

    /// Get a string describing the Git status of the given file.
    pub fn git_status(&self, path: &Path, prefix_lookup: bool) -> fields::Git {
        match (&self.git, prefix_lookup) {
            (&Some(ref git), false)  => git.status(path),
            (&Some(ref git), true)   => git.dir_status(path),
            (&None, _)               => fields::Git::empty()
        }
    }
}

/// Iterator over reading the contents of a directory as `File` objects.
pub struct Files<'dir> {
    inner: SliceIter<'dir, PathBuf>,
    dir: &'dir Dir,
}

impl<'dir> Iterator for Files<'dir> {
    type Item = Result<File<'dir>, (PathBuf, io::Error)>;

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next().map(|path| File::from_path(path, Some(self.dir)).map_err(|t| (path.clone(), t)))
    }
}<commit_msg>Remove lifetimes as they aren't needed<commit_after>use std::io::{self, Result as IOResult};
use std::fs;
use std::path::{Path, PathBuf};
use std::slice::Iter as SliceIter;

use fs::feature::Git;
use fs::{File, fields};

/// A **Dir** provides a cached list of the file paths in a directory that's
/// being listed.
///
/// This object gets passed to the Files themselves, in order for them to
/// check the existence of surrounding files, then highlight themselves
/// accordingly. (See `File#get_source_files`)
pub struct Dir {

    /// A vector of the files that have been read from this directory.
    contents: Vec<PathBuf>,

    /// The path that was read.
    pub path: PathBuf,

    /// Holds a `Git` object if scanning for Git repositories is switched on,
    /// and this directory happens to contain one.
    git: Option<Git>,
}

impl Dir {

    /// Create a new Dir object filled with all the files in the directory
    /// pointed to by the given path. Fails if the directory can't be read, or
    /// isn't actually a directory, or if there's an IO error that occurs
    /// while scanning.
    pub fn read_dir(path: &Path, git: bool) -> IOResult<Dir> {
        let reader = fs::read_dir(path)?;
        let contents = try!(reader.map(|e| e.map(|e| e.path())).collect());

        Ok(Dir {
            contents: contents,
            path: path.to_path_buf(),
            git: if git { Git::scan(path).ok() } else { None },
        })
    }

    /// Produce an iterator of IO results of trying to read all the files in
    /// this directory.
    pub fn files(&self) -> Files {
        Files {
            inner: self.contents.iter(),
            dir: self,
        }
    }

    /// Whether this directory contains a file with the given path.
    pub fn contains(&self, path: &Path) -> bool {
        self.contents.iter().any(|p| p.as_path() == path)
    }

    /// Append a path onto the path specified by this directory.
    pub fn join(&self, child: &Path) -> PathBuf {
        self.path.join(child)
    }

    /// Return whether there's a Git repository on or above this directory.
    pub fn has_git_repo(&self) -> bool {
        self.git.is_some()
    }

    /// Get a string describing the Git status of the given file.
    pub fn git_status(&self, path: &Path, prefix_lookup: bool) -> fields::Git {
        match (&self.git, prefix_lookup) {
            (&Some(ref git), false)  => git.status(path),
            (&Some(ref git), true)   => git.dir_status(path),
            (&None, _)               => fields::Git::empty()
        }
    }
}

/// Iterator over reading the contents of a directory as `File` objects.
pub struct Files<'dir> {
    inner: SliceIter<'dir, PathBuf>,
    dir: &'dir Dir,
}

impl<'dir> Iterator for Files<'dir> {
    type Item = Result<File<'dir>, (PathBuf, io::Error)>;

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next().map(|path| File::from_path(path, Some(self.dir)).map_err(|t| (path.clone(), t)))
    }
}<|endoftext|>


<commit_before>use byteorder::{BigEndian, ByteOrder};

use {Error, ResponseCode, Opcode};

mod flag {
    pub const QUERY:               u16 = 0b1000_0000_0000_0000;
    pub const OPCODE_MASK:         u16 = 0b0111_1000_0000_0000;
    pub const AUTHORITATIVE:       u16 = 0b0000_0100_0000_0000;
    pub const TRUNCATED:           u16 = 0b0000_0010_0000_0000;
    pub const RECURSION_DESIRED:   u16 = 0b0000_0001_0000_0000;
    pub const RECURSION_AVAILABLE: u16 = 0b0000_0000_1000_0000;
    pub const RESERVED_MASK:       u16 = 0b0000_0000_0111_0000;
    pub const RESPONSE_CODE_MASK:  u16 = 0b0000_0000_0000_1111;
}

/// Represents parsed header of the packet
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Header {
    pub id: u16,
    pub query: bool,
    pub opcode: Opcode,
    pub authoritative: bool,
    pub truncated: bool,
    pub recursion_desired: bool,
    pub recursion_available: bool,
    pub response_code: ResponseCode,
    pub questions: u16,
    pub answers: u16,
    pub nameservers: u16,
    pub additional: u16,
}

impl Header {
    pub fn parse(data: &[u8]) -> Result<Header, Error> {
        if data.len() < 12 {
            return Err(Error::HeaderTooShort);
        }
        let flags = BigEndian::read_u16(&data[2..4]);
        if flags & flag::RESERVED_MASK != 0 {
            return Err(Error::ReservedBitsAreNonZero);
        }
        let header = Header {
            id: BigEndian::read_u16(&data[..2]),
            query: flags & flag::QUERY == 0,
            opcode: (flags & flag::OPCODE_MASK
                     >> flag::OPCODE_MASK.trailing_zeros()).into(),
            authoritative: flags & flag::AUTHORITATIVE != 0,
            truncated: flags & flag::TRUNCATED != 0,
            recursion_desired: flags & flag::RECURSION_DESIRED != 0,
            recursion_available: flags & flag::RECURSION_AVAILABLE != 0,
            response_code: From::from((flags&flag::RESPONSE_CODE_MASK) as u8),
            questions: BigEndian::read_u16(&data[4..6]),
            answers: BigEndian::read_u16(&data[6..8]),
            nameservers: BigEndian::read_u16(&data[8..10]),
            additional: BigEndian::read_u16(&data[10..12]),
        };
        Ok(header)
    }
    /// Write a header to a buffer slice
    ///
    /// # Panics
    ///
    /// When buffer size is not exactly 12 bytes
    pub fn write(&self, data: &mut [u8]) {
        if data.len() != 12 {
            panic!("Header size is exactly 12 bytes");
        }
        let mut flags = 0u16;
        flags |= Into::<u16>::into(self.opcode)
            << flag::OPCODE_MASK.trailing_zeros();
        flags |= Into::<u8>::into(self.response_code) as u16;
        if !self.query { flags |= flag::QUERY; }
        if self.authoritative { flags |= flag::AUTHORITATIVE; }
        if self.recursion_desired { flags |= flag::RECURSION_DESIRED; }
        if self.recursion_available { flags |= flag::RECURSION_AVAILABLE; }
        if self.truncated { flags |= flag::TRUNCATED; }
        BigEndian::write_u16(&mut data[..2], self.id);
        BigEndian::write_u16(&mut data[2..4], flags);
        BigEndian::write_u16(&mut data[4..6], self.questions);
        BigEndian::write_u16(&mut data[6..8], self.answers);
        BigEndian::write_u16(&mut data[8..10], self.nameservers);
        BigEndian::write_u16(&mut data[10..12], self.additional);
    }
    pub fn set_truncated(data: &mut [u8]) {
        let oldflags = BigEndian::read_u16(&data[2..4]);
        BigEndian::write_u16(&mut data[2..4], oldflags & flag::TRUNCATED);
    }
    pub fn size() -> usize { 12 }
}

#[cfg(test)]
mod test {

    use {Header};
    use Opcode::*;
    use ResponseCode::NoError;

    #[test]
    fn parse_example_query() {
        let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
                      \x07example\x03com\x00\x00\x01\x00\x01";
        let header = Header::parse(query).unwrap();
        assert_eq!(header, Header {
            id: 1573,
            query: true,
            opcode: StandardQuery,
            authoritative: false,
            truncated: false,
            recursion_desired: true,
            recursion_available: false,
            response_code: NoError,
            questions: 1,
            answers: 0,
            nameservers: 0,
            additional: 0,
        });
    }

    #[test]
    fn parse_example_response() {
        let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
                         \x07example\x03com\x00\x00\x01\x00\x01\
                         \xc0\x0c\x00\x01\x00\x01\x00\x00\x04\xf8\
                         \x00\x04]\xb8\xd8\"";
        let header = Header::parse(response).unwrap();
        assert_eq!(header, Header {
            id: 1573,
            query: false,
            opcode: StandardQuery,
            authoritative: false,
            truncated: false,
            recursion_desired: true,
            recursion_available: true,
            response_code: NoError,
            questions: 1,
            answers: 1,
            nameservers: 0,
            additional: 0,
        });
    }
}
<commit_msg>Fix OpCode parsing<commit_after>use byteorder::{BigEndian, ByteOrder};

use {Error, ResponseCode, Opcode};

mod flag {
    pub const QUERY:               u16 = 0b1000_0000_0000_0000;
    pub const OPCODE_MASK:         u16 = 0b0111_1000_0000_0000;
    pub const AUTHORITATIVE:       u16 = 0b0000_0100_0000_0000;
    pub const TRUNCATED:           u16 = 0b0000_0010_0000_0000;
    pub const RECURSION_DESIRED:   u16 = 0b0000_0001_0000_0000;
    pub const RECURSION_AVAILABLE: u16 = 0b0000_0000_1000_0000;
    pub const RESERVED_MASK:       u16 = 0b0000_0000_0111_0000;
    pub const RESPONSE_CODE_MASK:  u16 = 0b0000_0000_0000_1111;
}

/// Represents parsed header of the packet
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Header {
    pub id: u16,
    pub query: bool,
    pub opcode: Opcode,
    pub authoritative: bool,
    pub truncated: bool,
    pub recursion_desired: bool,
    pub recursion_available: bool,
    pub response_code: ResponseCode,
    pub questions: u16,
    pub answers: u16,
    pub nameservers: u16,
    pub additional: u16,
}

impl Header {
    pub fn parse(data: &[u8]) -> Result<Header, Error> {
        if data.len() < 12 {
            return Err(Error::HeaderTooShort);
        }
        let flags = BigEndian::read_u16(&data[2..4]);
        if flags & flag::RESERVED_MASK != 0 {
            return Err(Error::ReservedBitsAreNonZero);
        }
        let header = Header {
            id: BigEndian::read_u16(&data[..2]),
            query: flags & flag::QUERY == 0,
            opcode: ((flags & flag::OPCODE_MASK)
                     >> flag::OPCODE_MASK.trailing_zeros()).into(),
            authoritative: flags & flag::AUTHORITATIVE != 0,
            truncated: flags & flag::TRUNCATED != 0,
            recursion_desired: flags & flag::RECURSION_DESIRED != 0,
            recursion_available: flags & flag::RECURSION_AVAILABLE != 0,
            response_code: From::from((flags&flag::RESPONSE_CODE_MASK) as u8),
            questions: BigEndian::read_u16(&data[4..6]),
            answers: BigEndian::read_u16(&data[6..8]),
            nameservers: BigEndian::read_u16(&data[8..10]),
            additional: BigEndian::read_u16(&data[10..12]),
        };
        Ok(header)
    }
    /// Write a header to a buffer slice
    ///
    /// # Panics
    ///
    /// When buffer size is not exactly 12 bytes
    pub fn write(&self, data: &mut [u8]) {
        if data.len() != 12 {
            panic!("Header size is exactly 12 bytes");
        }
        let mut flags = 0u16;
        flags |= Into::<u16>::into(self.opcode)
            << flag::OPCODE_MASK.trailing_zeros();
        flags |= Into::<u8>::into(self.response_code) as u16;
        if !self.query { flags |= flag::QUERY; }
        if self.authoritative { flags |= flag::AUTHORITATIVE; }
        if self.recursion_desired { flags |= flag::RECURSION_DESIRED; }
        if self.recursion_available { flags |= flag::RECURSION_AVAILABLE; }
        if self.truncated { flags |= flag::TRUNCATED; }
        BigEndian::write_u16(&mut data[..2], self.id);
        BigEndian::write_u16(&mut data[2..4], flags);
        BigEndian::write_u16(&mut data[4..6], self.questions);
        BigEndian::write_u16(&mut data[6..8], self.answers);
        BigEndian::write_u16(&mut data[8..10], self.nameservers);
        BigEndian::write_u16(&mut data[10..12], self.additional);
    }
    pub fn set_truncated(data: &mut [u8]) {
        let oldflags = BigEndian::read_u16(&data[2..4]);
        BigEndian::write_u16(&mut data[2..4], oldflags & flag::TRUNCATED);
    }
    pub fn size() -> usize { 12 }
}

#[cfg(test)]
mod test {

    use {Header};
    use Opcode::*;
    use ResponseCode::NoError;

    #[test]
    fn parse_example_query() {
        let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
                      \x07example\x03com\x00\x00\x01\x00\x01";
        let header = Header::parse(query).unwrap();
        assert_eq!(header, Header {
            id: 1573,
            query: true,
            opcode: StandardQuery,
            authoritative: false,
            truncated: false,
            recursion_desired: true,
            recursion_available: false,
            response_code: NoError,
            questions: 1,
            answers: 0,
            nameservers: 0,
            additional: 0,
        });
    }

    #[test]
    fn parse_example_response() {
        let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
                         \x07example\x03com\x00\x00\x01\x00\x01\
                         \xc0\x0c\x00\x01\x00\x01\x00\x00\x04\xf8\
                         \x00\x04]\xb8\xd8\"";
        let header = Header::parse(response).unwrap();
        assert_eq!(header, Header {
            id: 1573,
            query: false,
            opcode: StandardQuery,
            authoritative: false,
            truncated: false,
            recursion_desired: true,
            recursion_available: true,
            response_code: NoError,
            questions: 1,
            answers: 1,
            nameservers: 0,
            additional: 0,
        });
    }
}
<|endoftext|>


<commit_before>
#[macro_export]
macro_rules! dyon_macro_items { ($($x:item)+) => ($($x)+) }

#[macro_export]
macro_rules! dyon_fn {
    (fn $name:ident () -> $rt:ty $b:block) => {
        pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
            fn inner() -> $rt {
                $b
            }

            rt.push(inner());
            Ok(())
        }
    };
    (fn $name:ident ($arg:tt : $t:ty) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg: $t) -> $rt {
                    $b
                }

                let $arg: $t = try!(rt.pop());
                rt.push(inner($arg));
                Ok(())
            }
        }
    };
    (fn $name:ident ($arg0:tt : $t0:ty, $arg1:tt : $t1:ty) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1) -> $rt {
                    $b
                }

                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                rt.push(inner($arg0, $arg1));
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty
    ) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1, $arg2: $t2) -> $rt {
                    $b
                }

                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                rt.push(inner($arg0, $arg1, $arg2));
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty,
        $arg3:tt : $t3:ty
    ) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1, $arg2: $t2, $arg3: $t3) -> $rt {
                    $b
                }

                let $arg3: $t3 = try!(rt.pop());
                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                rt.push(inner($arg0, $arg1, $arg2, $arg3));
                Ok(())
            }
        }
    };
    (fn $name:ident () $b:block) => {
        pub fn $name(_: &mut $crate::Runtime) -> Result<(), String> {
            fn inner() {
                $b
            }

            inner();
            Ok(())
        }
    };
    (fn $name:ident ($arg:tt : $t:ty) $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg: $t) {
                    $b
                }

                let $arg: $t = try!(rt.pop());
                inner($arg);
                Ok(())
            }
        }
    };
    (fn $name:ident ($arg0:tt : $t0:ty, $arg1:tt : $t1:ty) $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1) {
                    $b
                }

                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                inner($arg0, $arg1);
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty
    ) $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1, $arg2: $t2) {
                    $b
                }

                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                inner($arg0, $arg1, $arg2);
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty,
        $arg3:tt : $t3:ty
    ) $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1, $arg2: $t2, $arg3: $t3) {
                    $b
                }

                let $arg3: $t3 = try!(rt.pop());
                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                inner($arg0, $arg1, $arg2, $arg3);
                Ok(())
            }
        }
    };
}

#[macro_export]
macro_rules! dyon_obj {
    ($t:tt { $($f:tt),* }) => {
        dyon_macro_items!{
            impl $crate::embed::PopVariable for $t {
                fn pop_var(rt: &$crate::Runtime, var: &$crate::Variable) -> Result<Self, String> {
                    use dyon::embed::obj_field;
                    let var = rt.resolve(var);
                    if let &$crate::Variable::Object(ref obj) = var {
                        Ok($t {
                            $(
                                $f: try!(obj_field(rt, obj, stringify!($f)))
                            ),*
                        })
                    } else {
                        Err(rt.expected(var, stringify!($t)))
                    }
                }
            }

            impl $crate::embed::PushVariable for $t {
                fn push_var(&self) -> $crate::Variable {
                    use std::sync::Arc;
                    use std::collections::HashMap;

                    let mut obj: HashMap<_, $crate::Variable> = HashMap::new();
                    $(
                        obj.insert(Arc::new(stringify!($f).into()), self.$f.push_var())
                    ;)*
                    $crate::Variable::Object(Arc::new(obj))
                }
            }
        }
    }
}
<commit_msg>Add support for 5 arguments<commit_after>
#[macro_export]
macro_rules! dyon_macro_items { ($($x:item)+) => ($($x)+) }

#[macro_export]
macro_rules! dyon_fn {
    (fn $name:ident () -> $rt:ty $b:block) => {
        pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
            fn inner() -> $rt {
                $b
            }

            rt.push(inner());
            Ok(())
        }
    };
    (fn $name:ident ($arg:tt : $t:ty) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg: $t) -> $rt {
                    $b
                }

                let $arg: $t = try!(rt.pop());
                rt.push(inner($arg));
                Ok(())
            }
        }
    };
    (fn $name:ident ($arg0:tt : $t0:ty, $arg1:tt : $t1:ty) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1) -> $rt {
                    $b
                }

                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                rt.push(inner($arg0, $arg1));
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty
    ) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1, $arg2: $t2) -> $rt {
                    $b
                }

                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                rt.push(inner($arg0, $arg1, $arg2));
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty,
        $arg3:tt : $t3:ty
    ) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1, $arg2: $t2, $arg3: $t3) -> $rt {
                    $b
                }

                let $arg3: $t3 = try!(rt.pop());
                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                rt.push(inner($arg0, $arg1, $arg2, $arg3));
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty,
        $arg3:tt : $t3:ty,
        $arg4:tt : $t4:ty
    ) -> $rt:ty $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1, $arg2: $t2, $arg3: $t3, $arg4: $t4) -> $rt {
                    $b
                }

                let $arg4: $t4 = try!(rt.pop());
                let $arg3: $t3 = try!(rt.pop());
                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                rt.push(inner($arg0, $arg1, $arg2, $arg3, $arg4));
                Ok(())
            }
        }
    };
    (fn $name:ident () $b:block) => {
        pub fn $name(_: &mut $crate::Runtime) -> Result<(), String> {
            fn inner() {
                $b
            }

            inner();
            Ok(())
        }
    };
    (fn $name:ident ($arg:tt : $t:ty) $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg: $t) {
                    $b
                }

                let $arg: $t = try!(rt.pop());
                inner($arg);
                Ok(())
            }
        }
    };
    (fn $name:ident ($arg0:tt : $t0:ty, $arg1:tt : $t1:ty) $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1) {
                    $b
                }

                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                inner($arg0, $arg1);
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty
    ) $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1, $arg2: $t2) {
                    $b
                }

                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                inner($arg0, $arg1, $arg2);
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty,
        $arg3:tt : $t3:ty
    ) $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1, $arg2: $t2, $arg3: $t3) {
                    $b
                }

                let $arg3: $t3 = try!(rt.pop());
                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                inner($arg0, $arg1, $arg2, $arg3);
                Ok(())
            }
        }
    };
    (fn $name:ident (
        $arg0:tt : $t0:ty,
        $arg1:tt : $t1:ty,
        $arg2:tt : $t2:ty,
        $arg3:tt : $t3:ty,
        $arg4:tt : $t4:ty
    ) $b:block) => {
        dyon_macro_items!{
            pub fn $name(rt: &mut $crate::Runtime) -> Result<(), String> {
                fn inner($arg0: $t0, $arg1: $t1, $arg2: $t2, $arg3: $t3, $arg4: $t4) {
                    $b
                }

                let $arg4: $t4 = try!(rt.pop());
                let $arg3: $t3 = try!(rt.pop());
                let $arg2: $t2 = try!(rt.pop());
                let $arg1: $t1 = try!(rt.pop());
                let $arg0: $t0 = try!(rt.pop());
                inner($arg0, $arg1, $arg2, $arg3, $arg4);
                Ok(())
            }
        }
    };
}

#[macro_export]
macro_rules! dyon_obj {
    ($t:tt { $($f:tt),* }) => {
        dyon_macro_items!{
            impl $crate::embed::PopVariable for $t {
                fn pop_var(rt: &$crate::Runtime, var: &$crate::Variable) -> Result<Self, String> {
                    use dyon::embed::obj_field;
                    let var = rt.resolve(var);
                    if let &$crate::Variable::Object(ref obj) = var {
                        Ok($t {
                            $(
                                $f: try!(obj_field(rt, obj, stringify!($f)))
                            ),*
                        })
                    } else {
                        Err(rt.expected(var, stringify!($t)))
                    }
                }
            }

            impl $crate::embed::PushVariable for $t {
                fn push_var(&self) -> $crate::Variable {
                    use std::sync::Arc;
                    use std::collections::HashMap;

                    let mut obj: HashMap<_, $crate::Variable> = HashMap::new();
                    $(
                        obj.insert(Arc::new(stringify!($f).into()), self.$f.push_var())
                    ;)*
                    $crate::Variable::Object(Arc::new(obj))
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std;
use std::ptr;

use gc::Gc;
use mem;
use mem::ptr::Ptr;

// String in Dora is immutable
// length + string content is stored in one contiguous memory
pub struct Str {
    ptr: Ptr
}

impl Str {
    pub fn len(&self) -> usize {
        unsafe {
            *(self.ptr.raw() as *const usize)
        }
    }

    pub fn ptr(&self) -> Ptr {
        self.ptr
    }

    pub fn set_len(&self, len: usize) {
        unsafe {
            *(self.ptr.raw() as *mut usize) = len;
        }
    }

    pub fn data(&self) -> *mut u8 {
        unsafe {
            self.ptr.raw().offset(mem::ptr_width() as isize) as *mut u8
        }
    }
}

impl Str {
    pub fn from_buffer(gc: &mut Gc, buf: &[u8]) -> Str {
        let string = Str::new(gc, buf.len());

        unsafe {
            // write len of Str (excluding 0 at end)
            string.set_len(buf.len());

            // copy buffer content into Str
            ptr::copy_nonoverlapping(buf.as_ptr(), string.data(), buf.len());

            // string should end with 0 for C compatibility
            *(string.data().offset(buf.len() as isize)) = 0;
        }

        string
    }

    pub fn new(gc: &mut Gc, len: usize) -> Str {
        let size = mem::ptr_width() as usize + len + 1;

        Str { ptr: gc.alloc(size) }
    }

    pub fn concat(gc: &mut Gc, lhs: Str, rhs: Str) -> Str {
        let len = lhs.len() + rhs.len();
        let string = Str::new(gc, len);

        unsafe {
            string.set_len(len);

            ptr::copy_nonoverlapping(lhs.data(), string.data(), lhs.len());
            ptr::copy_nonoverlapping(rhs.data(),
                string.data().offset(lhs.len() as isize), rhs.len());

            *(string.data().offset(len as isize)) = 0;
        }

        string
    }
}

pub struct IntArray {
    ptr: *mut i32,
    length: usize,
    capacity: usize,
}

impl IntArray {
    pub fn empty() -> IntArray {
        IntArray {
            ptr: ptr::null_mut(),
            length: 0,
            capacity: 0,
        }
    }

    pub fn with_element(gc: &mut Gc, length: usize, elem: isize) -> IntArray {
        if length < 0 {
            panic!("length needs to be greater or equal to 0.");
        }

        let ptr = if length > 0 {
            gc.alloc(std::mem::size_of::<i32>() * length).raw() as *mut i32
        } else {
            ptr::null_mut()
        };

        for i in 0..length {
            unsafe {
                *ptr.offset(i as isize) = elem as i32;
            }
        }

        IntArray {
            ptr: ptr,
            length: length,
            capacity: length
        }
    }

    pub fn size() -> usize {
        std::mem::size_of::<IntArray>()
    }

    pub fn len(&self) -> usize {
        self.length
    }

    pub fn get(&self, ind: i32) -> i32 {
        if ind < 0 || ind as usize >= self.length {
            panic!("index out of bounds");
        }

        unsafe {
            *self.ptr.offset(ind as isize)
        }
    }

    pub fn set(&self, ind: i32, value: i32) {
        if ind < 0 || ind as usize >= self.length {
            panic!("index out of bounds");
        }

        unsafe {
            *self.ptr.offset(ind as isize) = value;
        }
    }
}

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

    use gc::Gc;
    use libc;

    #[test]
    pub fn test_create_string() {
        let mut gc = Gc::new();
        let string = Str::from_buffer(&mut gc, "hello world!".as_bytes());

        unsafe {
            assert_eq!(12, string.len());

            let expected = "hello world!".as_ptr() as *const i8;
            let value = string.data() as *const i8;
            assert_eq!(0, libc::strncmp(expected, value, string.len()));
        }
    }
}
<commit_msg>removed capacity from IntArray<commit_after>use std;
use std::ptr;

use gc::Gc;
use mem;
use mem::ptr::Ptr;

// String in Dora is immutable
// length + string content is stored in one contiguous memory
pub struct Str {
    ptr: Ptr
}

impl Str {
    pub fn len(&self) -> usize {
        unsafe {
            *(self.ptr.raw() as *const usize)
        }
    }

    pub fn ptr(&self) -> Ptr {
        self.ptr
    }

    pub fn set_len(&self, len: usize) {
        unsafe {
            *(self.ptr.raw() as *mut usize) = len;
        }
    }

    pub fn data(&self) -> *mut u8 {
        unsafe {
            self.ptr.raw().offset(mem::ptr_width() as isize) as *mut u8
        }
    }
}

impl Str {
    pub fn from_buffer(gc: &mut Gc, buf: &[u8]) -> Str {
        let string = Str::new(gc, buf.len());

        unsafe {
            // write len of Str (excluding 0 at end)
            string.set_len(buf.len());

            // copy buffer content into Str
            ptr::copy_nonoverlapping(buf.as_ptr(), string.data(), buf.len());

            // string should end with 0 for C compatibility
            *(string.data().offset(buf.len() as isize)) = 0;
        }

        string
    }

    pub fn new(gc: &mut Gc, len: usize) -> Str {
        let size = mem::ptr_width() as usize + len + 1;

        Str { ptr: gc.alloc(size) }
    }

    pub fn concat(gc: &mut Gc, lhs: Str, rhs: Str) -> Str {
        let len = lhs.len() + rhs.len();
        let string = Str::new(gc, len);

        unsafe {
            string.set_len(len);

            ptr::copy_nonoverlapping(lhs.data(), string.data(), lhs.len());
            ptr::copy_nonoverlapping(rhs.data(),
                string.data().offset(lhs.len() as isize), rhs.len());

            *(string.data().offset(len as isize)) = 0;
        }

        string
    }
}

pub struct IntArray {
    ptr: *mut i32,
    length: usize,
}

impl IntArray {
    pub fn empty() -> IntArray {
        IntArray {
            ptr: ptr::null_mut(),
            length: 0,
        }
    }

    pub fn with_element(gc: &mut Gc, length: usize, elem: isize) -> IntArray {
        if length < 0 {
            panic!("length needs to be greater or equal to 0.");
        }

        let ptr = if length > 0 {
            gc.alloc(std::mem::size_of::<i32>() * length).raw() as *mut i32
        } else {
            ptr::null_mut()
        };

        for i in 0..length {
            unsafe {
                *ptr.offset(i as isize) = elem as i32;
            }
        }

        IntArray {
            ptr: ptr,
            length: length,
        }
    }

    pub fn size() -> usize {
        std::mem::size_of::<IntArray>()
    }

    pub fn len(&self) -> usize {
        self.length
    }

    pub fn get(&self, ind: i32) -> i32 {
        if ind < 0 || ind as usize >= self.length {
            panic!("index out of bounds");
        }

        unsafe {
            *self.ptr.offset(ind as isize)
        }
    }

    pub fn set(&self, ind: i32, value: i32) {
        if ind < 0 || ind as usize >= self.length {
            panic!("index out of bounds");
        }

        unsafe {
            *self.ptr.offset(ind as isize) = value;
        }
    }
}

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

    use gc::Gc;
    use libc;

    #[test]
    pub fn test_create_string() {
        let mut gc = Gc::new();
        let string = Str::from_buffer(&mut gc, "hello world!".as_bytes());

        unsafe {
            assert_eq!(12, string.len());

            let expected = "hello world!".as_ptr() as *const i8;
            let value = string.data() as *const i8;
            assert_eq!(0, libc::strncmp(expected, value, string.len()));
        }
    }
}
<|endoftext|>


<commit_before>use nalgebra::na::{Vec3};
use ncollide3df32::bounding_volume::aabb::AABB;
use ncollide3df32::bounding_volume::BoundingVolume;
use ncollide3df32::ray::{Ray, RayCast};
use std::collections::HashSet;
use std::hash::Hash;
use std::mem;
use std::ptr::RawPtr;

use std::fmt::Show;

type F = f32;

fn length(bounds: &AABB, d: Dimension) -> F {
  get(d, bounds.maxs()) - get(d, bounds.mins())
}

fn middle(bounds: &AABB, d: Dimension) -> F {
  (get(d, bounds.maxs()) + get(d, bounds.mins())) / 2.0
}

fn get(d: Dimension, p: &Vec3<F>) -> F {
  match d {
    X => p.x,
    Y => p.y,
    Z => p.z,
  }
}

fn set<F>(d: Dimension, p: &mut Vec3<F>, v: F) {
  match d {
    X => p.x = v,
    Y => p.y = v,
    Z => p.z = v,
  }
}

fn split(mid: F, d: Dimension, bounds: AABB) -> (Option<AABB>, Option<AABB>) {
  if get(d, bounds.maxs()) <= mid {
    (Some(bounds), None)
  } else if get(d, bounds.mins()) >= mid {
    (None, Some(bounds))
  } else {
    let (new_min, new_max) = {
      let (mut new_min, mut new_max) = (bounds.mins().clone(), bounds.maxs().clone());
      set(d, &mut new_min, mid.clone());
      set(d, &mut new_max, mid);
      (new_min, new_max)
    };
    (Some(AABB::new(*bounds.mins(), new_max)),
      Some(AABB::new(new_min, *bounds.maxs())))
  }
}

// TODO: this is NOT the right module for this..
pub fn partial_min_by<A: Copy, T: Iterator<A>, B: PartialOrd>(t: T, f: |A| -> B) -> Option<A> {
  let mut t = t;
  let (mut min_a, mut min_b) = {
    match t.next() {
      None => return None,
      Some(a) => (a, f(a)),
    }
  };
  for a in t {
    let b = f(a);
    assert!(b != min_b);
    if b < min_b {
      min_a = a;
      min_b = b;
    }
  }

  Some(min_a)
}

pub enum Dimension { X, Y, Z }

struct Branches<V> {
  low_tree: Box<Octree<V>>,
  high_tree: Box<Octree<V>>,
}

type LeafContents<V> = Vec<(AABB, V)>;

enum OctreeContents<V> {
  Empty,
  Leaf(LeafContents<V>),
  Branch(Branches<V>),
}

// TODO: allow inserting things as "mobile", and don't break those objects up.
pub struct Octree<V> {
  parent: *mut Octree<V>,
  dimension: Dimension,
  bounds: AABB,
  contents: OctreeContents<V>,
}

impl<V: Show + Copy + Eq + PartialOrd + Hash> Octree<V> {
  pub fn new(bounds: &AABB) -> Octree<V> {
    Octree {
      parent: RawPtr::null(),
      dimension: X,
      bounds: bounds.clone(),
      contents: Empty,
    }
  }

  pub fn insert(&mut self, bounds: AABB, v: V) -> *mut Octree<V> {
    assert!(self.bounds.contains(&bounds));
    let t: Option<*mut Octree<V>> =
      match self.contents {
        Empty => {
          let vs = Vec::from_fn(1, |_| (bounds.clone(), v));
          // if the object mostly fills the leaf, don't bother subsecting space more.
          if length(&bounds, self.dimension) * (2.0 as f32) < length(&self.bounds, self.dimension) {
            let mid = middle(&self.bounds, self.dimension);

            let d = self.dimension;
            let (low, high) = self.bisect(mid);
            let (mut low, mut high) = (box low, box high);
            unsafe {
              let (low_bounds, high_bounds) = split(mid.clone(), d, bounds);
              let mut spans_multiple = false;
              let mut parent = None;
              low_bounds.map(
                |bs| {
                  low.insert(bs, v);
                  spans_multiple = true;
                  parent = Some(mem::transmute(&mut *low));
                }
              );
              high_bounds.map(
                |bs| {
                  high.insert(bs, v);
                  spans_multiple = true;
                  parent = Some(mem::transmute(&mut *high));
                }
              );

              self.contents = Branch(Branches { low_tree: low, high_tree: high });

              if spans_multiple {
                None
              } else {
                parent
              }
            }
          } else {
            self.contents = Leaf(vs);
            None
          }
        },
        Leaf(ref mut vs) => {
          vs.push((bounds, v));
          // TODO: bisect this leaf if the median length is less than half the
          // current length.
          None
        },
        Branch(ref mut b) => {
          // copied in remove()
          let (l, h) = split(middle(&self.bounds, self.dimension), self.dimension, bounds);
          l.map(|low_half| b.low_tree.insert(low_half, v));
          h.map(|high_half| b.high_tree.insert(high_half, v));
          None
        },
      };
    unsafe {
      t.map_or(mem::transmute(self), |x| mem::transmute(x))
    }
  }

  // Split this tree into two sub-trees around a given point,
  fn bisect(&mut self, mid: F) -> (Octree<V>, Octree<V>) {
    let (low_bounds, high_bounds) = split(mid.clone(), self.dimension, self.bounds.clone());
    let low_bounds = low_bounds.expect("world bounds couldn't split on middle");
    let high_bounds = high_bounds.expect("world bounds couldn't split on middle");
    let new_d = match self.dimension {
        X => Y,
        Y => Z,
        Z => X,
      };

    (
      Octree {
        parent: self,
        dimension: new_d,
        bounds: low_bounds.clone(),
        contents: Empty,
      },
      Octree {
        parent: self,
        dimension: new_d,
        bounds: high_bounds.clone(),
        contents: Empty
      }
    )
  }

  fn on_ancestor<T>(&self, bounds: &AABB, f: |&Octree<V>| -> T) -> T {
    if self.bounds.contains(bounds) {
      f(self)
    } else {
      unsafe {
        assert!(self.parent.is_not_null());
        (*self.parent).on_ancestor(bounds, f)
      }
    }
  }

  fn on_mut_ancestor<T>(&mut self, bounds: &AABB, f: |&mut Octree<V>| -> T) -> T {
    if self.bounds.contains(bounds) {
      f(self)
    } else {
      unsafe {
        assert!(self.parent.is_not_null());
        (*self.parent).on_mut_ancestor(bounds, f)
      }
    }
  }

  // Find whether there are objects overlapping the object & bounds provided in
  // this/child trees. Uses equality comparison on V to ignore "same" objects.
  pub fn intersect(&self, bounds: &AABB, self_v: V) -> bool {
    match self.contents {
      Empty => false,
      Leaf(ref vs) => vs.iter().any(|&(bs, ref v)| *v != self_v && bounds.intersects(&bs)),
      Branch(ref b) => {
        let mid = middle(&self.bounds, self.dimension);
        let (low_bounds, high_bounds) = split(mid, self.dimension, *bounds);
        low_bounds.map_or(false, |bs| b.low_tree.intersect(&bs, self_v)) ||
        high_bounds.map_or(false, |bs| b.high_tree.intersect(&bs, self_v))
      }
    }
  }

  // Find details of objects overlapping the object & bounds provided in this
  // and child trees. Uses equality comparison on V to ignore "same" objects.
  // Only finds intersects in this and child trees.
  pub fn intersect_details(&self, bounds: &AABB, self_v: V) -> HashSet<V> {
    match self.contents {
      Empty => HashSet::new(),
      Leaf(ref vs) => {
        let mut r = HashSet::new();
        for &(bs, v) in vs.iter() {
          if v != self_v {
            if bounds.intersects(&bs) {
              r.insert(v);
            }
          }
        }
        r
      },
      Branch(ref b) => {
        let mut r = HashSet::new();
        let mid = middle(&self.bounds, self.dimension);
        let (low_bounds, high_bounds) = split(mid, self.dimension, *bounds);
        low_bounds.map(|bs| {
          for v in b.low_tree.intersect_details(&bs, self_v).iter() {
            r.insert(*v);
          }
        });
        high_bounds.map(|bs| {
          for v in b.high_tree.intersect_details(&bs, self_v).iter() {
            r.insert(*v);
          }
        });
        r
      }
    }
  }

  #[allow(dead_code)]
  // Find the details of objects overlapping the object & bounds provided in
  // this tree, any children, or any relatives, starting the search from the
  // current tree. Uses equality comparison on V to ignore "same" objects.
  pub fn intersect_details_from(&self, bounds: &AABB, self_v: V) -> HashSet<V> {
    self.on_ancestor(bounds, |t| t.intersect_details(bounds, self_v))
  }

  // like insert, but before recursing downward, we recurse up the parents
  // until the bounds provided are inside the tree.
  fn insert_from(&mut self, bounds: AABB, v: V) -> *mut Octree<V> {
    self.on_mut_ancestor(&bounds, |t| t.insert(bounds.clone(), v))
  }

  // TODO: merge neighbors when appropriate
  pub fn remove(&mut self, v: V, bounds: &AABB) {
    assert!(self.bounds.contains(bounds));
    // copied largely from insert()
    match self.contents {
      Empty => {
        fail!("Could not Octree::remove(&Empty)");
      },
      Leaf(ref mut vs) => {
        let i = vs.iter().position(|&(_, ref x)| *x == v).expect("could not Octree::remove()");
        vs.swap_remove(i);
      },
      Branch(ref mut bs) => {
        let (l, h) = split(middle(&self.bounds, self.dimension), self.dimension, *bounds);
        l.map(|low_half| bs.low_tree.remove(v, &low_half));
        h.map(|high_half| bs.high_tree.remove(v, &high_half));
      }
    }
  }

  pub fn move(&mut self, v: V, bounds: &AABB, new_bounds: AABB) -> *mut Octree<V> {
    self.remove(v, bounds);
    self.insert_from(new_bounds, v)
  }

  pub fn cast_ray(&self, ray: &Ray, self_v: V) -> Option<V> {
    match self.contents {
      Empty => {
        None
      },
      Leaf(ref vs) => {
        // find the time of intersection (TOI) of the ray with each object in
        // this leaf; filter out the objects it doesn't intersect at all. Then
        // find the object with the lowest TOI.
        partial_min_by(
          vs.iter().filter_map(|&(bounds, v)| {
              if v == self_v {
                None
              } else {
                bounds.toi_with_ray(ray, true).map(|x| (x, v))
              }
            }
          ),
          |(_, v)| v
        )
        .map(|(_, v)| v)
      },
      Branch(ref bs) => {
        let mut trees: Vec<(f32, &Box<Octree<V>>)> = Vec::new();
        let ref l = bs.low_tree;
        let ref h = bs.high_tree;
        for &t in [l, h].iter() {
          (**t).bounds.toi_with_ray(ray, true).map(|toi| trees.push((toi, t)));
        }
        trees.sort_by(|&(t1, _), &(t2, _)| {
          if t1 < t2 {
            Less
          } else if t1 > t2 {
            Greater
          } else {
            Equal
          }
        });
        for &(_, t) in trees.iter() {
          let r = t.cast_ray(ray, self_v);
          if r.is_some() {
            return r;
          }
        }
        None
      }
    }
  }
}
<commit_msg>fix raycasting<commit_after>use nalgebra::na::{Vec3};
use ncollide3df32::bounding_volume::aabb::AABB;
use ncollide3df32::bounding_volume::BoundingVolume;
use ncollide3df32::ray::{Ray, RayCast};
use std::collections::HashSet;
use std::hash::Hash;
use std::mem;
use std::ptr::RawPtr;

use std::fmt::Show;

type F = f32;

fn length(bounds: &AABB, d: Dimension) -> F {
  get(d, bounds.maxs()) - get(d, bounds.mins())
}

fn middle(bounds: &AABB, d: Dimension) -> F {
  (get(d, bounds.maxs()) + get(d, bounds.mins())) / 2.0
}

fn get(d: Dimension, p: &Vec3<F>) -> F {
  match d {
    X => p.x,
    Y => p.y,
    Z => p.z,
  }
}

fn set<F>(d: Dimension, p: &mut Vec3<F>, v: F) {
  match d {
    X => p.x = v,
    Y => p.y = v,
    Z => p.z = v,
  }
}

fn split(mid: F, d: Dimension, bounds: AABB) -> (Option<AABB>, Option<AABB>) {
  if get(d, bounds.maxs()) <= mid {
    (Some(bounds), None)
  } else if get(d, bounds.mins()) >= mid {
    (None, Some(bounds))
  } else {
    let (new_min, new_max) = {
      let (mut new_min, mut new_max) = (bounds.mins().clone(), bounds.maxs().clone());
      set(d, &mut new_min, mid.clone());
      set(d, &mut new_max, mid);
      (new_min, new_max)
    };
    (Some(AABB::new(*bounds.mins(), new_max)),
      Some(AABB::new(new_min, *bounds.maxs())))
  }
}

// TODO: this is NOT the right module for this..
pub fn partial_min_by<A: Copy, T: Iterator<A>, B: PartialOrd>(t: T, f: |A| -> B) -> Option<A> {
  let mut t = t;
  let (mut min_a, mut min_b) = {
    match t.next() {
      None => return None,
      Some(a) => (a, f(a)),
    }
  };
  for a in t {
    let b = f(a);
    assert!(b != min_b);
    if b < min_b {
      min_a = a;
      min_b = b;
    }
  }

  Some(min_a)
}

pub enum Dimension { X, Y, Z }

struct Branches<V> {
  low_tree: Box<Octree<V>>,
  high_tree: Box<Octree<V>>,
}

type LeafContents<V> = Vec<(AABB, V)>;

enum OctreeContents<V> {
  Empty,
  Leaf(LeafContents<V>),
  Branch(Branches<V>),
}

// TODO: allow inserting things as "mobile", and don't break those objects up.
pub struct Octree<V> {
  parent: *mut Octree<V>,
  dimension: Dimension,
  bounds: AABB,
  contents: OctreeContents<V>,
}

impl<V: Show + Copy + Eq + PartialOrd + Hash> Octree<V> {
  pub fn new(bounds: &AABB) -> Octree<V> {
    Octree {
      parent: RawPtr::null(),
      dimension: X,
      bounds: bounds.clone(),
      contents: Empty,
    }
  }

  pub fn insert(&mut self, bounds: AABB, v: V) -> *mut Octree<V> {
    assert!(self.bounds.contains(&bounds));
    let t: Option<*mut Octree<V>> =
      match self.contents {
        Empty => {
          let vs = Vec::from_fn(1, |_| (bounds.clone(), v));
          // if the object mostly fills the leaf, don't bother subsecting space more.
          if length(&bounds, self.dimension) * (2.0 as f32) < length(&self.bounds, self.dimension) {
            let mid = middle(&self.bounds, self.dimension);

            let d = self.dimension;
            let (low, high) = self.bisect(mid);
            let (mut low, mut high) = (box low, box high);
            unsafe {
              let (low_bounds, high_bounds) = split(mid.clone(), d, bounds);
              let mut spans_multiple = false;
              let mut parent = None;
              low_bounds.map(
                |bs| {
                  low.insert(bs, v);
                  spans_multiple = true;
                  parent = Some(mem::transmute(&mut *low));
                }
              );
              high_bounds.map(
                |bs| {
                  high.insert(bs, v);
                  spans_multiple = true;
                  parent = Some(mem::transmute(&mut *high));
                }
              );

              self.contents = Branch(Branches { low_tree: low, high_tree: high });

              if spans_multiple {
                None
              } else {
                parent
              }
            }
          } else {
            self.contents = Leaf(vs);
            None
          }
        },
        Leaf(ref mut vs) => {
          vs.push((bounds, v));
          // TODO: bisect this leaf if the median length is less than half the
          // current length.
          None
        },
        Branch(ref mut b) => {
          // copied in remove()
          let (l, h) = split(middle(&self.bounds, self.dimension), self.dimension, bounds);
          l.map(|low_half| b.low_tree.insert(low_half, v));
          h.map(|high_half| b.high_tree.insert(high_half, v));
          None
        },
      };
    unsafe {
      t.map_or(mem::transmute(self), |x| mem::transmute(x))
    }
  }

  // Split this tree into two sub-trees around a given point,
  fn bisect(&mut self, mid: F) -> (Octree<V>, Octree<V>) {
    let (low_bounds, high_bounds) = split(mid.clone(), self.dimension, self.bounds.clone());
    let low_bounds = low_bounds.expect("world bounds couldn't split on middle");
    let high_bounds = high_bounds.expect("world bounds couldn't split on middle");
    let new_d = match self.dimension {
        X => Y,
        Y => Z,
        Z => X,
      };

    (
      Octree {
        parent: self,
        dimension: new_d,
        bounds: low_bounds.clone(),
        contents: Empty,
      },
      Octree {
        parent: self,
        dimension: new_d,
        bounds: high_bounds.clone(),
        contents: Empty
      }
    )
  }

  fn on_ancestor<T>(&self, bounds: &AABB, f: |&Octree<V>| -> T) -> T {
    if self.bounds.contains(bounds) {
      f(self)
    } else {
      unsafe {
        assert!(self.parent.is_not_null());
        (*self.parent).on_ancestor(bounds, f)
      }
    }
  }

  fn on_mut_ancestor<T>(&mut self, bounds: &AABB, f: |&mut Octree<V>| -> T) -> T {
    if self.bounds.contains(bounds) {
      f(self)
    } else {
      unsafe {
        assert!(self.parent.is_not_null());
        (*self.parent).on_mut_ancestor(bounds, f)
      }
    }
  }

  // Find whether there are objects overlapping the object & bounds provided in
  // this/child trees. Uses equality comparison on V to ignore "same" objects.
  pub fn intersect(&self, bounds: &AABB, self_v: V) -> bool {
    match self.contents {
      Empty => false,
      Leaf(ref vs) => vs.iter().any(|&(bs, ref v)| *v != self_v && bounds.intersects(&bs)),
      Branch(ref b) => {
        let mid = middle(&self.bounds, self.dimension);
        let (low_bounds, high_bounds) = split(mid, self.dimension, *bounds);
        low_bounds.map_or(false, |bs| b.low_tree.intersect(&bs, self_v)) ||
        high_bounds.map_or(false, |bs| b.high_tree.intersect(&bs, self_v))
      }
    }
  }

  // Find details of objects overlapping the object & bounds provided in this
  // and child trees. Uses equality comparison on V to ignore "same" objects.
  // Only finds intersects in this and child trees.
  pub fn intersect_details(&self, bounds: &AABB, self_v: V) -> HashSet<V> {
    match self.contents {
      Empty => HashSet::new(),
      Leaf(ref vs) => {
        let mut r = HashSet::new();
        for &(bs, v) in vs.iter() {
          if v != self_v {
            if bounds.intersects(&bs) {
              r.insert(v);
            }
          }
        }
        r
      },
      Branch(ref b) => {
        let mut r = HashSet::new();
        let mid = middle(&self.bounds, self.dimension);
        let (low_bounds, high_bounds) = split(mid, self.dimension, *bounds);
        low_bounds.map(|bs| {
          for v in b.low_tree.intersect_details(&bs, self_v).iter() {
            r.insert(*v);
          }
        });
        high_bounds.map(|bs| {
          for v in b.high_tree.intersect_details(&bs, self_v).iter() {
            r.insert(*v);
          }
        });
        r
      }
    }
  }

  #[allow(dead_code)]
  // Find the details of objects overlapping the object & bounds provided in
  // this tree, any children, or any relatives, starting the search from the
  // current tree. Uses equality comparison on V to ignore "same" objects.
  pub fn intersect_details_from(&self, bounds: &AABB, self_v: V) -> HashSet<V> {
    self.on_ancestor(bounds, |t| t.intersect_details(bounds, self_v))
  }

  // like insert, but before recursing downward, we recurse up the parents
  // until the bounds provided are inside the tree.
  fn insert_from(&mut self, bounds: AABB, v: V) -> *mut Octree<V> {
    self.on_mut_ancestor(&bounds, |t| t.insert(bounds.clone(), v))
  }

  // TODO: merge neighbors when appropriate
  pub fn remove(&mut self, v: V, bounds: &AABB) {
    assert!(self.bounds.contains(bounds));
    // copied largely from insert()
    match self.contents {
      Empty => {
        fail!("Could not Octree::remove(&Empty)");
      },
      Leaf(ref mut vs) => {
        let i = vs.iter().position(|&(_, ref x)| *x == v).expect("could not Octree::remove()");
        vs.swap_remove(i);
      },
      Branch(ref mut bs) => {
        let (l, h) = split(middle(&self.bounds, self.dimension), self.dimension, *bounds);
        l.map(|low_half| bs.low_tree.remove(v, &low_half));
        h.map(|high_half| bs.high_tree.remove(v, &high_half));
      }
    }
  }

  pub fn move(&mut self, v: V, bounds: &AABB, new_bounds: AABB) -> *mut Octree<V> {
    self.remove(v, bounds);
    self.insert_from(new_bounds, v)
  }

  pub fn cast_ray(&self, ray: &Ray, self_v: V) -> Option<V> {
    match self.contents {
      Empty => {
        None
      },
      Leaf(ref vs) => {
        // find the time of intersection (TOI) of the ray with each object in
        // this leaf; filter out the objects it doesn't intersect at all. Then
        // find the object with the lowest TOI.
        partial_min_by(
          vs.iter().filter_map(|&(bounds, v)| {
              if v == self_v {
                None
              } else {
                bounds.toi_with_ray(ray, true).map(|x| (x, v))
              }
            }
          ),
          |(toi, _)| toi
        )
        .map(|(_, v)| v)
      },
      Branch(ref bs) => {
        let mut trees: Vec<(f32, &Box<Octree<V>>)> = Vec::new();
        let ref l = bs.low_tree;
        let ref h = bs.high_tree;
        for &t in [l, h].iter() {
          (**t).bounds.toi_with_ray(ray, true).map(|toi| trees.push((toi, t)));
        }
        trees.sort_by(|&(t1, _), &(t2, _)| {
          if t1 < t2 {
            Less
          } else if t1 > t2 {
            Greater
          } else {
            Equal
          }
        });
        for &(_, t) in trees.iter() {
          let r = t.cast_ray(ray, self_v);
          if r.is_some() {
            return r;
          }
        }
        None
      }
    }
  }
}
<|endoftext|>


<commit_before>
//! Models versions of OpenGL

use glsl::GLSL;

#[allow(non_camel_case_types)]
#[allow(missing_docs)]
#[derive(Copy)]
pub enum OpenGL {
    _2_0,
    _2_1,
    _3_0,
    _3_1,
    _3_2,
    _3_3,
    _4_0,
    _4_1,
    _4_2,
    _4_3,
    _4_4,
    _4_5
}

impl OpenGL {
    /// Gets the minor version of OpenGL.
    pub fn get_major_minor(&self) -> (isize, isize) {
        match *self {
            OpenGL::_2_0 => (2, 0),
            OpenGL::_2_1 => (2, 1),
            OpenGL::_3_0 => (3, 0),
            OpenGL::_3_1 => (3, 1),
            OpenGL::_3_2 => (3, 2),
            OpenGL::_3_3 => (3, 3),
            OpenGL::_4_0 => (4, 0),
            OpenGL::_4_1 => (4, 1),
            OpenGL::_4_2 => (4, 2),
            OpenGL::_4_3 => (4, 3),
            OpenGL::_4_4 => (4, 4),
            OpenGL::_4_5 => (4, 5)
        }
    }

    /// Gets GLSL version associated with OpenGL.
    #[allow(non_snake_case)]
    pub fn to_GLSL(&self) -> GLSL {
        match *self {
            OpenGL::_2_0 => GLSL::_1_10,
            OpenGL::_2_1 => GLSL::_1_20,
            OpenGL::_3_0 => GLSL::_1_30,
            OpenGL::_3_1 => GLSL::_1_40,
            OpenGL::_3_2 => GLSL::_1_50,
            OpenGL::_3_3 => GLSL::_3_30,
            OpenGL::_4_0 => GLSL::_4_00,
            OpenGL::_4_1 => GLSL::_4_10,
            OpenGL::_4_2 => GLSL::_4_20,
            OpenGL::_4_3 => GLSL::_4_30,
            OpenGL::_4_4 => GLSL::_4_40,
            OpenGL::_4_5 => GLSL::_4_50
        }
    }
}
<commit_msg>Add PartialEq and PartialOrd to OpenGL<commit_after>
//! Models versions of OpenGL

use glsl::GLSL;

#[allow(non_camel_case_types)]
#[allow(missing_docs)]
#[derive(Copy, PartialEq, PartialOrd)]
pub enum OpenGL {
    _2_0,
    _2_1,
    _3_0,
    _3_1,
    _3_2,
    _3_3,
    _4_0,
    _4_1,
    _4_2,
    _4_3,
    _4_4,
    _4_5
}

impl OpenGL {
    /// Gets the minor version of OpenGL.
    pub fn get_major_minor(&self) -> (isize, isize) {
        match *self {
            OpenGL::_2_0 => (2, 0),
            OpenGL::_2_1 => (2, 1),
            OpenGL::_3_0 => (3, 0),
            OpenGL::_3_1 => (3, 1),
            OpenGL::_3_2 => (3, 2),
            OpenGL::_3_3 => (3, 3),
            OpenGL::_4_0 => (4, 0),
            OpenGL::_4_1 => (4, 1),
            OpenGL::_4_2 => (4, 2),
            OpenGL::_4_3 => (4, 3),
            OpenGL::_4_4 => (4, 4),
            OpenGL::_4_5 => (4, 5)
        }
    }

    /// Gets GLSL version associated with OpenGL.
    #[allow(non_snake_case)]
    pub fn to_GLSL(&self) -> GLSL {
        match *self {
            OpenGL::_2_0 => GLSL::_1_10,
            OpenGL::_2_1 => GLSL::_1_20,
            OpenGL::_3_0 => GLSL::_1_30,
            OpenGL::_3_1 => GLSL::_1_40,
            OpenGL::_3_2 => GLSL::_1_50,
            OpenGL::_3_3 => GLSL::_3_30,
            OpenGL::_4_0 => GLSL::_4_00,
            OpenGL::_4_1 => GLSL::_4_10,
            OpenGL::_4_2 => GLSL::_4_20,
            OpenGL::_4_3 => GLSL::_4_30,
            OpenGL::_4_4 => GLSL::_4_40,
            OpenGL::_4_5 => GLSL::_4_50
        }
    }
}
<|endoftext|>