1use std::marker::PhantomData;
2use std::mem;
3use std::borrow::Cow;
4
5use bytemuck::Pod;
6use num_traits::{AsPrimitive, Num};
7use mzdata_param::Unit;
8
9use super::encodings::{ArrayRetrievalError, BinaryDataArrayType, Bytes};
10use super::ArrayType;
11
12pub trait ByteArrayView<'transient, 'lifespan: 'transient> {
18 fn view(&'lifespan self) -> Result<Cow<'lifespan, [u8]>, ArrayRetrievalError>;
20
21 fn coerce_from<T: Pod>(
24 buffer: Cow<'transient, [u8]>,
25 ) -> Result<Cow<'transient, [T]>, ArrayRetrievalError> {
26 let n = buffer.len();
27 if n == 0 {
28 return Ok(Cow::Owned(Vec::new()))
29 }
30 let z = mem::size_of::<T>();
31 if n % z != 0 {
32 return Err(ArrayRetrievalError::DataTypeSizeMismatch);
33 }
34 match buffer {
35 Cow::Borrowed(c) => {
36 Ok(Cow::Borrowed(bytemuck::try_cast_slice(c)?))
37 },
38 Cow::Owned(v) => {
39 let size_type = n / z;
40 let mut buf = Vec::with_capacity(size_type);
41 v.chunks_exact(z).try_for_each(|c| {
42 buf.extend(bytemuck::try_cast_slice(c)?);
43 Ok::<(), bytemuck::PodCastError>(())
44 })?;
45 Ok(Cow::Owned(buf))
46 },
47 }
48 }
49
50 fn coerce<T: Pod>(
53 &'lifespan self,
54 ) -> Result<Cow<'transient, [T]>, ArrayRetrievalError> {
55 match self.view() {
56 Ok(data) => {
57 #[cfg(target_endian = "big")]
58 {
59 let mut data: Cow<'_, [u8]> = Cow::Owned(data.to_vec());
60 self.dtype().swap_bytes(data.to_mut())?;
61 Self::coerce_from(data)
62 }
63 #[cfg(not(target_endian = "big"))]
64 {
65 Self::coerce_from(data)
66 }
67 },
68 Err(err) => Err(err),
69 }
70 }
71
72 fn convert<S: Num + Clone + AsPrimitive<D> + Pod, D: Num + Clone + Copy + 'static>(
76 &'lifespan self,
77 ) -> Result<Cow<'transient, [D]>, ArrayRetrievalError> {
78 match self.coerce::<S>() {
79 Ok(view) => {
80 match view {
81 Cow::Borrowed(view) => {
82 Ok(Cow::Owned(view.iter().map(|a| a.as_()).collect()))
83 }
84 Cow::Owned(owned) => {
85 let res = owned.iter().map(|a| a.as_()).collect();
86 Ok(Cow::Owned(res))
87 }
88 }
89 }
90 Err(err) => Err(err),
91 }
92 }
93
94 fn name(&self) -> &ArrayType;
96
97 fn dtype(&self) -> BinaryDataArrayType;
99
100 fn unit(&self) -> Unit;
102
103 fn data_processing_reference(&self) -> Option<&str> {
105 None
106 }
107
108 fn to_f32(&'lifespan self) -> Result<Cow<'transient, [f32]>, ArrayRetrievalError> {
111 type D = f32;
112 match self.dtype() {
113 BinaryDataArrayType::Float32 | BinaryDataArrayType::ASCII => self.coerce::<D>(),
114 BinaryDataArrayType::Float64 => {
115 type S = f64;
116 self.convert::<S, D>()
117 }
118 BinaryDataArrayType::Int32 => {
119 type S = i32;
120 self.convert::<S, D>()
121 }
122 BinaryDataArrayType::Int64 => {
123 type S = i64;
124 self.convert::<S, D>()
125 }
126 _ => Err(ArrayRetrievalError::DataTypeSizeMismatch),
127 }
128 }
129
130 fn to_f64(&'lifespan self) -> Result<Cow<'transient, [f64]>, ArrayRetrievalError> {
133 type D = f64;
134 match self.dtype() {
135 BinaryDataArrayType::Float32 => {
136 type S = f32;
137 self.convert::<S, D>()
138 }
139 BinaryDataArrayType::Float64 | BinaryDataArrayType::ASCII => self.coerce(),
140 BinaryDataArrayType::Int32 => {
141 type S = i32;
142 self.convert::<S, D>()
143 }
144 BinaryDataArrayType::Int64 => {
145 type S = i64;
146 self.convert::<S, D>()
147 }
148 _ => Err(ArrayRetrievalError::DataTypeSizeMismatch),
149 }
150 }
151
152 fn to_i32(&'lifespan self) -> Result<Cow<'transient, [i32]>, ArrayRetrievalError> {
155 type D = i32;
156 match self.dtype() {
157 BinaryDataArrayType::Float32 => {
158 type S = f32;
159 self.convert::<S, D>()
160 }
161 BinaryDataArrayType::Float64 => {
162 type S = f64;
163 self.convert::<S, D>()
164 }
165 BinaryDataArrayType::Int32 | BinaryDataArrayType::ASCII => self.coerce::<D>(),
166 BinaryDataArrayType::Int64 => {
167 type S = i64;
168 self.convert::<S, D>()
169 }
170 _ => Err(ArrayRetrievalError::DataTypeSizeMismatch),
171 }
172 }
173
174 fn to_i64(&'lifespan self) -> Result<Cow<'transient, [i64]>, ArrayRetrievalError> {
177 type D = i64;
178 match self.dtype() {
179 BinaryDataArrayType::Float32 => {
180 type S = f32;
181 self.convert::<S, D>()
182 }
183 BinaryDataArrayType::Float64 => {
184 type S = f64;
185 self.convert::<S, D>()
186 }
187 BinaryDataArrayType::Int64 | BinaryDataArrayType::ASCII => self.coerce::<D>(),
188 BinaryDataArrayType::Int32 => {
189 type S = i32;
190 self.convert::<S, D>()
191 }
192 _ => Err(ArrayRetrievalError::DataTypeSizeMismatch),
193 }
194 }
195
196 fn data_len(&'lifespan self) -> Result<usize, ArrayRetrievalError> {
198 let view = self.view()?;
199 let n = view.len();
200 Ok(n / self.dtype().size_of())
201 }
202
203 fn iter_type<T: Pod>(&'lifespan self) -> Result<DataSliceIter<'lifespan, T>, ArrayRetrievalError> {
204 Ok(DataSliceIter::new(self.view()?))
205 }
206
207 fn iter_u8(&'lifespan self) -> Result<DataSliceIter<'lifespan, u8>, ArrayRetrievalError> {
208 Ok(DataSliceIter::new(self.view()?))
209 }
210
211 fn iter_f32(&'lifespan self) -> Result<DataSliceIter<'lifespan, f32>, ArrayRetrievalError> {
212 Ok(DataSliceIter::new(self.view()?))
213 }
214
215 fn iter_f64(&'lifespan self) -> Result<DataSliceIter<'lifespan, f64>, ArrayRetrievalError> {
216 Ok(DataSliceIter::new(self.view()?))
217 }
218
219 fn iter_i32(&'lifespan self) -> Result<DataSliceIter<'lifespan, i32>, ArrayRetrievalError> {
220 Ok(DataSliceIter::new(self.view()?))
221 }
222
223 fn iter_i64(&'lifespan self) -> Result<DataSliceIter<'lifespan, i64>, ArrayRetrievalError> {
224 Ok(DataSliceIter::new(self.view()?))
225 }
226}
227
228pub trait ByteArrayViewMut<'transient, 'lifespan: 'transient>:
230 ByteArrayView<'transient, 'lifespan>
231{
232
233 fn unit_mut(&mut self) -> &mut Unit;
235
236 fn view_mut(&'transient mut self) -> Result<&'transient mut Bytes, ArrayRetrievalError>;
240
241 fn coerce_from_mut<T: Pod>(
274 buffer: &'transient mut [u8],
275 ) -> Result<&'transient mut [T], ArrayRetrievalError> {
276 if buffer.is_empty() {
277 return Ok(&mut []);
278 }
279 Ok(bytemuck::try_cast_slice_mut(buffer)?)
280 }
281
282 fn coerce_mut<T: Pod>(
283 &'lifespan mut self,
284 ) -> Result<&'transient mut [T], ArrayRetrievalError> {
285 let view = self.view_mut()?;
286 #[cfg(target_endian = "big")]
287 {
288 log::error!("Mutable view of raw bytes on big endian system is only partially supported.")
289 }
290 Self::coerce_from_mut(view)
291 }
292
293 #[allow(unused)]
294 fn set_data_processing_reference(&mut self, data_processing_reference: Option<Box<str>>) {}
296}
297
298#[derive(Debug)]
299pub struct DataSliceIter<'a, T: Pod> {
300 buffer: Cow<'a, [u8]>,
301 i: usize,
302 _t: PhantomData<T>
303}
304
305impl<T: Pod> ExactSizeIterator for DataSliceIter<'_, T> {
306 fn len(&self) -> usize {
307 let z = mem::size_of::<T>();
308 self.buffer.len() / z - self.i
309 }
310}
311
312impl<'a, T: Pod> DataSliceIter<'a, T> {
313 pub fn new(buffer: Cow<'a, [u8]>) -> Self {
314 Self { buffer, i: 0, _t: PhantomData }
315 }
316
317 pub fn next_value(&mut self) -> Option<T> {
318 let z = mem::size_of::<T>();
319 let offset = z * self.i;
320 if (offset + z) > self.buffer.len() {
321 None
322 } else {
323 let data = &self.buffer[offset..offset + z];
324 #[cfg(target_endian = "big")]
325 {
326 let mut data = data.to_vec();
327 data.reverse();
328 let val = bytemuck::pod_read_unaligned(&data);
329 self.i += 1;
330 Some(val)
331 }
332 #[cfg(not(target_endian = "big"))]
333 {
334 let val = bytemuck::pod_read_unaligned(data);
335 self.i += 1;
336 Some(val)
337 }
338 }
339 }
340}
341
342impl<T: Pod> Iterator for DataSliceIter<'_, T> {
343 type Item = T;
344
345 fn next(&mut self) -> Option<Self::Item> {
346 self.next_value()
347 }
348
349 fn size_hint(&self) -> (usize, Option<usize>) {
350 if mem::size_of::<T>() == 0 {
351 return (0, None);
352 }
353 let n = self.len();
354 (n, Some(n))
355 }
356}
357
358#[cfg(test)]
359mod test {
360 use super::*;
361
362 fn check_remaining<T: Pod + PartialEq + std::fmt::Debug>(values: &[T]) {
363 let mut it = DataSliceIter::<T>::new(Cow::Borrowed(bytemuck::cast_slice(values)));
364 for (i, value) in values.iter().enumerate() {
365 let n = values.len() - i;
366 assert_eq!(it.len(), n);
367 assert_eq!(it.size_hint(), (n, Some(n)));
368 assert_eq!(it.next(), Some(*value));
369 }
370 assert_eq!(it.len(), 0);
371 assert_eq!(it.size_hint(), (0, Some(0)));
372 assert_eq!(it.next(), None);
373 assert_eq!(it.next(), None);
374 }
375
376 #[test]
377 fn test_iterator_remaining() {
378 check_remaining::<u8>(&[]);
379 check_remaining(&[1u8]);
380 check_remaining(&[1u8, 2, 3]);
381 check_remaining(&[1i32, -2, 3]);
382 check_remaining(&[1i64, -2, 3]);
383 check_remaining(&[1.25f32, -2.5, 3.0]);
384 check_remaining(&[1.25f64, -2.5, 3.0]);
385
386 let units = DataSliceIter::<()>::new(Cow::Borrowed(&[]));
387 assert_eq!(units.take(3).collect::<Vec<_>>(), vec![(); 3]);
388 }
389}