vulkan_lib/library_loader/src/macros.rs
2023-01-14 13:03:01 +01:00

115 lines
4.4 KiB
Rust

#[macro_export]
macro_rules! load_function_ptrs {
($struct_name: ident, { $($name: ident($($param_n: ident: $param_ty: ty),*) -> $ret: ty,)+ }) => (
paste::item! {
$(
#[allow(non_camel_case_types)]
pub type [<PFN_ $name>] = extern "system" fn($($param_ty),*) -> $ret;
)+
pub struct $struct_name {
$(
pub $name: [<PFN_ $name>],
)+
}
impl $struct_name {
pub fn load<F>(mut f: F) -> $struct_name
where F: FnMut(&std::ffi::CStr) -> *const std::os::raw::c_void
{
$struct_name {
$(
$name: unsafe {
let dummy: *const std::ffi::c_void = std::ptr::null();
let name = std::ffi::CStr::from_bytes_with_nul_unchecked(concat!(stringify!($name), "\0").as_bytes());
let val = f(name);
if val.is_null() {
println!("failed loading {}", stringify!($name));
std::mem::transmute(dummy)
} else {
std::mem::transmute(val)
}
},
)+
}
}
$(
#[inline]
pub unsafe fn $name(&self $(, $param_n: $param_ty)*) -> $ret {
let ptr = self.$name;
ptr($($param_n),*)
}
)+
}
}
)
}
#[macro_export]
macro_rules! load_function_ptrs_from_lib {
($struct_name: ident, $library: expr, { $($name: ident($($param_n: ident: $param_ty: ty),*) -> $ret: ty,)+ }) => (
paste::item! {
$(
#[allow(non_camel_case_types)]
pub type [<PFN_ $name>] = extern "system" fn($($param_ty),*) -> $ret;
)+
pub struct $struct_name {
pub _lib: Option<shared_library::dynamic_library::DynamicLibrary>,
$(
pub $name: [<PFN_ $name>],
)+
}
impl $struct_name {
pub fn load() -> anyhow::Result<$struct_name> {
let lib = match shared_library::dynamic_library::DynamicLibrary::open(Some(std::path::Path::new($library))) {
Ok(lib) => lib,
Err(err) => {
return Err(anyhow::Error::msg(format!(
"Failed loading library ({}): {}",
$library,
err
)))
}
};
Ok($struct_name {
$(
$name: unsafe {
extern "system" fn $name($(_: $param_ty),*) { panic!("function pointer `{}` not loaded", stringify!($name)) }
let name = std::ffi::CStr::from_bytes_with_nul_unchecked(concat!(stringify!($name), "\0").as_bytes());
let val: *const std::os::raw::c_void = {
let str_name = name.to_str().expect("can't convert CStr");
lib.symbol(str_name)
.unwrap_or_else(|_| panic!("failed getting {}", str_name))
};
if val.is_null() {
println!("failed loading {}", stringify!($name));
std::mem::transmute($name as *const ())
} else {
std::mem::transmute(val)
}
},
)+
_lib: Some(lib),
})
}
$(
#[inline]
pub unsafe fn $name(&self $(, $param_n: $param_ty)*) -> $ret {
let ptr = self.$name;
ptr($($param_n),*)
}
)+
}
}
)
}