mzdeisotope-map 0.3.4

A library to deisotope and charge state deconvolve mass spectra
Documentation
use std::ops::{Index, IndexMut};

use mzpeaks::{
    feature::Feature,
    feature_map::FeatureMap,
    prelude::*,
    MZ,
};

#[derive(Debug, Default, Clone)]
pub struct IndexedFeature<Y> {
    pub(crate) feature: Feature<MZ, Y>,
    pub mz: f64,
    pub intensity: f32,
    pub charges: Option<Box<[i32]>>,
}

impl<Y> IndexedFeature<Y> {
    pub fn invalidate(&mut self) {
        self.mz = self.feature.mz();
        self.intensity = self.feature.intensity();
        self.charges = None;
    }

    pub fn charges(&self) -> Option<&[i32]> {
        self.charges.as_deref()
    }

    pub fn charges_mut(&mut self) -> &mut Option<Box<[i32]>> {
        &mut self.charges
    }
}

impl<Y> IndexedFeature<Y> {
    pub fn total_intensity(&self) -> f32 {
        self.intensity
    }
}

impl<Y> AsRef<Feature<MZ, Y>> for IndexedFeature<Y> {
    fn as_ref(&self) -> &Feature<MZ, Y> {
        &self.feature
    }
}

impl<Y> From<Feature<MZ, Y>> for IndexedFeature<Y> {
    fn from(value: Feature<MZ, Y>) -> Self {
        let mz = value.coordinate();
        let intensity = value.intensity();
        Self {
            feature: value,
            mz,
            intensity,
            charges: None,
        }
    }
}

impl<Y> From<IndexedFeature<Y>> for Feature<MZ, Y> {
    fn from(value: IndexedFeature<Y>) -> Self {
        value.feature
    }
}

impl<Y> PartialOrd for IndexedFeature<Y> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.feature.partial_cmp(&other.feature)
    }
}

impl<Y> PartialEq for IndexedFeature<Y> {
    fn eq(&self, other: &Self) -> bool {
        self.feature == other.feature
    }
}

impl<Y1> FeatureLike<MZ, Y1> for IndexedFeature<Y1> {
    fn len(&self) -> usize {
        <Feature<MZ, Y1> as FeatureLike<MZ, Y1>>::len(&self.feature)
    }

    fn iter(&self) -> impl Iterator<Item = (f64, f64, f32)> {
        <Feature<MZ, Y1> as FeatureLike<MZ, Y1>>::iter(&self.feature)
    }
}

impl<Y1> IntensityMeasurement for IndexedFeature<Y1> {
    fn intensity(&self) -> f32 {
        self.intensity
    }
}

impl<Y1> FeatureLikeMut<MZ, Y1> for IndexedFeature<Y1> {
    fn iter_mut(&mut self) -> impl Iterator<Item = (&mut f64, &mut f64, &mut f32)> {
        <Feature<MZ, Y1> as FeatureLikeMut<MZ, Y1>>::iter_mut(&mut self.feature)
    }

    fn push<T: CoordinateLike<MZ> + IntensityMeasurement>(&mut self, pt: &T, time: f64) {
        <Feature<MZ, Y1> as FeatureLikeMut<MZ, Y1>>::push(&mut self.feature, pt, time)
    }

    fn push_raw(&mut self, x: f64, y: f64, z: f32) {
        <Feature<MZ, Y1> as FeatureLikeMut<MZ, Y1>>::push_raw(&mut self.feature, x, y, z)
    }

    fn clear(&mut self) {
        <Feature<MZ, Y1> as FeatureLikeMut<MZ, Y1>>::clear(&mut self.feature)
    }
}

impl<T: CoordinateLike<MZ> + IntensityMeasurement, Y1> BuildFromPeak<T> for IndexedFeature<Y1> {
    fn push_peak(&mut self, value: &T, time: f64) {
        <Feature<MZ, Y1> as BuildFromPeak<T>>::push_peak(&mut self.feature, value, time)
    }
}

impl<Y1> TimeInterval<Y1> for IndexedFeature<Y1> {
    fn apex_time(&self) -> Option<f64> {
        <Feature<MZ, Y1> as TimeInterval<Y1>>::apex_time(&self.feature)
    }

    fn area(&self) -> f32 {
        <Feature<MZ, Y1> as TimeInterval<Y1>>::area(&self.feature)
    }

    fn end_time(&self) -> Option<f64> {
        <Feature<MZ, Y1> as TimeInterval<Y1>>::end_time(&self.feature)
    }

    fn start_time(&self) -> Option<f64> {
        <Feature<MZ, Y1> as TimeInterval<Y1>>::start_time(&self.feature)
    }

    fn iter_time(&self) -> impl Iterator<Item = f64> {
        <Feature<MZ, Y1> as TimeInterval<Y1>>::iter_time(&self.feature)
    }

    fn find_time(&self, time: f64) -> (Option<usize>, f64) {
        <Feature<MZ, Y1> as TimeInterval<Y1>>::find_time(&self.feature, time)
    }
}

impl<Y1> CoordinateLike<MZ> for IndexedFeature<Y1> {
    fn coordinate(&self) -> f64 {
        self.mz
    }
}

impl<Y1> TimeArray<Y1> for IndexedFeature<Y1> {
    fn time_view(&self) -> &[f64] {
        <Feature<MZ, Y1> as TimeArray<Y1>>::time_view(&self.feature)
    }

    fn intensity_view(&self) -> &[f32] {
        <Feature<MZ, Y1> as TimeArray<Y1>>::intensity_view(&self.feature)
    }
}

#[derive(Debug, Default, Clone)]
pub struct IndexedFeatureMap<Y> {
    features: FeatureMap<MZ, Y, IndexedFeature<Y>>,
    index: Vec<f64>,
}

impl<Y> AsRef<FeatureMap<MZ, Y, IndexedFeature<Y>>> for IndexedFeatureMap<Y> {
    fn as_ref(&self) -> &FeatureMap<MZ, Y, IndexedFeature<Y>> {
        &self.features
    }
}

impl<Y> FromIterator<IndexedFeature<Y>> for IndexedFeatureMap<Y> {
    fn from_iter<T: IntoIterator<Item = IndexedFeature<Y>>>(iter: T) -> Self {
        FeatureMap::from_iter(iter.into_iter(), true).into()
    }
}

impl<Y> From<FeatureMap<MZ, Y, IndexedFeature<Y>>> for IndexedFeatureMap<Y> {
    fn from(value: FeatureMap<MZ, Y, IndexedFeature<Y>>) -> Self {
        let mut this = Self {
            features: value,
            index: Vec::new(),
        };
        this.build_index();
        this
    }
}

impl<Y> From<FeatureMap<MZ, Y, Feature<MZ, Y>>> for IndexedFeatureMap<Y> {
    fn from(value: FeatureMap<MZ, Y, Feature<MZ, Y>>) -> Self {
        let mut this = Self {
            features: value.into_iter().map(IndexedFeature::from).collect(),
            index: Vec::new(),
        };
        this.build_index();
        this
    }
}

impl<Y> IndexedFeatureMap<Y> {
    pub fn new(features: Vec<IndexedFeature<Y>>) -> Self {
        let features = FeatureMap::new(features);
        let mut this = Self {
            features,
            index: Vec::new()
        };
        this.build_index();
        this
    }

    fn build_index(&mut self) {
        self.index = self.features.iter().map(|f| f.mz).collect();
    }

    pub fn as_slice(&self) -> &[IndexedFeature<Y>] {
        self.features.as_slice()
    }

    pub fn first(&self) -> Option<&IndexedFeature<Y>> {
        self.features.first()
    }

    pub fn is_empty(&self) -> bool {
        self.features.is_empty()
    }

    pub fn into_inner(self) -> FeatureMap<MZ, Y, IndexedFeature<Y>> {
        self.features
    }

    pub fn iter(&self) -> std::slice::Iter<'_, IndexedFeature<Y>> {
        self.features.iter()
    }

    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, IndexedFeature<Y>> {
        self.features.iter_mut()
    }

    pub fn len(&self) -> usize {
        self.features.len()
    }

    pub fn empty() -> Self {
        let inner = FeatureMap::<MZ, Y, Feature<MZ, Y>>::empty();
        inner.into()
    }
}

impl<Y> Index<usize> for IndexedFeatureMap<Y> {
    type Output = IndexedFeature<Y>;

    fn index(&self, index: usize) -> &Self::Output {
        &self.features[index]
    }
}

impl<Y> IndexMut<usize> for IndexedFeatureMap<Y> {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        &mut self.features[index]
    }
}

impl<Y1> FeatureMapLikeMut<MZ, Y1, IndexedFeature<Y1>> for IndexedFeatureMap<Y1> {
    fn push(&mut self, feature: IndexedFeature<Y1>) {
        if self.is_empty() {
            self.index.push(feature.mz);
            self.features.push(feature);
        } else {
            let is_tail =
                self.features.last().as_ref().unwrap().coordinate() <= feature.coordinate();
            self.features.push(feature);
            if !is_tail {
                self.sort();
            }
        }
    }

    fn sort(&mut self) {
        <FeatureMap<MZ, Y1, IndexedFeature<Y1>> as FeatureMapLikeMut<MZ, Y1, IndexedFeature<Y1>>>::sort(&mut self.features);
        self.build_index();
    }
}

impl<Y1> FeatureMapLike<MZ, Y1, IndexedFeature<Y1>> for IndexedFeatureMap<Y1> {
    fn search_by(&self, query: f64) -> Result<usize, usize> {
        self.index.binary_search_by(|b| b.total_cmp(&query))
    }

    fn len(&self) -> usize {
        <FeatureMap<MZ, Y1, IndexedFeature<Y1>> as FeatureMapLike<MZ, Y1, IndexedFeature<Y1>>>::len(
            &self.features,
        )
    }

    fn is_empty(&self) -> bool {
        <FeatureMap<MZ, Y1, IndexedFeature<Y1>> as FeatureMapLike<MZ, Y1, IndexedFeature<Y1>>>::is_empty(&self.features)
    }

    fn get_item(&self, i: usize) -> &IndexedFeature<Y1> {
        <FeatureMap<MZ, Y1, IndexedFeature<Y1>> as FeatureMapLike<MZ, Y1, IndexedFeature<Y1>>>::get_item(&self.features, i)
    }

    unsafe fn get_item_unchecked(&self, i: usize) -> &IndexedFeature<Y1> {
        <FeatureMap<MZ, Y1, IndexedFeature<Y1>> as FeatureMapLike<MZ, Y1, IndexedFeature<Y1>>>::get_item_unchecked(&self.features, i)
    }

    fn get_slice(&self, i: std::ops::Range<usize>) -> &[IndexedFeature<Y1>] {
        <FeatureMap<MZ, Y1, IndexedFeature<Y1>> as FeatureMapLike<MZ, Y1, IndexedFeature<Y1>>>::get_slice(&self.features, i)
    }

    fn iter<'a>(&'a self) -> impl Iterator<Item = &'a IndexedFeature<Y1>>
    where
        IndexedFeature<Y1>: 'a,
    {
        <FeatureMap<MZ, Y1, IndexedFeature<Y1>> as FeatureMapLike<MZ, Y1, IndexedFeature<Y1>>>::iter(
            &self.features,
        )
    }
}

pub struct FeatureIter<Y> {
    source: std::vec::IntoIter<IndexedFeature<Y>>,
}

impl<Y> Iterator for FeatureIter<Y> {
    type Item = Feature<MZ, Y>;

    fn next(&mut self) -> Option<Self::Item> {
        self.source.next().map(|f| f.feature)
    }
}

impl<Y> IntoIterator for IndexedFeatureMap<Y> {
    type Item = Feature<MZ, Y>;

    type IntoIter = FeatureIter<Y>;

    fn into_iter(self) -> Self::IntoIter {
        Self::IntoIter {
            source: self.features.into_iter(),
        }
    }
}