<commit_before>// Copyright (C) 2016 Chris Liebert

extern crate libc;

use std::ffi::CStr;
use std::fs::File;
use std::io::Error;
use std::io::prelude::*;
use std::num::ParseIntError;

use glium;
use glium::backend::glutin_backend::GlutinFacade;
use glium::Program;

#[cfg(feature = "sqlite")]
use glium::Version;

#[cfg(feature = "sqlite")]
use dbloader::{DBLoader, DBLoaderError};

/// A representation for a GPU program
///
/// Shader programs contain the source for a vertex and fragment shader
/// in addition to a name
///
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Shader {
    pub name: String,
    pub vertex_source: String,
    pub fragment_source: String,
}

#[derive(Debug)]
pub enum ShaderError {
    IoError(Error),
    ProgramChooserCreationError(glium::program::ProgramChooserCreationError),
    ProgramCreationError(glium::ProgramCreationError),
    InvalidGLSLVersionStringError(ParseIntError),
    UnsupportedGLSLVersionError(Error),
}

impl Shader {
    /// Create a default shader with hardcoded source
    ///
    pub fn default(display: &GlutinFacade) -> Result<glium::program::Program, ShaderError> {
        Shader::from_source(r#"
#version 110

// Input data
vec3 position;
vec3 normal;
vec2 texcoord;

// Uniforms
uniform mat4 projection;
uniform mat4 modelview;
uniform mat4 model;
uniform vec3 light_position_worldspace;

// Output data
vec3 out_position;
vec3 out_normal;
vec2 out_texcoord;
vec3 camera_direction;
vec3 light_direction;
vec3 light_position;

 void main() {
	mat4 mvp = projection * modelview * model;
	out_position = (mvp * vec4(position, 1.0)).xyz;
	camera_direction = normalize(vec3(0, 0, 0) - out_position);
	light_direction = vec3(0,-1, 0);
	light_position = light_position_worldspace;
	gl_Position = mvp * vec4(position, 1.0);
	out_normal = ( mvp * vec4(normal, 0)).xyz;
	out_texcoord = texcoord;
 }
     "#, r#"
#version 110

// Interpolated values from the vertex shaders
vec3 out_position;
vec3 out_normal;
vec2 out_texcoord;
vec3 camera_direction;
vec3 light_direction;

// Ouput data
vec3 color;

// Values that stay constant for the whole mesh.
uniform sampler2D diffuse_texture;

uniform vec3 ambient;
uniform vec3 diffuse;
uniform vec3 specular;
uniform vec3 light_position;

void main(){
	vec3 light_color = vec3(1,1,1);
	float light_power = 3.8;

	// Material properties
	vec4 diffuseColor4 = vec4(0.3, 0.3, 0.3, 1.0) * ( vec4(diffuse, 1.0) + texture2D(diffuse_texture, out_texcoord));
	vec3 diffuseColor =  vec3( diffuseColor4[0], diffuseColor4[1], diffuseColor4[2]);

	vec3 ambientColor = ambient + vec3(0.3, 0.3, 0.3) * diffuseColor;
	vec3 specularColor = specular;

	// Distance to the light
	float distance = length(light_position - out_position);
	// Normal of the computed fragment, in camera space
	vec3 n = normalize(out_normal);
	// Direction of the light (from the fragment to the light)
	vec3 l = normalize(light_direction);
	float cosTheta = clamp(dot(n, l), 0.0, 1.0);
	vec3 E = normalize(camera_direction);
	vec3 R = reflect(-l, n);
	float cosAlpha = clamp(dot(E, R), 0.0, 1.0);

	color =
		// Ambient : simulates indirect lighting
		ambientColor +
		// Diffuse : "color" of the object
		diffuseColor * light_color * light_power * cosTheta / (distance * distance) +
		// Specular : reflective highlight, like a mirror
		specularColor * light_color * light_power * pow(cosAlpha, 5.0) / (distance * distance);
}
"#,
		&display)
    }

    /// Create a `glium::program::Program` object from a `DBLoader` that contains the shader and shader_version tables in SQLite
    ///
	#[cfg(feature = "sqlite")]
    #[allow(unused_assignments)]
    pub fn from_dbloader(shader_name: &str, dbloader: &DBLoader, display: &GlutinFacade) -> Result<glium::program::Program, ShaderError> {
        use std::io::ErrorKind;
        use glium::Version;
        let supported_glsl_version: Version = display.get_supported_glsl_version();
        let api: glium::Api = supported_glsl_version.0;
        let major_version : u8 = supported_glsl_version.1;
        let minor_version : u8 = supported_glsl_version.2;
        let mut glsl_version_string: String = major_version.to_string();
        glsl_version_string.push_str(&minor_version.to_string());
        glsl_version_string.push('0');
        let mut use_gles: bool = false;// Use OpenGLES instead of OpenGL (for mobile devices)

        match api {
                glium::Api::Gl => {
                    use_gles = false;
                },
                glium::Api::GlEs => {
                    use_gles = true;
                    glsl_version_string.push_str(" es");
                },
        };

        let glsl_version_number: u32 = match glsl_version_string.parse() {
            Ok(s) => s,
            Err(e) => return Err(ShaderError::InvalidGLSLVersionStringError(e)),
        };

        println!("Using glsl version {}", &glsl_version_string);

        let shader: Shader = match dbloader.load_shader(shader_name, &glsl_version_string) {
            Ok(s) => s,
            Err(DBLoaderError::DBError(e)) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
            Err(e) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
        };

        let program: Program = match use_gles {
            true => try!(
                program!(display,
                    glsl_version_number es => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
            false => try!(
                program!(display,
                    glsl_version_number => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
        };

        // Shader compilation no longer required
        display.release_shader_compiler();
        return Ok(program);
    }

    /// Create a `glium::program::Program` object from a `DBLoader` that has a specific shader version
    ///
	#[cfg(feature = "sqlite")]
    pub fn from_dbloader_with_version(shader_name: &str, dbloader: &DBLoader, glsl_version: &Version, display: &GlutinFacade) -> Result<glium::program::Program, ShaderError> {
        use std::io::ErrorKind;
        if !display.is_glsl_version_supported(&glsl_version) {
            return Err(ShaderError::UnsupportedGLSLVersionError(Error::new(ErrorKind::InvalidData, "Unsupported GLSL version")));
        }

        let api: glium::Api = glsl_version.0;
        let major_version : u8 = glsl_version.1;
        let minor_version : u8 = glsl_version.2;
        let mut glsl_version_string: String = major_version.to_string();
        glsl_version_string.push_str(&minor_version.to_string());
        glsl_version_string.push('0');
        let mut _use_gles: bool = false;// Use OpenGLES instead of OpenGL (for mobile devices)

        match api {
            glium::Api::Gl => {
                _use_gles = false;
            },
            glium::Api::GlEs => {
                _use_gles = true;
                glsl_version_string.push_str(" es");
            },
        };

        let glsl_version_number: u32 = match glsl_version_string.parse() {
            Ok(s) => s,
            Err(e) =>  {
                // This is not likely to happen
                panic!("Unable to parse supported glsl version string: {}", e);
            },
        };

        println!("Using glsl version {}", &glsl_version_string);

        let shader: Shader = match dbloader.load_shader(shader_name, &glsl_version_string) {
            Ok(s) => s,
            Err(DBLoaderError::DBError(e)) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
            Err(e) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
        };

        Ok(match _use_gles {
            true => try!(
                program!(display,
                    glsl_version_number es => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
            false => try!(
                program!(display,
                    glsl_version_number => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
        })
    }

    /// Create a `glium::program::Program` object from vertex and fragment file sources
    ///
    pub fn from_file(vertex: &str, fragment: &str, display: &GlutinFacade) -> Result<Program, ShaderError> {
        let mut vf = try!(
        	File::open(vertex).map_err(ShaderError::IoError)
        );
        let mut vertex_source = String::new();
        try!(
        	vf.read_to_string(&mut vertex_source).map_err(ShaderError::IoError)
        );
        let mut ff = try!(
        	File::open(fragment).map_err(ShaderError::IoError)
        );
        let mut fragment_source = String::new();
        try!(
        	ff.read_to_string(&mut fragment_source).map_err(ShaderError::IoError)
        );
        let program = try!(
            Program::from_source(display, &vertex_source, &fragment_source, None)
                .map_err(ShaderError::ProgramCreationError)
        );
        Ok(program)
    }

    /// Create a `glium::program::Program` object from vertex and fragment sources
    ///
    pub fn from_source(vertex_source: &str, fragment_source: &str, display: &GlutinFacade) -> Result<Program, ShaderError> {
        let program = try!(
            Program::from_source(display, &vertex_source, &fragment_source, None)
                .map_err(ShaderError::ProgramCreationError)
        );
        Ok(program)
    }
}

/// `extern Shader shader_default(Display display);`
///
#[no_mangle]
pub extern "C" fn shader_default(display: &GlutinFacade)
                                        -> Box<glium::program::Program> {
    match Shader::default(display) {
        Ok(s) => Box::new(s),
        Err(e) => panic!("Unable to load default shader: {:?}", e),
    }
}

/// `extern void free_shader(Shader shader);`
///
#[no_mangle]
pub extern "C" fn free_shader(ptr: *mut glium::program::Program) {
    let box_ptr: Box<glium::program::Program> = unsafe { Box::from_raw(ptr) };
    drop(box_ptr)
}

/// `extern Shader get_shader_from_db_loader(const char* name, DBLoader dbloader, Renderer renderer, Display display);`
///
#[cfg(feature = "sqlite")]
#[no_mangle]
pub extern "C" fn get_shader_from_dbloader(shader_name_cstr: *const libc::c_char,
                                            dbloader: &DBLoader,
                                            display: &GlutinFacade)
                                            -> Box<glium::program::Program> {
    unsafe {
        let shader_name: String = CStr::from_ptr(shader_name_cstr).to_string_lossy().into_owned();
        let shader_program = Shader::from_dbloader(&shader_name, dbloader, display).unwrap();
        return Box::new(shader_program);
    }
}

/// `extern Shader get_shader_from_db_loader(const char* name, DBLoader dbloader, Renderer renderer, Display display);`
///
#[cfg(not(feature = "sqlite"))]
#[no_mangle]
pub extern "C" fn get_shader_from_dbloader(_shader_name_cstr: *const libc::c_char,
                                            _dbloader: *const libc::c_void,
                                            _display: &GlutinFacade)
                                            -> Box<glium::program::Program> {
    panic!("The SQLite feature is not enabled");
}

/// `extern Shader get_shader_from_source(const char* vertex, const char* fragment, Display display);`
///
#[no_mangle]
pub extern "C" fn get_shader_from_source(vertex_cstr: *const libc::c_char,
                                         fragment_cstr: *const libc::c_char,
                                         display: &GlutinFacade) -> Box<glium::program::Program> {
    unsafe {
        let vertex: String = CStr::from_ptr(vertex_cstr).to_string_lossy().into_owned();
        let fragment: String = CStr::from_ptr(fragment_cstr).to_string_lossy().into_owned();
        let shader_program = match Shader::from_source(&vertex, &fragment, display) {
	        Ok(s) => s,
	        Err(e) => panic!("Unable to create shader program: {:?}", e),
        };
        return Box::new(shader_program);
    }
}

/// `extern Shader is_shader_source_valid(const char* vertex, const char* fragment, Display display);`
///
#[no_mangle]
pub extern "C" fn shader_source_is_valid(vertex_cstr: *const libc::c_char,
                                         fragment_cstr: *const libc::c_char,
                                         display: &GlutinFacade) -> bool {
    unsafe {
        let vertex: String = CStr::from_ptr(vertex_cstr).to_string_lossy().into_owned();
        let fragment: String = CStr::from_ptr(fragment_cstr).to_string_lossy().into_owned();
        match Shader::from_source(&vertex, &fragment, display) {
	        Ok(s) =>  {
	            drop(s);
	            true
	        },
	        Err(_e) => {
	        	false
	        },
        }
    }
}<commit_msg>changed default shader to version 130, removed call to release_shader_compiler in shader.rs.<commit_after>// Copyright (C) 2016 Chris Liebert

extern crate libc;

use std::ffi::CStr;
use std::fs::File;
use std::io::Error;
use std::io::prelude::*;
use std::num::ParseIntError;

use glium;
use glium::backend::glutin_backend::GlutinFacade;
use glium::Program;

#[cfg(feature = "sqlite")]
use glium::Version;

#[cfg(feature = "sqlite")]
use dbloader::{DBLoader, DBLoaderError};

/// A representation for a GPU program
///
/// Shader programs contain the source for a vertex and fragment shader
/// in addition to a name
///
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Shader {
    pub name: String,
    pub vertex_source: String,
    pub fragment_source: String,
}

#[derive(Debug)]
pub enum ShaderError {
    IoError(Error),
    ProgramChooserCreationError(glium::program::ProgramChooserCreationError),
    ProgramCreationError(glium::ProgramCreationError),
    InvalidGLSLVersionStringError(ParseIntError),
    UnsupportedGLSLVersionError(Error),
}

impl Shader {
    /// Create a default shader with hardcoded source
    ///
    pub fn default(display: &GlutinFacade) -> Result<glium::program::Program, ShaderError> {
        Shader::from_source(r#"
#version 130

 // Input data
 in vec3 position;
 in vec3 normal;
 in vec2 texcoord;

// Uniforms
uniform mat4 projection;
uniform mat4 modelview;
uniform mat4 model;
uniform vec3 light_position_worldspace;

// Output data
out vec3 out_position;
out vec3 out_normal;
out vec2 out_texcoord;
out vec3 camera_direction;
out vec3 light_direction;
out vec3 light_position;

 void main() {
	mat4 mvp = projection * modelview * model;
	out_position = (mvp * vec4(position, 1.0)).xyz;
	camera_direction = normalize(vec3(0, 0, 0) - out_position);
	light_direction = vec3(0,-1, 0);
	light_position = light_position_worldspace;
	gl_Position = mvp * vec4(position, 1.0);
	out_normal = ( mvp * vec4(normal, 0)).xyz;
	out_texcoord = texcoord;
 }
     "#, r#"
#version 130
precision mediump float;

// Interpolated values from the vertex shaders
in vec3 out_position;
in vec3 out_normal;
in vec2 out_texcoord;
in vec3 camera_direction;
in vec3 light_direction;

// Ouput data
out vec3 color;

// Values that stay constant for the whole mesh.
uniform sampler2D diffuse_texture;
uniform vec3 ambient;
uniform vec3 diffuse;
uniform vec3 specular;
uniform vec3 light_position;

void main(){
	vec3 light_color = vec3(1,1,1);
	float light_power = 3.8f;

	// Material properties
	vec3 diffuseColor = vec3(0.3, 0.3, 0.3) * ( diffuse + texture(diffuse_texture, out_texcoord).rgb );

	vec3 ambientColor = ambient + vec3(0.3, 0.3, 0.3) * diffuseColor;
	vec3 specularColor = specular;

	// Distance to the light
	float distance = length(light_position - out_position);
	// Normal of the computed fragment, in camera space
	vec3 n = normalize(out_normal);
	// Direction of the light (from the fragment to the light)
	vec3 l = normalize(light_direction);
	float cosTheta = clamp(dot(n, l), 0.0, 1.0);
	vec3 E = normalize(camera_direction);
	vec3 R = reflect(-l, n);
	float cosAlpha = clamp(dot(E, R), 0.0, 1.0);

	color =
		// Ambient : simulates indirect lighting
		ambientColor +
		// Diffuse : "color" of the object
		diffuseColor * light_color * light_power * cosTheta / (distance * distance) +
		// Specular : reflective highlight, like a mirror
		specularColor * light_color * light_power * pow(cosAlpha, 5.0) / (distance * distance);
}
"#,
		&display)
    }

    /// Create a `glium::program::Program` object from a `DBLoader` that contains the shader and shader_version tables in SQLite
    ///
	#[cfg(feature = "sqlite")]
    #[allow(unused_assignments)]
    pub fn from_dbloader(shader_name: &str, dbloader: &DBLoader, display: &GlutinFacade) -> Result<glium::program::Program, ShaderError> {
        use std::io::ErrorKind;
        use glium::Version;
        let supported_glsl_version: Version = display.get_supported_glsl_version();
        let api: glium::Api = supported_glsl_version.0;
        let major_version : u8 = supported_glsl_version.1;
        let minor_version : u8 = supported_glsl_version.2;
        let mut glsl_version_string: String = major_version.to_string();
        glsl_version_string.push_str(&minor_version.to_string());
        glsl_version_string.push('0');
        let mut use_gles: bool = false;// Use OpenGLES instead of OpenGL (for mobile devices)

        match api {
                glium::Api::Gl => {
                    use_gles = false;
                },
                glium::Api::GlEs => {
                    use_gles = true;
                    glsl_version_string.push_str(" es");
                },
        };

        let glsl_version_number: u32 = match glsl_version_string.parse() {
            Ok(s) => s,
            Err(e) => return Err(ShaderError::InvalidGLSLVersionStringError(e)),
        };

        println!("Using glsl version {}", &glsl_version_string);

        let shader: Shader = match dbloader.load_shader(shader_name, &glsl_version_string) {
            Ok(s) => s,
            Err(DBLoaderError::DBError(e)) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
            Err(e) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
        };

        let program: Program = match use_gles {
            true => try!(
                program!(display,
                    glsl_version_number es => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
            false => try!(
                program!(display,
                    glsl_version_number => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
        };

        return Ok(program);
    }

    /// Create a `glium::program::Program` object from a `DBLoader` that has a specific shader version
    ///
	#[cfg(feature = "sqlite")]
    pub fn from_dbloader_with_version(shader_name: &str, dbloader: &DBLoader, glsl_version: &Version, display: &GlutinFacade) -> Result<glium::program::Program, ShaderError> {
        use std::io::ErrorKind;
        if !display.is_glsl_version_supported(&glsl_version) {
            return Err(ShaderError::UnsupportedGLSLVersionError(Error::new(ErrorKind::InvalidData, "Unsupported GLSL version")));
        }

        let api: glium::Api = glsl_version.0;
        let major_version : u8 = glsl_version.1;
        let minor_version : u8 = glsl_version.2;
        let mut glsl_version_string: String = major_version.to_string();
        glsl_version_string.push_str(&minor_version.to_string());
        glsl_version_string.push('0');
        let mut _use_gles: bool = false;// Use OpenGLES instead of OpenGL (for mobile devices)

        match api {
            glium::Api::Gl => {
                _use_gles = false;
            },
            glium::Api::GlEs => {
                _use_gles = true;
                glsl_version_string.push_str(" es");
            },
        };

        let glsl_version_number: u32 = match glsl_version_string.parse() {
            Ok(s) => s,
            Err(e) =>  {
                // This is not likely to happen
                panic!("Unable to parse supported glsl version string: {}", e);
            },
        };

        println!("Using glsl version {}", &glsl_version_string);

        let shader: Shader = match dbloader.load_shader(shader_name, &glsl_version_string) {
            Ok(s) => s,
            Err(DBLoaderError::DBError(e)) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
            Err(e) => {
                let description = format!("{:?}", e);
                return Err(ShaderError::IoError(Error::new(ErrorKind::InvalidData, description)));
            },
        };

        Ok(match _use_gles {
            true => try!(
                program!(display,
                    glsl_version_number es => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
            false => try!(
                program!(display,
                    glsl_version_number => {
                        vertex: &shader.vertex_source,
                        fragment: &shader.fragment_source,
                    }
                ).map_err(ShaderError::ProgramChooserCreationError)
            ),
        })
    }

    /// Create a `glium::program::Program` object from vertex and fragment file sources
    ///
    pub fn from_file(vertex: &str, fragment: &str, display: &GlutinFacade) -> Result<Program, ShaderError> {
        let mut vf = try!(
        	File::open(vertex).map_err(ShaderError::IoError)
        );
        let mut vertex_source = String::new();
        try!(
        	vf.read_to_string(&mut vertex_source).map_err(ShaderError::IoError)
        );
        let mut ff = try!(
        	File::open(fragment).map_err(ShaderError::IoError)
        );
        let mut fragment_source = String::new();
        try!(
        	ff.read_to_string(&mut fragment_source).map_err(ShaderError::IoError)
        );
        let program = try!(
            Program::from_source(display, &vertex_source, &fragment_source, None)
                .map_err(ShaderError::ProgramCreationError)
        );
        Ok(program)
    }

    /// Create a `glium::program::Program` object from vertex and fragment sources
    ///
    pub fn from_source(vertex_source: &str, fragment_source: &str, display: &GlutinFacade) -> Result<Program, ShaderError> {
        let program = try!(
            Program::from_source(display, &vertex_source, &fragment_source, None)
                .map_err(ShaderError::ProgramCreationError)
        );
        Ok(program)
    }
}

/// `extern Shader shader_default(Display display);`
///
#[no_mangle]
pub extern "C" fn shader_default(display: &GlutinFacade)
                                        -> Box<glium::program::Program> {
    match Shader::default(display) {
        Ok(s) => Box::new(s),
        Err(e) => panic!("Unable to load default shader: {:?}", e),
    }
}

/// `extern void free_shader(Shader shader);`
///
#[no_mangle]
pub extern "C" fn free_shader(ptr: *mut glium::program::Program) {
    let box_ptr: Box<glium::program::Program> = unsafe { Box::from_raw(ptr) };
    drop(box_ptr)
}

/// `extern Shader get_shader_from_db_loader(const char* name, DBLoader dbloader, Renderer renderer, Display display);`
///
#[cfg(feature = "sqlite")]
#[no_mangle]
pub extern "C" fn get_shader_from_dbloader(shader_name_cstr: *const libc::c_char,
                                            dbloader: &DBLoader,
                                            display: &GlutinFacade)
                                            -> Box<glium::program::Program> {
    unsafe {
        let shader_name: String = CStr::from_ptr(shader_name_cstr).to_string_lossy().into_owned();
        let shader_program = Shader::from_dbloader(&shader_name, dbloader, display).expect("Unable to load shader from database");
        return Box::new(shader_program);
    }
}

/// `extern Shader get_shader_from_db_loader(const char* name, DBLoader dbloader, Renderer renderer, Display display);`
///
#[cfg(not(feature = "sqlite"))]
#[no_mangle]
pub extern "C" fn get_shader_from_dbloader(_shader_name_cstr: *const libc::c_char,
                                            _dbloader: *const libc::c_void,
                                            _display: &GlutinFacade)
                                            -> Box<glium::program::Program> {
    panic!("The SQLite feature is not enabled");
}

/// `extern Shader get_shader_from_source(const char* vertex, const char* fragment, Display display);`
///
#[no_mangle]
pub extern "C" fn get_shader_from_source(vertex_cstr: *const libc::c_char,
                                         fragment_cstr: *const libc::c_char,
                                         display: &GlutinFacade) -> Box<glium::program::Program> {
    unsafe {
        let vertex: String = CStr::from_ptr(vertex_cstr).to_string_lossy().into_owned();
        let fragment: String = CStr::from_ptr(fragment_cstr).to_string_lossy().into_owned();
        let shader_program = match Shader::from_source(&vertex, &fragment, display) {
	        Ok(s) => s,
	        Err(e) => panic!("Unable to create shader program: {:?}", e),
        };
        return Box::new(shader_program);
    }
}

/// `extern Shader is_shader_source_valid(const char* vertex, const char* fragment, Display display);`
///
#[no_mangle]
pub extern "C" fn shader_source_is_valid(vertex_cstr: *const libc::c_char,
                                         fragment_cstr: *const libc::c_char,
                                         display: &GlutinFacade) -> bool {
    unsafe {
        let vertex: String = CStr::from_ptr(vertex_cstr).to_string_lossy().into_owned();
        let fragment: String = CStr::from_ptr(fragment_cstr).to_string_lossy().into_owned();
        match Shader::from_source(&vertex, &fragment, display) {
	        Ok(s) =>  {
	            drop(s);
	            true
	        },
	        Err(_e) => {
	        	false
	        },
        }
    }
}<|endoftext|>


<commit_before>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 } $( else if $m1 { $h1 } )*
    }}
}

pub fn get(request: Request, mut response: Response) {
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request, response),
            path == "/ip" => origin(&request, response),
            path.starts_with("/status/") => status(path, response),
            path.starts_with("/test") => test(&request, response),
        ];
    }
}

fn index(request: &Request, mut response: Response) {
    let index = "<!DOCTYPE html>

            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ";

    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(index.len() as u64));
    response.start().unwrap().write(index.as_bytes()).unwrap();
}

fn status(path: &str, mut response: Response) {
    // /status/xx
    // 0123456789
    let (_, param) = path.split_at(8);
    println!("Status {:?}", param);
    let code = match param.parse::<u16>() {
        Ok(status) => StatusCode::from_u16(status),
        Err(_) => StatusCode::BadRequest,
    };
    *response.status_mut() = code;
}

fn origin(request: &Request, mut response: Response) {
    let text = "Remote address decoding is not implemented yet";
    response.headers_mut().set(ContentType::plaintext());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}

fn test(request: &Request, mut response: Response) {
    let text = format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
                       request.remote_addr,
                       request.method,
                       request.version,
                       request.headers,
                       request.uri);
    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}
<commit_msg>Drop debug println!()<commit_after>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 } $( else if $m1 { $h1 } )*
    }}
}

pub fn get(request: Request, mut response: Response) {
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request, response),
            path == "/ip" => origin(&request, response),
            path.starts_with("/status/") => status(path, response),
            path.starts_with("/test") => test(&request, response),
        ];
    }
}

fn index(request: &Request, mut response: Response) {
    let index = "<!DOCTYPE html>

            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ";

    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(index.len() as u64));
    response.start().unwrap().write(index.as_bytes()).unwrap();
}

fn status(path: &str, mut response: Response) {
    // /status/xx
    // 0123456789
    let (_, param) = path.split_at(8);
    let code = match param.parse::<u16>() {
        Ok(status) => StatusCode::from_u16(status),
        Err(_) => StatusCode::BadRequest,
    };
    *response.status_mut() = code;
}

fn origin(request: &Request, mut response: Response) {
    let text = "Remote address decoding is not implemented yet";
    response.headers_mut().set(ContentType::plaintext());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}

fn test(request: &Request, mut response: Response) {
    let text = format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
                       request.remote_addr,
                       request.method,
                       request.version,
                       request.headers,
                       request.uri);
    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}
<|endoftext|>


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

#![allow(non_snake_case)]

register_long_diagnostics! {

E0373: r##"
This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
return a closure:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(|y| x + y)
}
```

Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
closed-over data by reference. This means that once `foo()` returns, `x` no
longer exists. An attempt to access `x` within the closure would thus be unsafe.

Another situation where this might be encountered is when spawning threads:

```
fn foo() {
    let x = 0u32;
    let y = 1u32;

    let thr = std::thread::spawn(|| {
        x + y
    });
}
```

Since our new thread runs in parallel, the stack frame containing `x` and `y`
may well have disappeared by the time we try to use them. Even if we call
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
stack frame won't disappear), we will not succeed: the compiler cannot prove
that this behaviour is safe, and so won't let us do it.

The solution to this problem is usually to switch to using a `move` closure.
This approach moves (or copies, where possible) data into the closure, rather
than taking references to it. For example:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(move |y| x + y)
}
```

Now that the closure has its own copy of the data, there's no need to worry
about safety.
"##,

E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:

```
fn main() {
    let x: i32;
    let y = x; // error, use of possibly uninitialized variable
```

To fix this, ensure that any declared variables are initialized before being
used.
"##

}

register_diagnostics! {
    E0382, // use of partially/collaterally moved value
    E0383, // partial reinitialization of uninitialized structure
    E0384, // reassignment of immutable variable
    E0385, // {} in an aliasable location
    E0386, // {} in an immutable container
    E0387, // {} in a captured outer variable in an `Fn` closure
    E0388, // {} in a static location
    E0389  // {} in a `&` reference
}
<commit_msg>Auto merge of #27475 - AgostonSzepessy:master, r=alexcrichton<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

register_long_diagnostics! {

E0373: r##"
This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
return a closure:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(|y| x + y)
}
```

Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
closed-over data by reference. This means that once `foo()` returns, `x` no
longer exists. An attempt to access `x` within the closure would thus be unsafe.

Another situation where this might be encountered is when spawning threads:

```
fn foo() {
    let x = 0u32;
    let y = 1u32;

    let thr = std::thread::spawn(|| {
        x + y
    });
}
```

Since our new thread runs in parallel, the stack frame containing `x` and `y`
may well have disappeared by the time we try to use them. Even if we call
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
stack frame won't disappear), we will not succeed: the compiler cannot prove
that this behaviour is safe, and so won't let us do it.

The solution to this problem is usually to switch to using a `move` closure.
This approach moves (or copies, where possible) data into the closure, rather
than taking references to it. For example:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(move |y| x + y)
}
```

Now that the closure has its own copy of the data, there's no need to worry
about safety.
"##,

E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:

```
fn main() {
    let x: i32;
    let y = x; // error, use of possibly uninitialized variable
```

To fix this, ensure that any declared variables are initialized before being
used.
"##,

E0384: r##"
This error occurs when an attempt is made to reassign an immutable variable.
For example:

```
fn main(){
    let x = 3;
    x = 5; // error, reassignment of immutable variable
}
```

By default, variables in Rust are immutable. To fix this error, add the keyword
`mut` after the keyword `let` when declaring the variable. For example:

```
fn main(){
    let mut x = 3;
    x = 5;
}
```
"##

}

register_diagnostics! {
    E0382, // use of partially/collaterally moved value
    E0383, // partial reinitialization of uninitialized structure
    E0385, // {} in an aliasable location
    E0386, // {} in an immutable container
    E0387, // {} in a captured outer variable in an `Fn` closure
    E0388, // {} in a static location
    E0389  // {} in a `&` reference
}
<|endoftext|>


<commit_before>use std::io;
use std::io::{Read, Write};
use std::marker::PhantomData;
use std::mem;
use std::sync::atomic;

use kernel32;
use winapi;

use consts::{self, KeyPress};
use ::error;
use ::Result;

pub type Handle = winapi::HANDLE;
pub type Mode = winapi::DWORD;
pub const STDIN_FILENO: winapi::DWORD = winapi::STD_INPUT_HANDLE;
pub const STDOUT_FILENO: winapi::DWORD = winapi::STD_OUTPUT_HANDLE;

fn get_std_handle(fd: winapi::DWORD) -> Result<winapi::HANDLE> {
    let handle = unsafe { kernel32::GetStdHandle(fd) };
    if handle == winapi::INVALID_HANDLE_VALUE {
        try!(Err(io::Error::last_os_error()));
    } else if handle.is_null() {
        try!(Err(io::Error::new(io::ErrorKind::Other,
                                "no stdio handle available for this process")));
    }
    Ok(handle)
}

#[macro_export]
macro_rules! check {
    ($funcall:expr) => {
        {
        let rc = unsafe { $funcall };
        if rc == 0 {
            try!(Err(io::Error::last_os_error()));
        }
        rc
        }
    };
}

/// Try to get the number of columns in the current terminal,
/// or assume 80 if it fails.
pub fn get_columns(handle: Handle) -> usize {
    let (cols, _) = get_win_size(handle);
    cols
}

/// Try to get the number of rows in the current terminal,
/// or assume 24 if it fails.
pub fn get_rows(handle: Handle) -> usize {
    let (_, rows) = get_win_size(handle);
    rows
}

fn get_win_size(handle: Handle) -> (usize, usize) {
    let mut info = unsafe { mem::zeroed() };
    match unsafe { kernel32::GetConsoleScreenBufferInfo(handle, &mut info) } {
        0 => (80, 24),
        _ => (info.dwSize.X as usize, 1 + info.srWindow.Bottom - info.srWindow.Top),
    }
}

/// Checking for an unsupported TERM in windows is a no-op
pub fn is_unsupported_term() -> bool {
    false
}

fn get_console_mode(handle: winapi::HANDLE) -> Result<Mode> {
    let mut original_mode = 0;
    check!(kernel32::GetConsoleMode(handle, &mut original_mode));
    Ok(original_mode)
}

/// Return whether or not STDIN, STDOUT or STDERR is a TTY
pub fn is_a_tty(fd: winapi::DWORD) -> bool {
    let handle = get_std_handle(fd);
    match handle {
        Ok(handle) => {
            // If this function doesn't fail then fd is a TTY
            get_console_mode(handle).is_ok()
        }
        Err(_) => false,
    }
}

/// Enable raw mode for the TERM
pub fn enable_raw_mode() -> Result<Mode> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    let original_mode = try!(get_console_mode(handle));
    // Disable these modes
    let raw = original_mode &
              !(winapi::wincon::ENABLE_LINE_INPUT | winapi::wincon::ENABLE_ECHO_INPUT |
                winapi::wincon::ENABLE_PROCESSED_INPUT);
    // Enable these modes
    let raw = raw | winapi::wincon::ENABLE_EXTENDED_FLAGS;
    let raw = raw | winapi::wincon::ENABLE_INSERT_MODE;
    let raw = raw | winapi::wincon::ENABLE_QUICK_EDIT_MODE;
    let raw = raw | winapi::wincon::ENABLE_WINDOW_INPUT;
    check!(kernel32::SetConsoleMode(handle, raw));
    Ok(original_mode)
}

/// Disable Raw mode for the term
pub fn disable_raw_mode(original_mode: Mode) -> Result<()> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    check!(kernel32::SetConsoleMode(handle, original_mode));
    Ok(())
}

pub fn stdout_handle() -> Result<Handle> {
    let handle = try!(get_std_handle(STDOUT_FILENO));
    Ok(handle)
}

/// Clear the screen. Used to handle ctrl+l
pub fn clear_screen(_: &mut Write, handle: Handle) -> Result<()> {
    let mut info = unsafe { mem::zeroed() };
    check!(kernel32::GetConsoleScreenBufferInfo(handle, &mut info));
    let coord = winapi::COORD { X: 0, Y: 0 };
    check!(kernel32::SetConsoleCursorPosition(handle, coord));
    let mut _count = 0;
    let n = info.dwSize.X as winapi::DWORD * info.dwSize.Y as winapi::DWORD;
    check!(kernel32::FillConsoleOutputCharacterA(handle,
                                                 ' ' as winapi::CHAR,
                                                 n,
                                                 coord,
                                                 &mut _count));
    Ok(())
}

/// Console input reader
pub struct RawReader<R> {
    handle: winapi::HANDLE,
    buf: Option<u16>,
    phantom: PhantomData<R>,
}

impl<R: Read> RawReader<R> {
    pub fn new(_: R) -> Result<RawReader<R>> {
        let handle = try!(get_std_handle(STDIN_FILENO));
        Ok(RawReader {
            handle: handle,
            buf: None,
            phantom: PhantomData,
        })
    }

    pub fn next_key(&mut self, _: bool) -> Result<KeyPress> {
        use std::char::decode_utf16;
        // use winapi::{LEFT_ALT_PRESSED, LEFT_CTRL_PRESSED, RIGHT_ALT_PRESSED, RIGHT_CTRL_PRESSED};
        use winapi::{LEFT_ALT_PRESSED, RIGHT_ALT_PRESSED};

        let mut rec: winapi::INPUT_RECORD = unsafe { mem::zeroed() };
        let mut count = 0;
        let mut esc_seen = false;
        loop {
            // TODO GetNumberOfConsoleInputEvents
            check!(kernel32::ReadConsoleInputW(self.handle,
                                               &mut rec,
                                               1 as winapi::DWORD,
                                               &mut count));

            if rec.EventType == winapi::WINDOW_BUFFER_SIZE_EVENT {
                SIGWINCH.store(true, atomic::Ordering::SeqCst);
                return Err(error::ReadlineError::WindowResize);
            } else if rec.EventType != winapi::KEY_EVENT {
                continue;
            }
            let key_event = unsafe { rec.KeyEvent() };
            // writeln!(io::stderr(), "key_event: {:?}", key_event).unwrap();
            if key_event.bKeyDown == 0 &&
               key_event.wVirtualKeyCode != winapi::VK_MENU as winapi::WORD {
                continue;
            }

            // let alt_gr = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED) ==
            // (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED);
            let alt = key_event.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) ==
                      (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED);
            // let ctrl = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) ==
            // (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED);
            let meta = alt || esc_seen;

            let utf16 = key_event.UnicodeChar;
            if utf16 == 0 {
                match key_event.wVirtualKeyCode as i32 {
                    winapi::VK_LEFT => return Ok(KeyPress::Left),
                    winapi::VK_RIGHT => return Ok(KeyPress::Right),
                    winapi::VK_UP => return Ok(KeyPress::Up),
                    winapi::VK_DOWN => return Ok(KeyPress::Down),
                    winapi::VK_DELETE => return Ok(KeyPress::Delete),
                    winapi::VK_HOME => return Ok(KeyPress::Home),
                    winapi::VK_END => return Ok(KeyPress::End),
                    _ => continue,
                };
            } else if utf16 == 27 {
                esc_seen = true;
                continue;
            } else {
                // TODO How to support surrogate pair ?
                self.buf = Some(utf16);
                let orc = decode_utf16(self).next();
                if orc.is_none() {
                    return Err(error::ReadlineError::Eof);
                }
                let c = try!(orc.unwrap());
                if meta {
                    match c {
                        'b' | 'B' => return Ok(KeyPress::Meta('B')),
                        'c' | 'C' => return Ok(KeyPress::Meta('C')),
                        'd' | 'D' => return Ok(KeyPress::Meta('D')),
                        'f' | 'F' => return Ok(KeyPress::Meta('F')),
                        'l' | 'L' => return Ok(KeyPress::Meta('L')),
                        't' | 'T' => return Ok(KeyPress::Meta('T')),
                        'u' | 'U' => return Ok(KeyPress::Meta('U')),
                        'y' | 'Y' => return Ok(KeyPress::Meta('Y')),
                        _ => return Ok(KeyPress::UnknownEscSeq),
                    }
                } else {
                    return Ok(consts::char_to_key_press(c));
                }
            }
        }
    }
}

impl<R: Read> Iterator for RawReader<R> {
    type Item = u16;

    fn next(&mut self) -> Option<u16> {
        let buf = self.buf;
        self.buf = None;
        buf
    }
}

pub static SIGWINCH: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;

pub fn install_sigwinch_handler() {
    // See ReadConsoleInputW && WINDOW_BUFFER_SIZE_EVENT
}
<commit_msg>Fix windows part<commit_after>use std::io;
use std::io::{Read, Write};
use std::marker::PhantomData;
use std::mem;
use std::sync::atomic;

use kernel32;
use winapi;

use consts::{self, KeyPress};
use ::error;
use ::Result;

pub type Handle = winapi::HANDLE;
pub type Mode = winapi::DWORD;
pub const STDIN_FILENO: winapi::DWORD = winapi::STD_INPUT_HANDLE;
pub const STDOUT_FILENO: winapi::DWORD = winapi::STD_OUTPUT_HANDLE;

fn get_std_handle(fd: winapi::DWORD) -> Result<winapi::HANDLE> {
    let handle = unsafe { kernel32::GetStdHandle(fd) };
    if handle == winapi::INVALID_HANDLE_VALUE {
        try!(Err(io::Error::last_os_error()));
    } else if handle.is_null() {
        try!(Err(io::Error::new(io::ErrorKind::Other,
                                "no stdio handle available for this process")));
    }
    Ok(handle)
}

#[macro_export]
macro_rules! check {
    ($funcall:expr) => {
        {
        let rc = unsafe { $funcall };
        if rc == 0 {
            try!(Err(io::Error::last_os_error()));
        }
        rc
        }
    };
}

/// Try to get the number of columns in the current terminal,
/// or assume 80 if it fails.
pub fn get_columns(handle: Handle) -> usize {
    let (cols, _) = get_win_size(handle);
    cols
}

/// Try to get the number of rows in the current terminal,
/// or assume 24 if it fails.
pub fn get_rows(handle: Handle) -> usize {
    let (_, rows) = get_win_size(handle);
    rows
}

fn get_win_size(handle: Handle) -> (usize, usize) {
    let mut info = unsafe { mem::zeroed() };
    match unsafe { kernel32::GetConsoleScreenBufferInfo(handle, &mut info) } {
        0 => (80, 24),
        _ => (info.dwSize.X as usize, (1 + info.srWindow.Bottom - info.srWindow.Top) as usize),
    }
}

/// Checking for an unsupported TERM in windows is a no-op
pub fn is_unsupported_term() -> bool {
    false
}

fn get_console_mode(handle: winapi::HANDLE) -> Result<Mode> {
    let mut original_mode = 0;
    check!(kernel32::GetConsoleMode(handle, &mut original_mode));
    Ok(original_mode)
}

/// Return whether or not STDIN, STDOUT or STDERR is a TTY
pub fn is_a_tty(fd: winapi::DWORD) -> bool {
    let handle = get_std_handle(fd);
    match handle {
        Ok(handle) => {
            // If this function doesn't fail then fd is a TTY
            get_console_mode(handle).is_ok()
        }
        Err(_) => false,
    }
}

/// Enable raw mode for the TERM
pub fn enable_raw_mode() -> Result<Mode> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    let original_mode = try!(get_console_mode(handle));
    // Disable these modes
    let raw = original_mode &
              !(winapi::wincon::ENABLE_LINE_INPUT | winapi::wincon::ENABLE_ECHO_INPUT |
                winapi::wincon::ENABLE_PROCESSED_INPUT);
    // Enable these modes
    let raw = raw | winapi::wincon::ENABLE_EXTENDED_FLAGS;
    let raw = raw | winapi::wincon::ENABLE_INSERT_MODE;
    let raw = raw | winapi::wincon::ENABLE_QUICK_EDIT_MODE;
    let raw = raw | winapi::wincon::ENABLE_WINDOW_INPUT;
    check!(kernel32::SetConsoleMode(handle, raw));
    Ok(original_mode)
}

/// Disable Raw mode for the term
pub fn disable_raw_mode(original_mode: Mode) -> Result<()> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    check!(kernel32::SetConsoleMode(handle, original_mode));
    Ok(())
}

pub fn stdout_handle() -> Result<Handle> {
    let handle = try!(get_std_handle(STDOUT_FILENO));
    Ok(handle)
}

/// Clear the screen. Used to handle ctrl+l
pub fn clear_screen(_: &mut Write, handle: Handle) -> Result<()> {
    let mut info = unsafe { mem::zeroed() };
    check!(kernel32::GetConsoleScreenBufferInfo(handle, &mut info));
    let coord = winapi::COORD { X: 0, Y: 0 };
    check!(kernel32::SetConsoleCursorPosition(handle, coord));
    let mut _count = 0;
    let n = info.dwSize.X as winapi::DWORD * info.dwSize.Y as winapi::DWORD;
    check!(kernel32::FillConsoleOutputCharacterA(handle,
                                                 ' ' as winapi::CHAR,
                                                 n,
                                                 coord,
                                                 &mut _count));
    Ok(())
}

/// Console input reader
pub struct RawReader<R> {
    handle: winapi::HANDLE,
    buf: Option<u16>,
    phantom: PhantomData<R>,
}

impl<R: Read> RawReader<R> {
    pub fn new(_: R) -> Result<RawReader<R>> {
        let handle = try!(get_std_handle(STDIN_FILENO));
        Ok(RawReader {
            handle: handle,
            buf: None,
            phantom: PhantomData,
        })
    }

    pub fn next_key(&mut self, _: bool) -> Result<KeyPress> {
        use std::char::decode_utf16;
        // use winapi::{LEFT_ALT_PRESSED, LEFT_CTRL_PRESSED, RIGHT_ALT_PRESSED, RIGHT_CTRL_PRESSED};
        use winapi::{LEFT_ALT_PRESSED, RIGHT_ALT_PRESSED};

        let mut rec: winapi::INPUT_RECORD = unsafe { mem::zeroed() };
        let mut count = 0;
        let mut esc_seen = false;
        loop {
            // TODO GetNumberOfConsoleInputEvents
            check!(kernel32::ReadConsoleInputW(self.handle,
                                               &mut rec,
                                               1 as winapi::DWORD,
                                               &mut count));

            if rec.EventType == winapi::WINDOW_BUFFER_SIZE_EVENT {
                SIGWINCH.store(true, atomic::Ordering::SeqCst);
                return Err(error::ReadlineError::WindowResize);
            } else if rec.EventType != winapi::KEY_EVENT {
                continue;
            }
            let key_event = unsafe { rec.KeyEvent() };
            // writeln!(io::stderr(), "key_event: {:?}", key_event).unwrap();
            if key_event.bKeyDown == 0 &&
               key_event.wVirtualKeyCode != winapi::VK_MENU as winapi::WORD {
                continue;
            }

            // let alt_gr = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED) ==
            // (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED);
            let alt = key_event.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) ==
                      (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED);
            // let ctrl = key_event.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) ==
            // (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED);
            let meta = alt || esc_seen;

            let utf16 = key_event.UnicodeChar;
            if utf16 == 0 {
                match key_event.wVirtualKeyCode as i32 {
                    winapi::VK_LEFT => return Ok(KeyPress::Left),
                    winapi::VK_RIGHT => return Ok(KeyPress::Right),
                    winapi::VK_UP => return Ok(KeyPress::Up),
                    winapi::VK_DOWN => return Ok(KeyPress::Down),
                    winapi::VK_DELETE => return Ok(KeyPress::Delete),
                    winapi::VK_HOME => return Ok(KeyPress::Home),
                    winapi::VK_END => return Ok(KeyPress::End),
                    _ => continue,
                };
            } else if utf16 == 27 {
                esc_seen = true;
                continue;
            } else {
                // TODO How to support surrogate pair ?
                self.buf = Some(utf16);
                let orc = decode_utf16(self).next();
                if orc.is_none() {
                    return Err(error::ReadlineError::Eof);
                }
                let c = try!(orc.unwrap());
                if meta {
                    match c {
                        'b' | 'B' => return Ok(KeyPress::Meta('B')),
                        'c' | 'C' => return Ok(KeyPress::Meta('C')),
                        'd' | 'D' => return Ok(KeyPress::Meta('D')),
                        'f' | 'F' => return Ok(KeyPress::Meta('F')),
                        'l' | 'L' => return Ok(KeyPress::Meta('L')),
                        't' | 'T' => return Ok(KeyPress::Meta('T')),
                        'u' | 'U' => return Ok(KeyPress::Meta('U')),
                        'y' | 'Y' => return Ok(KeyPress::Meta('Y')),
                        _ => return Ok(KeyPress::UnknownEscSeq),
                    }
                } else {
                    return Ok(consts::char_to_key_press(c));
                }
            }
        }
    }
}

impl<R: Read> Iterator for RawReader<R> {
    type Item = u16;

    fn next(&mut self) -> Option<u16> {
        let buf = self.buf;
        self.buf = None;
        buf
    }
}

pub static SIGWINCH: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;

pub fn install_sigwinch_handler() {
    // See ReadConsoleInputW && WINDOW_BUFFER_SIZE_EVENT
}
<|endoftext|>


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

//! Interactions with the file system.

use std::collections::HashMap;
use std::ffi::OsString;
use std::fmt;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use std::str;
use std::time::SystemTime;

use xi_rope::Rope;
use xi_rpc::RemoteError;

use crate::tabs::BufferId;

#[cfg(feature = "notify")]
use crate::tabs::OPEN_FILE_EVENT_TOKEN;
#[cfg(feature = "notify")]
use crate::watcher::FileWatcher;
#[cfg(target_family = "unix")]
use std::{fs::Permissions, os::unix::fs::PermissionsExt};

const UTF8_BOM: &str = "\u{feff}";

/// Tracks all state related to open files.
pub struct FileManager {
    open_files: HashMap<PathBuf, BufferId>,
    file_info: HashMap<BufferId, FileInfo>,
    /// A monitor of filesystem events, for things like reloading changed files.
    #[cfg(feature = "notify")]
    watcher: FileWatcher,
}

#[derive(Debug)]
pub struct FileInfo {
    pub encoding: CharacterEncoding,
    pub path: PathBuf,
    pub mod_time: Option<SystemTime>,
    pub has_changed: bool,
    #[cfg(target_family = "unix")]
    pub permissions: Option<u32>,
}

pub enum FileError {
    Io(io::Error, PathBuf),
    UnknownEncoding(PathBuf),
    HasChanged(PathBuf),
}

#[derive(Debug, Clone, Copy)]
pub enum CharacterEncoding {
    Utf8,
    Utf8WithBom,
}

impl FileManager {
    #[cfg(feature = "notify")]
    pub fn new(watcher: FileWatcher) -> Self {
        FileManager { open_files: HashMap::new(), file_info: HashMap::new(), watcher }
    }

    #[cfg(not(feature = "notify"))]
    pub fn new() -> Self {
        FileManager { open_files: HashMap::new(), file_info: HashMap::new() }
    }

    #[cfg(feature = "notify")]
    pub fn watcher(&mut self) -> &mut FileWatcher {
        &mut self.watcher
    }

    pub fn get_info(&self, id: BufferId) -> Option<&FileInfo> {
        self.file_info.get(&id)
    }

    pub fn get_editor(&self, path: &Path) -> Option<BufferId> {
        self.open_files.get(path).cloned()
    }

    /// Returns `true` if this file is open and has changed on disk.
    /// This state is stashed.
    pub fn check_file(&mut self, path: &Path, id: BufferId) -> bool {
        if let Some(info) = self.file_info.get_mut(&id) {
            let mod_t = get_mod_time(path);
            if mod_t != info.mod_time {
                info.has_changed = true
            }
            return info.has_changed;
        }
        false
    }

    pub fn open(&mut self, path: &Path, id: BufferId) -> Result<Rope, FileError> {
        if !path.exists() {
            let _ = File::create(path).map_err(|e| FileError::Io(e, path.to_owned()))?;
        }

        let (rope, info) = try_load_file(path)?;

        self.open_files.insert(path.to_owned(), id);
        if self.file_info.insert(id, info).is_none() {
            #[cfg(feature = "notify")]
            self.watcher.watch(path, false, OPEN_FILE_EVENT_TOKEN);
        }
        Ok(rope)
    }

    pub fn close(&mut self, id: BufferId) {
        if let Some(info) = self.file_info.remove(&id) {
            self.open_files.remove(&info.path);
            #[cfg(feature = "notify")]
            self.watcher.unwatch(&info.path, OPEN_FILE_EVENT_TOKEN);
        }
    }

    pub fn save(&mut self, path: &Path, text: &Rope, id: BufferId) -> Result<(), FileError> {
        let is_existing = self.file_info.contains_key(&id);
        if is_existing {
            self.save_existing(path, text, id)
        } else {
            self.save_new(path, text, id)
        }
    }

    fn save_new(&mut self, path: &Path, text: &Rope, id: BufferId) -> Result<(), FileError> {
        try_save(path, text, CharacterEncoding::Utf8, self.get_info(id))
            .map_err(|e| FileError::Io(e, path.to_owned()))?;
        let info = FileInfo {
            encoding: CharacterEncoding::Utf8,
            path: path.to_owned(),
            mod_time: get_mod_time(path),
            has_changed: false,
            #[cfg(target_family = "unix")]
            permissions: get_permissions(path),
        };
        self.open_files.insert(path.to_owned(), id);
        self.file_info.insert(id, info);
        #[cfg(feature = "notify")]
        self.watcher.watch(path, false, OPEN_FILE_EVENT_TOKEN);
        Ok(())
    }

    fn save_existing(&mut self, path: &Path, text: &Rope, id: BufferId) -> Result<(), FileError> {
        let prev_path = self.file_info[&id].path.clone();
        if prev_path != path {
            self.save_new(path, text, id)?;
            self.open_files.remove(&prev_path);
            #[cfg(feature = "notify")]
            self.watcher.unwatch(&prev_path, OPEN_FILE_EVENT_TOKEN);
        } else if self.file_info[&id].has_changed {
            return Err(FileError::HasChanged(path.to_owned()));
        } else {
            let encoding = self.file_info[&id].encoding;
            try_save(path, text, encoding, self.get_info(id))
                .map_err(|e| FileError::Io(e, path.to_owned()))?;
            self.file_info.get_mut(&id).unwrap().mod_time = get_mod_time(path);
        }
        Ok(())
    }
}

fn try_load_file<P>(path: P) -> Result<(Rope, FileInfo), FileError>
where
    P: AsRef<Path>,
{
    // TODO: support for non-utf8
    // it's arguable that the rope crate should have file loading functionality
    let mut f =
        File::open(path.as_ref()).map_err(|e| FileError::Io(e, path.as_ref().to_owned()))?;
    let mut bytes = Vec::new();
    f.read_to_end(&mut bytes).map_err(|e| FileError::Io(e, path.as_ref().to_owned()))?;

    let encoding = CharacterEncoding::guess(&bytes);
    let rope = try_decode(bytes, encoding, path.as_ref())?;
    let info = FileInfo {
        encoding,
        mod_time: get_mod_time(&path),
        #[cfg(target_family = "unix")]
        permissions: get_permissions(&path),
        path: path.as_ref().to_owned(),
        has_changed: false,
    };
    Ok((rope, info))
}

#[allow(unused)]
fn try_save(
    path: &Path,
    text: &Rope,
    encoding: CharacterEncoding,
    file_info: Option<&FileInfo>,
) -> io::Result<()> {
    let tmp_extension = path.extension().map_or_else(
        || OsString::from("swp"),
        |ext| {
            let mut ext = ext.to_os_string();
            ext.push(".swp");
            ext
        },
    );
    let tmp_path = &path.with_extension(tmp_extension);

    let mut f = File::create(tmp_path)?;
    match encoding {
        CharacterEncoding::Utf8WithBom => f.write_all(UTF8_BOM.as_bytes())?,
        CharacterEncoding::Utf8 => (),
    }

    for chunk in text.iter_chunks(..text.len()) {
        f.write_all(chunk.as_bytes())?;
    }

    fs::rename(tmp_path, path)?;

    #[cfg(target_family = "unix")]
    {
        if let Some(info) = file_info {
            fs::set_permissions(path, Permissions::from_mode(info.permissions.unwrap_or(0o644)))?;
        }
    }

    Ok(())
}

fn try_decode(bytes: Vec<u8>, encoding: CharacterEncoding, path: &Path) -> Result<Rope, FileError> {
    match encoding {
        CharacterEncoding::Utf8 => Ok(Rope::from(
            str::from_utf8(&bytes).map_err(|_e| FileError::UnknownEncoding(path.to_owned()))?,
        )),
        CharacterEncoding::Utf8WithBom => {
            let s = String::from_utf8(bytes)
                .map_err(|_e| FileError::UnknownEncoding(path.to_owned()))?;
            Ok(Rope::from(&s[UTF8_BOM.len()..]))
        }
    }
}

impl CharacterEncoding {
    fn guess(s: &[u8]) -> Self {
        if s.starts_with(UTF8_BOM.as_bytes()) {
            CharacterEncoding::Utf8WithBom
        } else {
            CharacterEncoding::Utf8
        }
    }
}

/// Returns the modification timestamp for the file at a given path,
/// if present.
fn get_mod_time<P: AsRef<Path>>(path: P) -> Option<SystemTime> {
    File::open(path).and_then(|f| f.metadata()).and_then(|meta| meta.modified()).ok()
}

/// Returns the file permissions for the file at a given path on UNIXy systems,
/// if present.
#[cfg(target_family = "unix")]
fn get_permissions<P: AsRef<Path>>(path: P) -> Option<u32> {
    File::open(path).and_then(|f| f.metadata()).map(|meta| meta.permissions().mode()).ok()
}

impl From<FileError> for RemoteError {
    fn from(src: FileError) -> RemoteError {
        //TODO: when we migrate to using the failure crate for error handling,
        // this should return a better message
        let code = src.error_code();
        let message = src.to_string();
        RemoteError::custom(code, message, None)
    }
}

impl FileError {
    fn error_code(&self) -> i64 {
        match self {
            FileError::Io(_, _) => 5,
            FileError::UnknownEncoding(_) => 6,
            FileError::HasChanged(_) => 7,
        }
    }
}

impl fmt::Display for FileError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            FileError::Io(ref e, ref p) => write!(f, "{}. File path: {:?}", e, p),
            FileError::UnknownEncoding(ref p) => write!(f, "Error decoding file: {:?}", p),
            FileError::HasChanged(ref p) => write!(
                f,
                "File has changed on disk. \
                 Please save elsewhere and reload the file. File path: {:?}",
                p
            ),
        }
    }
}
<commit_msg>core-lib: don't create empty file in FileManager::open<commit_after>// Copyright 2018 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Interactions with the file system.

use std::collections::HashMap;
use std::ffi::OsString;
use std::fmt;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use std::str;
use std::time::SystemTime;

use xi_rope::Rope;
use xi_rpc::RemoteError;

use crate::tabs::BufferId;

#[cfg(feature = "notify")]
use crate::tabs::OPEN_FILE_EVENT_TOKEN;
#[cfg(feature = "notify")]
use crate::watcher::FileWatcher;
#[cfg(target_family = "unix")]
use std::{fs::Permissions, os::unix::fs::PermissionsExt};

const UTF8_BOM: &str = "\u{feff}";

/// Tracks all state related to open files.
pub struct FileManager {
    open_files: HashMap<PathBuf, BufferId>,
    file_info: HashMap<BufferId, FileInfo>,
    /// A monitor of filesystem events, for things like reloading changed files.
    #[cfg(feature = "notify")]
    watcher: FileWatcher,
}

#[derive(Debug)]
pub struct FileInfo {
    pub encoding: CharacterEncoding,
    pub path: PathBuf,
    pub mod_time: Option<SystemTime>,
    pub has_changed: bool,
    #[cfg(target_family = "unix")]
    pub permissions: Option<u32>,
}

pub enum FileError {
    Io(io::Error, PathBuf),
    UnknownEncoding(PathBuf),
    HasChanged(PathBuf),
}

#[derive(Debug, Clone, Copy)]
pub enum CharacterEncoding {
    Utf8,
    Utf8WithBom,
}

impl FileManager {
    #[cfg(feature = "notify")]
    pub fn new(watcher: FileWatcher) -> Self {
        FileManager { open_files: HashMap::new(), file_info: HashMap::new(), watcher }
    }

    #[cfg(not(feature = "notify"))]
    pub fn new() -> Self {
        FileManager { open_files: HashMap::new(), file_info: HashMap::new() }
    }

    #[cfg(feature = "notify")]
    pub fn watcher(&mut self) -> &mut FileWatcher {
        &mut self.watcher
    }

    pub fn get_info(&self, id: BufferId) -> Option<&FileInfo> {
        self.file_info.get(&id)
    }

    pub fn get_editor(&self, path: &Path) -> Option<BufferId> {
        self.open_files.get(path).cloned()
    }

    /// Returns `true` if this file is open and has changed on disk.
    /// This state is stashed.
    pub fn check_file(&mut self, path: &Path, id: BufferId) -> bool {
        if let Some(info) = self.file_info.get_mut(&id) {
            let mod_t = get_mod_time(path);
            if mod_t != info.mod_time {
                info.has_changed = true
            }
            return info.has_changed;
        }
        false
    }

    pub fn open(&mut self, path: &Path, id: BufferId) -> Result<Rope, FileError> {
        if !path.exists() {
            return Ok(Rope::from(""));
        }

        let (rope, info) = try_load_file(path)?;

        self.open_files.insert(path.to_owned(), id);
        if self.file_info.insert(id, info).is_none() {
            #[cfg(feature = "notify")]
            self.watcher.watch(path, false, OPEN_FILE_EVENT_TOKEN);
        }
        Ok(rope)
    }

    pub fn close(&mut self, id: BufferId) {
        if let Some(info) = self.file_info.remove(&id) {
            self.open_files.remove(&info.path);
            #[cfg(feature = "notify")]
            self.watcher.unwatch(&info.path, OPEN_FILE_EVENT_TOKEN);
        }
    }

    pub fn save(&mut self, path: &Path, text: &Rope, id: BufferId) -> Result<(), FileError> {
        let is_existing = self.file_info.contains_key(&id);
        if is_existing {
            self.save_existing(path, text, id)
        } else {
            self.save_new(path, text, id)
        }
    }

    fn save_new(&mut self, path: &Path, text: &Rope, id: BufferId) -> Result<(), FileError> {
        try_save(path, text, CharacterEncoding::Utf8, self.get_info(id))
            .map_err(|e| FileError::Io(e, path.to_owned()))?;
        let info = FileInfo {
            encoding: CharacterEncoding::Utf8,
            path: path.to_owned(),
            mod_time: get_mod_time(path),
            has_changed: false,
            #[cfg(target_family = "unix")]
            permissions: get_permissions(path),
        };
        self.open_files.insert(path.to_owned(), id);
        self.file_info.insert(id, info);
        #[cfg(feature = "notify")]
        self.watcher.watch(path, false, OPEN_FILE_EVENT_TOKEN);
        Ok(())
    }

    fn save_existing(&mut self, path: &Path, text: &Rope, id: BufferId) -> Result<(), FileError> {
        let prev_path = self.file_info[&id].path.clone();
        if prev_path != path {
            self.save_new(path, text, id)?;
            self.open_files.remove(&prev_path);
            #[cfg(feature = "notify")]
            self.watcher.unwatch(&prev_path, OPEN_FILE_EVENT_TOKEN);
        } else if self.file_info[&id].has_changed {
            return Err(FileError::HasChanged(path.to_owned()));
        } else {
            let encoding = self.file_info[&id].encoding;
            try_save(path, text, encoding, self.get_info(id))
                .map_err(|e| FileError::Io(e, path.to_owned()))?;
            self.file_info.get_mut(&id).unwrap().mod_time = get_mod_time(path);
        }
        Ok(())
    }
}

fn try_load_file<P>(path: P) -> Result<(Rope, FileInfo), FileError>
where
    P: AsRef<Path>,
{
    // TODO: support for non-utf8
    // it's arguable that the rope crate should have file loading functionality
    let mut f =
        File::open(path.as_ref()).map_err(|e| FileError::Io(e, path.as_ref().to_owned()))?;
    let mut bytes = Vec::new();
    f.read_to_end(&mut bytes).map_err(|e| FileError::Io(e, path.as_ref().to_owned()))?;

    let encoding = CharacterEncoding::guess(&bytes);
    let rope = try_decode(bytes, encoding, path.as_ref())?;
    let info = FileInfo {
        encoding,
        mod_time: get_mod_time(&path),
        #[cfg(target_family = "unix")]
        permissions: get_permissions(&path),
        path: path.as_ref().to_owned(),
        has_changed: false,
    };
    Ok((rope, info))
}

#[allow(unused)]
fn try_save(
    path: &Path,
    text: &Rope,
    encoding: CharacterEncoding,
    file_info: Option<&FileInfo>,
) -> io::Result<()> {
    let tmp_extension = path.extension().map_or_else(
        || OsString::from("swp"),
        |ext| {
            let mut ext = ext.to_os_string();
            ext.push(".swp");
            ext
        },
    );
    let tmp_path = &path.with_extension(tmp_extension);

    let mut f = File::create(tmp_path)?;
    match encoding {
        CharacterEncoding::Utf8WithBom => f.write_all(UTF8_BOM.as_bytes())?,
        CharacterEncoding::Utf8 => (),
    }

    for chunk in text.iter_chunks(..text.len()) {
        f.write_all(chunk.as_bytes())?;
    }

    fs::rename(tmp_path, path)?;

    #[cfg(target_family = "unix")]
    {
        if let Some(info) = file_info {
            fs::set_permissions(path, Permissions::from_mode(info.permissions.unwrap_or(0o644)))?;
        }
    }

    Ok(())
}

fn try_decode(bytes: Vec<u8>, encoding: CharacterEncoding, path: &Path) -> Result<Rope, FileError> {
    match encoding {
        CharacterEncoding::Utf8 => Ok(Rope::from(
            str::from_utf8(&bytes).map_err(|_e| FileError::UnknownEncoding(path.to_owned()))?,
        )),
        CharacterEncoding::Utf8WithBom => {
            let s = String::from_utf8(bytes)
                .map_err(|_e| FileError::UnknownEncoding(path.to_owned()))?;
            Ok(Rope::from(&s[UTF8_BOM.len()..]))
        }
    }
}

impl CharacterEncoding {
    fn guess(s: &[u8]) -> Self {
        if s.starts_with(UTF8_BOM.as_bytes()) {
            CharacterEncoding::Utf8WithBom
        } else {
            CharacterEncoding::Utf8
        }
    }
}

/// Returns the modification timestamp for the file at a given path,
/// if present.
fn get_mod_time<P: AsRef<Path>>(path: P) -> Option<SystemTime> {
    File::open(path).and_then(|f| f.metadata()).and_then(|meta| meta.modified()).ok()
}

/// Returns the file permissions for the file at a given path on UNIXy systems,
/// if present.
#[cfg(target_family = "unix")]
fn get_permissions<P: AsRef<Path>>(path: P) -> Option<u32> {
    File::open(path).and_then(|f| f.metadata()).map(|meta| meta.permissions().mode()).ok()
}

impl From<FileError> for RemoteError {
    fn from(src: FileError) -> RemoteError {
        //TODO: when we migrate to using the failure crate for error handling,
        // this should return a better message
        let code = src.error_code();
        let message = src.to_string();
        RemoteError::custom(code, message, None)
    }
}

impl FileError {
    fn error_code(&self) -> i64 {
        match self {
            FileError::Io(_, _) => 5,
            FileError::UnknownEncoding(_) => 6,
            FileError::HasChanged(_) => 7,
        }
    }
}

impl fmt::Display for FileError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            FileError::Io(ref e, ref p) => write!(f, "{}. File path: {:?}", e, p),
            FileError::UnknownEncoding(ref p) => write!(f, "Error decoding file: {:?}", p),
            FileError::HasChanged(ref p) => write!(
                f,
                "File has changed on disk. \
                 Please save elsewhere and reload the file. File path: {:?}",
                p
            ),
        }
    }
}
<|endoftext|>


<commit_before>use sxd_document::Package;
use sxd_document::dom::Document;
use sxd_document::writer::format_document;
use sxd_document::parser::Parser;

use sxd_xpath;

use std::io::prelude::*;
use std::fs::File;

pub struct XmiReader {
    package : Package
}
impl XmiReader {
    pub fn new() -> Self {
        XmiReader {
            package : Package::new()
        }
    }

    pub fn from_file(file: &str) -> Self {
        let mut f = File::open(file).expect("No such file");
        let mut s = String::new();
        f.read_to_string(&mut s).expect("Could not read to string");
        let parser = Parser::new();
        let parseres = parser.parse(&s);
        println!("{:#?}", parseres);
        XmiReader {
            package: parseres.ok().expect("Could not parse")
        }
    }

    fn doc(&self) -> Document {
        self.package.as_document()
    }

    pub fn print(&mut self, file: &str) {
        let mut f = File::create(file).expect("Could not create file");
        let doc = self.doc();
        format_document(&doc, &mut f).ok().expect("unable to output XML");
    }

    pub fn test(&self) {
        let doc = self.doc();

        let hello = doc.create_element("hello");
        hello.set_attribute_value("planet", "Earth");
        let comment = doc.create_comment("What about other planets?");
        let text = doc.create_text("Greetings, Earthlings!");

        hello.append_child(comment);
        hello.append_child(text);
        doc.root().append_child(hello);
        info!("{:?}", doc);
    }
}
<commit_msg>XmiReader broken xpath integration<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::collections::HashMap;

use sxd_document::Package;
use sxd_document::dom::Document;
use sxd_document::writer::format_document;
use sxd_document::parser::Parser;
use sxd_xpath::{Value,Functions,Variables,Namespaces,Factory,EvaluationContext,Expression};
use sxd_xpath::function::register_core_functions;

pub struct XmiReader<'a> {
    package     : Package,
    functions   : Functions,
    variables   : Variables<'a>,
    namespaces  : Namespaces,
    factory     : Factory,
}
impl<'a> XmiReader<'a> {
    pub fn new() -> Self {
        let mut fns = HashMap::new();
        register_core_functions(&mut fns);
        XmiReader {
            package     : Package::new(),
            functions   : fns,
            variables   : HashMap::new(),
            namespaces  : HashMap::new(),
            factory     : Factory::new(),
        }
    }

    pub fn from_file(file: &str) -> Self {
        let mut f = File::open(file).expect("No such file");
        let mut s = String::new();
        f.read_to_string(&mut s).expect("Could not read to string");
        let parser = Parser::new();
        let parseres = parser.parse(&s);
        println!("{:#?}", parseres);
        let mut xmireader = XmiReader::new();
        xmireader.package = parseres.ok().expect("Could not parse");
        xmireader
    }

    fn evaluate(&self, xpath: &str) -> Value {
        let root = self.doc().root();
        let context = EvaluationContext::new(
            root,
            &self.functions,
            &self.variables,
            &self.namespaces,
        );
        let xpath = self.factory.build(xpath).unwrap().unwrap();
        xpath.evaluate(&context).ok().unwrap()
    }

    fn doc(&self) -> Document {
        self.package.as_document()
    }

    pub fn print(&mut self, file: &str) {
        let mut f = File::create(file).expect("Could not create file");
        let doc = self.doc();
        format_document(&doc, &mut f).ok().expect("unable to output XML");
    }

    pub fn test(&self) {
        let doc = self.doc();

        let hello = doc.create_element("hello");
        hello.set_attribute_value("planet", "Earth");
        let comment = doc.create_comment("What about other planets?");
        let text = doc.create_text("Greetings, Earthlings!");

        hello.append_child(comment);
        hello.append_child(text);
        doc.root().append_child(hello);
        info!("{:?}", doc);
    }
}
<|endoftext|>


<commit_before>// Unstable features coming in next Epoch
#![feature(match_default_bindings, dyn_trait)]
// Unstable features needed for light_arena
#![feature(integer_atomics, vec_resize_default)]
// Lints
#![deny(unused_qualifications, unused_must_use)]
#![allow(non_snake_case)]
// Clippy config
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        float_cmp, many_single_char_names, unreadable_literal, large_digit_groups, ifs_same_cond,
        if_same_then_else, match_same_arms
    )
)]

#[macro_use]
extern crate bitflags;
extern crate byteorder;
#[macro_use]
extern crate combine;
extern crate crossbeam;
#[macro_use]
extern crate failure;
extern crate image as img;
extern crate indicatif;
extern crate itertools as it;
#[macro_use]
extern crate lazy_static;
extern crate light_arena;
#[macro_use]
extern crate log;
extern crate ndarray;
extern crate ndarray_parallel;
extern crate num;
extern crate num_cpus;
#[cfg(feature = "exr")]
extern crate openexr;
extern crate parking_lot;
extern crate ply_rs;
extern crate rayon;
extern crate state;

#[cfg(test)]
#[macro_use]
extern crate approx;
#[cfg(test)]
#[macro_use]
extern crate quickcheck;

use std::f32;
use std::ops::{Add, Mul, Sub};

use num::{Num, One, Signed};

// stats needs to be declared first so its macros can be used by the following modules
#[macro_use]
mod stats;
mod api;
mod blockedarray;
pub mod bounds;
mod bsdf;
pub mod bvh;
pub mod camera;
mod cie;
pub mod display;
pub mod efloat;
mod fileutil;
pub mod film;
pub mod filter;
mod floatfile;
mod geometry;
pub mod imageio;
pub mod integrator;
mod interaction;
mod interpolation;
pub mod light;
pub mod lightdistrib;
pub mod material;
pub mod mipmap;
mod noise;
mod paramset;
pub mod pbrt;
pub mod primitive;
pub mod ray;
pub mod renderer;
pub mod rng;
pub mod sampler;
pub mod sampling;
pub mod scene;
pub mod shapes;
pub mod spectrum;
pub mod texture;
pub mod transform;

pub fn init_stats() {
    // This one needs to be called first
    stats::init_stats();
    api::init_stats();
    bvh::init_stats();
    film::init_stats();
    integrator::init_stats();
    lightdistrib::init_stats();
    mipmap::init_stats();
    renderer::init_stats();
    scene::init_stats();
    shapes::init_stats();
}

use geometry::{Normal3, Point2, Point3, Vector2, Vector3};
use spectrum::Spectrum;

pub type Vector2f = Vector2<f32>;
pub type Vector3f = Vector3<f32>;
pub type Point2f = Point2<f32>;
pub type Point2i = Point2<i32>;
pub type Point3f = Point3<f32>;
pub type Point3i = Point3<i32>;
pub type Normal3f = Normal3<f32>;

pub use transform::Transform;

pub const INV_2_PI: f32 = 0.15915494309189533577;
pub const MACHINE_EPSILON: f32 = f32::EPSILON * 0.5;
pub fn gamma(n: u32) -> f32 {
    (n as f32 * MACHINE_EPSILON) / (1.0 - n as f32 * MACHINE_EPSILON)
}

/// Smallest representable float strictly less than 1
pub const ONE_MINUS_EPSILON: f32 = 0.99999994f32;

#[derive(Debug, Copy, Clone, Default)]
pub struct PbrtOptions {
    pub num_threads: u8,
    pub quick_render: bool,
}

/// Linear interpolation between 2 values.
///
/// This version should be generic enough to linearly interpolate between 2 Spectrums using an f32
/// parameter.
pub fn lerp<S, T>(t: S, a: T, b: T) -> T
where
    S: One,
    S: Sub<S, Output = S>,
    S: Copy,
    T: Add<T, Output = T>,
    T: Mul<S, Output = T>,
{
    let one: S = num::one();
    a * (one - t) + b * t
}

/// Return the dimension index (0, 1 or 2) that contains the largest component.
pub fn max_dimension<T>(v: &Vector3<T>) -> usize
where
    T: Num + PartialOrd,
{
    if v.x > v.y {
        if v.x > v.z {
            0
        } else {
            2
        }
    } else if v.y > v.z {
        1
    } else {
        2
    }
}

pub fn max_component(v: &Vector3f) -> f32 {
    f32::max(v.x, f32::max(v.y, v.z))
}

/// Permute the components of this vector based on the given indices for x, y and z.
pub fn permute_v<T>(v: &Vector3<T>, x: usize, y: usize, z: usize) -> Vector3<T>
where
    T: Num + Copy,
{
    Vector3::new(v[x], v[y], v[z])
}

/// Permute the components of this point based on the given indices for x, y and z.
pub fn permute_p<T>(v: &Point3<T>, x: usize, y: usize, z: usize) -> Point3<T>
where
    T: Num + Signed + Copy,
{
    Point3::new(v[x], v[y], v[z])
}

/// Create an orthogonal coordinate system from a single vector.
pub fn coordinate_system(v1: &Vector3f) -> (Vector3f, Vector3f) {
    let v2 = if v1.x.abs() > v1.y.abs() {
        Vector3::new(-v1.z, 0.0, v1.x) / (v1.x * v1.x + v1.z * v1.z).sqrt()
    } else {
        Vector3::new(0.0, v1.z, -v1.y) / (v1.y * v1.y + v1.z * v1.z).sqrt()
    };

    let v3 = v1.cross(&v2);

    (v2, v3)
}

// TODO does this exist in std?
pub fn find_interval<P>(size: usize, pred: P) -> usize
where
    P: Fn(usize) -> bool,
{
    let mut first = 0;
    let mut len = size;
    while len > 0 {
        let half = len >> 1;
        let middle = first + half;
        // Bisect range based on value of _pred_ at _middle_
        if pred(middle as usize) {
            first = middle + 1;
            len -= half + 1;
        } else {
            len = half;
        }
    }
    clamp(first as isize - 1, 0, size as isize - 2) as usize
}

/// Version of min() that works on `PartialOrd`, so it works for both u32 and f32.
pub fn min<T: PartialOrd + Copy>(a: T, b: T) -> T {
    if a.lt(&b) {
        a
    } else {
        b
    }
}

/// Version of max() that works on `PartialOrd`, so it works for both u32 and f32.
pub fn max<T: PartialOrd + Copy>(a: T, b: T) -> T {
    if a.gt(&b) {
        a
    } else {
        b
    }
}

#[inline]
pub fn is_power_of_2(v: i32) -> bool {
    (v != 0) && (v & (v - 1)) == 0
}

#[inline]
pub fn round_up_pow_2(v: i32) -> i32 {
    let mut v = v;
    v -= 1;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v + 1
}

#[inline]
pub fn next_float_up(v: f32) -> f32 {
    let mut v = v;
    if v.is_infinite() && v > 0.0 {
        return v;
    }

    if v == -0.0 {
        v = 0.0;
    }
    let mut ui = v.to_bits();
    if v >= 0.0 {
        ui += 1;
    } else {
        ui -= 1;
    }
    f32::from_bits(ui)
}

#[inline]
pub fn next_float_down(v: f32) -> f32 {
    let mut v = v;
    if v.is_infinite() && v < 0.0 {
        return v;
    }

    if v == 0.0 {
        v = -0.0;
    }
    let mut ui = v.to_bits();
    if v > 0.0 {
        ui -= 1;
    } else {
        ui += 1;
    }
    f32::from_bits(ui)
}

pub fn clamp<T>(val: T, low: T, high: T) -> T
where
    T: PartialOrd + Copy,
{
    if val < low {
        low
    } else if val > high {
        high
    } else {
        val
    }
}

pub trait Clampable {
    fn clamp(self, min: f32, max: f32) -> Self;
}

impl Clampable for f32 {
    fn clamp(self, min: f32, max: f32) -> f32 {
        clamp(self, min, max)
    }
}

impl Clampable for Spectrum {
    fn clamp(self, min: f32, max: f32) -> Spectrum {
        Spectrum::rgb(
            self.r.clamp(min, max),
            self.g.clamp(min, max),
            self.b.clamp(min, max),
        )
    }
}

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

    #[test]
    fn test_find_interval() {
        let a = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

        // check clamping for out of range
        assert_eq!(0, find_interval(a.len(), |index| a[index] as isize <= -1));
        assert_eq!(a.len() - 2, find_interval(a.len(), |index| a[index] <= 100));

        for i in 0..a.len() - 1 {
            assert_eq!(i, find_interval(a.len(), |index| a[index] <= i));
            assert_eq!(
                i,
                find_interval(a.len(), |index| a[index] as f32 <= i as f32 + 0.5)
            );
            if i > 0 {
                assert_eq!(
                    i - 1,
                    find_interval(a.len(), |index| a[index] as f32 <= i as f32 - 0.5)
                );
            }
        }
    }

    #[test]
    fn test_gamma() {
        let g5 = gamma(5);
        let p = Point3f::new(-0.4, 0.9, 0.2);
        let v = g5 * p.abs();
        println!("gamma(5) = {}, p={:?}, v={:?}", gamma(5), p, v);
    }

    #[test]
    fn test_is_power_of_2() {
        assert!(is_power_of_2(4));
        assert!(is_power_of_2(8));
        assert!(is_power_of_2(1024));
        assert!(!is_power_of_2(3));
        assert!(!is_power_of_2(7));
    }

    #[test]
    fn test_round_up_pow_2() {
        assert_eq!(round_up_pow_2(1023), 1024);
        assert_eq!(round_up_pow_2(1024), 1024);
    }
}
<commit_msg>Remove unneeded feature<commit_after>// Unstable features coming in next Epoch
#![feature(dyn_trait)]
// Unstable features needed for light_arena
#![feature(integer_atomics, vec_resize_default)]
// Lints
#![deny(unused_qualifications, unused_must_use)]
#![allow(non_snake_case)]
// Clippy config
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        float_cmp, many_single_char_names, unreadable_literal, large_digit_groups, ifs_same_cond,
        if_same_then_else, match_same_arms
    )
)]

#[macro_use]
extern crate bitflags;
extern crate byteorder;
#[macro_use]
extern crate combine;
extern crate crossbeam;
#[macro_use]
extern crate failure;
extern crate image as img;
extern crate indicatif;
extern crate itertools as it;
#[macro_use]
extern crate lazy_static;
extern crate light_arena;
#[macro_use]
extern crate log;
extern crate ndarray;
extern crate ndarray_parallel;
extern crate num;
extern crate num_cpus;
#[cfg(feature = "exr")]
extern crate openexr;
extern crate parking_lot;
extern crate ply_rs;
extern crate rayon;
extern crate state;

#[cfg(test)]
#[macro_use]
extern crate approx;
#[cfg(test)]
#[macro_use]
extern crate quickcheck;

use std::f32;
use std::ops::{Add, Mul, Sub};

use num::{Num, One, Signed};

// stats needs to be declared first so its macros can be used by the following modules
#[macro_use]
mod stats;
mod api;
mod blockedarray;
pub mod bounds;
mod bsdf;
pub mod bvh;
pub mod camera;
mod cie;
pub mod display;
pub mod efloat;
mod fileutil;
pub mod film;
pub mod filter;
mod floatfile;
mod geometry;
pub mod imageio;
pub mod integrator;
mod interaction;
mod interpolation;
pub mod light;
pub mod lightdistrib;
pub mod material;
pub mod mipmap;
mod noise;
mod paramset;
pub mod pbrt;
pub mod primitive;
pub mod ray;
pub mod renderer;
pub mod rng;
pub mod sampler;
pub mod sampling;
pub mod scene;
pub mod shapes;
pub mod spectrum;
pub mod texture;
pub mod transform;

pub fn init_stats() {
    // This one needs to be called first
    stats::init_stats();
    api::init_stats();
    bvh::init_stats();
    film::init_stats();
    integrator::init_stats();
    lightdistrib::init_stats();
    mipmap::init_stats();
    renderer::init_stats();
    scene::init_stats();
    shapes::init_stats();
}

use geometry::{Normal3, Point2, Point3, Vector2, Vector3};
use spectrum::Spectrum;

pub type Vector2f = Vector2<f32>;
pub type Vector3f = Vector3<f32>;
pub type Point2f = Point2<f32>;
pub type Point2i = Point2<i32>;
pub type Point3f = Point3<f32>;
pub type Point3i = Point3<i32>;
pub type Normal3f = Normal3<f32>;

pub use transform::Transform;

pub const INV_2_PI: f32 = 0.15915494309189533577;
pub const MACHINE_EPSILON: f32 = f32::EPSILON * 0.5;
pub fn gamma(n: u32) -> f32 {
    (n as f32 * MACHINE_EPSILON) / (1.0 - n as f32 * MACHINE_EPSILON)
}

/// Smallest representable float strictly less than 1
pub const ONE_MINUS_EPSILON: f32 = 0.99999994f32;

#[derive(Debug, Copy, Clone, Default)]
pub struct PbrtOptions {
    pub num_threads: u8,
    pub quick_render: bool,
}

/// Linear interpolation between 2 values.
///
/// This version should be generic enough to linearly interpolate between 2 Spectrums using an f32
/// parameter.
pub fn lerp<S, T>(t: S, a: T, b: T) -> T
where
    S: One,
    S: Sub<S, Output = S>,
    S: Copy,
    T: Add<T, Output = T>,
    T: Mul<S, Output = T>,
{
    let one: S = num::one();
    a * (one - t) + b * t
}

/// Return the dimension index (0, 1 or 2) that contains the largest component.
pub fn max_dimension<T>(v: &Vector3<T>) -> usize
where
    T: Num + PartialOrd,
{
    if v.x > v.y {
        if v.x > v.z {
            0
        } else {
            2
        }
    } else if v.y > v.z {
        1
    } else {
        2
    }
}

pub fn max_component(v: &Vector3f) -> f32 {
    f32::max(v.x, f32::max(v.y, v.z))
}

/// Permute the components of this vector based on the given indices for x, y and z.
pub fn permute_v<T>(v: &Vector3<T>, x: usize, y: usize, z: usize) -> Vector3<T>
where
    T: Num + Copy,
{
    Vector3::new(v[x], v[y], v[z])
}

/// Permute the components of this point based on the given indices for x, y and z.
pub fn permute_p<T>(v: &Point3<T>, x: usize, y: usize, z: usize) -> Point3<T>
where
    T: Num + Signed + Copy,
{
    Point3::new(v[x], v[y], v[z])
}

/// Create an orthogonal coordinate system from a single vector.
pub fn coordinate_system(v1: &Vector3f) -> (Vector3f, Vector3f) {
    let v2 = if v1.x.abs() > v1.y.abs() {
        Vector3::new(-v1.z, 0.0, v1.x) / (v1.x * v1.x + v1.z * v1.z).sqrt()
    } else {
        Vector3::new(0.0, v1.z, -v1.y) / (v1.y * v1.y + v1.z * v1.z).sqrt()
    };

    let v3 = v1.cross(&v2);

    (v2, v3)
}

// TODO does this exist in std?
pub fn find_interval<P>(size: usize, pred: P) -> usize
where
    P: Fn(usize) -> bool,
{
    let mut first = 0;
    let mut len = size;
    while len > 0 {
        let half = len >> 1;
        let middle = first + half;
        // Bisect range based on value of _pred_ at _middle_
        if pred(middle as usize) {
            first = middle + 1;
            len -= half + 1;
        } else {
            len = half;
        }
    }
    clamp(first as isize - 1, 0, size as isize - 2) as usize
}

/// Version of min() that works on `PartialOrd`, so it works for both u32 and f32.
pub fn min<T: PartialOrd + Copy>(a: T, b: T) -> T {
    if a.lt(&b) {
        a
    } else {
        b
    }
}

/// Version of max() that works on `PartialOrd`, so it works for both u32 and f32.
pub fn max<T: PartialOrd + Copy>(a: T, b: T) -> T {
    if a.gt(&b) {
        a
    } else {
        b
    }
}

#[inline]
pub fn is_power_of_2(v: i32) -> bool {
    (v != 0) && (v & (v - 1)) == 0
}

#[inline]
pub fn round_up_pow_2(v: i32) -> i32 {
    let mut v = v;
    v -= 1;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v + 1
}

#[inline]
pub fn next_float_up(v: f32) -> f32 {
    let mut v = v;
    if v.is_infinite() && v > 0.0 {
        return v;
    }

    if v == -0.0 {
        v = 0.0;
    }
    let mut ui = v.to_bits();
    if v >= 0.0 {
        ui += 1;
    } else {
        ui -= 1;
    }
    f32::from_bits(ui)
}

#[inline]
pub fn next_float_down(v: f32) -> f32 {
    let mut v = v;
    if v.is_infinite() && v < 0.0 {
        return v;
    }

    if v == 0.0 {
        v = -0.0;
    }
    let mut ui = v.to_bits();
    if v > 0.0 {
        ui -= 1;
    } else {
        ui += 1;
    }
    f32::from_bits(ui)
}

pub fn clamp<T>(val: T, low: T, high: T) -> T
where
    T: PartialOrd + Copy,
{
    if val < low {
        low
    } else if val > high {
        high
    } else {
        val
    }
}

pub trait Clampable {
    fn clamp(self, min: f32, max: f32) -> Self;
}

impl Clampable for f32 {
    fn clamp(self, min: f32, max: f32) -> f32 {
        clamp(self, min, max)
    }
}

impl Clampable for Spectrum {
    fn clamp(self, min: f32, max: f32) -> Spectrum {
        Spectrum::rgb(
            self.r.clamp(min, max),
            self.g.clamp(min, max),
            self.b.clamp(min, max),
        )
    }
}

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

    #[test]
    fn test_find_interval() {
        let a = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

        // check clamping for out of range
        assert_eq!(0, find_interval(a.len(), |index| a[index] as isize <= -1));
        assert_eq!(a.len() - 2, find_interval(a.len(), |index| a[index] <= 100));

        for i in 0..a.len() - 1 {
            assert_eq!(i, find_interval(a.len(), |index| a[index] <= i));
            assert_eq!(
                i,
                find_interval(a.len(), |index| a[index] as f32 <= i as f32 + 0.5)
            );
            if i > 0 {
                assert_eq!(
                    i - 1,
                    find_interval(a.len(), |index| a[index] as f32 <= i as f32 - 0.5)
                );
            }
        }
    }

    #[test]
    fn test_gamma() {
        let g5 = gamma(5);
        let p = Point3f::new(-0.4, 0.9, 0.2);
        let v = g5 * p.abs();
        println!("gamma(5) = {}, p={:?}, v={:?}", gamma(5), p, v);
    }

    #[test]
    fn test_is_power_of_2() {
        assert!(is_power_of_2(4));
        assert!(is_power_of_2(8));
        assert!(is_power_of_2(1024));
        assert!(!is_power_of_2(3));
        assert!(!is_power_of_2(7));
    }

    #[test]
    fn test_round_up_pow_2() {
        assert_eq!(round_up_pow_2(1023), 1024);
        assert_eq!(round_up_pow_2(1024), 1024);
    }
}
<|endoftext|>