labview_interop/memory/
owned_handle.rs

1use std::fmt::Debug;
2use std::marker::PhantomData;
3use std::ops::{Deref, DerefMut};
4
5use super::{LVCopy, UHandle};
6use crate::errors::{InternalError, Result};
7use crate::labview::memory_api;
8
9/// A value allocated in the LabVIEW memory managed by Rust.
10///
11/// This will manage the lifetime and free the handle on drop.
12///
13/// This is a semantic difference from handle and is transparent with the handle data.
14///
15/// This means it can be used in structs in place of a handle.
16///
17/// # Example In Struct ([LStrOwned](crate::types::LStrOwned) is equivalent of [`OwnedUHandle<LStr>`]).
18/// ```no_run
19///# use labview_interop::labview_layout;
20///# use labview_interop::types::LStrOwned;
21///labview_layout!(
22///pub struct UserEventCluster {
23///    eventno: i32,
24///    id: LStrOwned,
25///}
26///);
27///```
28/// # From a Handle
29///
30/// You can convert a handle to an owned value using the [`UHandle::try_to_owned`] method.
31///
32/// The type must be [`LVCopy`] to ensure it is safe to copy the internal data.
33///
34/// ## Example
35/// ```no_run
36/// use labview_interop::types::{LStrHandle, LStrOwned};
37///
38/// fn handle_to_owned(handle: LStrHandle) -> LStrOwned {
39///    handle.try_to_owned().unwrap()
40/// }
41/// ```
42///
43/// # Clone
44///
45/// Clone is implemented but can panic if there is not enough memory to create the new handle.
46///
47/// There is also a [`OwnedUHandle::try_clone`] method which will return a Result.
48///
49/// The type must be [`LVCopy`] to ensure it is safe to clone.
50///
51///
52#[repr(transparent)]
53pub struct OwnedUHandle<T: ?Sized + 'static>(UHandle<'static, T>);
54
55impl<T: Copy + 'static> OwnedUHandle<T> {
56    /// Create a new handle to a sized value of `T`.
57    ///
58    /// It will copy the data from the provided value.
59    pub fn new(value: &T) -> Result<Self> {
60        let handle = unsafe { memory_api()?.new_handle(std::mem::size_of::<T>()) } as *mut *mut T;
61
62        if handle.is_null() {
63            Err(InternalError::HandleCreationFailed.into())
64        } else {
65            // Copy the value into the handle.
66            // # Safety - these pointers have just been created by the memory manager and we checked null.
67            unsafe {
68                **handle = *value;
69            }
70            Ok(Self(UHandle(handle, PhantomData)))
71        }
72    }
73}
74
75impl<T: ?Sized> OwnedUHandle<T> {
76    /// Create a new handle to the type `T`. It will create an empty handle
77    /// which you must initialise with the `init_routine`.
78    /// This is useful for unsized types.
79    ///
80    /// # Safety
81    ///
82    /// * This will create a handle to un-initialized memory. The provided initialisation
83    ///   routine must prepare the memory.
84    pub(crate) unsafe fn new_unsized(
85        init_routine: impl FnOnce(&mut UHandle<'static, T>) -> Result<()>,
86    ) -> Result<Self> {
87        let handle = memory_api()?.new_handle(0);
88        if handle.is_null() {
89            Err(InternalError::HandleCreationFailed.into())
90        } else {
91            let mut new_value = UHandle(handle as *mut *mut T, PhantomData);
92            init_routine(&mut new_value)?;
93            Ok(Self(new_value))
94        }
95    }
96
97    /// Return a new handle to the inner value.
98    ///
99    /// This takes a mutable borrow on the owned value as you can use the handle
100    /// to modify the inner value.
101    ///
102    /// Note: This is only if you need a true handle to put into a structure that is expecting this.
103    /// Better options are :
104    /// * If you can define the type, just define it with the owned value. An owned value can take the place of a handle.
105    /// * If you just need access to the data then use the Deref methods to access the handle.
106    ///
107    /// # Safety
108    ///
109    /// * This needs to take a mutable reference to self and lifetime annotation on UHandle,
110    ///   to avoid creating multiple UHandles.
111    ///
112    /// # Examples
113    ///
114    /// ## Use Handle in Struct
115    ///
116    /// ```no_run
117    /// use labview_interop::types::{LStrHandle, LStrOwned};
118    /// use labview_interop::labview_layout;
119    ///
120    /// // This must have a handle due to other uses.
121    /// labview_layout! {
122    ///   struct ClusterWithString<'a> {
123    ///     string_handle: LStrHandle<'a>
124    ///   }
125    /// }
126    ///
127    /// // Mutable is required since once you have a handle you can mutate the data.
128    /// let mut owned_string = LStrOwned::from_data(b"Hello World!").unwrap();
129    /// let handle = owned_string.handle_to_inner();
130    /// let cluster = ClusterWithString {
131    ///   string_handle: handle
132    /// };
133    /// // Do something with the cluster.
134    ///
135    /// ```
136    ///
137    /// ## Lifetime Guarantees - Single Handle
138    /// ```compile_fail,E0515
139    /// use labview_interop::memory::LvOwned;
140    ///
141    /// let mut owned = LvOwned::<f64>::new().unwrap();
142    /// let mut handle = owned.handle_to_inner();
143    /// // Cannot get a second handle due to lifetime.
144    /// // This fails to compile.
145    /// let handle2 = owned.handle_to_inner();
146    ///
147    /// *handle = 1.0;
148    ///
149    /// ```
150    ///
151    /// ## Lifetime Guarantees - Owned Outlives Handle
152    ///
153    /// ```compile_fail,E0515
154    /// use labview_interop::memory::LvOwned;
155    ///
156    /// let mut owned = LvOwned::<f64>::new().unwrap();
157    /// let mut handle = owned.handle_to_inner();
158    /// // Cannot drop owned because we have a handle.
159    /// // This fails to compile.
160    /// drop(owned);
161    ///
162    /// *handle = 1.0;
163    ///
164    /// ```
165    pub fn handle_to_inner(&mut self) -> UHandle<'_, T> {
166        UHandle(self.0 .0, PhantomData)
167    }
168}
169
170impl<T: ?Sized> Deref for OwnedUHandle<T> {
171    type Target = UHandle<'static, T>;
172
173    fn deref(&self) -> &Self::Target {
174        &self.0
175    }
176}
177
178impl<T: ?Sized> DerefMut for OwnedUHandle<T> {
179    fn deref_mut(&mut self) -> &mut Self::Target {
180        &mut self.0
181    }
182}
183
184impl<T: ?Sized> Drop for OwnedUHandle<T> {
185    fn drop(&mut self) {
186        let result = memory_api().map(|api| unsafe {
187            api.dispose_handle(self.0 .0 as usize)
188                .to_specific_result(())
189        });
190        if let Err(e) | Ok(Err(e)) = result {
191            println!("Error freeing handle from LV: {e}");
192        }
193    }
194}
195
196impl<T: Debug + ?Sized> Debug for OwnedUHandle<T> {
197    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198        super::fmt_handle("LvOwned", &self.0, f)
199    }
200}
201
202impl<T: ?Sized + LVCopy + 'static> OwnedUHandle<T> {
203    /// Try to clone the handle.
204    ///
205    /// This will create a new handle to the same data.
206    ///
207    /// # Errors
208    ///
209    /// * If there is not enough memory to create the handle this may error.
210    pub fn try_clone(&self) -> Result<Self> {
211        // Safety - The handle should be valid because it is an owned handle.
212        // Safety - The initialisation function will initialise the data or error.
213        unsafe {
214            OwnedUHandle::new_unsized(|handle| {
215                self.clone_into_pointer(handle as *mut UHandle<'static, T>)
216            })
217        }
218    }
219}
220
221impl<T: ?Sized + LVCopy + 'static> UHandle<'_, T> {
222    /// Try to create an owned handle from the current handle.
223    ///
224    /// The owned handle will have its own handle to the data and
225    /// will be responsible for freeing it.
226    ///
227    /// # Errors
228    ///
229    /// * If there is not enough memory to create the handle this may error.
230    /// * If the source handle is not valid this will error.
231    pub fn try_to_owned(&self) -> Result<OwnedUHandle<T>> {
232        // Safety - The clone_into_pointer will check the handle is valid.
233        // Safety - The initialisation function will initialise the data or error.
234        unsafe {
235            OwnedUHandle::new_unsized(|handle| {
236                self.clone_into_pointer(handle as *mut UHandle<'static, T>)
237            })
238        }
239    }
240}
241
242impl<T: ?Sized + LVCopy + 'static> Clone for OwnedUHandle<T> {
243    fn clone(&self) -> Self {
244        self.try_clone().unwrap()
245    }
246}
247
248/// # Safety
249///
250/// * LvOwned memory is access through UHandle which is managed by the Labview Memory Manager, which is thread safe
251unsafe impl<T: ?Sized> Send for OwnedUHandle<T> {}
252unsafe impl<T: ?Sized> Sync for OwnedUHandle<T> {}
253
254#[cfg(test)]
255mod tests {
256    use super::*;
257
258    #[test]
259    fn test_lvowned_debug() {
260        let mut value = 42;
261        let mut value_ptr = std::ptr::addr_of_mut!(value);
262        let handle = UHandle(std::ptr::addr_of_mut!(value_ptr), std::marker::PhantomData);
263        let owned = OwnedUHandle(handle);
264        assert_eq!(format!("{:?}", owned), "LvOwned(42)");
265    }
266}