mod tag;
mod ty;
pub mod value;
use std::{error, fmt};
use self::{tag::parse_tag, ty::parse_type, value::parse_value};
use crate::alignment::{record::data::field::Tag, record_buf::data::field::Value};
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ParseError {
UnexpectedEof,
ExpectedDelimiter,
InvalidTag(tag::ParseError),
InvalidType(Tag, ty::ParseError),
InvalidValue(Tag, value::ParseError),
}
impl ParseError {
pub fn tag(&self) -> Option<Tag> {
match self {
Self::InvalidType(tag, _) => Some(*tag),
Self::InvalidValue(tag, _) => Some(*tag),
_ => None,
}
}
}
impl error::Error for ParseError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
ParseError::InvalidTag(e) => Some(e),
ParseError::InvalidType(_, e) => Some(e),
ParseError::InvalidValue(_, e) => Some(e),
_ => None,
}
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ParseError::UnexpectedEof => write!(f, "unexpected EOF"),
ParseError::ExpectedDelimiter => write!(f, "expected delimiter"),
ParseError::InvalidTag(_) => write!(f, "invalid tag"),
ParseError::InvalidType(..) => write!(f, "invalid type"),
ParseError::InvalidValue(..) => write!(f, "invalid value"),
}
}
}
pub(super) fn parse_field(src: &mut &[u8]) -> Result<(Tag, Value), ParseError> {
use crate::io::reader::record_buf::next_field;
let mut buf = next_field(src);
let tag = parse_tag(&mut buf).map_err(ParseError::InvalidTag)?;
consume_delimiter(&mut buf)?;
let ty = parse_type(&mut buf).map_err(|e| ParseError::InvalidType(tag, e))?;
consume_delimiter(&mut buf)?;
let value = parse_value(&mut buf, ty).map_err(|e| ParseError::InvalidValue(tag, e))?;
Ok((tag, value))
}
fn consume_delimiter(src: &mut &[u8]) -> Result<(), ParseError> {
const DELIMITER: u8 = b':';
let (n, rest) = src.split_first().ok_or(ParseError::UnexpectedEof)?;
*src = rest;
if *n == DELIMITER {
Ok(())
} else {
Err(ParseError::ExpectedDelimiter)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_field() {
let mut src = &b"NH:i:1\tCO:Z:ndls"[..];
assert_eq!(
parse_field(&mut src),
Ok((Tag::ALIGNMENT_HIT_COUNT, Value::from(1)))
);
assert_eq!(
parse_field(&mut src),
Ok((Tag::COMMENT, Value::from("ndls")))
);
assert!(src.is_empty());
}
}