use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use super::{LVCopy, UHandle};
use crate::errors::{InternalError, Result};
use crate::labview::memory_api;
#[repr(transparent)]
pub struct OwnedUHandle<T: ?Sized + 'static>(UHandle<'static, T>);
impl<T: Copy + 'static> OwnedUHandle<T> {
pub fn new(value: &T) -> Result<Self> {
let handle = unsafe { memory_api()?.new_handle(std::mem::size_of::<T>()) } as *mut *mut T;
if handle.is_null() {
Err(InternalError::HandleCreationFailed.into())
} else {
unsafe {
**handle = *value;
}
Ok(Self(UHandle(handle, PhantomData)))
}
}
}
impl<T: ?Sized> OwnedUHandle<T> {
pub(crate) unsafe fn new_unsized(
init_routine: impl FnOnce(&mut UHandle<'static, T>) -> Result<()>,
) -> Result<Self> {
let handle = memory_api()?.new_handle(0);
if handle.is_null() {
Err(InternalError::HandleCreationFailed.into())
} else {
let mut new_value = UHandle(handle as *mut *mut T, PhantomData);
init_routine(&mut new_value)?;
Ok(Self(new_value))
}
}
pub fn handle_to_inner(&mut self) -> UHandle<'_, T> {
UHandle(self.0 .0, PhantomData)
}
}
impl<T: ?Sized> Deref for OwnedUHandle<T> {
type Target = UHandle<'static, T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: ?Sized> DerefMut for OwnedUHandle<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T: ?Sized> Drop for OwnedUHandle<T> {
fn drop(&mut self) {
let result = memory_api().map(|api| unsafe {
api.dispose_handle(self.0 .0 as usize)
.to_specific_result(())
});
if let Err(e) | Ok(Err(e)) = result {
println!("Error freeing handle from LV: {e}");
}
}
}
impl<T: Debug + ?Sized> Debug for OwnedUHandle<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
super::fmt_handle("LvOwned", &self.0, f)
}
}
impl<T: ?Sized + LVCopy + 'static> OwnedUHandle<T> {
pub fn try_clone(&self) -> Result<Self> {
unsafe {
OwnedUHandle::new_unsized(|handle| {
self.clone_into_pointer(handle as *mut UHandle<'static, T>)
})
}
}
}
impl<T: ?Sized + LVCopy + 'static> UHandle<'_, T> {
pub fn try_to_owned(&self) -> Result<OwnedUHandle<T>> {
unsafe {
OwnedUHandle::new_unsized(|handle| {
self.clone_into_pointer(handle as *mut UHandle<'static, T>)
})
}
}
}
impl<T: ?Sized + LVCopy + 'static> Clone for OwnedUHandle<T> {
fn clone(&self) -> Self {
self.try_clone().unwrap()
}
}
unsafe impl<T: ?Sized> Send for OwnedUHandle<T> {}
unsafe impl<T: ?Sized> Sync for OwnedUHandle<T> {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lvowned_debug() {
let mut value = 42;
let mut value_ptr = std::ptr::addr_of_mut!(value);
let handle = UHandle(std::ptr::addr_of_mut!(value_ptr), std::marker::PhantomData);
let owned = OwnedUHandle(handle);
assert_eq!(format!("{:?}", owned), "LvOwned(42)");
}
}