feophantlib/processor/
startup_parser.rs

1use nom::{
2    bytes::complete::{is_not, tag},
3    combinator::{map, map_res},
4    multi::many_till,
5    sequence::pair,
6    sequence::terminated,
7    IResult,
8};
9
10use std::collections::HashMap;
11
12pub fn parse_startup(
13    input: &[u8],
14) -> Result<HashMap<String, String>, nom::Err<nom::error::Error<&[u8]>>> {
15    let (input, _) = tag(b"\0\x03\0\0")(input)?; //Version but don't care
16    let (_, items) = parse_key_and_values(input)?;
17
18    let mut result: HashMap<String, String> = HashMap::new();
19
20    for (k, v) in items {
21        result.insert(k, v);
22    }
23
24    Ok(result)
25}
26
27fn parse_key_and_values(input: &[u8]) -> IResult<&[u8], Vec<(String, String)>> {
28    map(
29        many_till(pair(till_null, till_null), tag(b"\0")),
30        |(k, _)| k,
31    )(input)
32}
33
34fn till_null(input: &[u8]) -> IResult<&[u8], String> {
35    map_res(terminated(is_not("\0"), tag(b"\0")), |s: &[u8]| {
36        String::from_utf8(s.to_vec())
37    })(input)
38}
39
40#[cfg(test)]
41mod tests {
42    // Note this useful idiom: importing names from outer (for mod tests) scope.
43    use super::*;
44
45    #[test]
46    fn test_till_null() {
47        let test_string = b"user\0";
48
49        let (remaining, result) = till_null(test_string).unwrap();
50
51        assert_eq!("user", result);
52        assert_eq!(b"", remaining);
53    }
54
55    #[test]
56    fn test_parse_key_and_values() {
57        let test_string = b"user\0user2\0\0";
58
59        let correct = vec![("user".to_string(), "user2".to_string())];
60
61        let (remaining, result) = parse_key_and_values(test_string).unwrap();
62
63        assert_eq!(correct, result);
64        assert_eq!(b"", remaining);
65    }
66
67    #[test]
68    #[should_panic]
69    fn test_invalid_utf8_till_null() {
70        let test_string = b"\xc3\x28\0";
71
72        till_null(test_string).unwrap();
73    }
74
75    #[test]
76    fn test_start_up_string() {
77        let startup_mesg = b"\0\x03\0\0user\0some_user\0user2\0some_user\0\0";
78
79        let mut map: HashMap<String, String> = HashMap::new();
80        map.insert("user".to_string(), "some_user".to_string());
81        map.insert("user2".to_string(), "some_user".to_string());
82
83        let test_map = parse_startup(startup_mesg);
84
85        assert_eq!(map, test_map.unwrap());
86    }
87}