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 {
21 let n = data.len();
22 let mut buf = Vec::with_capacity(n * size_of::<T>());
23 for v in data {
24 buf.extend_from_slice(v.to_le_bytes().as_ref());
25 }
26 buf
27}
28
29pub fn as_bytes<T: Pod>(data: &[T]) -> &[u8] {
30 bytemuck::cast_slice(data)
31}
32
33pub fn vec_as_bytes<T: Pod>(data: Vec<T>) -> Bytes {
34 let mut buf = Bytes::with_capacity(data.len() * std::mem::size_of::<T>());
35 for val in data {
36 buf.extend_from_slice(bytemuck::bytes_of(&val));
37 }
38 buf
39}
40
41mod byte_rotation {
42 use super::*;
43
44 pub fn transpose_bytes_into<T: Pod, const N: usize>(data: &[T], buffer: &mut Vec<u8>) {
45 assert_eq!(core::mem::size_of::<T>(), N);
46 let bytes = bytemuck::cast_slice::<T, [u8; N]>(data);
47 buffer.clear();
48 let delta = (data.len() * N).saturating_sub(buffer.capacity());
49 if delta > 0 {
50 buffer.reserve(delta);
51 }
52
53 #[cfg(target_endian = "little")]
54 {
55 for i in 0..N {
56 buffer.extend(bytes.iter().map(|b| b[i]))
57 }
58 }
59 #[cfg(target_endian = "big")]
60 {
61 for i in (0..N).rev() {
62 buffer.extend(bytes.iter().map(|b| b[i]))
63 }
64 }
65 }
66
67 pub fn transpose_bytes<T: Pod, const N: usize>(data: &[T]) -> Bytes {
68 let mut result = Bytes::with_capacity(data.len() * N);
69 transpose_bytes_into::<T, N>(data, &mut result);
70 result
71 }
72
73 pub fn transpose_4bytes<T: Pod>(data: &[T]) -> Bytes {
74 assert_eq!(std::mem::size_of::<T>(), 4);
75 transpose_bytes::<_, 4>(data)
76 }
77
78 pub fn transpose_8bytes<T: Pod>(data: &[T]) -> Bytes {
79 assert_eq!(std::mem::size_of::<T>(), 8);
80 transpose_bytes::<_, 8>(data)
81 }
82
83 pub fn transpose_i32(data: &[i32]) -> Bytes {
84 transpose_4bytes(data)
85 }
86
87 pub fn transpose_f32(data: &[f32]) -> Bytes {
88 transpose_4bytes(data)
89 }
90
91 pub fn transpose_i64(data: &[i64]) -> Bytes {
92 transpose_8bytes(data)
93 }
94
95 pub fn transpose_f64(data: &[f64]) -> Bytes {
96 transpose_8bytes(data)
97 }
98
99 pub fn reverse_transpose_bytes_into<const N: usize>(data: &[u8], buffer: &mut Vec<u8>) {
100 let rem = data.len() % N;
101 assert_eq!(rem, 0);
102 let n_entries = data.len() / N;
103 buffer.clear();
104 buffer.resize(data.len(), 0);
105
106 #[cfg(target_endian = "little")]
107 {
108 for (i, band) in data.chunks_exact(n_entries).enumerate() {
109 for (j, byte) in band.iter().copied().enumerate() {
110 bytemuck::cast_slice_mut::<_, [u8; N]>(buffer)[j][i] = byte;
111 }
112 }
113 }
114 #[cfg(target_endian = "big")]
115 {
116 for (i, band) in data.chunks_exact(n_entries).enumerate() {
117 for (j, byte) in band.iter().copied().enumerate() {
118 bytemuck::cast_slice_mut::<_, [u8; N]>(buffer)[j][(N - 1) - i] = byte;
119 }
120 }
121 }
122 }
123
124 pub fn reverse_transpose_bytes<const N: usize>(data: &[u8]) -> Bytes {
125 let mut result: Bytes = vec![0; data.len()];
126 reverse_transpose_bytes_into::<N>(data, &mut result);
127 result
128 }
129
130 pub fn reverse_transpose_4bytes<T: Pod>(data: &[u8]) -> Bytes {
131 assert_eq!(std::mem::size_of::<T>(), 4);
132 reverse_transpose_bytes::<4>(data)
133 }
134
135 pub fn reverse_transpose_8bytes<T: Pod>(data: &[u8]) -> Bytes {
136 assert_eq!(std::mem::size_of::<T>(), 8);
137 reverse_transpose_bytes::<8>(data)
138 }
139
140 pub fn reverse_transpose_i32(data: &[u8]) -> Vec<u8> {
141 reverse_transpose_4bytes::<i32>(data)
142 }
143
144 pub fn reverse_transpose_f32(data: &[u8]) -> Vec<u8> {
145 reverse_transpose_4bytes::<f32>(data)
146 }
147
148 pub fn reverse_transpose_i64(data: &[u8]) -> Vec<u8> {
149 reverse_transpose_8bytes::<i64>(data)
150 }
151
152 pub fn reverse_transpose_f64(data: &[u8]) -> Vec<u8> {
153 reverse_transpose_8bytes::<f64>(data)
154 }
155}
156
157mod dictionary_encoding {
158 use super::*;
159 use io::prelude::*;
160 use num_traits::ops::bytes::{FromBytes, ToBytes};
161 use std::{
162 borrow::Cow,
163 collections::{HashMap, HashSet},
164 hash::Hash,
165 io::BufWriter,
166 };
167
168 trait DictValue<const W: usize>:
169 Pod + ToBytes<Bytes = [u8; W]> + Hash + Eq + Ord + FromBytes<Bytes = [u8; W]>
170 {
171 }
172
173 macro_rules! impl_dict_value {
174 ($val:ty, $size:literal) => {
175 impl DictValue<$size> for $val {}
176 };
177 }
178
179 impl_dict_value!(u8, 1);
180 impl_dict_value!(u16, 2);
181 impl_dict_value!(u32, 4);
182 impl_dict_value!(u64, 8);
183
184 trait DictIndex<const W: usize>:
185 Pod + ToBytes<Bytes = [u8; W]> + FromBytes<Bytes = [u8; W]>
186 {
187 fn from_usize(index: usize) -> Self;
188 fn to_usize(&self) -> usize;
189 }
190
191 macro_rules! impl_dict_index {
192 ($idx:ty, $size:literal) => {
193 impl DictIndex<$size> for $idx {
194 fn from_usize(index: usize) -> Self {
195 index as Self
196 }
197
198 fn to_usize(&self) -> usize {
199 *self as usize
200 }
201 }
202 };
203 }
204
205 impl_dict_index!(u8, 1);
206 impl_dict_index!(u16, 2);
207 impl_dict_index!(u32, 4);
208 impl_dict_index!(u64, 8);
209
210 #[derive(Default, Debug)]
211 pub struct DictionaryEncoder {
212 shuffle: bool,
213 buffer: Vec<u8>,
214 }
215
216 impl DictionaryEncoder {
217 pub fn new(shuffle: bool) -> Self {
218 Self {
219 shuffle,
220 buffer: Vec::new(),
221 }
222 }
223
224 fn build_value_map<T: Pod, const W1: usize, V: DictValue<W1>>(
225 &self,
226 data: &[T],
227 ) -> (Vec<V>, HashMap<V, usize>) {
228 debug_assert_eq!(core::mem::size_of::<T>(), core::mem::size_of::<V>());
229 debug_assert_eq!(core::mem::size_of::<T>(), W1);
230 let mut value_codes = HashSet::new();
231 for v in data {
232 let k: V = *bytemuck::from_bytes(bytemuck::bytes_of(v));
233 value_codes.insert(k);
234 }
235
236 let mut value_codes: Vec<_> = value_codes.into_iter().collect();
237 value_codes.sort();
238
239 let byte_map: HashMap<V, usize> = value_codes
240 .iter()
241 .enumerate()
242 .map(|(i, k)| (*k, i))
243 .collect();
244 (value_codes, byte_map)
245 }
246
247 fn create_writer<
248 T: Pod,
249 const W1: usize,
250 V: Pod + Ord + Hash + ToBytes<Bytes = [u8; W1]> + Eq,
251 const W2: usize,
252 K: DictIndex<W2>,
253 >(
254 &self,
255 data: &[T],
256 value_codes: &[V],
257 ) -> BufWriter<Vec<u8>> {
258 let data_offset = 16 + std::mem::size_of_val(value_codes);
259 let dict_buffer: Vec<u8> =
260 Vec::with_capacity(data_offset + data.len() * core::mem::size_of::<K>());
261 BufWriter::new(dict_buffer)
262 }
263
264 fn encode_dict_indices<
265 T: Pod,
266 const W1: usize,
267 V: Pod + Ord + Hash + ToBytes<Bytes = [u8; W1]> + Eq,
268 const W2: usize,
269 K: DictIndex<W2>,
270 >(
271 &mut self,
272 data: &[T],
273 value_codes: &[V],
274 byte_map: HashMap<V, usize>,
275 ) -> io::Result<Vec<u8>> {
276 let data_offset = 16 + std::mem::size_of_val(value_codes);
277 let mut writer = self.create_writer::<T, W1, V, W2, K>(data, value_codes);
278 writer.write_all(&(data_offset as u64).to_le_bytes())?;
279 writer.write_all(&(value_codes.len() as u64).to_le_bytes())?;
280
281 if self.shuffle {
282 byte_rotation::transpose_bytes_into::<V, W1>(value_codes, &mut self.buffer);
284 writer.write_all(&self.buffer)?;
285 } else {
289 for v in value_codes.iter() {
290 let bts = v.to_le_bytes();
291 writer.write_all(&bts)?;
292 }
293 }
294
295 if self.shuffle {
296 let mut buf = Vec::with_capacity(data.len());
297 for v in data {
298 let i = *byte_map
299 .get(bytemuck::from_bytes(bytemuck::bytes_of(v)))
300 .unwrap();
301 let ik: K = K::from_usize(i);
302 buf.push(ik);
303 }
304 byte_rotation::transpose_bytes_into::<K, W2>(&buf, &mut self.buffer);
306 writer.write_all(&self.buffer)?;
307 } else {
308 for v in data {
309 let i = *byte_map
310 .get(bytemuck::from_bytes(bytemuck::bytes_of(v)))
311 .unwrap();
312 let ik: K = K::from_usize(i);
313 writer.write_all(&ik.to_le_bytes())?;
314 }
315 }
316
317 writer.flush()?;
318 let val = writer.into_inner().unwrap();
319 Ok(val)
320 }
321
322 fn encode_values<T: Pod, const W1: usize, V: DictValue<W1>>(
323 &mut self,
324 data: &[T],
325 ) -> Result<Vec<u8>, io::Error> {
326 let (value_codes, byte_map) = self.build_value_map(data);
327 let n_value_codes = value_codes.len();
328
329 if n_value_codes <= 2usize.pow(8) {
330 self.encode_dict_indices::<T, W1, V, 1, u8>(data, &value_codes, byte_map)
331 } else if n_value_codes <= 2usize.pow(16) {
332 self.encode_dict_indices::<T, W1, V, 2, u16>(data, &value_codes, byte_map)
333 } else if n_value_codes <= 2usize.pow(32) {
334 self.encode_dict_indices::<T, W1, V, 4, u32>(data, &value_codes, byte_map)
335 } else if n_value_codes <= 2usize.pow(64) {
336 self.encode_dict_indices::<T, W1, V, 8, u64>(data, &value_codes, byte_map)
337 } else {
338 Err(io::Error::new(
339 io::ErrorKind::Unsupported,
340 "Cannot encode a dictionary with more than 2 ** 64 values",
341 ))
342 }
343 }
344
345 pub fn encode<T: Pod>(&mut self, data: &[T]) -> io::Result<Bytes> {
346 if data.is_empty() {
347 return Ok(Vec::new());
348 }
349 let z_val = core::mem::size_of::<T>();
350 if z_val <= 1 {
351 self.encode_values::<T, 1, u8>(data)
352 } else if z_val <= 2 {
353 self.encode_values::<T, 2, u16>(data)
354 } else if z_val <= 4 {
355 self.encode_values::<T, 4, u32>(data)
356 } else if z_val <= 8 {
357 self.encode_values::<T, 8, u64>(data)
358 } else {
359 Err(io::Error::new(
360 io::ErrorKind::Unsupported,
361 "Cannot encode a dictionary with more than 2 ** 64 keys",
362 ))
363 }
364 }
365 }
366
367 #[derive(Default, Debug)]
368 pub struct DictionaryDecoder {
369 shuffle: bool,
370 buffer: Vec<u8>,
371 }
372
373 impl DictionaryDecoder {
374 pub fn new(shuffle: bool) -> Self {
375 Self {
376 shuffle,
377 buffer: Default::default(),
378 }
379 }
380
381 fn make_reader<'a>(&self, buffer: &'a [u8]) -> io::BufReader<&'a [u8]> {
382 io::BufReader::new(buffer)
383 }
384
385 fn decode_value_buffer<T: Pod, const W1: usize, V: DictValue<W1>>(
386 &mut self,
387 buffer: &[u8],
388 n_values: usize,
389 ) -> Vec<T> {
390 macro_rules! decode_chunk {
391 ($chunk:ident) => {{
392 let chunk_a: [u8; W1] = $chunk.try_into().unwrap();
393 let val = V::from_le_bytes(&chunk_a);
394 let val: T = *bytemuck::from_bytes(bytemuck::bytes_of(&val));
395 val
396 }};
397 }
398 let mut value_buffer = Vec::with_capacity(n_values);
399 if self.shuffle {
400 let blocks = match core::mem::size_of::<T>() {
401 1 => Cow::Borrowed(buffer),
402 2 => {
403 byte_rotation::reverse_transpose_bytes_into::<2>(buffer, &mut self.buffer);
404 Cow::Borrowed(self.buffer.as_slice())
405 }
406 4 => {
407 byte_rotation::reverse_transpose_bytes_into::<4>(buffer, &mut self.buffer);
408 Cow::Borrowed(self.buffer.as_slice())
409 }
410 8 => {
411 byte_rotation::reverse_transpose_bytes_into::<8>(buffer, &mut self.buffer);
412 Cow::Borrowed(self.buffer.as_slice())
413 }
414 x => {
415 panic!("Unsupported size {x}");
416 }
417 };
418 for chunk in blocks.chunks_exact(W1) {
419 let val = decode_chunk!(chunk);
420 value_buffer.push(val);
421 }
422 } else {
423 for chunk in buffer.chunks_exact(W1) {
424 let val = decode_chunk!(chunk);
425 value_buffer.push(val);
426 }
427 };
428 value_buffer
429 }
430
431 fn decode_index_buffer<T: Pod, const W2: usize, K: DictIndex<W2>>(
432 &mut self,
433 value_codes: &[T],
434 index_buffer: &[u8],
435 ) -> Vec<T> {
436 let mut result = Vec::with_capacity(index_buffer.len() / W2);
437 if self.shuffle {
438 byte_rotation::reverse_transpose_bytes_into::<W2>(index_buffer, &mut self.buffer);
439 for chunk in self.buffer.chunks_exact(W2) {
440 let b: [u8; W2] = chunk.try_into().unwrap();
441 let k: usize = K::from_le_bytes(&b).to_usize();
442 result.push(value_codes[k])
443 }
444 } else {
445 for chunk in index_buffer.chunks_exact(W2) {
446 let b: [u8; W2] = chunk.try_into().unwrap();
447 let k: usize = K::from_le_bytes(&b).to_usize();
448 result.push(value_codes[k])
449 }
450 }
451 result
452 }
453
454 pub fn decode<T: Pod>(&mut self, buffer: &[u8]) -> io::Result<Vec<T>> {
455 if buffer.is_empty() {
456 return Ok(Vec::new());
457 }
458 let mut reader = self.make_reader(buffer);
459 let mut z_buf = [0u8; 8];
460 reader.read_exact(&mut z_buf)?;
461 let data_offset = u64::from_le_bytes(z_buf);
462 if data_offset == 0 {
463 return Ok(Vec::new());
464 }
465 let mut z_buf = [0u8; 8];
466 reader.read_exact(&mut z_buf)?;
467 let n_value_codes = u64::from_le_bytes(z_buf);
468 if n_value_codes == 0 {
469 return Ok(Vec::new());
470 }
471 let value_buffer = &buffer[16..(data_offset as usize)];
472 let value_width = (data_offset - 16) / n_value_codes;
473 let index_buffer = &buffer[data_offset as usize..];
474
475 let n_value_codes = n_value_codes as usize;
476
477 macro_rules! decode_indices {
478 ($values:ident) => {
479 if n_value_codes <= 2usize.pow(8) {
480 self.decode_index_buffer::<T, 1, u8>(&$values, index_buffer)
481 } else if n_value_codes <= 2usize.pow(16) {
482 self.decode_index_buffer::<T, 2, u16>(&$values, index_buffer)
483 } else if n_value_codes <= 2usize.pow(32) {
484 self.decode_index_buffer::<T, 4, u32>(&$values, index_buffer)
485 } else if n_value_codes <= 2usize.pow(64) {
486 self.decode_index_buffer::<T, 8, u64>(&$values, index_buffer)
487 } else {
488 return Err(io::Error::new(
489 io::ErrorKind::Unsupported,
490 "Cannot decode a dictionary with more than 2 ** 64 indices",
491 ));
492 }
493 };
494 }
495
496 let values = if value_width <= 1 {
497 let values = self.decode_value_buffer::<T, 1, u8>(value_buffer, n_value_codes);
498 decode_indices!(values)
499 } else if value_width <= 2 {
500 let values = self.decode_value_buffer::<T, 2, u16>(value_buffer, n_value_codes);
501 decode_indices!(values)
502 } else if value_width <= 4 {
503 let values = self.decode_value_buffer::<T, 4, u32>(value_buffer, n_value_codes);
504 decode_indices!(values)
505 } else if value_width <= 8 {
506 let values = self.decode_value_buffer::<T, 8, u64>(value_buffer, n_value_codes);
507 decode_indices!(values)
508 } else {
509 return Err(io::Error::new(
510 io::ErrorKind::Unsupported,
511 "Cannot decode dictionary with value byte width greater than 8",
512 ));
513 };
514
515 Ok(values)
516 }
517 }
518
519 pub fn dictionary_encoding<T: Pod>(data: &[T]) -> Result<Vec<u8>, io::Error> {
520 let mut encoder = DictionaryEncoder::new(true);
521 encoder.encode(data)
522 }
523
524 pub fn dictionary_decoding<T: Pod>(buffer: &[u8]) -> io::Result<Vec<T>> {
525 let mut decoder = DictionaryDecoder::new(true);
526 decoder.decode(buffer)
527 }
528}
529
530pub use byte_rotation::*;
531
532pub use dictionary_encoding::{dictionary_decoding, dictionary_encoding};
533
534#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord, Default)]
537#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
538pub enum ArrayType {
539 #[default]
540 Unknown,
541 MZArray,
542 IntensityArray,
543 ChargeArray,
544 SignalToNoiseArray,
545 TimeArray,
546 WavelengthArray,
547
548 IonMobilityArray,
549 MeanIonMobilityArray,
550 MeanDriftTimeArray,
551 MeanInverseReducedIonMobilityArray,
552 RawIonMobilityArray,
553 RawDriftTimeArray,
554 RawInverseReducedIonMobilityArray,
555 DeconvolutedIonMobilityArray,
556 DeconvolutedDriftTimeArray,
557 DeconvolutedInverseReducedIonMobilityArray,
558
559 ScanningQuadrupolePositionLowerBoundMZ,
560 ScanningQuadrupolePositionUpperBoundMZ,
561
562 IndexArray,
563
564 BaselineArray,
565 ResolutionArray,
566 PressureArray,
567 TemperatureArray,
568 FlowRateArray,
569 NonStandardDataArray {
570 name: Box<String>,
571 },
572}
573
574impl Display for ArrayType {
575 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
576 write!(f, "{:?}", self)
577 }
578}
579
580impl ArrayType {
581 pub const fn preferred_dtype(&self) -> BinaryDataArrayType {
588 match self {
589 ArrayType::MZArray => BinaryDataArrayType::Float64,
590 ArrayType::IntensityArray => BinaryDataArrayType::Float32,
591 ArrayType::ChargeArray => BinaryDataArrayType::Int32,
592 ArrayType::IndexArray => BinaryDataArrayType::Int64,
593 _ => BinaryDataArrayType::Float32,
594 }
595 }
596
597 pub const fn as_mean_ion_mobility(&self) -> Option<ArrayType> {
599 Some(match self {
600 Self::RawDriftTimeArray
601 | Self::DeconvolutedDriftTimeArray
602 | Self::MeanDriftTimeArray => Self::MeanDriftTimeArray,
603 Self::RawInverseReducedIonMobilityArray
604 | Self::DeconvolutedInverseReducedIonMobilityArray
605 | Self::MeanInverseReducedIonMobilityArray => Self::MeanInverseReducedIonMobilityArray,
606 Self::RawIonMobilityArray
607 | Self::DeconvolutedIonMobilityArray
608 | Self::MeanIonMobilityArray => Self::MeanIonMobilityArray,
609 _ => return None,
610 })
611 }
612
613 pub const fn as_raw_ion_mobility(&self) -> Option<ArrayType> {
615 Some(match self {
616 Self::RawDriftTimeArray
617 | Self::DeconvolutedDriftTimeArray
618 | Self::MeanDriftTimeArray => Self::RawDriftTimeArray,
619 Self::RawInverseReducedIonMobilityArray
620 | Self::DeconvolutedInverseReducedIonMobilityArray
621 | Self::MeanInverseReducedIonMobilityArray => Self::RawInverseReducedIonMobilityArray,
622 Self::RawIonMobilityArray
623 | Self::DeconvolutedIonMobilityArray
624 | Self::MeanIonMobilityArray => Self::RawIonMobilityArray,
625 _ => return None,
626 })
627 }
628
629 pub const fn as_deconvoluted_ion_mobility(&self) -> Option<ArrayType> {
631 Some(match self {
632 Self::RawDriftTimeArray
633 | Self::DeconvolutedDriftTimeArray
634 | Self::MeanDriftTimeArray => Self::DeconvolutedDriftTimeArray,
635 Self::RawInverseReducedIonMobilityArray
636 | Self::DeconvolutedInverseReducedIonMobilityArray
637 | Self::MeanInverseReducedIonMobilityArray => {
638 Self::DeconvolutedInverseReducedIonMobilityArray
639 }
640 Self::RawIonMobilityArray
641 | Self::DeconvolutedIonMobilityArray
642 | Self::MeanIonMobilityArray => Self::DeconvolutedIonMobilityArray,
643 _ => return None,
644 })
645 }
646
647 pub fn nonstandard<S: ToString>(name: S) -> ArrayType {
649 ArrayType::NonStandardDataArray {
650 name: name.to_string().into(),
651 }
652 }
653
654 pub const fn is_ion_mobility(&self) -> bool {
656 matches!(
657 self,
658 Self::IonMobilityArray
659 | Self::MeanIonMobilityArray
660 | Self::MeanDriftTimeArray
661 | Self::MeanInverseReducedIonMobilityArray
662 | Self::DeconvolutedIonMobilityArray
663 | Self::DeconvolutedDriftTimeArray
664 | Self::DeconvolutedInverseReducedIonMobilityArray
665 | Self::RawIonMobilityArray
666 | Self::RawDriftTimeArray
667 | Self::RawInverseReducedIonMobilityArray,
668 )
669 }
670
671 pub fn as_param(&self, unit: Option<Unit>) -> Param {
676 const CV: ControlledVocabulary = ControlledVocabulary::MS;
677 match self {
678 ArrayType::MZArray => CV
679 .const_param_ident_unit("m/z array", 1000514, unit.unwrap_or(Unit::MZ))
680 .into(),
681 ArrayType::IntensityArray => CV
682 .const_param_ident_unit(
683 "intensity array",
684 1000515,
685 unit.unwrap_or(Unit::DetectorCounts),
686 )
687 .into(),
688 ArrayType::ChargeArray => CV.const_param_ident("charge array", 1000516).into(),
689 ArrayType::TimeArray => CV
690 .const_param_ident_unit("time array", 1000595, unit.unwrap_or(Unit::Minute))
691 .into(),
692 ArrayType::WavelengthArray => CV
693 .const_param_ident_unit("wavelength array", 1000617, Unit::Nanometer)
694 .into(),
695 ArrayType::SignalToNoiseArray => CV
696 .const_param_ident("signal to noise array", 1000517)
697 .into(),
698 ArrayType::IonMobilityArray => CV
699 .const_param_ident_unit("ion mobility array", 1002893, unit.unwrap_or_default())
700 .into(),
701
702 ArrayType::RawDriftTimeArray => CV
703 .const_param_ident_unit(
704 "raw ion mobility drift time array",
705 1003153,
706 unit.unwrap_or_default(),
707 )
708 .into(),
709 ArrayType::RawInverseReducedIonMobilityArray => CV
710 .const_param_ident_unit(
711 "raw inverse reduced ion mobility array",
712 1003008,
713 unit.unwrap_or_default(),
714 )
715 .into(),
716 ArrayType::RawIonMobilityArray => CV
717 .const_param_ident_unit("raw ion mobility array", 1003007, unit.unwrap_or_default())
718 .into(),
719
720 ArrayType::MeanIonMobilityArray => CV
721 .const_param_ident_unit(
722 "mean ion mobility array",
723 1002816,
724 unit.unwrap_or_default(),
725 )
726 .into(),
727 ArrayType::MeanDriftTimeArray => CV
728 .const_param_ident_unit(
729 "mean ion mobility drift time array",
730 1002477,
731 unit.unwrap_or_default(),
732 )
733 .into(),
734 ArrayType::MeanInverseReducedIonMobilityArray => CV
735 .const_param_ident_unit(
736 "mean inverse reduced ion mobility array",
737 1003006,
738 unit.unwrap_or_default(),
739 )
740 .into(),
741
742 ArrayType::DeconvolutedIonMobilityArray => CV
743 .const_param_ident_unit(
744 "deconvoluted ion mobility array",
745 1003154,
746 unit.unwrap_or_default(),
747 )
748 .into(),
749 ArrayType::DeconvolutedDriftTimeArray => CV
750 .const_param_ident_unit(
751 "deconvoluted ion mobility drift time array",
752 1003156,
753 unit.unwrap_or_default(),
754 )
755 .into(),
756 ArrayType::DeconvolutedInverseReducedIonMobilityArray => CV
757 .const_param_ident_unit(
758 "deconvoluted inverse reduced ion mobility array",
759 1003155,
760 unit.unwrap_or_default(),
761 )
762 .into(),
763
764 ArrayType::NonStandardDataArray { name } => {
765 let mut p = CV.param_val(1000786, "non-standard data array", name.to_string());
766 p.unit = unit.unwrap_or_default();
767 p
768 }
769 ArrayType::BaselineArray => CV.const_param_ident("baseline array", 1002530).into(),
770 ArrayType::ResolutionArray => CV.const_param_ident("resolution array", 1002529).into(),
771 ArrayType::PressureArray => {
772 let mut p = CV.const_param_ident("pressure array", 1000821);
773 p.unit = unit.unwrap_or_default();
774 p.into()
775 }
776 ArrayType::TemperatureArray => {
777 let mut p = CV.const_param_ident("temperature array", 1000822);
778 p.unit = unit.unwrap_or_default();
779 p.into()
780 }
781 ArrayType::FlowRateArray => {
782 let mut p = CV.const_param_ident("flow rate array", 1000820);
783 p.unit = unit.unwrap_or_default();
784 p.into()
785 }
786 ArrayType::ScanningQuadrupolePositionLowerBoundMZ => {
787 let mut p = CV.const_param_ident("scanning quadrupole position lower bound m/z array", 1003157);
788 p.unit = unit.unwrap_or_default();
789 p.into()
790 }
791 ArrayType::ScanningQuadrupolePositionUpperBoundMZ => {
792 let mut p = CV.const_param_ident("scanning quadrupole position upper bound m/z array", 1003158);
793 p.unit = unit.unwrap_or_default();
794 p.into()
795 }
796 ArrayType::IndexArray => {
797 CV.const_param_ident("index array", 1003870).into()
798 }
799 _ => {
800 panic!("Could not determine how to name for array {}", self);
801 }
802 }
803 }
804
805 pub const fn as_param_const(&self) -> ParamCow<'static> {
810 const CV: ControlledVocabulary = ControlledVocabulary::MS;
811 match self {
812 ArrayType::MZArray => CV.const_param_ident_unit("m/z array", 1000514, Unit::MZ),
813 ArrayType::IntensityArray => {
814 CV.const_param_ident_unit("intensity array", 1000515, Unit::DetectorCounts)
815 }
816 ArrayType::ChargeArray => CV.const_param_ident("charge array", 1000516),
817 ArrayType::TimeArray => CV.const_param_ident_unit("time array", 1000595, Unit::Minute),
818 ArrayType::WavelengthArray => {
819 CV.const_param_ident_unit("wavelength array", 1000617, Unit::Nanometer)
820 }
821 ArrayType::SignalToNoiseArray => CV.const_param_ident("signal to noise array", 1000517),
822 ArrayType::IonMobilityArray => CV.const_param_ident("ion mobility array", 1002893),
823 ArrayType::RawIonMobilityArray => {
824 CV.const_param_ident("raw ion mobility array", 1003007)
825 }
826 ArrayType::MeanIonMobilityArray => {
827 CV.const_param_ident("mean ion mobility array", 1002816)
828 }
829 ArrayType::DeconvolutedIonMobilityArray => {
830 CV.const_param_ident("deconvoluted ion mobility array", 1003154)
831 }
832 ArrayType::RawDriftTimeArray => CV.const_param_ident_unit(
833 "raw ion mobility drift time array",
834 1003153,
835 Unit::Unknown,
836 ),
837 ArrayType::RawInverseReducedIonMobilityArray => CV.const_param_ident_unit(
838 "raw inverse reduced ion mobility array",
839 1003008,
840 Unit::VoltSecondPerSquareCentimeter,
841 ),
842
843 ArrayType::MeanDriftTimeArray => CV.const_param_ident_unit(
844 "mean ion mobility drift time array",
845 1002477,
846 Unit::Unknown,
847 ),
848 ArrayType::MeanInverseReducedIonMobilityArray => CV.const_param_ident_unit(
849 "mean inverse reduced ion mobility array",
850 1003006,
851 Unit::VoltSecondPerSquareCentimeter,
852 ),
853
854 ArrayType::DeconvolutedDriftTimeArray => CV.const_param_ident_unit(
855 "deconvoluted ion mobility drift time array",
856 1003156,
857 Unit::Unknown,
858 ),
859 ArrayType::DeconvolutedInverseReducedIonMobilityArray => CV.const_param_ident_unit(
860 "deconvoluted inverse reduced ion mobility array",
861 1003155,
862 Unit::VoltSecondPerSquareCentimeter,
863 ),
864
865 ArrayType::NonStandardDataArray { name: _name } => {
866 panic!(
867 "Cannot format NonStandardDataArray in a const context, please use `as_param`"
868 );
869 }
870 ArrayType::BaselineArray => CV.const_param_ident("baseline array", 1002530),
871 ArrayType::ResolutionArray => CV.const_param_ident("resolution array", 1002529),
872 ArrayType::PressureArray => CV.const_param_ident_unit("pressure array", 1000821, Unit::Pascal),
873 ArrayType::TemperatureArray => CV.const_param_ident("temperature array", 1000822),
874 ArrayType::FlowRateArray => CV.const_param_ident_unit("flow rate array", 1000820, Unit::MicrolitersPerMinute),
875 ArrayType::ScanningQuadrupolePositionLowerBoundMZ => {
876 let mut p = CV.const_param_ident("scanning quadrupole position lower bound m/z array", 1003157);
877 p.unit = Unit::MZ;
878 p
879 }
880 ArrayType::IndexArray => {
881 CV.const_param_ident("index array", 1003870)
882 }
883 ArrayType::ScanningQuadrupolePositionUpperBoundMZ => {
884 let mut p = CV.const_param_ident("scanning quadrupole position upper bound m/z array", 1003158);
885 p.unit = Unit::MZ;
886 p
887 }
888 _ => {
889 panic!("Could not determine how to name for array");
890 }
891 }
892 }
893
894 pub const fn as_param_with_unit_const(&self, unit: Unit) -> ParamCow<'static> {
899 const CV: ControlledVocabulary = ControlledVocabulary::MS;
900 match self {
901 ArrayType::MZArray => CV.const_param_ident_unit("m/z array", 1000514, unit),
902 ArrayType::IntensityArray => {
903 CV.const_param_ident_unit("intensity array", 1000515, unit)
904 }
905 ArrayType::ChargeArray => CV.const_param_ident_unit("charge array", 1000516, unit),
906 ArrayType::TimeArray => CV.const_param_ident_unit("time array", 1000595, unit),
907 ArrayType::RawIonMobilityArray => {
908 CV.const_param_ident_unit("raw ion mobility array", 1003007, unit)
909 }
910 ArrayType::MeanIonMobilityArray => {
911 CV.const_param_ident_unit("mean ion mobility array", 1002816, unit)
912 }
913 ArrayType::DeconvolutedIonMobilityArray => {
914 CV.const_param_ident_unit("deconvoluted ion mobility array", 1003154, unit)
915 }
916 ArrayType::NonStandardDataArray { name: _name } => {
917 panic!(
918 "Cannot format NonStandardDataArray in a const context, please use `as_param`"
919 );
920 }
921
922 ArrayType::RawDriftTimeArray => {
923 CV.const_param_ident_unit("raw ion mobility drift time array", 1003153, unit)
924 }
925 ArrayType::RawInverseReducedIonMobilityArray => {
926 CV.const_param_ident_unit("raw inverse reduced ion mobility array", 1003008, unit)
927 }
928
929 ArrayType::MeanDriftTimeArray => {
930 CV.const_param_ident_unit("mean ion mobility drift time array", 1002477, unit)
931 }
932 ArrayType::MeanInverseReducedIonMobilityArray => {
933 CV.const_param_ident_unit("mean inverse reduced ion mobility array", 1003006, unit)
934 }
935
936 ArrayType::DeconvolutedDriftTimeArray => CV.const_param_ident_unit(
937 "deconvoluted ion mobility drift time array",
938 1003156,
939 unit,
940 ),
941 ArrayType::DeconvolutedInverseReducedIonMobilityArray => CV.const_param_ident_unit(
942 "deconvoluted inverse reduced ion mobility array",
943 1003155,
944 unit,
945 ),
946
947 ArrayType::BaselineArray => CV.const_param_ident_unit("baseline array", 1002530, unit),
948 ArrayType::ResolutionArray => {
949 CV.const_param_ident_unit("resolution array", 1002529, unit)
950 }
951 ArrayType::PressureArray => CV.const_param_ident_unit("pressure array", 1000821, unit),
952 ArrayType::TemperatureArray => {
953 CV.const_param_ident_unit("temperature array", 1000822, unit)
954 }
955 ArrayType::FlowRateArray => CV.const_param_ident_unit("flow rate array", 1000820, unit),
956 ArrayType::ScanningQuadrupolePositionLowerBoundMZ => {
957 CV.const_param_ident_unit("scanning quadrupole position lower bound m/z array", 1003157, unit)
958 }
959 ArrayType::ScanningQuadrupolePositionUpperBoundMZ => {
960 CV.const_param_ident_unit("scanning quadrupole position upper bound m/z array", 1003158, unit)
961 }
962 ArrayType::SignalToNoiseArray => {
963 CV.const_param_ident_unit("signal to noise array", 1000517, unit)
964 }
965 ArrayType::WavelengthArray => {
966 CV.const_param_ident_unit("wavelength array", 1000617, unit)
967 }
968 ArrayType::IonMobilityArray => {
969 CV.const_param_ident_unit("ion mobility array", 1002893, unit)
970 }
971 ArrayType::IndexArray => {
972 CV.const_param_ident_unit("index array", 1003870, unit)
973 }
974 _ => {
975 panic!("Could not determine how to name for array");
976 }
977 }
978 }
979
980 pub fn from_accession(x: CURIE) -> Option<Self> {
982 let tp = if x == Self::MZArray.as_param_const().curie().unwrap() {
983 Self::MZArray
984 } else if x == Self::IntensityArray.as_param_const().curie().unwrap() {
985 Self::IntensityArray
986 } else if x == Self::ChargeArray.as_param_const().curie().unwrap() {
987 Self::ChargeArray
988 } else if x == Self::SignalToNoiseArray.as_param_const().curie().unwrap() {
989 Self::SignalToNoiseArray
990 } else if x == Self::TimeArray.as_param_const().curie().unwrap() {
991 Self::TimeArray
992 } else if x == Self::WavelengthArray.as_param_const().curie().unwrap() {
993 Self::WavelengthArray
994 } else if x == Self::IonMobilityArray.as_param_const().curie().unwrap() {
995 Self::IonMobilityArray
996 } else if x == Self::MeanIonMobilityArray.as_param_const().curie().unwrap() {
997 Self::MeanIonMobilityArray
998 } else if x == Self::MeanDriftTimeArray.as_param_const().curie().unwrap() {
999 Self::MeanDriftTimeArray
1000 } else if x
1001 == Self::MeanInverseReducedIonMobilityArray
1002 .as_param_const()
1003 .curie()
1004 .unwrap()
1005 {
1006 Self::MeanInverseReducedIonMobilityArray
1007 } else if x == Self::RawIonMobilityArray.as_param_const().curie().unwrap() {
1008 Self::RawIonMobilityArray
1009 } else if x == Self::RawDriftTimeArray.as_param_const().curie().unwrap() {
1010 Self::RawDriftTimeArray
1011 } else if x
1012 == Self::RawInverseReducedIonMobilityArray
1013 .as_param_const()
1014 .curie()
1015 .unwrap()
1016 {
1017 Self::RawInverseReducedIonMobilityArray
1018 } else if x
1019 == Self::DeconvolutedIonMobilityArray
1020 .as_param_const()
1021 .curie()
1022 .unwrap()
1023 {
1024 Self::DeconvolutedIonMobilityArray
1025 } else if x
1026 == Self::DeconvolutedDriftTimeArray
1027 .as_param_const()
1028 .curie()
1029 .unwrap()
1030 {
1031 Self::DeconvolutedDriftTimeArray
1032 } else if x
1033 == Self::DeconvolutedInverseReducedIonMobilityArray
1034 .as_param_const()
1035 .curie()
1036 .unwrap()
1037 {
1038 Self::DeconvolutedInverseReducedIonMobilityArray
1039 } else if x == Self::BaselineArray.as_param_const().curie().unwrap() {
1040 Self::BaselineArray
1041 } else if x == Self::ResolutionArray.as_param_const().curie().unwrap() {
1042 Self::ResolutionArray
1043 } else if x == Self::PressureArray.as_param_const().curie().unwrap() {
1044 Self::PressureArray
1045 } else if x == Self::TemperatureArray.as_param_const().curie().unwrap() {
1046 Self::TemperatureArray
1047 } else if x == Self::FlowRateArray.as_param_const().curie().unwrap() {
1048 Self::FlowRateArray
1049 } else if x == Self::ScanningQuadrupolePositionLowerBoundMZ.as_param_const().curie().unwrap() {
1050 Self::ScanningQuadrupolePositionLowerBoundMZ
1051 } else if x == Self::ScanningQuadrupolePositionUpperBoundMZ.as_param_const().curie().unwrap() {
1052 Self::ScanningQuadrupolePositionUpperBoundMZ
1053 } else if x == Self::IndexArray.as_param_const().curie().unwrap() {
1054 Self::IndexArray
1055 }
1056 else if x
1057 == (Self::NonStandardDataArray {
1058 name: "".to_string().into(),
1059 })
1060 .as_param(None)
1061 .curie()
1062 .unwrap()
1063 {
1064 Self::NonStandardDataArray {
1065 name: "".to_string().into(),
1066 }
1067 } else {
1068 return None;
1069 };
1070 Some(tp)
1071 }
1072}
1073
1074#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, Default)]
1077#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1078pub enum BinaryDataArrayType {
1079 #[default]
1080 Unknown,
1081 Float64,
1082 Float32,
1083 Int64,
1084 Int32,
1085 ASCII,
1086}
1087
1088impl Display for BinaryDataArrayType {
1089 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1090 write!(f, "{:?}", self)
1091 }
1092}
1093
1094impl BinaryDataArrayType {
1095 pub const fn size_of(&self) -> usize {
1097 match self {
1098 BinaryDataArrayType::Unknown | BinaryDataArrayType::ASCII => 1,
1099 BinaryDataArrayType::Float32 | BinaryDataArrayType::Int32 => 4,
1100 BinaryDataArrayType::Float64 | BinaryDataArrayType::Int64 => 8,
1101 }
1102 }
1103
1104 pub const fn as_param_const(&self) -> Option<ParamCow<'static>> {
1106 let name = match self {
1107 BinaryDataArrayType::Unknown => return None,
1108 BinaryDataArrayType::Float64 => "64-bit float",
1109 BinaryDataArrayType::Float32 => "32-bit float",
1110 BinaryDataArrayType::Int64 => "64-bit integer",
1111 BinaryDataArrayType::Int32 => "32-bit integer",
1112 BinaryDataArrayType::ASCII => "null-terminated ASCII string",
1113 };
1114 if let Some(curie) = self.curie() {
1115 Some(ParamCow::const_new(
1116 name,
1117 ValueRef::Empty,
1118 Some(curie.accession),
1119 Some(curie.controlled_vocabulary),
1120 Unit::Unknown,
1121 ))
1122 } else {
1123 None
1124 }
1125 }
1126
1127 pub const fn curie(&self) -> Option<CURIE> {
1129 match self {
1130 Self::Float32 => Some(curie!(MS:1000521)),
1131 Self::Float64 => Some(curie!(MS:1000523)),
1132 Self::Int32 => Some(curie!(MS:1000519)),
1133 Self::Int64 => Some(curie!(MS:1000522)),
1134 Self::ASCII => Some(curie!(MS:1001479)),
1135 _ => None,
1136 }
1137 }
1138
1139 pub fn from_accession(accession: CURIE) -> Option<Self> {
1140 match accession {
1141 x if Some(x) == Self::Float32.curie() => Some(Self::Float32),
1142 x if Some(x) == Self::Float64.curie() => Some(Self::Float64),
1143 x if Some(x) == Self::Int32.curie() => Some(Self::Int32),
1144 x if Some(x) == Self::Int64.curie() => Some(Self::Int64),
1145 x if Some(x) == Self::ASCII.curie() => Some(Self::ASCII),
1146 _ => None,
1147 }
1148 }
1149
1150 pub fn swap_bytes(&self, data: &mut [u8]) -> Result<(), ArrayRetrievalError> {
1152 let z = self.size_of();
1153 if !(data.len() % z == 0) {
1154 return Err(ArrayRetrievalError::DataTypeSizeMismatch)
1155 }
1156 match z {
1157 1 => {
1158 data.reverse();
1159 }
1160 4 => {
1161 data.as_chunks_mut::<4>().0.into_iter().for_each(|c| {
1162 *c = u32::from_ne_bytes(*c).swap_bytes().to_ne_bytes();
1163 });
1164 }
1165 8 => {
1166 data.as_chunks_mut::<8>().0.into_iter().for_each(|c| {
1167 *c = u64::from_ne_bytes(*c).swap_bytes().to_ne_bytes();
1168 });
1169 }
1176 x => {
1177 data.chunks_exact_mut(x).for_each(|c| c.reverse());
1178 }
1179 }
1180 Ok(())
1181 }
1182}
1183
1184#[derive(Debug, Clone, Copy, PartialEq, Hash, Default)]
1188#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1189pub enum BinaryCompressionType {
1190 #[default]
1191 NoCompression,
1192 Zlib,
1193 NumpressLinear,
1194 NumpressSLOF,
1195 NumpressPIC,
1196 NumpressLinearZlib,
1197 NumpressSLOFZlib,
1198 NumpressPICZlib,
1199 LinearPrediction,
1200 DeltaPrediction,
1201 Decoded,
1202 Zstd,
1203 ShuffleZstd,
1204 DeltaShuffleZstd,
1205 ZstdDict,
1206 NumpressLinearZstd,
1207 NumpressSLOFZstd,
1208 NumpressPICZstd,
1209}
1210
1211impl BinaryCompressionType {
1212 pub const COMPRESSION_METHODS: &[Self] = &[
1213 Self::NoCompression,
1214 Self::Zlib,
1215
1216 #[cfg(feature = "numpress")]
1217 Self::NumpressLinear,
1218 #[cfg(feature = "numpress")]
1219 Self::NumpressLinearZlib,
1220 #[cfg(feature = "numpress")]
1221 Self::NumpressSLOF,
1222 #[cfg(feature = "numpress")]
1223 Self::NumpressSLOFZlib,
1224
1225 #[cfg(feature = "zstd")]
1226 Self::Zstd,
1227 #[cfg(feature = "zstd")]
1228 Self::ShuffleZstd,
1229 #[cfg(feature = "zstd")]
1230 Self::DeltaShuffleZstd,
1231 #[cfg(feature = "zstd")]
1232 Self::ZstdDict,
1233
1234 #[cfg(all(feature = "zstd", feature = "numpress"))]
1235 Self::NumpressLinearZstd,
1236 #[cfg(all(feature = "zstd", feature = "numpress"))]
1237 Self::NumpressSLOFZstd,
1238 ];
1239
1240 pub fn unsupported_msg(&self, context: Option<&str>) -> String {
1242 match context {
1243 Some(ctx) => format!("Cannot decode array compressed with {:?} ({})", self, ctx),
1244 None => format!("Cannot decode array compressed with {:?}", self),
1245 }
1246 }
1247
1248 pub const fn is_endian_aware(&self) -> bool {
1251 match self {
1252 BinaryCompressionType::Zlib |
1253 BinaryCompressionType::NoCompression |
1254 BinaryCompressionType::DeltaPrediction |
1255 BinaryCompressionType::LinearPrediction |
1256 BinaryCompressionType::Zstd => false,
1257 _ => true,
1258
1259 }
1260 }
1261
1262 pub const fn accession(&self) -> Option<u32> {
1263 let acc = match self {
1264 BinaryCompressionType::NoCompression => 1000576,
1265 BinaryCompressionType::Zlib => 1000574,
1266 BinaryCompressionType::NumpressLinear => 1002312,
1267 BinaryCompressionType::NumpressSLOF => 1002314,
1268 BinaryCompressionType::NumpressPIC => 1002313,
1269 BinaryCompressionType::NumpressLinearZlib => 1002746,
1270 BinaryCompressionType::NumpressSLOFZlib => 1002748,
1271 BinaryCompressionType::NumpressPICZlib => 1002747,
1272 BinaryCompressionType::DeltaPrediction => 1003089,
1273 BinaryCompressionType::LinearPrediction => 1003090,
1274 BinaryCompressionType::NumpressSLOFZstd => 1003785,
1275 BinaryCompressionType::NumpressLinearZstd => 1003783,
1276 BinaryCompressionType::NumpressPICZstd => 1003784,
1277 BinaryCompressionType::ZstdDict => 1003782,
1278 BinaryCompressionType::Zstd => 1003780,
1279 BinaryCompressionType::ShuffleZstd => 1003781,
1280 BinaryCompressionType::DeltaShuffleZstd => 9999999,
1281 BinaryCompressionType::Decoded => return None,
1282 };
1283 Some(acc)
1284 }
1285
1286 pub fn from_accession(accession: CURIE) -> Option<Self> {
1288 match accession {
1289 CURIE {
1290 controlled_vocabulary: ControlledVocabulary::MS,
1291 accession: 1000576,
1292 } => Some(Self::NoCompression),
1293 CURIE {
1294 controlled_vocabulary: ControlledVocabulary::MS,
1295 accession: 1000574,
1296 } => Some(BinaryCompressionType::Zlib),
1297 CURIE {
1298 controlled_vocabulary: ControlledVocabulary::MS,
1299 accession: 1002312,
1300 } => Some(BinaryCompressionType::NumpressLinear),
1301 CURIE {
1302 controlled_vocabulary: ControlledVocabulary::MS,
1303 accession: 1002314,
1304 } => Some(BinaryCompressionType::NumpressSLOF),
1305 CURIE {
1306 controlled_vocabulary: ControlledVocabulary::MS,
1307 accession: 1002313,
1308 } => Some(BinaryCompressionType::NumpressPIC),
1309 CURIE {
1310 controlled_vocabulary: ControlledVocabulary::MS,
1311 accession: 1002746,
1312 } => Some(BinaryCompressionType::NumpressLinearZlib),
1313 CURIE {
1314 controlled_vocabulary: ControlledVocabulary::MS,
1315 accession: 1002748,
1316 } => Some(BinaryCompressionType::NumpressSLOFZlib),
1317 CURIE {
1318 controlled_vocabulary: ControlledVocabulary::MS,
1319 accession: 1002747,
1320 } => Some(BinaryCompressionType::NumpressPICZlib),
1321 CURIE {
1322 controlled_vocabulary: ControlledVocabulary::MS,
1323 accession: 1003089,
1324 } => Some(BinaryCompressionType::DeltaPrediction),
1325 CURIE {
1326 controlled_vocabulary: ControlledVocabulary::MS,
1327 accession: 1003090,
1328 } => Some(BinaryCompressionType::LinearPrediction),
1329 x if x
1330 == CURIE {
1331 controlled_vocabulary: ControlledVocabulary::MS,
1332 accession: BinaryCompressionType::NumpressSLOFZstd.accession().unwrap(),
1333 } =>
1334 {
1335 Some(BinaryCompressionType::NumpressSLOFZstd)
1336 }
1337 x if x
1338 == CURIE {
1339 controlled_vocabulary: ControlledVocabulary::MS,
1340 accession: BinaryCompressionType::NumpressPICZstd.accession().unwrap(),
1341 } =>
1342 {
1343 Some(BinaryCompressionType::NumpressPICZstd)
1344 }
1345 x if x
1346 == CURIE {
1347 controlled_vocabulary: ControlledVocabulary::MS,
1348 accession: BinaryCompressionType::NumpressLinearZstd
1349 .accession()
1350 .unwrap(),
1351 } =>
1352 {
1353 Some(BinaryCompressionType::NumpressLinearZstd)
1354 }
1355 x if x
1356 == CURIE {
1357 controlled_vocabulary: ControlledVocabulary::MS,
1358 accession: BinaryCompressionType::ZstdDict.accession().unwrap(),
1359 } =>
1360 {
1361 Some(BinaryCompressionType::ZstdDict)
1362 }
1363 x if x
1364 == CURIE {
1365 controlled_vocabulary: ControlledVocabulary::MS,
1366 accession: BinaryCompressionType::Zstd.accession().unwrap(),
1367 } =>
1368 {
1369 Some(BinaryCompressionType::Zstd)
1370 }
1371 x if x
1372 == CURIE {
1373 controlled_vocabulary: ControlledVocabulary::MS,
1374 accession: BinaryCompressionType::ShuffleZstd.accession().unwrap(),
1375 } =>
1376 {
1377 Some(BinaryCompressionType::ShuffleZstd)
1378 }
1379 x if x
1380 == CURIE {
1381 controlled_vocabulary: ControlledVocabulary::MS,
1382 accession: BinaryCompressionType::DeltaShuffleZstd.accession().unwrap(),
1383 } =>
1384 {
1385 Some(BinaryCompressionType::DeltaShuffleZstd)
1386 }
1387 _ => None,
1388 }
1389 }
1390
1391 pub const fn as_param(&self) -> Option<ParamCow<'static>> {
1396 let (name, accession) = match self {
1397 BinaryCompressionType::Decoded => return None,
1398 BinaryCompressionType::NoCompression => ("no compression", self.accession()),
1399 BinaryCompressionType::Zlib => ("zlib compression", self.accession()),
1400 BinaryCompressionType::NumpressLinear => (
1401 "MS-Numpress linear prediction compression",
1402 self.accession(),
1403 ),
1404 BinaryCompressionType::NumpressSLOF => (
1405 "MS-Numpress short logged float compression",
1406 self.accession(),
1407 ),
1408 BinaryCompressionType::NumpressPIC => {
1409 ("MS-Numpress positive integer compression", self.accession())
1410 }
1411 BinaryCompressionType::NumpressLinearZlib => (
1412 "MS-Numpress linear prediction compression followed by zlib compression",
1413 self.accession(),
1414 ),
1415 BinaryCompressionType::NumpressSLOFZlib => (
1416 "MS-Numpress short logged float compression followed by zlib compression",
1417 self.accession(),
1418 ),
1419 BinaryCompressionType::NumpressPICZlib => (
1420 "MS-Numpress positive integer compression followed by zlib compression",
1421 self.accession(),
1422 ),
1423 BinaryCompressionType::DeltaPrediction => (
1424 "truncation, delta prediction and zlib compression",
1425 self.accession(),
1426 ),
1427 BinaryCompressionType::LinearPrediction => (
1428 "truncation, linear prediction and zlib compression",
1429 self.accession(),
1430 ),
1431 BinaryCompressionType::NumpressSLOFZstd => {
1432 return Some(ParamCow::const_new(
1433 "MS-Numpress short logged float compression followed by zstd compression",
1434 ValueRef::Empty,
1435 self.accession(),
1436 Some(ControlledVocabulary::MS),
1437 Unit::Unknown,
1438 ))
1439 }
1440 BinaryCompressionType::NumpressLinearZstd => {
1441 return Some(ParamCow::const_new(
1442 "MS-Numpress linear prediction compression followed by zstd compression",
1443 ValueRef::Empty,
1444 self.accession(),
1445 Some(ControlledVocabulary::MS),
1446 Unit::Unknown,
1447 ))
1448 }
1449 BinaryCompressionType::NumpressPICZstd => {
1450 return Some(ParamCow::const_new(
1451 "MS-Numpress positive integer compression followed by zstd compression",
1452 ValueRef::Empty,
1453 self.accession(),
1454 Some(ControlledVocabulary::MS),
1455 Unit::Unknown,
1456 ))
1457 }
1458 BinaryCompressionType::ZstdDict => {
1459 return Some(ParamCow::const_new(
1460 "dict-zstd compression",
1461 ValueRef::Empty,
1462 self.accession(),
1463 Some(ControlledVocabulary::MS),
1464 Unit::Unknown,
1465 ))
1466 }
1467 BinaryCompressionType::Zstd => {
1468 return Some(ParamCow::const_new(
1469 "zstd compression",
1470 ValueRef::Empty,
1471 self.accession(),
1472 Some(ControlledVocabulary::MS),
1473 Unit::Unknown,
1474 ))
1475 }
1476 BinaryCompressionType::ShuffleZstd => {
1477 return Some(ParamCow::const_new(
1478 "byte-shuffle-zstd compression",
1479 ValueRef::Empty,
1480 self.accession(),
1481 Some(ControlledVocabulary::MS),
1482 Unit::Unknown,
1483 ))
1484 }
1485 BinaryCompressionType::DeltaShuffleZstd => {
1486 return Some(ParamCow::const_new(
1487 "delta-byte-shuffle-zstd compression",
1488 ValueRef::Empty,
1489 self.accession(),
1490 Some(ControlledVocabulary::MS),
1491 Unit::Unknown,
1492 ))
1493 }
1494 };
1495 Some(
1496 ControlledVocabulary::MS
1497 .const_param_ident(name, unsafe { accession.unwrap_unchecked() }),
1498 )
1499 }
1500}
1501
1502impl Display for BinaryCompressionType {
1503 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1504 write!(f, "{:?}", self)
1505 }
1506}
1507
1508#[derive(Debug, Clone, Error, PartialEq)]
1512pub enum ArrayRetrievalError {
1513 #[error("Array type {0:?} not found")]
1514 NotFound(ArrayType),
1515 #[error("An error occurred while decompressing: {0}")]
1516 DecompressionError(String),
1517 #[error("The requested data type does not match the number of bytes available in the buffer")]
1518 DataTypeSizeMismatch,
1519}
1520
1521impl From<bytemuck::PodCastError> for ArrayRetrievalError {
1522 fn from(value: bytemuck::PodCastError) -> Self {
1523 match value {
1524 bytemuck::PodCastError::TargetAlignmentGreaterAndInputNotAligned => {
1525 Self::DataTypeSizeMismatch
1526 }
1527 bytemuck::PodCastError::OutputSliceWouldHaveSlop => Self::DataTypeSizeMismatch,
1528 bytemuck::PodCastError::SizeMismatch => Self::DataTypeSizeMismatch,
1529 bytemuck::PodCastError::AlignmentMismatch => Self::DataTypeSizeMismatch,
1530 }
1531 }
1532}
1533
1534impl From<ArrayRetrievalError> for io::Error {
1535 fn from(value: ArrayRetrievalError) -> Self {
1536 match value {
1537 ArrayRetrievalError::NotFound(_) => io::Error::new(io::ErrorKind::NotFound, value),
1538 ArrayRetrievalError::DecompressionError(e) => {
1539 io::Error::new(io::ErrorKind::InvalidData, e)
1540 }
1541 ArrayRetrievalError::DataTypeSizeMismatch => {
1542 io::Error::new(io::ErrorKind::InvalidData, value)
1543 }
1544 }
1545 }
1546}
1547
1548#[cfg(feature = "numpress")]
1549impl From<numpress::Error> for ArrayRetrievalError {
1550 fn from(value: numpress::Error) -> Self {
1551 ArrayRetrievalError::DecompressionError(value.to_string())
1552 }
1553}
1554
1555pub fn linear_prediction_decoding<F: Num + Copy + Mul + AddAssign>(values: &mut [F]) -> &mut [F] {
1556 if values.len() < 2 {
1557 return values;
1558 }
1559
1560 let two = F::one() + F::one();
1561
1562 let prev2 = values[1];
1563 let prev1 = values[2];
1564 let offset = values[1];
1565
1566 values
1567 .iter_mut()
1568 .skip(2)
1569 .fold((prev1, prev2), |(prev1, prev2), current| {
1570 let tmp = *current + two * prev1 - prev2 - offset;
1571 let prev1 = *current;
1572 let prev2 = prev1;
1573 *current = tmp;
1574 (prev1, prev2)
1575 });
1576
1577 for i in 0..values.len() {
1578 if i < 2 {
1579 continue;
1580 }
1581 let v = values[i] + two * values[i - 1] - values[i - 2] - values[1];
1582 values[i] = v;
1583 }
1584 values
1585}
1586
1587pub fn linear_prediction_encoding<F: Num + Copy + Mul<F> + AddAssign>(
1588 values: &mut [F],
1589) -> &mut [F] {
1590 let n = values.len();
1591 if n < 3 {
1592 return values;
1593 }
1594 let offset = values[1];
1595 let prev2 = values[0];
1596 let prev1 = values[1];
1597 let two = F::one() + F::one();
1598
1599 values
1600 .iter_mut()
1601 .fold((prev1, prev2), |(prev1, prev2), val| {
1602 *val += offset - two * prev1 + prev2;
1603 let tmp = prev1;
1604 let prev1 = *val + two * prev1 - prev2 - offset;
1605 let prev2 = tmp;
1606 (prev1, prev2)
1607 });
1608 values
1609}
1610
1611pub fn delta_decoding<F: Num + Copy + Mul + AddAssign>(values: &mut [F]) -> &mut [F] {
1612 if values.len() < 2 {
1613 return values;
1614 }
1615
1616 let offset = values[0];
1617 let prev = values[1];
1618
1619 values.iter_mut().skip(2).fold(prev, |prev, current| {
1620 *current += prev - offset;
1621 *current
1622 });
1623 values
1624}
1625
1626pub fn delta_encoding<F: Num + Copy + Mul + AddAssign>(values: &mut [F]) -> &mut [F] {
1627 let n = values.len();
1628 if n < 2 {
1629 return values;
1630 }
1631 let prev = values[0];
1632 let offset = values[0];
1633
1634 let it = values.iter_mut();
1635 it.skip(1).fold(prev, |prev, current| {
1636 let tmp = *current;
1637 *current += offset - prev;
1638 tmp
1639 });
1640 values
1641}
1642
1643#[cfg(test)]
1644mod test {
1645 use super::*;
1646
1647 #[test]
1648 fn test_dtype_size() {
1649 assert_eq!(BinaryDataArrayType::ASCII.size_of(), 1);
1650 assert_eq!(BinaryDataArrayType::Float32.size_of(), 4);
1651 assert_eq!(BinaryDataArrayType::Int32.size_of(), 4);
1652 assert_eq!(BinaryDataArrayType::Float64.size_of(), 8);
1653 assert_eq!(BinaryDataArrayType::Int64.size_of(), 8);
1654 }
1655
1656 #[test]
1657 fn test_array_type_param() {
1658 let array_types = [
1659 ArrayType::MZArray,
1660 ArrayType::IntensityArray,
1661 ArrayType::ChargeArray,
1662 ArrayType::SignalToNoiseArray,
1663 ArrayType::TimeArray,
1664 ArrayType::WavelengthArray,
1665 ArrayType::IonMobilityArray,
1666 ArrayType::MeanIonMobilityArray,
1667 ArrayType::RawIonMobilityArray,
1668 ArrayType::DeconvolutedIonMobilityArray,
1669 ];
1670
1671 for at in array_types {
1672 assert_eq!(at.as_param_const().name, at.as_param(None).name)
1673 }
1674 }
1675
1676 #[test]
1677 fn test_binary_encoding_conv() {
1678 let encodings = [
1679 BinaryCompressionType::Decoded,
1680 BinaryCompressionType::NoCompression,
1681 BinaryCompressionType::NumpressLinear,
1682 BinaryCompressionType::NumpressLinearZlib,
1683 BinaryCompressionType::NumpressPIC,
1684 BinaryCompressionType::NumpressPICZlib,
1685 BinaryCompressionType::NumpressSLOF,
1686 BinaryCompressionType::NumpressSLOFZlib,
1687 BinaryCompressionType::Zlib,
1688 ];
1689
1690 for enc in encodings {
1691 let reps = match enc {
1692 BinaryCompressionType::NoCompression => ("no compression", 1000576),
1693 BinaryCompressionType::Zlib => ("zlib compression", 1000574),
1694 BinaryCompressionType::NumpressLinear => {
1695 ("MS-Numpress linear prediction compression", 1002312)
1696 }
1697 BinaryCompressionType::NumpressSLOF => {
1698 ("MS-Numpress short logged float compression", 1002314)
1699 }
1700 BinaryCompressionType::NumpressPIC => {
1701 ("MS-Numpress positive integer compression", 1002313)
1702 }
1703 BinaryCompressionType::NumpressLinearZlib => (
1704 "MS-Numpress linear prediction compression followed by zlib compression",
1705 1002746,
1706 ),
1707 BinaryCompressionType::NumpressPICZlib => (
1708 "MS-Numpress positive integer compression followed by zlib compression",
1709 1002747,
1710 ),
1711 BinaryCompressionType::NumpressSLOFZlib => (
1712 "MS-Numpress short logged float compression followed by zlib compression",
1713 1002748,
1714 ),
1715 _ => ("", 0),
1716 };
1717 if let Some(p) = enc.as_param() {
1718 assert_eq!(p.name, reps.0);
1719 assert_eq!(p.accession.unwrap(), reps.1);
1720 }
1721 }
1722 }
1723
1724 #[test]
1725 fn test_transpose() {
1726 let data: Vec<_> = (0..128i32).map(|i| i.pow(2u32) as f64).collect();
1727 let flip = transpose_f64(&data);
1728 let rev = reverse_transpose_f64(&flip);
1729 let rev_cast: &[f64] = bytemuck::cast_slice(&rev);
1730 assert_eq!(data, rev_cast);
1731 }
1732
1733 #[test]
1734 fn test_dict() {
1735 let data: Vec<_> = (0..127i32).map(|i| i.pow(2u32) as f64).collect();
1736 let encoded = dictionary_encoding(&data).unwrap();
1737 let decoded: Vec<f64> = dictionary_decoding(&encoded).unwrap();
1738
1739 assert_eq!(data, decoded);
1740 }
1741
1742 #[test]
1743 fn test_byteswap() {
1744 let x = 42u32;
1745 let mut bytes_of = x.to_le_bytes();
1746 BinaryDataArrayType::Int32.swap_bytes(&mut bytes_of).unwrap();
1747 let y1 = u32::from_le_bytes(bytes_of);
1748 let y2 = x.swap_bytes();
1749 assert_eq!(y1, y2);
1750
1751 bytes_of = x.to_be_bytes();
1752 BinaryDataArrayType::Int32.swap_bytes(&mut bytes_of).unwrap();
1753 let y1 = u32::from_le_bytes(bytes_of);
1754 assert_eq!(x, y1);
1755 }
1756}