1use std::borrow::Cow;
2use std::cmp::Ordering;
3use std::collections::HashMap;
4use std::collections::hash_map::{Iter, IterMut};
5use std::convert::TryFrom;
6
7#[cfg(feature = "parallelism")]
8use rayon::prelude::*;
9
10use mzpeaks::Tolerance;
11
12use mzdata_param::Unit;
13
14use super::BinaryDataArrayType;
15use super::array::DataArray;
16use super::encodings::{ArrayRetrievalError, ArrayType, BinaryCompressionType};
17use super::traits::{ByteArrayView, ByteArrayViewMut};
18
19#[derive(Debug, Default, Clone)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36pub struct BinaryArrayMap {
37 pub byte_buffer_map: HashMap<ArrayType, DataArray>,
38}
39
40impl BinaryArrayMap {
41 pub fn new() -> BinaryArrayMap {
42 BinaryArrayMap {
43 ..Default::default()
44 }
45 }
46
47 pub fn len(&self) -> usize {
49 self.byte_buffer_map.len()
50 }
51
52 pub fn is_empty(&self) -> bool {
53 self.byte_buffer_map.is_empty()
54 }
55
56 pub fn has_ion_mobility(&self) -> bool {
58 self.byte_buffer_map.keys().any(|a| a.is_ion_mobility())
59 }
60
61 pub fn iter(&self) -> Iter<'_, ArrayType, DataArray> {
63 self.byte_buffer_map.iter()
64 }
65
66 #[cfg(feature = "parallelism")]
67 pub fn par_iter(&self) -> rayon::collections::hash_map::Iter<'_, ArrayType, DataArray> {
68 self.byte_buffer_map.par_iter()
69 }
70
71 pub fn iter_mut(&mut self) -> IterMut<'_, ArrayType, DataArray> {
73 self.byte_buffer_map.iter_mut()
74 }
75
76 #[cfg(feature = "parallelism")]
77 pub fn par_iter_mut(
78 &mut self,
79 ) -> rayon::collections::hash_map::IterMut<'_, ArrayType, DataArray> {
80 self.byte_buffer_map.par_iter_mut()
81 }
82
83 pub fn encode_array(
90 &mut self,
91 array_type: &ArrayType,
92 compression: BinaryCompressionType,
93 ) -> Result<(), ArrayRetrievalError> {
94 if let Some(arr) = self.get_mut(array_type) {
95 arr.store_compressed(compression)?;
96 Ok(())
97 } else {
98 Err(ArrayRetrievalError::NotFound(array_type.clone()))
99 }
100 }
101
102 pub fn decode_all_arrays(&mut self) -> Result<(), ArrayRetrievalError> {
122 #[cfg(not(feature = "parallelism"))]
123 {
124 self._decode_all_arrays()
125 }
126 #[cfg(feature = "parallelism")]
127 {
128 if self.len() > 2 {
129 self._decode_all_arrays_parallel()
130 } else {
131 self._decode_all_arrays()
132 }
133 }
134 }
135
136 fn _decode_all_arrays(&mut self) -> Result<(), ArrayRetrievalError> {
137 for (_key, value) in self.iter_mut() {
138 match value.compression {
139 BinaryCompressionType::Decoded => {}
140 _ => {
141 value.decode_and_store()?;
142 }
143 }
144 }
145 Ok(())
146 }
147
148 #[cfg(feature = "parallelism")]
149 fn _decode_all_arrays_parallel(&mut self) -> Result<(), ArrayRetrievalError> {
150 let res: Result<(), ArrayRetrievalError> = self
151 .iter_mut()
152 .par_bridge()
153 .map(|(_key, value)| {
154 match value.compression {
155 BinaryCompressionType::Decoded => {}
156 _ => {
157 value.decode_and_store()?;
158 }
159 }
160 Ok(())
161 })
162 .collect::<Result<(), ArrayRetrievalError>>();
163 res
164 }
165
166 pub fn decode_array(&mut self, array_type: &ArrayType) -> Result<(), ArrayRetrievalError> {
172 if let Some(array) = self.get_mut(array_type) {
173 array.decode_and_store()?;
174 Ok(())
175 } else {
176 Err(ArrayRetrievalError::NotFound(array_type.clone()))
177 }
178 }
179
180 pub fn add(&mut self, array: DataArray) {
182 self.byte_buffer_map.insert(array.name.clone(), array);
183 }
184
185 pub fn get(&self, array_type: &ArrayType) -> Option<&DataArray> {
187 self.byte_buffer_map.get(array_type)
188 }
189
190 pub fn get_mut(&mut self, array_type: &ArrayType) -> Option<&mut DataArray> {
192 self.byte_buffer_map.get_mut(array_type)
193 }
194
195 pub fn has_array(&self, array_type: &ArrayType) -> bool {
197 self.byte_buffer_map.contains_key(array_type)
198 }
199
200 pub fn clear(&mut self) {
202 self.byte_buffer_map.clear();
203 }
204
205 pub fn search(&self, query: f64, error_tolerance: Tolerance) -> Option<usize> {
210 if let Ok(mzs) = self.mzs() {
211 let (lower, _upper) = error_tolerance.bounds(query);
212 match mzs[..].binary_search_by(|m| m.partial_cmp(&lower).unwrap()) {
213 Ok(i) => {
214 let mut best_error = error_tolerance.call(query, mzs[i]).abs();
215 let mut best_index = i;
216 let mut index = i + 1;
217 while index < mzs.len() {
218 let error = error_tolerance.call(query, mzs[index]).abs();
219 if error < best_error {
220 best_index = index;
221 best_error = error;
222 }
223 index += 1;
224 }
225 if best_error < error_tolerance.tol() {
226 return Some(best_index);
227 }
228 None
229 }
230 Err(_err) => None,
231 }
232 } else {
233 None
234 }
235 }
236
237 pub fn mzs(&'_ self) -> Result<Cow<'_, [f64]>, ArrayRetrievalError> {
252 let mz_array = self
253 .get(&ArrayType::MZArray)
254 .ok_or(ArrayRetrievalError::NotFound(ArrayType::MZArray))?
255 .to_f64()
256 .inspect_err(|e| log::error!("Failed to decode m/z array: {e}"))?;
257 Ok(mz_array)
258 }
259
260 pub fn sort_from_indices(&mut self, mut mask: Vec<usize>) -> Result<(), ArrayRetrievalError> {
277 let n = mask.len();
278 const TOMBSTONE: usize = usize::MAX;
279 for idx in 0..n {
280 if mask[idx] != TOMBSTONE {
281 let mut current_idx = idx;
282 loop {
283 let next_idx = mask[current_idx];
284 mask[current_idx] = TOMBSTONE;
285 if mask[next_idx] == TOMBSTONE {
286 break;
287 }
288 for (_, v) in self.iter_mut() {
289 if v.data_len()? != n {
290 continue;
291 }
292 match v.dtype {
293 BinaryDataArrayType::Float64 => {
294 let view = v.coerce_mut::<f64>()?;
295 view.swap(current_idx, next_idx);
296 }
297 BinaryDataArrayType::Float32 => {
298 let view = v.coerce_mut::<f32>()?;
299 view.swap(current_idx, next_idx);
300 }
301 BinaryDataArrayType::Int64 => {
302 let view = v.coerce_mut::<i64>()?;
303 view.swap(current_idx, next_idx);
304 }
305 BinaryDataArrayType::Int32 => {
306 let view = v.coerce_mut::<i32>()?;
307 view.swap(current_idx, next_idx);
308 }
309 BinaryDataArrayType::ASCII => todo!(),
310 BinaryDataArrayType::Unknown => todo!(),
311 }
312 }
313 current_idx = next_idx;
314 }
315 }
316 }
317 Ok(())
318 }
319
320 pub fn sort_by_array(&mut self, name: &ArrayType) -> Result<(), ArrayRetrievalError> {
328 let query_axis = self
329 .get(name)
330 .ok_or_else(|| ArrayRetrievalError::NotFound(name.clone()))?;
331 macro_rules! sort_mask {
332 ($conv:expr, $cmp:expr) => {{
333 let vals = $conv?;
334 if vals.is_sorted() {
335 return Ok(());
336 }
337 let n = vals.len();
338 let mut mask: Vec<usize> = (0..n).into_iter().collect();
339 mask.sort_by(|i, j| {
340 let a = vals[*i];
341 let b = vals[*j];
342 $cmp(&a, &b)
343 });
344 (mask, n)
345 }};
346 }
347 let (mask, _) = match query_axis.dtype() {
348 BinaryDataArrayType::Float64 => {
349 sort_mask!(query_axis.to_f64(), f64::total_cmp)
350 }
351 BinaryDataArrayType::Float32 => {
352 sort_mask!(query_axis.to_f32(), f32::total_cmp)
353 }
354 BinaryDataArrayType::Int64 => {
355 sort_mask!(query_axis.to_i64(), i64::cmp)
356 }
357 BinaryDataArrayType::Int32 => {
358 sort_mask!(query_axis.to_i32(), i32::cmp)
359 }
360 BinaryDataArrayType::ASCII => todo!(),
361 BinaryDataArrayType::Unknown => todo!(),
362 };
363
364 self.sort_from_indices(mask)
365 }
366
367 pub fn mzs_mut(&mut self) -> Result<&mut [f64], ArrayRetrievalError> {
374 if let Some(mz_array) = self.get_mut(&ArrayType::MZArray) {
375 mz_array
376 .decode_and_store()
377 .inspect_err(|e| log::error!("Failed to decode m/z array: {e}"))?;
378 mz_array.store_as(BinaryDataArrayType::Float64)?;
379 mz_array.coerce_mut()
380 } else {
381 Err(ArrayRetrievalError::NotFound(ArrayType::MZArray))
382 }
383 }
384
385 pub fn intensities(&'_ self) -> Result<Cow<'_, [f32]>, ArrayRetrievalError> {
387 let intensities = self
388 .get(&ArrayType::IntensityArray)
389 .ok_or(ArrayRetrievalError::NotFound(ArrayType::IntensityArray))?
390 .to_f32()
391 .inspect_err(|e| log::error!("Failed to decode intensity array: {e:?}"))?;
392 Ok(intensities)
393 }
394
395 pub fn intensities_mut(&mut self) -> Result<&mut [f32], ArrayRetrievalError> {
400 if let Some(arr) = self.get_mut(&ArrayType::IntensityArray) {
401 arr
402 .decode_and_store()
403 .inspect_err(|e| log::error!("Failed to decode intensity array: {e}"))?;
404 arr
405 .store_as(BinaryDataArrayType::Float32)
406 .inspect_err(|e| log::error!("Failed to decode intensity array: {e}"))?;
407 arr.coerce_mut()
408 } else {
409 Err(ArrayRetrievalError::NotFound(ArrayType::IntensityArray))
410 }
411 }
412
413 pub fn charges(&'_ self) -> Result<Cow<'_, [i32]>, ArrayRetrievalError> {
415 match self.get(&ArrayType::ChargeArray) {
416 Some(data_array) => data_array.to_i32(),
417 None => Err(ArrayRetrievalError::NotFound(ArrayType::ChargeArray)),
418 }
419 }
420
421 pub fn charge_mut(&mut self) -> Result<&mut [i32], ArrayRetrievalError> {
426 if let Some(arr) = self.get_mut(&ArrayType::ChargeArray) {
427 arr.decode_and_store()?;
428 arr
429 .store_as(BinaryDataArrayType::Int32)
430 .inspect_err(|e| log::error!("Failed to decode charge array: {e}"))?;
431 arr.coerce_mut()
432 } else {
433 Err(ArrayRetrievalError::NotFound(ArrayType::ChargeArray))
434 }
435 }
436
437 pub fn ion_mobility(&self) -> Result<(Cow<'_, [f64]>, ArrayType), ArrayRetrievalError> {
439 if let Some((array_type, data_array)) = self
440 .byte_buffer_map
441 .iter()
442 .find(|(a, _)| a.is_ion_mobility())
443 {
444 Ok((
445 data_array
446 .to_f64()
447 .inspect_err(|e| log::error!("Failed to decode ion mobility array: {e}"))?,
448 array_type.clone(),
449 ))
450 } else {
451 Err(ArrayRetrievalError::NotFound(ArrayType::IonMobilityArray))
452 }
453 }
454
455 pub fn ion_mobility_mut(&mut self) -> Result<(&mut [f64], ArrayType), ArrayRetrievalError> {
459 if let Some((array_type, data_array)) = self
460 .byte_buffer_map
461 .iter_mut()
462 .find(|(a, _)| a.is_ion_mobility())
463 {
464 data_array
465 .decode_and_store()
466 .inspect_err(|e| log::error!("Failed to decode ion mobility array: {e}"))?;
467 data_array.store_as(BinaryDataArrayType::Float32)?;
468 Ok((data_array.coerce_mut()?, array_type.clone()))
469 } else {
470 Err(ArrayRetrievalError::NotFound(ArrayType::IonMobilityArray))
471 }
472 }
473
474 pub fn stack_ion_mobility(self) -> Result<BinaryArrayMap3D, ArrayRetrievalError> {
478 BinaryArrayMap3D::try_from(self)
479 }
480}
481
482impl IntoIterator for BinaryArrayMap {
483 type Item = (ArrayType, DataArray);
484
485 type IntoIter = <HashMap<ArrayType, DataArray> as IntoIterator>::IntoIter;
486
487 fn into_iter(self) -> Self::IntoIter {
488 self.byte_buffer_map.into_iter()
489 }
490}
491
492#[cfg(feature = "mzsignal")]
493mod mzsignal_impl {
494 use super::*;
495
496 use crate::to_bytes;
497 use mzsignal::ArrayPair;
498
499 impl From<ArrayPair<'_>> for BinaryArrayMap {
500 fn from(value: ArrayPair<'_>) -> Self {
501 let mz_array = DataArray::wrap(
502 &ArrayType::MZArray,
503 BinaryDataArrayType::Float64,
504 to_bytes(&value.mz_array),
505 );
506
507 let intensity_array = DataArray::wrap(
508 &ArrayType::IntensityArray,
509 BinaryDataArrayType::Float32,
510 to_bytes(&value.intensity_array),
511 );
512
513 let mut array_map = BinaryArrayMap::new();
514 array_map.add(mz_array);
515 array_map.add(intensity_array);
516 array_map
517 }
518 }
519}
520
521#[derive(Debug, Default, Clone, Copy, PartialEq)]
522#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
523struct NonNaNF64(f64);
524
525impl std::hash::Hash for NonNaNF64 {
526 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
527 self.0.to_bits().hash(state);
528 }
529}
530
531impl From<f64> for NonNaNF64 {
532 fn from(value: f64) -> Self {
533 Self::wrap(value)
534 .unwrap_or_else(|| panic!("Expected an order-able f64 value, but found {}", value))
535 }
536}
537
538impl NonNaNF64 {
539 fn wrap(value: f64) -> Option<Self> {
540 if value.is_nan() {
541 None
542 } else {
543 Some(Self(value))
544 }
545 }
546}
547
548impl PartialOrd for NonNaNF64 {
549 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
550 Some(self.cmp(other))
551 }
552}
553
554impl Eq for NonNaNF64 {}
555
556impl Ord for NonNaNF64 {
557 fn cmp(&self, other: &Self) -> Ordering {
558 self.0.total_cmp(&other.0)
559 }
560}
561
562macro_rules! _populate_stacked_array_from {
563 ($im_dim:ident, $view:ident, $index_map:ident, $array_bins:ident, $array_type:ident, $array:ident) => {
564 for (i_im, im) in $im_dim.iter() {
565 let v = $view[*i_im];
566 let i_axis = $index_map[&NonNaNF64(*im)];
567 let bin = &mut $array_bins[i_axis];
568 if let Some(bin_array) = bin.get_mut($array_type) {
569 bin_array.push(v)?;
570 } else {
571 let mut bin_array = DataArray::from_name_and_type($array_type, $array.dtype());
572 *bin_array.unit_mut() = $array.unit();
573 bin_array.push(v)?;
574 bin.add(bin_array);
575 }
576 }
577 };
578}
579
580#[derive(Debug, Default, Clone)]
587#[cfg_attr(feature = "serde", serde_with::serde_as)]
588#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
589pub struct BinaryArrayMap3D {
590 pub ion_mobility_dimension: Vec<f64>,
591 pub ion_mobility_type: ArrayType,
592 pub ion_mobility_unit: Unit,
593 pub arrays: Vec<BinaryArrayMap>,
594 pub additional_arrays: BinaryArrayMap,
595 #[cfg_attr(feature = "serde", serde_as(as = "Vec<(_, _)>"))]
596 ion_mobility_index: HashMap<NonNaNF64, usize>,
597}
598
599impl BinaryArrayMap3D {
600 pub fn from_ion_mobility_dimension(
606 ion_mobility_dimension: Vec<f64>,
607 ion_mobility_type: ArrayType,
608 ion_mobility_unit: Unit,
609 ) -> BinaryArrayMap3D {
610 let ion_mobility_index: HashMap<_, _> = ion_mobility_dimension
611 .iter()
612 .copied()
613 .enumerate()
614 .map(|(i, f)| {
615 (
616 NonNaNF64::wrap(f)
617 .unwrap_or_else(|| panic!("Expected non-NaN value for ion mobility")),
618 i,
619 )
620 })
621 .collect();
622 let mut arrays = Vec::new();
623 arrays.resize_with(ion_mobility_dimension.len(), BinaryArrayMap::default);
624 Self {
625 ion_mobility_dimension,
626 ion_mobility_type,
627 ion_mobility_unit,
628 arrays,
629 ion_mobility_index,
630 additional_arrays: Default::default(),
631 }
632 }
633
634 pub fn from_ion_mobility_dimension_and_arrays(
640 ion_mobility_dimension: Vec<f64>,
641 ion_mobility_type: ArrayType,
642 ion_mobility_unit: Unit,
643 arrays: Vec<BinaryArrayMap>,
644 ) -> BinaryArrayMap3D {
645 let ion_mobility_index: HashMap<_, _> = ion_mobility_dimension
646 .iter()
647 .copied()
648 .enumerate()
649 .map(|(i, f)| {
650 (
651 NonNaNF64::wrap(f)
652 .unwrap_or_else(|| panic!("Expected non-NaN value for ion mobility")),
653 i,
654 )
655 })
656 .collect();
657
658 assert_eq!(
659 ion_mobility_dimension.len(),
660 arrays.len(),
661 "The number of ion mobility points does not match the number of point-level maps!"
662 );
663
664 Self {
665 ion_mobility_dimension,
666 ion_mobility_type,
667 ion_mobility_unit,
668 arrays,
669 ion_mobility_index,
670 additional_arrays: Default::default(),
671 }
672 }
673
674 pub fn get_ion_mobility(&self, ion_mobility: f64) -> Option<&BinaryArrayMap> {
676 if let Some(i) = NonNaNF64::wrap(ion_mobility) {
677 if let Some(i) = self.ion_mobility_index.get(&i) {
678 self.arrays.get(*i)
679 } else {
680 None
681 }
682 } else {
683 None
684 }
685 }
686
687 pub fn search_ion_mobility(
693 &self,
694 ion_mobility: f64,
695 error_tolerance: f64,
696 ) -> Option<(&BinaryArrayMap, f64)> {
697 match self
698 .ion_mobility_dimension
699 .binary_search_by(|x: &f64| x.total_cmp(&ion_mobility))
700 {
701 Ok(i) => {
702 let delta = ion_mobility - self.ion_mobility_dimension[i];
703 if delta.abs() <= error_tolerance {
704 self.arrays.get(i).map(|a| (a, delta))
705 } else {
706 None
707 }
708 }
709 Err(i) => {
710 if self.arrays.is_empty() {
711 return None;
712 }
713 let delta = ion_mobility - self.ion_mobility_dimension[i];
714 if delta.abs() <= error_tolerance {
715 self.arrays.get(i).map(|a| (a, delta))
716 } else {
717 None
718 }
719 }
720 }
721 }
722
723 pub fn search_ion_mobility_index(&self, ion_mobility: f64, error_tolerance: f64) -> Option<(usize, f64)> {
729 match self
730 .ion_mobility_dimension
731 .binary_search_by(|x: &f64| x.total_cmp(&ion_mobility))
732 {
733 Ok(i) => {
734 let delta = ion_mobility - self.ion_mobility_dimension[i];
735 if delta.abs() <= error_tolerance {
736 Some((i, self.ion_mobility_dimension[i]))
737 } else {
738 None
739 }
740 }
741 Err(i) => {
742 if self.arrays.is_empty() {
743 return None;
744 }
745 let delta = ion_mobility - self.ion_mobility_dimension[i];
746 if delta.abs() <= error_tolerance {
747 Some((i, self.ion_mobility_dimension[i]))
748 } else {
749 None
750 }
751 }
752 }
753 }
754
755 pub fn get_ion_mobility_mut(&mut self, ion_mobility: f64) -> Option<&mut BinaryArrayMap> {
759 if let Some(i) = NonNaNF64::wrap(ion_mobility) {
760 if let Some(i) = self.ion_mobility_index.get(&i) {
761 self.arrays.get_mut(*i)
762 } else {
763 None
764 }
765 } else {
766 None
767 }
768 }
769
770 pub fn iter(&self) -> impl Iterator<Item = (f64, &BinaryArrayMap)> {
773 self.ion_mobility_dimension
774 .iter()
775 .copied()
776 .zip(self.arrays.iter())
777 }
778
779 pub fn iter_mut(&mut self) -> impl Iterator<Item = (f64, &mut BinaryArrayMap)> {
782 self.ion_mobility_dimension
783 .iter()
784 .copied()
785 .zip(self.arrays.iter_mut())
786 }
787
788 pub fn unstack(&self) -> Result<BinaryArrayMap, ArrayRetrievalError> {
798 let mut destination = self.additional_arrays.clone();
799
800 let mut im_dim =
801 DataArray::from_name_and_type(&self.ion_mobility_type, BinaryDataArrayType::Float64);
802 im_dim.unit = self.ion_mobility_unit;
803 let mut sizes = Vec::new();
804 let mut mz_size = None;
805 for (layer, im) in self.arrays.iter().zip(self.ion_mobility_dimension.iter()) {
806 sizes.clear();
807 for (key, array) in layer.iter() {
808 match destination.get_mut(key) {
809 Some(sink) => {
810 sink.extend_raw(&array.data).inspect_err(|e| {
811 log::error!("Failed to extend {key:?}: {e}");
812 })?;
813 }
814 None => {
815 destination.add(array.clone());
816 }
817 }
818 if matches!(key, ArrayType::MZArray) {
819 mz_size = Some(array.data_len()?);
820 } else {
821 sizes.push((key, array.data_len()?));
822 }
823 }
824 if let Some(mz_size) = mz_size {
825 im_dim.extend_iter(std::iter::repeat_n(*im, mz_size))?;
826 } else if let Some((_, size)) = sizes.first() {
827 im_dim.extend_iter(std::iter::repeat_n(*im, *size))?;
828 }
829 }
830
831 let sorter = if let Some(mz_array) = destination.get(&ArrayType::MZArray) {
832 let mzs = mz_array.to_f64()?;
833 let ims = im_dim.to_f64()?;
834
835 let mut indices: Vec<usize> = Vec::with_capacity(mzs.len());
836 indices.extend(0..mzs.len());
837 indices.sort_by(|i, j| {
838 mzs[*i]
839 .total_cmp(&mzs[*j])
840 .then_with(|| ims[*i].total_cmp(&ims[*j]))
841 });
842 Some(indices)
843 } else {
844 None
845 };
846
847 let final_size = im_dim.data_len()?;
848
849 destination.add(im_dim);
850
851 if let Some(sorter) = sorter {
852 destination.sort_from_indices(sorter)?;
853 } else if final_size > 0 {
854 log::debug!("Unsorted unstack");
855 }
856 Ok(destination)
857 }
858
859 pub fn stack(source: &BinaryArrayMap) -> Result<Self, ArrayRetrievalError> {
871 let mut this = Self::default();
872 if !source.has_ion_mobility() {
873 return Err(ArrayRetrievalError::NotFound(ArrayType::IonMobilityArray));
874 }
875 let (im_dim, im_type) = source.ion_mobility()?;
876 this.ion_mobility_unit = source.get(&im_type).unwrap().unit;
877 this.ion_mobility_type = im_type;
878 if im_dim.is_empty() {
879 return Ok(this);
880 }
881 let mut im_dim: Vec<(usize, f64)> = im_dim.iter().copied().enumerate().collect();
882 im_dim.sort_by(|(_, va), (_, vb)| va.total_cmp(vb));
883
884 let mut im_axis = Vec::with_capacity(200);
885 let mut last_v = im_dim.first().unwrap().1 - 1.0;
886 let mut index_map = HashMap::new();
887 for (_, v) in im_dim.iter() {
888 if v.total_cmp(&last_v).is_gt() {
889 last_v = *v;
890 index_map.insert(NonNaNF64::from(*v), im_axis.len());
891 im_axis.push(*v);
892 }
893 }
894
895 let mut array_bins: Vec<BinaryArrayMap> = Vec::with_capacity(im_axis.len());
896 array_bins.resize(im_axis.len(), BinaryArrayMap::default());
897 for (array_type, array) in source.iter() {
898 if array_type.is_ion_mobility() {
899 continue;
900 }
901 if array.data_len()? != im_dim.len() {
902 this.additional_arrays.add(array.clone());
903 continue;
904 }
905 match array.dtype() {
906 BinaryDataArrayType::Unknown => {
907 panic!("Cannot re-sort opaque or unknown dimension data types")
908 }
909 BinaryDataArrayType::Float64 => {
910 let view = array.to_f64()?;
911 _populate_stacked_array_from!(
912 im_dim, view, index_map, array_bins, array_type, array
913 );
914 }
915 BinaryDataArrayType::Float32 => {
916 let view = array.to_f32()?;
917 _populate_stacked_array_from!(
918 im_dim, view, index_map, array_bins, array_type, array
919 );
920 }
921 BinaryDataArrayType::Int64 => {
922 let view = array.to_i64()?;
923 _populate_stacked_array_from!(
924 im_dim, view, index_map, array_bins, array_type, array
925 );
926 }
927 BinaryDataArrayType::Int32 => {
928 let view = array.to_i32()?;
929 _populate_stacked_array_from!(
930 im_dim, view, index_map, array_bins, array_type, array
931 );
932 }
933 BinaryDataArrayType::ASCII => {
934 let view = array.decode()?;
935 _populate_stacked_array_from!(
936 im_dim, view, index_map, array_bins, array_type, array
937 );
938 }
939 }
940 }
941 this.ion_mobility_dimension = im_axis;
942 this.ion_mobility_index = index_map;
943 this.arrays = array_bins;
944 Ok(this)
945 }
946}
947
948impl TryFrom<BinaryArrayMap> for BinaryArrayMap3D {
949 type Error = ArrayRetrievalError;
950
951 fn try_from(value: BinaryArrayMap) -> Result<Self, Self::Error> {
952 Self::stack(&value)
953 }
954}
955
956impl TryFrom<&BinaryArrayMap> for BinaryArrayMap3D {
958 type Error = ArrayRetrievalError;
959
960 fn try_from(value: &BinaryArrayMap) -> Result<Self, Self::Error> {
961 Self::stack(value)
962 }
963}
964
965impl TryFrom<BinaryArrayMap3D> for BinaryArrayMap {
966 type Error = ArrayRetrievalError;
967
968 fn try_from(value: BinaryArrayMap3D) -> Result<Self, Self::Error> {
969 value.unstack()
970 }
971}
972
973impl TryFrom<&BinaryArrayMap3D> for BinaryArrayMap {
975 type Error = ArrayRetrievalError;
976
977 fn try_from(value: &BinaryArrayMap3D) -> Result<Self, Self::Error> {
978 value.unstack()
979 }
980}
981
982
983
984#[cfg(test)]
985mod test {
986 use crate::BinaryDataArrayType;
987
988 use super::*;
989 use std::fs;
990 use std::io::{self, prelude::*};
991
992 fn make_array_from_file() -> io::Result<DataArray> {
993 let mut fh = fs::File::open("../../test/data/mz_f64_zlib_bas64.txt")?;
994 let mut buf = String::new();
995 fh.read_to_string(&mut buf)?;
996 let bytes: Vec<u8> = buf.into();
997 let mut da = DataArray::wrap(&ArrayType::MZArray, BinaryDataArrayType::Float64, bytes);
998 da.compression = BinaryCompressionType::Zlib;
999 Ok(da)
1000 }
1001
1002 #[test]
1003 fn test_construction() -> io::Result<()> {
1004 let da = make_array_from_file()?;
1005 let mut map = BinaryArrayMap::new();
1006 assert!(!map.has_array(&ArrayType::MZArray));
1007 map.add(da);
1008 assert!(map.has_array(&ArrayType::MZArray));
1009 Ok(())
1010 }
1011
1012 #[test]
1013 fn test_decode() -> io::Result<()> {
1014 let da = make_array_from_file()?;
1015 let mut map = BinaryArrayMap::new();
1016 map.add(da);
1017 assert_eq!(
1018 map.get(&ArrayType::MZArray).unwrap().compression,
1019 BinaryCompressionType::Zlib
1020 );
1021 map.decode_all_arrays()?;
1022 assert_eq!(
1023 map.get(&ArrayType::MZArray).unwrap().compression,
1024 BinaryCompressionType::Decoded
1025 );
1026 Ok(())
1027 }
1028}