redis_parser/
resp3.rs

1/// # RESP2
2/// This module provides utilities to parse the RESP3 protocol.
3use 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    // Aggregate types
45    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
184/// Parse bytes into a `Resp3Type` enum
185pub 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}