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];
33
34 let typed_data = if data_type == Some(DataType::Bool) {
35 let required_bytes = expected_len.div_ceil(8);
36 if data.len() < required_bytes {
37 return Err(AsyncTiffError::General(format!(
38 "Bool data length {} is less than required {} bytes for {} elements",
39 data.len(),
40 required_bytes,
41 expected_len
42 )));
43 }
44 TypedArray::Bool(expand_bitmask(&data, expected_len))
45 } else {
46 let typed_data = TypedArray::try_new(data, data_type)?;
47 if typed_data.len() != expected_len {
48 return Err(AsyncTiffError::General(format!(
49 "Internal error: incorrect shape or data length passed to Array::try_new. Got data length {}, expected {}",
50 typed_data.len(),
51 expected_len
52 )));
53 }
54 typed_data
55 };
56
57 Ok(Self {
58 data: typed_data,
59 shape,
60 data_type,
61 })
62 }
63
64 pub fn data(&self) -> &TypedArray {
66 &self.data
67 }
68
69 pub fn into_inner(self) -> (TypedArray, [usize; 3], Option<DataType>) {
71 (self.data, self.shape, self.data_type)
72 }
73
74 pub fn shape(&self) -> [usize; 3] {
82 self.shape
83 }
84
85 pub fn data_type(&self) -> Option<DataType> {
89 self.data_type
90 }
91}
92
93#[derive(Debug, Clone)]
112pub enum TypedArray {
113 Bool(Vec<bool>),
117 UInt8(Vec<u8>),
119 UInt16(Vec<u16>),
121 UInt32(Vec<u32>),
123 UInt64(Vec<u64>),
125 Int8(Vec<i8>),
127 Int16(Vec<i16>),
129 Int32(Vec<i32>),
131 Int64(Vec<i64>),
133 Float32(Vec<f32>),
135 Float64(Vec<f64>),
137}
138
139impl TypedArray {
140 pub fn try_new(data: Vec<u8>, data_type: Option<DataType>) -> AsyncTiffResult<Self> {
144 match data_type {
145 None | Some(DataType::UInt8) => Ok(TypedArray::UInt8(data)),
146 Some(DataType::Bool) => {
147 Err(AsyncTiffError::General(
150 "Bool must be constructed via Array::try_new".to_string(),
151 ))
152 }
153 Some(DataType::UInt16) => {
154 if !data.len().is_multiple_of(2) {
155 return Err(AsyncTiffError::General(format!(
156 "Data length {} is not divisible by UInt16 size (2 bytes)",
157 data.len()
158 )));
159 }
160 Ok(TypedArray::UInt16(try_cast_vec(data).unwrap_or_else(
161 |(_, data)| {
162 data.chunks_exact(2)
164 .map(|b| u16::from_ne_bytes([b[0], b[1]]))
165 .collect()
166 },
167 )))
168 }
169 Some(DataType::UInt32) => {
170 if !data.len().is_multiple_of(4) {
171 return Err(AsyncTiffError::General(format!(
172 "Data length {} is not divisible by UInt32 size (4 bytes)",
173 data.len()
174 )));
175 }
176 Ok(TypedArray::UInt32(try_cast_vec(data).unwrap_or_else(
177 |(_, data)| {
178 data.chunks_exact(4)
180 .map(|b| u32::from_ne_bytes([b[0], b[1], b[2], b[3]]))
181 .collect()
182 },
183 )))
184 }
185 Some(DataType::UInt64) => {
186 if !data.len().is_multiple_of(8) {
187 return Err(AsyncTiffError::General(format!(
188 "Data length {} is not divisible by UInt64 size (8 bytes)",
189 data.len()
190 )));
191 }
192 Ok(TypedArray::UInt64(try_cast_vec(data).unwrap_or_else(
193 |(_, data)| {
194 data.chunks_exact(8)
196 .map(|b| {
197 u64::from_ne_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
198 })
199 .collect()
200 },
201 )))
202 }
203 Some(DataType::Int8) => Ok(TypedArray::Int8(cast_vec(data))),
205 Some(DataType::Int16) => {
206 if !data.len().is_multiple_of(2) {
207 return Err(AsyncTiffError::General(format!(
208 "Data length {} is not divisible by Int16 size (2 bytes)",
209 data.len()
210 )));
211 }
212 Ok(TypedArray::Int16(try_cast_vec(data).unwrap_or_else(
213 |(_, data)| {
214 data.chunks_exact(2)
216 .map(|b| i16::from_ne_bytes([b[0], b[1]]))
217 .collect()
218 },
219 )))
220 }
221 Some(DataType::Int32) => {
222 if !data.len().is_multiple_of(4) {
223 return Err(AsyncTiffError::General(format!(
224 "Data length {} is not divisible by Int32 size (4 bytes)",
225 data.len()
226 )));
227 }
228 Ok(TypedArray::Int32(try_cast_vec(data).unwrap_or_else(
229 |(_, data)| {
230 data.chunks_exact(4)
232 .map(|b| i32::from_ne_bytes([b[0], b[1], b[2], b[3]]))
233 .collect()
234 },
235 )))
236 }
237 Some(DataType::Int64) => {
238 if !data.len().is_multiple_of(8) {
239 return Err(AsyncTiffError::General(format!(
240 "Data length {} is not divisible by Int64 size (8 bytes)",
241 data.len()
242 )));
243 }
244 Ok(TypedArray::Int64(try_cast_vec(data).unwrap_or_else(
245 |(_, data)| {
246 data.chunks_exact(8)
248 .map(|b| {
249 i64::from_ne_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
250 })
251 .collect()
252 },
253 )))
254 }
255 Some(DataType::Float32) => {
256 if !data.len().is_multiple_of(4) {
257 return Err(AsyncTiffError::General(format!(
258 "Data length {} is not divisible by Float32 size (4 bytes)",
259 data.len()
260 )));
261 }
262 Ok(TypedArray::Float32(try_cast_vec(data).unwrap_or_else(
263 |(_, data)| {
264 data.chunks_exact(4)
266 .map(|b| f32::from_ne_bytes([b[0], b[1], b[2], b[3]]))
267 .collect()
268 },
269 )))
270 }
271 Some(DataType::Float64) => {
272 if !data.len().is_multiple_of(8) {
273 return Err(AsyncTiffError::General(format!(
274 "Data length {} is not divisible by Float64 size (8 bytes)",
275 data.len()
276 )));
277 }
278 Ok(TypedArray::Float64(try_cast_vec(data).unwrap_or_else(
279 |(_, data)| {
280 data.chunks_exact(8)
282 .map(|b| {
283 f64::from_ne_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])
284 })
285 .collect()
286 },
287 )))
288 }
289 }
290 }
291
292 pub fn len(&self) -> usize {
294 match self {
295 TypedArray::Bool(data) => data.len(),
296 TypedArray::UInt8(data) => data.len(),
297 TypedArray::UInt16(data) => data.len(),
298 TypedArray::UInt32(data) => data.len(),
299 TypedArray::UInt64(data) => data.len(),
300 TypedArray::Int8(data) => data.len(),
301 TypedArray::Int16(data) => data.len(),
302 TypedArray::Int32(data) => data.len(),
303 TypedArray::Int64(data) => data.len(),
304 TypedArray::Float32(data) => data.len(),
305 TypedArray::Float64(data) => data.len(),
306 }
307 }
308
309 pub fn is_empty(&self) -> bool {
311 self.len() == 0
312 }
313}
314
315impl AsRef<[u8]> for TypedArray {
316 fn as_ref(&self) -> &[u8] {
317 match self {
318 TypedArray::Bool(data) => cast_slice(data),
319 TypedArray::UInt8(data) => data.as_slice(),
320 TypedArray::UInt16(data) => cast_slice(data),
321 TypedArray::UInt32(data) => cast_slice(data),
322 TypedArray::UInt64(data) => cast_slice(data),
323 TypedArray::Int8(data) => cast_slice(data),
324 TypedArray::Int16(data) => cast_slice(data),
325 TypedArray::Int32(data) => cast_slice(data),
326 TypedArray::Int64(data) => cast_slice(data),
327 TypedArray::Float32(data) => cast_slice(data),
328 TypedArray::Float64(data) => cast_slice(data),
329 }
330 }
331}
332
333fn expand_bitmask(data: &[u8], len: usize) -> Vec<bool> {
337 let mut result = Vec::with_capacity(len);
338 for i in 0..len {
339 let byte_idx = i / 8;
340 let bit_idx = 7 - (i % 8); let bit = (data[byte_idx] >> bit_idx) & 1;
342 result.push(bit == 1);
343 }
344 result
345}