#[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 [] = extern "system" fn($($param_ty),*) -> $ret; )+ pub struct $struct_name { $( pub $name: [], )+ } impl $struct_name { pub fn load(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 [] = extern "system" fn($($param_ty),*) -> $ret; )+ pub struct $struct_name { pub _lib: Option, $( pub $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),*) } )+ } } ) }