labview_interop/memory/uptr.rs
1//! A module for working with LabVIEW pointers.
2
3use crate::errors::InternalError;
4use std::ops::{Deref, DerefMut};
5
6/// A pointer from LabVIEW for the data.
7///
8/// In general, these should be avoided in favor of `UHandle` which allows
9/// for more functionality such as resizing types.
10#[repr(transparent)]
11#[derive(PartialEq, Eq, Clone, Copy, Debug)]
12pub struct UPtr<T: ?Sized>(*mut T);
13
14impl<T: ?Sized> UPtr<T> {
15 /// Create a new UPtr from a raw pointer
16 pub fn new(ptr: *mut T) -> Self {
17 Self(ptr)
18 }
19 /// Get a reference to the internal type. Errors if the pointer is null.
20 ///
21 /// # Safety
22 /// This is a wrapper around `pointer::as_ref` and so must follow its safety rules. Namely:
23 ///
24 ///* When calling this method, you have to ensure that either the pointer is null or all of the following is true:
25 ///* The pointer must be properly aligned.
26 ///* It must be "dereferenceable" in the sense defined in [the module documentation].
27 ///* The pointer must point to an initialized instance of T.
28 ///* 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).
29 pub unsafe fn as_ref(&self) -> crate::errors::Result<&T> {
30 self.0.as_ref().ok_or(InternalError::InvalidHandle.into())
31 }
32
33 /// Get a mutable reference to the internal type. Errors if pointer contains a null.
34 ///
35 /// # Safety
36 ///
37 /// This method wraps the `pointer::as_mut` method and so follows its safety rules which require all of the following is true:
38 ///
39 /// * The pointer must be properly aligned.
40 /// * It must be “dereferenceable” in the sense defined in the module documentation.
41 /// * The pointer must point to an initialized instance of T.
42 /// * 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.
43 pub unsafe fn as_ref_mut(&self) -> crate::errors::Result<&mut T> {
44 self.0.as_mut().ok_or(InternalError::InvalidHandle.into())
45 }
46}
47
48impl<T: ?Sized> Deref for UPtr<T> {
49 type Target = T;
50
51 /// Extract the target type.
52 ///
53 /// This will panic if the handle or internal pointer is null.
54 fn deref(&self) -> &Self::Target {
55 unsafe { self.as_ref().unwrap() }
56 }
57}
58
59impl<T: ?Sized> DerefMut for UPtr<T> {
60 /// Deref to a mutable reference.
61 ///
62 /// This will panic if the handle or internal pointer is null.
63 fn deref_mut(&mut self) -> &mut Self::Target {
64 unsafe { self.as_ref_mut().unwrap() }
65 }
66}
67
68/// # Safety
69///
70/// * UPtr memory is managed by the Labview Memory Manager, which is thread safe
71unsafe impl<T: ?Sized> Send for UPtr<T> {}
72unsafe impl<T: ?Sized> Sync for UPtr<T> {}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_uptr() {
80 let mut data = 42;
81 let mut ptr = UPtr(std::ptr::addr_of_mut!(data));
82 assert_eq!(*ptr, 42);
83 *ptr = 43;
84 assert_eq!(*ptr, 43);
85 }
86
87 #[test]
88 fn test_uptr_as_ref() {
89 let mut data = 42;
90 let ptr = UPtr(std::ptr::addr_of_mut!(data));
91 assert_eq!(unsafe { ptr.as_ref() }.unwrap(), &42);
92 }
93
94 #[test]
95 fn test_uptr_as_ref_mut() {
96 let mut data = 42;
97 let ptr = UPtr(std::ptr::addr_of_mut!(data));
98 assert_eq!(unsafe { ptr.as_ref_mut() }.unwrap(), &mut 42);
99 }
100
101 #[test]
102 fn test_uptr_null() {
103 let ptr: UPtr<i32> = UPtr(std::ptr::null_mut());
104 assert!(unsafe { ptr.as_ref() }.is_err());
105 assert!(unsafe { ptr.as_ref_mut() }.is_err());
106 }
107}