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>>;