123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- #[macro_use]
- mod macros;
- use std::convert::TryInto;
- #[derive(Debug, PartialEq, Clone)]
- pub enum Value<'a> {
- Array(Vec<Value<'a>>),
- Blob(&'a [u8]),
- String(&'a str),
- Error(&'a str, &'a str),
- Integer(i64),
- Boolean(bool),
- Float(f64),
- BigInteger(i128),
- Null,
- }
- #[derive(Debug, Clone, Eq, PartialEq)]
- pub enum Error {
- Partial,
- InvalidPrefix,
- InvalidLength,
- InvalidBoolean,
- InvalidNumber,
- Protocol(u8, u8),
- NewLine,
- }
- pub fn parse_server(bytes: &[u8]) -> Result<(&[u8], Vec<&[u8]>), Error> {
- let (bytes, byte) = next!(bytes);
- match byte {
- b'*' => parse_server_array(bytes),
- _ => Err(Error::Protocol(b'*', byte)),
- }
- }
- fn parse_server_array(bytes: &[u8]) -> Result<(&[u8], Vec<&[u8]>), Error> {
- let (bytes, len) = read_line_number!(bytes, i32);
- if len <= 0 {
- return Err(Error::Protocol(b'x', b'y'));
- }
- let mut v = vec![];
- let mut bytes = bytes;
- for _i in 0..len {
- let n = next!(bytes);
- let r = match n.1 {
- b'$' => parse_blob(n.0),
- _ => Err(Error::Protocol(b'$', n.1)),
- }?;
- bytes = r.0;
- v.push(match r.1 {
- Value::Blob(x) => Ok(x),
- _ => Err(Error::Protocol(b'x', b'y')),
- }?);
- }
- Ok((bytes, v))
- }
- pub fn parse(bytes: &[u8]) -> Result<(&[u8], Value), Error> {
- let (bytes, byte) = next!(bytes);
- match byte {
- b'*' => parse_array(bytes),
- b'$' => parse_blob(bytes),
- b':' => parse_integer(bytes),
- b'(' => parse_big_integer(bytes),
- b',' => parse_float(bytes),
- b'#' => parse_boolean(bytes),
- b'+' => parse_str(bytes),
- b'-' => parse_error(bytes),
- _ => Err(Error::InvalidPrefix),
- }
- }
- fn parse_error(bytes: &[u8]) -> Result<(&[u8], Value), Error> {
- let (bytes, err_type) = read_until!(bytes, b' ');
- let (bytes, str) = read_line!(bytes);
- let err_type = unsafe { std::str::from_utf8_unchecked(err_type) };
- let str = unsafe { std::str::from_utf8_unchecked(str) };
- ret!(bytes, Value::Error(err_type, str))
- }
- fn parse_str(bytes: &[u8]) -> Result<(&[u8], Value), Error> {
- let (bytes, str) = read_line!(bytes);
- let str = unsafe { std::str::from_utf8_unchecked(str) };
- ret!(bytes, Value::String(str))
- }
- fn parse_boolean(bytes: &[u8]) -> Result<(&[u8], Value), Error> {
- let (bytes, byte) = next!(bytes);
- let v = match byte {
- b't' => true,
- b'f' => false,
- _ => return Err(Error::InvalidBoolean),
- };
- ret!(bytes, Value::Boolean(v))
- }
- fn parse_big_integer(bytes: &[u8]) -> Result<(&[u8], Value), Error> {
- let (bytes, number) = read_line_number!(bytes, i128);
- ret!(bytes, Value::BigInteger(number))
- }
- fn parse_integer(bytes: &[u8]) -> Result<(&[u8], Value), Error> {
- let (bytes, number) = read_line_number!(bytes, i64);
- ret!(bytes, Value::Integer(number))
- }
- fn parse_float(bytes: &[u8]) -> Result<(&[u8], Value), Error> {
- let (bytes, number) = read_line_number!(bytes, f64);
- ret!(bytes, Value::Float(number))
- }
- fn parse_blob(bytes: &[u8]) -> Result<(&[u8], Value), Error> {
- let (bytes, len) = read_line_number!(bytes, i32);
- if len <= 0 {
- return ret!(bytes, Value::Null);
- }
- let (bytes, blob) = read_len!(bytes, len);
- let bytes = assert_nl!(bytes);
- ret!(bytes, Value::Blob(blob))
- }
- fn parse_array(bytes: &[u8]) -> Result<(&[u8], Value), Error> {
- let (bytes, len) = read_line_number!(bytes, i32);
- if len <= 0 {
- return ret!(bytes, Value::Null);
- }
- let mut v = vec![Value::Null; len as usize];
- let mut bytes = bytes;
- for i in 0..len {
- let r = parse(bytes)?;
- bytes = r.0;
- v[i as usize] = r.1;
- }
- ret!(bytes, Value::Array(v))
- }
- #[cfg(test)]
- mod test {
- use super::*;
- #[test]
- fn test_parse_partial() {
- let d = b"*-1";
- assert_eq!(Err(Error::Partial), parse(d));
- }
- #[test]
- fn test_parse_partial_2() {
- let d = b"*12\r\n";
- assert_eq!(Err(Error::Partial), parse(d));
- }
- #[test]
- fn test_incomplete_blob_parsing() {
- let d = b"$60\r\nfoobar\r\n";
- assert_eq!(Err(Error::Partial), parse(d));
- }
- #[test]
- fn test_complete_blob_parsing() {
- let d = b"$6\r\nfoobar\r\n";
- let r = parse(d);
- assert!(r.is_ok());
- let data = match r.unwrap().1 {
- Value::Blob(x) => unsafe { std::str::from_utf8_unchecked(x) },
- _ => "",
- };
- assert_eq!(data, "foobar");
- }
- #[test]
- fn test_complete_blob_parsing_and_extra_buffer() {
- let d = b"$6\r\nfoobar\r\n$6\r\nfoobar\r\n";
- let r = parse(d);
- assert!(r.is_ok());
- let (buf, data) = r.unwrap();
- let data = match data {
- Value::Blob(x) => unsafe { std::str::from_utf8_unchecked(x) },
- _ => "",
- };
- assert_eq!(data, "foobar");
- assert_eq!(b"$6\r\nfoobar\r\n", buf);
- }
- #[test]
- fn test_complete_array_parser() {
- let d = b"*2\r\n$6\r\nfoobar\r\n$3\r\nfoo\r\n";
- let r = parse(d);
- assert!(r.is_ok());
- let x = match r.unwrap().1 {
- Value::Array(x) => x,
- _ => panic!("Unxpected type"),
- };
- assert_eq!(2, x.len());
- }
- #[test]
- fn test_complete_nested_array_parser() {
- let d = b"*2\r\n$6\r\nfoobar\r\n*1\r\n$3\r\nfoo\r\n";
- let r = parse(d);
- assert!(r.is_ok());
- let x = match r.unwrap().1 {
- Value::Array(x) => x,
- _ => panic!("Unxpected type"),
- };
- assert_eq!(2, x.len());
- }
- #[test]
- fn test_parse_float() {
- let d = b",0.25887\r\n";
- let r = parse(d);
- assert!(r.is_ok());
- let x = match r.unwrap().1 {
- Value::Float(x) => x,
- _ => panic!("Unxpected type"),
- };
- assert_eq!(0.25887, x);
- }
- #[test]
- fn test_parse_integer() {
- let d = b":25887\r\n";
- let r = parse(d);
- assert!(r.is_ok());
- let x = match r.unwrap().1 {
- Value::Integer(x) => x,
- _ => panic!("Unxpected type"),
- };
- assert_eq!(25887, x);
- }
- #[test]
- fn test_parse_big_integer() {
- let d = b"(25887\r\n";
- let r = parse(d);
- assert!(r.is_ok());
- let x = match r.unwrap().1 {
- Value::BigInteger(x) => x,
- _ => panic!("Unxpected type"),
- };
- assert_eq!(25887, x);
- }
- #[test]
- fn test_parse_false() {
- let d = b"#f\r\n";
- let r = parse(d);
- assert!(r.is_ok());
- let x = match r.unwrap().1 {
- Value::Boolean(x) => x,
- _ => panic!("Unxpected type"),
- };
- assert!(!x);
- }
- #[test]
- fn test_parse_true() {
- let d = b"#t\r\n";
- let r = parse(d);
- assert!(r.is_ok());
- let x = match r.unwrap().1 {
- Value::Boolean(x) => x,
- _ => panic!("Unxpected type"),
- };
- assert!(x);
- }
- #[test]
- fn test_parse_boolean_unexpected() {
- let d = b"#1\r\n";
- assert_eq!(Err(Error::InvalidBoolean), parse(d));
- }
- #[test]
- fn test_parse_str() {
- let d = b"+hello world\r\n";
- let r = parse(d);
- assert!(r.is_ok());
- let x = match r.unwrap().1 {
- Value::String(x) => x,
- _ => panic!("Unxpected type"),
- };
- assert_eq!("hello world", x);
- }
- #[test]
- fn test_parse_error() {
- let d = b"-ERR this is the error description\r\n";
- let r = parse(d);
- assert!(r.is_ok());
- let x = match r.unwrap().1 {
- Value::Error(a, b) => (a, b),
- _ => panic!("Unxpected type"),
- };
- assert_eq!("ERR", x.0);
- assert_eq!("this is the error description", x.1);
- }
- }
|