#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]
#![allow(clippy::all)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
#[cfg(not(feature = "runtime-linking"))]
unsafe extern "C" {
pub fn aic_set_sdk_wrapper_id(id: u32);
}
#[cfg(feature = "runtime-linking")]
mod runtime_linking {
use super::*;
use libloading::Library;
use std::{
fmt,
path::{Path, PathBuf},
sync::OnceLock,
};
static AIC_LIBRARY: OnceLock<LoadedLibrary> = OnceLock::new();
#[derive(Debug)]
pub enum DynamicLoadingError {
AlreadyLoaded,
OpenLibrary {
path: PathBuf,
source: libloading::Error,
},
LoadSymbol {
symbol: &'static str,
source: libloading::Error,
},
}
impl fmt::Display for DynamicLoadingError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::AlreadyLoaded => write!(f, "the AIC dynamic library is already loaded"),
Self::OpenLibrary { path, source } => write!(
f,
"failed to load AIC dynamic library '{}': {source}",
path.display()
),
Self::LoadSymbol { symbol, source } => {
write!(f, "failed to load AIC symbol '{symbol}': {source}")
}
}
}
}
impl std::error::Error for DynamicLoadingError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::AlreadyLoaded => None,
Self::OpenLibrary { source, .. } | Self::LoadSymbol { source, .. } => Some(source),
}
}
}
struct LoadedLibrary {
_library: Library,
symbols: Symbols,
}
impl LoadedLibrary {
unsafe fn load(path: &Path) -> Result<Self, DynamicLoadingError> {
let library = unsafe { Library::new(path) }.map_err(|source| {
DynamicLoadingError::OpenLibrary {
path: path.to_path_buf(),
source,
}
})?;
let symbols = unsafe { Symbols::load(&library)? };
Ok(Self {
_library: library,
symbols,
})
}
}
fn symbols() -> &'static Symbols {
&AIC_LIBRARY
.get_or_init(|| {
let name = libloading::library_filename("aic");
unsafe { LoadedLibrary::load(Path::new(&name)) }.unwrap_or_else(|err| {
panic!(
"{err}. Make it discoverable on the dynamic loader search path (e.g. \
LD_LIBRARY_PATH, rpath, or a system install), or call \
`aic_sdk_sys::load_library` with an explicit path before using the SDK."
)
})
})
.symbols
}
macro_rules! aic_symbols {
($(
fn $name:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret:ty)?;
)+) => {
struct Symbols {
$(
$name: unsafe extern "C" fn($($arg_ty),*) $(-> $ret)?,
)+
}
impl Symbols {
unsafe fn load(library: &Library) -> Result<Self, DynamicLoadingError> {
$(
let $name = *unsafe {
library.get(concat!(stringify!($name), "\0").as_bytes())
}
.map_err(|source| DynamicLoadingError::LoadSymbol {
symbol: stringify!($name),
source,
})?;
)+
Ok(Self { $($name,)+ })
}
}
$(
pub unsafe fn $name($($arg: $arg_ty),*) $(-> $ret)? {
unsafe { (symbols().$name)($($arg),*) }
}
)+
};
}
include!(concat!(env!("OUT_DIR"), "/runtime_symbols.rs"));
pub unsafe fn load_library<P: AsRef<Path>>(path: P) -> Result<(), DynamicLoadingError> {
let loaded = unsafe { LoadedLibrary::load(path.as_ref())? };
AIC_LIBRARY
.set(loaded)
.map_err(|_| DynamicLoadingError::AlreadyLoaded)
}
pub fn is_library_loaded() -> bool {
AIC_LIBRARY.get().is_some()
}
}
#[cfg(feature = "runtime-linking")]
pub use runtime_linking::*;