1use bytemuck::{cast_slice, cast_vec, try_cast_vec};
2
3use crate::data_type::DataType;
4use crate::error::{AsyncTiffError, AsyncTiffResult};
5
6#[derive(Debug, Clone)]
8pub struct Array {
9 pub(crate) data: TypedArray,
11
12 pub(crate) shape: [usize; 3],
19
20 pub(crate) data_type: Option<DataType>,
24}
25
26impl Array {
27 pub(crate) fn try_new(
28 data: Vec<u8>,
29 shape: [usize; 3],
30 data_type: Option<DataType>,
31 ) -> AsyncTiffResult<Self> {
32 let expected_len = shape[0] * shape[1] * shape[2];
34
35 let typed_data = TypedArray::try_new(data, data_type)?;
36 if typed_data.len() != expected_len {
37 return Err(AsyncTiffError::General(format!("Internal error: incorrect shape or data length passed to Array::try_new. Got data length {}, expected {}", typed_data.len(), expected_len)));
38 }
39
40 Ok(Self {
41 data: typed_data,
42 shape,
43 data_type,
44 })
45 }
46
47 pub fn data(&self) -> &TypedArray {
49 &self.data
50 }
51
52 pub fn into_inner(self) -> (TypedArray, [usize; 3], Option<DataType>) {
54 (self.data, self.shape, self.data_type)
55 }
56
57 pub fn shape(&self) -> [usize; 3] {
65 self.shape
66 }
67
68 pub fn data_type(&self) -> Option<DataType> {
72 self.data_type
73 }
74}
75
76#[derive(Debug, Clone)]
95pub enum TypedArray {
96 UInt8(Vec<u8>),
98 UInt16(Vec<u16>),
100 UInt32(Vec<u32>),
102 UInt64(Vec<u64>),
104 Int8(Vec<i8>),
106 Int16(Vec<i16>),
108 Int32(Vec<i32>),
110 Int64(Vec<i64>),
112 Float32(Vec<f32>),
114 Float64(Vec<f64>),
116}
117
118impl TypedArray {
119 pub fn try_new(data: Vec<u8>, data_type: Option<DataType>) -> AsyncTiffResult<Self> {
123 match data_type {
124 None | Some(DataType::UInt8) => Ok(TypedArray::UInt8(data)),
125 Some(DataType::UInt16) => {
126 if !data.len().is_multiple_of(2) {
127 return Err(AsyncTiffError::General(format!(
128 "Data length {} is not divisible by UInt16 size (2 bytes)",
129 data.len()
130 )));
131 }
132 Ok(TypedArray::UInt16(try_cast_vec(data).unwrap_or_else(
133 |(_, data)| {
134 data.chunks_exact(2)
136 .map(|b| u16::from_ne_bytes([b[0], b[1]]))
137 .collect()
138 },
139 )))
140 }
141 Some(DataType::UInt32) => {
142 if !data.len().is_multiple_of(4) {
143 return Err(AsyncTiffError::General(format!(
144 "Data length {} is not divisible by UInt32 size (4 bytes)",
145 data.len()
146 )));
147 }
148 Ok(TypedArray::UInt32(try_cast_vec(data).unwrap_or_else(
149 |(_, data)| {
150 data.chunks_exact(4)
152 .map(|b| u32::from_ne_bytes([b[0], b[1], b[2], b[3]]))
153 .collect()
154 },
155 )))
156 }
157 Some(DataType::UInt64) => {
158 if !data.len().is_multiple_of(8) {
159 return Err(AsyncTiffError::General(format!(
160 "Data length {} is not divisible by UInt64 size (8 bytes)",
161 data.len()
162 )));
163 }
164 Ok(TypedArray::UInt64(try_cast_vec(data).unwrap_or_else(
165 |(_, data)| {
166 data.chunks_exact(8)
168 .map(|b| {
169 u64::from_ne_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
170 })
171 .collect()
172 },
173 )))
174 }
175 Some(DataType::Int8) => Ok(TypedArray::Int8(cast_vec(data))),
177 Some(DataType::Int16) => {
178 if !data.len().is_multiple_of(2) {
179 return Err(AsyncTiffError::General(format!(
180 "Data length {} is not divisible by Int16 size (2 bytes)",
181 data.len()
182 )));
183 }
184 Ok(TypedArray::Int16(try_cast_vec(data).unwrap_or_else(
185 |(_, data)| {
186 data.chunks_exact(2)
188 .map(|b| i16::from_ne_bytes([b[0], b[1]]))
189 .collect()
190 },
191 )))
192 }
193 Some(DataType::Int32) => {
194 if !data.len().is_multiple_of(4) {
195 return Err(AsyncTiffError::General(format!(
196 "Data length {} is not divisible by Int32 size (4 bytes)",
197 data.len()
198 )));
199 }
200 Ok(TypedArray::Int32(try_cast_vec(data).unwrap_or_else(
201 |(_, data)| {
202 data.chunks_exact(4)
204 .map(|b| i32::from_ne_bytes([b[0], b[1], b[2], b[3]]))
205 .collect()
206 },
207 )))
208 }
209 Some(DataType::Int64) => {
210 if !data.len().is_multiple_of(8) {
211 return Err(AsyncTiffError::General(format!(
212 "Data length {} is not divisible by Int64 size (8 bytes)",
213 data.len()
214 )));
215 }
216 Ok(TypedArray::Int64(try_cast_vec(data).unwrap_or_else(
217 |(_, data)| {
218 data.chunks_exact(8)
220 .map(|b| {
221 i64::from_ne_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
222 })
223 .collect()
224 },
225 )))
226 }
227 Some(DataType::Float32) => {
228 if !data.len().is_multiple_of(4) {
229 return Err(AsyncTiffError::General(format!(
230 "Data length {} is not divisible by Float32 size (4 bytes)",
231 data.len()
232 )));
233 }
234 Ok(TypedArray::Float32(try_cast_vec(data).unwrap_or_else(
235 |(_, data)| {
236 data.chunks_exact(4)
238 .map(|b| f32::from_ne_bytes([b[0], b[1], b[2], b[3]]))
239 .collect()
240 },
241 )))
242 }
243 Some(DataType::Float64) => {
244 if !data.len().is_multiple_of(8) {
245 return Err(AsyncTiffError::General(format!(
246 "Data length {} is not divisible by Float64 size (8 bytes)",
247 data.len()
248 )));
249 }
250 Ok(TypedArray::Float64(try_cast_vec(data).unwrap_or_else(
251 |(_, data)| {
252 data.chunks_exact(8)
254 .map(|b| {
255 f64::from_ne_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
256 })
257 .collect()
258 },
259 )))
260 }
261 }
262 }
263
264 pub fn len(&self) -> usize {
266 match self {
267 TypedArray::UInt8(data) => data.len(),
268 TypedArray::UInt16(data) => data.len(),
269 TypedArray::UInt32(data) => data.len(),
270 TypedArray::UInt64(data) => data.len(),
271 TypedArray::Int8(data) => data.len(),
272 TypedArray::Int16(data) => data.len(),
273 TypedArray::Int32(data) => data.len(),
274 TypedArray::Int64(data) => data.len(),
275 TypedArray::Float32(data) => data.len(),
276 TypedArray::Float64(data) => data.len(),
277 }
278 }
279
280 pub fn is_empty(&self) -> bool {
282 self.len() == 0
283 }
284}
285
286impl AsRef<[u8]> for TypedArray {
287 fn as_ref(&self) -> &[u8] {
288 match self {
289 TypedArray::UInt8(data) => data.as_slice(),
290 TypedArray::UInt16(data) => cast_slice(data),
291 TypedArray::UInt32(data) => cast_slice(data),
292 TypedArray::UInt64(data) => cast_slice(data),
293 TypedArray::Int8(data) => cast_slice(data),
294 TypedArray::Int16(data) => cast_slice(data),
295 TypedArray::Int32(data) => cast_slice(data),
296 TypedArray::Int64(data) => cast_slice(data),
297 TypedArray::Float32(data) => cast_slice(data),
298 TypedArray::Float64(data) => cast_slice(data),
299 }
300 }
301}