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}