use std::ffi::OsStr;
use crate::{Library, Result};
pub trait Bindings: Sized {
fn load(library: Library) -> Result<Self>;
fn library(&self) -> &Library;
unsafe fn open(path: impl AsRef<OsStr>) -> Result<Self> {
Self::load(unsafe { Library::open(path) }?)
}
}
#[macro_export]
macro_rules! library {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident {
$(
$(#[$fmeta:meta])*
$fvis:vis fn $func:ident ( $($arg:ident : $argty:ty),* $(,)? ) $(-> $ret:ty)? ;
)*
}
) => {
$(#[$meta])*
$vis struct $name {
__dlsym_library: $crate::Library,
$( $func: unsafe extern "C" fn($($argty),*) $(-> $ret)?, )*
}
impl $crate::Bindings for $name {
fn load(library: $crate::Library) -> $crate::Result<Self> {
$(
let $func = unsafe {
library
.get::<unsafe extern "C" fn($($argty),*) $(-> $ret)?>(const {
match ::core::ffi::CStr::from_bytes_with_nul(
::core::concat!(::core::stringify!($func), "\0").as_bytes(),
) {
::core::result::Result::Ok(name) => name,
::core::result::Result::Err(_) => {
::core::panic!("symbol name contains a NUL byte")
}
}
})?
.into_inner()
};
)*
::core::result::Result::Ok(Self {
__dlsym_library: library,
$( $func, )*
})
}
fn library(&self) -> &$crate::Library {
&self.__dlsym_library
}
}
impl $name {
$(
$(#[$fmeta])*
#[allow(clippy::too_many_arguments)]
$fvis unsafe fn $func(&self, $($arg: $argty),*) $(-> $ret)? {
unsafe { (self.$func)($($arg),*) }
}
)*
}
};
}