Skip to main content

mzdata_bindata/
traits.rs

1use std::marker::PhantomData;
2use std::slice;
3use std::mem;
4use std::borrow::Cow;
5
6use bytemuck::Pod;
7use num_traits::{AsPrimitive, Num};
8use mzdata_param::Unit;
9
10use super::encodings::{ArrayRetrievalError, BinaryDataArrayType, Bytes};
11use super::ArrayType;
12
13
14pub trait ByteArrayView<'transient, 'lifespan: 'transient> {
15    fn view(&'lifespan self) -> Result<Cow<'lifespan, [u8]>, ArrayRetrievalError>;
16
17    fn coerce_from<T: Pod>(
18        buffer: Cow<'transient, [u8]>,
19    ) -> Result<Cow<'transient, [T]>, ArrayRetrievalError> {
20        let n = buffer.len();
21        if n == 0 {
22            return Ok(Cow::Owned(Vec::new()))
23        }
24        let z = mem::size_of::<T>();
25        if n % z != 0 {
26            return Err(ArrayRetrievalError::DataTypeSizeMismatch);
27        }
28        match buffer {
29            Cow::Borrowed(c) => {
30                Ok(Cow::Borrowed(bytemuck::try_cast_slice(c)?))
31            },
32            Cow::Owned(v) => {
33                let size_type = n / z;
34                let mut buf = Vec::with_capacity(size_type);
35                v.chunks_exact(z).try_for_each(|c| {
36                    buf.extend(bytemuck::try_cast_slice(c)?);
37                    Ok::<(), bytemuck::PodCastError>(())
38                })?;
39                Ok(Cow::Owned(buf))
40            },
41        }
42    }
43
44    fn coerce<T: Pod>(
45        &'lifespan self,
46    ) -> Result<Cow<'transient, [T]>, ArrayRetrievalError> {
47        match self.view() {
48            Ok(data) => {
49                #[cfg(target_endian = "big")]
50                {
51                    let mut data = Cow::Owned(data.to_vec());
52                    self.dtype().swap_bytes(&mut data)?;
53                    Self::coerce_from(data)
54                }
55                #[cfg(not(target_endian = "big"))]
56                {
57                    Self::coerce_from(data)
58                }
59            },
60            Err(err) => Err(err),
61        }
62    }
63
64    /// Decode the array, then copy it to a new array, converting each element from type `D` to to type `S`
65    fn convert<S: Num + Clone + AsPrimitive<D> + Pod, D: Num + Clone + Copy + 'static>(
66        &'lifespan self,
67    ) -> Result<Cow<'transient, [D]>, ArrayRetrievalError> {
68        match self.coerce::<S>() {
69            Ok(view) => {
70                match view {
71                    Cow::Borrowed(view) => {
72                        Ok(Cow::Owned(view.iter().map(|a| a.as_()).collect()))
73                    }
74                    Cow::Owned(owned) => {
75                        let res = owned.iter().map(|a| a.as_()).collect();
76                        Ok(Cow::Owned(res))
77                    }
78                }
79            }
80            Err(err) => Err(err),
81        }
82    }
83
84    /// The kind of array this is
85    fn name(&self) -> &ArrayType;
86
87    /// The real data type encoded in bytes
88    fn dtype(&self) -> BinaryDataArrayType;
89
90    /// The unit of measurement each data point is in
91    fn unit(&self) -> Unit;
92
93    /// Get the identifier referencing a [`DataProcessing`](crate::meta::DataProcessing)
94    fn data_processing_reference(&self) -> Option<&str> {
95        None
96    }
97
98    fn to_f32(&'lifespan self) -> Result<Cow<'transient, [f32]>, ArrayRetrievalError> {
99        type D = f32;
100        match self.dtype() {
101            BinaryDataArrayType::Float32 | BinaryDataArrayType::ASCII => self.coerce::<D>(),
102            BinaryDataArrayType::Float64 => {
103                type S = f64;
104                self.convert::<S, D>()
105            }
106            BinaryDataArrayType::Int32 => {
107                type S = i32;
108                self.convert::<S, D>()
109            }
110            BinaryDataArrayType::Int64 => {
111                type S = i64;
112                self.convert::<S, D>()
113            }
114            _ => Err(ArrayRetrievalError::DataTypeSizeMismatch),
115        }
116    }
117
118    fn to_f64(&'lifespan self) -> Result<Cow<'transient, [f64]>, ArrayRetrievalError> {
119        type D = f64;
120        match self.dtype() {
121            BinaryDataArrayType::Float32 => {
122                type S = f32;
123                self.convert::<S, D>()
124            }
125            BinaryDataArrayType::Float64 | BinaryDataArrayType::ASCII => self.coerce(),
126            BinaryDataArrayType::Int32 => {
127                type S = i32;
128                self.convert::<S, D>()
129            }
130            BinaryDataArrayType::Int64 => {
131                type S = i64;
132                self.convert::<S, D>()
133            }
134            _ => Err(ArrayRetrievalError::DataTypeSizeMismatch),
135        }
136    }
137
138    fn to_i32(&'lifespan self) -> Result<Cow<'transient, [i32]>, ArrayRetrievalError> {
139        type D = i32;
140        match self.dtype() {
141            BinaryDataArrayType::Float32 => {
142                type S = f32;
143                self.convert::<S, D>()
144            }
145            BinaryDataArrayType::Float64 => {
146                type S = f64;
147                self.convert::<S, D>()
148            }
149            BinaryDataArrayType::Int32 | BinaryDataArrayType::ASCII => self.coerce::<D>(),
150            BinaryDataArrayType::Int64 => {
151                type S = i64;
152                self.convert::<S, D>()
153            }
154            _ => Err(ArrayRetrievalError::DataTypeSizeMismatch),
155        }
156    }
157
158    fn to_i64(&'lifespan self) -> Result<Cow<'transient, [i64]>, ArrayRetrievalError> {
159        type D = i64;
160        match self.dtype() {
161            BinaryDataArrayType::Float32 => {
162                type S = f32;
163                self.convert::<S, D>()
164            }
165            BinaryDataArrayType::Float64 => {
166                type S = f64;
167                self.convert::<S, D>()
168            }
169            BinaryDataArrayType::Int64 | BinaryDataArrayType::ASCII => self.coerce::<D>(),
170            BinaryDataArrayType::Int32 => {
171                type S = i32;
172                self.convert::<S, D>()
173            }
174            _ => Err(ArrayRetrievalError::DataTypeSizeMismatch),
175        }
176    }
177
178    /// The size of encoded array in terms of # of elements of the [`BinaryDataArrayType`] given by [`ByteArrayView::dtype`]
179    fn data_len(&'lifespan self) -> Result<usize, ArrayRetrievalError> {
180        let view = self.view()?;
181        let n = view.len();
182        Ok(n / self.dtype().size_of())
183    }
184
185    fn iter_type<T: Pod>(&'lifespan self) -> Result<DataSliceIter<'lifespan, T>, ArrayRetrievalError> {
186        Ok(DataSliceIter::new(self.view()?))
187    }
188
189    fn iter_u8(&'lifespan self) -> Result<DataSliceIter<'lifespan, u8>, ArrayRetrievalError> {
190        Ok(DataSliceIter::new(self.view()?))
191    }
192
193    fn iter_f32(&'lifespan self) -> Result<DataSliceIter<'lifespan, f32>, ArrayRetrievalError> {
194        Ok(DataSliceIter::new(self.view()?))
195    }
196
197    fn iter_f64(&'lifespan self) -> Result<DataSliceIter<'lifespan, f64>, ArrayRetrievalError> {
198        Ok(DataSliceIter::new(self.view()?))
199    }
200
201    fn iter_i32(&'lifespan self) -> Result<DataSliceIter<'lifespan, i32>, ArrayRetrievalError> {
202        Ok(DataSliceIter::new(self.view()?))
203    }
204
205    fn iter_i64(&'lifespan self) -> Result<DataSliceIter<'lifespan, i64>, ArrayRetrievalError> {
206        Ok(DataSliceIter::new(self.view()?))
207    }
208}
209
210pub trait ByteArrayViewMut<'transient, 'lifespan: 'transient>:
211    ByteArrayView<'transient, 'lifespan>
212{
213
214    /// Specify the unit of the data array
215    fn unit_mut(&mut self) -> &mut Unit;
216
217    /// Get a mutable view of the bytes backing this data array.
218    ///
219    /// This is in turn used by [`ByteArrayViewMut::coerce_mut`] to produce a typed array
220    fn view_mut(&'transient mut self) -> Result<&'transient mut Bytes, ArrayRetrievalError>;
221
222    fn coerce_from_mut<T: Clone + Sized>(
223        buffer: &mut [u8],
224    ) -> Result<&'transient mut [T], ArrayRetrievalError> {
225        let n = buffer.len();
226        if n == 0 {
227            return Ok(&mut [])
228        }
229        let z = mem::size_of::<T>();
230        if n % z != 0 {
231            return Err(ArrayRetrievalError::DataTypeSizeMismatch);
232        }
233        let m = n / z;
234        unsafe { Ok(slice::from_raw_parts_mut(buffer.as_mut_ptr() as *mut T, m)) }
235    }
236
237    fn coerce_mut<T: Clone + Sized>(
238        &'lifespan mut self,
239    ) -> Result<&'transient mut [T], ArrayRetrievalError> {
240        let view = self.view_mut()?;
241        #[cfg(target_endian = "big")]
242        {
243            log::error!("Mutable view of raw bytes on big endian system is only partially supported.")
244        }
245        Self::coerce_from_mut(view)
246    }
247
248    #[allow(unused)]
249    /// Set the identifier referencing a [`DataProcessing`](crate::meta::DataProcessing)
250    fn set_data_processing_reference(&mut self, data_processing_reference: Option<Box<str>>) {}
251}
252
253#[derive(Debug)]
254pub struct DataSliceIter<'a, T: Pod> {
255    buffer: Cow<'a, [u8]>,
256    i: usize,
257    _t: PhantomData<T>
258}
259
260impl<T: Pod> ExactSizeIterator for DataSliceIter<'_, T> {
261    fn len(&self) -> usize {
262        let z = mem::size_of::<T>();
263        self.buffer.len() / z
264    }
265}
266
267impl<'a, T: Pod> DataSliceIter<'a, T> {
268    pub fn new(buffer: Cow<'a, [u8]>) -> Self {
269        Self { buffer, i: 0, _t: PhantomData }
270    }
271
272    pub fn next_value(&mut self) -> Option<T> {
273        let z = mem::size_of::<T>();
274        let offset = z * self.i;
275        if (offset + z) > self.buffer.len() {
276            None
277        } else {
278            let data = &self.buffer[offset..offset + z];
279            #[cfg(target_endian = "big")]
280            {
281                let mut data = data.to_vec();
282                data.reverse();
283                let val = bytemuck::from_bytes(data);
284                self.i += 1;
285                Some(*val)
286            }
287            #[cfg(not(target_endian = "big"))]
288            {
289                let val = bytemuck::from_bytes(data);
290                self.i += 1;
291                Some(*val)
292            }
293        }
294    }
295}
296
297impl<T: Pod> Iterator for DataSliceIter<'_, T> {
298    type Item = T;
299
300    fn next(&mut self) -> Option<Self::Item> {
301        self.next_value()
302    }
303}