1use atoi::atoi;
2use bytes::Buf;
3use bytes::Bytes;
4use std::io::Cursor;
5use std::str;
6use thiserror::Error;
7
8pub const STRING_IDENT: u8 = b'$';
10pub const INTEGER_IDENT: u8 = b'%';
12pub const ARRAY_IDENT: u8 = b'*';
14pub const BOOLEAN_IDENT: u8 = b'^';
16pub const NULL_IDENT: u8 = b'-';
18pub const MAP_IDENT: u8 = b'#';
20pub const DOUBLE_IDENT: u8 = b'.';
22pub const ERROR_IDENT: u8 = b'!';
24
25#[derive(Debug, PartialEq)]
27pub enum Frame {
28 String(Bytes),
30 Integer(i64),
32 Array(Vec<Frame>),
34 Boolean(bool),
36 Null,
38 Map(Vec<Frame>),
40 Double(f64),
42 Error(Bytes),
44}
45
46#[derive(Debug, Error, PartialEq)]
48pub enum ParseFrameError {
49 #[error("incomplete frame")]
51 Incomplete,
52
53 #[error("invalid frame format")]
55 InvalidFormat,
56}
57
58impl Frame {
59 pub fn as_str(&self) -> &'static str {
61 match self {
62 Frame::String(_) => {"frame::String"}
63 Frame::Integer(_) => {"frame::Integer"}
64 Frame::Array(_) => {"frame::Array"}
65 Frame::Boolean(_) => {"frame::Boolean"}
66 Frame::Null => {"frame::StrNull"}
67 Frame::Map(_) => {"frame::Map"}
68 Frame::Double(_) => {"frame::Double"}
69 Frame::Error(_) => {"frame::Error"}
70 }
71 }
72}
73
74pub fn parse(buf: &mut Cursor<&[u8]>) -> Result<Frame, ParseFrameError> {
76 let line = get_line(buf)?;
77 if line.is_empty() {
78 return Err(ParseFrameError::InvalidFormat);
79 }
80 let frame_type = line[0];
81 let line = &line[1..];
82 match frame_type {
83 STRING_IDENT => parse_string(buf, line),
84 INTEGER_IDENT => parse_integer(line),
85 ARRAY_IDENT => parse_array(buf, line),
86 BOOLEAN_IDENT => parse_boolean(line),
87 NULL_IDENT => parse_null(line),
88 MAP_IDENT => parse_map(buf, line),
89 DOUBLE_IDENT => parse_double(line),
90 ERROR_IDENT => parse_error(buf, line),
91 _ => Err(ParseFrameError::InvalidFormat),
92 }
93}
94
95fn get_line<'a>(buf: &mut Cursor<&'a [u8]>) -> Result<&'a [u8], ParseFrameError> {
96 if !buf.has_remaining() {
97 return Err(ParseFrameError::Incomplete);
98 }
99
100 let start = buf.position() as usize;
101 let end = buf.get_ref().len() - 1;
102
103 for i in start..end {
104 if buf.get_ref()[i] == b'\r' && buf.get_ref()[i + 1] == b'\n' {
105 buf.set_position((i + 2) as u64);
106 return Ok(&buf.get_ref()[start..i]);
107 }
108 }
109
110 Err(ParseFrameError::Incomplete)
111}
112
113fn skip(buf: &mut Cursor<&[u8]>, n: usize) -> Result<(), ParseFrameError> {
114 if buf.remaining() < n {
115 return Err(ParseFrameError::Incomplete);
116 }
117 buf.advance(n);
118 Ok(())
119}
120
121fn parse_string(buf: &mut Cursor<&[u8]>, line: &[u8]) -> Result<Frame, ParseFrameError> {
122 let len = atoi::<usize>(line).ok_or(ParseFrameError::InvalidFormat)?;
123 let n = len + 2;
124
125 if buf.remaining() < n {
126 return Err(ParseFrameError::Incomplete);
127 }
128
129 let data = Bytes::copy_from_slice(&buf.chunk()[..len]);
130
131 skip(buf, n)?;
132
133 Ok(Frame::String(data))
134}
135
136fn parse_integer(line: &[u8]) -> Result<Frame, ParseFrameError> {
137 let int = atoi::<i64>(line).ok_or(ParseFrameError::InvalidFormat)?;
138 Ok(Frame::Integer(int))
139}
140
141fn parse_array(buf: &mut Cursor<&[u8]>, line: &[u8]) -> Result<Frame, ParseFrameError> {
142 let len = atoi::<usize>(line).ok_or(ParseFrameError::InvalidFormat)?;
143 let mut vec = Vec::with_capacity(len);
144 for _ in 0..len {
145 vec.push(parse(buf)?);
146 }
147
148 Ok(Frame::Array(vec))
149}
150
151fn parse_boolean(line: &[u8]) -> Result<Frame, ParseFrameError> {
152 if line.len() > 1 {
153 return Err(ParseFrameError::InvalidFormat);
154 }
155
156 let val = line[0];
157
158 match val {
159 b'0' => Ok(Frame::Boolean(false)),
160 b'1' => Ok(Frame::Boolean(true)),
161 _ => Err(ParseFrameError::InvalidFormat),
162 }
163}
164
165fn parse_null(line: &[u8]) -> Result<Frame, ParseFrameError> {
166 if !line.is_empty() {
167 return Err(ParseFrameError::InvalidFormat);
168 }
169 Ok(Frame::Null)
170}
171
172fn parse_map(buf: &mut Cursor<&[u8]>, line: &[u8]) -> Result<Frame, ParseFrameError> {
173 let len = atoi::<usize>(line).ok_or(ParseFrameError::InvalidFormat)?;
174 let mut map = Vec::with_capacity(2 * len);
175 for _ in 0..len {
176 let key = parse(buf)?;
177 let value = parse(buf)?;
178 map.push(key);
179 map.push(value);
180 }
181
182 Ok(Frame::Map(map))
183}
184
185fn parse_double(line: &[u8]) -> Result<Frame, ParseFrameError> {
186 let double = str::from_utf8(line)
187 .map_err(|_| ParseFrameError::InvalidFormat)?
188 .parse::<f64>()
189 .map_err(|_| ParseFrameError::InvalidFormat)?;
190 Ok(Frame::Double(double))
191}
192
193fn parse_error(buf: &mut Cursor<&[u8]>, line: &[u8]) -> Result<Frame, ParseFrameError> {
194 let len = atoi::<usize>(line).ok_or(ParseFrameError::InvalidFormat)?;
195 let n = len + 2;
196
197 if buf.remaining() < n {
198 return Err(ParseFrameError::Incomplete);
199 }
200
201 let data = Bytes::copy_from_slice(&buf.chunk()[..len]);
202
203 skip(buf, n)?;
204
205 Ok(Frame::Error(data))
206}
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211 use bytes::{BufMut, BytesMut};
212 use std::fs;
213 use std::io::Cursor;
214 use std::path::{Path, PathBuf};
215
216 fn get_cursor_from_bytes(bytes: &[u8]) -> Cursor<&[u8]> {
217 Cursor::new(bytes)
218 }
219
220 fn read_file(path: PathBuf) -> Vec<u8> {
221 fs::read(path).unwrap()
222 }
223
224 fn get_frame_from_file(data: &[u8], ident: u8) -> Bytes {
225 let mut frame = BytesMut::new();
226 frame.put_u8(ident);
227 frame.put_slice(format!("{}", data.len()).as_bytes());
228 frame.put_u8(b'\r');
229 frame.put_u8(b'\n');
230 frame.put(data);
231 frame.put_u8(b'\r');
232 frame.put_u8(b'\n');
233
234 frame.copy_to_bytes(frame.len())
235 }
236
237 #[test]
238 fn parse_given_empty_line_returns_invalid_format_error() {
239 let mut buf = get_cursor_from_bytes(b"\r\n");
240 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
241 }
242
243 #[test]
244 fn parse_given_unknown_type_returns_invalid_format_error() {
245 let mut buf = get_cursor_from_bytes(b"foo\r\n");
246 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
247 }
248
249 #[test]
250 fn parse_given_string_with_no_length_returns_invalid_format_error() {
251 let mut buf = get_cursor_from_bytes(b"$\r\n");
252 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
253 }
254
255 #[test]
256 fn parse_given_string_with_invalid_length_returns_invalid_format_error() {
257 let mut buf = get_cursor_from_bytes(b"$abc\r\n");
258 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
259 }
260
261 #[test]
262 fn parse_given_incomplete_string_with_zero_length_returns_incomplete_error() {
263 let mut buf = get_cursor_from_bytes(b"$0\r\n");
264 assert_eq!(parse(&mut buf), Err(ParseFrameError::Incomplete))
265 }
266
267 #[test]
268 fn parse_given_incomplete_string_with_non_zero_length_returns_incomplete_error() {
269 let mut buf = get_cursor_from_bytes(b"$1\r\n");
270 assert_eq!(parse(&mut buf), Err(ParseFrameError::Incomplete))
271 }
272
273 #[test]
274 fn parse_given_string_with_zero_length_returns_empty_string() {
275 let mut buf = get_cursor_from_bytes(b"$0\r\n\r\n");
276 assert_eq!(parse(&mut buf), Ok(Frame::String(Bytes::from(""))))
277 }
278
279 #[test]
280 fn parse_given_string_with_length_less_than_length_of_data_returns_data_upto_given_length() {
281 let mut buf = get_cursor_from_bytes(b"$1\r\nfoo\r\n");
282 assert_eq!(parse(&mut buf), Ok(Frame::String(Bytes::from("f"))))
283 }
284
285 #[test]
286 fn parse_given_string_with_length_greater_than_length_of_data_returns_incomplete_error() {
287 let mut buf = get_cursor_from_bytes(b"$100\r\nfoo\r\n");
288 assert_eq!(parse(&mut buf), Err(ParseFrameError::Incomplete))
289 }
290
291 #[test]
292 fn parse_given_string_returns_string() {
293 let mut buf = get_cursor_from_bytes(b"$3\r\nfoo\r\n");
294 assert_eq!(parse(&mut buf), Ok(Frame::String(Bytes::from("foo"))))
295 }
296
297 #[test]
298 fn parse_given_string_with_delimiter_in_data_returns_string() {
299 let mut buf = get_cursor_from_bytes(b"$5\r\nfoo\r\n\r\n");
300 assert_eq!(parse(&mut buf), Ok(Frame::String(Bytes::from("foo\r\n"))))
301 }
302
303 #[test]
304 fn parse_given_string_with_pdf_data_returns_pdf_data() {
305 let file_data = read_file(Path::new("test_data").join("test.pdf"));
306 let frame = get_frame_from_file(file_data.as_slice(), STRING_IDENT);
307 let mut buf = get_cursor_from_bytes(&frame);
308 assert_eq!(parse(&mut buf), Ok(Frame::String(Bytes::from(file_data))))
309 }
310
311 #[test]
312 fn parse_given_string_with_png_data_returns_png_data() {
313 let file_data = read_file(Path::new("test_data").join("test.png"));
314 let frame = get_frame_from_file(file_data.as_slice(), STRING_IDENT);
315 let mut buf = get_cursor_from_bytes(&frame);
316 assert_eq!(parse(&mut buf), Ok(Frame::String(Bytes::from(file_data))))
317 }
318
319 #[test]
320 fn parse_given_string_with_jpg_data_returns_jpg_data() {
321 let file_data = read_file(Path::new("test_data").join("test.jpg"));
322 let frame = get_frame_from_file(file_data.as_slice(), STRING_IDENT);
323 let mut buf = get_cursor_from_bytes(&frame);
324 assert_eq!(parse(&mut buf), Ok(Frame::String(Bytes::from(file_data))))
325 }
326
327 #[test]
328 fn parse_given_string_with_html_data_returns_html_data() {
329 let file_data = read_file(Path::new("test_data").join("test.html"));
330 let frame = get_frame_from_file(file_data.as_slice(), STRING_IDENT);
331 let mut buf = get_cursor_from_bytes(&frame);
332 assert_eq!(parse(&mut buf), Ok(Frame::String(Bytes::from(file_data))))
333 }
334
335 #[test]
336 fn parse_given_invalid_integer_returns_invalid_format_error() {
337 let mut buf = get_cursor_from_bytes(b"%abc\r\n");
338 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
339 }
340
341 #[test]
342 fn parse_given_empty_integer_returns_invalid_format_error() {
343 let mut buf = get_cursor_from_bytes(b"%\r\n");
344 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
345 }
346
347 #[test]
348 fn parse_given_negative_integer_returns_given_integer() {
349 let mut buf = get_cursor_from_bytes(b"%-1\r\n");
350 assert_eq!(parse(&mut buf), Ok(Frame::Integer(-1)))
351 }
352
353 #[test]
354 fn parse_given_zero_returns_zero() {
355 let mut buf = get_cursor_from_bytes(b"%0\r\n");
356 assert_eq!(parse(&mut buf), Ok(Frame::Integer(0)))
357 }
358
359 #[test]
360 fn parse_given_positive_integer_returns_given_integer() {
361 let mut buf = get_cursor_from_bytes(b"%1000\r\n");
362 assert_eq!(parse(&mut buf), Ok(Frame::Integer(1000)))
363 }
364
365 #[test]
366 fn parse_given_out_of_range_integer_returns_format_error() {
367 let mut buf = get_cursor_from_bytes(b"%9223372036854775808\r\n");
368 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
369 }
370
371 #[test]
372 fn parse_given_false_returns_false() {
373 let mut buf = get_cursor_from_bytes(b"^0\r\n");
374 assert_eq!(parse(&mut buf), Ok(Frame::Boolean(false)))
375 }
376
377 #[test]
378 fn parse_given_true_returns_true() {
379 let mut buf = get_cursor_from_bytes(b"^1\r\n");
380 assert_eq!(parse(&mut buf), Ok(Frame::Boolean(true)))
381 }
382
383 #[test]
384 fn parse_given_invalid_boolean_returns_invalid_format_error() {
385 let mut buf = get_cursor_from_bytes(b"^foo\r\n");
386 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
387 }
388
389 #[test]
390 fn parse_given_null_returns_null() {
391 let mut buf = get_cursor_from_bytes(b"-\r\n");
392 assert_eq!(parse(&mut buf), Ok(Frame::Null))
393 }
394
395 #[test]
396 fn parse_given_invalid_null_returns_invalid_format_error() {
397 let mut buf = get_cursor_from_bytes(b"-foo\r\n");
398 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
399 }
400
401 #[test]
402 fn parse_given_double_with_invalid_decimal_part_returns_invalid_format_error() {
403 let mut buf = get_cursor_from_bytes(b".20.foo\r\n");
404 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
405 }
406
407 #[test]
408 fn parse_given_double_with_invalid_integer_part_returns_invalid_format_error() {
409 let mut buf = get_cursor_from_bytes(b".foo.90\r\n");
410 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
411 }
412
413 #[test]
414 fn parse_given_double_with_zero_decimal_part_returns_double() {
415 let mut buf = get_cursor_from_bytes(b".10.000\r\n");
416 assert_eq!(parse(&mut buf), Ok(Frame::Double(10.0)))
417 }
418
419 #[test]
420 fn parse_given_double_with_trailing_zeroes_returns_double() {
421 let mut buf = get_cursor_from_bytes(b".10.100\r\n");
422 assert_eq!(parse(&mut buf), Ok(Frame::Double(10.1)))
423 }
424
425 #[test]
426 fn parse_given_double_with_leading_zeroes_returns_double() {
427 let mut buf = get_cursor_from_bytes(b".000010.100\r\n");
428 assert_eq!(parse(&mut buf), Ok(Frame::Double(10.1)))
429 }
430
431 #[test]
432 fn parse_given_invalid_double_returns_invalid_format_error() {
433 let mut buf = get_cursor_from_bytes(b".abc\r\n");
434 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
435 }
436
437 #[test]
438 fn parse_given_error_with_no_length_returns_invalid_format_error() {
439 let mut buf = get_cursor_from_bytes(b"!\r\n");
440 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
441 }
442
443 #[test]
444 fn parse_given_error_with_invalid_length_returns_invalid_format_error() {
445 let mut buf = get_cursor_from_bytes(b"!abc\r\n");
446 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
447 }
448
449 #[test]
450 fn parse_given_incomplete_error_with_zero_length_returns_incomplete_error() {
451 let mut buf = get_cursor_from_bytes(b"!0\r\n");
452 assert_eq!(parse(&mut buf), Err(ParseFrameError::Incomplete))
453 }
454
455 #[test]
456 fn parse_given_incomplete_error_with_non_zero_length_returns_incomplete_error() {
457 let mut buf = get_cursor_from_bytes(b"!1\r\n");
458 assert_eq!(parse(&mut buf), Err(ParseFrameError::Incomplete))
459 }
460
461 #[test]
462 fn parse_given_error_with_zero_length_returns_empty_error_frame() {
463 let mut buf = get_cursor_from_bytes(b"!0\r\n\r\n");
464 assert_eq!(parse(&mut buf), Ok(Frame::Error(Bytes::from(""))))
465 }
466
467 #[test]
468 fn parse_given_error_with_length_less_than_length_of_data_returns_data_upto_given_length() {
469 let mut buf = get_cursor_from_bytes(b"!1\r\nfoo\r\n");
470 assert_eq!(parse(&mut buf), Ok(Frame::Error(Bytes::from("f"))))
471 }
472
473 #[test]
474 fn parse_given_error_with_length_greater_than_length_of_data_returns_incomplete_error() {
475 let mut buf = get_cursor_from_bytes(b"!100\r\nfoo\r\n");
476 assert_eq!(parse(&mut buf), Err(ParseFrameError::Incomplete))
477 }
478
479 #[test]
480 fn parse_given_error_returns_error_frame() {
481 let mut buf = get_cursor_from_bytes(b"!3\r\nfoo\r\n");
482 assert_eq!(parse(&mut buf), Ok(Frame::Error(Bytes::from("foo"))))
483 }
484
485 #[test]
486 fn parse_given_error_with_delimiter_in_data_returns_error_frame() {
487 let mut buf = get_cursor_from_bytes(b"!5\r\nfoo\r\n\r\n");
488 assert_eq!(parse(&mut buf), Ok(Frame::Error(Bytes::from("foo\r\n"))))
489 }
490
491 #[test]
492 fn parse_given_error_with_pdf_data_returns_pdf_data() {
493 let file_data = read_file(Path::new("test_data").join("test.pdf"));
494 let frame = get_frame_from_file(file_data.as_slice(), ERROR_IDENT);
495 let mut buf = get_cursor_from_bytes(&frame);
496 assert_eq!(parse(&mut buf), Ok(Frame::Error(Bytes::from(file_data))))
497 }
498
499 #[test]
500 fn parse_given_error_with_png_data_returns_png_data() {
501 let file_data = read_file(Path::new("test_data").join("test.png"));
502 let frame = get_frame_from_file(file_data.as_slice(), ERROR_IDENT);
503 let mut buf = get_cursor_from_bytes(&frame);
504 assert_eq!(parse(&mut buf), Ok(Frame::Error(Bytes::from(file_data))))
505 }
506
507 #[test]
508 fn parse_given_error_with_jpg_data_returns_jpg_data() {
509 let file_data = read_file(Path::new("test_data").join("test.jpg"));
510 let frame = get_frame_from_file(file_data.as_slice(), ERROR_IDENT);
511 let mut buf = get_cursor_from_bytes(&frame);
512 assert_eq!(parse(&mut buf), Ok(Frame::Error(Bytes::from(file_data))))
513 }
514
515 #[test]
516 fn parse_given_error_with_html_data_returns_html_data() {
517 let file_data = read_file(Path::new("test_data").join("test.html"));
518 let frame = get_frame_from_file(file_data.as_slice(), ERROR_IDENT);
519 let mut buf = get_cursor_from_bytes(&frame);
520 assert_eq!(parse(&mut buf), Ok(Frame::Error(Bytes::from(file_data))))
521 }
522
523 #[test]
524 fn parse_given_array_with_no_length_returns_invalid_format_error() {
525 let mut buf = get_cursor_from_bytes(b"*\r\n");
526 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
527 }
528
529 #[test]
530 fn parse_given_array_with_zero_length_returns_empty_array() {
531 let mut buf = get_cursor_from_bytes(b"*0\r\n");
532 assert_eq!(parse(&mut buf), Ok(Frame::Array(Vec::new())))
533 }
534
535 #[test]
536 fn parse_given_array_with_invalid_length_invalid_format_error() {
537 let mut buf = get_cursor_from_bytes(b"*abc\r\n");
538 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
539 }
540
541 #[test]
542 fn parse_given_map_with_no_length_returns_invalid_format_error() {
543 let mut buf = get_cursor_from_bytes(b"#\r\n");
544 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
545 }
546
547 #[test]
548 fn parse_given_map_with_zero_length_returns_empty_map() {
549 let mut buf = get_cursor_from_bytes(b"#0\r\n");
550 assert_eq!(parse(&mut buf), Ok(Frame::Map(Vec::new())))
551 }
552
553 #[test]
554 fn parse_given_map_with_invalid_length_returns_invalid_format_error() {
555 let mut buf = get_cursor_from_bytes(b"#abc\r\n");
556 assert_eq!(parse(&mut buf), Err(ParseFrameError::InvalidFormat))
557 }
558
559 #[test]
560 fn parse_given_incomplete_map_return_incomplete_error() {
561 let mut buf = get_cursor_from_bytes(b"#2\r\n$3\r\nfoo\r\n");
562 assert_eq!(parse(&mut buf), Err(ParseFrameError::Incomplete))
563 }
564}