1use std::borrow::Cow;
2use std::iter::FusedIterator;
3
4use mzpeaks::prelude::*;
5use mzpeaks::{
6 peak::{CentroidPeak, DeconvolutedPeak, MZPoint},
7 peak_set::PeakSetVec,
8 IndexType, MZPeakSetType, MassPeakSetType,
9};
10
11use mzdata_bindata::{ArrayRetrievalError, BinaryArrayMap, BuildFromArrayMap, ArraysAvailable, utils::mass_charge_ratio};
12
13trait SummaryOps {
14 fn base_peak(&self) -> CentroidPeak;
16
17 fn mz_range(&self) -> (f64, f64);
19
20 fn tic(&self) -> f32;
22
23 fn search(&self, query: f64, error_tolerance: Tolerance) -> Option<usize>;
27
28 fn len(&self) -> usize;
31
32 fn get(&self, i: usize) -> Option<MZPoint>;
34
35 fn fetch_summaries(&self) -> SpectrumSummary;
38
39 #[allow(unused)]
40 fn is_empty(&self) -> bool;
42}
43
44impl SummaryOps for BinaryArrayMap {
45 fn base_peak(&self) -> CentroidPeak {
46 let mut peak = CentroidPeak::new(0.0, 0.0, 0);
47 if let Ok(intensities) = self.intensities() {
48 let result = intensities
49 .iter()
50 .enumerate()
51 .max_by(|ia, ib| ia.1.total_cmp(ib.1));
52 if let Ok(mzs) = self.mzs() {
53 if let Some((i, inten)) = result {
54 peak = CentroidPeak::new(mzs[i], *inten, i as IndexType)
55 }
56 }
57 }
58 peak
59 }
60
61 fn mz_range(&self) -> (f64, f64) {
62 if let Ok(mzs) = self.mzs() {
63 if mzs.is_empty() {
64 (0.0, 0.0)
65 } else {
66 (*mzs.first().unwrap(), *mzs.last().unwrap())
67 }
68 } else {
69 (0.0, 0.0)
70 }
71 }
72
73 fn tic(&self) -> f32 {
74 if let Ok(intensities) = self.intensities() {
75 intensities.iter().sum()
76 } else {
77 0.0
78 }
79 }
80
81 fn search(&self, query: f64, error_tolerance: Tolerance) -> Option<usize> {
82 self.search(query, error_tolerance)
83 }
84
85 fn len(&self) -> usize {
86 self.mzs().map(|arr| arr.len()).unwrap_or_default()
87 }
88
89 fn get(&self, i: usize) -> Option<MZPoint> {
90 match (self.mzs(), self.intensities()) {
91 (Ok(mzs), Ok(intensities)) => match (mzs.get(i), intensities.get(i)) {
92 (Some(mz), Some(intensity)) => Some(MZPoint::new(*mz, *intensity)),
93 _ => None,
94 },
95 _ => None,
96 }
97 }
98
99 fn fetch_summaries(&self) -> SpectrumSummary {
100 let (mzs, intensities) = match (self.mzs(), self.intensities()) {
101 (Ok(mzs), Ok(intensities)) => (mzs, intensities),
102 (_, _) => (Cow::Owned(Vec::new()), Cow::Owned(Vec::new())),
103 };
104
105 let (tic, (bpmz, bpint, bpidx)) = mzs.iter().zip(intensities.iter()).enumerate().fold(
106 (0.0, (0.0, 0.0f32, 0)),
107 |(mut tic, (mut bpmz, mut bpint, mut bpidx)), (idx, (mz, int))| {
108 tic += int;
109 if *int > bpint {
110 bpint = *int;
111 bpmz = *mz;
112 bpidx = idx;
113 }
114
115 (tic, (bpmz, bpint, bpidx))
116 },
117 );
118 let mz_range = if mzs.is_empty() {
119 (0.0, 0.0)
120 } else {
121 (mzs.first().copied().unwrap(), mzs.last().copied().unwrap())
122 };
123 SpectrumSummary::new(
124 tic,
125 CentroidPeak::new(bpmz, bpint, bpidx as u32),
126 mz_range,
127 mzs.len(),
128 )
129 }
130
131 fn is_empty(&self) -> bool {
132 self.len() == 0
133 }
134}
135
136impl<C: CentroidLike> SummaryOps for MZPeakSetType<C> {
137 fn base_peak(&self) -> CentroidPeak {
138 let result = self
139 .iter()
140 .enumerate()
141 .max_by(|ia, ib| ia.1.intensity().partial_cmp(&ib.1.intensity()).unwrap());
142 if let Some((i, peak)) = result {
143 CentroidPeak::new(peak.coordinate(), peak.intensity(), i as IndexType)
144 } else {
145 CentroidPeak::new(0.0, 0.0, 0)
146 }
147 }
148
149 fn mz_range(&self) -> (f64, f64) {
150 if PeakCollection::is_empty(self) {
151 (0.0, 0.0)
152 } else {
153 (
154 self.first().as_ref().unwrap().mz(),
155 self.last().as_ref().unwrap().mz(),
156 )
157 }
158 }
159
160 fn tic(&self) -> f32 {
161 self.iter().map(|p| p.intensity()).sum()
162 }
163
164 fn search(&self, query: f64, error_tolerance: Tolerance) -> Option<usize> {
165 PeakCollection::search(self, query, error_tolerance)
166 }
167
168 fn len(&self) -> usize {
169 PeakCollection::len(self)
170 }
171
172 fn get(&self, i: usize) -> Option<MZPoint> {
173 self.peaks
174 .get(i)
175 .map(|p| MZPoint::new(p.mz(), p.intensity()))
176 }
177
178 fn fetch_summaries(&self) -> SpectrumSummary {
179 let state = self.iter().fold(
180 (
181 0.0f32,
182 CentroidPeak::default(),
183 (f64::INFINITY, f64::NEG_INFINITY),
184 ),
185 |(mut tic, mut bp, (mut mz_min, mut mz_max)), p| {
186 tic += p.intensity();
187 if p.intensity() > bp.intensity {
188 bp = p.as_centroid();
189 }
190 let mz = p.mz();
191 mz_min = mz_min.min(mz);
192 mz_max = mz_max.max(mz);
193 (tic, bp, (mz_min, mz_max))
194 },
195 );
196
197 SpectrumSummary::new(state.0, state.1, state.2, SummaryOps::len(self))
198 }
199
200 fn is_empty(&self) -> bool {
201 PeakCollection::is_empty(self)
202 }
203}
204
205impl<D: DeconvolutedCentroidLike> SummaryOps for MassPeakSetType<D> {
206 fn base_peak(&self) -> CentroidPeak {
207 let result = self
208 .iter()
209 .enumerate()
210 .max_by(|ia, ib| ia.1.intensity().partial_cmp(&ib.1.intensity()).unwrap());
211 if let Some((i, peak)) = result {
212 CentroidPeak::new(
213 mass_charge_ratio(peak.coordinate(), peak.charge()),
214 peak.intensity(),
215 i as IndexType,
216 )
217 } else {
218 CentroidPeak::new(0.0, 0.0, 0)
219 }
220 }
221
222 fn mz_range(&self) -> (f64, f64) {
223 if PeakCollection::is_empty(self) {
224 (0.0, 0.0)
225 } else {
226 self.iter()
227 .map(|p| {
228 let m = p.neutral_mass();
229 let z = p.charge();
230 mass_charge_ratio(m, z)
231 })
232 .fold((f64::MAX, f64::MIN), |state, mz| {
233 (state.0.min(mz), state.1.max(mz))
234 })
235 }
236 }
237
238 fn tic(&self) -> f32 {
239 self.iter().map(|p| p.intensity()).sum()
240 }
241
242 fn search(&self, query: f64, error_tolerance: Tolerance) -> Option<usize> {
243 PeakCollection::search(self, query, error_tolerance)
244 }
245
246 fn len(&self) -> usize {
247 PeakCollection::len(self)
248 }
249
250 fn get(&self, i: usize) -> Option<MZPoint> {
251 self.peaks.get(i).map(|p| {
252 MZPoint::new(
253 mass_charge_ratio(p.neutral_mass(), p.charge()),
254 p.intensity(),
255 )
256 })
257 }
258
259 fn fetch_summaries(&self) -> SpectrumSummary {
260 let state = self.iter().fold(
261 (
262 0.0f32,
263 CentroidPeak::default(),
264 (f64::INFINITY, f64::NEG_INFINITY),
265 ),
266 |(mut tic, mut bp, (mut mz_min, mut mz_max)), p| {
267 tic += p.intensity();
268 let mz = mass_charge_ratio(p.neutral_mass(), p.charge());
269 if p.intensity() > bp.intensity {
270 bp.intensity = p.intensity();
271 bp.index = p.get_index();
272 bp.mz = mz;
273 }
274 mz_min = mz_min.min(mz);
275 mz_max = mz_max.max(mz);
276 (tic, bp, (mz_min, mz_max))
277 },
278 );
279
280 SpectrumSummary::new(state.0, state.1, state.2, PeakCollection::len(self))
281 }
282
283 fn is_empty(&self) -> bool {
284 PeakCollection::is_empty(self)
285 }
286}
287
288#[derive(Debug)]
294#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
295pub enum PeakDataLevel<
296 C: CentroidLike = CentroidPeak,
297 D: DeconvolutedCentroidLike = DeconvolutedPeak,
298> {
299 Missing,
301 RawData(BinaryArrayMap),
303 Centroid(MZPeakSetType<C>),
305 Deconvoluted(MassPeakSetType<D>),
307}
308
309impl<C: CentroidLike, D: DeconvolutedCentroidLike> PeakDataLevel<C, D> {
310 pub fn iter(&self) -> PeakDataIterDispatch<'_, C, D> {
315 match self {
316 PeakDataLevel::Missing => PeakDataIterDispatch::PeakData(PeakDataIter::new(self)),
317 PeakDataLevel::RawData(a) => {
318 PeakDataIterDispatch::RawData(RawIter::from_binary_array_map(a).unwrap())
319 }
320 PeakDataLevel::Centroid(_) => PeakDataIterDispatch::PeakData(PeakDataIter::new(self)),
321 PeakDataLevel::Deconvoluted(_) => {
322 PeakDataIterDispatch::PeakData(PeakDataIter::new(self))
323 }
324 }
325 }
326
327 pub(crate) fn try_build_peaks(arrays: &BinaryArrayMap) -> Result<Self, ArrayRetrievalError>
329 where
330 C: BuildFromArrayMap,
331 D: BuildFromArrayMap,
332 {
333 {
334 if let ArraysAvailable::Ok = D::has_arrays_for(arrays) {
335 let peaks = D::try_from_arrays(arrays)?.into();
336 Ok(Self::Deconvoluted(peaks))
337 } else if let ArraysAvailable::Ok = C::has_arrays_for(arrays) {
338 let peaks = C::try_from_arrays(arrays)?.into();
339 Ok(Self::Centroid(peaks))
340 } else {
341 Ok(Self::Missing)
342 }
343 }
344 }
345}
346
347impl<C: CentroidLike + BuildFromArrayMap, D: DeconvolutedCentroidLike + BuildFromArrayMap>
348 TryFrom<&BinaryArrayMap> for PeakDataLevel<C, D>
349{
350 type Error = ArrayRetrievalError;
351
352 fn try_from(value: &BinaryArrayMap) -> Result<Self, Self::Error> {
353 Self::try_build_peaks(value)
354 }
355}
356
357impl<C: CentroidLike, D: DeconvolutedCentroidLike> PeakDataLevel<C, D> {
358 pub fn base_peak(&self) -> CentroidPeak {
360 match self {
361 Self::Missing => CentroidPeak::new(0.0, 0.0, 0),
362 Self::RawData(arrays) => arrays.base_peak(),
363 Self::Centroid(peaks) => SummaryOps::base_peak(peaks),
364 Self::Deconvoluted(peaks) => SummaryOps::base_peak(peaks),
365 }
366 }
367
368 pub fn mz_range(&self) -> (f64, f64) {
370 match self {
371 Self::Missing => (0.0, 0.0),
372 Self::RawData(arrays) => arrays.mz_range(),
373 Self::Centroid(peaks) => peaks.mz_range(),
374 Self::Deconvoluted(peaks) => peaks.mz_range(),
375 }
376 }
377
378 pub fn tic(&self) -> f32 {
380 match self {
381 Self::Missing => 0.0,
382 Self::RawData(arrays) => arrays.tic(),
383 Self::Centroid(peaks) => peaks.tic(),
384 Self::Deconvoluted(peaks) => peaks.tic(),
385 }
386 }
387
388 pub fn search(&self, query: f64, error_tolerance: Tolerance) -> Option<usize> {
393 match self {
394 Self::Missing => None,
395 Self::RawData(arrays) => arrays.search(query, error_tolerance),
396 Self::Centroid(peaks) => SummaryOps::search(peaks, query, error_tolerance),
397 Self::Deconvoluted(peaks) => SummaryOps::search(peaks, query, error_tolerance),
398 }
399 }
400
401 pub fn len(&self) -> usize {
404 match self {
405 Self::Missing => 0,
406 Self::RawData(arrays) => SummaryOps::len(arrays),
407 Self::Centroid(peaks) => SummaryOps::len(peaks),
408 Self::Deconvoluted(peaks) => SummaryOps::len(peaks),
409 }
410 }
411
412 pub fn get(&self, i: usize) -> Option<MZPoint> {
416 match self {
417 PeakDataLevel::Missing => None,
418 PeakDataLevel::RawData(arr) => SummaryOps::get(arr, i),
419 PeakDataLevel::Centroid(peaks) => peaks.get(i),
420 PeakDataLevel::Deconvoluted(peaks) => peaks.get(i),
421 }
422 }
423
424 pub fn fetch_summaries(&self) -> SpectrumSummary {
427 match self {
428 Self::Missing => SpectrumSummary::new(0.0, CentroidPeak::default(), (0.0, 0.0), 0),
429 Self::RawData(arrays) => arrays.fetch_summaries(),
430 Self::Centroid(peaks) => peaks.fetch_summaries(),
431 Self::Deconvoluted(peaks) => peaks.fetch_summaries(),
432 }
433 }
434
435 pub fn is_empty(&self) -> bool {
437 self.len() == 0
438 }
439}
440
441pub struct RawIter<'a> {
446 mz_array: Cow<'a, [f64]>,
447 intensity_array: Cow<'a, [f32]>,
448 n: usize,
449 i: usize,
450}
451
452impl<'a> RawIter<'a> {
453 fn new(mz_array: Cow<'a, [f64]>, intensity_array: Cow<'a, [f32]>) -> Self {
454 let n = mz_array.len();
455 let i = 0;
456 Self {
457 mz_array,
458 intensity_array,
459 n,
460 i,
461 }
462 }
463
464 fn from_binary_array_map(arrays: &'a BinaryArrayMap) -> Result<Self, ArrayRetrievalError> {
465 let mz_array = arrays.mzs()?;
466 let intensity_array = arrays.intensities()?;
467
468 Ok(Self::new(mz_array, intensity_array))
469 }
470}
471
472impl Iterator for RawIter<'_> {
473 type Item = MZPoint;
474
475 fn next(&mut self) -> Option<Self::Item> {
476 if self.i >= self.n {
477 None
478 } else {
479 let i = self.i;
480 let mz = self.mz_array[i];
481 let intens = self.intensity_array[i];
482 self.i += 1;
483 Some(MZPoint::new(mz, intens))
484 }
485 }
486}
487
488pub struct PeakDataIter<'a, C: CentroidLike, D: DeconvolutedCentroidLike> {
492 peaks: &'a PeakDataLevel<C, D>,
493 i: usize,
494 n: usize,
495}
496
497impl<C: CentroidLike, D: DeconvolutedCentroidLike> Iterator for PeakDataIter<'_, C, D> {
498 type Item = MZPoint;
499
500 fn next(&mut self) -> Option<Self::Item> {
501 let i = self.i;
502 if i >= self.n {
503 None
504 } else {
505 self.i += 1;
506 self.get(i)
507 }
508 }
509}
510
511impl<C: CentroidLike, D: DeconvolutedCentroidLike> ExactSizeIterator for PeakDataIter<'_, C, D> {
512 fn len(&self) -> usize {
513 self.n - self.i
514 }
515}
516
517impl<C: CentroidLike, D: DeconvolutedCentroidLike> FusedIterator for PeakDataIter<'_, C, D> {}
518
519impl<C: CentroidLike, D: DeconvolutedCentroidLike> DoubleEndedIterator for PeakDataIter<'_, C, D> {
520 fn next_back(&mut self) -> Option<Self::Item> {
521 let n = self.n;
522 if self.i >= n {
523 None
524 } else {
525 let pt = self.get(n - 1);
526 self.n -= 1;
527 pt
528 }
529 }
530}
531
532impl<'a, C: CentroidLike, D: DeconvolutedCentroidLike> PeakDataIter<'a, C, D> {
533 pub fn new(peaks: &'a PeakDataLevel<C, D>) -> Self {
534 let n = peaks.len();
535 Self { peaks, i: 0, n }
536 }
537
538 pub fn get(&self, i: usize) -> Option<MZPoint> {
539 self.peaks.get(i)
540 }
541}
542
543pub enum PeakDataIterDispatch<'a, C: CentroidLike, D: DeconvolutedCentroidLike> {
549 PeakData(PeakDataIter<'a, C, D>),
550 RawData(RawIter<'a>),
551 RefPeakData(RefPeakDataIter<'a, C, D>),
552}
553
554impl<C: CentroidLike, D: DeconvolutedCentroidLike> Iterator for PeakDataIterDispatch<'_, C, D> {
555 type Item = MZPoint;
556
557 fn next(&mut self) -> Option<Self::Item> {
558 match self {
559 PeakDataIterDispatch::PeakData(a) => a.next(),
560 PeakDataIterDispatch::RawData(a) => a.next(),
561 PeakDataIterDispatch::RefPeakData(a) => a.next(),
562 }
563 }
564}
565
566#[derive(Debug)]
567pub enum RefPeakDataLevel<'a, C: CentroidLike, D: DeconvolutedCentroidLike> {
570 Missing,
572 RawData(&'a BinaryArrayMap),
574 Centroid(&'a MZPeakSetType<C>),
576 Deconvoluted(&'a MassPeakSetType<D>),
578}
579
580#[derive(Debug, Default, Clone)]
582pub struct SpectrumSummary {
583 pub tic: f32,
585 pub base_peak: CentroidPeak,
587 pub mz_range: (f64, f64),
589 pub count: usize,
591}
592
593impl SpectrumSummary {
594 pub fn new(tic: f32, base_peak: CentroidPeak, mz_range: (f64, f64), count: usize) -> Self {
595 Self {
596 tic,
597 base_peak,
598 mz_range,
599 count,
600 }
601 }
602
603 pub fn len(&self) -> usize {
604 self.count
605 }
606
607 pub fn is_empty(&self) -> bool {
608 self.count == 0
609 }
610}
611
612impl<C: CentroidLike, D: DeconvolutedCentroidLike> RefPeakDataLevel<'_, C, D> {
613 pub fn base_peak(&self) -> CentroidPeak {
615 match self {
616 RefPeakDataLevel::Missing => CentroidPeak::new(0.0, 0.0, 0),
617 RefPeakDataLevel::RawData(arrays) => arrays.base_peak(),
618 RefPeakDataLevel::Centroid(peaks) => SummaryOps::base_peak(*peaks),
619 RefPeakDataLevel::Deconvoluted(peaks) => SummaryOps::base_peak(*peaks),
620 }
621 }
622
623 pub fn mz_range(&self) -> (f64, f64) {
625 match self {
626 Self::Missing => (0.0, 0.0),
627 Self::RawData(arrays) => arrays.mz_range(),
628 Self::Centroid(peaks) => peaks.mz_range(),
629 Self::Deconvoluted(peaks) => peaks.mz_range(),
630 }
631 }
632
633 pub fn tic(&self) -> f32 {
635 match self {
636 Self::Missing => 0.0,
637 Self::RawData(arrays) => arrays.tic(),
638 Self::Centroid(peaks) => peaks.tic(),
639 Self::Deconvoluted(peaks) => peaks.tic(),
640 }
641 }
642
643 pub fn search(&self, query: f64, error_tolerance: Tolerance) -> Option<usize> {
648 match self {
649 Self::Missing => None,
650 Self::RawData(arrays) => arrays.search(query, error_tolerance),
651 Self::Centroid(peaks) => SummaryOps::search(*peaks, query, error_tolerance),
652 Self::Deconvoluted(peaks) => SummaryOps::search(*peaks, query, error_tolerance),
653 }
654 }
655
656 pub fn len(&self) -> usize {
659 match self {
660 RefPeakDataLevel::Missing => 0,
661 RefPeakDataLevel::RawData(arrays) => SummaryOps::len(*arrays),
662 RefPeakDataLevel::Centroid(peaks) => SummaryOps::len(*peaks),
663 RefPeakDataLevel::Deconvoluted(peaks) => SummaryOps::len(*peaks),
664 }
665 }
666
667 pub fn is_empty(&self) -> bool {
669 self.len() == 0
670 }
671
672 pub fn iter(&self) -> PeakDataIterDispatch<'_, C, D> {
677 match self {
678 RefPeakDataLevel::Missing => {
679 PeakDataIterDispatch::RefPeakData(RefPeakDataIter::new(self))
680 }
681 RefPeakDataLevel::RawData(a) => {
682 PeakDataIterDispatch::RawData(RawIter::from_binary_array_map(a).unwrap())
683 }
684 RefPeakDataLevel::Centroid(_) => {
685 PeakDataIterDispatch::RefPeakData(RefPeakDataIter::new(self))
686 }
687 RefPeakDataLevel::Deconvoluted(_) => {
688 PeakDataIterDispatch::RefPeakData(RefPeakDataIter::new(self))
689 }
690 }
691 }
692
693 pub fn get(&self, i: usize) -> Option<MZPoint> {
697 match self {
698 RefPeakDataLevel::Missing => None,
699 RefPeakDataLevel::RawData(arr) => SummaryOps::get(*arr, i),
700 RefPeakDataLevel::Centroid(peaks) => peaks.get(i),
701 RefPeakDataLevel::Deconvoluted(peaks) => peaks.get(i),
702 }
703 }
704
705 pub fn fetch_summaries(&self) -> SpectrumSummary {
708 match self {
709 RefPeakDataLevel::Missing => {
710 SpectrumSummary::new(0.0, CentroidPeak::default(), (0.0, 0.0), 0)
711 }
712 RefPeakDataLevel::RawData(arrays) => arrays.fetch_summaries(),
713 RefPeakDataLevel::Centroid(peaks) => peaks.fetch_summaries(),
714 RefPeakDataLevel::Deconvoluted(peaks) => peaks.fetch_summaries(),
715 }
716 }
717}
718
719impl<C: CentroidLike + Clone, D: DeconvolutedCentroidLike + Clone> RefPeakDataLevel<'_, C, D> {
720 pub fn cloned(&self) -> PeakDataLevel<C, D> {
721 match self {
722 RefPeakDataLevel::Missing => PeakDataLevel::Missing,
723 RefPeakDataLevel::RawData(a) => PeakDataLevel::RawData(BinaryArrayMap::clone(a)),
724 RefPeakDataLevel::Centroid(a) => PeakDataLevel::Centroid(PeakSetVec::clone(a)),
725 RefPeakDataLevel::Deconvoluted(a) => PeakDataLevel::Deconvoluted(PeakSetVec::clone(a)),
726 }
727 }
728}
729
730pub struct RefPeakDataIter<'a, C: CentroidLike, D: DeconvolutedCentroidLike> {
734 peaks: &'a RefPeakDataLevel<'a, C, D>,
735 i: usize,
736 n: usize,
737}
738
739impl<C: CentroidLike, D: DeconvolutedCentroidLike> Iterator for RefPeakDataIter<'_, C, D> {
740 type Item = MZPoint;
741
742 fn next(&mut self) -> Option<Self::Item> {
743 let i = self.i;
744 if i >= self.n {
745 None
746 } else {
747 self.i += 1;
748 self.get(i)
749 }
750 }
751}
752
753impl<C: CentroidLike, D: DeconvolutedCentroidLike> ExactSizeIterator for RefPeakDataIter<'_, C, D> {
754 fn len(&self) -> usize {
755 self.n - self.i
756 }
757}
758
759impl<C: CentroidLike, D: DeconvolutedCentroidLike> FusedIterator for RefPeakDataIter<'_, C, D> {}
760
761impl<C: CentroidLike, D: DeconvolutedCentroidLike> DoubleEndedIterator
762 for RefPeakDataIter<'_, C, D>
763{
764 fn next_back(&mut self) -> Option<Self::Item> {
765 let n = self.n;
766 if self.i >= n {
767 None
768 } else {
769 let pt = self.get(n - 1);
770 self.n -= 1;
771 pt
772 }
773 }
774}
775
776impl<'a, C: CentroidLike, D: DeconvolutedCentroidLike> RefPeakDataIter<'a, C, D> {
777 pub fn new(peaks: &'a RefPeakDataLevel<'a, C, D>) -> Self {
778 let n = peaks.len();
779 Self { peaks, i: 0, n }
780 }
781
782 pub fn get(&self, i: usize) -> Option<MZPoint> {
783 self.peaks.get(i)
784 }
785}
786
787#[cfg(test)]
788mod test {
789 use super::*;
790 use mzdata_bindata::BuildArrayMapFrom;
791
792 fn check_remaining(
793 mut it: impl ExactSizeIterator<Item = MZPoint> + DoubleEndedIterator,
794 expected: &[MZPoint],
795 ) {
796 let mut expected = expected.iter().cloned();
797 loop {
798 let n = expected.len();
799 assert_eq!(it.len(), n);
800 assert_eq!(it.next(), expected.next());
801 assert_eq!(it.len(), expected.len());
802 assert_eq!(it.next_back(), expected.next_back());
803 if n == 0 {
804 break;
805 }
806 }
807 assert_eq!(it.next_back(), None);
808 assert_eq!(it.next(), None);
809 }
810
811 #[test]
812 fn test_peak_iterator_remaining() {
813 for n in 0..5 {
814 let peaks: Vec<_> = (0..n)
815 .map(|i| CentroidPeak::new(100.0 + i as f64, i as f32, i))
816 .collect();
817 let expected: Vec<_> = peaks
818 .iter()
819 .map(|p| MZPoint::new(p.mz, p.intensity))
820 .collect();
821 let raw: PeakDataLevel = PeakDataLevel::RawData(CentroidPeak::as_arrays(&peaks));
822 let centroid: PeakDataLevel = PeakDataLevel::Centroid(PeakSetVec::new(peaks));
823 for data in [&raw, ¢roid] {
824 check_remaining(PeakDataIter::new(data), &expected);
825 let borrowed: RefPeakDataLevel<CentroidPeak, DeconvolutedPeak> = match data {
826 PeakDataLevel::RawData(a) => RefPeakDataLevel::RawData(a),
827 PeakDataLevel::Centroid(a) => RefPeakDataLevel::Centroid(a),
828 _ => unreachable!(),
829 };
830 check_remaining(RefPeakDataIter::new(&borrowed), &expected);
831 }
832 }
833 let missing: PeakDataLevel = PeakDataLevel::Missing;
834 check_remaining(PeakDataIter::new(&missing), &[]);
835 let missing: RefPeakDataLevel<CentroidPeak, DeconvolutedPeak> = RefPeakDataLevel::Missing;
836 check_remaining(RefPeakDataIter::new(&missing), &[]);
837 }
838}