noodles_sam/record/data/field/
value.rs

1//! SAM record data field value and types.
2
3mod array;
4pub mod base_modifications;
5mod integer;
6
7pub use self::base_modifications::BaseModifications;
8
9use std::io;
10
11use bstr::{BStr, ByteSlice};
12
13use self::{array::parse_array, integer::parse_integer_value};
14use super::Type;
15use crate::alignment::record::data::field::Value;
16
17pub(super) fn parse_value<'a>(src: &mut &'a [u8], ty: Type) -> io::Result<Value<'a>> {
18    match ty {
19        Type::Character => parse_character_value(src),
20        Type::Integer => parse_integer_value(src),
21        Type::Float => parse_float_value(src),
22        Type::String => Ok(parse_string_value(src)),
23        Type::Hex => Ok(parse_hex_value(src)),
24        Type::Array => parse_array(src).map(Value::Array),
25    }
26}
27
28fn parse_character_value<'a>(src: &mut &'a [u8]) -> io::Result<Value<'a>> {
29    if let Some((b, rest)) = src.split_first() {
30        *src = rest;
31        Ok(Value::Character(*b))
32    } else {
33        Err(io::Error::from(io::ErrorKind::UnexpectedEof))
34    }
35}
36
37fn parse_float_value<'a>(src: &mut &'a [u8]) -> io::Result<Value<'a>> {
38    let (n, i) = lexical_core::parse_partial(src)
39        .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
40
41    *src = &src[i..];
42
43    Ok(Value::Float(n))
44}
45
46fn parse_string<'a>(src: &mut &'a [u8]) -> &'a BStr {
47    const DELIMITER: u8 = b'\t';
48
49    let i = src.as_bstr().find_byte(DELIMITER).unwrap_or(src.len());
50    let (buf, rest) = src.split_at(i);
51    *src = rest;
52    buf.as_bstr()
53}
54
55fn parse_string_value<'a>(src: &mut &'a [u8]) -> Value<'a> {
56    Value::String(parse_string(src))
57}
58
59fn parse_hex_value<'a>(src: &mut &'a [u8]) -> Value<'a> {
60    Value::Hex(parse_string(src))
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn test_parse_value() -> io::Result<()> {
69        let mut src = &b"n"[..];
70        assert!(matches!(
71            parse_value(&mut src, Type::Character)?,
72            Value::Character(b'n')
73        ));
74
75        let mut src = &b"0"[..];
76        assert!(matches!(
77            parse_value(&mut src, Type::Integer)?,
78            Value::Int32(0)
79        ));
80
81        let mut src = &b"0.0"[..];
82        assert!(matches!(
83            parse_value(&mut src, Type::Float)?,
84            Value::Float(n) if n == 0.0
85        ));
86
87        let mut src = &b"ndls"[..];
88        assert!(matches!(
89            parse_value(&mut src, Type::String)?,
90            Value::String(s) if s == "ndls"
91        ));
92
93        let mut src = &b"CAFE"[..];
94        assert!(matches!(
95            parse_value(&mut src, Type::Hex)?,
96            Value::Hex(s) if s == "CAFE"
97        ));
98
99        let mut src = &b"C,0"[..];
100        assert!(matches!(
101            parse_value(&mut src, Type::Array)?,
102            Value::Array(_)
103        ));
104
105        Ok(())
106    }
107}