noodles_sam/record/data/
field.rs1mod tag;
4mod ty;
5pub mod value;
6
7use std::io;
8
9use self::ty::Type;
10use self::{tag::parse_tag, ty::parse_type, value::parse_value};
11use crate::alignment::record::data::field::{Tag, Value};
12
13pub(super) fn parse_field<'a>(src: &mut &'a [u8]) -> io::Result<(Tag, Value<'a>)> {
14 let tag = parse_tag(src)?;
15 consume_delimiter(src)?;
16 let ty = parse_type(src)?;
17 consume_delimiter(src)?;
18 let value = parse_value(src, ty)?;
19 maybe_consume_terminator(src)?;
20
21 Ok((tag, value))
22}
23
24fn consume_delimiter(src: &mut &[u8]) -> io::Result<()> {
25 const DELIMITER: u8 = b':';
26
27 if let Some((b, rest)) = src.split_first() {
28 if *b == DELIMITER {
29 *src = rest;
30 Ok(())
31 } else {
32 Err(io::Error::new(
33 io::ErrorKind::InvalidData,
34 "invalid delimiter",
35 ))
36 }
37 } else {
38 Err(io::Error::from(io::ErrorKind::UnexpectedEof))
39 }
40}
41
42fn maybe_consume_terminator(src: &mut &[u8]) -> io::Result<()> {
43 const TERMINATOR: u8 = b'\t';
44
45 if let Some((b, rest)) = src.split_first() {
46 if *b == TERMINATOR {
47 *src = rest;
48 } else {
49 return Err(io::Error::new(
50 io::ErrorKind::InvalidData,
51 "invalid field terminator",
52 ));
53 }
54 }
55
56 Ok(())
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn test_parse_field() -> io::Result<()> {
65 let mut src = &b"NH:i:1"[..];
66 assert!(matches!(
67 parse_field(&mut src)?,
68 (Tag::ALIGNMENT_HIT_COUNT, Value::Int32(1))
69 ));
70
71 let mut src = &b"NH:i:1\t"[..];
72 assert!(matches!(
73 parse_field(&mut src)?,
74 (Tag::ALIGNMENT_HIT_COUNT, Value::Int32(1))
75 ));
76
77 let mut src = &b""[..];
78 assert!(matches!(
79 parse_field(&mut src),
80 Err(e) if e.kind() == io::ErrorKind::UnexpectedEof
81 ));
82
83 let mut src = &b"NH_i:1"[..];
84 assert!(matches!(
85 parse_field(&mut src),
86 Err(e) if e.kind() == io::ErrorKind::InvalidData
87 ));
88
89 let mut src = &b"NH:i_1"[..];
90 assert!(matches!(
91 parse_field(&mut src),
92 Err(e) if e.kind() == io::ErrorKind::InvalidData
93 ));
94
95 let mut src = &b"NH:i:1\n"[..];
96 assert!(matches!(
97 parse_field(&mut src),
98 Err(e) if e.kind() == io::ErrorKind::InvalidData
99 ));
100
101 Ok(())
102 }
103}