labview_interop/types/array/
dimensions.rs1use crate::errors::{InternalError, LVInteropError};
2
3#[repr(transparent)]
4#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5pub struct LVArrayDims<const D: usize>([i32; D]);
6
7impl<const D: usize> LVArrayDims<D> {
8 pub fn new_empty() -> Self {
9 Self([0; D])
10 }
11
12 pub fn shape(&self) -> [i32; D] {
13 self.0
14 }
15 pub fn element_count(&self) -> usize {
16 self.0.iter().fold(1, |size, dim| size * *dim as usize)
17 }
18}
19
20impl<const D: usize> From<[i32; D]> for LVArrayDims<D> {
21 fn from(dim_sizes: [i32; D]) -> Self {
22 Self(dim_sizes)
23 }
24}
25
26impl<const D: usize> TryFrom<&[usize; D]> for LVArrayDims<D> {
27 type Error = LVInteropError;
28
29 fn try_from(value: &[usize; D]) -> Result<Self, Self::Error> {
30 let mut dimensions = [0i32; D];
31
32 for (into, &from) in dimensions.iter_mut().zip(value.iter()) {
33 *into = from
34 .try_into()
35 .map_err(|_| LVInteropError::from(InternalError::ArrayDimensionsOutOfRange))?
36 }
37 Ok(dimensions.into())
38 }
39}
40
41impl<const D: usize> TryFrom<&[usize]> for LVArrayDims<D> {
42 type Error = LVInteropError;
43
44 fn try_from(value: &[usize]) -> Result<Self, Self::Error> {
45 let array: &[usize; D] = value
46 .try_into()
47 .map_err(|_| LVInteropError::from(InternalError::ArrayDimensionMismatch))?;
48 array.try_into()
49 }
50}
51
52impl<const D: usize> From<LVArrayDims<D>> for [usize; D] {
53 fn from(value: LVArrayDims<D>) -> Self {
55 let mut usize_values = [0usize; D];
56 for (output, input) in usize_values.iter_mut().zip(value.0.iter()) {
57 *output = (*input).try_into().expect("Negative dimension size.");
58 }
59 usize_values
60 }
61}
62
63impl LVArrayDims<2> {
65 pub fn rows(&self) -> i32 {
66 self.0[0]
67 }
68
69 pub fn columns(&self) -> i32 {
70 self.0[1]
71 }
72}
73
74impl LVArrayDims<3> {
75 pub fn rows(&self) -> i32 {
76 self.0[1]
77 }
78
79 pub fn columns(&self) -> i32 {
80 self.0[2]
81 }
82
83 pub fn pages(&self) -> i32 {
84 self.0[0]
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn new_dims_empty() {
94 let ref_dims = LVArrayDims::<3>([0, 0, 0]);
95 let dims = LVArrayDims::<3>::new_empty();
96 assert_eq!(dims, ref_dims);
97 assert_eq!(dims.element_count(), 0);
98 }
99
100 #[test]
101 fn dimension_element_count() {
102 let dims = LVArrayDims::<3>([2, 3, 4]);
103 assert_eq!(dims.element_count(), 24);
104
105 let dims = LVArrayDims::<2>([2, 3]);
106 assert_eq!(dims.element_count(), 6);
107
108 let dims = LVArrayDims::<1>([2]);
109 assert_eq!(dims.element_count(), 2);
110 }
111
112 #[test]
113 fn test_dim_equality() {
114 let dims1 = LVArrayDims::<3>([2, 3, 4]);
115 let dims2 = LVArrayDims::<3>([2, 3, 4]);
116 assert_eq!(dims1, dims2);
117 }
118
119 #[test]
120 fn test_dims_from_usize_ok() {
121 let dims = &[1usize, 2usize];
122 let lvdims: LVArrayDims<2> = dims.try_into().unwrap();
123 assert_eq!(lvdims, [1i32, 2].into())
124 }
125
126 #[test]
127 fn test_dims_from_usize_out_of_range() {
128 let dims = &[1usize, i32::MAX as usize + 1];
129 let result: Result<LVArrayDims<2>, _> = dims.try_into();
130
131 let _expected_err: Result<LVArrayDims<2>, _> = Err(LVInteropError::from(
132 InternalError::ArrayDimensionsOutOfRange,
133 ));
134 assert!(matches!(result, _expected_err));
135 }
136
137 #[test]
138 fn test_access_dims() {
139 let dims = LVArrayDims::<2>([2, 3]);
140 assert_eq!(dims.shape(), [2, 3]);
141 }
142
143 #[test]
144 fn test_2d_dim_names() {
145 let dims = LVArrayDims::<2>([2, 3]);
146 assert_eq!(dims.rows(), 2);
147 assert_eq!(dims.columns(), 3);
148 }
149
150 #[test]
151 fn test_3d_dim_names() {
152 let dims = LVArrayDims::<3>([2, 3, 4]);
153 assert_eq!(dims.rows(), 3);
154 assert_eq!(dims.columns(), 4);
155 assert_eq!(dims.pages(), 2);
156 }
157}