1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! SAM record data field value and types.

mod array;
pub mod base_modifications;

pub use self::base_modifications::BaseModifications;

use std::io;

use bstr::{BStr, ByteSlice};

use self::array::parse_array;
use super::Type;
use crate::alignment::record::data::field::Value;

pub(super) fn parse_value<'a>(src: &mut &'a [u8], ty: Type) -> io::Result<Value<'a>> {
    match ty {
        Type::Character => parse_character_value(src),
        Type::Int32 => parse_int32_value(src),
        Type::Float => parse_float_value(src),
        Type::String => Ok(parse_string_value(src)),
        Type::Hex => Ok(parse_hex_value(src)),
        Type::Array => parse_array(src).map(Value::Array),
    }
}

fn parse_character_value<'a>(src: &mut &'a [u8]) -> io::Result<Value<'a>> {
    if let Some((b, rest)) = src.split_first() {
        *src = rest;
        Ok(Value::Character(*b))
    } else {
        Err(io::Error::from(io::ErrorKind::UnexpectedEof))
    }
}

fn parse_int32_value<'a>(src: &mut &'a [u8]) -> io::Result<Value<'a>> {
    let (n, i) = lexical_core::parse_partial(src)
        .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;

    *src = &src[i..];

    Ok(Value::Int32(n))
}

fn parse_float_value<'a>(src: &mut &'a [u8]) -> io::Result<Value<'a>> {
    let (n, i) = lexical_core::parse_partial(src)
        .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;

    *src = &src[i..];

    Ok(Value::Float(n))
}

fn parse_string<'a>(src: &mut &'a [u8]) -> &'a BStr {
    const DELIMITER: u8 = b'\t';

    let i = src.as_bstr().find_byte(DELIMITER).unwrap_or(src.len());
    let (buf, rest) = src.split_at(i);
    *src = rest;
    buf.as_bstr()
}

fn parse_string_value<'a>(src: &mut &'a [u8]) -> Value<'a> {
    Value::String(parse_string(src))
}

fn parse_hex_value<'a>(src: &mut &'a [u8]) -> Value<'a> {
    Value::Hex(parse_string(src))
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::alignment::record::data::field::value::Array;

    #[test]
    fn test_parse_value() -> io::Result<()> {
        let mut src = &b"n"[..];
        assert!(matches!(
            parse_value(&mut src, Type::Character)?,
            Value::Character(b'n')
        ));

        let mut src = &b"0"[..];
        assert!(matches!(
            parse_value(&mut src, Type::Int32)?,
            Value::Int32(0)
        ));

        let mut src = &b"0.0"[..];
        assert!(matches!(
            parse_value(&mut src, Type::Float)?,
            Value::Float(n) if n == 0.0
        ));

        let mut src = &b"ndls"[..];
        assert!(matches!(
            parse_value(&mut src, Type::String)?,
            Value::String(s) if s == "ndls"
        ));

        let mut src = &b"CAFE"[..];
        assert!(matches!(
            parse_value(&mut src, Type::Hex)?,
            Value::Hex(s) if s == "CAFE"
        ));

        let mut src = &b"C,0"[..];
        if let Value::Array(Array::UInt8(values)) = parse_value(&mut src, Type::Array)? {
            let actual: Vec<_> = values.iter().collect::<Result<_, _>>()?;
            assert_eq!(actual, [0]);
        } else {
            panic!();
        }

        Ok(())
    }
}