1use std::{marker::PhantomData, mem};
2
3use mzpeaks::{CentroidLike, CentroidPeak, DeconvolutedCentroidLike, DeconvolutedPeak};
4
5use crate::{MultiLayerSpectrum, SpectrumLike};
6
7use super::utils::GroupIterState;
8
9
10pub trait SpectrumGrouping<
12 C: CentroidLike = CentroidPeak,
13 D: DeconvolutedCentroidLike = DeconvolutedPeak,
14 S: SpectrumLike<C, D> = MultiLayerSpectrum<C, D>,
15>: Default
16{
17 fn precursor(&self) -> Option<&S>;
19 fn precursor_mut(&mut self) -> Option<&mut S>;
21 fn set_precursor(&mut self, prec: S);
23
24 fn products(&self) -> &[S];
26
27 fn products_mut(&mut self) -> &mut Vec<S>;
29
30 fn total_spectra(&self) -> usize {
32 self.precursor().is_some() as usize + self.products().len()
33 }
34
35 fn earliest_spectrum(&self) -> Option<&S> {
37 self.precursor().or_else(|| {
38 self.products().iter().min_by(|a, b| {
39 a.acquisition()
40 .start_time()
41 .total_cmp(&b.acquisition().start_time())
42 })
43 })
44 }
45
46 fn latest_spectrum(&self) -> Option<&S> {
48 let product = self.products().iter().max_by(|a, b| {
49 a.acquisition()
50 .start_time()
51 .total_cmp(&b.acquisition().start_time())
52 });
53 match (self.precursor(), product) {
54 (None, None) => None,
55 (None, Some(c)) => Some(c),
56 (Some(p), None) => Some(p),
57 (Some(p), Some(c)) => {
58 if p.start_time() > c.start_time() {
59 Some(p)
60 } else {
61 Some(c)
62 }
63 },
64 }
65 }
66
67 fn lowest_ms_level(&self) -> Option<u8> {
69 let prec_level = self.precursor().map(|p| p.ms_level()).unwrap_or(u8::MAX);
70 let val = self
71 .products()
72 .iter()
73 .fold(prec_level, |state, s| state.min(s.ms_level()));
74 if val > 0 {
75 Some(val)
76 } else {
77 None
78 }
79 }
80
81 fn highest_ms_level(&self) -> Option<u8> {
83 let prec_level = self
84 .precursor()
85 .map(|p| p.ms_level())
86 .unwrap_or_else(|| u8::MIN);
87 let val = self
88 .products()
89 .iter()
90 .fold(prec_level, |state, s| state.max(s.ms_level()));
91 if val > 0 {
92 Some(val)
93 } else {
94 None
95 }
96 }
97
98 fn into_parts(self) -> (Option<S>, Vec<S>);
100}
101
102#[derive(Debug, Clone, PartialEq)]
106#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
107pub struct SpectrumGroup<C = CentroidPeak, D = DeconvolutedPeak, S = MultiLayerSpectrum<C, D>>
108where
109 C: CentroidLike,
110 D: DeconvolutedCentroidLike,
111 S: SpectrumLike<C, D>,
112{
113 pub precursor: Option<S>,
115 pub products: Vec<S>,
118 centroid_type: PhantomData<C>,
119 deconvoluted_type: PhantomData<D>,
120}
121
122impl<C, D, S> IntoIterator for SpectrumGroup<C, D, S>
123where
124 C: CentroidLike,
125 D: DeconvolutedCentroidLike,
126 S: SpectrumLike<C, D> + Default,
127{
128 type Item = S;
129
130 type IntoIter = SpectrumGroupIntoIter<C, D, S, Self>;
131
132 fn into_iter(self) -> Self::IntoIter {
133 SpectrumGroupIntoIter::new(self)
134 }
135}
136
137impl<'a, C, D, S> SpectrumGroup<C, D, S>
138where
139 C: CentroidLike,
140 D: DeconvolutedCentroidLike,
141 S: SpectrumLike<C, D>,
142{
143 pub fn new(precursor: Option<S>, products: Vec<S>) -> Self {
144 Self { precursor, products, centroid_type: PhantomData, deconvoluted_type: PhantomData }
145 }
146
147 pub fn iter(&'a self) -> SpectrumGroupIter<'a, C, D, S> {
148 SpectrumGroupIter::new(self)
149 }
150}
151
152pub struct SpectrumGroupIntoIter<
155 C: CentroidLike = CentroidPeak,
156 D: DeconvolutedCentroidLike = DeconvolutedPeak,
157 S: SpectrumLike<C, D> + Default = MultiLayerSpectrum<C, D>,
158 G: SpectrumGrouping<C, D, S> = SpectrumGroup<C, D, S>,
159> {
160 group: G,
161 state: GroupIterState,
162 _c: PhantomData<C>,
163 _d: PhantomData<D>,
164 _s: PhantomData<S>,
165}
166
167impl<
168 C: CentroidLike,
169 D: DeconvolutedCentroidLike,
170 S: SpectrumLike<C, D> + Default,
171 G: SpectrumGrouping<C, D, S>,
172 > Iterator for SpectrumGroupIntoIter<C, D, S, G>
173{
174 type Item = S;
175
176 fn next(&mut self) -> Option<Self::Item> {
177 {
178 let n = self.n_products();
179 let emission = match self.state {
180 GroupIterState::Precursor => match self.group.precursor_mut() {
181 Some(prec) => {
182 if n > 0 {
183 self.state = GroupIterState::Product(0);
184 } else {
185 self.state = GroupIterState::Done;
186 }
187 Some(mem::take(prec))
188 }
189 None => {
190 if n > 0 {
191 self.state = if n > 1 {
192 GroupIterState::Product(1)
193 } else {
194 GroupIterState::Done
195 };
196 Some(mem::take(&mut self.group.products_mut()[0]))
197 } else {
198 self.state = GroupIterState::Done;
199 None
200 }
201 }
202 },
203 GroupIterState::Product(i) => {
204 if i < n.saturating_sub(1) {
205 self.state = GroupIterState::Product(i + 1);
206 Some(mem::take(&mut self.group.products_mut()[i]))
207 } else {
208 self.state = GroupIterState::Done;
209 Some(mem::take(&mut self.group.products_mut()[i]))
210 }
211 }
212 GroupIterState::Done => None,
213 };
214 emission
215 }
216 }
217}
218
219impl<
220 C: CentroidLike,
221 D: DeconvolutedCentroidLike,
222 S: SpectrumLike<C, D> + Default,
223 G: SpectrumGrouping<C, D, S>,
224 > SpectrumGroupIntoIter<C, D, S, G>
225{
226 pub fn new(group: G) -> Self {
227 Self {
228 group,
229 state: GroupIterState::Precursor,
230 _c: PhantomData,
231 _d: PhantomData,
232 _s: PhantomData,
233 }
234 }
235
236 fn n_products(&self) -> usize {
237 self.group.products().len()
238 }
239}
240
241pub struct SpectrumGroupIter<
245 'a,
246 C: CentroidLike = CentroidPeak,
247 D: DeconvolutedCentroidLike = DeconvolutedPeak,
248 S: SpectrumLike<C, D> = MultiLayerSpectrum<C, D>,
249 G: SpectrumGrouping<C, D, S> = SpectrumGroup<C, D, S>,
250> {
251 group: &'a G,
252 state: GroupIterState,
253 _c: PhantomData<C>,
254 _d: PhantomData<D>,
255 _s: PhantomData<S>,
256}
257
258impl<
259 'a,
260 C: CentroidLike,
261 D: DeconvolutedCentroidLike,
262 S: SpectrumLike<C, D> + 'a,
263 G: SpectrumGrouping<C, D, S>,
264 > Iterator for SpectrumGroupIter<'a, C, D, S, G>
265{
266 type Item = &'a S;
267
268 fn next(&mut self) -> Option<Self::Item> {
269 {
270 let n = self.n_products();
271 let emission = match self.state {
272 GroupIterState::Precursor => match self.group.precursor() {
273 Some(prec) => {
274 if n > 0 {
275 self.state = GroupIterState::Product(0);
276 } else {
277 self.state = GroupIterState::Done;
278 }
279 Some(prec)
280 }
281 None => {
282 if n > 0 {
283 self.state = if n > 1 {
284 GroupIterState::Product(1)
285 } else {
286 GroupIterState::Done
287 };
288 Some(&self.group.products()[0])
289 } else {
290 self.state = GroupIterState::Done;
291 None
292 }
293 }
294 },
295 GroupIterState::Product(i) => {
296 if i < n.saturating_sub(1) {
297 self.state = GroupIterState::Product(i + 1);
298 Some(&self.group.products()[i])
299 } else {
300 self.state = GroupIterState::Done;
301 Some(&self.group.products()[i])
302 }
303 }
304 GroupIterState::Done => None,
305 };
306 emission
307 }
308 }
309}
310
311impl<
312 'a,
313 C: CentroidLike,
314 D: DeconvolutedCentroidLike,
315 S: SpectrumLike<C, D>,
316 G: SpectrumGrouping<C, D, S>,
317 > SpectrumGroupIter<'a, C, D, S, G>
318{
319 pub fn new(group: &'a G) -> Self {
320 Self {
321 group,
322 state: GroupIterState::Precursor,
323 _c: PhantomData,
324 _d: PhantomData,
325 _s: PhantomData,
326 }
327 }
328
329 fn n_products(&self) -> usize {
330 self.group.products().len()
331 }
332}
333
334impl<C: CentroidLike, D: DeconvolutedCentroidLike, S: SpectrumLike<C, D>>
335 Default for SpectrumGroup<C, D, S>
336{
337 fn default() -> Self {
338 Self {
339 precursor: None,
340 products: Vec::new(),
341 centroid_type: PhantomData,
342 deconvoluted_type: PhantomData,
343 }
344 }
345}
346
347impl<C, D, S> SpectrumGrouping<C, D, S> for SpectrumGroup<C, D, S>
348where
349 C: CentroidLike,
350 D: DeconvolutedCentroidLike,
351 S: SpectrumLike<C, D>,
352{
353 fn precursor(&self) -> Option<&S> {
354 match &self.precursor {
355 Some(prec) => Some(prec),
356 None => None,
357 }
358 }
359
360 fn precursor_mut(&mut self) -> Option<&mut S> {
361 match &mut self.precursor {
362 Some(prec) => Some(prec),
363 None => None,
364 }
365 }
366
367 fn set_precursor(&mut self, prec: S) {
368 self.precursor = Some(prec)
369 }
370
371 fn products(&self) -> &[S] {
372 &self.products
373 }
374
375 fn products_mut(&mut self) -> &mut Vec<S> {
376 &mut self.products
377 }
378
379 fn into_parts(self) -> (Option<S>, Vec<S>) {
380 (self.precursor, self.products)
381 }
382}
383
384
385#[cfg(test)]
386mod test {
387 use crate::Spectrum;
388
389 use super::*;
390
391 fn make_group() -> SpectrumGroup {
392 let mut spec1 = Spectrum::default();
393 {
394 let desc1 = spec1.description_mut();
395 desc1.id = "index=0".into();
396 desc1.ms_level = 1;
397 desc1.index = 0;
398 desc1.acquisition.first_scan_mut().unwrap().start_time = 100.0;
399 }
400
401 let mut spec2 = Spectrum::default();
402 {
403 let desc2 = spec2.description_mut();
404 desc2.id = "index=1".into();
405 desc2.ms_level = 2;
406 desc2.index = 1;
407 desc2.acquisition.first_scan_mut().unwrap().start_time = 101.0;
408 }
409
410 let mut spec3 = Spectrum::default();
411 {
412 let desc3 = spec3.description_mut();
413 desc3.id = "index=2".into();
414 desc3.ms_level = 2;
415 desc3.index = 2;
416 desc3.acquisition.first_scan_mut().unwrap().start_time = 101.5;
417 }
418
419 SpectrumGroup::new(Some(spec1), vec![
420 spec2,
421 spec3
422 ])
423 }
424
425 #[test]
426 fn test_construct() {
427 let group = make_group();
428 assert_eq!(group.lowest_ms_level().unwrap(), 1);
429 assert_eq!(group.highest_ms_level().unwrap(), 2);
430
431 assert_eq!(group.earliest_spectrum().unwrap().ms_level(), 1);
432 assert_eq!(group.latest_spectrum().unwrap().ms_level(), 2);
433
434 assert_eq!(group.iter().count(), 3);
435 assert_eq!(group.into_iter().count(), 3);
436 }
437}