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) }?)
}
unsafe fn open_first<I>(candidates: I) -> Result<Self>
where
I: IntoIterator,
I::Item: AsRef<OsStr>,
{
Self::load(unsafe { Library::open_first(candidates) }?)
}
}
#[macro_export]
macro_rules! library {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident {
$( unsafe extern $abi:literal { $($body:tt)* } )*
}
) => {
$(#[$meta])*
$vis struct $name {
__dlsym_library: $crate::Library,
__dlsym_symbols: $crate::__private::Symbols<{ $name::__DLSYM_COUNT }>,
}
impl $name {
const __DLSYM_COUNT: usize = 0 $(+ $crate::__dlsym_block!{count $abi { $($body)* }})*;
const __DLSYM_NAMES: &'static [&'static str] = &{
let mut names = [""; $name::__DLSYM_COUNT];
let mut index = 0usize;
$( $crate::__dlsym_block!{names {names, index} $abi { $($body)* }} )*
let _ = index;
names
};
#[allow(long_running_const_eval)]
const __DLSYM_ORDER: &'static [(u64, usize)] =
&$crate::__private::sort_order::<{ $name::__DLSYM_COUNT }>($name::__DLSYM_NAMES);
$( $crate::__dlsym_block!{methods {} $abi { $($body)* }} )*
}
impl $crate::Bindings for $name {
#[allow(unused_mut, unused_assignments, unused_variables)]
fn load(library: $crate::Library) -> $crate::Result<Self> {
let mut symbols = [::core::ptr::null_mut(); $name::__DLSYM_COUNT];
let mut index = 0usize;
$( $crate::__dlsym_block!{load {&library, symbols, index} $abi { $($body)* }} )*
::core::result::Result::Ok(Self {
__dlsym_symbols: $crate::__private::Symbols(symbols),
__dlsym_library: library,
})
}
fn library(&self) -> &$crate::Library {
&self.__dlsym_library
}
}
impl ::core::fmt::Debug for $name {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
f.debug_struct(::core::stringify!($name))
.field("library", &self.__dlsym_library)
.finish_non_exhaustive()
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __dlsym_block {
(count $abi:literal { $(
$(#[$($attr:tt)*])* $ivis:vis $($kw:ident)+
$(( $($args:tt)* ))? $(-> $ret:ty)? $(: $sty:ty)? ;
)* }) => {
0 $(+ <[&str]>::len(&[::core::stringify!($($kw)+)]))*
};
(names {$names:ident, $i:ident} $abi:literal { $(
$(#[$($attr:tt)*])* $ivis:vis $($kw:ident)+
$(( $($args:tt)* ))? $(-> $ret:ty)? $(: $sty:ty)? ;
)* }) => {
$(
$names[$i] = $crate::__dlsym_name!($($kw)+);
$i += 1;
)*
};
(methods $ctx:tt $abi:literal { $(
$(#[$($attr:tt)*])* $ivis:vis $($kw:ident)+
$(( $($args:tt)* ))? $(-> $ret:ty)? $(: $sty:ty)? ;
)* }) => {
$(
$crate::__dlsym_attrs!{(method {} $abi [$ivis] [$($kw)+]
[$(($($args)*))?] [$(-> $ret)?] [$(: $sty)?]) [no] [] [] $(#[$($attr)*])*}
)*
};
(load $ctx:tt $abi:literal { $(
$(#[$($attr:tt)*])* $ivis:vis $($kw:ident)+
$(( $($args:tt)* ))? $(-> $ret:ty)? $(: $sty:ty)? ;
)* }) => {
$(
$crate::__dlsym_attrs!{(load $ctx $abi [$ivis] [$($kw)+]
[$(($($args)*))?] [$(-> $ret)?] [$(: $sty)?]) [no] [] [] $(#[$($attr)*])*}
)*
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __dlsym_name {
(fn $n:ident) => {
::core::stringify!($n)
};
(safe fn $n:ident) => {
::core::stringify!($n)
};
(unsafe fn $n:ident) => {
::core::stringify!($n)
};
(static $n:ident) => {
::core::stringify!($n)
};
(safe static $n:ident) => {
::core::stringify!($n)
};
(unsafe static $n:ident) => {
::core::stringify!($n)
};
(static mut $n:ident) => {
::core::stringify!($n)
};
(unsafe static mut $n:ident) => {
::core::stringify!($n)
};
($($kw:ident)+) => {
""
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __dlsym_attrs {
($k:tt [$o:ident] [$($l:tt)*] [$($a:tt)*] #[optional] $($t:tt)*) => {
$crate::__dlsym_attrs!{$k [yes] [$($l)*] [$($a)*] $($t)*}
};
($k:tt [$o:ident] [$($l:tt)*] [$($a:tt)*] #[link_name = $link:literal] $($t:tt)*) => {
$crate::__dlsym_attrs!{$k [$o] [$link] [$($a)*] $($t)*}
};
($k:tt [$o:ident] [$($l:tt)*] [$($a:tt)*] #[$($x:tt)*] $($t:tt)*) => {
$crate::__dlsym_attrs!{$k [$o] [$($l)*] [$($a)* #[$($x)*]] $($t)*}
};
(($mode:ident $ctx:tt $abi:literal [$vis:vis] [$($kw:ident)+] $($rest:tt)*)
[$o:ident] [$($l:tt)*] [$($a:tt)*]) => {
$crate::__dlsym_decode!{($mode $ctx $abi [$o] [$($l)*] [$($a)*] [$vis] $($rest)*) $($kw)+}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __dlsym_decode {
(($($k:tt)*) fn $n:ident) => { $crate::__dlsym_gen!{$($k)* unsafe fn $n} };
(($($k:tt)*) unsafe fn $n:ident) => { $crate::__dlsym_gen!{$($k)* unsafe fn $n} };
(($($k:tt)*) safe fn $n:ident) => { $crate::__dlsym_gen!{$($k)* safe fn $n} };
(($($k:tt)*) static $n:ident) => { $crate::__dlsym_gen!{$($k)* unsafe static $n} };
(($($k:tt)*) unsafe static $n:ident) => { $crate::__dlsym_gen!{$($k)* unsafe static $n} };
(($($k:tt)*) safe static $n:ident) => { $crate::__dlsym_gen!{$($k)* safe static $n} };
(($($k:tt)*) static mut $n:ident) => { $crate::__dlsym_gen!{$($k)* unsafe mut $n} };
(($($k:tt)*) unsafe static mut $n:ident) => { $crate::__dlsym_gen!{$($k)* unsafe mut $n} };
(($($k:tt)*) $($kw:ident)+) => {
::core::compile_error!(::core::concat!(
"dlsym::library!: expected `[safe|unsafe] fn NAME(..)` or ",
"`[safe|unsafe] static [mut] NAME: TYPE`, found `",
::core::stringify!($($kw)+), "`"
));
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __dlsym_gen {
(load {$lib:expr, $syms:ident, $i:ident} $abi:literal [$o:ident] [$link:literal]
[$($a:tt)*] [$vis:vis] [$($args:tt)*] [$($ret:tt)*] [$($sty:tt)*]
$safety:ident $kind:ident $n:ident) => {
$crate::__dlsym_load_stmt!{{$syms $i ($crate::__private::resolve(
$lib,
const { $crate::__private::link_name(::core::concat!($link, "\0")) },
$crate::__dlsym_optional!($o),
$crate::__dlsym_is_fn!($kind),
)?)} [] $($a)*}
};
(load {$lib:expr, $syms:ident, $i:ident} $abi:literal [$o:ident] []
[$($a:tt)*] [$vis:vis] [$($args:tt)*] [$($ret:tt)*] [$($sty:tt)*]
$safety:ident $kind:ident $n:ident) => {
$crate::__dlsym_load_stmt!{{$syms $i ($crate::__private::resolve(
$lib,
const { $crate::__private::link_name(::core::concat!(::core::stringify!($n), "\0")) },
$crate::__dlsym_optional!($o),
$crate::__dlsym_is_fn!($kind),
)?)} [] $($a)*}
};
(method $ctx:tt $abi:literal [$o:ident] [$($l:tt)*] [$($a:tt)*] [$vis:vis]
[($($arg:ident : $t:ty),+ , ...)] [$(-> $r:ty)?] [] $safety:ident fn $n:ident) => {
$($a)*
#[allow(non_snake_case)]
$vis fn $n(&self) -> $crate::__dlsym_wrap!($o
$crate::Symbol<'_, unsafe extern $abi fn($($t),+ , ...) $(-> $r)?>)
{
let addr = self.__dlsym_symbols.0
[const { $crate::__private::index_of(Self::__DLSYM_NAMES, Self::__DLSYM_ORDER, ::core::stringify!($n)) }];
$crate::__dlsym_unwrap!($o addr => $crate::__private::symbol(self, addr))
}
};
(method $ctx:tt $abi:literal [$o:ident] [$($l:tt)*] [$($a:tt)*] [$vis:vis]
[($($arg:ident : $t:ty),* $(,)?)] [$(-> $r:ty)?] [] $safety:ident fn $n:ident) => {
$crate::__dlsym_fn_method!{$safety $o [$($a)*] [$vis] $n
[unsafe extern $abi fn($($t),*) $(-> $r)?] [$($arg : $t),*]
[$crate::__dlsym_ret!($($r)?)]}
};
(method $ctx:tt $abi:literal [$o:ident] [$($l:tt)*] [$($a:tt)*] [$vis:vis]
[] [] [: $t:ty] unsafe static $n:ident) => {
$($a)*
#[allow(non_snake_case)]
$vis unsafe fn $n(&self) -> $crate::__dlsym_wrap!($o &$t) {
let addr = self.__dlsym_symbols.0
[const { $crate::__private::index_of(Self::__DLSYM_NAMES, Self::__DLSYM_ORDER, ::core::stringify!($n)) }];
$crate::__dlsym_unwrap!($o addr => unsafe { &*addr.cast::<$t>() })
}
};
(method $ctx:tt $abi:literal [$o:ident] [$($l:tt)*] [$($a:tt)*] [$vis:vis]
[] [] [: $t:ty] safe static $n:ident) => {
$($a)*
#[allow(non_snake_case)]
$vis fn $n(&self) -> $crate::__dlsym_wrap!($o &$t) {
const { $crate::__private::assert_sync::<$t>() };
let addr = self.__dlsym_symbols.0
[const { $crate::__private::index_of(Self::__DLSYM_NAMES, Self::__DLSYM_ORDER, ::core::stringify!($n)) }];
$crate::__dlsym_unwrap!($o addr => unsafe { &*addr.cast::<$t>() })
}
};
(method $ctx:tt $abi:literal [$o:ident] [$($l:tt)*] [$($a:tt)*] [$vis:vis]
[] [] [: $t:ty] unsafe mut $n:ident) => {
$($a)*
#[allow(non_snake_case)]
$vis fn $n(&self) -> $crate::__dlsym_wrap!($o *mut $t) {
let addr = self.__dlsym_symbols.0
[const { $crate::__private::index_of(Self::__DLSYM_NAMES, Self::__DLSYM_ORDER, ::core::stringify!($n)) }];
$crate::__dlsym_unwrap!($o addr => addr.cast::<$t>())
}
};
(method $ctx:tt $abi:literal [$o:ident] [$($l:tt)*] [$($a:tt)*] [$vis:vis]
[$($args:tt)*] [$($ret:tt)*] [$($sty:tt)*] $safety:ident $kind:ident $n:ident) => {
::core::compile_error!(::core::concat!(
"dlsym::library!: malformed item `", ::core::stringify!($n),
"`: functions need `(args)` and no `: TYPE`; statics need `: TYPE`"
));
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __dlsym_fn_method {
(unsafe $o:ident [$($a:tt)*] [$vis:vis] $n:ident [$f:ty] [$($arg:ident : $t:ty),*] [$r:ty]) => {
$($a)*
#[allow(non_snake_case, clippy::too_many_arguments)]
$vis unsafe fn $n(&self, $($arg: $t),*) -> $crate::__dlsym_wrap!($o $r) {
let addr = self.__dlsym_symbols.0
[const { $crate::__private::index_of(Self::__DLSYM_NAMES, Self::__DLSYM_ORDER, ::core::stringify!($n)) }];
$crate::__dlsym_unwrap!($o addr =>
unsafe { ::core::mem::transmute::<*mut ::core::ffi::c_void, $f>(addr)($($arg),*) })
}
};
(safe $o:ident [$($a:tt)*] [$vis:vis] $n:ident [$f:ty] [$($arg:ident : $t:ty),*] [$r:ty]) => {
$($a)*
#[allow(non_snake_case, clippy::too_many_arguments)]
$vis fn $n(&self, $($arg: $t),*) -> $crate::__dlsym_wrap!($o $r) {
let addr = self.__dlsym_symbols.0
[const { $crate::__private::index_of(Self::__DLSYM_NAMES, Self::__DLSYM_ORDER, ::core::stringify!($n)) }];
$crate::__dlsym_unwrap!($o addr =>
unsafe { ::core::mem::transmute::<*mut ::core::ffi::c_void, $f>(addr)($($arg),*) })
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __dlsym_load_stmt {
($k:tt [$($c:tt)*] #[cfg $p:tt] $($t:tt)*) => {
$crate::__dlsym_load_stmt!{$k [$($c)* $p] $($t)*}
};
($k:tt [$($c:tt)*] #[$($x:tt)*] $($t:tt)*) => {
$crate::__dlsym_load_stmt!{$k [$($c)*] $($t)*}
};
({$syms:ident $i:ident ($($e:tt)*)} [$($p:tt)*]) => {
$(#[cfg $p])*
{
$syms[$i] = $($e)*;
}
$i += 1;
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __dlsym_is_fn {
(fn) => {
true
};
($kind:ident) => {
false
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __dlsym_optional {
(yes) => {
true
};
(no) => {
false
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __dlsym_ret {
() => {
()
};
($r:ty) => {
$r
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __dlsym_wrap {
(no $($t:tt)*) => { $($t)* };
(yes $($t:tt)*) => { ::core::option::Option<$($t)*> };
}
#[doc(hidden)]
#[macro_export]
macro_rules! __dlsym_unwrap {
(no $addr:ident => $e:expr) => {
$e
};
(yes $addr:ident => $e:expr) => {
if $addr.is_null() {
::core::option::Option::None
} else {
::core::option::Option::Some($e)
}
};
}