use log::warn;
use std::collections::{HashMap, VecDeque};
use std::fs;
use std::io;
use std::marker::PhantomData;
use std::ops::Index;
use std::path::{self, PathBuf};
use std::sync::mpsc::Receiver;
use thiserror::Error;
use mzpeaks::{CentroidLike, CentroidPeak, DeconvolutedCentroidLike, DeconvolutedPeak};
use crate::meta::{
DataProcessing, FileDescription, InstrumentConfiguration, MassSpectrometryRun, Software,
};
use crate::prelude::MSDataFileMetadata;
use crate::spectrum::group::{SpectrumGroup, SpectrumGroupingIterator};
use crate::spectrum::spectrum_types::{MultiLayerSpectrum, SpectrumLike};
use super::utils::FileSource;
use super::OffsetIndex;
pub trait SeekRead: io::Read + io::Seek {}
impl<T: io::Read + io::Seek> SeekRead for T {}
pub trait SpectrumSource<
C: CentroidLike + Default = CentroidPeak,
D: DeconvolutedCentroidLike + Default = DeconvolutedPeak,
S: SpectrumLike<C, D> = MultiLayerSpectrum<C, D>,
>: Iterator<Item = S>
{
fn reset(&mut self);
fn get_spectrum_by_id(&mut self, id: &str) -> Option<S>;
fn get_spectrum_by_index(&mut self, index: usize) -> Option<S>;
fn get_spectrum_by_time(&mut self, time: f64) -> Option<S> {
let n = self.len();
let mut lo: usize = 0;
let mut hi: usize = n;
let mut best_error: f64 = f64::INFINITY;
let mut best_match: Option<S> = None;
if lo == hi {
return None;
}
while hi != lo {
let mid = (hi + lo) / 2;
let scan = self.get_spectrum_by_index(mid)?;
let scan_time = scan.start_time();
let err = (scan_time - time).abs();
if err < best_error {
best_error = err;
best_match = Some(scan);
} else if (scan_time - time).abs() < 1e-3 {
return Some(scan);
} else if scan_time > time {
hi = mid;
} else {
lo = mid;
}
}
best_match
}
fn len(&self) -> usize {
self.get_index().len()
}
fn is_empty(&self) -> bool {
self.len() == 0
}
fn get_index(&self) -> &OffsetIndex;
fn set_index(&mut self, index: OffsetIndex);
fn _offset_of_id(&self, id: &str) -> Option<u64> {
self.get_index().get(id)
}
fn _offset_of_index(&self, index: usize) -> Option<u64> {
self.get_index()
.get_index(index)
.map(|(_id, offset)| offset)
}
fn _offset_of_time(&mut self, time: f64) -> Option<u64> {
match self.get_spectrum_by_time(time) {
Some(scan) => self._offset_of_index(scan.index()),
None => None,
}
}
fn iter(&mut self) -> SpectrumIterator<C, D, S, Self>
where
Self: Sized,
{
SpectrumIterator::new(self)
}
fn groups(&mut self) -> SpectrumGroupingIterator<SpectrumIterator<'_, C, D, S, Self>, C, D, S>
where
Self: Sized,
{
SpectrumGroupingIterator::new(self.iter())
}
fn into_groups(self) -> SpectrumGroupingIterator<Self, C, D, S>
where
Self: Sized,
{
SpectrumGroupingIterator::new(self)
}
}
pub struct SpectrumIterator<
'lifespan,
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D>,
R: SpectrumSource<C, D, S>,
> {
source: &'lifespan mut R,
spectrum_type: PhantomData<S>,
centroid_type: PhantomData<C>,
deconvoluted_type: PhantomData<D>,
index: usize,
back_index: usize,
}
impl<
'lifespan,
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
R: SpectrumSource<C, D, S>,
S: SpectrumLike<C, D>,
> SpectrumIterator<'lifespan, C, D, S, R>
{
pub fn new(source: &mut R) -> SpectrumIterator<C, D, S, R> {
SpectrumIterator::<C, D, S, R> {
source,
index: 0,
back_index: 0,
spectrum_type: PhantomData,
centroid_type: PhantomData,
deconvoluted_type: PhantomData,
}
}
}
impl<
'lifespan,
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
R: SpectrumSource<C, D, S>,
S: SpectrumLike<C, D>,
> Iterator for SpectrumIterator<'lifespan, C, D, S, R>
{
type Item = S;
fn next(&mut self) -> Option<Self::Item> {
if self.index + self.back_index >= self.len() {
return None;
}
let result = self.source.get_spectrum_by_index(self.index);
self.index += 1;
result
}
}
impl<
'lifespan,
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
R: SpectrumSource<C, D, S>,
S: SpectrumLike<C, D>,
> ExactSizeIterator for SpectrumIterator<'lifespan, C, D, S, R>
{
fn len(&self) -> usize {
self.source.len()
}
}
impl<
'lifespan,
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
R: SpectrumSource<C, D, S>,
S: SpectrumLike<C, D>,
> DoubleEndedIterator for SpectrumIterator<'lifespan, C, D, S, R>
{
fn next_back(&mut self) -> Option<Self::Item> {
if self.index + self.back_index >= self.len() {
return None;
};
let i = self.len() - (self.back_index + 1);
let result = self.source.get_spectrum_by_index(i);
self.back_index += 1;
result
}
}
impl<
'lifespan,
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D>,
R: SpectrumSource<C, D, S>,
> SpectrumSource<C, D, S> for SpectrumIterator<'lifespan, C, D, S, R>
{
fn reset(&mut self) {
self.index = 0;
self.back_index = 0;
}
fn get_spectrum_by_id(&mut self, id: &str) -> Option<S> {
self.source.get_spectrum_by_id(id)
}
fn get_spectrum_by_index(&mut self, index: usize) -> Option<S> {
self.source.get_spectrum_by_index(index)
}
fn get_spectrum_by_time(&mut self, time: f64) -> Option<S> {
self.source.get_spectrum_by_time(time)
}
fn get_index(&self) -> &OffsetIndex {
self.source.get_index()
}
fn set_index(&mut self, index: OffsetIndex) {
self.source.set_index(index);
}
}
impl<
'lifespan,
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
R: SpectrumSource<C, D, S>,
S: SpectrumLike<C, D>,
> MSDataFileMetadata for SpectrumIterator<'lifespan, C, D, S, R>
where
R: MSDataFileMetadata,
{
crate::delegate_impl_metadata_trait!(source);
}
pub trait MZFileReader<
C: CentroidLike + Default = CentroidPeak,
D: DeconvolutedCentroidLike + Default = DeconvolutedPeak,
S: SpectrumLike<C, D> = MultiLayerSpectrum<C, D>,
>: SpectrumSource<C, D, S> + Sized
{
fn construct_index_from_stream(&mut self) -> u64;
fn read_index(&mut self, reader: Box<dyn io::Read>) -> Result<&Self, serde_json::Error> {
match OffsetIndex::from_reader(reader) {
Ok(index) => {
self.set_index(index);
Ok(self)
}
Err(err) => Err(err),
}
}
fn write_index(&self, writer: Box<dyn io::Write>) -> Result<&Self, serde_json::Error> {
match self.get_index().to_writer(writer) {
Ok(_) => Ok(self),
Err(err) => Err(err),
}
}
fn open_path<P>(path: P) -> io::Result<Self>
where
P: Into<path::PathBuf> + Clone,
{
let source: FileSource<fs::File> = FileSource::from(path.clone());
let index_file_name = source.index_file_name();
match fs::File::open(path.into()) {
Ok(file) => {
let mut reader = Self::open_file(file)?;
if let Some(index_path) = &index_file_name {
if index_path.exists() {
let index_stream = fs::File::open(index_path)?;
match reader.read_index(Box::new(io::BufReader::new(index_stream))) {
Ok(_) => {}
Err(_err) => {
reader.construct_index_from_stream();
}
}
} else {
reader.construct_index_from_stream();
}
}
Ok(reader)
}
Err(err) => Err(err),
}
}
fn open_file(source: fs::File) -> io::Result<Self>;
}
fn _save_index<
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D>,
>(
index_path: &PathBuf,
reader: &impl MZFileReader<C, D, S>,
) -> io::Result<()> {
let index_stream = fs::File::create(index_path)?;
match reader.write_index(Box::new(io::BufWriter::new(index_stream))) {
Ok(_) => {}
Err(err) => {
warn!(
"Failed to write index to {} because {:?}",
index_path.display(),
err
);
}
}
Ok(())
}
#[derive(Debug, Error)]
pub enum SpectrumAccessError {
#[error("The requested spectrum was not found")]
SpectrumNotFound,
#[error("The requested spectrum native ID {0} was not found")]
SpectrumIdNotFound(String),
#[error("The requested spectrum index {0} was not found")]
SpectrumIndexNotFound(usize),
#[error("I/O error occurred while reading: {0:?}")]
IOError(#[source] Option<io::Error>),
}
impl From<SpectrumAccessError> for io::Error {
fn from(value: SpectrumAccessError) -> Self {
let s = value.to_string();
match value {
SpectrumAccessError::SpectrumNotFound => io::Error::new(io::ErrorKind::NotFound, s),
SpectrumAccessError::SpectrumIdNotFound(_) => {
io::Error::new(io::ErrorKind::NotFound, s)
}
SpectrumAccessError::SpectrumIndexNotFound(_) => {
io::Error::new(io::ErrorKind::NotFound, s)
}
SpectrumAccessError::IOError(e) => match e {
Some(e) => e,
None => io::Error::new(io::ErrorKind::Other, s),
},
}
}
}
pub trait RandomAccessSpectrumIterator<
C: CentroidLike + Default = CentroidPeak,
D: DeconvolutedCentroidLike + Default = DeconvolutedPeak,
S: SpectrumLike<C, D> = MultiLayerSpectrum<C, D>,
>: SpectrumSource<C, D, S>
{
fn start_from_id(&mut self, id: &str) -> Result<&mut Self, SpectrumAccessError>;
fn start_from_index(&mut self, index: usize) -> Result<&mut Self, SpectrumAccessError>;
fn start_from_time(&mut self, time: f64) -> Result<&mut Self, SpectrumAccessError>;
}
impl<
'lifespan,
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D>,
R: SpectrumSource<C, D, S>,
> RandomAccessSpectrumIterator<C, D, S> for SpectrumIterator<'lifespan, C, D, S, R>
{
fn start_from_id(&mut self, id: &str) -> Result<&mut Self, SpectrumAccessError> {
if let Some(scan) = self.get_spectrum_by_id(id) {
self.index = scan.index();
self.back_index = 0;
Ok(self)
} else if self.get_index().contains_key(id) {
Err(SpectrumAccessError::IOError(None))
} else {
Err(SpectrumAccessError::SpectrumIdNotFound(id.to_string()))
}
}
fn start_from_index(&mut self, index: usize) -> Result<&mut Self, SpectrumAccessError> {
if index < self.len() {
self.index = index;
self.back_index = 0;
Ok(self)
} else {
Err(SpectrumAccessError::SpectrumIndexNotFound(index))
}
}
fn start_from_time(&mut self, time: f64) -> Result<&mut Self, SpectrumAccessError> {
if let Some(scan) = self.get_spectrum_by_time(time) {
self.index = scan.index();
self.back_index = 0;
Ok(self)
} else if self
.get_spectrum_by_index(self.len() - 1)
.expect("Failed to fetch spectrum for boundary testing")
.start_time()
< time
{
Err(SpectrumAccessError::SpectrumNotFound)
} else {
Err(SpectrumAccessError::IOError(None))
}
}
}
pub trait RandomAccessSpectrumSource<
C: CentroidLike + Default = CentroidPeak,
D: DeconvolutedCentroidLike + Default = DeconvolutedPeak,
S: SpectrumLike<C, D> = MultiLayerSpectrum<C, D>,
>: SpectrumSource<C, D, S> + RandomAccessSpectrumIterator<C, D, S>
{
}
impl<
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D>,
T: SpectrumSource<C, D, S> + RandomAccessSpectrumIterator<C, D, S>,
> RandomAccessSpectrumSource<C, D, S> for T
{
}
pub trait SpectrumSourceWithMetadata<
C: CentroidLike + Default = CentroidPeak,
D: DeconvolutedCentroidLike + Default = DeconvolutedPeak,
S: SpectrumLike<C, D> = MultiLayerSpectrum<C, D>,
>: SpectrumSource<C, D, S> + MSDataFileMetadata {}
impl<
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D>,
T: SpectrumSource<C, D, S> + MSDataFileMetadata,
> SpectrumSourceWithMetadata<C, D, S> for T {}
pub struct StreamingSpectrumIterator<
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D>,
I: Iterator<Item = S>,
> {
source: I,
buffer: VecDeque<S>,
_index: OffsetIndex,
_c: PhantomData<C>,
_d: PhantomData<D>,
}
impl<
C: CentroidLike + Default + Send,
D: DeconvolutedCentroidLike + Default + Send,
S: SpectrumLike<C, D> + Send,
> From<SpectrumReceiver<C, D, S>>
for StreamingSpectrumIterator<C, D, S, SpectrumReceiver<C, D, S>>
{
fn from(value: SpectrumReceiver<C, D, S>) -> Self {
Self::new(value)
}
}
impl<
C: CentroidLike + Default + Send,
D: DeconvolutedCentroidLike + Default + Send,
S: SpectrumLike<C, D> + Send,
> From<Receiver<S>> for StreamingSpectrumIterator<C, D, S, SpectrumReceiver<C, D, S>>
{
fn from(value: Receiver<S>) -> Self {
Self::new(value.into())
}
}
impl<
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D>,
I: Iterator<Item = S>,
> SpectrumSource<C, D, S> for StreamingSpectrumIterator<C, D, S, I>
{
fn reset(&mut self) {
panic!("Cannot reset StreamingSpectrumIterator")
}
fn get_spectrum_by_id(&mut self, id: &str) -> Option<S> {
self.by_ref().iter().find(|s| s.id() == id)
}
fn get_spectrum_by_index(&mut self, index: usize) -> Option<S> {
self.by_ref().iter().find(|s| s.index() == index)
}
fn get_spectrum_by_time(&mut self, time: f64) -> Option<S> {
let mut placeholder: Option<S> = None;
let mut delta = f64::INFINITY;
while let Some(s) = self.next() {
let new_delta = (s.start_time() - time).abs();
if s.start_time() < time {
placeholder = Some(s);
delta = new_delta;
} else if s.start_time() >= time {
if new_delta < delta {
return Some(s);
} else {
self.push_front(s);
return placeholder;
}
}
}
None
}
fn get_index(&self) -> &OffsetIndex {
&self._index
}
fn set_index(&mut self, index: OffsetIndex) {
self._index = index
}
}
impl<
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D>,
I: Iterator<Item = S>,
> Iterator for StreamingSpectrumIterator<C, D, S, I>
{
type Item = S;
fn next(&mut self) -> Option<Self::Item> {
if !self.buffer.is_empty() {
self.buffer.pop_front()
} else {
self.source.next()
}
}
}
impl<
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D>,
I: Iterator<Item = S>,
> StreamingSpectrumIterator<C, D, S, I>
{
pub fn new(source: I) -> Self {
Self {
source,
buffer: VecDeque::new(),
_index: OffsetIndex::new("spectrum".to_string()),
_c: PhantomData,
_d: PhantomData,
}
}
fn push_front(&mut self, spectrum: S) {
self.buffer.push_front(spectrum);
}
}
impl<
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D>,
I: Iterator<Item = S>,
> RandomAccessSpectrumIterator<C, D, S> for StreamingSpectrumIterator<C, D, S, I>
{
fn start_from_id(&mut self, id: &str) -> Result<&mut Self, SpectrumAccessError> {
match self.get_spectrum_by_id(id) {
Some(s) => {
self.push_front(s);
Ok(self)
}
None => Err(SpectrumAccessError::SpectrumIdNotFound(id.to_string())),
}
}
fn start_from_index(&mut self, index: usize) -> Result<&mut Self, SpectrumAccessError> {
match self.get_spectrum_by_index(index) {
Some(s) => {
self.push_front(s);
Ok(self)
}
None => Err(SpectrumAccessError::SpectrumIndexNotFound(index)),
}
}
fn start_from_time(&mut self, time: f64) -> Result<&mut Self, SpectrumAccessError> {
match self.get_spectrum_by_time(time) {
Some(s) => {
self.push_front(s);
Ok(self)
}
None => Err(SpectrumAccessError::SpectrumNotFound),
}
}
}
impl<
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D>,
I: Iterator<Item = S>,
> MSDataFileMetadata for StreamingSpectrumIterator<C, D, S, I>
where
I: MSDataFileMetadata,
{
crate::delegate_impl_metadata_trait!(source);
}
pub struct SpectrumReceiver<
C: CentroidLike + Default + Send,
D: DeconvolutedCentroidLike + Default + Send,
S: SpectrumLike<C, D> + Send,
> {
receiver: Receiver<S>,
pub(crate) file_description: FileDescription,
pub(crate) instrument_configurations: HashMap<u32, InstrumentConfiguration>,
pub(crate) softwares: Vec<Software>,
pub(crate) data_processings: Vec<DataProcessing>,
pub(crate) run: MassSpectrometryRun,
num_spectra: Option<u64>,
_c: PhantomData<C>,
_d: PhantomData<D>,
}
impl<
C: CentroidLike + Default + Send,
D: DeconvolutedCentroidLike + Default + Send,
S: SpectrumLike<C, D> + Send,
> Iterator for SpectrumReceiver<C, D, S>
{
type Item = S;
fn next(&mut self) -> Option<Self::Item> {
match self.receiver.recv() {
Ok(s) => Some(s),
Err(e) => {
log::warn!("Failed to receive spectrum: {}", e);
None
}
}
}
}
impl<
C: CentroidLike + Default + Send,
D: DeconvolutedCentroidLike + Default + Send,
S: SpectrumLike<C, D> + Send,
> From<Receiver<S>> for SpectrumReceiver<C, D, S>
{
fn from(value: Receiver<S>) -> Self {
Self {
receiver: value,
file_description: Default::default(),
instrument_configurations: Default::default(),
softwares: Default::default(),
data_processings: Default::default(),
run: Default::default(),
num_spectra: Default::default(),
_c: PhantomData,
_d: PhantomData,
}
}
}
impl<
C: CentroidLike + Default + Send,
D: DeconvolutedCentroidLike + Default + Send,
S: SpectrumLike<C, D> + Send,
> MSDataFileMetadata for SpectrumReceiver<C, D, S>
{
crate::impl_metadata_trait!();
fn spectrum_count_hint(&self) -> Option<u64> {
self.num_spectra
}
fn run_description(&self) -> Option<&MassSpectrometryRun> {
Some(&self.run)
}
fn run_description_mut(&mut self) -> Option<&mut MassSpectrometryRun> {
Some(&mut self.run)
}
}
impl<
C: CentroidLike + Default + Send,
D: DeconvolutedCentroidLike + Default + Send,
S: SpectrumLike<C, D> + Send,
> SpectrumReceiver<C, D, S>
{
#[allow(unused)]
pub fn new(
receiver: Receiver<S>,
file_description: FileDescription,
instrument_configurations: HashMap<u32, InstrumentConfiguration>,
softwares: Vec<Software>,
data_processings: Vec<DataProcessing>,
run: MassSpectrometryRun,
num_spectra: Option<u64>,
) -> Self {
Self {
receiver,
file_description,
instrument_configurations,
softwares,
data_processings,
run,
num_spectra,
_c: PhantomData,
_d: PhantomData,
}
}
}
pub trait SpectrumGrouping<
C: CentroidLike + Default = CentroidPeak,
D: DeconvolutedCentroidLike + Default = DeconvolutedPeak,
S: SpectrumLike<C, D> = MultiLayerSpectrum<C, D>,
>: Default
{
fn precursor(&self) -> Option<&S>;
fn precursor_mut(&mut self) -> Option<&mut S>;
fn set_precursor(&mut self, prec: S);
fn products(&self) -> &[S];
fn products_mut(&mut self) -> &mut Vec<S>;
fn total_spectra(&self) -> usize {
self.precursor().is_some() as usize + self.products().len()
}
fn earliest_spectrum(&self) -> Option<&S> {
self.precursor().or_else(|| {
self.products().iter().min_by(|a, b| {
a.acquisition()
.start_time()
.total_cmp(&b.acquisition().start_time())
})
})
}
fn latest_spectrum(&self) -> Option<&S> {
self.precursor().or_else(|| {
self.products().iter().max_by(|a, b| {
a.acquisition()
.start_time()
.total_cmp(&b.acquisition().start_time())
})
})
}
fn lowest_ms_level(&self) -> Option<u8> {
let prec_level = self.precursor().map(|p| p.ms_level()).unwrap_or(u8::MAX);
let val = self
.products()
.iter()
.fold(prec_level, |state, s| state.min(s.ms_level()));
if val > 0 {
Some(val)
} else {
None
}
}
fn highest_ms_level(&self) -> Option<u8> {
let prec_level = self
.precursor()
.map(|p| p.ms_level())
.unwrap_or_else(|| u8::MIN);
let val = self
.products()
.iter()
.fold(prec_level, |state, s| state.max(s.ms_level()));
if val > 0 {
Some(val)
} else {
None
}
}
fn into_parts(self) -> (Option<S>, Vec<S>);
}
pub trait RandomAccessSpectrumGroupingIterator<
C: CentroidLike + Default = CentroidPeak,
D: DeconvolutedCentroidLike + Default = DeconvolutedPeak,
S: SpectrumLike<C, D> = MultiLayerSpectrum<C, D>,
G: SpectrumGrouping<C, D, S> = SpectrumGroup<C, D, S>,
>: Iterator<Item = G>
{
fn start_from_id(&mut self, id: &str) -> Result<&Self, SpectrumAccessError>;
fn start_from_index(&mut self, index: usize) -> Result<&Self, SpectrumAccessError>;
fn start_from_time(&mut self, time: f64) -> Result<&Self, SpectrumAccessError>;
fn reset_state(&mut self);
}
#[derive(Debug, Default)]
pub struct MemorySpectrumSource<
C: CentroidLike + Default = CentroidPeak,
D: DeconvolutedCentroidLike + Default = DeconvolutedPeak,
S: SpectrumLike<C, D> = MultiLayerSpectrum<C, D>,
> {
spectra: VecDeque<S>,
position: usize,
offsets: OffsetIndex,
_c: PhantomData<C>,
_d: PhantomData<D>,
}
impl<
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D> + Clone,
> MemorySpectrumSource<C, D, S>
{
pub fn new(spectra: VecDeque<S>) -> Self {
let mut offsets = OffsetIndex::new("spectrum".to_string());
spectra.iter().enumerate().for_each(|(i, s)| {
offsets.insert(s.id().to_string(), i as u64);
});
Self {
spectra,
position: 0,
offsets,
_c: PhantomData,
_d: PhantomData,
}
}
}
impl<
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D> + Clone,
> Iterator for MemorySpectrumSource<C, D, S>
{
type Item = S;
fn next(&mut self) -> Option<Self::Item> {
if self.position < self.spectra.len() {
let idx = self.position;
self.position += 1;
let value = self.spectra.index(idx);
Some(value.clone())
} else {
None
}
}
}
impl<
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D> + Clone,
> SpectrumSource<C, D, S> for MemorySpectrumSource<C, D, S>
{
fn reset(&mut self) {
self.position = 0;
}
fn get_spectrum_by_id(&mut self, id: &str) -> Option<S> {
self.offsets.get(id).map(|i| {
let value = &self.spectra[i as usize];
value.clone()
})
}
fn get_spectrum_by_index(&mut self, index: usize) -> Option<S> {
if index < self.len() {
Some(self.spectra.index(index).clone())
} else {
None
}
}
fn get_index(&self) -> &OffsetIndex {
&self.offsets
}
fn set_index(&mut self, index: OffsetIndex) {
self.offsets = index
}
}
impl<
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D> + Clone,
> RandomAccessSpectrumIterator<C, D, S> for MemorySpectrumSource<C, D, S>
{
fn start_from_id(&mut self, id: &str) -> Result<&mut Self, SpectrumAccessError> {
match self.offsets.get(id) {
Some(offset) => {
self.position = offset as usize;
Ok(self)
}
None => Err(SpectrumAccessError::SpectrumNotFound),
}
}
fn start_from_index(&mut self, id: usize) -> Result<&mut Self, SpectrumAccessError> {
match self.offsets.get_index(id) {
Some((_, offset)) => {
self.position = offset as usize;
Ok(self)
}
None => Err(SpectrumAccessError::SpectrumNotFound),
}
}
fn start_from_time(&mut self, time: f64) -> Result<&mut Self, SpectrumAccessError> {
if let Some(scan) = self.get_spectrum_by_time(time) {
self.position = scan.index();
Ok(self)
} else {
Err(SpectrumAccessError::SpectrumNotFound)
}
}
}
impl<
C: CentroidLike + Default,
D: DeconvolutedCentroidLike + Default,
S: SpectrumLike<C, D> + Clone,
> From<VecDeque<S>> for MemorySpectrumSource<C, D, S>
{
fn from(value: VecDeque<S>) -> Self {
Self::new(value)
}
}
pub trait SpectrumWriter<
C: CentroidLike + Default = CentroidPeak,
D: DeconvolutedCentroidLike + Default = DeconvolutedPeak,
>
{
fn write<S: SpectrumLike<C, D> + 'static>(&mut self, spectrum: &S) -> io::Result<usize>;
fn write_owned<S: SpectrumLike<C, D> + 'static>(&mut self, spectrum: S) -> io::Result<usize> {
self.write(&spectrum)
}
fn flush(&mut self) -> io::Result<()>;
fn write_all<'b, S: SpectrumLike<C, D> + 'static, T: Iterator<Item = &'b S>>(
&mut self,
iterator: T,
) -> io::Result<usize> {
let mut n = 0;
for spectrum in iterator {
n += self.write(spectrum)?;
}
Ok(n)
}
fn write_group<S: SpectrumLike<C, D> + 'static, G: SpectrumGrouping<C, D, S> + 'static>(
&mut self,
group: &G,
) -> io::Result<usize> {
let mut n = 0;
if let Some(precursor) = group.precursor() {
n += self.write(precursor)?;
}
for product in group.products() {
n += self.write(product)?;
}
Ok(n)
}
fn write_group_owned<
S: SpectrumLike<C, D> + 'static,
G: SpectrumGrouping<C, D, S> + 'static,
>(
&mut self,
group: G,
) -> io::Result<usize> {
let (precursor, products) = group.into_parts();
let mut n = 0;
if let Some(precursor) = precursor {
n += self.write_owned(precursor)?;
}
for product in products {
n += self.write_owned(product)?;
}
Ok(n)
}
fn write_all_groups<
'b,
S: SpectrumLike<C, D> + 'static,
G: SpectrumGrouping<C, D, S> + 'static,
T: Iterator<Item = &'b G>,
>(
&mut self,
iterator: T,
) -> io::Result<usize> {
let mut n = 0;
for group in iterator {
n += self.write_group(group)?;
}
Ok(n)
}
fn close(&mut self) -> io::Result<()>;
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_object_safe() {
let _f = |_x: &dyn SpectrumSource| {};
}
}