#![allow(non_camel_case_types, non_snake_case, clippy::missing_safety_doc)]
#[rustfmt::skip]
mod generated;
pub use generated::*;
use std::path::{Path, PathBuf};
use std::sync::OnceLock;
use crate::loader::{self, LoadError};
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct daqIntfID {
pub Data1: u32,
pub Data2: u16,
pub Data3: u16,
pub Data4: u64,
}
struct Loaded {
api: &'static Api,
directory: PathBuf,
}
static LOADED: OnceLock<Result<Loaded, LoadError>> = OnceLock::new();
fn load(directory_override: Option<&Path>) -> Result<Loaded, LoadError> {
let directory = match directory_override {
Some(dir) => dir.to_path_buf(),
None => loader::native_library_directory()?,
};
let loaded = loader::load_from(&directory)?;
let api = Api::resolve(&loaded.libraries)?;
std::mem::forget(loaded.libraries);
Ok(Loaded {
api: Box::leak(Box::new(api)),
directory,
})
}
pub fn initialize() -> Result<&'static Api, LoadError> {
match LOADED.get_or_init(|| load(None)) {
Ok(loaded) => Ok(loaded.api),
Err(e) => Err(e.clone()),
}
}
pub fn initialize_from(directory: &Path) -> Result<&'static Api, LoadError> {
let result = LOADED.get_or_init(|| load(Some(directory)));
match result {
Ok(loaded) => {
if loaded.directory != directory {
return Err(LoadError::LibraryLoadFailed {
library: directory.to_path_buf(),
reason: format!(
"openDAQ native libraries are already loaded from {} and cannot be \
reloaded in the same process",
loaded.directory.display()
),
});
}
Ok(loaded.api)
}
Err(e) => Err(e.clone()),
}
}
pub fn api() -> &'static Api {
match initialize() {
Ok(api) => api,
Err(e) => panic!("failed to load the openDAQ native libraries: {e}"),
}
}
pub fn native_library_directory() -> Result<PathBuf, LoadError> {
match LOADED.get_or_init(|| load(None)) {
Ok(loaded) => Ok(loaded.directory.clone()),
Err(e) => Err(e.clone()),
}
}