use super::*;
use std::fmt;
use std::iter::Peekable;
use std::str::Lines;
#[derive(PartialEq, PartialOrd, Debug)]
pub enum ErrorKind {
Invalid(char),
Conversion,
EOF,
}
#[derive(PartialEq, PartialOrd, Debug)]
pub struct Error {
kind: ErrorKind,
line: usize,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Error parsing file at line {}: {:?}",
self.line, self.kind
)
}
}
impl std::error::Error for Error {}
pub struct Parser<'s> {
iter: Peekable<Lines<'s>>,
channels: u8,
line: usize,
}
impl<'s> Parser<'s> {
pub fn new(input: &'s str) -> Parser<'s> {
Parser {
iter: input.lines().peekable(),
channels: 0,
line: 1,
}
}
fn err(&self, kind: ErrorKind) -> Error {
Error {
kind,
line: self.line,
}
}
fn peek(&mut self) -> Option<&&'s str> {
self.iter.peek()
}
fn next(&mut self) -> Option<&'s str> {
let n = self.iter.next();
if n.is_some() {
self.line += 1;
}
n
}
fn parse_peptide(&mut self) -> Result<Peptide, Error> {
let line = self.iter.next().ok_or_else(|| self.err(ErrorKind::EOF))?;
let mut data = line.split('\t');
assert_eq!(data.next(), Some("S"));
let n = data.next().ok_or_else(|| self.err(ErrorKind::EOF))?;
assert!(n.len() <= 1);
let unique: bool = n == "U";
let sequence = data.next().ok_or_else(|| self.err(ErrorKind::EOF))?.into();
let mut values = Vec::with_capacity(self.channels as usize);
for _ in 0..self.channels {
let mz = data
.next()
.ok_or_else(|| self.err(ErrorKind::EOF))?
.parse::<u32>()
.map_err(|_| self.err(ErrorKind::Conversion))?;
let _ = data.next().ok_or_else(|| self.err(ErrorKind::EOF))?;
values.push(mz);
}
let _ = data.next();
let purity = data.next().unwrap_or("1.0").parse::<f32>().unwrap_or(1.0);
let scan = data
.skip(3)
.next()
.unwrap_or("")
.parse::<usize>()
.unwrap_or(0);
Ok(Peptide {
sequence,
unique,
values,
scan,
purity,
})
}
fn parse_protein(&mut self) -> Result<Protein, Error> {
let line = self.iter.next().ok_or_else(|| self.err(ErrorKind::EOF))?;
let mut data = line.split('\t');
assert_eq!(data.next(), Some("P"));
let accession = data.next().ok_or_else(|| self.err(ErrorKind::EOF))?.into();
let spectral_count = data
.next()
.ok_or_else(|| self.err(ErrorKind::EOF))?
.parse::<u16>()
.map_err(|_| self.err(ErrorKind::Conversion))?;
let sequence_count = data
.next()
.ok_or_else(|| self.err(ErrorKind::EOF))?
.parse::<u16>()
.map_err(|_| self.err(ErrorKind::Conversion))?;
let sequence_coverage = data
.next()
.ok_or_else(|| self.err(ErrorKind::EOF))?
.trim_end_matches('%')
.parse::<f32>()
.map_err(|_| self.err(ErrorKind::Conversion))?;
let molecular_weight = data
.next()
.ok_or_else(|| self.err(ErrorKind::EOF))?
.parse::<u32>()
.map_err(|_| self.err(ErrorKind::Conversion))?;
let description = data.last().ok_or_else(|| self.err(ErrorKind::EOF))?.into();
let mut peptides = Vec::new();
while let Some(next) = self.iter.peek() {
if next.starts_with('S') {
peptides.push(self.parse_peptide()?);
} else {
break;
}
}
Ok(Protein {
accession,
spectral_count,
sequence_count,
sequence_coverage,
molecular_weight,
description,
peptides,
channels: self.channels,
})
}
fn parse_headers(&mut self) -> Option<()> {
while let Some(line) = self.peek() {
if line.starts_with('H') {
let line = self.next()?;
if line.contains("m/z") {
self.channels = (line.matches("m/z_").count() / 2) as u8;
}
} else {
return Some(());
}
}
None
}
pub fn parse(mut self) -> Result<Dataset, Error> {
let mut data = Vec::new();
while let Some(line) = self.peek() {
let init = line
.chars()
.next()
.ok_or_else(|| self.err(ErrorKind::EOF))?;
match init {
'H' => self
.parse_headers()
.ok_or_else(|| self.err(ErrorKind::EOF))?,
'P' => data.push(self.parse_protein()?),
_ => return Err(self.err(ErrorKind::Invalid(init))),
}
}
Ok(Dataset {
proteins: data,
channels: self.channels,
})
}
}