#[cfg(feature = "serialization")]
use serde::Serialize;
#[cfg_attr(feature = "serde", derive(Serialize))]
#[derive(PartialEq, PartialOrd, Clone, Default)]
pub struct Protein {
pub accession: String,
pub description: String,
pub spectral_count: u16,
pub sequence_count: u16,
pub sequence_coverage: f32,
pub molecular_weight: u32,
pub peptides: Vec<Peptide>,
pub channels: u8,
}
impl Protein {
pub fn total(&self) -> Vec<u32> {
let mut v = Vec::with_capacity(self.channels as usize);
for c in 0..self.channels {
let sum = self.peptides.iter().map(|pep| pep.values[c as usize]).sum();
v.push(sum);
}
v
}
pub fn ratios(&self) -> Vec<f64> {
let values = self.total();
let total = values.iter().sum::<u32>() as f64;
values.iter().map(|v| *v as f64 / total).collect()
}
}
#[cfg_attr(feature = "serde", derive(Serialize))]
#[derive(PartialEq, PartialOrd, Clone, Debug, Default)]
pub struct Peptide {
pub sequence: String,
pub values: Vec<u32>,
pub unique: bool,
pub purity: f32,
pub scan: usize,
}
impl Peptide {
pub fn tryptic(&self) -> bool {
let cterm = self.sequence.ends_with('-');
let front = self.sequence.starts_with(|c| match c {
'K' | 'R' | '-' => true,
_ => false,
});
let end = self
.sequence
.split('.')
.skip(1)
.next()
.map(|s| {
s.ends_with(|c| match c {
'K' | 'R' => true,
_ => cterm,
})
})
.unwrap_or(false);
front && end
}
pub fn ratios(&self) -> Vec<f64> {
let total: f64 = self.values.iter().sum::<u32>() as f64;
self.values.iter().map(|v| *v as f64 / total).collect()
}
pub fn swap_channels(&mut self, a: usize, b: usize) {
self.values.swap(a, b)
}
}
#[cfg(test)]
mod test {
use super::*;
fn gen_peptide(sequence: &str) -> Peptide {
Peptide {
sequence: sequence.into(),
..Peptide::default()
}
}
#[test]
fn test_trypic() {
assert!(gen_peptide("-.KMDKDK.-").tryptic());
assert!(!gen_peptide("S.KMDKDK.-").tryptic());
assert!(gen_peptide("R.TLDGFK*K.F").tryptic());
assert!(!gen_peptide("K.KMDKDT.A").tryptic());
}
}