use crate::{CustomEntryLoader, LoaderError};
use libloading::Library;
use std::{
error::Error,
ffi::{CStr, OsStr},
fmt::{self, Display},
};
#[cfg(all(
unix,
not(any(target_os = "macos", target_os = "ios", target_os = "android"))
))]
const LIB_PATH: &str = "libvulkan.so.1";
#[cfg(target_os = "android")]
const LIB_PATH: &str = "libvulkan.so";
#[cfg(any(target_os = "macos", target_os = "ios"))]
const LIB_PATH: &str = "libvulkan.dylib";
#[cfg(windows)]
const LIB_PATH: &str = "vulkan-1.dll";
pub type DefaultEntryLoaderLibrary = Library;
pub type EntryLoader = CustomEntryLoader<DefaultEntryLoaderLibrary>;
#[derive(Debug)]
pub struct LibraryError(libloading::Error);
impl Display for LibraryError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl Error for LibraryError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.0)
}
}
#[derive(Debug)]
pub enum EntryLoaderError {
Library(LibraryError),
EntryLoad(LoaderError),
}
impl Display for EntryLoaderError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
EntryLoaderError::Library(_) => write!(f, "The library failed to load"),
EntryLoaderError::EntryLoad(_) => write!(f, "The entry loader failed to initialize"),
}
}
}
impl Error for EntryLoaderError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
EntryLoaderError::Library(err) => Some(err),
EntryLoaderError::EntryLoad(err) => Some(err),
}
}
}
impl EntryLoader {
pub fn new() -> Result<EntryLoader, EntryLoaderError> {
EntryLoader::with_lib_path(LIB_PATH)
}
pub fn with_lib_path<P: AsRef<OsStr>>(lib_path: P) -> Result<EntryLoader, EntryLoaderError> {
let library = unsafe {
Library::new(lib_path).map_err(|err| EntryLoaderError::Library(LibraryError(err)))?
};
let symbol = |library: &mut Library, name| unsafe {
let cstr = CStr::from_ptr(name);
let bytes = cstr.to_bytes_with_nul();
library.get(bytes).ok().map(|symbol| *symbol)
};
unsafe {
CustomEntryLoader::with_library(library, symbol).map_err(EntryLoaderError::EntryLoad)
}
}
}