wolfram_expr/
array_buf.rs1use crate::wxf::NumericArrayEnum;
9use crate::ByteArray;
10
11mod sealed {
15 use crate::complex::{Complex32, Complex64};
16 pub trait Sealed {}
17 impl Sealed for i8 {}
18 impl Sealed for i16 {}
19 impl Sealed for i32 {}
20 impl Sealed for i64 {}
21 impl Sealed for u8 {}
22 impl Sealed for u16 {}
23 impl Sealed for u32 {}
24 impl Sealed for u64 {}
25 impl Sealed for f32 {}
26 impl Sealed for f64 {}
27 impl Sealed for Complex32 {}
28 impl Sealed for Complex64 {}
29}
30
31pub trait ArrayElement<Tag: Copy + PartialEq>: Copy + 'static + sealed::Sealed {
37 const TAG: Tag;
39}
40
41#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
48pub struct ArrayBuf<Tag> {
49 pub(crate) data_type: Tag,
50 pub(crate) dimensions: Vec<usize>,
51 pub(crate) bytes: ByteArray,
52}
53
54impl<Tag: Copy + PartialEq> ArrayBuf<Tag> {
55 pub fn new(data_type: Tag, dimensions: Vec<usize>, bytes: ByteArray) -> Self {
58 ArrayBuf {
59 data_type,
60 dimensions,
61 bytes,
62 }
63 }
64
65 pub fn data_type(&self) -> Tag {
67 self.data_type
68 }
69
70 pub fn dimensions(&self) -> &[usize] {
72 &self.dimensions
73 }
74
75 pub(crate) fn as_bytes(&self) -> &[u8] {
77 &self.bytes
78 }
79
80 pub fn rank(&self) -> usize {
82 self.dimensions.len()
83 }
84
85 pub fn element_count(&self) -> usize {
87 self.dimensions.iter().product()
88 }
89
90
91 pub fn from_slice<T: ArrayElement<Tag>>(dimensions: Vec<usize>, slice: &[T]) -> Self {
94 assert_eq!(
95 dimensions.iter().product::<usize>(),
96 slice.len(),
97 "ArrayBuf::from_slice: dims product must equal slice length"
98 );
99 let bytes: &[u8] = unsafe {
100 std::slice::from_raw_parts(
101 slice.as_ptr() as *const u8,
102 std::mem::size_of_val(slice),
103 )
104 };
105 ArrayBuf::new(T::TAG, dimensions, ByteArray::from(bytes))
106 }
107
108 pub fn try_as_slice<T: ArrayElement<Tag>>(&self) -> Option<&[T]> {
111 if self.data_type != T::TAG {
112 return None;
113 }
114 let bytes = self.as_bytes();
115 let elem_size = std::mem::size_of::<T>();
116 debug_assert_eq!(bytes.len() % elem_size, 0);
117 if bytes.is_empty() {
118 return Some(&[]);
119 }
120 Some(unsafe {
122 std::slice::from_raw_parts(
123 bytes.as_ptr() as *const T,
124 bytes.len() / elem_size,
125 )
126 })
127 }
128}
129
130pub trait NumericArrayRead {
134 fn data_type(&self) -> NumericArrayEnum;
136 fn dimensions(&self) -> &[usize];
138 #[doc(hidden)]
139 fn as_bytes(&self) -> &[u8];
140
141 fn rank(&self) -> usize {
143 self.dimensions().len()
144 }
145 fn element_count(&self) -> usize {
147 self.dimensions().iter().product()
148 }
149 #[doc(hidden)]
150 fn byte_count(&self) -> usize {
151 self.as_bytes().len()
152 }
153 #[doc(hidden)]
154 fn element_size(&self) -> usize {
155 self.data_type().size_in_bytes()
156 }
157
158 fn try_as_slice<T: ArrayElement<NumericArrayEnum>>(&self) -> Option<&[T]> {
160 if self.data_type() != T::TAG {
161 return None;
162 }
163 let bytes = self.as_bytes();
164 let elem_size = std::mem::size_of::<T>();
165 debug_assert_eq!(bytes.len() % elem_size, 0);
166 Some(unsafe {
168 std::slice::from_raw_parts(
169 bytes.as_ptr() as *const T,
170 bytes.len() / elem_size,
171 )
172 })
173 }
174}
175
176impl<Tag: Into<NumericArrayEnum> + Copy + PartialEq> NumericArrayRead for ArrayBuf<Tag> {
177 fn data_type(&self) -> NumericArrayEnum {
178 self.data_type.into()
179 }
180 fn dimensions(&self) -> &[usize] {
181 &self.dimensions
182 }
183 fn as_bytes(&self) -> &[u8] {
184 &self.bytes
185 }
186}