1use bytemuck::{self, Pod};
2
3use std::{
4 fmt::Display,
5 io,
6 ops::{AddAssign, Mul},
7};
8
9use thiserror::{self, Error};
10use num_traits::{Num, ToBytes};
11
12#[cfg(feature = "numpress")]
13use numpress;
14
15use mzdata_param::{curie, Param, ControlledVocabulary, ParamCow, Unit, CURIE, ValueRef};
16
17pub type Bytes = Vec<u8>;
18
19pub fn to_bytes<T: Pod + ToBytes>(data: &[T]) -> Bytes {
31 let n = data.len();
32 let mut buf = Vec::with_capacity(n * size_of::<T>());
33 for v in data {
34 buf.extend_from_slice(v.to_le_bytes().as_ref());
35 }
36 buf
37}
38
39pub fn as_bytes<T: Pod>(data: &[T]) -> &[u8] {
55 bytemuck::cast_slice(data)
56}
57
58pub fn vec_as_bytes<T: Pod>(data: Vec<T>) -> Bytes {
73 let mut buf = Bytes::with_capacity(data.len() * std::mem::size_of::<T>());
74 for val in data {
75 buf.extend_from_slice(bytemuck::bytes_of(&val));
76 }
77 buf
78}
79
80mod byte_rotation {
81 use super::*;
82
83 pub fn transpose_bytes_into<T: Pod, const N: usize>(data: &[T], buffer: &mut Vec<u8>) {
84 assert_eq!(core::mem::size_of::<T>(), N);
85 let bytes = bytemuck::cast_slice::<T, [u8; N]>(data);
86 buffer.clear();
87 let delta = (data.len() * N).saturating_sub(buffer.capacity());
88 if delta > 0 {
89 buffer.reserve(delta);
90 }
91
92 #[cfg(target_endian = "little")]
93 {
94 for i in 0..N {
95 buffer.extend(bytes.iter().map(|b| b[i]))
96 }
97 }
98 #[cfg(target_endian = "big")]
99 {
100 for i in (0..N).rev() {
101 buffer.extend(bytes.iter().map(|b| b[i]))
102 }
103 }
104 }
105
106 pub fn transpose_bytes<T: Pod, const N: usize>(data: &[T]) -> Bytes {
107 let mut result = Bytes::with_capacity(data.len() * N);
108 transpose_bytes_into::<T, N>(data, &mut result);
109 result
110 }
111
112 pub fn transpose_4bytes<T: Pod>(data: &[T]) -> Bytes {
113 assert_eq!(std::mem::size_of::<T>(), 4);
114 transpose_bytes::<_, 4>(data)
115 }
116
117 pub fn transpose_8bytes<T: Pod>(data: &[T]) -> Bytes {
118 assert_eq!(std::mem::size_of::<T>(), 8);
119 transpose_bytes::<_, 8>(data)
120 }
121
122 pub fn transpose_i32(data: &[i32]) -> Bytes {
123 transpose_4bytes(data)
124 }
125
126 pub fn transpose_f32(data: &[f32]) -> Bytes {
127 transpose_4bytes(data)
128 }
129
130 pub fn transpose_i64(data: &[i64]) -> Bytes {
131 transpose_8bytes(data)
132 }
133
134 pub fn transpose_f64(data: &[f64]) -> Bytes {
135 transpose_8bytes(data)
136 }
137
138 pub fn reverse_transpose_bytes_into<const N: usize>(data: &[u8], buffer: &mut Vec<u8>) {
139 let rem = data.len() % N;
140 assert_eq!(rem, 0);
141 let n_entries = data.len() / N;
142 buffer.clear();
143 buffer.resize(data.len(), 0);
144
145 #[cfg(target_endian = "little")]
146 {
147 for (i, band) in data.chunks_exact(n_entries).enumerate() {
148 for (j, byte) in band.iter().copied().enumerate() {
149 bytemuck::cast_slice_mut::<_, [u8; N]>(buffer)[j][i] = byte;
150 }
151 }
152 }
153 #[cfg(target_endian = "big")]
154 {
155 for (i, band) in data.chunks_exact(n_entries).enumerate() {
156 for (j, byte) in band.iter().copied().enumerate() {
157 bytemuck::cast_slice_mut::<_, [u8; N]>(buffer)[j][(N - 1) - i] = byte;
158 }
159 }
160 }
161 }
162
163 pub fn reverse_transpose_bytes<const N: usize>(data: &[u8]) -> Bytes {
164 let mut result: Bytes = vec![0; data.len()];
165 reverse_transpose_bytes_into::<N>(data, &mut result);
166 result
167 }
168
169 pub fn reverse_transpose_4bytes<T: Pod>(data: &[u8]) -> Bytes {
170 assert_eq!(std::mem::size_of::<T>(), 4);
171 reverse_transpose_bytes::<4>(data)
172 }
173
174 pub fn reverse_transpose_8bytes<T: Pod>(data: &[u8]) -> Bytes {
175 assert_eq!(std::mem::size_of::<T>(), 8);
176 reverse_transpose_bytes::<8>(data)
177 }
178
179 pub fn reverse_transpose_i32(data: &[u8]) -> Vec<u8> {
180 reverse_transpose_4bytes::<i32>(data)
181 }
182
183 pub fn reverse_transpose_f32(data: &[u8]) -> Vec<u8> {
184 reverse_transpose_4bytes::<f32>(data)
185 }
186
187 pub fn reverse_transpose_i64(data: &[u8]) -> Vec<u8> {
188 reverse_transpose_8bytes::<i64>(data)
189 }
190
191 pub fn reverse_transpose_f64(data: &[u8]) -> Vec<u8> {
192 reverse_transpose_8bytes::<f64>(data)
193 }
194}
195
196mod dictionary_encoding {
197 use super::*;
198 use io::prelude::*;
199 use num_traits::ops::bytes::{FromBytes, ToBytes};
200 use std::{
201 borrow::Cow,
202 collections::{HashMap, HashSet},
203 hash::Hash,
204 io::BufWriter,
205 };
206
207 trait DictValue<const W: usize>:
208 Pod + ToBytes<Bytes = [u8; W]> + Hash + Eq + Ord + FromBytes<Bytes = [u8; W]>
209 {
210 }
211
212 macro_rules! impl_dict_value {
213 ($val:ty, $size:literal) => {
214 impl DictValue<$size> for $val {}
215 };
216 }
217
218 impl_dict_value!(u8, 1);
219 impl_dict_value!(u16, 2);
220 impl_dict_value!(u32, 4);
221 impl_dict_value!(u64, 8);
222
223 trait DictIndex<const W: usize>:
224 Pod + ToBytes<Bytes = [u8; W]> + FromBytes<Bytes = [u8; W]>
225 {
226 fn from_usize(index: usize) -> Self;
227 fn to_usize(&self) -> usize;
228 }
229
230 macro_rules! impl_dict_index {
231 ($idx:ty, $size:literal) => {
232 impl DictIndex<$size> for $idx {
233 fn from_usize(index: usize) -> Self {
234 index as Self
235 }
236
237 fn to_usize(&self) -> usize {
238 *self as usize
239 }
240 }
241 };
242 }
243
244 impl_dict_index!(u8, 1);
245 impl_dict_index!(u16, 2);
246 impl_dict_index!(u32, 4);
247 impl_dict_index!(u64, 8);
248
249 #[derive(Default, Debug)]
250 pub struct DictionaryEncoder {
251 shuffle: bool,
252 buffer: Vec<u8>,
253 }
254
255 impl DictionaryEncoder {
256 pub fn new(shuffle: bool) -> Self {
257 Self {
258 shuffle,
259 buffer: Vec::new(),
260 }
261 }
262
263 fn build_value_map<T: Pod, const W1: usize, V: DictValue<W1>>(
264 &self,
265 data: &[T],
266 ) -> (Vec<V>, HashMap<V, usize>) {
267 debug_assert_eq!(core::mem::size_of::<T>(), core::mem::size_of::<V>());
268 debug_assert_eq!(core::mem::size_of::<T>(), W1);
269 let mut value_codes = HashSet::new();
270 for v in data {
271 let k: V = *bytemuck::from_bytes(bytemuck::bytes_of(v));
272 value_codes.insert(k);
273 }
274
275 let mut value_codes: Vec<_> = value_codes.into_iter().collect();
276 value_codes.sort();
277
278 let byte_map: HashMap<V, usize> = value_codes
279 .iter()
280 .enumerate()
281 .map(|(i, k)| (*k, i))
282 .collect();
283 (value_codes, byte_map)
284 }
285
286 fn create_writer<
287 T: Pod,
288 const W1: usize,
289 V: Pod + Ord + Hash + ToBytes<Bytes = [u8; W1]> + Eq,
290 const W2: usize,
291 K: DictIndex<W2>,
292 >(
293 &self,
294 data: &[T],
295 value_codes: &[V],
296 ) -> BufWriter<Vec<u8>> {
297 let data_offset = 16 + std::mem::size_of_val(value_codes);
298 let dict_buffer: Vec<u8> =
299 Vec::with_capacity(data_offset + data.len() * core::mem::size_of::<K>());
300 BufWriter::new(dict_buffer)
301 }
302
303 fn encode_dict_indices<
304 T: Pod,
305 const W1: usize,
306 V: Pod + Ord + Hash + ToBytes<Bytes = [u8; W1]> + Eq,
307 const W2: usize,
308 K: DictIndex<W2>,
309 >(
310 &mut self,
311 data: &[T],
312 value_codes: &[V],
313 byte_map: HashMap<V, usize>,
314 ) -> io::Result<Vec<u8>> {
315 let data_offset = 16 + std::mem::size_of_val(value_codes);
316 let mut writer = self.create_writer::<T, W1, V, W2, K>(data, value_codes);
317 writer.write_all(&(data_offset as u64).to_le_bytes())?;
318 writer.write_all(&(value_codes.len() as u64).to_le_bytes())?;
319
320 if self.shuffle {
321 byte_rotation::transpose_bytes_into::<V, W1>(value_codes, &mut self.buffer);
323 writer.write_all(&self.buffer)?;
324 } else {
328 for v in value_codes.iter() {
329 let bts = v.to_le_bytes();
330 writer.write_all(&bts)?;
331 }
332 }
333
334 if self.shuffle {
335 let mut buf = Vec::with_capacity(data.len());
336 for v in data {
337 let i = *byte_map
338 .get(bytemuck::from_bytes(bytemuck::bytes_of(v)))
339 .unwrap();
340 let ik: K = K::from_usize(i);
341 buf.push(ik);
342 }
343 byte_rotation::transpose_bytes_into::<K, W2>(&buf, &mut self.buffer);
345 writer.write_all(&self.buffer)?;
346 } else {
347 for v in data {
348 let i = *byte_map
349 .get(bytemuck::from_bytes(bytemuck::bytes_of(v)))
350 .unwrap();
351 let ik: K = K::from_usize(i);
352 writer.write_all(&ik.to_le_bytes())?;
353 }
354 }
355
356 writer.flush()?;
357 let val = writer.into_inner().unwrap();
358 Ok(val)
359 }
360
361 fn encode_values<T: Pod, const W1: usize, V: DictValue<W1>>(
362 &mut self,
363 data: &[T],
364 ) -> Result<Vec<u8>, io::Error> {
365 let (value_codes, byte_map) = self.build_value_map(data);
366 let n_value_codes = value_codes.len();
367
368 if n_value_codes <= 2usize.pow(8) {
369 self.encode_dict_indices::<T, W1, V, 1, u8>(data, &value_codes, byte_map)
370 } else if n_value_codes <= 2usize.pow(16) {
371 self.encode_dict_indices::<T, W1, V, 2, u16>(data, &value_codes, byte_map)
372 } else if n_value_codes <= 2usize.pow(32) {
373 self.encode_dict_indices::<T, W1, V, 4, u32>(data, &value_codes, byte_map)
374 } else if n_value_codes <= 2usize.pow(64) {
375 self.encode_dict_indices::<T, W1, V, 8, u64>(data, &value_codes, byte_map)
376 } else {
377 Err(io::Error::new(
378 io::ErrorKind::Unsupported,
379 "Cannot encode a dictionary with more than 2 ** 64 values",
380 ))
381 }
382 }
383
384 pub fn encode<T: Pod>(&mut self, data: &[T]) -> io::Result<Bytes> {
385 if data.is_empty() {
386 return Ok(Vec::new());
387 }
388 let z_val = core::mem::size_of::<T>();
389 if z_val <= 1 {
390 self.encode_values::<T, 1, u8>(data)
391 } else if z_val <= 2 {
392 self.encode_values::<T, 2, u16>(data)
393 } else if z_val <= 4 {
394 self.encode_values::<T, 4, u32>(data)
395 } else if z_val <= 8 {
396 self.encode_values::<T, 8, u64>(data)
397 } else {
398 Err(io::Error::new(
399 io::ErrorKind::Unsupported,
400 "Cannot encode a dictionary with more than 2 ** 64 keys",
401 ))
402 }
403 }
404 }
405
406 #[derive(Default, Debug)]
407 pub struct DictionaryDecoder {
408 shuffle: bool,
409 buffer: Vec<u8>,
410 }
411
412 impl DictionaryDecoder {
413 pub fn new(shuffle: bool) -> Self {
414 Self {
415 shuffle,
416 buffer: Default::default(),
417 }
418 }
419
420 fn make_reader<'a>(&self, buffer: &'a [u8]) -> io::BufReader<&'a [u8]> {
421 io::BufReader::new(buffer)
422 }
423
424 fn decode_value_buffer<T: Pod, const W1: usize, V: DictValue<W1>>(
425 &mut self,
426 buffer: &[u8],
427 n_values: usize,
428 ) -> Vec<T> {
429 macro_rules! decode_chunk {
430 ($chunk:ident) => {{
431 let chunk_a: [u8; W1] = $chunk.try_into().unwrap();
432 let val = V::from_le_bytes(&chunk_a);
433 let val: T = *bytemuck::from_bytes(bytemuck::bytes_of(&val));
434 val
435 }};
436 }
437 let mut value_buffer = Vec::with_capacity(n_values);
438 if self.shuffle {
439 let blocks = match core::mem::size_of::<T>() {
440 1 => Cow::Borrowed(buffer),
441 2 => {
442 byte_rotation::reverse_transpose_bytes_into::<2>(buffer, &mut self.buffer);
443 Cow::Borrowed(self.buffer.as_slice())
444 }
445 4 => {
446 byte_rotation::reverse_transpose_bytes_into::<4>(buffer, &mut self.buffer);
447 Cow::Borrowed(self.buffer.as_slice())
448 }
449 8 => {
450 byte_rotation::reverse_transpose_bytes_into::<8>(buffer, &mut self.buffer);
451 Cow::Borrowed(self.buffer.as_slice())
452 }
453 x => {
454 panic!("Unsupported size {x}");
455 }
456 };
457 for chunk in blocks.chunks_exact(W1) {
458 let val = decode_chunk!(chunk);
459 value_buffer.push(val);
460 }
461 } else {
462 for chunk in buffer.chunks_exact(W1) {
463 let val = decode_chunk!(chunk);
464 value_buffer.push(val);
465 }
466 };
467 value_buffer
468 }
469
470 fn decode_index_buffer<T: Pod, const W2: usize, K: DictIndex<W2>>(
471 &mut self,
472 value_codes: &[T],
473 index_buffer: &[u8],
474 ) -> Vec<T> {
475 let mut result = Vec::with_capacity(index_buffer.len() / W2);
476 if self.shuffle {
477 byte_rotation::reverse_transpose_bytes_into::<W2>(index_buffer, &mut self.buffer);
478 for chunk in self.buffer.chunks_exact(W2) {
479 let b: [u8; W2] = chunk.try_into().unwrap();
480 let k: usize = K::from_le_bytes(&b).to_usize();
481 result.push(value_codes[k])
482 }
483 } else {
484 for chunk in index_buffer.chunks_exact(W2) {
485 let b: [u8; W2] = chunk.try_into().unwrap();
486 let k: usize = K::from_le_bytes(&b).to_usize();
487 result.push(value_codes[k])
488 }
489 }
490 result
491 }
492
493 pub fn decode<T: Pod>(&mut self, buffer: &[u8]) -> io::Result<Vec<T>> {
494 if buffer.is_empty() {
495 return Ok(Vec::new());
496 }
497 let mut reader = self.make_reader(buffer);
498 let mut z_buf = [0u8; 8];
499 reader.read_exact(&mut z_buf)?;
500 let data_offset = u64::from_le_bytes(z_buf);
501 if data_offset == 0 {
502 return Ok(Vec::new());
503 }
504 let mut z_buf = [0u8; 8];
505 reader.read_exact(&mut z_buf)?;
506 let n_value_codes = u64::from_le_bytes(z_buf);
507 if n_value_codes == 0 {
508 return Ok(Vec::new());
509 }
510 let value_buffer = &buffer[16..(data_offset as usize)];
511 let value_width = (data_offset - 16) / n_value_codes;
512 let index_buffer = &buffer[data_offset as usize..];
513
514 let n_value_codes = n_value_codes as usize;
515
516 macro_rules! decode_indices {
517 ($values:ident) => {
518 if n_value_codes <= 2usize.pow(8) {
519 self.decode_index_buffer::<T, 1, u8>(&$values, index_buffer)
520 } else if n_value_codes <= 2usize.pow(16) {
521 self.decode_index_buffer::<T, 2, u16>(&$values, index_buffer)
522 } else if n_value_codes <= 2usize.pow(32) {
523 self.decode_index_buffer::<T, 4, u32>(&$values, index_buffer)
524 } else if n_value_codes <= 2usize.pow(64) {
525 self.decode_index_buffer::<T, 8, u64>(&$values, index_buffer)
526 } else {
527 return Err(io::Error::new(
528 io::ErrorKind::Unsupported,
529 "Cannot decode a dictionary with more than 2 ** 64 indices",
530 ));
531 }
532 };
533 }
534
535 let values = if value_width <= 1 {
536 let values = self.decode_value_buffer::<T, 1, u8>(value_buffer, n_value_codes);
537 decode_indices!(values)
538 } else if value_width <= 2 {
539 let values = self.decode_value_buffer::<T, 2, u16>(value_buffer, n_value_codes);
540 decode_indices!(values)
541 } else if value_width <= 4 {
542 let values = self.decode_value_buffer::<T, 4, u32>(value_buffer, n_value_codes);
543 decode_indices!(values)
544 } else if value_width <= 8 {
545 let values = self.decode_value_buffer::<T, 8, u64>(value_buffer, n_value_codes);
546 decode_indices!(values)
547 } else {
548 return Err(io::Error::new(
549 io::ErrorKind::Unsupported,
550 "Cannot decode dictionary with value byte width greater than 8",
551 ));
552 };
553
554 Ok(values)
555 }
556 }
557
558 pub fn dictionary_encoding<T: Pod>(data: &[T]) -> Result<Vec<u8>, io::Error> {
559 let mut encoder = DictionaryEncoder::new(true);
560 encoder.encode(data)
561 }
562
563 pub fn dictionary_decoding<T: Pod>(buffer: &[u8]) -> io::Result<Vec<T>> {
564 let mut decoder = DictionaryDecoder::new(true);
565 decoder.decode(buffer)
566 }
567}
568
569#[allow(unused)]
570pub use byte_rotation::*;
571
572#[allow(unused)]
573pub use dictionary_encoding::{dictionary_decoding, dictionary_encoding};
574
575#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord, Default)]
578#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
579pub enum ArrayType {
580 #[default]
582 Unknown,
583 MZArray,
585 IntensityArray,
588 ChargeArray,
590 SignalToNoiseArray,
592 TimeArray,
595 WavelengthArray,
598
599 IonMobilityArray,
602
603 MeanIonMobilityArray,
606 MeanDriftTimeArray,
609 MeanInverseReducedIonMobilityArray,
612
613 RawIonMobilityArray,
616 RawDriftTimeArray,
619 RawInverseReducedIonMobilityArray,
622
623 DeconvolutedIonMobilityArray,
627 DeconvolutedDriftTimeArray,
631 DeconvolutedInverseReducedIonMobilityArray,
635
636 ScanningQuadrupolePositionLowerBoundMZ,
639 ScanningQuadrupolePositionUpperBoundMZ,
642
643 IndexArray,
645
646 BaselineArray,
648 ResolutionArray,
650 PressureArray,
652 TemperatureArray,
654 FlowRateArray,
656
657 NonStandardDataArray {
660 name: Box<String>,
661 },
662}
663
664impl Display for ArrayType {
665 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
666 write!(f, "{:?}", self)
667 }
668}
669
670impl ArrayType {
671 pub const fn preferred_dtype(&self) -> BinaryDataArrayType {
687 match self {
688 ArrayType::MZArray => BinaryDataArrayType::Float64,
689 ArrayType::IntensityArray => BinaryDataArrayType::Float32,
690 ArrayType::ChargeArray => BinaryDataArrayType::Int32,
691 ArrayType::IndexArray => BinaryDataArrayType::Int64,
692 _ => BinaryDataArrayType::Float32,
693 }
694 }
695
696 pub const fn as_mean_ion_mobility(&self) -> Option<ArrayType> {
709 Some(match self {
710 Self::RawDriftTimeArray
711 | Self::DeconvolutedDriftTimeArray
712 | Self::MeanDriftTimeArray => Self::MeanDriftTimeArray,
713 Self::RawInverseReducedIonMobilityArray
714 | Self::DeconvolutedInverseReducedIonMobilityArray
715 | Self::MeanInverseReducedIonMobilityArray => Self::MeanInverseReducedIonMobilityArray,
716 Self::RawIonMobilityArray
717 | Self::DeconvolutedIonMobilityArray
718 | Self::MeanIonMobilityArray => Self::MeanIonMobilityArray,
719 _ => return None,
720 })
721 }
722
723 pub const fn as_raw_ion_mobility(&self) -> Option<ArrayType> {
725 Some(match self {
726 Self::RawDriftTimeArray
727 | Self::DeconvolutedDriftTimeArray
728 | Self::MeanDriftTimeArray => Self::RawDriftTimeArray,
729 Self::RawInverseReducedIonMobilityArray
730 | Self::DeconvolutedInverseReducedIonMobilityArray
731 | Self::MeanInverseReducedIonMobilityArray => Self::RawInverseReducedIonMobilityArray,
732 Self::RawIonMobilityArray
733 | Self::DeconvolutedIonMobilityArray
734 | Self::MeanIonMobilityArray => Self::RawIonMobilityArray,
735 _ => return None,
736 })
737 }
738
739 pub const fn as_deconvoluted_ion_mobility(&self) -> Option<ArrayType> {
741 Some(match self {
742 Self::RawDriftTimeArray
743 | Self::DeconvolutedDriftTimeArray
744 | Self::MeanDriftTimeArray => Self::DeconvolutedDriftTimeArray,
745 Self::RawInverseReducedIonMobilityArray
746 | Self::DeconvolutedInverseReducedIonMobilityArray
747 | Self::MeanInverseReducedIonMobilityArray => {
748 Self::DeconvolutedInverseReducedIonMobilityArray
749 }
750 Self::RawIonMobilityArray
751 | Self::DeconvolutedIonMobilityArray
752 | Self::MeanIonMobilityArray => Self::DeconvolutedIonMobilityArray,
753 _ => return None,
754 })
755 }
756
757 pub fn nonstandard<S: ToString>(name: S) -> ArrayType {
759 ArrayType::NonStandardDataArray {
760 name: name.to_string().into(),
761 }
762 }
763
764 pub const fn preferred_unit(&self) -> Option<Unit> {
766 let unit = match self {
767 Self::MZArray | Self::ScanningQuadrupolePositionLowerBoundMZ | Self::ScanningQuadrupolePositionUpperBoundMZ => Unit::MZ,
768 Self::IntensityArray => Unit::DetectorCounts,
769 Self::WavelengthArray => Unit::Nanometer,
770 Self::TimeArray | Self::FlowRateArray => Unit::Minute,
771 Self::PressureArray => Unit::Pascal,
772 Self::RawDriftTimeArray | Self::MeanDriftTimeArray | Self::DeconvolutedDriftTimeArray => Unit::Millisecond,
773 Self::RawInverseReducedIonMobilityArray | Self::MeanInverseReducedIonMobilityArray | Self::DeconvolutedInverseReducedIonMobilityArray => Unit::VoltSecondPerSquareCentimeter,
774 _ => return None
775 };
776 Some(unit)
777 }
778
779 pub const fn is_ion_mobility(&self) -> bool {
789 matches!(
790 self,
791 Self::IonMobilityArray
792 | Self::MeanIonMobilityArray
793 | Self::MeanDriftTimeArray
794 | Self::MeanInverseReducedIonMobilityArray
795 | Self::DeconvolutedIonMobilityArray
796 | Self::DeconvolutedDriftTimeArray
797 | Self::DeconvolutedInverseReducedIonMobilityArray
798 | Self::RawIonMobilityArray
799 | Self::RawDriftTimeArray
800 | Self::RawInverseReducedIonMobilityArray,
801 )
802 }
803
804 pub fn as_param(&self, unit: Option<Unit>) -> Param {
812 const CV: ControlledVocabulary = ControlledVocabulary::MS;
813 let unit = unit.or_else(|| self.preferred_unit());
814
815 if let Self::NonStandardDataArray { name } = self {
816 let mut p = CV.param_val(
817 1000786,
818 "non-standard data array",
819 name.to_string()
820 );
821 p.unit = unit.unwrap_or_default();
822 p
823 }
824 else {
825 match unit {
826 Some(unit) => self.as_param_with_unit_const(unit).into(),
827 None => self.as_param_const().into()
828 }
829 }
830
831 }
959
960 pub const fn as_param_const(&self) -> ParamCow<'static> {
971 const CV: ControlledVocabulary = ControlledVocabulary::MS;
972
973 match self {
974 ArrayType::MZArray => CV.const_param_ident_unit("m/z array", 1000514, self.preferred_unit().unwrap()),
975 ArrayType::IntensityArray => {
976 CV.const_param_ident_unit("intensity array", 1000515, self.preferred_unit().unwrap())
977 }
978 ArrayType::ChargeArray => CV.const_param_ident("charge array", 1000516),
979 ArrayType::TimeArray => CV.const_param_ident_unit("time array", 1000595, self.preferred_unit().unwrap()),
980 ArrayType::WavelengthArray => {
981 CV.const_param_ident_unit("wavelength array", 1000617, self.preferred_unit().unwrap())
982 }
983 ArrayType::SignalToNoiseArray => CV.const_param_ident("signal to noise array", 1000517),
984 ArrayType::IonMobilityArray => CV.const_param_ident("ion mobility array", 1002893),
985 ArrayType::RawIonMobilityArray => {
986 CV.const_param_ident("raw ion mobility array", 1003007)
987 }
988 ArrayType::MeanIonMobilityArray => {
989 CV.const_param_ident("mean ion mobility array", 1002816)
990 }
991 ArrayType::DeconvolutedIonMobilityArray => {
992 CV.const_param_ident("deconvoluted ion mobility array", 1003154)
993 }
994 ArrayType::RawDriftTimeArray => CV.const_param_ident_unit(
995 "raw ion mobility drift time array",
996 1003153,
997 self.preferred_unit().unwrap(),
998 ),
999 ArrayType::RawInverseReducedIonMobilityArray => CV.const_param_ident_unit(
1000 "raw inverse reduced ion mobility array",
1001 1003008,
1002 self.preferred_unit().unwrap(),
1003 ),
1004
1005 ArrayType::MeanDriftTimeArray => CV.const_param_ident_unit(
1006 "mean ion mobility drift time array",
1007 1002477,
1008 self.preferred_unit().unwrap(),
1009 ),
1010 ArrayType::MeanInverseReducedIonMobilityArray => CV.const_param_ident_unit(
1011 "mean inverse reduced ion mobility array",
1012 1003006,
1013 self.preferred_unit().unwrap(),
1014 ),
1015
1016 ArrayType::DeconvolutedDriftTimeArray => CV.const_param_ident_unit(
1017 "deconvoluted ion mobility drift time array",
1018 1003156,
1019 self.preferred_unit().unwrap(),
1020 ),
1021 ArrayType::DeconvolutedInverseReducedIonMobilityArray => CV.const_param_ident_unit(
1022 "deconvoluted inverse reduced ion mobility array",
1023 1003155,
1024 self.preferred_unit().unwrap(),
1025 ),
1026
1027 ArrayType::NonStandardDataArray { name: _name } => {
1028 panic!(
1029 "Cannot format NonStandardDataArray in a const context, please use `as_param`"
1030 );
1031 }
1032 ArrayType::BaselineArray => CV.const_param_ident("baseline array", 1002530),
1033 ArrayType::ResolutionArray => CV.const_param_ident("resolution array", 1002529),
1034 ArrayType::PressureArray => CV.const_param_ident_unit("pressure array", 1000821, self.preferred_unit().unwrap()),
1035 ArrayType::TemperatureArray => CV.const_param_ident("temperature array", 1000822),
1036 ArrayType::FlowRateArray => CV.const_param_ident_unit("flow rate array", 1000820, self.preferred_unit().unwrap()),
1037 ArrayType::ScanningQuadrupolePositionLowerBoundMZ => {
1038 let mut p = CV.const_param_ident("scanning quadrupole position lower bound m/z array", 1003157);
1039 p.unit = self.preferred_unit().unwrap();
1040 p
1041 }
1042 ArrayType::IndexArray => {
1043 CV.const_param_ident("index array", 1003870)
1044 }
1045 ArrayType::ScanningQuadrupolePositionUpperBoundMZ => {
1046 let mut p = CV.const_param_ident("scanning quadrupole position upper bound m/z array", 1003158);
1047 p.unit = self.preferred_unit().unwrap();
1048 p
1049 }
1050 _ => {
1051 panic!("Could not determine how to name for array");
1052 }
1053 }
1054 }
1055
1056 pub const fn as_param_with_unit_const(&self, unit: Unit) -> ParamCow<'static> {
1068 let mut inner = self.as_param_const();
1069 inner.unit = unit;
1070 inner
1071 }
1072
1073 pub fn from_accession(x: CURIE) -> Option<Self> {
1075 let tp = if x == Self::MZArray.as_param_const().curie().unwrap() {
1076 Self::MZArray
1077 } else if x == Self::IntensityArray.as_param_const().curie().unwrap() {
1078 Self::IntensityArray
1079 } else if x == Self::ChargeArray.as_param_const().curie().unwrap() {
1080 Self::ChargeArray
1081 } else if x == Self::SignalToNoiseArray.as_param_const().curie().unwrap() {
1082 Self::SignalToNoiseArray
1083 } else if x == Self::TimeArray.as_param_const().curie().unwrap() {
1084 Self::TimeArray
1085 } else if x == Self::WavelengthArray.as_param_const().curie().unwrap() {
1086 Self::WavelengthArray
1087 } else if x == Self::IonMobilityArray.as_param_const().curie().unwrap() {
1088 Self::IonMobilityArray
1089 } else if x == Self::MeanIonMobilityArray.as_param_const().curie().unwrap() {
1090 Self::MeanIonMobilityArray
1091 } else if x == Self::MeanDriftTimeArray.as_param_const().curie().unwrap() {
1092 Self::MeanDriftTimeArray
1093 } else if x
1094 == Self::MeanInverseReducedIonMobilityArray
1095 .as_param_const()
1096 .curie()
1097 .unwrap()
1098 {
1099 Self::MeanInverseReducedIonMobilityArray
1100 } else if x == Self::RawIonMobilityArray.as_param_const().curie().unwrap() {
1101 Self::RawIonMobilityArray
1102 } else if x == Self::RawDriftTimeArray.as_param_const().curie().unwrap() {
1103 Self::RawDriftTimeArray
1104 } else if x
1105 == Self::RawInverseReducedIonMobilityArray
1106 .as_param_const()
1107 .curie()
1108 .unwrap()
1109 {
1110 Self::RawInverseReducedIonMobilityArray
1111 } else if x
1112 == Self::DeconvolutedIonMobilityArray
1113 .as_param_const()
1114 .curie()
1115 .unwrap()
1116 {
1117 Self::DeconvolutedIonMobilityArray
1118 } else if x
1119 == Self::DeconvolutedDriftTimeArray
1120 .as_param_const()
1121 .curie()
1122 .unwrap()
1123 {
1124 Self::DeconvolutedDriftTimeArray
1125 } else if x
1126 == Self::DeconvolutedInverseReducedIonMobilityArray
1127 .as_param_const()
1128 .curie()
1129 .unwrap()
1130 {
1131 Self::DeconvolutedInverseReducedIonMobilityArray
1132 } else if x == Self::BaselineArray.as_param_const().curie().unwrap() {
1133 Self::BaselineArray
1134 } else if x == Self::ResolutionArray.as_param_const().curie().unwrap() {
1135 Self::ResolutionArray
1136 } else if x == Self::PressureArray.as_param_const().curie().unwrap() {
1137 Self::PressureArray
1138 } else if x == Self::TemperatureArray.as_param_const().curie().unwrap() {
1139 Self::TemperatureArray
1140 } else if x == Self::FlowRateArray.as_param_const().curie().unwrap() {
1141 Self::FlowRateArray
1142 } else if x == Self::ScanningQuadrupolePositionLowerBoundMZ.as_param_const().curie().unwrap() {
1143 Self::ScanningQuadrupolePositionLowerBoundMZ
1144 } else if x == Self::ScanningQuadrupolePositionUpperBoundMZ.as_param_const().curie().unwrap() {
1145 Self::ScanningQuadrupolePositionUpperBoundMZ
1146 } else if x == Self::IndexArray.as_param_const().curie().unwrap() {
1147 Self::IndexArray
1148 }
1149 else if x
1150 == (Self::NonStandardDataArray {
1151 name: "".to_string().into(),
1152 })
1153 .as_param(None)
1154 .curie()
1155 .unwrap()
1156 {
1157 Self::NonStandardDataArray {
1158 name: "".to_string().into(),
1159 }
1160 } else {
1161 return None;
1162 };
1163 Some(tp)
1164 }
1165}
1166
1167#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, Default)]
1170#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1171pub enum BinaryDataArrayType {
1172 #[default]
1174 Unknown,
1175 Float64,
1177 Float32,
1179 Int64,
1181 Int32,
1183 ASCII,
1185}
1186
1187impl Display for BinaryDataArrayType {
1188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1189 write!(f, "{:?}", self)
1190 }
1191}
1192
1193impl BinaryDataArrayType {
1194 pub const fn size_of(&self) -> usize {
1205 match self {
1206 BinaryDataArrayType::Unknown | BinaryDataArrayType::ASCII => 1,
1207 BinaryDataArrayType::Float32 | BinaryDataArrayType::Int32 => 4,
1208 BinaryDataArrayType::Float64 | BinaryDataArrayType::Int64 => 8,
1209 }
1210 }
1211
1212 pub const fn as_param_const(&self) -> Option<ParamCow<'static>> {
1214 let name = match self {
1215 BinaryDataArrayType::Unknown => return None,
1216 BinaryDataArrayType::Float64 => "64-bit float",
1217 BinaryDataArrayType::Float32 => "32-bit float",
1218 BinaryDataArrayType::Int64 => "64-bit integer",
1219 BinaryDataArrayType::Int32 => "32-bit integer",
1220 BinaryDataArrayType::ASCII => "null-terminated ASCII string",
1221 };
1222 if let Some(curie) = self.curie() {
1223 Some(ParamCow::const_new(
1224 name,
1225 ValueRef::Empty,
1226 Some(curie.accession),
1227 Some(curie.controlled_vocabulary),
1228 Unit::Unknown,
1229 ))
1230 } else {
1231 None
1232 }
1233 }
1234
1235 pub const fn curie(&self) -> Option<CURIE> {
1237 match self {
1238 Self::Float32 => Some(curie!(MS:1000521)),
1239 Self::Float64 => Some(curie!(MS:1000523)),
1240 Self::Int32 => Some(curie!(MS:1000519)),
1241 Self::Int64 => Some(curie!(MS:1000522)),
1242 Self::ASCII => Some(curie!(MS:1001479)),
1243 _ => None,
1244 }
1245 }
1246
1247 pub fn from_accession(accession: CURIE) -> Option<Self> {
1248 match accession {
1249 x if Some(x) == Self::Float32.curie() => Some(Self::Float32),
1250 x if Some(x) == Self::Float64.curie() => Some(Self::Float64),
1251 x if Some(x) == Self::Int32.curie() => Some(Self::Int32),
1252 x if Some(x) == Self::Int64.curie() => Some(Self::Int64),
1253 x if Some(x) == Self::ASCII.curie() => Some(Self::ASCII),
1254 _ => None,
1255 }
1256 }
1257
1258 pub fn swap_bytes(&self, data: &mut [u8]) -> Result<(), ArrayRetrievalError> {
1270 let z = self.size_of();
1271 if !(data.len() % z == 0) {
1272 return Err(ArrayRetrievalError::DataTypeSizeMismatch)
1273 }
1274 match z {
1275 1 => {
1276 data.reverse();
1277 }
1278 4 => {
1279 data.as_chunks_mut::<4>().0.into_iter().for_each(|c| {
1280 *c = u32::from_ne_bytes(*c).swap_bytes().to_ne_bytes();
1281 });
1282 }
1283 8 => {
1284 data.as_chunks_mut::<8>().0.into_iter().for_each(|c| {
1285 *c = u64::from_ne_bytes(*c).swap_bytes().to_ne_bytes();
1286 });
1287 }
1294 x => {
1295 data.chunks_exact_mut(x).for_each(|c| c.reverse());
1296 }
1297 }
1298 Ok(())
1299 }
1300}
1301
1302#[derive(Debug, Clone, Copy, PartialEq, Hash, Default)]
1306#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1307pub enum BinaryCompressionType {
1308 #[default]
1310 NoCompression,
1311
1312 Zlib,
1316
1317 NumpressLinear,
1325
1326 NumpressSLOF,
1332
1333 NumpressPIC,
1339 NumpressLinearZlib,
1341 NumpressSLOFZlib,
1343 NumpressPICZlib,
1345 LinearPrediction,
1349 DeltaPrediction,
1353 Decoded,
1355 Zstd,
1363 ShuffleZstd,
1368 DeltaShuffleZstd,
1374 ZstdDict,
1381 NumpressLinearZstd,
1383 NumpressSLOFZstd,
1385 NumpressPICZstd,
1387}
1388
1389impl BinaryCompressionType {
1390 pub const COMPRESSION_METHODS: &[Self] = &[
1392 Self::NoCompression,
1393 Self::Zlib,
1394
1395 #[cfg(feature = "numpress")]
1396 Self::NumpressLinear,
1397 #[cfg(feature = "numpress")]
1398 Self::NumpressLinearZlib,
1399 #[cfg(feature = "numpress")]
1400 Self::NumpressSLOF,
1401 #[cfg(feature = "numpress")]
1402 Self::NumpressSLOFZlib,
1403
1404 #[cfg(feature = "zstd")]
1405 Self::Zstd,
1406 #[cfg(feature = "zstd")]
1407 Self::ShuffleZstd,
1408 #[cfg(feature = "zstd")]
1409 Self::DeltaShuffleZstd,
1410 #[cfg(feature = "zstd")]
1411 Self::ZstdDict,
1412
1413 #[cfg(all(feature = "zstd", feature = "numpress"))]
1414 Self::NumpressLinearZstd,
1415 #[cfg(all(feature = "zstd", feature = "numpress"))]
1416 Self::NumpressSLOFZstd,
1417 ];
1418
1419 pub fn unsupported_msg(&self, context: Option<&str>) -> String {
1421 match context {
1422 Some(ctx) => format!("Cannot decode array compressed with {:?} ({})", self, ctx),
1423 None => format!("Cannot decode array compressed with {:?}", self),
1424 }
1425 }
1426
1427 pub const fn is_endian_aware(&self) -> bool {
1430 match self {
1431 BinaryCompressionType::Zlib |
1432 BinaryCompressionType::NoCompression |
1433 BinaryCompressionType::DeltaPrediction |
1434 BinaryCompressionType::LinearPrediction |
1435 BinaryCompressionType::Zstd => false,
1436 _ => true,
1437
1438 }
1439 }
1440
1441 pub const fn accession(&self) -> Option<u32> {
1443 let acc = match self {
1444 BinaryCompressionType::NoCompression => 1000576,
1445 BinaryCompressionType::Zlib => 1000574,
1446 BinaryCompressionType::NumpressLinear => 1002312,
1447 BinaryCompressionType::NumpressSLOF => 1002314,
1448 BinaryCompressionType::NumpressPIC => 1002313,
1449 BinaryCompressionType::NumpressLinearZlib => 1002746,
1450 BinaryCompressionType::NumpressSLOFZlib => 1002748,
1451 BinaryCompressionType::NumpressPICZlib => 1002747,
1452 BinaryCompressionType::DeltaPrediction => 1003089,
1453 BinaryCompressionType::LinearPrediction => 1003090,
1454 BinaryCompressionType::NumpressSLOFZstd => 1003785,
1455 BinaryCompressionType::NumpressLinearZstd => 1003783,
1456 BinaryCompressionType::NumpressPICZstd => 1003784,
1457 BinaryCompressionType::ZstdDict => 1003782,
1458 BinaryCompressionType::Zstd => 1003780,
1459 BinaryCompressionType::ShuffleZstd => 1003781,
1460 BinaryCompressionType::DeltaShuffleZstd => 9999999,
1461 BinaryCompressionType::Decoded => return None,
1462 };
1463 Some(acc)
1464 }
1465
1466 pub fn from_accession(accession: CURIE) -> Option<Self> {
1468 match accession {
1469 CURIE {
1470 controlled_vocabulary: ControlledVocabulary::MS,
1471 accession: 1000576,
1472 } => Some(Self::NoCompression),
1473 CURIE {
1474 controlled_vocabulary: ControlledVocabulary::MS,
1475 accession: 1000574,
1476 } => Some(BinaryCompressionType::Zlib),
1477 CURIE {
1478 controlled_vocabulary: ControlledVocabulary::MS,
1479 accession: 1002312,
1480 } => Some(BinaryCompressionType::NumpressLinear),
1481 CURIE {
1482 controlled_vocabulary: ControlledVocabulary::MS,
1483 accession: 1002314,
1484 } => Some(BinaryCompressionType::NumpressSLOF),
1485 CURIE {
1486 controlled_vocabulary: ControlledVocabulary::MS,
1487 accession: 1002313,
1488 } => Some(BinaryCompressionType::NumpressPIC),
1489 CURIE {
1490 controlled_vocabulary: ControlledVocabulary::MS,
1491 accession: 1002746,
1492 } => Some(BinaryCompressionType::NumpressLinearZlib),
1493 CURIE {
1494 controlled_vocabulary: ControlledVocabulary::MS,
1495 accession: 1002748,
1496 } => Some(BinaryCompressionType::NumpressSLOFZlib),
1497 CURIE {
1498 controlled_vocabulary: ControlledVocabulary::MS,
1499 accession: 1002747,
1500 } => Some(BinaryCompressionType::NumpressPICZlib),
1501 CURIE {
1502 controlled_vocabulary: ControlledVocabulary::MS,
1503 accession: 1003089,
1504 } => Some(BinaryCompressionType::DeltaPrediction),
1505 CURIE {
1506 controlled_vocabulary: ControlledVocabulary::MS,
1507 accession: 1003090,
1508 } => Some(BinaryCompressionType::LinearPrediction),
1509 x if x
1510 == CURIE {
1511 controlled_vocabulary: ControlledVocabulary::MS,
1512 accession: BinaryCompressionType::NumpressSLOFZstd.accession().unwrap(),
1513 } =>
1514 {
1515 Some(BinaryCompressionType::NumpressSLOFZstd)
1516 }
1517 x if x
1518 == CURIE {
1519 controlled_vocabulary: ControlledVocabulary::MS,
1520 accession: BinaryCompressionType::NumpressPICZstd.accession().unwrap(),
1521 } =>
1522 {
1523 Some(BinaryCompressionType::NumpressPICZstd)
1524 }
1525 x if x
1526 == CURIE {
1527 controlled_vocabulary: ControlledVocabulary::MS,
1528 accession: BinaryCompressionType::NumpressLinearZstd
1529 .accession()
1530 .unwrap(),
1531 } =>
1532 {
1533 Some(BinaryCompressionType::NumpressLinearZstd)
1534 }
1535 x if x
1536 == CURIE {
1537 controlled_vocabulary: ControlledVocabulary::MS,
1538 accession: BinaryCompressionType::ZstdDict.accession().unwrap(),
1539 } =>
1540 {
1541 Some(BinaryCompressionType::ZstdDict)
1542 }
1543 x if x
1544 == CURIE {
1545 controlled_vocabulary: ControlledVocabulary::MS,
1546 accession: BinaryCompressionType::Zstd.accession().unwrap(),
1547 } =>
1548 {
1549 Some(BinaryCompressionType::Zstd)
1550 }
1551 x if x
1552 == CURIE {
1553 controlled_vocabulary: ControlledVocabulary::MS,
1554 accession: BinaryCompressionType::ShuffleZstd.accession().unwrap(),
1555 } =>
1556 {
1557 Some(BinaryCompressionType::ShuffleZstd)
1558 }
1559 x if x
1560 == CURIE {
1561 controlled_vocabulary: ControlledVocabulary::MS,
1562 accession: BinaryCompressionType::DeltaShuffleZstd.accession().unwrap(),
1563 } =>
1564 {
1565 Some(BinaryCompressionType::DeltaShuffleZstd)
1566 }
1567 _ => None,
1568 }
1569 }
1570
1571 pub const fn as_param(&self) -> Option<ParamCow<'static>> {
1576 let (name, accession) = match self {
1577 BinaryCompressionType::Decoded => return None,
1578 BinaryCompressionType::NoCompression => ("no compression", self.accession()),
1579 BinaryCompressionType::Zlib => ("zlib compression", self.accession()),
1580 BinaryCompressionType::NumpressLinear => (
1581 "MS-Numpress linear prediction compression",
1582 self.accession(),
1583 ),
1584 BinaryCompressionType::NumpressSLOF => (
1585 "MS-Numpress short logged float compression",
1586 self.accession(),
1587 ),
1588 BinaryCompressionType::NumpressPIC => {
1589 ("MS-Numpress positive integer compression", self.accession())
1590 }
1591 BinaryCompressionType::NumpressLinearZlib => (
1592 "MS-Numpress linear prediction compression followed by zlib compression",
1593 self.accession(),
1594 ),
1595 BinaryCompressionType::NumpressSLOFZlib => (
1596 "MS-Numpress short logged float compression followed by zlib compression",
1597 self.accession(),
1598 ),
1599 BinaryCompressionType::NumpressPICZlib => (
1600 "MS-Numpress positive integer compression followed by zlib compression",
1601 self.accession(),
1602 ),
1603 BinaryCompressionType::DeltaPrediction => (
1604 "truncation, delta prediction and zlib compression",
1605 self.accession(),
1606 ),
1607 BinaryCompressionType::LinearPrediction => (
1608 "truncation, linear prediction and zlib compression",
1609 self.accession(),
1610 ),
1611 BinaryCompressionType::NumpressSLOFZstd => {
1612 return Some(ParamCow::const_new(
1613 "MS-Numpress short logged float compression followed by zstd compression",
1614 ValueRef::Empty,
1615 self.accession(),
1616 Some(ControlledVocabulary::MS),
1617 Unit::Unknown,
1618 ))
1619 }
1620 BinaryCompressionType::NumpressLinearZstd => {
1621 return Some(ParamCow::const_new(
1622 "MS-Numpress linear prediction compression followed by zstd compression",
1623 ValueRef::Empty,
1624 self.accession(),
1625 Some(ControlledVocabulary::MS),
1626 Unit::Unknown,
1627 ))
1628 }
1629 BinaryCompressionType::NumpressPICZstd => {
1630 return Some(ParamCow::const_new(
1631 "MS-Numpress positive integer compression followed by zstd compression",
1632 ValueRef::Empty,
1633 self.accession(),
1634 Some(ControlledVocabulary::MS),
1635 Unit::Unknown,
1636 ))
1637 }
1638 BinaryCompressionType::ZstdDict => {
1639 return Some(ParamCow::const_new(
1640 "dict-zstd compression",
1641 ValueRef::Empty,
1642 self.accession(),
1643 Some(ControlledVocabulary::MS),
1644 Unit::Unknown,
1645 ))
1646 }
1647 BinaryCompressionType::Zstd => {
1648 return Some(ParamCow::const_new(
1649 "zstd compression",
1650 ValueRef::Empty,
1651 self.accession(),
1652 Some(ControlledVocabulary::MS),
1653 Unit::Unknown,
1654 ))
1655 }
1656 BinaryCompressionType::ShuffleZstd => {
1657 return Some(ParamCow::const_new(
1658 "byte-shuffle-zstd compression",
1659 ValueRef::Empty,
1660 self.accession(),
1661 Some(ControlledVocabulary::MS),
1662 Unit::Unknown,
1663 ))
1664 }
1665 BinaryCompressionType::DeltaShuffleZstd => {
1666 return Some(ParamCow::const_new(
1667 "delta-byte-shuffle-zstd compression",
1668 ValueRef::Empty,
1669 self.accession(),
1670 Some(ControlledVocabulary::MS),
1671 Unit::Unknown,
1672 ))
1673 }
1674 };
1675 Some(
1676 ControlledVocabulary::MS
1677 .const_param_ident(name, unsafe { accession.unwrap_unchecked() }),
1678 )
1679 }
1680}
1681
1682impl Display for BinaryCompressionType {
1683 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1684 write!(f, "{:?}", self)
1685 }
1686}
1687
1688#[derive(Debug, Clone, Error, PartialEq)]
1692pub enum ArrayRetrievalError {
1693 #[error("Array type {0:?} not found")]
1694 NotFound(ArrayType),
1695 #[error("An error occurred while decompressing: {0}")]
1696 DecompressionError(String),
1697 #[error("The requested data type does not match the number of bytes available in the buffer, or the conversion is unsupported")]
1698 DataTypeSizeMismatch,
1699 #[error("The content was not properly Base64 encoded")]
1700 MalformedBase64Encoding,
1701}
1702
1703impl From<bytemuck::PodCastError> for ArrayRetrievalError {
1704 fn from(value: bytemuck::PodCastError) -> Self {
1705 match value {
1706 bytemuck::PodCastError::TargetAlignmentGreaterAndInputNotAligned => {
1707 Self::DataTypeSizeMismatch
1708 }
1709 bytemuck::PodCastError::OutputSliceWouldHaveSlop => Self::DataTypeSizeMismatch,
1710 bytemuck::PodCastError::SizeMismatch => Self::DataTypeSizeMismatch,
1711 bytemuck::PodCastError::AlignmentMismatch => Self::DataTypeSizeMismatch,
1712 }
1713 }
1714}
1715
1716impl From<ArrayRetrievalError> for io::Error {
1717 fn from(value: ArrayRetrievalError) -> Self {
1718 match value {
1719 ArrayRetrievalError::NotFound(_) => io::Error::new(io::ErrorKind::NotFound, value),
1720 ArrayRetrievalError::DecompressionError(e) => {
1721 io::Error::new(io::ErrorKind::InvalidData, e)
1722 }
1723 ArrayRetrievalError::DataTypeSizeMismatch => {
1724 io::Error::new(io::ErrorKind::InvalidData, value)
1725 },
1726 ArrayRetrievalError::MalformedBase64Encoding => {
1727 io::Error::new(io::ErrorKind::InvalidData, value)
1728 }
1729 }
1730 }
1731}
1732
1733#[cfg(feature = "numpress")]
1734impl From<numpress::Error> for ArrayRetrievalError {
1735 fn from(value: numpress::Error) -> Self {
1736 ArrayRetrievalError::DecompressionError(value.to_string())
1737 }
1738}
1739
1740pub fn linear_prediction_decoding<F: Num + Copy + Mul + AddAssign>(values: &mut [F]) -> &mut [F] {
1742 if values.len() < 2 {
1743 return values;
1744 }
1745
1746 let two = F::one() + F::one();
1747
1748 let prev2 = values[1];
1749 let prev1 = values[2];
1750 let offset = values[1];
1751
1752 values
1753 .iter_mut()
1754 .skip(2)
1755 .fold((prev1, prev2), |(prev1, prev2), current| {
1756 let tmp = *current + two * prev1 - prev2 - offset;
1757 let prev1 = *current;
1758 let prev2 = prev1;
1759 *current = tmp;
1760 (prev1, prev2)
1761 });
1762
1763 for i in 0..values.len() {
1764 if i < 2 {
1765 continue;
1766 }
1767 let v = values[i] + two * values[i - 1] - values[i - 2] - values[1];
1768 values[i] = v;
1769 }
1770 values
1771}
1772
1773pub fn linear_prediction_encoding<F: Num + Copy + Mul<F> + AddAssign>(
1775 values: &mut [F],
1776) -> &mut [F] {
1777 let n = values.len();
1778 if n < 3 {
1779 return values;
1780 }
1781 let offset = values[1];
1782 let prev2 = values[0];
1783 let prev1 = values[1];
1784 let two = F::one() + F::one();
1785
1786 values
1787 .iter_mut()
1788 .fold((prev1, prev2), |(prev1, prev2), val| {
1789 *val += offset - two * prev1 + prev2;
1790 let tmp = prev1;
1791 let prev1 = *val + two * prev1 - prev2 - offset;
1792 let prev2 = tmp;
1793 (prev1, prev2)
1794 });
1795 values
1796}
1797
1798pub fn delta_decoding<F: Num + Copy + Mul + AddAssign>(values: &mut [F]) -> &mut [F] {
1800 if values.len() < 2 {
1801 return values;
1802 }
1803
1804 let offset = values[0];
1805 let prev = values[1];
1806
1807 values.iter_mut().skip(2).fold(prev, |prev, current| {
1808 *current += prev - offset;
1809 *current
1810 });
1811 values
1812}
1813
1814pub fn delta_encoding<F: Num + Copy + Mul + AddAssign>(values: &mut [F]) -> &mut [F] {
1816 let n = values.len();
1817 if n < 2 {
1818 return values;
1819 }
1820 let prev = values[0];
1821 let offset = values[0];
1822
1823 let it = values.iter_mut();
1824 it.skip(1).fold(prev, |prev, current| {
1825 let tmp = *current;
1826 *current += offset - prev;
1827 tmp
1828 });
1829 values
1830}
1831
1832#[cfg(test)]
1833mod test {
1834 use super::*;
1835
1836 #[test]
1837 fn test_dtype_size() {
1838 assert_eq!(BinaryDataArrayType::ASCII.size_of(), 1);
1839 assert_eq!(BinaryDataArrayType::Float32.size_of(), 4);
1840 assert_eq!(BinaryDataArrayType::Int32.size_of(), 4);
1841 assert_eq!(BinaryDataArrayType::Float64.size_of(), 8);
1842 assert_eq!(BinaryDataArrayType::Int64.size_of(), 8);
1843 }
1844
1845 #[test]
1846 fn test_array_type_param() {
1847 let array_types = [
1848 ArrayType::MZArray,
1849 ArrayType::IntensityArray,
1850 ArrayType::ChargeArray,
1851 ArrayType::SignalToNoiseArray,
1852 ArrayType::TimeArray,
1853 ArrayType::WavelengthArray,
1854 ArrayType::IonMobilityArray,
1855 ArrayType::MeanIonMobilityArray,
1856 ArrayType::RawIonMobilityArray,
1857 ArrayType::DeconvolutedIonMobilityArray,
1858 ];
1859
1860 for at in array_types {
1861 assert_eq!(at.as_param_const().name, at.as_param(None).name)
1862 }
1863 }
1864
1865 #[test]
1866 fn test_binary_encoding_conv() {
1867 let encodings = [
1868 BinaryCompressionType::Decoded,
1869 BinaryCompressionType::NoCompression,
1870 BinaryCompressionType::NumpressLinear,
1871 BinaryCompressionType::NumpressLinearZlib,
1872 BinaryCompressionType::NumpressPIC,
1873 BinaryCompressionType::NumpressPICZlib,
1874 BinaryCompressionType::NumpressSLOF,
1875 BinaryCompressionType::NumpressSLOFZlib,
1876 BinaryCompressionType::Zlib,
1877 ];
1878
1879 for enc in encodings {
1880 let reps = match enc {
1881 BinaryCompressionType::NoCompression => ("no compression", 1000576),
1882 BinaryCompressionType::Zlib => ("zlib compression", 1000574),
1883 BinaryCompressionType::NumpressLinear => {
1884 ("MS-Numpress linear prediction compression", 1002312)
1885 }
1886 BinaryCompressionType::NumpressSLOF => {
1887 ("MS-Numpress short logged float compression", 1002314)
1888 }
1889 BinaryCompressionType::NumpressPIC => {
1890 ("MS-Numpress positive integer compression", 1002313)
1891 }
1892 BinaryCompressionType::NumpressLinearZlib => (
1893 "MS-Numpress linear prediction compression followed by zlib compression",
1894 1002746,
1895 ),
1896 BinaryCompressionType::NumpressPICZlib => (
1897 "MS-Numpress positive integer compression followed by zlib compression",
1898 1002747,
1899 ),
1900 BinaryCompressionType::NumpressSLOFZlib => (
1901 "MS-Numpress short logged float compression followed by zlib compression",
1902 1002748,
1903 ),
1904 _ => ("", 0),
1905 };
1906 if let Some(p) = enc.as_param() {
1907 assert_eq!(p.name, reps.0);
1908 assert_eq!(p.accession.unwrap(), reps.1);
1909 }
1910 }
1911 }
1912
1913 #[test]
1914 fn test_transpose() {
1915 let data: Vec<_> = (0..128i32).map(|i| i.pow(2u32) as f64).collect();
1916 let flip = transpose_f64(&data);
1917 let rev = reverse_transpose_f64(&flip);
1918 let rev_cast: &[f64] = bytemuck::cast_slice(&rev);
1919 assert_eq!(data, rev_cast);
1920 }
1921
1922 #[test]
1923 fn test_dict() {
1924 let data: Vec<_> = (0..127i32).map(|i| i.pow(2u32) as f64).collect();
1925 let encoded = dictionary_encoding(&data).unwrap();
1926 let decoded: Vec<f64> = dictionary_decoding(&encoded).unwrap();
1927
1928 assert_eq!(data, decoded);
1929 }
1930
1931 #[test]
1932 fn test_byteswap() {
1933 let x = 42u32;
1934 let mut bytes_of = x.to_le_bytes();
1935 BinaryDataArrayType::Int32.swap_bytes(&mut bytes_of).unwrap();
1936 let y1 = u32::from_le_bytes(bytes_of);
1937 let y2 = x.swap_bytes();
1938 assert_eq!(y1, y2);
1939
1940 bytes_of = x.to_be_bytes();
1941 BinaryDataArrayType::Int32.swap_bytes(&mut bytes_of).unwrap();
1942 let y1 = u32::from_le_bytes(bytes_of);
1943 assert_eq!(x, y1);
1944 }
1945}