Skip to main content

mzdata_bindata/
conversion.rs

1use std::{collections::HashSet, convert::TryInto, mem};
2
3use mzpeaks::{
4    prelude::*,
5    feature::{ChargedFeature, Feature},
6    CentroidLike, CentroidPeak, CoordinateLike, DeconvolutedPeak, DeconvolutedPeakSet,
7    IonMobility,MZPeakSetType, Mass, PeakSet,
8    MZ,
9};
10
11use mzdata_param::Unit;
12
13use crate::{utils::{mass_charge_ratio, neutral_mass}};
14
15use super::{
16    array::DataArray,
17    encodings::{ArrayRetrievalError, ArrayType, BinaryCompressionType, BinaryDataArrayType},
18    map::BinaryArrayMap,
19    BinaryArrayMap3D, ByteArrayView,
20};
21
22impl From<&PeakSet> for BinaryArrayMap {
23    fn from(peaks: &PeakSet) -> BinaryArrayMap {
24        let mut arrays = BinaryArrayMap::new();
25
26        let mut mz_array = DataArray::from_name_type_size(
27            &ArrayType::MZArray,
28            BinaryDataArrayType::Float64,
29            peaks.len() * BinaryDataArrayType::Float64.size_of(),
30        );
31
32        let mut intensity_array = DataArray::from_name_type_size(
33            &ArrayType::IntensityArray,
34            BinaryDataArrayType::Float32,
35            peaks.len() * BinaryDataArrayType::Float32.size_of(),
36        );
37
38        mz_array.compression = BinaryCompressionType::Decoded;
39        intensity_array.compression = BinaryCompressionType::Decoded;
40
41        for p in peaks.iter() {
42            let mz: f64 = p.coordinate();
43            let inten: f32 = p.intensity();
44
45            let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
46            mz_array.data.extend(raw_bytes);
47
48            let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
49            intensity_array.data.extend(raw_bytes);
50        }
51
52        arrays.add(mz_array);
53        arrays.add(intensity_array);
54        arrays
55    }
56}
57
58impl<C: CentroidLike + From<CentroidPeak>> From<BinaryArrayMap> for MZPeakSetType<C> {
59    fn from(arrays: BinaryArrayMap) -> MZPeakSetType<C> {
60        (&arrays).into()
61    }
62}
63
64impl<C: CentroidLike + From<CentroidPeak>> From<&BinaryArrayMap> for MZPeakSetType<C> {
65    fn from(arrays: &BinaryArrayMap) -> MZPeakSetType<C> {
66        let mz_array = arrays.mzs().unwrap();
67        let intensity_array = arrays.intensities().unwrap();
68        let mut peaks = Vec::with_capacity(mz_array.len());
69
70        for (i, (mz, intensity)) in mz_array.iter().zip(intensity_array.iter()).enumerate() {
71            peaks.push(
72                CentroidPeak {
73                    mz: *mz,
74                    intensity: *intensity,
75                    index: i as u32,
76                }
77                .into(),
78            )
79        }
80        MZPeakSetType::<C>::new(peaks)
81    }
82}
83
84impl From<&BinaryArrayMap> for DeconvolutedPeakSet {
85    fn from(arrays: &BinaryArrayMap) -> DeconvolutedPeakSet {
86        let mz_array = arrays.mzs().unwrap();
87        let intensity_array = arrays.intensities().unwrap();
88        let charge_array = arrays
89            .charges()
90            .expect("Charge state array is required for deconvoluted peaks");
91        let mut peaks = Vec::with_capacity(mz_array.len());
92        for (i, ((mz, intensity), charge)) in mz_array
93            .iter()
94            .zip(intensity_array.iter())
95            .zip(charge_array.iter())
96            .enumerate()
97        {
98            peaks.push(DeconvolutedPeak {
99                neutral_mass: neutral_mass(*mz, *charge),
100                intensity: *intensity,
101                charge: *charge,
102                index: i as u32,
103            })
104        }
105
106        DeconvolutedPeakSet::new(peaks)
107    }
108}
109
110impl From<&DeconvolutedPeakSet> for BinaryArrayMap {
111    fn from(peaks: &DeconvolutedPeakSet) -> BinaryArrayMap {
112        let mut arrays = BinaryArrayMap::new();
113
114        let mut mz_array = DataArray::from_name_type_size(
115            &ArrayType::MZArray,
116            BinaryDataArrayType::Float64,
117            peaks.len() * BinaryDataArrayType::Float64.size_of(),
118        );
119
120        let mut intensity_array = DataArray::from_name_type_size(
121            &ArrayType::IntensityArray,
122            BinaryDataArrayType::Float32,
123            peaks.len() * BinaryDataArrayType::Float32.size_of(),
124        );
125
126        let mut charge_array = DataArray::from_name_type_size(
127            &ArrayType::ChargeArray,
128            BinaryDataArrayType::Int32,
129            peaks.len() * BinaryDataArrayType::Int32.size_of(),
130        );
131
132        mz_array.compression = BinaryCompressionType::Decoded;
133        intensity_array.compression = BinaryCompressionType::Decoded;
134        charge_array.compression = BinaryCompressionType::Decoded;
135
136        for p in peaks.iter() {
137            let mz: f64 = p.mz();
138            let inten: f32 = p.intensity();
139            let charge = p.charge();
140
141            let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
142            mz_array.data.extend_from_slice(&raw_bytes);
143
144            let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
145            intensity_array.data.extend_from_slice(&raw_bytes);
146
147            let raw_bytes: [u8; mem::size_of::<i32>()] = charge.to_le_bytes();
148            charge_array.data.extend_from_slice(&raw_bytes);
149        }
150
151        arrays.add(mz_array);
152        arrays.add(intensity_array);
153        arrays.add(charge_array);
154        arrays
155    }
156}
157
158#[derive(Debug, Clone)]
159pub enum ArraysAvailable {
160    Unknown,
161    Ok,
162    MissingArrays(Vec<ArrayType>),
163}
164
165pub trait BuildFromArrayMap: Sized {
166    fn arrays_required() -> Option<Vec<ArrayType>> {
167        None
168    }
169
170    fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError>;
171
172    fn from_arrays(arrays: &BinaryArrayMap) -> Vec<Self> {
173        Self::try_from_arrays(arrays).unwrap()
174    }
175
176    /// A pre-emptive check for the presence of the required arrays.
177    fn has_arrays_for(arrays: &BinaryArrayMap) -> ArraysAvailable {
178        if let Some(arrays_required) = Self::arrays_required() {
179            let missing: Vec<_> = arrays_required
180                .into_iter()
181                .filter(|array_type| !arrays.has_array(array_type))
182                .collect();
183            if !missing.is_empty() {
184                ArraysAvailable::MissingArrays(missing)
185            } else {
186                ArraysAvailable::Ok
187            }
188        } else {
189            ArraysAvailable::Unknown
190        }
191    }
192}
193
194pub trait BuildArrayMapFrom: Sized {
195    fn arrays_included(&self) -> Option<Vec<ArrayType>> {
196        None
197    }
198
199    fn as_arrays(source: &[Self]) -> BinaryArrayMap;
200}
201
202pub trait BuildArrayMap3DFrom: BuildArrayMapFrom {
203    fn as_arrays_3d(source: &[Self]) -> BinaryArrayMap3D {
204        BuildArrayMapFrom::as_arrays(source).try_into().unwrap()
205    }
206}
207
208pub trait BuildFromArrayMap3D: BuildFromArrayMap {
209    fn try_from_arrays_3d(arrays: &BinaryArrayMap3D) -> Result<Vec<Self>, ArrayRetrievalError> {
210        BuildFromArrayMap::try_from_arrays(&arrays.unstack()?)
211    }
212
213    fn from_arrays_3d(arrays: &BinaryArrayMap3D) -> Vec<Self> {
214        Self::try_from_arrays_3d(arrays).unwrap()
215    }
216
217    fn has_arrays_3d_for(arrays: &BinaryArrayMap3D) -> ArraysAvailable {
218        if let Some(arrays_required) = Self::arrays_required() {
219            let arrays_required: Vec<_> = arrays_required
220                .into_iter()
221                .filter(|a| !a.is_ion_mobility())
222                .collect();
223            let mut arrays_not_seen: HashSet<_> = arrays_required.iter().cloned().collect();
224            let mut missing = Vec::new();
225            for (_, arr) in arrays.iter() {
226                if arr.is_empty() {
227                    continue;
228                }
229                missing.clear();
230                for array_type in arrays_required.iter() {
231                    if arr.has_array(array_type) {
232                        arrays_not_seen.remove(array_type);
233                    } else {
234                        missing.push(array_type);
235                    }
236                }
237                if missing.is_empty() {
238                    return ArraysAvailable::Ok;
239                }
240            }
241            if arrays_not_seen.is_empty() {
242                ArraysAvailable::Unknown
243            } else {
244                ArraysAvailable::MissingArrays(arrays_not_seen.into_iter().collect())
245            }
246        } else {
247            ArraysAvailable::Unknown
248        }
249    }
250}
251
252// Basic peaks
253
254impl BuildArrayMapFrom for CentroidPeak {
255    fn arrays_included(&self) -> Option<Vec<ArrayType>> {
256        Some(vec![ArrayType::MZArray, ArrayType::IntensityArray])
257    }
258
259    fn as_arrays(source: &[Self]) -> BinaryArrayMap {
260        let mut arrays = BinaryArrayMap::new();
261
262        let mut mz_array = DataArray::from_name_type_size(
263            &ArrayType::MZArray,
264            BinaryDataArrayType::Float64,
265            source.len() * BinaryDataArrayType::Float64.size_of(),
266        );
267        mz_array.unit = Unit::MZ;
268
269        let mut intensity_array = DataArray::from_name_type_size(
270            &ArrayType::IntensityArray,
271            BinaryDataArrayType::Float32,
272            source.len() * BinaryDataArrayType::Float32.size_of(),
273        );
274        intensity_array.unit = Unit::DetectorCounts;
275
276        mz_array.compression = BinaryCompressionType::Decoded;
277        intensity_array.compression = BinaryCompressionType::Decoded;
278
279        for p in source.iter() {
280            let mz: f64 = p.coordinate();
281            let inten: f32 = p.intensity();
282
283            let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
284            mz_array.data.extend_from_slice(&raw_bytes);
285
286            let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
287            intensity_array.data.extend_from_slice(&raw_bytes);
288        }
289
290        arrays.add(mz_array);
291        arrays.add(intensity_array);
292        arrays
293    }
294}
295
296impl BuildFromArrayMap for CentroidPeak {
297    fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
298        let mz_array = arrays.mzs()?;
299        let intensity_array = arrays.intensities()?;
300        let mut peaks = Vec::with_capacity(mz_array.len());
301
302        for (i, (mz, intensity)) in mz_array.iter().zip(intensity_array.iter()).enumerate() {
303            peaks.push(CentroidPeak {
304                mz: *mz,
305                intensity: *intensity,
306                index: i as u32,
307            })
308        }
309        Ok(peaks)
310    }
311
312    fn arrays_required() -> Option<Vec<ArrayType>> {
313        Some(vec![ArrayType::MZArray, ArrayType::IntensityArray])
314    }
315}
316
317impl BuildArrayMapFrom for DeconvolutedPeak {
318    fn as_arrays(source: &[Self]) -> BinaryArrayMap {
319        let mut arrays = BinaryArrayMap::new();
320
321        let mut mz_array = DataArray::from_name_type_size(
322            &ArrayType::MZArray,
323            BinaryDataArrayType::Float64,
324            source.len() * BinaryDataArrayType::Float64.size_of(),
325        );
326        mz_array.unit = Unit::MZ;
327
328        let mut intensity_array = DataArray::from_name_type_size(
329            &ArrayType::IntensityArray,
330            BinaryDataArrayType::Float32,
331            source.len() * BinaryDataArrayType::Float32.size_of(),
332        );
333        intensity_array.unit = Unit::DetectorCounts;
334
335        let mut charge_array = DataArray::from_name_type_size(
336            &ArrayType::ChargeArray,
337            BinaryDataArrayType::Int32,
338            source.len() * BinaryDataArrayType::Int32.size_of(),
339        );
340
341        mz_array.compression = BinaryCompressionType::Decoded;
342        intensity_array.compression = BinaryCompressionType::Decoded;
343        charge_array.compression = BinaryCompressionType::Decoded;
344
345        for p in source.iter() {
346            let mz: f64 = p.mz();
347            let inten: f32 = p.intensity();
348            let charge = p.charge();
349
350            let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
351            mz_array.data.extend_from_slice(&raw_bytes);
352
353            let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
354            intensity_array.data.extend_from_slice(&raw_bytes);
355
356            let raw_bytes: [u8; mem::size_of::<i32>()] = charge.to_le_bytes();
357            charge_array.data.extend_from_slice(&raw_bytes);
358        }
359
360        arrays.add(mz_array);
361        arrays.add(intensity_array);
362        arrays.add(charge_array);
363        arrays
364    }
365
366    fn arrays_included(&self) -> Option<Vec<ArrayType>> {
367        Some(vec![
368            ArrayType::MZArray,
369            ArrayType::IntensityArray,
370            ArrayType::ChargeArray,
371        ])
372    }
373}
374
375impl BuildFromArrayMap for DeconvolutedPeak {
376    fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
377        let mz_array = arrays.mzs()?;
378        let intensity_array = arrays.intensities()?;
379        let charge_array = arrays.charges()?;
380        let mut peaks = Vec::with_capacity(mz_array.len());
381        for (i, ((mz, intensity), charge)) in mz_array
382            .iter()
383            .zip(intensity_array.iter())
384            .zip(charge_array.iter())
385            .enumerate()
386        {
387            peaks.push(DeconvolutedPeak {
388                neutral_mass: neutral_mass(*mz, *charge),
389                intensity: *intensity,
390                charge: *charge,
391                index: i as u32,
392            })
393        }
394
395        Ok(peaks)
396    }
397}
398
399// Ion mobility features
400
401impl BuildArrayMapFrom for Feature<MZ, IonMobility> {
402    fn arrays_included(&self) -> Option<Vec<ArrayType>> {
403        Some(vec![
404            ArrayType::MZArray,
405            ArrayType::IntensityArray,
406            ArrayType::RawIonMobilityArray,
407            ArrayType::nonstandard("feature identifier array"),
408        ])
409    }
410
411    fn as_arrays(source: &[Self]) -> BinaryArrayMap {
412        let mut arrays = BinaryArrayMap::new();
413        let n: usize = source.iter().map(|f| f.len()).sum();
414
415        let mut mz_array = DataArray::from_name_type_size(
416            &ArrayType::MZArray,
417            BinaryDataArrayType::Float64,
418            n * BinaryDataArrayType::Float64.size_of(),
419        );
420        mz_array.unit = Unit::MZ;
421
422        let mut intensity_array = DataArray::from_name_type_size(
423            &ArrayType::IntensityArray,
424            BinaryDataArrayType::Float32,
425            n * BinaryDataArrayType::Float32.size_of(),
426        );
427        intensity_array.unit = Unit::DetectorCounts;
428
429        let mut ion_mobility_array = DataArray::from_name_type_size(
430            &ArrayType::RawIonMobilityArray,
431            BinaryDataArrayType::Float64,
432            n * BinaryDataArrayType::Float64.size_of(),
433        );
434
435        let mut marker_array = DataArray::from_name_type_size(
436            &ArrayType::nonstandard("feature identifier array"),
437            BinaryDataArrayType::Int32,
438            n * BinaryDataArrayType::Int32.size_of(),
439        );
440
441        mz_array.compression = BinaryCompressionType::Decoded;
442        intensity_array.compression = BinaryCompressionType::Decoded;
443        ion_mobility_array.compression = BinaryCompressionType::Decoded;
444        marker_array.compression = BinaryCompressionType::Decoded;
445
446        let mut acc = Vec::with_capacity(n);
447        source.iter().enumerate().for_each(|(i, f)| {
448            f.iter()
449                .for_each(|(mz, im, inten)| acc.push((mz, im, inten, i)))
450        });
451        acc.sort_by(|(mz_a, im_a, _, key_a), (mz_b, im_b, _, key_b)| {
452            mz_a.total_cmp(mz_b)
453                .then(im_a.total_cmp(im_b))
454                .then(key_a.cmp(key_b))
455        });
456
457        for (mz, im, inten, key) in acc.iter() {
458            mz_array.data.extend_from_slice(&mz.to_le_bytes());
459            intensity_array.data.extend_from_slice(&inten.to_le_bytes());
460            ion_mobility_array.data.extend_from_slice(&im.to_le_bytes());
461            marker_array
462                .data
463                .extend_from_slice(&(*key as i32).to_le_bytes());
464        }
465
466        arrays.add(mz_array);
467        arrays.add(intensity_array);
468        arrays.add(ion_mobility_array);
469        arrays.add(marker_array);
470        arrays
471    }
472}
473
474impl BuildFromArrayMap for Feature<MZ, IonMobility> {
475    fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
476        let mz_array = arrays.mzs()?;
477        let intensity_array = arrays.intensities()?;
478        let im_array = arrays
479            .get(&ArrayType::RawIonMobilityArray)
480            .ok_or(ArrayRetrievalError::NotFound(
481                ArrayType::RawIonMobilityArray,
482            ))?
483            .to_f64()?;
484
485        let array_key = ArrayType::nonstandard("feature identifier array");
486        let marker_array = arrays
487            .get(&array_key)
488            .ok_or(ArrayRetrievalError::NotFound(array_key))?
489            .to_i32()?;
490
491        let n = marker_array.iter().map(|i| *i as usize).max();
492
493        let mut features = if let Some(n) = n {
494            let mut features = Vec::with_capacity(n);
495            features.resize(n, Feature::default());
496            features
497        } else {
498            return Ok(Vec::new());
499        };
500
501        mz_array
502            .iter()
503            .zip(intensity_array.iter())
504            .zip(im_array.iter())
505            .zip(marker_array.iter())
506            .for_each(|(((mz, inten), im), key)| {
507                features[(*key) as usize].push_raw(*mz, *im, *inten);
508            });
509
510        Ok(features)
511    }
512}
513
514impl BuildArrayMapFrom for ChargedFeature<Mass, IonMobility> {
515    fn arrays_included(&self) -> Option<Vec<ArrayType>> {
516        Some(vec![
517            ArrayType::MZArray,
518            ArrayType::IntensityArray,
519            ArrayType::RawIonMobilityArray,
520            ArrayType::ChargeArray,
521            ArrayType::nonstandard("feature identifier array"),
522        ])
523    }
524
525    fn as_arrays(source: &[Self]) -> BinaryArrayMap {
526        let mut arrays = BinaryArrayMap::new();
527        let n: usize = source.iter().map(|f| f.len()).sum();
528
529        let mut mz_array = DataArray::from_name_type_size(
530            &ArrayType::MZArray,
531            BinaryDataArrayType::Float64,
532            n * BinaryDataArrayType::Float64.size_of(),
533        );
534        mz_array.unit = Unit::MZ;
535
536        let mut intensity_array = DataArray::from_name_type_size(
537            &ArrayType::IntensityArray,
538            BinaryDataArrayType::Float32,
539            n * BinaryDataArrayType::Float32.size_of(),
540        );
541        intensity_array.unit = Unit::DetectorCounts;
542
543        let mut charge_array = DataArray::from_name_type_size(
544            &ArrayType::ChargeArray,
545            BinaryDataArrayType::Int32,
546            n * BinaryDataArrayType::Int32.size_of(),
547        );
548
549        let mut ion_mobility_array = DataArray::from_name_type_size(
550            &ArrayType::RawIonMobilityArray,
551            BinaryDataArrayType::Float64,
552            n * BinaryDataArrayType::Float64.size_of(),
553        );
554
555        let mut marker_array = DataArray::from_name_type_size(
556            &ArrayType::nonstandard("feature identifier array"),
557            BinaryDataArrayType::Int32,
558            n * BinaryDataArrayType::Int32.size_of(),
559        );
560
561        mz_array.compression = BinaryCompressionType::Decoded;
562        intensity_array.compression = BinaryCompressionType::Decoded;
563        ion_mobility_array.compression = BinaryCompressionType::Decoded;
564        marker_array.compression = BinaryCompressionType::Decoded;
565
566        let mut acc = Vec::with_capacity(n);
567        source.iter().enumerate().for_each(|(i, f)| {
568            f.iter().for_each(|(mass, im, inten)| {
569                acc.push((mass_charge_ratio(mass, f.charge), im, inten, f.charge, i))
570            })
571        });
572        acc.sort_by(|(mz_a, im_a, _, _, key_a), (mz_b, im_b, _, _, key_b)| {
573            mz_a.total_cmp(mz_b)
574                .then(im_a.total_cmp(im_b))
575                .then(key_a.cmp(key_b))
576        });
577
578        for (mz, im, inten, charge, key) in acc.iter() {
579            mz_array.data.extend(mz.to_le_bytes());
580            intensity_array.data.extend(inten.to_le_bytes());
581            ion_mobility_array.data.extend(im.to_le_bytes());
582            charge_array.data.extend(charge.to_le_bytes());
583            marker_array.data.extend((*key as i32).to_le_bytes());
584        }
585
586        arrays.add(mz_array);
587        arrays.add(intensity_array);
588        arrays.add(ion_mobility_array);
589        arrays.add(charge_array);
590        arrays.add(marker_array);
591        arrays
592    }
593}
594
595impl BuildFromArrayMap for ChargedFeature<Mass, IonMobility> {
596    fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
597        let mz_array = arrays.mzs()?;
598        let intensity_array = arrays.intensities()?;
599        let im_array = arrays
600            .get(&ArrayType::RawIonMobilityArray)
601            .ok_or(ArrayRetrievalError::NotFound(
602                ArrayType::RawIonMobilityArray,
603            ))?
604            .to_f64()?;
605
606        let charge_array = arrays
607            .get(&ArrayType::ChargeArray)
608            .ok_or(ArrayRetrievalError::NotFound(ArrayType::ChargeArray))?
609            .to_i32()?;
610
611        let array_key = ArrayType::nonstandard("feature identifier array");
612        let marker_array = arrays
613            .get(&array_key)
614            .ok_or(ArrayRetrievalError::NotFound(array_key))?
615            .to_i32()?;
616
617        let n = marker_array.iter().map(|i| *i as usize).max();
618
619        let mut features = if let Some(n) = n {
620            let mut features = Vec::with_capacity(n);
621            features.resize(n, ChargedFeature::default());
622            features
623        } else {
624            return Ok(Vec::new());
625        };
626
627        mz_array
628            .iter()
629            .zip(intensity_array.iter())
630            .zip(im_array.iter().zip(charge_array.iter()))
631            .zip(marker_array.iter())
632            .for_each(|(((mz, inten), (im, charge)), key)| {
633                let f = &mut features[(*key) as usize];
634                if f.is_empty() {
635                    f.charge = *charge;
636                }
637                f.push_raw(neutral_mass(*mz, *charge), *im, *inten);
638            });
639
640        Ok(features)
641    }
642}
643
644impl BuildArrayMap3DFrom for Feature<MZ, IonMobility> {}
645
646impl BuildFromArrayMap3D for Feature<MZ, IonMobility> {
647    fn try_from_arrays_3d(arrays: &BinaryArrayMap3D) -> Result<Vec<Self>, ArrayRetrievalError> {
648        let key = ArrayType::nonstandard("feature identifier array");
649        let mut n: usize = 0;
650        for (_, arr) in arrays.iter() {
651            if arr.is_empty() {
652                continue;
653            }
654            if let Some(arr) = arr.get(&key) {
655                if let Some(i) = arr.iter_i32()?.map(|i| i as usize).max() {
656                    n = n.max(i);
657                }
658            }
659        }
660
661        if n == 0 {
662            return Ok(Vec::new());
663        }
664        n += 1;
665        let mut index = Vec::with_capacity(n);
666        index.resize(n, Feature::default());
667
668        for (im, arr) in arrays.iter() {
669            if arr.is_empty() {
670                continue;
671            }
672
673            let mz_array = arr.mzs()?;
674            let intensity_array = arr.intensities()?;
675            let marker_array = arr
676                .get(&key)
677                .ok_or_else(|| ArrayRetrievalError::NotFound(key.clone()))?
678                .to_i32()?;
679
680            for ((mz, inten), key_i) in mz_array
681                .iter()
682                .zip(intensity_array.iter())
683                .zip(marker_array.iter())
684            {
685                index[(*key_i) as usize].push_raw(*mz, im, *inten);
686            }
687        }
688
689        Ok(index)
690    }
691}
692
693impl BuildArrayMap3DFrom for ChargedFeature<Mass, IonMobility> {}
694
695impl BuildFromArrayMap3D for ChargedFeature<Mass, IonMobility> {
696    fn try_from_arrays_3d(arrays: &BinaryArrayMap3D) -> Result<Vec<Self>, ArrayRetrievalError> {
697        let key = ArrayType::nonstandard("feature identifier array");
698        let mut n: usize = 0;
699        for (_, arr) in arrays.iter() {
700            if arr.is_empty() {
701                continue;
702            }
703            if let Some(arr) = arr.get(&key) {
704                if let Some(i) = arr.iter_i32()?.map(|i| i as usize).max() {
705                    n = n.max(i);
706                }
707            }
708        }
709
710        if n == 0 {
711            return Ok(Vec::new());
712        }
713        n += 1;
714        let mut index = Vec::with_capacity(n);
715        index.resize(n, ChargedFeature::default());
716
717        for (im, arr) in arrays.iter() {
718            if arr.is_empty() {
719                continue;
720            }
721
722            let mz_array = arr.mzs()?;
723            let intensity_array = arr.intensities()?;
724            let marker_array = arr
725                .get(&key)
726                .ok_or_else(|| ArrayRetrievalError::NotFound(key.clone()))?
727                .to_i32()?;
728            let charge_array = arr.charges()?;
729
730            for ((mz, inten), (charge, key_i)) in mz_array
731                .iter()
732                .zip(intensity_array.iter())
733                .zip(charge_array.iter().zip(marker_array.iter()))
734            {
735                let f = &mut index[(*key_i) as usize];
736                f.push_raw(*mz, im, *inten);
737                f.charge = *charge;
738            }
739        }
740
741        Ok(index)
742    }
743}
744
745// Ion mobility-aware peaks
746
747impl BuildArrayMapFrom for mzpeaks::peak::IonMobilityAwareCentroidPeak {
748    fn arrays_included(&self) -> Option<Vec<ArrayType>> {
749        Some(vec![
750            ArrayType::MZArray,
751            ArrayType::IntensityArray,
752            ArrayType::IonMobilityArray,
753        ])
754    }
755
756    fn as_arrays(source: &[Self]) -> BinaryArrayMap {
757        let mut arrays = BinaryArrayMap::new();
758
759        let mut mz_array = DataArray::from_name_type_size(
760            &ArrayType::MZArray,
761            BinaryDataArrayType::Float64,
762            source.len() * BinaryDataArrayType::Float64.size_of(),
763        );
764        mz_array.unit = Unit::MZ;
765
766        let mut intensity_array = DataArray::from_name_type_size(
767            &ArrayType::IntensityArray,
768            BinaryDataArrayType::Float32,
769            source.len() * BinaryDataArrayType::Float32.size_of(),
770        );
771        intensity_array.unit = Unit::DetectorCounts;
772
773        let mut im_array = DataArray::from_name_type_size(
774            &ArrayType::IonMobilityArray,
775            BinaryDataArrayType::Float64,
776            source.len() * BinaryDataArrayType::Float64.size_of(),
777        );
778
779        mz_array.compression = BinaryCompressionType::Decoded;
780        intensity_array.compression = BinaryCompressionType::Decoded;
781        im_array.compression = BinaryCompressionType::Decoded;
782
783        for p in source.iter() {
784            let mz: f64 = p.mz();
785            let inten: f32 = p.intensity();
786            let im = p.ion_mobility();
787
788            let raw_bytes: [u8; mem::size_of::<f64>()] = mz.to_le_bytes();
789            mz_array.data.extend_from_slice(&raw_bytes);
790
791            let raw_bytes: [u8; mem::size_of::<f32>()] = inten.to_le_bytes();
792            intensity_array.data.extend_from_slice(&raw_bytes);
793
794            let raw_bytes: [u8; mem::size_of::<f64>()] = im.to_le_bytes();
795            im_array.data.extend_from_slice(&raw_bytes);
796        }
797
798        arrays.add(mz_array);
799        arrays.add(intensity_array);
800        arrays.add(im_array);
801        arrays
802    }
803}
804
805impl BuildFromArrayMap for mzpeaks::peak::IonMobilityAwareCentroidPeak {
806    fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
807        let mz_array = arrays.mzs()?;
808        let intensity_array = arrays.intensities()?;
809        let (im_array, _) = arrays.ion_mobility()?;
810        let mut peaks = Vec::with_capacity(mz_array.len());
811
812        for (i, (mz, (intensity, ion_mobility))) in mz_array
813            .iter()
814            .zip(intensity_array.iter().zip(im_array.iter()))
815            .enumerate()
816        {
817            peaks.push(mzpeaks::peak::IonMobilityAwareCentroidPeak {
818                mz: *mz,
819                intensity: *intensity,
820                index: i as u32,
821                ion_mobility: *ion_mobility,
822            })
823        }
824        Ok(peaks)
825    }
826
827    fn arrays_required() -> Option<Vec<ArrayType>> {
828        Some(vec![
829            ArrayType::MZArray,
830            ArrayType::IntensityArray,
831            ArrayType::IonMobilityArray,
832        ])
833    }
834}
835
836impl BuildArrayMapFrom for mzpeaks::peak::IonMobilityAwareDeconvolutedPeak {
837    fn arrays_included(&self) -> Option<Vec<ArrayType>> {
838        Some(vec![
839            ArrayType::MZArray,
840            ArrayType::IntensityArray,
841            ArrayType::ChargeArray,
842            ArrayType::IonMobilityArray,
843        ])
844    }
845
846    fn as_arrays(source: &[Self]) -> BinaryArrayMap {
847        let mut arrays = BinaryArrayMap::new();
848
849        let mut mz_array = DataArray::from_name_type_size(
850            &ArrayType::MZArray,
851            BinaryDataArrayType::Float64,
852            source.len() * BinaryDataArrayType::Float64.size_of(),
853        );
854        mz_array.unit = Unit::MZ;
855
856        let mut intensity_array = DataArray::from_name_type_size(
857            &ArrayType::IntensityArray,
858            BinaryDataArrayType::Float32,
859            source.len() * BinaryDataArrayType::Float32.size_of(),
860        );
861        intensity_array.unit = Unit::DetectorCounts;
862
863        let mut charge_array = DataArray::from_name_type_size(
864            &ArrayType::ChargeArray,
865            BinaryDataArrayType::Int32,
866            source.len() * BinaryDataArrayType::Int32.size_of(),
867        );
868
869        let mut im_array = DataArray::from_name_type_size(
870            &ArrayType::IonMobilityArray,
871            BinaryDataArrayType::Float64,
872            source.len() * BinaryDataArrayType::Float64.size_of(),
873        );
874
875        mz_array.compression = BinaryCompressionType::Decoded;
876        intensity_array.compression = BinaryCompressionType::Decoded;
877        im_array.compression = BinaryCompressionType::Decoded;
878        charge_array.compression = BinaryCompressionType::Decoded;
879
880        for p in source.iter() {
881            let mz: f64 = p.mz();
882            let inten: f32 = p.intensity();
883            let im = p.ion_mobility();
884
885            mz_array.data.extend_from_slice(&mz.to_le_bytes());
886            intensity_array.data.extend_from_slice(&inten.to_le_bytes());
887            im_array.data.extend_from_slice(&im.to_le_bytes());
888            charge_array
889                .data
890                .extend_from_slice(&p.charge().to_le_bytes());
891        }
892
893        arrays.add(mz_array);
894        arrays.add(intensity_array);
895        arrays.add(im_array);
896        arrays.add(charge_array);
897        arrays
898    }
899}
900
901impl BuildFromArrayMap for mzpeaks::peak::IonMobilityAwareDeconvolutedPeak {
902    fn try_from_arrays(arrays: &BinaryArrayMap) -> Result<Vec<Self>, ArrayRetrievalError> {
903        let mz_array = arrays.mzs()?;
904        let intensity_array = arrays.intensities()?;
905        let charge_array = arrays.charges()?;
906        let (im_array, _) = arrays.ion_mobility()?;
907        let mut peaks = Vec::with_capacity(mz_array.len());
908
909        for (i, (mz, (intensity, (ion_mobility, charge)))) in mz_array
910            .iter()
911            .zip(
912                intensity_array
913                    .iter()
914                    .zip(im_array.iter().zip(charge_array.iter())),
915            )
916            .enumerate()
917        {
918            let mass = neutral_mass(*mz, *charge);
919            peaks.push(mzpeaks::peak::IonMobilityAwareDeconvolutedPeak {
920                neutral_mass: mass,
921                intensity: *intensity,
922                index: i as u32,
923                ion_mobility: *ion_mobility,
924                charge: *charge,
925            })
926        }
927        Ok(peaks)
928    }
929
930    fn arrays_required() -> Option<Vec<ArrayType>> {
931        Some(vec![
932            ArrayType::MZArray,
933            ArrayType::IntensityArray,
934            ArrayType::ChargeArray,
935            ArrayType::IonMobilityArray,
936        ])
937    }
938}