1use std::{borrow::Cow, str::from_utf8};
2
3use nom::{
4 branch::alt,
5 bytes::streaming::take,
6 character::streaming::{char, crlf, i64, not_line_ending},
7 combinator::{map, map_res},
8 error::ErrorKind,
9 sequence::{delimited, terminated},
10 IResult,
11};
12
13pub type Error<'a> = nom::Err<nom::error::Error<Cow<'a, [u8]>>>;
15pub(crate) type RawError<'a> = nom::Err<nom::error::Error<&'a [u8]>>;
16
17pub fn parse_str(data: &[u8]) -> IResult<&[u8], &str> {
19 map_res(delimited(char('+'), not_line_ending, crlf), from_utf8)(data)
20}
21
22pub fn parse_err(data: &[u8]) -> IResult<&[u8], &str> {
24 map_res(delimited(char('-'), not_line_ending, crlf), from_utf8)(data)
25}
26
27pub fn parse_int(data: &[u8]) -> IResult<&[u8], i64> {
29 delimited(char(':'), i64, crlf)(data)
30}
31
32pub fn parse_bytes(data: &[u8]) -> IResult<&[u8], Option<&[u8]>> {
34 let (data, len) = delimited(char('$'), i64, crlf)(data)?;
35 Ok(match len {
36 -1 => (data, None),
37 0.. => map(terminated(take(len as usize), crlf), Some)(data)?,
38 _ => {
39 return Err(nom::Err::Failure(nom::error::Error::new(
40 data,
41 ErrorKind::Digit,
42 )))
43 }
44 })
45}
46
47pub fn parse_array(data: &[u8]) -> IResult<&[u8], i64> {
50 delimited(char('*'), i64, crlf)(data)
51}
52
53pub fn parse_str_loose(data: &[u8]) -> IResult<&[u8], &str> {
55 alt((
56 parse_str,
57 map_res(map(parse_bytes, Option::unwrap_or_default), from_utf8),
58 ))(data)
59}
60
61pub fn parse_int_loose(data: &[u8]) -> IResult<&[u8], i64> {
63 alt((parse_int, map_res(parse_str_loose, str::parse)))(data)
64}
65
66#[cfg(test)]
67mod test {
68 use super::*;
69
70 #[test]
71 fn test_parse_str() {
72 let resp = "+OK\r\n".as_bytes();
73 let (rem, res) = parse_str(resp).expect("Parsed string");
74
75 assert_eq!(0, rem.len());
76 assert_eq!("OK", res);
77 }
78
79 #[test]
80 fn test_parse_int() {
81 let resp = ":10\r\n".as_bytes();
82 let (rem, res) = parse_int(resp).expect("Parsed int");
83
84 assert_eq!(0, rem.len());
85 assert_eq!(10, res);
86 }
87
88 #[test]
89 fn test_parse_bytes() {
90 let resp = "$6\r\nfoobar\r\n".as_bytes();
91 let (rem, res) = parse_bytes(resp).expect("Parsed bytes");
92
93 assert_eq!(0, rem.len());
94 assert_eq!(Some("foobar".as_bytes()), res);
95 }
96
97 #[test]
98 fn test_parse_empty_bytes() {
99 let resp = "$0\r\n\r\n".as_bytes();
100 let (rem, res) = parse_bytes(resp).expect("Parsed bytes");
101
102 assert_eq!(0, rem.len());
103 assert_eq!(Some([].as_slice()), res);
104 }
105
106 #[test]
107 fn test_parse_null_bytes() {
108 let resp = "$-1\r\n".as_bytes();
109 let (rem, res) = parse_bytes(resp).expect("Parsed bytes");
110
111 assert_eq!(0, rem.len());
112 assert_eq!(None, res);
113 }
114
115 #[test]
116 fn test_parse_array() {
117 let resp = "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n".as_bytes();
118 let (rem, res) = parse_array(resp).expect("Parsed bytes");
119
120 assert_eq!(18, rem.len());
121 assert_eq!(2, res);
122 }
123
124 #[test]
125 fn test_parse_empty_array() {
126 let resp = "*0\r\n".as_bytes();
127 let (rem, res) = parse_array(resp).expect("Parsed bytes");
128
129 assert_eq!(0, rem.len());
130 assert_eq!(0, res);
131 }
132
133 #[test]
134 fn test_parse_null_array() {
135 let resp = "*-1\r\n".as_bytes();
136 let (rem, res) = parse_array(resp).expect("Parsed bytes");
137
138 assert_eq!(0, rem.len());
139 assert_eq!(-1, res);
140 }
141}