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}