tproxy_config/
fn_holder.rs1#![allow(dead_code)]
2
3pub trait FnCast: Copy {}
4
5pub struct FnHolder<F: FnCast> {
6 _lib: ::libloading::Library,
7 pub func: F,
8}
9
10unsafe impl<F: FnCast> Send for FnHolder<F> {}
11unsafe impl<F: FnCast> Sync for FnHolder<F> {}
12
13pub fn load_function<F: FnCast>(module_name: &str, function_name: &str) -> Option<FnHolder<F>> {
14 unsafe {
15 let function_name_cstr = std::ffi::CString::new(function_name).ok()?;
16 let _lib = ::libloading::Library::new(module_name).ok()?;
17 let func: F = _lib.get(function_name_cstr.to_bytes_with_nul()).map(|sym| *sym).ok()?;
18 Some(FnHolder { _lib, func })
19 }
20}
21
22#[macro_export]
23macro_rules! define_fn_dynamic_load {
24 ($fn_type:ident, $fn_signature:ty, $static_var:ident, $load_fn:ident, $module_name:expr, $fn_name:expr) => {
25 pub type $fn_type = $fn_signature;
26
27 impl $crate::fn_holder::FnCast for $fn_type {}
28
29 #[allow(non_upper_case_globals)]
30 static $static_var: std::sync::OnceLock<Option<$crate::fn_holder::FnHolder<$fn_type>>> = std::sync::OnceLock::new();
31
32 #[allow(non_snake_case)]
33 pub fn $load_fn() -> Option<$fn_type> {
34 $static_var
35 .get_or_init(|| $crate::fn_holder::load_function($module_name, $fn_name))
36 .as_ref()
37 .map(|fn_holder| fn_holder.func)
38 }
39 };
40}
41
42