use std::ffi::c_void;
use std::ptr::NonNull;
use crate::error::{check, Error, Result};
use crate::sys::{self, daqIntfID};
pub(crate) struct Ref {
ptr: NonNull<c_void>,
}
unsafe impl Send for Ref {}
unsafe impl Sync for Ref {}
impl Ref {
pub(crate) unsafe fn from_owned(ptr: *mut c_void) -> Option<Ref> {
NonNull::new(ptr).map(|ptr| Ref { ptr })
}
pub(crate) unsafe fn from_borrowed(ptr: *mut c_void) -> Option<Ref> {
let ptr = NonNull::new(ptr)?;
(sys::api().daqBaseObject_addRef)(ptr.as_ptr());
Some(Ref { ptr })
}
pub(crate) fn as_ptr(&self) -> *mut c_void {
self.ptr.as_ptr()
}
pub(crate) fn into_raw(self) -> *mut c_void {
let ptr = self.ptr.as_ptr();
std::mem::forget(self);
ptr
}
}
impl Clone for Ref {
fn clone(&self) -> Ref {
unsafe { (sys::api().daqBaseObject_addRef)(self.ptr.as_ptr()) };
Ref { ptr: self.ptr }
}
}
impl Drop for Ref {
fn drop(&mut self) {
unsafe { (sys::api().daqBaseObject_releaseRef)(self.ptr.as_ptr()) };
}
}
impl std::fmt::Debug for Ref {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:p}", self.ptr.as_ptr())
}
}
#[repr(transparent)]
#[derive(Clone, Debug)]
pub struct BaseObject(pub(crate) Ref);
pub unsafe trait Interface: Sized + crate::sealed::Sealed {
const NAME: &'static str;
fn interface_id() -> Option<daqIntfID>;
unsafe fn from_raw(ptr: *mut c_void) -> Option<Self>;
fn as_raw(&self) -> *mut c_void {
self.as_base_object().0.as_ptr()
}
fn as_base_object(&self) -> &BaseObject;
fn to_base_object(&self) -> BaseObject {
BaseObject(self.as_base_object().0.clone())
}
}
impl crate::sealed::Sealed for BaseObject {}
unsafe impl Interface for BaseObject {
const NAME: &'static str = "daqBaseObject";
fn interface_id() -> Option<daqIntfID> {
None
}
unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
Ref::from_owned(ptr).map(BaseObject)
}
fn as_base_object(&self) -> &BaseObject {
self
}
}
impl BaseObject {
pub fn cast<T: Interface>(&self) -> Result<T> {
match T::interface_id() {
Some(id) => {
let mut out: *mut c_void = std::ptr::null_mut();
check(
unsafe {
(sys::api().daqBaseObject_queryInterface)(self.0.as_ptr(), id, &mut out)
},
"daqBaseObject_queryInterface",
)?;
unsafe { T::from_raw(out) }.ok_or_else(|| {
Error::new(
sys::OPENDAQ_ERR_NOINTERFACE,
"daqBaseObject_queryInterface",
None,
)
})
}
None => {
let cloned = self.0.clone();
Ok(unsafe { T::from_raw(cloned.into_raw()) }.expect("non-null by construction"))
}
}
}
pub fn try_cast<T: Interface>(&self) -> Option<T> {
self.cast().ok()
}
pub fn is_a<T: Interface>(&self) -> bool {
let Some(id) = T::interface_id() else {
return false;
};
let mut out: *mut c_void = std::ptr::null_mut();
let code =
unsafe { (sys::api().daqBaseObject_borrowInterface)(self.0.as_ptr(), id, &mut out) };
!crate::error::failure_code(code) && !out.is_null()
}
pub fn hash_code(&self) -> Result<usize> {
let mut out: usize = 0;
check(
unsafe { (sys::api().daqBaseObject_getHashCode)(self.0.as_ptr(), &mut out) },
"daqBaseObject_getHashCode",
)?;
Ok(out)
}
pub fn equals<T: Interface>(&self, other: &T) -> Result<bool> {
let mut out: u8 = 0;
check(
unsafe { (sys::api().daqBaseObject_equals)(self.0.as_ptr(), other.as_raw(), &mut out) },
"daqBaseObject_equals",
)?;
Ok(out != 0)
}
pub fn ptr_eq<T: Interface>(&self, other: &T) -> bool {
self.0.as_ptr() == other.as_raw()
}
pub fn dispose(&self) -> Result<()> {
check(
unsafe { (sys::api().daqBaseObject_dispose)(self.0.as_ptr()) },
"daqBaseObject_dispose",
)
}
pub fn new() -> Result<BaseObject> {
let mut out: *mut c_void = std::ptr::null_mut();
check(
unsafe { (sys::api().daqBaseObject_create)(&mut out) },
"daqBaseObject_create",
)?;
unsafe { BaseObject::from_raw(out) }
.ok_or_else(|| Error::new(sys::OPENDAQ_ERR_GENERALERROR, "daqBaseObject_create", None))
}
}
impl std::fmt::Display for BaseObject {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut chars: *mut std::ffi::c_char = std::ptr::null_mut();
let code = unsafe { (sys::api().daqBaseObject_toString)(self.0.as_ptr(), &mut chars) };
if crate::error::failure_code(code) || chars.is_null() {
return write!(f, "<openDAQ object {:?}>", self.0);
}
let text = unsafe { std::ffi::CStr::from_ptr(chars) }
.to_string_lossy()
.into_owned();
unsafe { (sys::api().daqFreeMemory)(chars as *mut c_void) };
f.write_str(&text)
}
}