labview_interop/types/array/mod.rs
1//! The arrays module covers LabVIEW multidimensional array.
2//!
3
4mod dimensions;
5#[cfg(feature = "link")]
6mod memory;
7#[cfg(all(feature = "ndarray", target_pointer_width = "64"))]
8mod ndarray;
9
10use crate::labview_layout;
11#[cfg(feature = "link")]
12pub use crate::memory::OwnedUHandle;
13use crate::memory::{LVCopy, UHandle};
14pub use dimensions::LVArrayDims;
15#[cfg(feature = "link")]
16pub use memory::NumericArrayResizable;
17
18labview_layout!(
19 /// Internal LabVIEW array representation.
20 ///
21 /// todo: does this follow cluster packing rules? yes but lots breaks.
22 pub struct LVArray<const D: usize, T> {
23 dim_sizes: LVArrayDims<D>,
24 // For 64 bit use the DST syntax which is more correct to what we
25 // are representing.
26 #[cfg(target_pointer_width = "64")]
27 data: [T],
28 // DST not supported in packing used for 32 bit.
29 #[cfg(target_pointer_width = "32")]
30 data: T,
31 }
32);
33
34impl<const D: usize, T> LVCopy for LVArray<D, T> {}
35
36///implement a basic, unsafe API that works for packed usage on 32 bit targets.
37///
38/// It is copy only as we must copy out of the pointers.
39impl<const D: usize, T> LVArray<D, T> {
40 /// Get the dimensions of the array.
41 #[cfg(target_pointer_width = "32")]
42 pub fn dimension_sizes(&self) -> LVArrayDims<D> {
43 // This 32 bit version must make potentially unaligned accesses in the structure
44 // so this is a little more convoluted.
45 // Because these lead the struct they should infact always be aligned.
46 let mut dimensions = [0i32; D];
47
48 for (index, value) in dimensions.iter_mut().enumerate() {
49 let element_ptr = std::ptr::addr_of!(self.dim_sizes.0[index]);
50 // Safety: the indexes must be in range due to the const generic value.
51 let dim_size = unsafe { std::ptr::read_unaligned(element_ptr) };
52 *value = dim_size;
53 }
54
55 dimensions.into()
56 }
57
58 /// Get the dimensions of the array.
59 #[cfg(target_pointer_width = "64")]
60 pub fn dimension_sizes(&self) -> LVArrayDims<D> {
61 self.dim_sizes
62 }
63
64 /// Get the total number of elements in the array across all dimensions.
65 pub fn element_count(&self) -> usize {
66 self.dimension_sizes().element_count()
67 }
68
69 /// Get the value directly from the array. This is an unsafe method used on
70 /// 32 bit targets where the packed structure means we cannot access a slice.
71 ///
72 /// On 64 bit targets use [`LVArray::data_as_slice`] instead.
73 ///
74 /// # Safety
75 ///
76 /// If the index is out of the range then it is undefined behaviour.
77 pub unsafe fn get_value_unchecked(&self, index: usize) -> T {
78 let data_ptr = std::ptr::addr_of!(self.data) as *const T;
79 let element_ptr = data_ptr.add(index);
80 std::ptr::read_unaligned(element_ptr)
81
82 //self.data[index]`
83 }
84
85 /// Set the value at the index. This is an unsafe method used on 32 bit targets
86 /// where the packed structure means we cannot access a slice.
87 ///
88 /// On 64 bit targets use [`LVArray::data_as_slice_mut`] instead.
89 ///
90 /// # Safety
91 ///
92 /// If the index is out of range then it is undefined behaviour.
93 pub unsafe fn set_value_unchecked(&mut self, index: usize, value: T) {
94 let data_ptr = std::ptr::addr_of_mut!(self.data) as *mut T;
95 let element_ptr = data_ptr.add(index);
96 std::ptr::write_unaligned(element_ptr, value);
97 }
98}
99
100#[cfg(target_pointer_width = "64")]
101impl<const D: usize, T> LVArray<D, T> {
102 /// Get the data component as a slice.
103 ///
104 /// Note: for muti-dimension arrays this is a raw structure so you will
105 /// need to understand the dimenisons and data ordering.
106 ///
107 /// For 1D arrays this can just be used as the data contents.
108 pub fn data_as_slice(&self) -> &[T] {
109 let size = self.element_count();
110 // Safety: Dimensions are set by LabVIEW to be valid.
111 unsafe { std::slice::from_raw_parts(self.data.as_ptr(), size) }
112 }
113
114 /// Get the data component as a mutable slice.
115 ///
116 /// Note: for multi-dimension arrays this is a raw structure so you will
117 /// need to understand the dimensions and data ordering.
118 ///
119 /// For 1D arrays this can just be used as the data contents.
120 pub fn data_as_slice_mut(&mut self) -> &mut [T] {
121 let size = self.element_count();
122 // Safety: Dimensions are set by LabVIEW to be valid.
123 unsafe { std::slice::from_raw_parts_mut(self.data.as_mut_ptr(), size) }
124 }
125}
126
127/// Definition of a handle to an array. Helper for FFI definition.
128pub type LVArrayHandle<'a, const D: usize, T> = UHandle<'a, LVArray<D, T>>;
129
130/// Definition of an owned handle to an array. Helper for FFI definition.
131#[cfg(feature = "link")]
132pub type LVArrayOwned<const D: usize, T> = OwnedUHandle<LVArray<D, T>>;