|
@@ -1,15 +1,9 @@
|
|
-mod bytes;
|
|
|
|
#[macro_use]
|
|
#[macro_use]
|
|
mod macros;
|
|
mod macros;
|
|
|
|
|
|
-use bytes::Bytes;
|
|
|
|
use std::convert::TryInto;
|
|
use std::convert::TryInto;
|
|
|
|
|
|
-pub struct Parser {
|
|
|
|
- pos: usize
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#[derive(Debug, PartialEq)]
|
|
|
|
|
|
+#[derive(Debug, PartialEq, Clone)]
|
|
pub enum Value<'a> {
|
|
pub enum Value<'a> {
|
|
Array(Vec<Value<'a>>),
|
|
Array(Vec<Value<'a>>),
|
|
Blob(&'a [u8]),
|
|
Blob(&'a [u8]),
|
|
@@ -22,10 +16,31 @@ pub enum Value<'a> {
|
|
Null,
|
|
Null,
|
|
}
|
|
}
|
|
|
|
|
|
-impl<'a> Clone for Value<'a> {
|
|
|
|
- fn clone(&self) -> Value<'a> {
|
|
|
|
|
|
+#[derive(Debug, PartialEq, Clone)]
|
|
|
|
+pub enum Frame {
|
|
|
|
+ Array(Vec<Frame>),
|
|
|
|
+ Blob(Vec<u8>),
|
|
|
|
+ String(String),
|
|
|
|
+ Error(String, String),
|
|
|
|
+ Integer(i64),
|
|
|
|
+ Boolean(bool),
|
|
|
|
+ Float(f64),
|
|
|
|
+ BigInteger(i128),
|
|
|
|
+ Null,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<'a> Value<'a> {
|
|
|
|
+ pub fn to_frame(&self) -> Frame {
|
|
match self {
|
|
match self {
|
|
- _ => Self::Null,
|
|
|
|
|
|
+ Self::String(x) => Frame::String(x.to_string()),
|
|
|
|
+ Self::Blob(x) => Frame::Blob(x.to_vec()),
|
|
|
|
+ Self::Array(x) => Frame::Array(x.iter().map(|x| x.to_frame()).collect()),
|
|
|
|
+ Self::Boolean(x) => Frame::Boolean(*x),
|
|
|
|
+ Self::BigInteger(x) => Frame::BigInteger(*x),
|
|
|
|
+ Self::Integer(x) => Frame::Integer(*x),
|
|
|
|
+ Self::Float(x) => Frame::Float(*x),
|
|
|
|
+ Self::Error(x, y) => Frame::Error(x.to_string(), y.to_string()),
|
|
|
|
+ Self::Null => Frame::Null,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -40,100 +55,89 @@ pub enum Error {
|
|
NewLine,
|
|
NewLine,
|
|
}
|
|
}
|
|
|
|
|
|
-impl Default for Parser {
|
|
|
|
- fn default() -> Self {
|
|
|
|
- Self::new()
|
|
|
|
|
|
+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),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-impl Parser {
|
|
|
|
- pub fn new() -> Self {
|
|
|
|
- Parser {
|
|
|
|
- pos: 0,
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- pub fn parse(&mut self, bytes: &[u8]) -> Result<Value, Error> {
|
|
|
|
- self.pos = 0;
|
|
|
|
- self.parse_bytes(bytes)
|
|
|
|
- }
|
|
|
|
|
|
+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_bytes(&mut self, bytes: &[u8]) -> Result<Value, Error> {
|
|
|
|
- match next!(self, bytes) {
|
|
|
|
- b'*' => self.parse_array(bytes),
|
|
|
|
- b'$' => self.parse_blob(bytes),
|
|
|
|
- b':' => self.parse_integer(bytes),
|
|
|
|
- b'(' => self.parse_big_integer(bytes),
|
|
|
|
- b',' => self.parse_float(bytes),
|
|
|
|
- b'#' => self.parse_boolean(bytes),
|
|
|
|
- b'+' => self.parse_str(bytes),
|
|
|
|
- b'-' => self.parse_error(bytes),
|
|
|
|
- _ => Err(Error::InvalidPrefix),
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+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_error(&mut self, bytes: &[u8]) -> Result<Value, Error> {
|
|
|
|
- let err_type = unsafe { std::str::from_utf8_unchecked(read_until!(self, bytes, b' ')) };
|
|
|
|
- let str = unsafe { std::str::from_utf8_unchecked(read_line!(self, bytes)) };
|
|
|
|
- Ok(Value::Error(err_type, 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_str(&mut self, bytes: &[u8]) -> Result<Value, Error> {
|
|
|
|
- let str = unsafe { std::str::from_utf8_unchecked(read_line!(self, bytes)) };
|
|
|
|
- Ok(Value::String(str))
|
|
|
|
- }
|
|
|
|
|
|
+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_boolean(&mut self, bytes: &[u8]) -> Result<Value, Error> {
|
|
|
|
- let v = match next!(self, bytes) {
|
|
|
|
- b't' => true,
|
|
|
|
- b'f' => false,
|
|
|
|
- _ => return Err(Error::InvalidBoolean),
|
|
|
|
- };
|
|
|
|
- Ok(Value::Boolean(v))
|
|
|
|
- }
|
|
|
|
|
|
+fn parse_integer(bytes: &[u8]) -> Result<(&[u8], Value), Error> {
|
|
|
|
+ let (bytes, number) = read_line_number!(bytes, i64);
|
|
|
|
+ ret!(bytes, Value::Integer(number))
|
|
|
|
+}
|
|
|
|
|
|
- fn parse_big_integer(&mut self, bytes: &[u8]) -> Result<Value, Error> {
|
|
|
|
- let number = read_line_number!(self, bytes, i128);
|
|
|
|
- Ok(Value::BigInteger(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_integer(&mut self, bytes: &[u8]) -> Result<Value, Error> {
|
|
|
|
- let number = read_line_number!(self, bytes, i64);
|
|
|
|
- Ok(Value::Integer(number))
|
|
|
|
- }
|
|
|
|
|
|
+fn parse_blob(bytes: &[u8]) -> Result<(&[u8], Value), Error> {
|
|
|
|
+ let (bytes, len) = read_line_number!(bytes, i32);
|
|
|
|
|
|
- fn parse_float(&mut self, bytes: &[u8]) -> Result<Value, Error> {
|
|
|
|
- let number = read_line_number!(self, bytes, f64);
|
|
|
|
- Ok(Value::Float(number))
|
|
|
|
|
|
+ if len <= 0 {
|
|
|
|
+ return ret!(bytes, Value::Null);
|
|
}
|
|
}
|
|
|
|
|
|
- fn parse_blob(&mut self, bytes: &[u8]) -> Result<Value, Error> {
|
|
|
|
- let len = read_line_number!(self, bytes, i32);
|
|
|
|
|
|
+ let (bytes, blob) = read_len!(bytes, len);
|
|
|
|
+ let bytes = assert_nl!(bytes);
|
|
|
|
|
|
- if len <= 0 {
|
|
|
|
- return Ok(Value::Null);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- let blob = read_len!(self, bytes, len);
|
|
|
|
- assert_nl!(self, bytes);
|
|
|
|
|
|
+ ret!(bytes, Value::Blob(blob))
|
|
|
|
+}
|
|
|
|
|
|
- Ok(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);
|
|
}
|
|
}
|
|
|
|
|
|
- fn parse_array(&mut self, bytes: &[u8]) -> Result<Value, Error> {
|
|
|
|
- let len = read_line_number!(self, bytes, i32);
|
|
|
|
- if len <= 0 {
|
|
|
|
- return Ok(Value::Null);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- let mut v = vec![Value::Null; len as usize];
|
|
|
|
-
|
|
|
|
- for i in 0..len {
|
|
|
|
- v[i as usize] = self.parse_bytes(bytes)?;
|
|
|
|
- }
|
|
|
|
|
|
+ let mut v = vec![Value::Null; len as usize];
|
|
|
|
+ let mut bytes = bytes;
|
|
|
|
|
|
- Ok(Value::Array(v))
|
|
|
|
|
|
+ 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)]
|
|
#[cfg(test)]
|
|
@@ -142,51 +146,64 @@ mod test {
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_parse_partial() {
|
|
fn test_parse_partial() {
|
|
- let mut p = Parser::new();
|
|
|
|
let d = b"*-1";
|
|
let d = b"*-1";
|
|
- assert_eq!(Err(Error::Partial), p.parse(d));
|
|
|
|
|
|
+ assert_eq!(Err(Error::Partial), parse(d));
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_parse_partial_2() {
|
|
fn test_parse_partial_2() {
|
|
- let mut p = Parser::new();
|
|
|
|
let d = b"*12\r\n";
|
|
let d = b"*12\r\n";
|
|
- assert_eq!(Err(Error::Partial), p.parse(d));
|
|
|
|
|
|
+ assert_eq!(Err(Error::Partial), parse(d));
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_incomplete_blob_parsing() {
|
|
fn test_incomplete_blob_parsing() {
|
|
let d = b"$60\r\nfoobar\r\n";
|
|
let d = b"$60\r\nfoobar\r\n";
|
|
- let mut p = Parser::new();
|
|
|
|
|
|
|
|
- assert_eq!(Err(Error::Partial), p.parse(d));
|
|
|
|
|
|
+ assert_eq!(Err(Error::Partial), parse(d));
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_complete_blob_parsing() {
|
|
fn test_complete_blob_parsing() {
|
|
let d = b"$6\r\nfoobar\r\n";
|
|
let d = b"$6\r\nfoobar\r\n";
|
|
- let mut p = Parser::new();
|
|
|
|
|
|
|
|
- let r = p.parse(d);
|
|
|
|
|
|
+ let r = parse(d);
|
|
assert!(r.is_ok());
|
|
assert!(r.is_ok());
|
|
|
|
|
|
- let data = match r.unwrap() {
|
|
|
|
|
|
+ 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) },
|
|
Value::Blob(x) => unsafe { std::str::from_utf8_unchecked(x) },
|
|
_ => "",
|
|
_ => "",
|
|
};
|
|
};
|
|
|
|
|
|
assert_eq!(data, "foobar");
|
|
assert_eq!(data, "foobar");
|
|
|
|
+ assert_eq!(b"$6\r\nfoobar\r\n", buf);
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_complete_array_parser() {
|
|
fn test_complete_array_parser() {
|
|
let d = b"*2\r\n$6\r\nfoobar\r\n$3\r\nfoo\r\n";
|
|
let d = b"*2\r\n$6\r\nfoobar\r\n$3\r\nfoo\r\n";
|
|
- let mut p = Parser::new();
|
|
|
|
|
|
|
|
- let r = p.parse(d);
|
|
|
|
|
|
+ let r = parse(d);
|
|
assert!(r.is_ok());
|
|
assert!(r.is_ok());
|
|
|
|
|
|
- let x = match r.unwrap() {
|
|
|
|
|
|
+ let x = match r.unwrap().1 {
|
|
Value::Array(x) => x,
|
|
Value::Array(x) => x,
|
|
_ => panic!("Unxpected type"),
|
|
_ => panic!("Unxpected type"),
|
|
};
|
|
};
|
|
@@ -197,12 +214,11 @@ mod test {
|
|
#[test]
|
|
#[test]
|
|
fn test_complete_nested_array_parser() {
|
|
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 d = b"*2\r\n$6\r\nfoobar\r\n*1\r\n$3\r\nfoo\r\n";
|
|
- let mut p = Parser::new();
|
|
|
|
|
|
|
|
- let r = p.parse(d);
|
|
|
|
|
|
+ let r = parse(d);
|
|
assert!(r.is_ok());
|
|
assert!(r.is_ok());
|
|
|
|
|
|
- let x = match r.unwrap() {
|
|
|
|
|
|
+ let x = match r.unwrap().1 {
|
|
Value::Array(x) => x,
|
|
Value::Array(x) => x,
|
|
_ => panic!("Unxpected type"),
|
|
_ => panic!("Unxpected type"),
|
|
};
|
|
};
|
|
@@ -213,12 +229,11 @@ mod test {
|
|
#[test]
|
|
#[test]
|
|
fn test_parse_float() {
|
|
fn test_parse_float() {
|
|
let d = b",0.25887\r\n";
|
|
let d = b",0.25887\r\n";
|
|
- let mut p = Parser::new();
|
|
|
|
|
|
|
|
- let r = p.parse(d);
|
|
|
|
|
|
+ let r = parse(d);
|
|
assert!(r.is_ok());
|
|
assert!(r.is_ok());
|
|
|
|
|
|
- let x = match r.unwrap() {
|
|
|
|
|
|
+ let x = match r.unwrap().1 {
|
|
Value::Float(x) => x,
|
|
Value::Float(x) => x,
|
|
_ => panic!("Unxpected type"),
|
|
_ => panic!("Unxpected type"),
|
|
};
|
|
};
|
|
@@ -229,12 +244,11 @@ mod test {
|
|
#[test]
|
|
#[test]
|
|
fn test_parse_integer() {
|
|
fn test_parse_integer() {
|
|
let d = b":25887\r\n";
|
|
let d = b":25887\r\n";
|
|
- let mut p = Parser::new();
|
|
|
|
|
|
|
|
- let r = p.parse(d);
|
|
|
|
|
|
+ let r = parse(d);
|
|
assert!(r.is_ok());
|
|
assert!(r.is_ok());
|
|
|
|
|
|
- let x = match r.unwrap() {
|
|
|
|
|
|
+ let x = match r.unwrap().1 {
|
|
Value::Integer(x) => x,
|
|
Value::Integer(x) => x,
|
|
_ => panic!("Unxpected type"),
|
|
_ => panic!("Unxpected type"),
|
|
};
|
|
};
|
|
@@ -245,12 +259,11 @@ mod test {
|
|
#[test]
|
|
#[test]
|
|
fn test_parse_big_integer() {
|
|
fn test_parse_big_integer() {
|
|
let d = b"(25887\r\n";
|
|
let d = b"(25887\r\n";
|
|
- let mut p = Parser::new();
|
|
|
|
|
|
|
|
- let r = p.parse(d);
|
|
|
|
|
|
+ let r = parse(d);
|
|
assert!(r.is_ok());
|
|
assert!(r.is_ok());
|
|
|
|
|
|
- let x = match r.unwrap() {
|
|
|
|
|
|
+ let x = match r.unwrap().1 {
|
|
Value::BigInteger(x) => x,
|
|
Value::BigInteger(x) => x,
|
|
_ => panic!("Unxpected type"),
|
|
_ => panic!("Unxpected type"),
|
|
};
|
|
};
|
|
@@ -261,12 +274,11 @@ mod test {
|
|
#[test]
|
|
#[test]
|
|
fn test_parse_false() {
|
|
fn test_parse_false() {
|
|
let d = b"#f\r\n";
|
|
let d = b"#f\r\n";
|
|
- let mut p = Parser::new();
|
|
|
|
|
|
|
|
- let r = p.parse(d);
|
|
|
|
|
|
+ let r = parse(d);
|
|
assert!(r.is_ok());
|
|
assert!(r.is_ok());
|
|
|
|
|
|
- let x = match r.unwrap() {
|
|
|
|
|
|
+ let x = match r.unwrap().1 {
|
|
Value::Boolean(x) => x,
|
|
Value::Boolean(x) => x,
|
|
_ => panic!("Unxpected type"),
|
|
_ => panic!("Unxpected type"),
|
|
};
|
|
};
|
|
@@ -277,12 +289,11 @@ mod test {
|
|
#[test]
|
|
#[test]
|
|
fn test_parse_true() {
|
|
fn test_parse_true() {
|
|
let d = b"#t\r\n";
|
|
let d = b"#t\r\n";
|
|
- let mut p = Parser::new();
|
|
|
|
|
|
|
|
- let r = p.parse(d);
|
|
|
|
|
|
+ let r = parse(d);
|
|
assert!(r.is_ok());
|
|
assert!(r.is_ok());
|
|
|
|
|
|
- let x = match r.unwrap() {
|
|
|
|
|
|
+ let x = match r.unwrap().1 {
|
|
Value::Boolean(x) => x,
|
|
Value::Boolean(x) => x,
|
|
_ => panic!("Unxpected type"),
|
|
_ => panic!("Unxpected type"),
|
|
};
|
|
};
|
|
@@ -293,20 +304,18 @@ mod test {
|
|
#[test]
|
|
#[test]
|
|
fn test_parse_boolean_unexpected() {
|
|
fn test_parse_boolean_unexpected() {
|
|
let d = b"#1\r\n";
|
|
let d = b"#1\r\n";
|
|
- let mut p = Parser::new();
|
|
|
|
|
|
|
|
- assert_eq!(Err(Error::InvalidBoolean), p.parse(d));
|
|
|
|
|
|
+ assert_eq!(Err(Error::InvalidBoolean), parse(d));
|
|
}
|
|
}
|
|
|
|
|
|
#[test]
|
|
#[test]
|
|
fn test_parse_str() {
|
|
fn test_parse_str() {
|
|
let d = b"+hello world\r\n";
|
|
let d = b"+hello world\r\n";
|
|
- let mut p = Parser::new();
|
|
|
|
|
|
|
|
- let r = p.parse(d);
|
|
|
|
|
|
+ let r = parse(d);
|
|
assert!(r.is_ok());
|
|
assert!(r.is_ok());
|
|
|
|
|
|
- let x = match r.unwrap() {
|
|
|
|
|
|
+ let x = match r.unwrap().1 {
|
|
Value::String(x) => x,
|
|
Value::String(x) => x,
|
|
_ => panic!("Unxpected type"),
|
|
_ => panic!("Unxpected type"),
|
|
};
|
|
};
|
|
@@ -317,12 +326,11 @@ mod test {
|
|
#[test]
|
|
#[test]
|
|
fn test_parse_error() {
|
|
fn test_parse_error() {
|
|
let d = b"-ERR this is the error description\r\n";
|
|
let d = b"-ERR this is the error description\r\n";
|
|
- let mut p = Parser::new();
|
|
|
|
|
|
|
|
- let r = p.parse(d);
|
|
|
|
|
|
+ let r = parse(d);
|
|
assert!(r.is_ok());
|
|
assert!(r.is_ok());
|
|
|
|
|
|
- let x = match r.unwrap() {
|
|
|
|
|
|
+ let x = match r.unwrap().1 {
|
|
Value::Error(a, b) => (a, b),
|
|
Value::Error(a, b) => (a, b),
|
|
_ => panic!("Unxpected type"),
|
|
_ => panic!("Unxpected type"),
|
|
};
|
|
};
|