noodles_vcf/header/parser/
record.rs1mod key;
2mod value;
3
4use std::{error, fmt};
5
6use self::{key::parse_key, value::parse_value};
7use crate::header::{FileFormat, Record};
8
9#[derive(Clone, Debug, Eq, PartialEq)]
11pub enum ParseError {
12 MissingPrefix,
14 InvalidKey(key::ParseError),
16 InvalidValue(value::ParseError),
18}
19
20impl error::Error for ParseError {
21 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
22 match self {
23 Self::MissingPrefix => None,
24 Self::InvalidKey(e) => Some(e),
25 Self::InvalidValue(e) => Some(e),
26 }
27 }
28}
29
30impl fmt::Display for ParseError {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 match self {
33 Self::MissingPrefix => write!(f, "missing prefix"),
34 Self::InvalidKey(_) => write!(f, "invalid key"),
35 Self::InvalidValue(_) => write!(f, "invalid value"),
36 }
37 }
38}
39
40#[allow(missing_docs)]
41pub fn parse_record(mut src: &[u8], file_format: FileFormat) -> Result<Record, ParseError> {
42 consume_prefix(&mut src)?;
43 let key = parse_key(&mut src).map_err(ParseError::InvalidKey)?;
44 parse_value(&mut src, file_format, key).map_err(ParseError::InvalidValue)
45}
46
47fn consume_prefix(src: &mut &[u8]) -> Result<(), ParseError> {
48 const PREFIX: &[u8] = b"##";
49
50 if let Some(rest) = src.strip_prefix(PREFIX) {
51 *src = rest;
52 Ok(())
53 } else {
54 Err(ParseError::MissingPrefix)
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn test_consume_prefix() {
64 let mut src = &b"##fileformat"[..];
65 assert!(consume_prefix(&mut src).is_ok());
66 assert_eq!(src, b"fileformat");
67
68 let mut src = &b""[..];
69 assert_eq!(consume_prefix(&mut src), Err(ParseError::MissingPrefix));
70
71 let mut src = &b"#"[..];
72 assert_eq!(consume_prefix(&mut src), Err(ParseError::MissingPrefix));
73
74 let mut src = &b"@"[..];
75 assert_eq!(consume_prefix(&mut src), Err(ParseError::MissingPrefix));
76 }
77}