use std::borrow::{Borrow, Cow};
use super::bindata::{ArrayRetrievalError, ArrayType, BinaryArrayMap, ByteArrayView};
use crate::params::{Param, ParamDescribed};
use crate::spectrum::scan_properties::{
ChromatogramDescription, ChromatogramType, Precursor, ScanPolarity,
};
use mzpeaks::coordinate::{Time, MZ};
use mzpeaks::feature::{FeatureView, SimpleFeature, TimeInterval};
#[derive(Debug, Default, Clone)]
pub struct Chromatogram {
description: ChromatogramDescription,
pub arrays: BinaryArrayMap,
}
const EMPTY: &[f64] = &[0.0];
macro_rules! as_feature_view {
($chromatogram:ident, $view:ident => $then:tt) => {
if let Ok(t) = $chromatogram.time() {
if let Ok(i) = $chromatogram.intensity() {
let $view = FeatureView::<Time, Time>::new(t.borrow(), t.borrow(), i.borrow());
Some($then)
} else {
None
}
} else {
None
}
};
}
#[allow(unused)]
pub(crate) fn as_simple_feature(chromatogram: &Chromatogram) -> Option<SimpleFeature<MZ, Time>> {
if let Ok(t) = chromatogram.time() {
if let Ok(i) = chromatogram.intensity() {
let mut f = SimpleFeature::<MZ, Time>::empty(0.0);
f.extend(t.iter().zip(i.iter()).map(|(y, z)| (0.0f64, *y, *z)));
return Some(f);
}
}
None
}
impl TimeInterval<Time> for Chromatogram {
fn start_time(&self) -> Option<f64> {
if let Ok(t) = self.time() {
t.first().copied()
} else {
None
}
}
fn end_time(&self) -> Option<f64> {
if let Ok(t) = self.time() {
t.last().copied()
} else {
None
}
}
fn apex_time(&self) -> Option<f64> {
as_feature_view!(self, view => {
view.apex_time()
})?
}
fn area(&self) -> f32 {
as_feature_view!(self, view => {
view.area()
})
.unwrap()
}
fn iter_time(&self) -> impl Iterator<Item = f64> {
if let Ok(t) = self.time() {
Vec::from(t).into_iter()
} else {
Vec::from(EMPTY).into_iter()
}
}
}
pub trait ChromatogramLike {
fn description(&self) -> &ChromatogramDescription;
fn description_mut(&mut self) -> &mut ChromatogramDescription;
#[inline]
fn precursor(&self) -> Option<&Precursor> {
let desc = self.description();
if let Some(precursor) = &desc.precursor {
Some(precursor)
} else {
None
}
}
#[inline]
fn start_time(&self) -> Option<f64> {
if let Ok(t) = self.time() {
t.first().copied()
} else {
None
}
}
#[inline]
fn end_time(&self) -> Option<f64> {
if let Ok(t) = self.time() {
t.last().copied()
} else {
None
}
}
#[inline]
fn ms_level(&self) -> Option<u8> {
self.description().ms_level
}
#[inline]
fn id(&self) -> &str {
&self.description().id
}
#[inline]
fn chromatogram_typ(&self) -> ChromatogramType {
self.description().chromatogram_type
}
#[inline]
fn index(&self) -> usize {
self.description().index
}
#[inline]
fn polarity(&self) -> ScanPolarity {
self.description().polarity
}
fn is_aggregate(&self) -> bool {
self.description().is_aggregate()
}
fn is_electromagnetic_radiation(&self) -> bool {
self.description().is_electromagnetic_radiation()
}
fn is_ion_current(&self) -> bool {
self.description().is_ion_current()
}
fn time(&self) -> Result<Cow<'_, [f64]>, ArrayRetrievalError>;
fn intensity(&self) -> Result<Cow<'_, [f32]>, ArrayRetrievalError>;
}
impl Chromatogram {
pub fn new(description: ChromatogramDescription, arrays: BinaryArrayMap) -> Self {
Self {
description,
arrays,
}
}
pub fn time(&self) -> Result<Cow<'_, [f64]>, ArrayRetrievalError> {
if let Some(a) = self.arrays.get(&ArrayType::TimeArray) {
a.to_f64()
} else {
Err(ArrayRetrievalError::NotFound(ArrayType::TimeArray))
}
}
pub fn intensity(&self) -> Result<Cow<'_, [f32]>, ArrayRetrievalError> {
if let Some(a) = self.arrays.get(&ArrayType::IntensityArray) {
a.to_f32()
} else {
Err(ArrayRetrievalError::NotFound(ArrayType::IntensityArray))
}
}
pub fn apex_time(&self) -> Option<f64> {
TimeInterval::apex_time(&self)
}
pub fn area(&self) -> f32 {
TimeInterval::area(&self)
}
}
impl ChromatogramLike for Chromatogram {
fn description(&self) -> &ChromatogramDescription {
&self.description
}
fn time(&self) -> Result<Cow<'_, [f64]>, ArrayRetrievalError> {
self.time()
}
fn intensity(&self) -> Result<Cow<'_, [f32]>, ArrayRetrievalError> {
self.intensity()
}
fn description_mut(&mut self) -> &mut ChromatogramDescription {
&mut self.description
}
}
impl ParamDescribed for Chromatogram {
fn params(&self) -> &[Param] {
self.description.params()
}
fn params_mut(&mut self) -> &mut crate::ParamList {
self.description.params_mut()
}
}