miniquad 0.3.13

Cross-platform window context and rendering library.
Documentation
#[derive(Debug)]
pub enum Error {
    DlOpenError,
    DlSymError,
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod linux {
    use super::Error;
    use libc::{dlclose, dlopen, dlsym, RTLD_LAZY, RTLD_LOCAL};
    use std::{
        ffi::{c_void, CString},
        ptr::NonNull,
    };

    pub struct Module(NonNull<c_void>);

    impl Module {
        pub fn load(path: &str) -> Result<Self, Error> {
            let path = CString::new(path).unwrap();

            let module = unsafe { dlopen(path.as_ptr(), RTLD_LAZY | RTLD_LOCAL) };
            if module.is_null() {
                Err(Error::DlOpenError)
            } else {
                Ok(Module(unsafe { NonNull::new_unchecked(module) }))
            }
        }

        pub fn get_symbol<F: Sized>(&self, name: &str) -> Result<F, Error> {
            let name = CString::new(name).unwrap();

            let symbol = unsafe { dlsym(self.0.as_ptr(), name.as_ptr()) };

            if symbol.is_null() {
                return Err(Error::DlSymError);
            }

            Ok(unsafe { std::mem::transmute_copy::<_, F>(&symbol) })
        }
    }

    impl Drop for Module {
        fn drop(&mut self) {
            unsafe { dlclose(self.0.as_ptr()) };
        }
    }
}

#[cfg(target_os = "windows")]
mod windows {
    use super::Error;
    use winapi::{
        shared::minwindef::HINSTANCE,
        um::libloaderapi::{FreeLibrary, GetProcAddress, LoadLibraryA},
    };

    pub struct Module(pub HINSTANCE);

    impl Module {
        pub fn load(path: &str) -> Result<Self, Error> {
            let path = std::ffi::CString::new(path).unwrap();
            let library = unsafe { LoadLibraryA(path.as_ptr()) };

            if library.is_null() {
                return Err(Error::DlOpenError);
            }
            Ok(Self(library))
        }
        pub fn get_symbol<F: Sized>(&self, name: &str) -> Result<F, Error> {
            let name = std::ffi::CString::new(name).unwrap();
            let proc = unsafe { GetProcAddress(self.0, name.as_ptr() as *const _) };

            if proc.is_null() {
                return Err(Error::DlSymError);
            }
            return Ok(unsafe { std::mem::transmute_copy(&proc) });
        }
    }

    impl Drop for Module {
        fn drop(&mut self) {
            unsafe { FreeLibrary(self.0) };
        }
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub use linux::*;

#[cfg(target_os = "windows")]
pub use windows::Module;