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
use nom::{
bytes::streaming::tag,
bytes::streaming::{take_until, take_while},
character::{
is_alphanumeric,
streaming::{u16, u8},
},
combinator::map,
error::{context, ContextError, ParseError},
multi::length_data,
sequence::{delimited, separated_pair, terminated, tuple},
IResult,
};
pub use nom::Err;
pub fn generic_field<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
i: &'a [u8],
) -> IResult<&'a [u8], (u16, &[u8]), E> {
terminated(
separated_pair(u16, tag("="), take_until("\x01")),
tag("\x01"),
)(i)
}
fn begin_string<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
i: &'a [u8],
) -> IResult<&'a [u8], &[u8], E> {
context(
"begin_string",
delimited(tag("8="), take_until("\x01"), tag("\x01")),
)(i)
}
fn checksum<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
i: &'a [u8],
) -> IResult<&[u8], u8, E> {
context("checksum", delimited(tag("10="), u8, tag("\x01")))(i)
}
fn body_length<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
i: &'a [u8],
) -> IResult<&[u8], u16, E> {
delimited(tag("9="), u16, tag("\x01"))(i)
}
fn _message_type<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
i: &'a [u8],
) -> IResult<&[u8], &[u8], E> {
context(
"message_type",
delimited(tag("35="), take_while(is_alphanumeric), tag("\x01")),
)(i)
}
#[derive(Debug)]
pub struct RawMessage<'a> {
pub begin_string: &'a [u8],
pub body: &'a [u8],
pub checksum: u8,
}
pub fn raw_message<'a>(i: &'a [u8]) -> IResult<&'a [u8], RawMessage<'a>> {
map(
tuple((begin_string, length_data(body_length), checksum)),
|(begin_string, body, checksum)| RawMessage {
begin_string,
body,
checksum,
},
)(i)
}
#[cfg(test)]
mod tests {
use super::raw_message;
use nom::Err::Incomplete;
#[test]
fn parse_complete_ok() {
let input = b"8=MSG_BODY\x019=19\x01<lots of tags here>10=015\x01";
assert!(raw_message(input).is_ok());
}
#[test]
fn parse_from_chunks_ok() {
let input = &[
b"8=MSG_BOD".as_slice(),
b"Y\x019=19\x01<lots".as_slice(),
b" of tags here>10=015\x01".as_slice(),
b"leftover".as_slice(),
];
let mut buf = Vec::new();
let mut i = input.iter();
{
buf.extend_from_slice(i.next().unwrap());
assert!(matches!(raw_message(&buf), Err(Incomplete(_))));
}
{
buf.extend_from_slice(i.next().unwrap());
assert!(matches!(raw_message(&buf), Err(Incomplete(_))));
}
{
buf.extend_from_slice(i.next().unwrap());
assert!(matches!(raw_message(&buf), Ok(([], _))));
}
{
buf.extend_from_slice(i.next().unwrap());
assert!(matches!(raw_message(&buf), Ok((b"leftover", _))));
}
}
}