1use nom::branch::alt;
4use nom::multi::many_m_n;
5use nom::{bytes::streaming::tag, IResult};
6
7use crate::utils::{parse_bytes_with_length, parse_integer_with_prefix, parse_str_with_prefix};
8
9#[derive(Debug, PartialEq)]
11pub enum Resp2Type<'a> {
12 String(&'a str),
13 Error(&'a str),
14 Integer(usize),
15 BulkString(&'a [u8]),
16 Null,
17 Array(Vec<Resp2Type<'a>>),
18}
19
20fn parse_simple_string(input: &[u8]) -> IResult<&[u8], Resp2Type> {
21 let (input, string) = parse_str_with_prefix(input, '+')?;
22
23 Ok((input, Resp2Type::String(string)))
24}
25
26fn parse_error(input: &[u8]) -> IResult<&[u8], Resp2Type> {
27 let (input, string) = parse_str_with_prefix(input, '-')?;
28
29 Ok((input, Resp2Type::Error(string)))
30}
31
32fn parse_integer(input: &[u8]) -> IResult<&[u8], Resp2Type> {
33 let (input, int) = parse_integer_with_prefix(input, ':')?;
34
35 Ok((input, Resp2Type::Integer(int)))
36}
37
38fn parse_bulk_string(input: &[u8]) -> IResult<&[u8], Resp2Type> {
39 let (input, length) = parse_integer_with_prefix(input, '$')?;
40 let (input, bytes) = parse_bytes_with_length(input, length)?;
41
42 Ok((input, Resp2Type::BulkString(bytes)))
43}
44
45fn parse_null_string(input: &[u8]) -> IResult<&[u8], Resp2Type> {
46 let (input, _) = tag("$-1\r\n")(input)?;
47
48 Ok((input, Resp2Type::Null))
49}
50
51fn parse_array(input: &[u8]) -> IResult<&[u8], Resp2Type> {
52 let (input, length) = parse_integer_with_prefix(input, '*')?;
53 let (input, result) = many_m_n(length, length, parse)(input)?;
54
55 Ok((input, Resp2Type::Array(result)))
56}
57
58pub fn parse(input: &[u8]) -> IResult<&[u8], Resp2Type> {
60 alt((
61 parse_simple_string,
62 parse_error,
63 parse_integer,
64 parse_bulk_string,
65 parse_null_string,
66 parse_array,
67 ))(input)
68}
69
70#[cfg(test)]
71mod tests {
72 use crate::resp2::{parse, Resp2Type};
73
74 #[test]
75 fn test_parse_simple_string() {
76 assert_eq!(
77 parse(&b"+OK\r\n"[..]),
78 Ok((&b""[..], Resp2Type::String("OK")))
79 );
80 }
81
82 #[test]
83 fn test_parse_error() {
84 assert_eq!(
85 parse(&b"-Error message\r\n"[..]),
86 Ok((&b""[..], Resp2Type::Error("Error message")))
87 );
88 }
89
90 #[test]
91 fn test_parse_integer() {
92 assert_eq!(
93 parse(&b":100\r\n"[..]),
94 Ok((&b""[..], Resp2Type::Integer(100)))
95 );
96 }
97
98 #[test]
99 fn test_parse_bulk_string() {
100 assert_eq!(
101 parse(&b"$10\r\n1234567890\r\n"[..]),
102 Ok((&b""[..], Resp2Type::BulkString(&b"1234567890"[..])))
103 );
104 }
105
106 #[test]
107 fn test_parse_null_string() {
108 assert_eq!(parse(&b"$-1\r\n"[..]), Ok((&b""[..], Resp2Type::Null)));
109 }
110
111 #[test]
112 fn test_parse_array_empty() {
113 assert_eq!(
114 parse(&b"*0\r\n"[..]),
115 Ok((&b""[..], Resp2Type::Array(vec![])))
116 );
117 }
118
119 #[test]
120 fn test_parse_array_mixed_objecs() {
121 assert_eq!(
122 parse(&b"*3\r\n:1\r\n:2\r\n$3\r\nfoo\r\n"[..]),
123 Ok((
124 &b""[..],
125 Resp2Type::Array(vec![
126 Resp2Type::Integer(1),
127 Resp2Type::Integer(2),
128 Resp2Type::BulkString(&b"foo"[..])
129 ])
130 ))
131 );
132 }
133}