use std::ffi::c_void;
use crate::sys;
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug, Clone, thiserror::Error)]
#[error("openDAQ call {operation} failed with {} (0x{code:08X}){}",
self.name().unwrap_or("an unknown error"),
self.message.as_deref().map(|m| format!(": {m}")).unwrap_or_default())]
pub struct Error {
code: u32,
operation: &'static str,
message: Option<String>,
}
impl Error {
pub(crate) fn new(code: u32, operation: &'static str, message: Option<String>) -> Self {
Error {
code,
operation,
message,
}
}
pub fn code(&self) -> u32 {
self.code
}
pub fn name(&self) -> Option<&'static str> {
sys::error_code_name(self.code)
}
pub fn operation(&self) -> &'static str {
self.operation
}
pub fn message(&self) -> Option<&str> {
self.message.as_deref()
}
pub fn is(&self, code: u32) -> bool {
self.code == code
}
pub fn is_reader_invalidated(&self) -> bool {
self.operation == crate::readers::READER_INVALIDATED_OPERATION
}
}
pub(crate) fn failure_code(code: u32) -> bool {
code & 0x8000_0000 != 0
}
fn last_error_message() -> Option<String> {
let api = sys::api();
let mut message: *mut sys::daqString = std::ptr::null_mut();
let stored = unsafe { (api.daqGetErrorInfoMessage)(&mut message) };
if !failure_code(stored) || message.is_null() {
return None;
}
let mut chars: *const std::ffi::c_char = std::ptr::null();
let err = unsafe { (api.daqString_getCharPtr)(message, &mut chars) };
let result = if failure_code(err) || chars.is_null() {
None
} else {
Some(
unsafe { std::ffi::CStr::from_ptr(chars) }
.to_string_lossy()
.into_owned(),
)
};
unsafe { (api.daqBaseObject_releaseRef)(message as *mut c_void) };
result
}
pub(crate) fn check(code: u32, operation: &'static str) -> Result<()> {
if failure_code(code) {
Err(Error::new(code, operation, last_error_message()))
} else {
Ok(())
}
}
pub fn clear_error_info() {
unsafe { (sys::api().daqClearErrorInfo)() }
}