1use nom::IResult;
4use num_bigint::BigInt;
5
6use crate::utils::{
7 parse_bytes_with_length, parse_double_with_prefix, parse_integer_with_prefix,
8 parse_str_with_length, parse_str_with_prefix,
9};
10use nom::branch::alt;
11use nom::bytes::streaming::{tag, take};
12use nom::character::streaming::{char, crlf, digit1};
13use nom::combinator::map_res;
14use nom::lib::std::str::from_utf8;
15use nom::multi::many_m_n;
16use nom::sequence::{delimited, tuple};
17use std::str::FromStr;
18
19#[derive(Debug, PartialOrd, PartialEq)]
20pub enum VerbatimStringFormat {
21 Text,
22 Markdown,
23}
24
25#[derive(Debug, PartialEq)]
26pub enum Resp3Type<'a> {
27 Blob(&'a [u8]),
28 String(&'a str),
29 Error(&'a str),
30 Number(usize),
31 Null,
32 Double(f64),
33 Boolean(bool),
34 BlobError {
35 code: &'a str,
36 message: &'a str,
37 },
38 VerbatimString {
39 format: VerbatimStringFormat,
40 text: &'a str,
41 },
42 BigNumber(BigInt),
43
44 Array(Vec<Resp3Type<'a>>),
46
47 HashMap(usize),
48 Set(usize),
49 Attribute(usize),
50 Push(Vec<Resp3Type<'a>>),
51
52 StreamArray,
53 StreamSet,
54 StreamMap,
55 StreamEnd,
56}
57
58fn parse_blob_string(input: &[u8]) -> IResult<&[u8], Resp3Type> {
59 let (input, length) = parse_integer_with_prefix(input, '$')?;
60 let (input, blob) = parse_bytes_with_length(input, length)?;
61 Ok((input, Resp3Type::Blob(blob)))
62}
63
64fn parse_simple_string(input: &[u8]) -> IResult<&[u8], Resp3Type> {
65 let (input, str) = parse_str_with_prefix(input, '+')?;
66 Ok((input, Resp3Type::String(str)))
67}
68
69fn parse_error(input: &[u8]) -> IResult<&[u8], Resp3Type> {
70 let (input, str) = parse_str_with_prefix(input, '-')?;
71 Ok((input, Resp3Type::Error(str)))
72}
73
74fn parse_number(input: &[u8]) -> IResult<&[u8], Resp3Type> {
75 let (input, num) = parse_integer_with_prefix(input, ':')?;
76 Ok((input, Resp3Type::Number(num)))
77}
78
79fn parse_null(input: &[u8]) -> IResult<&[u8], Resp3Type> {
80 let (input, _) = tag("_\r\n")(input)?;
81 Ok((input, Resp3Type::Null))
82}
83
84fn parse_double(input: &[u8]) -> IResult<&[u8], Resp3Type> {
85 let (input, d) = parse_double_with_prefix(input, ',')?;
86 Ok((input, Resp3Type::Double(d)))
87}
88
89fn parse_boolean(input: &[u8]) -> IResult<&[u8], Resp3Type> {
90 let (input, b) = delimited(char('#'), alt((char('t'), char('f'))), crlf)(input)?;
91
92 let bool = match b {
93 't' => true,
94 'f' => false,
95 _ => unreachable!(),
96 };
97
98 Ok((input, Resp3Type::Boolean(bool)))
99}
100
101fn parse_blob_error(input: &[u8]) -> IResult<&[u8], Resp3Type> {
102 let (input, length) = parse_integer_with_prefix(input, '!')?;
103 let (input, blob) = parse_str_with_length(input, length)?;
104 let mut splitter = blob.splitn(2, ' ');
105 let code = splitter.next().unwrap();
106 let message = splitter.next().unwrap_or_else(|| "");
107 Ok((input, Resp3Type::BlobError { code, message }))
108}
109
110fn parse_verbatim_string(input: &[u8]) -> IResult<&[u8], Resp3Type> {
111 let (input, length) = parse_integer_with_prefix(input, '=')?;
112 let (_, bytes) = parse_bytes_with_length(input, length)?;
113 let (input, (format, text)) = map_res(
114 tuple((alt((tag("txt"), tag("mkd"))), char(':'), take(length - 4))),
115 |(tag, _, contents)| from_utf8(contents).map(|c| (tag, c)),
116 )(bytes)?;
117
118 let format = match format {
119 b"txt" => VerbatimStringFormat::Text,
120 b"mkd" => VerbatimStringFormat::Markdown,
121 _ => unreachable!(),
122 };
123
124 Ok((input, Resp3Type::VerbatimString { format, text }))
125}
126
127fn parse_big_number(input: &[u8]) -> IResult<&[u8], Resp3Type> {
128 let (input, num) = map_res(delimited(char('('), digit1, crlf), |out| {
129 num_bigint::BigInt::from_str(from_utf8(out).unwrap())
130 })(input)?;
131
132 Ok((input, Resp3Type::BigNumber(num)))
133}
134
135fn parse_array(input: &[u8]) -> IResult<&[u8], Resp3Type> {
136 let (input, length) = parse_integer_with_prefix(input, '*')?;
137 let (input, result) = many_m_n(length, length, parse)(input)?;
138
139 Ok((input, Resp3Type::Array(result)))
140}
141
142fn parse_map(input: &[u8]) -> IResult<&[u8], Resp3Type> {
143 let (input, length) = parse_integer_with_prefix(input, '%')?;
144 Ok((input, Resp3Type::HashMap(length)))
145}
146
147fn parse_set(input: &[u8]) -> IResult<&[u8], Resp3Type> {
148 let (input, length) = parse_integer_with_prefix(input, '~')?;
149 Ok((input, Resp3Type::Set(length)))
150}
151
152fn parse_attribute(input: &[u8]) -> IResult<&[u8], Resp3Type> {
153 let (input, length) = parse_integer_with_prefix(input, '|')?;
154 Ok((input, Resp3Type::Attribute(length)))
155}
156
157fn parse_push(input: &[u8]) -> IResult<&[u8], Resp3Type> {
158 let (input, length) = parse_integer_with_prefix(input, '>')?;
159 let (input, result) = many_m_n(length, length, parse)(input)?;
160
161 Ok((input, Resp3Type::Array(result)))
162}
163
164fn parse_stream_array(input: &[u8]) -> IResult<&[u8], Resp3Type> {
165 let (input, _) = tag("*?\r\n")(input)?;
166 Ok((input, Resp3Type::StreamArray))
167}
168
169fn parse_stream_set(input: &[u8]) -> IResult<&[u8], Resp3Type> {
170 let (input, _) = tag("~?\r\n")(input)?;
171 Ok((input, Resp3Type::StreamSet))
172}
173
174fn parse_stream_map(input: &[u8]) -> IResult<&[u8], Resp3Type> {
175 let (input, _) = tag("%?\r\n")(input)?;
176 Ok((input, Resp3Type::StreamMap))
177}
178
179fn parse_stream_end(input: &[u8]) -> IResult<&[u8], Resp3Type> {
180 let (input, _) = tag(".\r\n")(input)?;
181 Ok((input, Resp3Type::StreamEnd))
182}
183
184pub fn parse(input: &[u8]) -> IResult<&[u8], Resp3Type> {
186 alt((
187 parse_blob_string,
188 parse_simple_string,
189 parse_error,
190 parse_number,
191 parse_null,
192 parse_double,
193 parse_boolean,
194 parse_blob_error,
195 parse_verbatim_string,
196 parse_big_number,
197 parse_array,
198 parse_map,
199 parse_set,
200 parse_attribute,
201 parse_push,
202 parse_stream_array,
203 parse_stream_set,
204 parse_stream_map,
205 parse_stream_end,
206 ))(input)
207}
208
209#[cfg(test)]
210mod tests {
211 use crate::resp3::{parse, Resp3Type, VerbatimStringFormat};
212 use num_bigint::BigInt;
213 use std::str::FromStr;
214
215 #[test]
216 fn test_parse_blob_string() {
217 assert_eq!(
218 parse(&b"$5\r\n12345\r\n"[..]),
219 Ok((&b""[..], Resp3Type::Blob(&b"12345"[..])))
220 );
221 }
222
223 #[test]
224 fn test_parse_simple_string() {
225 assert_eq!(
226 parse(&b"+12345\r\n"[..]),
227 Ok((&b""[..], Resp3Type::String("12345")))
228 );
229 }
230
231 #[test]
232 fn test_parse_error() {
233 assert_eq!(
234 parse(&b"-ERROR 1234\r\n"[..]),
235 Ok((&b""[..], Resp3Type::Error("ERROR 1234")))
236 );
237 }
238
239 #[test]
240 fn test_parse_number() {
241 assert_eq!(
242 parse(&b":1234\r\n"[..]),
243 Ok((&b""[..], Resp3Type::Number(1234)))
244 );
245 }
246
247 #[test]
248 fn test_parse_null() {
249 assert_eq!(parse(&b"_\r\n"[..]), Ok((&b""[..], Resp3Type::Null)));
250 }
251
252 #[test]
253 fn test_parse_double() {
254 assert_eq!(
255 parse(&b",1.234\r\n"[..]),
256 Ok((&b""[..], Resp3Type::Double(1.234f64)))
257 );
258 }
259
260 #[test]
261 fn test_parse_boolean() {
262 assert_eq!(
263 parse(&b"#t\r\n"[..]),
264 Ok((&b""[..], Resp3Type::Boolean(true)))
265 );
266 assert_eq!(
267 parse(&b"#f\r\n"[..]),
268 Ok((&b""[..], Resp3Type::Boolean(false)))
269 );
270 }
271
272 #[test]
273 fn test_parse_blob_error() {
274 assert_eq!(
275 parse(&b"!10\r\nERROR 1234\r\n"[..]),
276 Ok((
277 &b""[..],
278 Resp3Type::BlobError {
279 code: "ERROR",
280 message: "1234"
281 }
282 ))
283 );
284 }
285
286 #[test]
287 fn test_verbatim_string() {
288 assert_eq!(
289 parse(&b"=8\r\ntxt:1234\r\n"[..]),
290 Ok((
291 &b""[..],
292 Resp3Type::VerbatimString {
293 format: VerbatimStringFormat::Text,
294 text: "1234"
295 }
296 ))
297 );
298 assert_eq!(
299 parse(&b"=8\r\nmkd:1234\r\n"[..]),
300 Ok((
301 &b""[..],
302 Resp3Type::VerbatimString {
303 format: VerbatimStringFormat::Markdown,
304 text: "1234"
305 }
306 ))
307 );
308 }
309
310 #[test]
311 fn test_parse_big_number() {
312 assert_eq!(
313 parse(&b"(3492890328409238509324850943850943825024385\r\n"[..]),
314 Ok((
315 &b""[..],
316 Resp3Type::BigNumber(
317 BigInt::from_str("3492890328409238509324850943850943825024385").unwrap()
318 )
319 ))
320 );
321 }
322
323 #[test]
324 fn test_parse_array_empty() {
325 assert_eq!(
326 parse(&b"*0\r\n"[..]),
327 Ok((&b""[..], Resp3Type::Array(vec![])))
328 );
329 }
330
331 #[test]
332 fn test_parse_array_mixed_objecs() {
333 assert_eq!(
334 parse(&b"*3\r\n:1\r\n:2\r\n$3\r\nfoo\r\n"[..]),
335 Ok((
336 &b""[..],
337 Resp3Type::Array(vec![
338 Resp3Type::Number(1),
339 Resp3Type::Number(2),
340 Resp3Type::Blob(&b"foo"[..])
341 ])
342 ))
343 );
344 }
345
346 #[test]
347 fn test_parse_map() {
348 assert_eq!(parse(&b"%2\r\n"[..]), Ok((&b""[..], Resp3Type::HashMap(2))));
349 }
350
351 #[test]
352 fn test_parse_set() {
353 assert_eq!(parse(&b"~2\r\n"[..]), Ok((&b""[..], Resp3Type::Set(2))));
354 }
355
356 #[test]
357 fn test_parse_attribute() {
358 assert_eq!(
359 parse(&b"|2\r\n"[..]),
360 Ok((&b""[..], Resp3Type::Attribute(2)))
361 );
362 }
363
364 #[test]
365 fn test_parse_push() {
366 assert_eq!(
367 parse(&b">2\r\n:1\r\n:2\r\n"[..]),
368 Ok((
369 &b""[..],
370 Resp3Type::Array(vec![Resp3Type::Number(1), Resp3Type::Number(2),])
371 ))
372 );
373 }
374
375 #[test]
376 fn test_parse_stream_array() {
377 assert_eq!(
378 parse(&b"*?\r\n"[..]),
379 Ok((&b""[..], Resp3Type::StreamArray))
380 );
381 }
382
383 #[test]
384 fn test_parse_stream_set() {
385 assert_eq!(parse(&b"~?\r\n"[..]), Ok((&b""[..], Resp3Type::StreamSet)));
386 }
387
388 #[test]
389 fn test_parse_stream_map() {
390 assert_eq!(parse(&b"%?\r\n"[..]), Ok((&b""[..], Resp3Type::StreamMap)));
391 }
392
393 #[test]
394 fn test_parse_stream_end() {
395 assert_eq!(parse(&b".\r\n"[..]), Ok((&b""[..], Resp3Type::StreamEnd)));
396 }
397}