use std::ffi::c_void;
use std::sync::LazyLock;
use dlopen2::wrapper::{Container, WrapperApi};
use crate::errors::LVInteropError;
use crate::{
errors::{InternalError, Result},
memory::MagicCookie,
types::LVStatusCode,
};
const LVRT_PATH: &str = "lvrt";
fn load_container<T: WrapperApi>() -> Result<Container<T>> {
let self_result = unsafe {
Container::load_self()
.map_err(|e| LVInteropError::InternalError(InternalError::NoLabviewApi(e.to_string())))
};
match self_result {
Ok(container) => Ok(container),
Err(_) => {
unsafe {
Container::load(LVRT_PATH).map_err(|e| {
LVInteropError::InternalError(InternalError::NoLabviewApi(e.to_string()))
})
}
}
}
}
pub(crate) type UHandleValue = usize;
pub(crate) type UPtrValue = usize;
static SYNC_API: LazyLock<Result<Container<SyncApi>>> = LazyLock::new(load_container);
pub fn sync_api() -> Result<&'static Container<SyncApi>> {
SYNC_API.as_ref().map_err(|e| e.clone())
}
static MEMORY_API: LazyLock<Result<Container<MemoryApi>>> = LazyLock::new(|| {
let result = load_container::<MemoryApi>();
if let Err(e) = &result {
eprintln!("Failed to load LabVIEW Memory Manager API: {e}");
}
result
});
pub fn memory_api() -> Result<&'static Container<MemoryApi>> {
MEMORY_API.as_ref().map_err(|e| e.clone())
}
#[derive(WrapperApi)]
pub struct SyncApi {
#[dlopen2_name = "PostLVUserEvent"]
post_lv_user_event:
unsafe extern "C" fn(reference: MagicCookie, data: *mut c_void) -> LVStatusCode,
#[dlopen2_name = "Occur"]
occur: unsafe extern "C" fn(occurance: MagicCookie) -> LVStatusCode,
}
#[derive(WrapperApi)]
pub struct MemoryApi {
#[dlopen2_name = "DSCheckHandle"]
check_handle: unsafe extern "C" fn(handle: UHandleValue) -> LVStatusCode,
#[dlopen2_name = "DSCheckPtr"]
check_ptr: unsafe extern "C" fn(ptr: UPtrValue) -> LVStatusCode,
#[dlopen2_name = "DSNewHandle"]
new_handle: unsafe extern "C" fn(size: usize) -> *mut *mut std::ffi::c_void,
#[dlopen2_name = "DSCopyHandle"]
copy_handle: unsafe extern "C" fn(ph: *mut UHandleValue, hsrc: UHandleValue) -> LVStatusCode,
#[dlopen2_name = "DSDisposeHandle"]
dispose_handle: unsafe extern "C" fn(handle: UHandleValue) -> LVStatusCode,
#[dlopen2_name = "DSSetHandleSize"]
set_handle_size: unsafe extern "C" fn(handle: UHandleValue, size: usize) -> LVStatusCode,
#[dlopen2_name = "NIGetOneErrorCode"]
error_code_description:
unsafe extern "C" fn(error_code: i32, error_text: *mut UHandleValue) -> bool,
#[dlopen2_name = "NumericArrayResize"]
numeric_array_resize: unsafe extern "C" fn(
type_code: i32,
number_of_dims: i32,
handle_ptr: *mut UHandleValue,
total_new_size: usize,
) -> LVStatusCode,
}