From ba6c938a6b504f2787958a11e5bd5960a01f37ef Mon Sep 17 00:00:00 2001 From: hodasemi Date: Fri, 8 Dec 2023 20:51:24 +0100 Subject: [PATCH] Initial commit --- .gitignore | 3 ++ .vscode/settings.json | 7 +++ Cargo.toml | 8 +++ src/lib.rs | 1 + src/macros.rs | 115 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 134 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 Cargo.toml create mode 100644 src/lib.rs create mode 100644 src/macros.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a61e4a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +Cargo.lock + +target/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..04bc8ea --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "workbench.colorCustomizations": { + "activityBar.background": "#382B16", + "titleBar.activeBackground": "#4F3D1F", + "titleBar.activeForeground": "#FDFBF9" + } +} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..bab8f06 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "library_loader" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..eda363d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod macros; diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..f753e7a --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,115 @@ +#[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),*) + } + )+ + } + } + ) +}