labview_interop/memory/uhandle.rs
1use crate::errors::InternalError;
2use std::fmt::Debug;
3use std::marker::PhantomData;
4use std::ops::{Deref, DerefMut};
5
6/// A handle from LabVIEW for the data.
7///
8/// A handle is a double pointer so the underlying
9/// data can be resized and moved.
10///
11/// `Deref` is implemented for this type so you can access the data using `*`
12/// but this can panic if the handle is invalid.
13///
14/// ```
15/// # use labview_interop::memory::UHandle;
16/// fn print_value(handle: UHandle<i32>) {
17/// println!("{}", *handle);
18/// }
19/// ```
20///
21/// If you want to handle the error you can use the `UHandle::as_ref` or `UHandle::as_ref_mut` method.
22#[repr(transparent)]
23#[derive(PartialEq, Eq)]
24pub struct UHandle<'a, T: ?Sized + 'a>(pub *mut *mut T, pub PhantomData<&'a T>);
25
26impl<T: ?Sized> UHandle<'_, T> {
27 /// Get a reference to the internal type. Errors if the pointer is null.
28 ///
29 /// # Safety
30 /// This is a wrapper around `pointer::as_ref` and so must follow its safety rules. Namely:
31 ///
32 ///* When calling this method, you have to ensure that either the pointer is null or all of the following is true:
33 ///* The pointer must be properly aligned.
34 ///* It must be "dereferenceable" in the sense defined in [the module documentation].
35 ///* The pointer must point to an initialized instance of T.
36 ///* You must enforce Rust's aliasing rules, since the returned lifetime 'a is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. In particular, while this reference exists, the memory the pointer points to must not get mutated (except inside UnsafeCell).
37 pub unsafe fn as_ref(&self) -> crate::errors::Result<&T> {
38 self.0
39 .as_ref()
40 .and_then(|ptr| ptr.as_ref())
41 .ok_or(InternalError::InvalidHandle.into())
42 }
43
44 /// Get a mutable reference to the internal type. Errors if handle contains a null.
45 ///
46 /// # Safety
47 ///
48 /// This method wraps the `pointer::as_mut` method and so follows its safety rules which require all of the following is true:
49 ///
50 /// * The pointer must be properly aligned.
51 /// * It must be “dereferenceable” in the sense defined in the module documentation.
52 /// * The pointer must point to an initialized instance of T.
53 /// * You must enforce Rust’s aliasing rules, since the returned lifetime 'a is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. In particular, while this reference exists, the memory the pointer points to must not get accessed (read or written) through any other pointer.
54 pub unsafe fn as_ref_mut(&self) -> crate::errors::Result<&mut T> {
55 self.0
56 .as_ref()
57 .and_then(|ptr| ptr.as_mut())
58 .ok_or(InternalError::InvalidHandle.into())
59 }
60
61 /// Check the validity of the handle to ensure it wont panic later.
62 ///
63 /// A valid handle is:
64 ///
65 /// . Not Null.
66 /// . Points to a pointer.
67 /// . That pointer is in the LabVIEW memory zone.
68 ///
69 /// The last 2 checks are done by LabVIEW and require the `link` feature.
70 ///
71 /// If the `link` feature is not enabled then we just check it is not null.
72 ///
73 /// # Panics/Safety
74 ///
75 /// This will cause a segfault if the handle doesn't point to a valid address.
76 pub fn valid(&self) -> bool {
77 // check if is not NULL
78 let inner_ref = unsafe { self.as_ref() };
79
80 // # Safety
81 //
82 // Make sure we don't call the following function on an invalid pointer
83 if inner_ref.is_err() {
84 return false;
85 }
86 // Only call the API in the link feature.
87 #[cfg(feature = "link")]
88 {
89 // check if the memory manager actually knows about the handle if it is not null
90 let ret = unsafe {
91 crate::labview::memory_api()
92 .unwrap()
93 .check_handle(self.0 as usize)
94 };
95 ret == crate::types::LVStatusCode::SUCCESS
96 }
97 #[cfg(not(feature = "link"))]
98 {
99 return true;
100 }
101 }
102
103 /// Add a from raw method for testing only.
104 #[cfg(test)]
105 pub fn from_raw(ptr: *mut *mut T) -> Self {
106 Self(ptr, PhantomData)
107 }
108}
109
110impl<T: ?Sized> Deref for UHandle<'_, T> {
111 type Target = T;
112
113 /// Extract the target type.
114 ///
115 /// This will panic if the handle or internal pointer is null.
116 fn deref(&self) -> &Self::Target {
117 unsafe { self.as_ref().unwrap() }
118 }
119}
120
121impl<T: ?Sized> DerefMut for UHandle<'_, T> {
122 /// Deref to a mutable reference.
123 ///
124 /// This will panic if the handle or internal pointer is null.
125 fn deref_mut(&mut self) -> &mut Self::Target {
126 unsafe { self.as_ref_mut().unwrap() }
127 }
128}
129
130impl<T: Debug + ?Sized> Debug for UHandle<'_, T> {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 super::fmt_handle("UHandle", self, f)
133 }
134}
135
136#[cfg(feature = "link")]
137mod uhandle_link_features {
138 use super::*;
139 use crate::memory::LVCopy;
140 impl<T: ?Sized> UHandle<'_, T> {
141 /// Resize the handle to the desired size.
142 ///
143 /// # Safety
144 ///
145 /// * The handle must be valid.
146 pub unsafe fn resize(&mut self, desired_size: usize) -> crate::errors::Result<()> {
147 let err = crate::labview::memory_api()?.set_handle_size(self.0 as usize, desired_size);
148 err.to_specific_result(())
149 }
150 }
151
152 impl<T: ?Sized + LVCopy + 'static> UHandle<'_, T> {
153 /// Copy the contents of one handle into another.
154 ///
155 /// If other points to a null value then this will allocate a handle for the contents.
156 ///
157 /// The data in the handle must be `'static` or copy as this will only perform a shallow copy.
158 ///
159 /// # Safety
160 ///
161 /// * If the other pointer is invalid this may cause UB.
162 /// * If the other pointer points to null, you must wrap the value as an owned handle otherwise it will leak memory.
163 ///
164 /// # Examples
165 ///
166 /// ## Allowed Types
167 /// ```no_run
168 /// use labview_interop::labview_layout;
169 /// use labview_interop::memory::{UHandle, OwnedUHandle};
170 /// use labview_interop::types::LStrHandle;
171 ///
172 /// labview_layout! {
173 /// #[derive(Copy, Clone)]
174 /// struct ClusterWithNumbers {
175 /// float: f64,
176 /// int: i32
177 /// }
178 /// }
179 ///
180 /// fn copy_handles(input: UHandle<ClusterWithNumbers>) {
181 /// let cluster = ClusterWithNumbers { float: 3.14, int: 42 };
182 /// let mut new_owned = OwnedUHandle::new(&cluster).unwrap();
183 /// unsafe {
184 /// let mut target_handle = new_owned.handle_to_inner();
185 /// input.clone_into_pointer(&mut target_handle).unwrap();
186 /// }
187 /// }
188 /// ```
189 ///
190 /// ## Lifetime Guarantees - Fails with Sub-Handles
191 /// ```compile_fail,E0521
192 /// use labview_interop::labview_layout;
193 /// use labview_interop::memory::{UHandle, LvOwned};
194 /// use labview_interop::types::LStrHandle;
195 ///
196 /// labview_layout! {
197 /// struct ClusterWithString<'a> {
198 /// string_handle: LStrHandle<'a>,
199 /// int: i32
200 /// }
201 /// }
202 ///
203 /// fn copy_handles(input: UHandle<ClusterWithString>) {
204 /// let mut new_owned = LvOwned::<ClusterWithString>::new().unwrap();
205 /// unsafe {
206 /// let mut target_handle = new_owned.handle_to_inner();
207 /// input.clone_into_pointer(&mut target_handle).unwrap();
208 /// }
209 /// }
210 /// ```
211 /// ## Lifetime Guarantees - Fails with Owned Handle
212 /// ```compile_fail
213 /// use labview_interop::labview_layout;
214 /// use labview_interop::memory::{UHandle, LvOwned};
215 /// use labview_interop::types::LStrOwned;
216 ///
217 /// labview_layout! {
218 /// struct ClusterWithString {
219 /// string_handle: LStrOwned,
220 /// int: i32
221 /// }
222 /// }
223 ///
224 /// fn copy_handles(input: UHandle<ClusterWithString>, mut output: UHandle<ClusterWithString>) {
225 /// unsafe {
226 /// input.clone_into_pointer(&mut output).unwrap();
227 /// }
228 /// }
229 /// ```
230 pub unsafe fn clone_into_pointer(
231 &self,
232 other: *mut UHandle<'_, T>,
233 ) -> crate::errors::Result<()> {
234 // Validate this handle first to improve safety.
235 if !self.valid() {
236 return Err(InternalError::InvalidHandle.into());
237 }
238 let error =
239 crate::labview::memory_api()?.copy_handle(other as *mut usize, self.0 as usize);
240 error.to_specific_result(())
241 }
242 }
243}
244
245/// # Safety
246///
247/// * UHandle memory is managed by the Labview Memory Manager, which is thread safe
248unsafe impl<T: ?Sized> Send for UHandle<'_, T> {}
249unsafe impl<T: ?Sized> Sync for UHandle<'_, T> {}
250
251#[cfg(test)]
252mod tests {
253 use super::*;
254
255 #[test]
256 fn test_handle_debug() {
257 let mut value = 42;
258 let mut value_ptr = std::ptr::addr_of_mut!(value);
259 let handle = UHandle(std::ptr::addr_of_mut!(value_ptr), PhantomData);
260 assert_eq!(format!("{:?}", handle), "UHandle(42)");
261 }
262
263 #[test]
264 fn test_invalid_handle_debug() {
265 let handle = UHandle(std::ptr::null_mut::<*mut i32>(), PhantomData);
266 assert_eq!(format!("{:?}", handle), "UHandle(Invalid)");
267 }
268
269 #[test]
270 fn test_handle_debug_inner_from_reference() {
271 let mut value = 42;
272 let mut value_ptr = std::ptr::addr_of_mut!(value);
273 let handle = UHandle(std::ptr::addr_of_mut!(value_ptr), PhantomData);
274 assert_eq!(format!("{:?}", *handle), "42");
275 }
276
277 #[test]
278 fn test_handle_deref() {
279 let mut value = 42;
280 let mut value_ptr = std::ptr::addr_of_mut!(value);
281 let handle = UHandle(std::ptr::addr_of_mut!(value_ptr), PhantomData);
282 assert_eq!(*handle, 42);
283 }
284
285 #[test]
286 fn test_handle_deref_mut() {
287 let mut value = 42;
288 let mut value_ptr = std::ptr::addr_of_mut!(value);
289 let mut handle = UHandle(std::ptr::addr_of_mut!(value_ptr), PhantomData);
290 *handle = 43;
291 assert_eq!(*handle, 43);
292 }
293
294 #[test]
295 fn handle_as_ref_valid() {
296 let mut value = 42;
297 let mut value_ptr = std::ptr::addr_of_mut!(value);
298 let handle = UHandle(std::ptr::addr_of_mut!(value_ptr), PhantomData);
299 assert_eq!(unsafe { handle.as_ref() }.unwrap(), &42);
300 }
301
302 #[test]
303 fn handle_as_ref_outer_null() {
304 let handle = UHandle(std::ptr::null_mut::<*mut i32>(), PhantomData);
305 assert!(unsafe { handle.as_ref() }.is_err());
306 }
307
308 #[test]
309 fn handle_as_ref_inner_null() {
310 let mut inner_ptr = std::ptr::null_mut::<i32>();
311 let handle = UHandle(std::ptr::addr_of_mut!(inner_ptr), PhantomData);
312 assert!(unsafe { handle.as_ref() }.is_err());
313 }
314
315 #[test]
316 fn handle_as_ref_mut_valid() {
317 let mut value = 42;
318 let mut value_ptr = std::ptr::addr_of_mut!(value);
319 let handle = UHandle(std::ptr::addr_of_mut!(value_ptr), PhantomData);
320 assert_eq!(unsafe { handle.as_ref_mut() }.unwrap(), &mut 42);
321 }
322
323 #[test]
324 fn handle_as_ref_mut_outer_null() {
325 let handle = UHandle(std::ptr::null_mut::<*mut i32>(), PhantomData);
326 assert!(unsafe { handle.as_ref_mut() }.is_err());
327 }
328
329 #[test]
330 fn handle_as_ref_mut_inner_null() {
331 let mut inner_ptr = std::ptr::null_mut::<i32>();
332 let handle = UHandle(std::ptr::addr_of_mut!(inner_ptr), PhantomData);
333 assert!(unsafe { handle.as_ref_mut() }.is_err());
334 }
335
336 #[test]
337 fn handle_valid_check_false_if_null() {
338 let handle = UHandle(std::ptr::null_mut::<*mut i32>(), PhantomData);
339 assert!(!handle.valid());
340 }
341
342 #[cfg(not(feature = "link"))]
343 #[test]
344 fn handle_valid_check_is_valid_no_link() {
345 let mut value = 42;
346 let mut value_ptr = std::ptr::addr_of_mut!(value);
347 let handle = UHandle(std::ptr::addr_of_mut!(value_ptr), PhantomData);
348 assert!(handle.valid());
349 }
350}