use crate::module;
use crate::module::error::Error;
use crate::module::library::symbol::Symbol;
use bp3d_debug::debug;
use libc::{dlclose, dlopen, dlsym, RTLD_LAZY};
use std::ffi::{c_void, CString};
use std::fmt::Debug;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
#[cfg(target_vendor = "apple")]
pub const EXT: &str = "dylib";
#[cfg(all(unix, not(target_vendor = "apple")))]
pub const EXT: &str = "so";
#[derive(Debug)]
#[repr(transparent)]
pub struct Library(*mut c_void);
unsafe impl Send for Library {}
impl Library {
pub fn open_self() -> module::Result<Self> {
let handle = unsafe { dlopen(std::ptr::null(), RTLD_LAZY) };
if handle.is_null() {
return Err(Error::Io(std::io::Error::last_os_error()));
}
Ok(Library(handle))
}
pub unsafe fn load(path: impl AsRef<Path>) -> module::Result<Self> {
let path = CString::new(path.as_ref().as_os_str().as_bytes()).map_err(|_| Error::Null)?;
let handle = dlopen(path.as_ptr(), RTLD_LAZY);
if handle.is_null() {
return Err(Error::Io(std::io::Error::last_os_error()));
}
Ok(Library(handle))
}
}
impl super::Library for Library {
unsafe fn load_symbol<T>(
&self,
name: impl AsRef<str>,
) -> module::Result<Option<Symbol<'_, T>>> {
let name = CString::new(name.as_ref().as_bytes()).map_err(|_| Error::Null)?;
let sym = dlsym(self.0, name.as_ptr());
if sym.is_null() {
Ok(None)
} else {
Ok(Some(Symbol::from_raw(sym)))
}
}
}
impl Drop for Library {
fn drop(&mut self) {
debug!("dlclose");
unsafe { dlclose(self.0) };
}
}