<commit_before>//!
//! A binding for the library `SDL2_image`
//!
//!
//! Note that you need to build with the
//! feature `image` for this module to be enabled,
//! like so:
//!
//! ```bash
//! $ cargo build --features "image"
//! ```
//!
//! If you want to use this with from inside your own
//! crate, you will need to add this in your Cargo.toml
//!
//! ```toml
//! [dependencies.sdl2]
//! version = ...
//! default-features = false
//! features = ["image"]
//! ```

use std::os::raw::{c_int, c_char};
use std::ffi::CString;
use std::path::Path;
use surface::Surface;
use render::{TextureCreator, Texture};
use rwops::RWops;
use version::Version;
use get_error;
use sys;
use sys::image;

bitflags! {
    /// InitFlags are passed to init() to control which subsystem
    /// functionality to load.
    pub struct InitFlag : u32 {
        const JPG  = image::IMG_InitFlags_IMG_INIT_JPG as u32;
        const PNG  = image::IMG_InitFlags_IMG_INIT_PNG as u32;
        const TIF  = image::IMG_InitFlags_IMG_INIT_TIF as u32;
        const WEBP = image::IMG_InitFlags_IMG_INIT_WEBP as u32;
    }
}

// This is used for error message for init
impl ::std::fmt::Display for InitFlag {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        if self.contains(InitFlag::JPG) {
            f.write_str("INIT_JPG ")?;
        }
        if self.contains(InitFlag::PNG) {
            f.write_str("INIT_PNG ")?;
        }
        if self.contains(InitFlag::TIF) {
            f.write_str("INIT_TIF ")?;
        }
        if self.contains(InitFlag::WEBP) {
            f.write_str("INIT_WEBP ")?;
        }
        Ok(())
    }
}

/// Static method extensions for creating Surfaces
pub trait LoadSurface: Sized {
    // Self is only returned here to type hint to the compiler.
    // The syntax for type hinting in this case is not yet defined.
    // The intended return value is Result<~Surface, String>.
    fn from_file<P: AsRef<Path>>(filename: P) -> Result<Self, String>;
    fn from_xpm_array(xpm: *const *const i8) -> Result<Self, String>;
}

/// Method extensions to Surface for saving to disk
pub trait SaveSurface {
    fn save<P: AsRef<Path>>(&self, filename: P) -> Result<(), String>;
    fn save_rw(&self, dst: &mut RWops) -> Result<(), String>;
}

impl<'a> LoadSurface for Surface<'a> {
    fn from_file<P: AsRef<Path>>(filename: P) -> Result<Surface<'a>, String> {
        //! Loads an SDL Surface from a file
        unsafe {
            let c_filename = CString::new(filename.as_ref().to_str().unwrap()).unwrap();
            let raw = image::IMG_Load(c_filename.as_ptr() as *const _);
            if (raw as *mut ()).is_null() {
                Err(get_error())
            } else {
                Ok(Surface::from_ll(raw))
            }
        }
    }

    fn from_xpm_array(xpm: *const *const i8) -> Result<Surface<'a>, String> {
        //! Loads an SDL Surface from XPM data
        unsafe {
            let raw = image::IMG_ReadXPMFromArray(xpm as *mut *mut c_char);
            if (raw as *mut ()).is_null() {
                Err(get_error())
            } else {
                Ok(Surface::from_ll(raw))
            }
        }
    }
}

impl<'a> SaveSurface for Surface<'a> {
    fn save<P: AsRef<Path>>(&self, filename: P) -> Result<(), String> {
        //! Saves an SDL Surface to a file
        unsafe {
            let c_filename = CString::new(filename.as_ref().to_str().unwrap()).unwrap();
            let status = image::IMG_SavePNG(self.raw(), c_filename.as_ptr() as *const _);
            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }

    fn save_rw(&self, dst: &mut RWops) -> Result<(), String> {
        //! Saves an SDL Surface to an RWops
        unsafe {
            let status = image::IMG_SavePNG_RW(self.raw(), dst.raw(), 0);

            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }
}

/// Method extensions for creating Textures from a `TextureCreator`
pub trait LoadTexture {
    fn load_texture<P: AsRef<Path>>(&self, filename: P) -> Result<Texture, String>;
}

impl<T> LoadTexture for TextureCreator<T> {
    fn load_texture<P: AsRef<Path>>(&self, filename: P) -> Result<Texture, String> {
        //! Loads an SDL Texture from a file
        unsafe {
            let c_filename = CString::new(filename.as_ref().to_str().unwrap()).unwrap();
            let raw = image::IMG_LoadTexture(self.raw(), c_filename.as_ptr() as *const _);
            if (raw as *mut ()).is_null() {
                Err(get_error())
            } else {
                Ok(self.raw_create_texture(raw))
            }
        }
    }
}

/// Context manager for `sdl2_image` to manage quitting. Can't do much with it but
/// keep it alive while you are using it.
pub struct Sdl2ImageContext;

impl Drop for Sdl2ImageContext {
    fn drop(&mut self) {
        unsafe {
            image::IMG_Quit();
        }
    }
}

/// Initializes `SDL2_image` with `InitFlags`.
/// If not every flag is set it returns an error
pub fn init(flags: InitFlag) -> Result<Sdl2ImageContext, String> {
    let return_flags = unsafe {
        let used = image::IMG_Init(flags.bits() as c_int);
        InitFlag::from_bits_truncate(used as u32)
    };
    if !flags.intersects(return_flags) {
        // According to docs, error message text is not always set
        let mut error = get_error();
        if error.is_empty() {
            let un_init_flags = return_flags ^ flags;
            error = format!("Could not init: {}", un_init_flags);
            let _ = ::set_error(&error);
        }
        Err(error)
    } else {
        Ok(Sdl2ImageContext)
    }
}

/// Returns the version of the dynamically linked `SDL_image` library
pub fn get_linked_version() -> Version {
    unsafe { Version::from_ll(*image::IMG_Linked_Version()) }
}

#[inline]
fn to_surface_result<'a>(raw: *mut sys::SDL_Surface) -> Result<Surface<'a>, String> {
    if (raw as *mut ()).is_null() {
        Err(get_error())
    } else {
        unsafe { Ok(Surface::from_ll(raw)) }
    }
}

pub trait ImageRWops {
    /// load as a surface. except TGA
    fn load(&self) -> Result<Surface, String>;
    /// load as a surface. This can load all supported image formats.
    fn load_typed(&self, _type: &str) -> Result<Surface, String>;

    fn load_cur(&self) -> Result<Surface, String>;
    fn load_ico(&self) -> Result<Surface, String>;
    fn load_bmp(&self) -> Result<Surface, String>;
    fn load_pnm(&self) -> Result<Surface, String>;
    fn load_xpm(&self) -> Result<Surface, String>;
    fn load_xcf(&self) -> Result<Surface, String>;
    fn load_pcx(&self) -> Result<Surface, String>;
    fn load_gif(&self) -> Result<Surface, String>;
    fn load_jpg(&self) -> Result<Surface, String>;
    fn load_tif(&self) -> Result<Surface, String>;
    fn load_png(&self) -> Result<Surface, String>;
    fn load_tga(&self) -> Result<Surface, String>;
    fn load_lbm(&self) -> Result<Surface, String>;
    fn load_xv(&self) -> Result<Surface, String>;
    fn load_webp(&self) -> Result<Surface, String>;

    fn is_cur(&self) -> bool;
    fn is_ico(&self) -> bool;
    fn is_bmp(&self) -> bool;
    fn is_pnm(&self) -> bool;
    fn is_xpm(&self) -> bool;
    fn is_xcf(&self) -> bool;
    fn is_pcx(&self) -> bool;
    fn is_gif(&self) -> bool;
    fn is_jpg(&self) -> bool;
    fn is_tif(&self) -> bool;
    fn is_png(&self) -> bool;
    fn is_lbm(&self) -> bool;
    fn is_xv(&self) -> bool;
    fn is_webp(&self) -> bool;
}

impl<'a> ImageRWops for RWops<'a> {
    fn load(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_Load_RW(self.raw(), 0) };
        to_surface_result(raw)
    }
    fn load_typed(&self, _type: &str) -> Result<Surface, String> {
        let raw = unsafe {
            let c_type = CString::new(_type.as_bytes()).unwrap();
            image::IMG_LoadTyped_RW(self.raw(), 0, c_type.as_ptr() as *const _)
        };
        to_surface_result(raw)
    }

    fn load_cur(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadCUR_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_ico(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadICO_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_bmp(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadBMP_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_pnm(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadPNM_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_xpm(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadXPM_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_xcf(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadXCF_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_pcx(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadPCX_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_gif(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadGIF_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_jpg(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadJPG_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_tif(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadTIF_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_png(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadPNG_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_tga(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadTGA_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_lbm(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadLBM_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_xv(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadXV_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_webp(&self) -> Result<Surface, String> {
        let raw = unsafe { image::IMG_LoadWEBP_RW(self.raw()) };
        to_surface_result(raw)
    }

    fn is_cur(&self) -> bool {
        unsafe { image::IMG_isCUR(self.raw()) == 1 }
    }
    fn is_ico(&self) -> bool {
        unsafe { image::IMG_isICO(self.raw()) == 1 }
    }
    fn is_bmp(&self) -> bool {
        unsafe { image::IMG_isBMP(self.raw()) == 1 }
    }
    fn is_pnm(&self) -> bool {
        unsafe { image::IMG_isPNM(self.raw()) == 1 }
    }
    fn is_xpm(&self) -> bool {
        unsafe { image::IMG_isXPM(self.raw()) == 1 }
    }
    fn is_xcf(&self) -> bool {
        unsafe { image::IMG_isXCF(self.raw()) == 1 }
    }
    fn is_pcx(&self) -> bool {
        unsafe { image::IMG_isPCX(self.raw()) == 1 }
    }
    fn is_gif(&self) -> bool {
        unsafe { image::IMG_isGIF(self.raw()) == 1 }
    }
    fn is_jpg(&self) -> bool {
        unsafe { image::IMG_isJPG(self.raw()) == 1 }
    }
    fn is_tif(&self) -> bool {
        unsafe { image::IMG_isTIF(self.raw()) == 1 }
    }
    fn is_png(&self) -> bool {
        unsafe { image::IMG_isPNG(self.raw()) == 1 }
    }
    fn is_lbm(&self) -> bool {
        unsafe { image::IMG_isLBM(self.raw()) == 1 }
    }
    fn is_xv(&self) -> bool {
        unsafe { image::IMG_isXV(self.raw()) == 1 }
    }
    fn is_webp(&self) -> bool {
        unsafe { image::IMG_isWEBP(self.raw()) == 1 }
    }
}
<commit_msg>Resolves Rust-SDL2/rust-sdl2#983.<commit_after>//!
//! A binding for the library `SDL2_image`
//!
//!
//! Note that you need to build with the
//! feature `image` for this module to be enabled,
//! like so:
//!
//! ```bash
//! $ cargo build --features "image"
//! ```
//!
//! If you want to use this with from inside your own
//! crate, you will need to add this in your Cargo.toml
//!
//! ```toml
//! [dependencies.sdl2]
//! version = ...
//! default-features = false
//! features = ["image"]
//! ```

use std::os::raw::{c_int, c_char};
use std::ffi::CString;
use std::path::Path;
use surface::Surface;
use render::{TextureCreator, Texture};
use rwops::RWops;
use version::Version;
use get_error;
use sys;
use sys::image;

bitflags! {
    /// InitFlags are passed to init() to control which subsystem
    /// functionality to load.
    pub struct InitFlag : u32 {
        const JPG  = image::IMG_InitFlags_IMG_INIT_JPG as u32;
        const PNG  = image::IMG_InitFlags_IMG_INIT_PNG as u32;
        const TIF  = image::IMG_InitFlags_IMG_INIT_TIF as u32;
        const WEBP = image::IMG_InitFlags_IMG_INIT_WEBP as u32;
    }
}

// This is used for error message for init
impl ::std::fmt::Display for InitFlag {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        if self.contains(InitFlag::JPG) {
            f.write_str("INIT_JPG ")?;
        }
        if self.contains(InitFlag::PNG) {
            f.write_str("INIT_PNG ")?;
        }
        if self.contains(InitFlag::TIF) {
            f.write_str("INIT_TIF ")?;
        }
        if self.contains(InitFlag::WEBP) {
            f.write_str("INIT_WEBP ")?;
        }
        Ok(())
    }
}

/// Static method extensions for creating Surfaces
pub trait LoadSurface: Sized {
    // Self is only returned here to type hint to the compiler.
    // The syntax for type hinting in this case is not yet defined.
    // The intended return value is Result<~Surface, String>.
    fn from_file<P: AsRef<Path>>(filename: P) -> Result<Self, String>;
    fn from_xpm_array(xpm: *const *const i8) -> Result<Self, String>;
}

/// Method extensions to Surface for saving to disk
pub trait SaveSurface {
    fn save<P: AsRef<Path>>(&self, filename: P) -> Result<(), String>;
    fn save_rw(&self, dst: &mut RWops) -> Result<(), String>;
}

impl<'a> LoadSurface for Surface<'a> {
    fn from_file<P: AsRef<Path>>(filename: P) -> Result<Surface<'a>, String> {
        //! Loads an SDL Surface from a file
        unsafe {
            let c_filename = CString::new(filename.as_ref().to_str().unwrap()).unwrap();
            let raw = image::IMG_Load(c_filename.as_ptr() as *const _);
            if (raw as *mut ()).is_null() {
                Err(get_error())
            } else {
                Ok(Surface::from_ll(raw))
            }
        }
    }

    fn from_xpm_array(xpm: *const *const i8) -> Result<Surface<'a>, String> {
        //! Loads an SDL Surface from XPM data
        unsafe {
            let raw = image::IMG_ReadXPMFromArray(xpm as *mut *mut c_char);
            if (raw as *mut ()).is_null() {
                Err(get_error())
            } else {
                Ok(Surface::from_ll(raw))
            }
        }
    }
}

impl<'a> SaveSurface for Surface<'a> {
    fn save<P: AsRef<Path>>(&self, filename: P) -> Result<(), String> {
        //! Saves an SDL Surface to a file
        unsafe {
            let c_filename = CString::new(filename.as_ref().to_str().unwrap()).unwrap();
            let status = image::IMG_SavePNG(self.raw(), c_filename.as_ptr() as *const _);
            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }

    fn save_rw(&self, dst: &mut RWops) -> Result<(), String> {
        //! Saves an SDL Surface to an RWops
        unsafe {
            let status = image::IMG_SavePNG_RW(self.raw(), dst.raw(), 0);

            if status != 0 {
                Err(get_error())
            } else {
                Ok(())
            }
        }
    }
}

/// Method extensions for creating Textures from a `TextureCreator`
pub trait LoadTexture {
    fn load_texture<P: AsRef<Path>>(&self, filename: P) -> Result<Texture, String>;
}

impl<T> LoadTexture for TextureCreator<T> {
    fn load_texture<P: AsRef<Path>>(&self, filename: P) -> Result<Texture, String> {
        //! Loads an SDL Texture from a file
        unsafe {
            let c_filename = CString::new(filename.as_ref().to_str().unwrap()).unwrap();
            let raw = image::IMG_LoadTexture(self.raw(), c_filename.as_ptr() as *const _);
            if (raw as *mut ()).is_null() {
                Err(get_error())
            } else {
                Ok(self.raw_create_texture(raw))
            }
        }
    }
}

/// Context manager for `sdl2_image` to manage quitting. Can't do much with it but
/// keep it alive while you are using it.
pub struct Sdl2ImageContext;

impl Drop for Sdl2ImageContext {
    fn drop(&mut self) {
        unsafe {
            image::IMG_Quit();
        }
    }
}

/// Initializes `SDL2_image` with `InitFlags`.
/// If not every flag is set it returns an error
pub fn init(flags: InitFlag) -> Result<Sdl2ImageContext, String> {
    let return_flags = unsafe {
        let used = image::IMG_Init(flags.bits() as c_int);
        InitFlag::from_bits_truncate(used as u32)
    };
    if !flags.intersects(return_flags) {
        // According to docs, error message text is not always set
        let mut error = get_error();
        if error.is_empty() {
            let un_init_flags = return_flags ^ flags;
            error = format!("Could not init: {}", un_init_flags);
            let _ = ::set_error(&error);
        }
        Err(error)
    } else {
        Ok(Sdl2ImageContext)
    }
}

/// Returns the version of the dynamically linked `SDL_image` library
pub fn get_linked_version() -> Version {
    unsafe { Version::from_ll(*image::IMG_Linked_Version()) }
}

#[inline]
fn to_surface_result<'a>(raw: *mut sys::SDL_Surface) -> Result<Surface<'a>, String> {
    if (raw as *mut ()).is_null() {
        Err(get_error())
    } else {
        unsafe { Ok(Surface::from_ll(raw)) }
    }
}

pub trait ImageRWops {
    /// load as a surface. except TGA
    fn load(&self) -> Result<Surface<'static>, String>;
    /// load as a surface. This can load all supported image formats.
    fn load_typed(&self, _type: &str) -> Result<Surface<'static>, String>;

    fn load_cur(&self) -> Result<Surface<'static>, String>;
    fn load_ico(&self) -> Result<Surface<'static>, String>;
    fn load_bmp(&self) -> Result<Surface<'static>, String>;
    fn load_pnm(&self) -> Result<Surface<'static>, String>;
    fn load_xpm(&self) -> Result<Surface<'static>, String>;
    fn load_xcf(&self) -> Result<Surface<'static>, String>;
    fn load_pcx(&self) -> Result<Surface<'static>, String>;
    fn load_gif(&self) -> Result<Surface<'static>, String>;
    fn load_jpg(&self) -> Result<Surface<'static>, String>;
    fn load_tif(&self) -> Result<Surface<'static>, String>;
    fn load_png(&self) -> Result<Surface<'static>, String>;
    fn load_tga(&self) -> Result<Surface<'static>, String>;
    fn load_lbm(&self) -> Result<Surface<'static>, String>;
    fn load_xv(&self) -> Result<Surface<'static>, String>;
    fn load_webp(&self) -> Result<Surface<'static>, String>;

    fn is_cur(&self) -> bool;
    fn is_ico(&self) -> bool;
    fn is_bmp(&self) -> bool;
    fn is_pnm(&self) -> bool;
    fn is_xpm(&self) -> bool;
    fn is_xcf(&self) -> bool;
    fn is_pcx(&self) -> bool;
    fn is_gif(&self) -> bool;
    fn is_jpg(&self) -> bool;
    fn is_tif(&self) -> bool;
    fn is_png(&self) -> bool;
    fn is_lbm(&self) -> bool;
    fn is_xv(&self) -> bool;
    fn is_webp(&self) -> bool;
}

impl<'a> ImageRWops for RWops<'a> {
    fn load(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_Load_RW(self.raw(), 0) };
        to_surface_result(raw)
    }
    fn load_typed(&self, _type: &str) -> Result<Surface<'static>, String> {
        let raw = unsafe {
            let c_type = CString::new(_type.as_bytes()).unwrap();
            image::IMG_LoadTyped_RW(self.raw(), 0, c_type.as_ptr() as *const _)
        };
        to_surface_result(raw)
    }

    fn load_cur(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadCUR_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_ico(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadICO_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_bmp(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadBMP_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_pnm(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadPNM_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_xpm(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadXPM_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_xcf(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadXCF_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_pcx(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadPCX_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_gif(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadGIF_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_jpg(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadJPG_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_tif(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadTIF_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_png(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadPNG_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_tga(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadTGA_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_lbm(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadLBM_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_xv(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadXV_RW(self.raw()) };
        to_surface_result(raw)
    }
    fn load_webp(&self) -> Result<Surface<'static>, String> {
        let raw = unsafe { image::IMG_LoadWEBP_RW(self.raw()) };
        to_surface_result(raw)
    }

    fn is_cur(&self) -> bool {
        unsafe { image::IMG_isCUR(self.raw()) == 1 }
    }
    fn is_ico(&self) -> bool {
        unsafe { image::IMG_isICO(self.raw()) == 1 }
    }
    fn is_bmp(&self) -> bool {
        unsafe { image::IMG_isBMP(self.raw()) == 1 }
    }
    fn is_pnm(&self) -> bool {
        unsafe { image::IMG_isPNM(self.raw()) == 1 }
    }
    fn is_xpm(&self) -> bool {
        unsafe { image::IMG_isXPM(self.raw()) == 1 }
    }
    fn is_xcf(&self) -> bool {
        unsafe { image::IMG_isXCF(self.raw()) == 1 }
    }
    fn is_pcx(&self) -> bool {
        unsafe { image::IMG_isPCX(self.raw()) == 1 }
    }
    fn is_gif(&self) -> bool {
        unsafe { image::IMG_isGIF(self.raw()) == 1 }
    }
    fn is_jpg(&self) -> bool {
        unsafe { image::IMG_isJPG(self.raw()) == 1 }
    }
    fn is_tif(&self) -> bool {
        unsafe { image::IMG_isTIF(self.raw()) == 1 }
    }
    fn is_png(&self) -> bool {
        unsafe { image::IMG_isPNG(self.raw()) == 1 }
    }
    fn is_lbm(&self) -> bool {
        unsafe { image::IMG_isLBM(self.raw()) == 1 }
    }
    fn is_xv(&self) -> bool {
        unsafe { image::IMG_isXV(self.raw()) == 1 }
    }
    fn is_webp(&self) -> bool {
        unsafe { image::IMG_isWEBP(self.raw()) == 1 }
    }
}
<|endoftext|>


<commit_before>//=========================================================================
// public imports
//=========================================================================
pub use secret_collection::*;
pub use secret_item::*;
pub use secret_value::*;

//=========================================================================
// private imports
//=========================================================================
use std::ptr;
use std::collections::HashMap;
use glib::Error;
use glib::glib_container::GlibContainer;
use glib::object::{Ref, Wrapper, Object, Upcast};
use glib::types::{StaticType, Type};
use glib::translate::*;
use SecretResult;
use ffi;

/// A SecretService object represents the Secret Service implementation which runs as a D-Bus service.
/// In order to securely transfer secrets to the Sercret Service, a session is established. This will automatically be done when calling `SecretService::get()`
/// To search for items, use the `search()` method.
/// Multiple collections can exist in the Secret Service, each of which contains secret items. To access the list of Collections, use `get_collections()`.
/// Certain actions on the Secret Service require user prompting to complete, such as creating a collection, or unlocking a collection. When such a prompt is necessary, then a SecretPrompt object is created by libsecret, and passed to the secret_service_prompt() method. In this way it is handled automatically.
pub struct SecretService(Ref);

impl SecretService {

    /// Constructs a new SecretService which has established a session and whose collections are loaded.
    /// The underlying FFI object might be identical for multiple instances of this struct.
    pub fn get() -> SecretResult<Self>{
        SecretService::with_flags(SECRET_SERVICE_OPEN_SESSION | SECRET_SERVICE_LOAD_COLLECTIONS)
    }

    fn with_flags(flags: i32) -> SecretResult<Self> {
        let mut err = ptr::null_mut();
        let ptr = unsafe{ffi::secret_service_get_sync(flags, ptr::null_mut(), &mut err)};
        if err.is_null() {
            Ok(unsafe{from_glib_full(ptr)})
        } else {
            Err(Error::wrap(err))
        }
    }

    /// Returns if a session to the SecretService is currently established.
    pub fn is_session_established(&self) -> bool {
        let flags = unsafe {ffi::secret_service_get_flags(self.to_glib_none().0)};
        flags & SECRET_SERVICE_OPEN_SESSION != 0
    }

    /// Returns if the Service's collections are loaded.
    pub fn are_collections_loaded(&self) -> bool {
        let flags = unsafe {ffi::secret_service_get_flags(self.to_glib_none().0)};
        flags & SECRET_SERVICE_LOAD_COLLECTIONS != 0
    }

    /// Get the set of algorithms being used to transfer secrets between this secret service proxy and the Secret Service itself.
    /// The contained String has the format "algorithm-algorithm-algorithm-..."
    pub fn get_session_algorithms(&self) -> String {
        unsafe{
            let ptr = ffi::secret_service_get_session_algorithms(self.to_glib_none().0);
            from_glib_none(ptr)
        }
    }

    /// Get the collections of the Service.
    /// A collection contains multiple SecretItems.
    pub fn get_collections(&self) -> Vec<SecretCollection> {
        unsafe {
            let glist = ffi::secret_service_get_collections(self.to_glib_none().0);
            Vec::from_glib_full(glist)
        }
    }

    /// Search for items matching the attributes. All collections are searched. The attributes should be a table of string keys and string values.
    pub fn search(&self, attributes: &HashMap<String, String>) -> SecretResult<Vec<SecretItem>> {
        let mut err = ptr::null_mut();
        unsafe {
            let glist = ffi::secret_service_search_sync(self.to_glib_none().0, ptr::null(), attributes.to_glib_none().0, SECRET_SEARCH_ALL, ptr::null_mut(), &mut err);
            if err.is_null() {
                Ok(Vec::from_glib_full(glist))
            } else {
                Err(Error::wrap(err))
            }
        }
    }

    /// Store a secret value in the secret service.
    /// The `attributes` should be a set of key and value string pairs.
    /// If the attributes match a secret item already stored in the collection, then the item will be updated with these new values.
    /// `collection` is a collection alias, or `None` to store the value in the default collection (TODO: What about session storage?)
    /// `label` specifies a label for the secret.
    /// `value` is the actual secret to store. This can be created with `SecretValue::new()`.
    pub fn store(&self, attributes: &HashMap<String, String>, collection: Option<&str>, label: &str, value: &SecretValue) -> SecretResult<()> {
        let mut err = ptr::null_mut();
        unsafe {
            ffi::secret_service_store_sync(self.to_glib_none().0, ptr::null(), attributes.to_glib_none().0, collection.to_glib_none().0, label.to_glib_none().0, value.to_glib_none(), ptr::null_mut(), &mut err);
            if err.is_null() {
                Ok(())
            } else {
                Err(Error::wrap(err))
            }
        }
    }

    /*
    pub fn lookup () -> SecretValue {

    }
    */

    /*
    pub fn clear () -> bool {

    }
    */

    /*
    pub fn set_alias(&str alias, ) -> bool {
        //FIXME: actually we should put this into SecretCollection
    }
    */

    /// Ensures that a session is established.
    pub fn ensure_session(&self) -> SecretResult<()> {
        unsafe {
            let mut err = ptr::null_mut();
            ffi::secret_service_ensure_session_sync(self.to_glib_none().0, ptr::null_mut(), &mut err);
            if err.is_null() {
                Ok(())
            } else {
                Err(Error::wrap(err))
            }
        }
    }

    /// Ensures that the collections are loaded.
    pub fn load_collections(&self) -> SecretResult<()> {
        unsafe {
            let mut err = ptr::null_mut();
            ffi::secret_service_load_collections_sync(self.to_glib_none().0, ptr::null_mut(), &mut err);
            if err.is_null() {
                Ok(())
            } else {
                Err(Error::wrap(err))
            }
        }
    }
}

unsafe impl Upcast<Object> for SecretService { }

impl StaticType for SecretService {
    fn static_type() -> Type{
        unsafe { from_glib(ffi::secret_service_get_type()) }
    }
}

impl Wrapper for SecretService {
    type GlibType = ffi::SecretService;

    unsafe fn wrap(r: Ref) -> Self{
        SecretService(r)
    }

    fn as_ref(&self) -> &Ref{
        &self.0
    }

    fn unwrap(self) -> Ref{
        self.0
    }
}

#[allow(dead_code)]
const SECRET_SERVICE_NONE: i32              = 0;
const SECRET_SERVICE_OPEN_SESSION: i32      = 1 << 1;
const SECRET_SERVICE_LOAD_COLLECTIONS: i32  = 1 << 2;

#[allow(dead_code)]
const SECRET_SEARCH_NONE: i32               = 0;
#[allow(dead_code)]
const SECRET_SEARCH_ALL: i32                = 1 << 1;
#[allow(dead_code)]
const SECRET_SEARCH_UNLOCK: i32             = 1 << 2;
#[allow(dead_code)]
const SECRET_SEARCH_LOAD_SECRETS: i32       = 1 << 3;
<commit_msg>Implement clear()<commit_after>//=========================================================================
// public imports
//=========================================================================
pub use secret_collection::*;
pub use secret_item::*;
pub use secret_value::*;

//=========================================================================
// private imports
//=========================================================================
use std::ptr;
use std::collections::HashMap;
use glib::Error;
use glib::glib_container::GlibContainer;
use glib::object::{Ref, Wrapper, Object, Upcast};
use glib::types::{StaticType, Type};
use glib::translate::*;
use SecretResult;
use ffi;

/// A SecretService object represents the Secret Service implementation which runs as a D-Bus service.
/// In order to securely transfer secrets to the Sercret Service, a session is established. This will automatically be done when calling `SecretService::get()`
/// To search for items, use the `search()` method.
/// Multiple collections can exist in the Secret Service, each of which contains secret items. To access the list of Collections, use `get_collections()`.
/// Certain actions on the Secret Service require user prompting to complete, such as creating a collection, or unlocking a collection. When such a prompt is necessary, then a SecretPrompt object is created by libsecret, and passed to the secret_service_prompt() method. In this way it is handled automatically.
pub struct SecretService(Ref);

impl SecretService {

    /// Constructs a new SecretService which has established a session and whose collections are loaded.
    /// The underlying FFI object might be identical for multiple instances of this struct.
    pub fn get() -> SecretResult<Self>{
        SecretService::with_flags(SECRET_SERVICE_OPEN_SESSION | SECRET_SERVICE_LOAD_COLLECTIONS)
    }

    fn with_flags(flags: i32) -> SecretResult<Self> {
        let mut err = ptr::null_mut();
        let ptr = unsafe{ffi::secret_service_get_sync(flags, ptr::null_mut(), &mut err)};
        if err.is_null() {
            Ok(unsafe{from_glib_full(ptr)})
        } else {
            Err(Error::wrap(err))
        }
    }

    /// Returns if a session to the SecretService is currently established.
    pub fn is_session_established(&self) -> bool {
        let flags = unsafe {ffi::secret_service_get_flags(self.to_glib_none().0)};
        flags & SECRET_SERVICE_OPEN_SESSION != 0
    }

    /// Returns if the Service's collections are loaded.
    pub fn are_collections_loaded(&self) -> bool {
        let flags = unsafe {ffi::secret_service_get_flags(self.to_glib_none().0)};
        flags & SECRET_SERVICE_LOAD_COLLECTIONS != 0
    }

    /// Get the set of algorithms being used to transfer secrets between this secret service proxy and the Secret Service itself.
    /// The contained String has the format "algorithm-algorithm-algorithm-..."
    pub fn get_session_algorithms(&self) -> String {
        unsafe{
            let ptr = ffi::secret_service_get_session_algorithms(self.to_glib_none().0);
            from_glib_none(ptr)
        }
    }

    /// Get the collections of the Service.
    /// A collection contains multiple SecretItems.
    pub fn get_collections(&self) -> Vec<SecretCollection> {
        unsafe {
            let glist = ffi::secret_service_get_collections(self.to_glib_none().0);
            Vec::from_glib_full(glist)
        }
    }

    /// Search for items matching the attributes. All collections are searched. The attributes should be a table of string keys and string values.
    pub fn search(&self, attributes: &HashMap<String, String>) -> SecretResult<Vec<SecretItem>> {
        let mut err = ptr::null_mut();
        unsafe {
            let glist = ffi::secret_service_search_sync(self.to_glib_none().0, ptr::null(), attributes.to_glib_none().0, SECRET_SEARCH_ALL, ptr::null_mut(), &mut err);
            if err.is_null() {
                Ok(Vec::from_glib_full(glist))
            } else {
                Err(Error::wrap(err))
            }
        }
    }

    /// Store a secret value in the secret service.
    /// The `attributes` should be a set of key and value string pairs.
    /// If the attributes match a secret item already stored in the collection, then the item will be updated with these new values.
    /// `collection` is a collection alias, or `None` to store the value in the default collection (TODO: What about session storage?)
    /// `label` specifies a label for the secret.
    /// `value` is the actual secret to store. This can be created with `SecretValue::new()`.
    pub fn store(&self, attributes: &HashMap<String, String>, collection: Option<&str>, label: &str, value: &SecretValue) -> SecretResult<()> {
        let mut err = ptr::null_mut();
        unsafe {
            ffi::secret_service_store_sync(self.to_glib_none().0, ptr::null(), attributes.to_glib_none().0, collection.to_glib_none().0, label.to_glib_none().0, value.to_glib_none(), ptr::null_mut(), &mut err);
            if err.is_null() {
                Ok(())
            } else {
                Err(Error::wrap(err))
            }
        }
    }

    /*
    pub fn lookup () -> SecretValue {

    }
    */

    /// Remove unlocked items which match the attributes from the secret service.
    /// The attributes should be a set of key and value string pairs.
    pub fn clear(&self, attributes: &HashMap<String, String>) -> SecretResult<()> {
        let mut err = ptr::null_mut();
        unsafe {
            ffi::secret_service_clear_sync(self.to_glib_none().0, ptr::null(), attributes.to_glib_none().0, ptr::null_mut(), &mut err);
            if err.is_null() {
                Ok(())
            } else {
                Err(Error::wrap(err))
            }
        }
    }

    /// Ensures that a session is established.
    pub fn ensure_session(&self) -> SecretResult<()> {
        unsafe {
            let mut err = ptr::null_mut();
            ffi::secret_service_ensure_session_sync(self.to_glib_none().0, ptr::null_mut(), &mut err);
            if err.is_null() {
                Ok(())
            } else {
                Err(Error::wrap(err))
            }
        }
    }

    /// Ensures that the collections are loaded.
    pub fn load_collections(&self) -> SecretResult<()> {
        unsafe {
            let mut err = ptr::null_mut();
            ffi::secret_service_load_collections_sync(self.to_glib_none().0, ptr::null_mut(), &mut err);
            if err.is_null() {
                Ok(())
            } else {
                Err(Error::wrap(err))
            }
        }
    }
}

unsafe impl Upcast<Object> for SecretService { }

impl StaticType for SecretService {
    fn static_type() -> Type{
        unsafe { from_glib(ffi::secret_service_get_type()) }
    }
}

impl Wrapper for SecretService {
    type GlibType = ffi::SecretService;

    unsafe fn wrap(r: Ref) -> Self{
        SecretService(r)
    }

    fn as_ref(&self) -> &Ref{
        &self.0
    }

    fn unwrap(self) -> Ref{
        self.0
    }
}

#[allow(dead_code)]
const SECRET_SERVICE_NONE: i32              = 0;
const SECRET_SERVICE_OPEN_SESSION: i32      = 1 << 1;
const SECRET_SERVICE_LOAD_COLLECTIONS: i32  = 1 << 2;

#[allow(dead_code)]
const SECRET_SEARCH_NONE: i32               = 0;
#[allow(dead_code)]
const SECRET_SEARCH_ALL: i32                = 1 << 1;
#[allow(dead_code)]
const SECRET_SEARCH_UNLOCK: i32             = 1 << 2;
#[allow(dead_code)]
const SECRET_SEARCH_LOAD_SECRETS: i32       = 1 << 3;
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! `x86_64` architecture-specific implementation.
// pub mod cpu;
pub mod drivers;
pub mod interrupts;

#[path = "../x86_all/bda.rs"] pub mod bda;
#[path = "../x86_all/multiboot2.rs"] pub mod multiboot2;

pub const ARCH_BITS: u8 = 64;

extern {
    // TODO: It would be really nice if there was a less ugly way of doing
    // this... (read: after the Revolution when we add memory regions to the
    // heap programmatically.)
    #[link_name = "heap_base_addr"]
    #[linkage = "external"]
    pub static HEAP_BASE: *mut u8;
    #[link_name = "heap_top_addr"]
    #[linkage = "external"]
    pub static HEAP_TOP: *mut u8;
    // Of course, we will still need to export the kernel stack addresses like
    // this, but it would be nice if they could be, i dont know, not mut u8s
    // pointers, like God intended.
    #[link_name = "stack_base"]
    pub static STACK_BASE: *mut u8;
    #[link_name = "stack_top"]
    pub static STACK_TOP: *mut u8;
}

use memory::PAddr;

/// Trampoline to ensure we have a correct stack frame for calling [`arch_init`]
///
/// I have no idea why this works, but it does.
///
/// [`arch_init`]: fn.arch_init
#[naked]
#[no_mangle]
pub unsafe extern "C" fn long_mode_init() {
    asm!("movabsq $$(stack_top), %rsp");
    asm!("mov ax, 0
          mov ss, ax
          mov ds, ax
          mov es, ax
          mov fs, ax
          mov gs, ax
          call arch_init"
        :::: "intel");

}

/// Entry point for architecture-specific kernel init
///
/// This expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
#[no_mangle]
pub extern "C" fn arch_init(multiboot_addr: PAddr) {
    use cpu::{control_regs, msr};
    use elf;
    use params::InitParams;

    kinfoln!(dots: " . ", "Beginning `arch_init()` for x86_64");

    ::io::term::CONSOLE.lock().clear();
    ::logger::initialize()
        .expect("Could not initialize logger!");

    // -- Unpack multiboot tag ------------------------------------------------
    kinfoln!( dots: " . "
            , "trying to unpack multiboot info at {:#p}"
            , multiboot_addr);

    // try to interpret the structure at the multiboot address as a multiboot
    // info struct. if it's invalid, fail.
    let boot_info
        = unsafe { multiboot2::Info::from(multiboot_addr)
                    .expect("Could not unpack multiboot2 information!") };

    // Extract ELF sections tag from the multiboot info
    let elf_sections_tag
        = boot_info.elf_sections()
                   .expect("ELF sections tag required!");

    kinfoln!(dots: " . ", "Detecting kernel ELF sections:");

    // Extract kernel ELF sections from  multiboot info
    let mut n_elf_sections = 0;

    let kernel_begin
        = elf_sections_tag.sections()
            .filter(|s| s.is_allocated())
            .map(|s| {
                kinfoln!( dots: " . . ", "{}", s );
                kinfoln!( dots: " . . . ", "flags: [ {:?} ]", s.flags());
                s.address() })
            .min()
            .expect("Could not find kernel start section!\
                    \nSomething is deeply wrong.");

    let kernel_end
        = elf_sections_tag.sections()
            .filter(|s| s.is_allocated())
            .map(|s| { n_elf_sections += 1; s.address() })
            .max()
            .expect("Could not find kernel end section!\
                    \nSomething is deeply wrong.");

    kinfoln!( dots: " . ", "Detected {} kernel ELF sections.", n_elf_sections);
    kinfoln!( dots: " . . ", "Kernel begins at {:#p} and ends at {:#p}."
            , kernel_begin, kernel_end );

    let multiboot_end = multiboot_addr + boot_info.length as u64;

    kinfoln!( dots: " . . ", "Multiboot info begins at {:#x} and ends at {:#x}."
            , multiboot_addr, multiboot_end);

    let mut params = InitParams { kernel_base: kernel_begin
                            , kernel_top: kernel_end
                            , multiboot_start: Some(multiboot_addr)
                            , multiboot_end: Some(multiboot_end)
                            , heap_base: unsafe { PAddr::from(HEAP_BASE) }
                            , heap_top: unsafe { PAddr::from(HEAP_TOP) }
                            , stack_base: unsafe { PAddr::from(STACK_BASE) }
                            , stack_top: unsafe { PAddr::from(STACK_TOP) }
                            , ..Default::default()
                        };

    // Extract the memory map tag from the multiboot info
    let mem_map = boot_info.mem_map()
                           .expect("Memory map tag required!");

    kinfoln!(dots: " . ", "Detected memory areas:");
    for area in mem_map {
        kinfoln!( dots: " . . ", "{}", area);
        params.mem_map.push(area.into());
    }

     // -- enable flags needed for paging ------------------------------------
     unsafe {
         control_regs::cr0::enable_write_protect(true);
         kinfoln!(dots: " . ", "Page write protect ENABED" );

         msr::enable_nxe();
         kinfoln!(dots: " . ", "Page no execute bit ENABLED");
     }

    kinfoln!(dots: " . ", "Transferring to `kernel_init()`.");
    ::kernel_init(&params);
}
<commit_msg>fix(x86_64::arch_init): use ELF section END addr for finding kernel end<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (eliza@elizas.website)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! `x86_64` architecture-specific implementation.
// pub mod cpu;
pub mod drivers;
pub mod interrupts;

#[path = "../x86_all/bda.rs"] pub mod bda;
#[path = "../x86_all/multiboot2.rs"] pub mod multiboot2;

pub const ARCH_BITS: u8 = 64;

extern {
    // TODO: It would be really nice if there was a less ugly way of doing
    // this... (read: after the Revolution when we add memory regions to the
    // heap programmatically.)
    #[link_name = "heap_base_addr"]
    #[linkage = "external"]
    pub static HEAP_BASE: *mut u8;
    #[link_name = "heap_top_addr"]
    #[linkage = "external"]
    pub static HEAP_TOP: *mut u8;
    // Of course, we will still need to export the kernel stack addresses like
    // this, but it would be nice if they could be, i dont know, not mut u8s
    // pointers, like God intended.
    #[link_name = "stack_base"]
    pub static STACK_BASE: *mut u8;
    #[link_name = "stack_top"]
    pub static STACK_TOP: *mut u8;
}

use memory::PAddr;

/// Trampoline to ensure we have a correct stack frame for calling [`arch_init`]
///
/// I have no idea why this works, but it does.
///
/// [`arch_init`]: fn.arch_init
#[naked]
#[no_mangle]
pub unsafe extern "C" fn long_mode_init() {
    asm!("movabsq $$(stack_top), %rsp");
    asm!("mov ax, 0
          mov ss, ax
          mov ds, ax
          mov es, ax
          mov fs, ax
          mov gs, ax
          call arch_init"
        :::: "intel");

}

/// Entry point for architecture-specific kernel init
///
/// This expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
#[no_mangle]
pub extern "C" fn arch_init(multiboot_addr: PAddr) {
    use cpu::{control_regs, msr};
    use elf;
    use params::InitParams;

    kinfoln!(dots: " . ", "Beginning `arch_init()` for x86_64");

    ::io::term::CONSOLE.lock().clear();
    ::logger::initialize()
        .expect("Could not initialize logger!");

    // -- Unpack multiboot tag ------------------------------------------------
    kinfoln!( dots: " . "
            , "trying to unpack multiboot info at {:#p}"
            , multiboot_addr);

    // try to interpret the structure at the multiboot address as a multiboot
    // info struct. if it's invalid, fail.
    let boot_info
        = unsafe { multiboot2::Info::from(multiboot_addr)
                    .expect("Could not unpack multiboot2 information!") };

    // Extract ELF sections tag from the multiboot info
    let elf_sections_tag
        = boot_info.elf_sections()
                   .expect("ELF sections tag required!");

    kinfoln!(dots: " . ", "Detecting kernel ELF sections:");

    // Extract kernel ELF sections from  multiboot info
    let mut n_elf_sections = 0;

    let kernel_begin
        = elf_sections_tag.sections()
            .filter(|s| s.is_allocated())
            .map(|s| {
                kinfoln!( dots: " . . ", "{}", s );
                kinfoln!( dots: " . . . ", "flags: [ {:?} ]", s.flags());
                s.address() })
            .min()
            .expect("Could not find kernel start section!\
                    \nSomething is deeply wrong.");

    let kernel_end
        = elf_sections_tag.sections()
            .filter(|s| s.is_allocated())
            .map(|s| { n_elf_sections += 1; s.end_address() })
            .max()
            .expect("Could not find kernel end section!\
                    \nSomething is deeply wrong.");

    kinfoln!( dots: " . ", "Detected {} kernel ELF sections.", n_elf_sections);
    kinfoln!( dots: " . . ", "Kernel begins at {:#p} and ends at {:#p}."
            , kernel_begin, kernel_end );

    let multiboot_end = multiboot_addr + boot_info.length as u64;

    kinfoln!( dots: " . . ", "Multiboot info begins at {:#x} and ends at {:#x}."
            , multiboot_addr, multiboot_end);

    let mut params = InitParams { kernel_base: kernel_begin
                            , kernel_top: kernel_end
                            , multiboot_start: Some(multiboot_addr)
                            , multiboot_end: Some(multiboot_end)
                            , heap_base: unsafe { PAddr::from(HEAP_BASE) }
                            , heap_top: unsafe { PAddr::from(HEAP_TOP) }
                            , stack_base: unsafe { PAddr::from(STACK_BASE) }
                            , stack_top: unsafe { PAddr::from(STACK_TOP) }
                            , ..Default::default()
                        };

    // Extract the memory map tag from the multiboot info
    let mem_map = boot_info.mem_map()
                           .expect("Memory map tag required!");

    kinfoln!(dots: " . ", "Detected memory areas:");
    for area in mem_map {
        kinfoln!( dots: " . . ", "{}", area);
        params.mem_map.push(area.into());
    }

     // -- enable flags needed for paging ------------------------------------
     unsafe {
         control_regs::cr0::enable_write_protect(true);
         kinfoln!(dots: " . ", "Page write protect ENABED" );

         msr::enable_nxe();
         kinfoln!(dots: " . ", "Page no execute bit ENABLED");
     }

    kinfoln!(dots: " . ", "Transferring to `kernel_init()`.");
    ::kernel_init(&params);
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 liquid_amber
// This file is distributed under MIT license.
// See LICENSE file.

extern crate green;

#[start]
fn start(argc: int, argv: *const *const u8) -> int {
    green::start(argc, argv, green::basic::event_loop, main)
}

fn fibonacci(n: int) -> int {
    if n < 2 {
        return n;
    }
    let (sink_, source) = channel();
    {
        let sink = sink_.clone();
        spawn(proc() {
            sink.send(fibonacci(n - 2))
        });
    }
    {
        let sink = sink_.clone();
        spawn(proc() {
            sink.send(fibonacci(n - 1))
        });
    }
    source.recv() + source.recv()
}

fn main() {
    println!("{}", fibonacci(10));
}
<commit_msg>Use rustuv::event_loop instead of green::basic::event_loop<commit_after>// Copyright (c) 2014 liquid_amber
// This file is distributed under MIT license.
// See LICENSE file.

extern crate green;
extern crate rustuv;

fn fibonacci(n: int) -> int {
    if n < 2 {
        n
    } else {
        let mut n1 = std::sync::Future::spawn(
            proc () fibonacci(n - 1));
        let mut n2 = std::sync::Future::spawn(
            proc () fibonacci(n - 2));
        n1.get() + n2.get()
    }
}

#[start]
fn start(argc: int, argv: *const *const u8) -> int {
    // I don't know the reason, however, green::basic::event_loop cause error.
    // task '<main>' failed at 'called `Result::unwrap()` on an `Err` value: invalid argument', /home/rustbuild/src/rust-buildbot/slave/nightly-linux/build/src/libcore/result.rs:545
    green::start(argc, argv, rustuv::event_loop, main)
}

fn main() {
    println!("{}", fibonacci(40));
}
<|endoftext|>


<commit_before>use regex::Regex;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use super::file::{FileHeaderSpec, FileHeaderData};

pub struct ParserError {
    summary: String,
    parsertext: String,
    index: i32,
    explanation: Option<String>,
}

impl ParserError {
    pub fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: Some(String::from(expl)),
        }
    }

    pub fn short(sum: &'static str, text: String, idx: i32) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: None
        }
    }
}

impl Error for ParserError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Debug for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}\n\n", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "{}\n\n", e);
        }

        write!(fmt, "On position {}\nin\n{}", self.index, self.parsertext);
        Ok(())
    }

}

impl Display for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "\n\n{}", e);
        }

        Ok(())
    }

}

pub trait FileHeaderParser<'a> : Sized {
    fn new(spec: &'a FileHeaderSpec) -> Self;
    fn read(&self, string: Option<String>) -> Result<FileHeaderData, ParserError>;
    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
}

type TextTpl = (Option<String>, Option<String>);

pub struct Parser<HP>
{
    headerp : HP,
}

impl<'a, HP> Parser<HP> where
    HP: FileHeaderParser<'a>,
{

    fn new(headerp: HP) -> Parser<HP> {
        Parser {
            headerp: headerp,
        }
    }

    pub fn read(&self, s: String) -> Result<(FileHeaderData, String), ParserError>
    {
        let divided = self.divide_text(&s);

        if divided.is_err() {
            return Err(divided.err().unwrap());
        }

        let (header, data) = divided.ok().unwrap();

        let h_parseres = try!(self.headerp.read(header));

        Ok((h_parseres, data.unwrap_or(String::new())))
    }

    fn write(&self, tpl : (FileHeaderData, String)) -> Result<String, ParserError>
    {
        let (header, data) = tpl;
        let h_text = try!(self.headerp.write(&header));

        Ok(h_text + &data[..])
    }

    fn divide_text(&self, text: &String) -> Result<TextTpl, ParserError> {
        let re = Regex::new(r"(?m)^\-\-\-$\n(.*)^\-\-\-$\n(.*)").unwrap();

        let captures = re.captures(&text[..]).unwrap_or(
            return Err(ParserError::new("Cannot run regex on text",
                                        text.clone(), 0,
                                        "Cannot run regex on text to divide it into header and content."))
        );

        if captures.len() != 2 {
            return Err(ParserError::new("Unexpected Regex output",
                                        text.clone(), 0,
                                        "The regex to divide text into header and content had an unexpected output."))
        }

        let header  = captures.at(0).map(|s| String::from(s));
        let content = captures.at(1).map(|s| String::from(s));
        Ok((header, content))
    }

}

<commit_msg>Make Parser::write() public<commit_after>use regex::Regex;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use super::file::{FileHeaderSpec, FileHeaderData};

pub struct ParserError {
    summary: String,
    parsertext: String,
    index: i32,
    explanation: Option<String>,
}

impl ParserError {
    pub fn new(sum: &'static str, text: String, idx: i32, expl: &'static str) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: Some(String::from(expl)),
        }
    }

    pub fn short(sum: &'static str, text: String, idx: i32) -> ParserError {
        ParserError {
            summary: String::from(sum),
            parsertext: text,
            index: idx,
            explanation: None
        }
    }
}

impl Error for ParserError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Debug for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}\n\n", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "{}\n\n", e);
        }

        write!(fmt, "On position {}\nin\n{}", self.index, self.parsertext);
        Ok(())
    }

}

impl Display for ParserError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ParserError: {}", self.summary);

        if let Some(ref e) = self.explanation {
            write!(fmt, "\n\n{}", e);
        }

        Ok(())
    }

}

pub trait FileHeaderParser<'a> : Sized {
    fn new(spec: &'a FileHeaderSpec) -> Self;
    fn read(&self, string: Option<String>) -> Result<FileHeaderData, ParserError>;
    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError>;
}

type TextTpl = (Option<String>, Option<String>);

pub struct Parser<HP>
{
    headerp : HP,
}

impl<'a, HP> Parser<HP> where
    HP: FileHeaderParser<'a>,
{

    fn new(headerp: HP) -> Parser<HP> {
        Parser {
            headerp: headerp,
        }
    }

    pub fn read(&self, s: String) -> Result<(FileHeaderData, String), ParserError>
    {
        let divided = self.divide_text(&s);

        if divided.is_err() {
            return Err(divided.err().unwrap());
        }

        let (header, data) = divided.ok().unwrap();

        let h_parseres = try!(self.headerp.read(header));

        Ok((h_parseres, data.unwrap_or(String::new())))
    }

    pub fn write(&self, tpl : (FileHeaderData, String)) -> Result<String, ParserError>
    {
        let (header, data) = tpl;
        let h_text = try!(self.headerp.write(&header));

        Ok(h_text + &data[..])
    }

    fn divide_text(&self, text: &String) -> Result<TextTpl, ParserError> {
        let re = Regex::new(r"(?m)^\-\-\-$\n(.*)^\-\-\-$\n(.*)").unwrap();

        let captures = re.captures(&text[..]).unwrap_or(
            return Err(ParserError::new("Cannot run regex on text",
                                        text.clone(), 0,
                                        "Cannot run regex on text to divide it into header and content."))
        );

        if captures.len() != 2 {
            return Err(ParserError::new("Unexpected Regex output",
                                        text.clone(), 0,
                                        "The regex to divide text into header and content had an unexpected output."))
        }

        let header  = captures.at(0).map(|s| String::from(s));
        let content = captures.at(1).map(|s| String::from(s));
        Ok((header, content))
    }

}

<|endoftext|>


<commit_before>#![allow(missing_docs)]

use super::Error;
use nix::libc::{c_long, c_uint, c_void};

pub type khronos_utime_nanoseconds_t = khronos_uint64_t;
pub type khronos_uint64_t = u64;
pub type khronos_ssize_t = c_long;
pub type EGLint = i32;
pub type EGLchar = char;
pub type EGLLabelKHR = *const c_void;
pub type EGLNativeDisplayType = NativeDisplayType;
pub type EGLNativePixmapType = NativePixmapType;
pub type EGLNativeWindowType = NativeWindowType;
pub type NativeDisplayType = *const c_void;
pub type NativePixmapType = *const c_void;
pub type NativeWindowType = *const c_void;

extern "system" fn egl_debug_log(
    severity: egl::types::EGLenum,
    command: *const EGLchar,
    _id: EGLint,
    _thread: EGLLabelKHR,
    _obj: EGLLabelKHR,
    message: *const EGLchar,
) {
    let _ = std::panic::catch_unwind(move || unsafe {
        let msg = std::ffi::CStr::from_ptr(message as *const _);
        let message_utf8 = msg.to_string_lossy();
        let cmd = std::ffi::CStr::from_ptr(command as *const _);
        let command_utf8 = cmd.to_string_lossy();
        let logger = crate::slog_or_fallback(None).new(slog::o!("backend" => "egl"));
        match severity {
            egl::DEBUG_MSG_CRITICAL_KHR | egl::DEBUG_MSG_ERROR_KHR => {
                slog::error!(logger, "[EGL] {}: {}", command_utf8, message_utf8)
            }
            egl::DEBUG_MSG_WARN_KHR => slog::warn!(logger, "[EGL] {}: {}", command_utf8, message_utf8),
            egl::DEBUG_MSG_INFO_KHR => slog::info!(logger, "[EGL] {}: {}", command_utf8, message_utf8),
            _ => slog::debug!(logger, "[EGL] {}: {}", command_utf8, message_utf8),
        };
    });
}

/// Loads libEGL symbols, if not loaded already.
/// This normally happens automatically during [`EGLDisplay`] initialization.
pub fn make_sure_egl_is_loaded() -> Result<Vec<String>, Error> {
    use std::{
        ffi::{CStr, CString},
        ptr,
    };

    fn constrain<F>(f: F) -> F
    where
        F: for<'a> Fn(&'a str) -> *const ::std::os::raw::c_void,
    {
        f
    }
    let proc_address = constrain(|sym| unsafe { super::get_proc_address(sym) });

    egl::LOAD.call_once(|| unsafe {
        egl::load_with(|sym| {
            let name = CString::new(sym).unwrap();
            let symbol = egl::LIB.get::<*mut c_void>(name.as_bytes());
            match symbol {
                Ok(x) => *x as *const _,
                Err(_) => ptr::null(),
            }
        });
        egl::load_with(&proc_address);
        egl::BindWaylandDisplayWL::load_with(&proc_address);
        egl::UnbindWaylandDisplayWL::load_with(&proc_address);
        egl::QueryWaylandBufferWL::load_with(&proc_address);
        egl::DebugMessageControlKHR::load_with(&proc_address);
    });

    let extensions = unsafe {
        let p = super::wrap_egl_call(|| egl::QueryString(egl::NO_DISPLAY, egl::EXTENSIONS as i32))
            .map_err(Error::InitFailed)?; //TODO EGL_EXT_client_extensions not supported

        // this possibility is available only with EGL 1.5 or EGL_EXT_platform_base, otherwise
        // `eglQueryString` returns an error
        if p.is_null() {
            return Err(Error::EglExtensionNotSupported(&["EGL_EXT_platform_base"]));
        } else {
            let p = CStr::from_ptr(p);
            let list = String::from_utf8(p.to_bytes().to_vec()).unwrap_or_else(|_| String::new());
            list.split(' ').map(|e| e.to_string()).collect::<Vec<_>>()
        }
    };

    egl::DEBUG.call_once(|| unsafe {
        if extensions.iter().any(|ext| ext == "EGL_KHR_debug") {
            let debug_attribs = [
                egl::DEBUG_MSG_CRITICAL_KHR as isize,
                egl::TRUE as isize,
                egl::DEBUG_MSG_ERROR_KHR as isize,
                egl::TRUE as isize,
                egl::DEBUG_MSG_WARN_KHR as isize,
                egl::TRUE as isize,
                egl::DEBUG_MSG_INFO_KHR as isize,
                egl::TRUE as isize,
                egl::NONE as isize,
            ];
            // we do not check for success, because there is not much we can do otherwise.
            egl::DebugMessageControlKHR(Some(egl_debug_log), debug_attribs.as_ptr());
        }
    });

    Ok(extensions)
}

/// Module containing raw egl function bindings
#[allow(clippy::all, missing_debug_implementations)]
pub mod egl {
    use super::*;
    use libloading::Library;
    use std::sync::Once;

    lazy_static::lazy_static! {
        pub static ref LIB: Library = unsafe { Library::new("libEGL.so.1") }.expect("Failed to load LibEGL");
    }

    pub static LOAD: Once = Once::new();
    pub static DEBUG: Once = Once::new();

    include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs"));

    type EGLDEBUGPROCKHR = Option<
        extern "system" fn(
            _error: egl::types::EGLenum,
            command: *const EGLchar,
            _id: EGLint,
            _thread: EGLLabelKHR,
            _obj: EGLLabelKHR,
            message: *const EGLchar,
        ),
    >;
    #[allow(dead_code, non_upper_case_globals)]
    pub const DEBUG_MSG_CRITICAL_KHR: types::EGLenum = 0x33B9;
    #[allow(dead_code, non_upper_case_globals)]
    pub const DEBUG_MSG_ERROR_KHR: types::EGLenum = 0x33BA;
    #[allow(dead_code, non_upper_case_globals)]
    pub const DEBUG_MSG_INFO_KHR: types::EGLenum = 0x33BC;
    #[allow(dead_code, non_upper_case_globals)]
    pub const DEBUG_MSG_WARN_KHR: types::EGLenum = 0x33BB;

    #[allow(non_snake_case, unused_variables, dead_code)]
    #[inline]
    pub unsafe fn DebugMessageControlKHR(
        callback: EGLDEBUGPROCKHR,
        attrib_list: *const types::EGLAttrib,
    ) -> types::EGLint {
        __gl_imports::mem::transmute::<
            _,
            extern "system" fn(EGLDEBUGPROCKHR, *const types::EGLAttrib) -> types::EGLint,
        >(wayland_storage::DebugMessageControlKHR.f)(callback, attrib_list)
    }
    /*
     * `gl_generator` cannot generate bindings for the `EGL_WL_bind_wayland_display` extension.
     *  Lets do it ourselves...
     */

    #[allow(non_snake_case, unused_variables, dead_code)]
    #[inline]
    pub unsafe fn BindWaylandDisplayWL(
        dpy: types::EGLDisplay,
        display: *mut __gl_imports::raw::c_void,
    ) -> types::EGLBoolean {
        __gl_imports::mem::transmute::<
            _,
            extern "system" fn(types::EGLDisplay, *mut __gl_imports::raw::c_void) -> types::EGLBoolean,
        >(wayland_storage::BindWaylandDisplayWL.f)(dpy, display)
    }

    #[allow(non_snake_case, unused_variables, dead_code)]
    #[inline]
    pub unsafe fn UnbindWaylandDisplayWL(
        dpy: types::EGLDisplay,
        display: *mut __gl_imports::raw::c_void,
    ) -> types::EGLBoolean {
        __gl_imports::mem::transmute::<
            _,
            extern "system" fn(types::EGLDisplay, *mut __gl_imports::raw::c_void) -> types::EGLBoolean,
        >(wayland_storage::UnbindWaylandDisplayWL.f)(dpy, display)
    }

    #[allow(non_snake_case, unused_variables, dead_code)]
    #[inline]
    pub unsafe fn QueryWaylandBufferWL(
        dpy: types::EGLDisplay,
        buffer: *mut __gl_imports::raw::c_void,
        attribute: types::EGLint,
        value: *mut types::EGLint,
    ) -> types::EGLBoolean {
        __gl_imports::mem::transmute::<
            _,
            extern "system" fn(
                types::EGLDisplay,
                *mut __gl_imports::raw::c_void,
                types::EGLint,
                *mut types::EGLint,
            ) -> types::EGLBoolean,
        >(wayland_storage::QueryWaylandBufferWL.f)(dpy, buffer, attribute, value)
    }

    mod wayland_storage {
        use super::{FnPtr, __gl_imports::raw};
        pub static mut BindWaylandDisplayWL: FnPtr = FnPtr {
            f: super::missing_fn_panic as *const raw::c_void,
            is_loaded: false,
        };
        pub static mut UnbindWaylandDisplayWL: FnPtr = FnPtr {
            f: super::missing_fn_panic as *const raw::c_void,
            is_loaded: false,
        };
        pub static mut QueryWaylandBufferWL: FnPtr = FnPtr {
            f: super::missing_fn_panic as *const raw::c_void,
            is_loaded: false,
        };
        pub static mut DebugMessageControlKHR: FnPtr = FnPtr {
            f: super::missing_fn_panic as *const raw::c_void,
            is_loaded: false,
        };
    }

    #[allow(non_snake_case)]
    pub mod DebugMessageControlKHR {
        use super::FnPtr;
        use super::__gl_imports::raw;
        use super::{metaloadfn, wayland_storage};

        #[inline]
        #[allow(dead_code)]
        pub fn is_loaded() -> bool {
            unsafe { wayland_storage::DebugMessageControlKHR.is_loaded }
        }

        #[allow(dead_code)]
        pub fn load_with<F>(mut loadfn: F)
        where
            F: FnMut(&'static str) -> *const raw::c_void,
        {
            unsafe {
                wayland_storage::DebugMessageControlKHR =
                    FnPtr::new(metaloadfn(&mut loadfn, "eglDebugMessageControlKHR", &[]))
            }
        }
    }

    #[allow(non_snake_case)]
    pub mod BindWaylandDisplayWL {
        use super::{FnPtr, __gl_imports::raw, metaloadfn, wayland_storage};

        #[inline]
        #[allow(dead_code)]
        pub fn is_loaded() -> bool {
            unsafe { wayland_storage::BindWaylandDisplayWL.is_loaded }
        }

        #[allow(dead_code)]
        pub fn load_with<F>(mut loadfn: F)
        where
            F: FnMut(&str) -> *const raw::c_void,
        {
            unsafe {
                wayland_storage::BindWaylandDisplayWL =
                    FnPtr::new(metaloadfn(&mut loadfn, "eglBindWaylandDisplayWL", &[]))
            }
        }
    }

    #[allow(non_snake_case)]
    pub mod UnbindWaylandDisplayWL {
        use super::{FnPtr, __gl_imports::raw, metaloadfn, wayland_storage};

        #[inline]
        #[allow(dead_code)]
        pub fn is_loaded() -> bool {
            unsafe { wayland_storage::UnbindWaylandDisplayWL.is_loaded }
        }

        #[allow(dead_code)]
        pub fn load_with<F>(mut loadfn: F)
        where
            F: FnMut(&str) -> *const raw::c_void,
        {
            unsafe {
                wayland_storage::UnbindWaylandDisplayWL =
                    FnPtr::new(metaloadfn(&mut loadfn, "eglUnbindWaylandDisplayWL", &[]))
            }
        }
    }

    #[allow(non_snake_case)]
    pub mod QueryWaylandBufferWL {
        use super::{FnPtr, __gl_imports::raw, metaloadfn, wayland_storage};

        #[inline]
        #[allow(dead_code)]
        pub fn is_loaded() -> bool {
            unsafe { wayland_storage::QueryWaylandBufferWL.is_loaded }
        }

        #[allow(dead_code)]
        pub fn load_with<F>(mut loadfn: F)
        where
            F: FnMut(&str) -> *const raw::c_void,
        {
            unsafe {
                wayland_storage::QueryWaylandBufferWL =
                    FnPtr::new(metaloadfn(&mut loadfn, "eglQueryWaylandBufferWL", &[]))
            }
        }
    }

    // Accepted as <target> in eglCreateImageKHR
    pub const WAYLAND_BUFFER_WL: c_uint = 0x31D5;
    // Accepted in the <attrib_list> parameter of eglCreateImageKHR:
    pub const WAYLAND_PLANE_WL: c_uint = 0x31D6;
    // Possible values for EGL_TEXTURE_FORMAT:
    pub const TEXTURE_Y_U_V_WL: i32 = 0x31D7;
    pub const TEXTURE_Y_UV_WL: i32 = 0x31D8;
    pub const TEXTURE_Y_XUXV_WL: i32 = 0x31D9;
    pub const TEXTURE_EXTERNAL_WL: i32 = 0x31DA;
    // Accepted in the <attribute> parameter of eglQueryWaylandBufferWL:
    pub const EGL_TEXTURE_FORMAT: i32 = 0x3080;
    pub const WAYLAND_Y_INVERTED_WL: i32 = 0x31DB;
}
<commit_msg>egl: Fix segfault in egl logging for empty command strings<commit_after>#![allow(missing_docs)]

use super::Error;
use nix::libc::{c_long, c_uint, c_void};

pub type khronos_utime_nanoseconds_t = khronos_uint64_t;
pub type khronos_uint64_t = u64;
pub type khronos_ssize_t = c_long;
pub type EGLint = i32;
pub type EGLchar = char;
pub type EGLLabelKHR = *const c_void;
pub type EGLNativeDisplayType = NativeDisplayType;
pub type EGLNativePixmapType = NativePixmapType;
pub type EGLNativeWindowType = NativeWindowType;
pub type NativeDisplayType = *const c_void;
pub type NativePixmapType = *const c_void;
pub type NativeWindowType = *const c_void;

extern "system" fn egl_debug_log(
    severity: egl::types::EGLenum,
    command: *const EGLchar,
    _id: EGLint,
    _thread: EGLLabelKHR,
    _obj: EGLLabelKHR,
    message: *const EGLchar,
) {
    let _ = std::panic::catch_unwind(move || unsafe {
        let msg = std::ffi::CStr::from_ptr(message as *const _);
        let message_utf8 = msg.to_string_lossy();
        let command_utf8 = if !command.is_null() {
            let cmd = std::ffi::CStr::from_ptr(command as *const _);
            cmd.to_string_lossy()
        } else {
            std::borrow::Cow::Borrowed("")
        };
        let logger = crate::slog_or_fallback(None).new(slog::o!("backend" => "egl"));
        match severity {
            egl::DEBUG_MSG_CRITICAL_KHR | egl::DEBUG_MSG_ERROR_KHR => {
                slog::error!(logger, "[EGL] {}: {}", command_utf8, message_utf8)
            }
            egl::DEBUG_MSG_WARN_KHR => slog::warn!(logger, "[EGL] {}: {}", command_utf8, message_utf8),
            egl::DEBUG_MSG_INFO_KHR => slog::info!(logger, "[EGL] {}: {}", command_utf8, message_utf8),
            _ => slog::debug!(logger, "[EGL] {}: {}", command_utf8, message_utf8),
        };
    });
}

/// Loads libEGL symbols, if not loaded already.
/// This normally happens automatically during [`EGLDisplay`] initialization.
pub fn make_sure_egl_is_loaded() -> Result<Vec<String>, Error> {
    use std::{
        ffi::{CStr, CString},
        ptr,
    };

    fn constrain<F>(f: F) -> F
    where
        F: for<'a> Fn(&'a str) -> *const ::std::os::raw::c_void,
    {
        f
    }
    let proc_address = constrain(|sym| unsafe { super::get_proc_address(sym) });

    egl::LOAD.call_once(|| unsafe {
        egl::load_with(|sym| {
            let name = CString::new(sym).unwrap();
            let symbol = egl::LIB.get::<*mut c_void>(name.as_bytes());
            match symbol {
                Ok(x) => *x as *const _,
                Err(_) => ptr::null(),
            }
        });
        egl::load_with(&proc_address);
        egl::BindWaylandDisplayWL::load_with(&proc_address);
        egl::UnbindWaylandDisplayWL::load_with(&proc_address);
        egl::QueryWaylandBufferWL::load_with(&proc_address);
        egl::DebugMessageControlKHR::load_with(&proc_address);
    });

    let extensions = unsafe {
        let p = super::wrap_egl_call(|| egl::QueryString(egl::NO_DISPLAY, egl::EXTENSIONS as i32))
            .map_err(Error::InitFailed)?; //TODO EGL_EXT_client_extensions not supported

        // this possibility is available only with EGL 1.5 or EGL_EXT_platform_base, otherwise
        // `eglQueryString` returns an error
        if p.is_null() {
            return Err(Error::EglExtensionNotSupported(&["EGL_EXT_platform_base"]));
        } else {
            let p = CStr::from_ptr(p);
            let list = String::from_utf8(p.to_bytes().to_vec()).unwrap_or_else(|_| String::new());
            list.split(' ').map(|e| e.to_string()).collect::<Vec<_>>()
        }
    };

    egl::DEBUG.call_once(|| unsafe {
        if extensions.iter().any(|ext| ext == "EGL_KHR_debug") {
            let debug_attribs = [
                egl::DEBUG_MSG_CRITICAL_KHR as isize,
                egl::TRUE as isize,
                egl::DEBUG_MSG_ERROR_KHR as isize,
                egl::TRUE as isize,
                egl::DEBUG_MSG_WARN_KHR as isize,
                egl::TRUE as isize,
                egl::DEBUG_MSG_INFO_KHR as isize,
                egl::TRUE as isize,
                egl::NONE as isize,
            ];
            // we do not check for success, because there is not much we can do otherwise.
            egl::DebugMessageControlKHR(Some(egl_debug_log), debug_attribs.as_ptr());
        }
    });

    Ok(extensions)
}

/// Module containing raw egl function bindings
#[allow(clippy::all, missing_debug_implementations)]
pub mod egl {
    use super::*;
    use libloading::Library;
    use std::sync::Once;

    lazy_static::lazy_static! {
        pub static ref LIB: Library = unsafe { Library::new("libEGL.so.1") }.expect("Failed to load LibEGL");
    }

    pub static LOAD: Once = Once::new();
    pub static DEBUG: Once = Once::new();

    include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs"));

    type EGLDEBUGPROCKHR = Option<
        extern "system" fn(
            _error: egl::types::EGLenum,
            command: *const EGLchar,
            _id: EGLint,
            _thread: EGLLabelKHR,
            _obj: EGLLabelKHR,
            message: *const EGLchar,
        ),
    >;
    #[allow(dead_code, non_upper_case_globals)]
    pub const DEBUG_MSG_CRITICAL_KHR: types::EGLenum = 0x33B9;
    #[allow(dead_code, non_upper_case_globals)]
    pub const DEBUG_MSG_ERROR_KHR: types::EGLenum = 0x33BA;
    #[allow(dead_code, non_upper_case_globals)]
    pub const DEBUG_MSG_INFO_KHR: types::EGLenum = 0x33BC;
    #[allow(dead_code, non_upper_case_globals)]
    pub const DEBUG_MSG_WARN_KHR: types::EGLenum = 0x33BB;

    #[allow(non_snake_case, unused_variables, dead_code)]
    #[inline]
    pub unsafe fn DebugMessageControlKHR(
        callback: EGLDEBUGPROCKHR,
        attrib_list: *const types::EGLAttrib,
    ) -> types::EGLint {
        __gl_imports::mem::transmute::<
            _,
            extern "system" fn(EGLDEBUGPROCKHR, *const types::EGLAttrib) -> types::EGLint,
        >(wayland_storage::DebugMessageControlKHR.f)(callback, attrib_list)
    }
    /*
     * `gl_generator` cannot generate bindings for the `EGL_WL_bind_wayland_display` extension.
     *  Lets do it ourselves...
     */

    #[allow(non_snake_case, unused_variables, dead_code)]
    #[inline]
    pub unsafe fn BindWaylandDisplayWL(
        dpy: types::EGLDisplay,
        display: *mut __gl_imports::raw::c_void,
    ) -> types::EGLBoolean {
        __gl_imports::mem::transmute::<
            _,
            extern "system" fn(types::EGLDisplay, *mut __gl_imports::raw::c_void) -> types::EGLBoolean,
        >(wayland_storage::BindWaylandDisplayWL.f)(dpy, display)
    }

    #[allow(non_snake_case, unused_variables, dead_code)]
    #[inline]
    pub unsafe fn UnbindWaylandDisplayWL(
        dpy: types::EGLDisplay,
        display: *mut __gl_imports::raw::c_void,
    ) -> types::EGLBoolean {
        __gl_imports::mem::transmute::<
            _,
            extern "system" fn(types::EGLDisplay, *mut __gl_imports::raw::c_void) -> types::EGLBoolean,
        >(wayland_storage::UnbindWaylandDisplayWL.f)(dpy, display)
    }

    #[allow(non_snake_case, unused_variables, dead_code)]
    #[inline]
    pub unsafe fn QueryWaylandBufferWL(
        dpy: types::EGLDisplay,
        buffer: *mut __gl_imports::raw::c_void,
        attribute: types::EGLint,
        value: *mut types::EGLint,
    ) -> types::EGLBoolean {
        __gl_imports::mem::transmute::<
            _,
            extern "system" fn(
                types::EGLDisplay,
                *mut __gl_imports::raw::c_void,
                types::EGLint,
                *mut types::EGLint,
            ) -> types::EGLBoolean,
        >(wayland_storage::QueryWaylandBufferWL.f)(dpy, buffer, attribute, value)
    }

    mod wayland_storage {
        use super::{FnPtr, __gl_imports::raw};
        pub static mut BindWaylandDisplayWL: FnPtr = FnPtr {
            f: super::missing_fn_panic as *const raw::c_void,
            is_loaded: false,
        };
        pub static mut UnbindWaylandDisplayWL: FnPtr = FnPtr {
            f: super::missing_fn_panic as *const raw::c_void,
            is_loaded: false,
        };
        pub static mut QueryWaylandBufferWL: FnPtr = FnPtr {
            f: super::missing_fn_panic as *const raw::c_void,
            is_loaded: false,
        };
        pub static mut DebugMessageControlKHR: FnPtr = FnPtr {
            f: super::missing_fn_panic as *const raw::c_void,
            is_loaded: false,
        };
    }

    #[allow(non_snake_case)]
    pub mod DebugMessageControlKHR {
        use super::FnPtr;
        use super::__gl_imports::raw;
        use super::{metaloadfn, wayland_storage};

        #[inline]
        #[allow(dead_code)]
        pub fn is_loaded() -> bool {
            unsafe { wayland_storage::DebugMessageControlKHR.is_loaded }
        }

        #[allow(dead_code)]
        pub fn load_with<F>(mut loadfn: F)
        where
            F: FnMut(&'static str) -> *const raw::c_void,
        {
            unsafe {
                wayland_storage::DebugMessageControlKHR =
                    FnPtr::new(metaloadfn(&mut loadfn, "eglDebugMessageControlKHR", &[]))
            }
        }
    }

    #[allow(non_snake_case)]
    pub mod BindWaylandDisplayWL {
        use super::{FnPtr, __gl_imports::raw, metaloadfn, wayland_storage};

        #[inline]
        #[allow(dead_code)]
        pub fn is_loaded() -> bool {
            unsafe { wayland_storage::BindWaylandDisplayWL.is_loaded }
        }

        #[allow(dead_code)]
        pub fn load_with<F>(mut loadfn: F)
        where
            F: FnMut(&str) -> *const raw::c_void,
        {
            unsafe {
                wayland_storage::BindWaylandDisplayWL =
                    FnPtr::new(metaloadfn(&mut loadfn, "eglBindWaylandDisplayWL", &[]))
            }
        }
    }

    #[allow(non_snake_case)]
    pub mod UnbindWaylandDisplayWL {
        use super::{FnPtr, __gl_imports::raw, metaloadfn, wayland_storage};

        #[inline]
        #[allow(dead_code)]
        pub fn is_loaded() -> bool {
            unsafe { wayland_storage::UnbindWaylandDisplayWL.is_loaded }
        }

        #[allow(dead_code)]
        pub fn load_with<F>(mut loadfn: F)
        where
            F: FnMut(&str) -> *const raw::c_void,
        {
            unsafe {
                wayland_storage::UnbindWaylandDisplayWL =
                    FnPtr::new(metaloadfn(&mut loadfn, "eglUnbindWaylandDisplayWL", &[]))
            }
        }
    }

    #[allow(non_snake_case)]
    pub mod QueryWaylandBufferWL {
        use super::{FnPtr, __gl_imports::raw, metaloadfn, wayland_storage};

        #[inline]
        #[allow(dead_code)]
        pub fn is_loaded() -> bool {
            unsafe { wayland_storage::QueryWaylandBufferWL.is_loaded }
        }

        #[allow(dead_code)]
        pub fn load_with<F>(mut loadfn: F)
        where
            F: FnMut(&str) -> *const raw::c_void,
        {
            unsafe {
                wayland_storage::QueryWaylandBufferWL =
                    FnPtr::new(metaloadfn(&mut loadfn, "eglQueryWaylandBufferWL", &[]))
            }
        }
    }

    // Accepted as <target> in eglCreateImageKHR
    pub const WAYLAND_BUFFER_WL: c_uint = 0x31D5;
    // Accepted in the <attrib_list> parameter of eglCreateImageKHR:
    pub const WAYLAND_PLANE_WL: c_uint = 0x31D6;
    // Possible values for EGL_TEXTURE_FORMAT:
    pub const TEXTURE_Y_U_V_WL: i32 = 0x31D7;
    pub const TEXTURE_Y_UV_WL: i32 = 0x31D8;
    pub const TEXTURE_Y_XUXV_WL: i32 = 0x31D9;
    pub const TEXTURE_EXTERNAL_WL: i32 = 0x31DA;
    // Accepted in the <attribute> parameter of eglQueryWaylandBufferWL:
    pub const EGL_TEXTURE_FORMAT: i32 = 0x3080;
    pub const WAYLAND_Y_INVERTED_WL: i32 = 0x31DB;
}
<|endoftext|>