use crate::ffi::collections::NonNullConst;
use crate::ffi::library::library_loader::{
LibraryLoaderBinding, LibraryLoaderInterface, NativeLibraryHandle, NativeLibraryLoaderInterface,
};
use crate::ffi::CBaseFn;
use crate::library::{Error, InternalLibrary, Symbol};
use crate::ownership::{
AccessIdentifier, ImmutableAccessIdentifier, MutableAccessIdentifier, Owned,
};
use crate::ToOsPathBuff;
use std::borrow::Borrow;
use std::ffi::{c_void, CStr};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
#[cfg(windows)]
use std::os::windows::raw::HANDLE;
use std::path::Path;
#[cfg(windows)]
use std::ptr::NonNull;
pub trait LibraryLoaderABICompat {}
pub trait LibraryLoaderAPI<'a> {
type InternalLoader;
fn to_interface(&self) -> NonNullConst<LibraryLoaderInterface>;
unsafe fn from_interface(handler: NonNullConst<LibraryLoaderInterface>) -> Self;
unsafe fn from_void_ptr(handler: NonNullConst<c_void>) -> Self;
unsafe fn load(&mut self, path: &impl AsRef<Path>) -> Result<InternalLibrary<Owned>, Error>;
unsafe fn unload(&mut self, internal: InternalLibrary<Owned>) -> Result<(), Error>;
unsafe fn get_data_symbol<O, U>(
&self,
internal: &InternalLibrary<O>,
symbol: &impl AsRef<CStr>,
caster: impl FnOnce(NonNullConst<c_void>) -> &'a U,
) -> Result<Symbol<'a, &'a U>, Error>
where
O: ImmutableAccessIdentifier;
unsafe fn get_function_symbol<O, U>(
&self,
internal: &InternalLibrary<O>,
symbol: &impl AsRef<CStr>,
caster: impl FnOnce(CBaseFn) -> U,
) -> Result<Symbol<'a, U>, Error>
where
O: ImmutableAccessIdentifier;
unsafe fn get_internal_interface(&self) -> Self::InternalLoader;
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct LibraryLoader<T, O> {
_loader: T,
_ownership: PhantomData<*const O>,
}
impl<'a, T, O> Deref for LibraryLoader<T, O>
where
T: LibraryLoaderAPI<'a>,
O: AccessIdentifier,
{
type Target = T;
fn deref(&self) -> &Self::Target {
&self._loader
}
}
impl<'a, T, O> DerefMut for LibraryLoader<T, O>
where
T: LibraryLoaderAPI<'a>,
O: MutableAccessIdentifier,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self._loader
}
}
impl<'a, T, O> LibraryLoader<T, O>
where
T: LibraryLoaderAPI<'a>,
O: AccessIdentifier,
{
#[inline]
pub fn to_interface(&self) -> NonNullConst<LibraryLoaderInterface> {
self._loader.to_interface()
}
#[inline]
pub unsafe fn from_interface(handler: NonNullConst<LibraryLoaderInterface>) -> Self {
Self {
_loader: T::from_interface(handler),
_ownership: PhantomData,
}
}
#[inline]
pub unsafe fn from_void_ptr(handler: NonNullConst<c_void>) -> Self {
Self {
_loader: T::from_void_ptr(handler),
_ownership: PhantomData,
}
}
}
impl<'a, T, O> LibraryLoader<T, O>
where
T: LibraryLoaderAPI<'a>,
O: MutableAccessIdentifier,
{
#[inline]
pub unsafe fn load(
&mut self,
path: &impl AsRef<Path>,
) -> Result<InternalLibrary<Owned>, Error> {
self._loader.load(path)
}
#[inline]
pub unsafe fn unload(&mut self, internal: InternalLibrary<Owned>) -> Result<(), Error> {
self._loader.unload(internal)
}
}
impl<'a, T, O> LibraryLoader<T, O>
where
T: LibraryLoaderAPI<'a>,
O: ImmutableAccessIdentifier,
{
#[inline]
pub unsafe fn get_data_symbol<LO, U>(
&self,
internal: &InternalLibrary<LO>,
symbol: &impl AsRef<CStr>,
caster: impl FnOnce(NonNullConst<c_void>) -> &'a U,
) -> Result<Symbol<'a, &'a U>, Error>
where
LO: ImmutableAccessIdentifier,
{
self._loader.get_data_symbol(internal, symbol, caster)
}
#[inline]
pub unsafe fn get_function_symbol<LO, U>(
&self,
internal: &InternalLibrary<LO>,
symbol: &impl AsRef<CStr>,
caster: impl FnOnce(CBaseFn) -> U,
) -> Result<Symbol<'a, U>, Error>
where
LO: ImmutableAccessIdentifier,
{
self._loader.get_function_symbol(internal, symbol, caster)
}
#[inline]
pub unsafe fn get_internal_interface(&self) -> LibraryLoader<T::InternalLoader, O> {
LibraryLoader {
_loader: self._loader.get_internal_interface(),
_ownership: PhantomData,
}
}
}
#[derive(Debug, Copy, Clone)]
pub struct InvalidLoader {
_interface: NonNullConst<c_void>,
}
unsafe impl Send for InvalidLoader {}
unsafe impl Sync for InvalidLoader {}
impl InvalidLoader {
#[inline]
pub fn new(interface: NonNullConst<c_void>) -> Self {
Self {
_interface: interface,
}
}
}
impl Deref for InvalidLoader {
type Target = NonNullConst<c_void>;
#[inline]
fn deref(&self) -> &Self::Target {
&self._interface
}
}
impl DerefMut for InvalidLoader {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self._interface
}
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct UnknownLoader<'loader> {
_interface: NonNullConst<LibraryLoaderInterface>,
_phantom: PhantomData<&'loader ()>,
}
unsafe impl Send for UnknownLoader<'_> {}
unsafe impl Sync for UnknownLoader<'_> {}
impl Deref for UnknownLoader<'_> {
type Target = NonNullConst<LibraryLoaderInterface>;
#[inline]
fn deref(&self) -> &Self::Target {
&self._interface
}
}
impl DerefMut for UnknownLoader<'_> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self._interface
}
}
impl LibraryLoaderABICompat for UnknownLoader<'_> {}
impl<'a> LibraryLoaderAPI<'a> for UnknownLoader<'a> {
type InternalLoader = InvalidLoader;
#[inline]
fn to_interface(&self) -> NonNullConst<LibraryLoaderInterface> {
self._interface
}
#[inline]
unsafe fn from_interface(interface: NonNullConst<LibraryLoaderInterface>) -> Self {
Self {
_interface: interface,
_phantom: PhantomData,
}
}
#[inline]
unsafe fn from_void_ptr(interface: NonNullConst<c_void>) -> Self {
Self::from_interface(interface.cast())
}
#[inline]
unsafe fn load(&mut self, path: &impl AsRef<Path>) -> Result<InternalLibrary<Owned>, Error> {
let path_buff = path.as_ref().to_os_path_buff_null();
self._interface
.into_mut()
.as_mut()
.load(NonNullConst::from(path_buff.as_slice()))
.to_result()
.map_or_else(|e| Err(Error::FFIError(e)), |v| Ok(InternalLibrary::new(v)))
}
#[inline]
unsafe fn unload(&mut self, internal: InternalLibrary<Owned>) -> Result<(), Error> {
self._interface
.into_mut()
.as_mut()
.unload(internal.as_handle())
.to_result()
.map_or_else(|e| Err(Error::FFIError(e)), |_v| Ok(()))
}
#[inline]
unsafe fn get_data_symbol<O, U>(
&self,
internal: &InternalLibrary<O>,
symbol: &impl AsRef<CStr>,
caster: impl FnOnce(NonNullConst<c_void>) -> &'a U,
) -> Result<Symbol<'a, &'a U>, Error>
where
O: ImmutableAccessIdentifier,
{
self._interface
.as_ref()
.get_data_symbol(
internal.borrow().as_handle(),
NonNullConst::from(symbol.as_ref().to_bytes_with_nul()),
)
.to_result()
.map_or_else(
|e| Err(Error::FFIError(e)),
|v| Ok(Symbol::new(caster(v.symbol))),
)
}
#[inline]
unsafe fn get_function_symbol<O, U>(
&self,
internal: &InternalLibrary<O>,
symbol: &impl AsRef<CStr>,
caster: impl FnOnce(CBaseFn) -> U,
) -> Result<Symbol<'a, U>, Error>
where
O: ImmutableAccessIdentifier,
{
self._interface
.as_ref()
.get_function_symbol(
internal.borrow().as_handle(),
NonNullConst::from(symbol.as_ref().to_bytes_with_nul()),
)
.to_result()
.map_or_else(
|e| Err(Error::FFIError(e)),
|v| Ok(Symbol::new(caster(v.symbol))),
)
}
#[inline]
unsafe fn get_internal_interface(&self) -> Self::InternalLoader {
Self::InternalLoader::new(self._interface.as_ref().get_internal_interface())
}
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct NativeLoader<'loader> {
_interface: UnknownLoader<'loader>,
}
impl Deref for NativeLoader<'_> {
type Target = NonNullConst<LibraryLoaderInterface>;
#[inline]
fn deref(&self) -> &Self::Target {
self._interface.deref()
}
}
impl DerefMut for NativeLoader<'_> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self._interface.deref_mut()
}
}
impl LibraryLoaderABICompat for NativeLoader<'_> {}
impl<'a> LibraryLoaderAPI<'a> for NativeLoader<'a> {
type InternalLoader = NativeLoaderInternal<'a>;
#[inline]
fn to_interface(&self) -> NonNullConst<LibraryLoaderInterface> {
self._interface.to_interface()
}
#[inline]
unsafe fn from_interface(interface: NonNullConst<LibraryLoaderInterface>) -> Self {
Self {
_interface: UnknownLoader::from_interface(interface),
}
}
#[inline]
unsafe fn from_void_ptr(interface: NonNullConst<c_void>) -> Self {
Self::from_interface(interface.cast())
}
#[inline]
unsafe fn load(&mut self, path: &impl AsRef<Path>) -> Result<InternalLibrary<Owned>, Error> {
self._interface.load(path)
}
#[inline]
unsafe fn unload(&mut self, internal: InternalLibrary<Owned>) -> Result<(), Error> {
self._interface.unload(internal)
}
#[inline]
unsafe fn get_data_symbol<O, U>(
&self,
internal: &InternalLibrary<O>,
symbol: &impl AsRef<CStr>,
caster: impl FnOnce(NonNullConst<c_void>) -> &'a U,
) -> Result<Symbol<'a, &'a U>, Error>
where
O: ImmutableAccessIdentifier,
{
self._interface.get_data_symbol(internal, symbol, caster)
}
#[inline]
unsafe fn get_function_symbol<O, U>(
&self,
internal: &InternalLibrary<O>,
symbol: &impl AsRef<CStr>,
caster: impl FnOnce(CBaseFn) -> U,
) -> Result<Symbol<'a, U>, Error>
where
O: ImmutableAccessIdentifier,
{
self._interface
.get_function_symbol(internal, symbol, caster)
}
#[inline]
unsafe fn get_internal_interface(&self) -> Self::InternalLoader {
Self::InternalLoader::from_void_ptr(*self._interface.get_internal_interface())
}
}
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct NativeLoaderInternal<'loader> {
_interface: NonNullConst<NativeLibraryLoaderInterface>,
_phantom: PhantomData<&'loader ()>,
}
unsafe impl Send for NativeLoaderInternal<'_> {}
unsafe impl Sync for NativeLoaderInternal<'_> {}
impl Deref for NativeLoaderInternal<'_> {
type Target = NonNullConst<NativeLibraryLoaderInterface>;
#[inline]
fn deref(&self) -> &Self::Target {
&self._interface
}
}
impl DerefMut for NativeLoaderInternal<'_> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self._interface
}
}
impl<'a> LibraryLoaderAPI<'a> for NativeLoaderInternal<'a> {
type InternalLoader = Self;
#[inline]
fn to_interface(&self) -> NonNullConst<LibraryLoaderInterface> {
unsafe { self._interface.as_ref().loader }
}
#[inline]
unsafe fn from_interface(interface: NonNullConst<LibraryLoaderInterface>) -> Self {
NativeLoader::from_interface(interface).get_internal_interface()
}
#[inline]
unsafe fn from_void_ptr(interface: NonNullConst<c_void>) -> Self {
Self {
_interface: interface.cast(),
_phantom: PhantomData,
}
}
#[inline]
unsafe fn load(&mut self, path: &impl AsRef<Path>) -> Result<InternalLibrary<Owned>, Error> {
NativeLoader::from_interface(self.to_interface()).load(path)
}
#[inline]
unsafe fn unload(&mut self, internal: InternalLibrary<Owned>) -> Result<(), Error> {
NativeLoader::from_interface(self.to_interface()).unload(internal)
}
#[inline]
unsafe fn get_data_symbol<O, U>(
&self,
internal: &InternalLibrary<O>,
symbol: &impl AsRef<CStr>,
caster: impl FnOnce(NonNullConst<c_void>) -> &'a U,
) -> Result<Symbol<'a, &'a U>, Error>
where
O: ImmutableAccessIdentifier,
{
NativeLoader::from_interface(self.to_interface()).get_data_symbol(internal, symbol, caster)
}
#[inline]
unsafe fn get_function_symbol<O, U>(
&self,
internal: &InternalLibrary<O>,
symbol: &impl AsRef<CStr>,
caster: impl FnOnce(CBaseFn) -> U,
) -> Result<Symbol<'a, U>, Error>
where
O: ImmutableAccessIdentifier,
{
NativeLoader::from_interface(self.to_interface())
.get_function_symbol(internal, symbol, caster)
}
#[inline]
unsafe fn get_internal_interface(&self) -> Self::InternalLoader {
*self
}
}
impl NativeLoaderInternal<'_> {
#[inline]
#[cfg(unix)]
pub unsafe fn load_ext(
&mut self,
path: &impl AsRef<Path>,
flags: i32,
) -> Result<InternalLibrary<Owned>, Error> {
use crate::ffi::library::library_loader::NativeLibraryLoaderBindingUnix;
let path_buff = path.as_ref().to_os_path_buff_null();
self._interface
.into_mut()
.as_mut()
.load_ext(NonNullConst::from(path_buff.as_slice()), flags)
.to_result()
.map_or_else(|e| Err(Error::FFIError(e)), |v| Ok(InternalLibrary::new(v)))
}
#[inline]
#[cfg(windows)]
pub unsafe fn load_ext(
&mut self,
path: &impl AsRef<Path>,
h_file: Option<NonNull<HANDLE>>,
flags: u32,
) -> Result<InternalLibrary<Owned>, Error> {
use crate::ffi::library::library_loader::NativeLibraryLoaderBindingWindows;
let path_buff = path.as_ref().to_os_path_buff_null();
self._interface
.into_mut()
.as_mut()
.load_ext(NonNullConst::from(path_buff.as_slice()), h_file, flags)
.to_result()
.map_or_else(|e| Err(Error::FFIError(e)), |v| Ok(InternalLibrary::new(v)))
}
#[inline]
pub unsafe fn get_native_handle<O>(
&self,
internal: &InternalLibrary<O>,
) -> Result<NativeLibraryHandle, Error>
where
O: ImmutableAccessIdentifier,
{
#[cfg(unix)]
use crate::ffi::library::library_loader::NativeLibraryLoaderBindingUnix;
#[cfg(windows)]
use crate::ffi::library::library_loader::NativeLibraryLoaderBindingWindows;
self._interface
.as_ref()
.get_native_handle(internal.borrow().as_handle())
.to_result()
.map_err(Error::FFIError)
}
}