Pārlūkot izejas kodu

Rewrote everything as a function

Cesar Rodas 3 gadi atpakaļ
vecāks
revīzija
ff177d4d03
2 mainītis faili ar 172 papildinājumiem un 151 dzēšanām
  1. 132 124
      parser/src/lib.rs
  2. 40 27
      parser/src/macros.rs

+ 132 - 124
parser/src/lib.rs

@@ -1,15 +1,9 @@
-mod bytes;
 #[macro_use]
 mod macros;
 
-use bytes::Bytes;
 use std::convert::TryInto;
 
-pub struct Parser {
-    pos: usize
-}
-
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Clone)]
 pub enum Value<'a> {
     Array(Vec<Value<'a>>),
     Blob(&'a [u8]),
@@ -22,10 +16,31 @@ pub enum Value<'a> {
     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 {
-            _ => 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,
 }
 
-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)]
@@ -142,51 +146,64 @@ mod test {
 
     #[test]
     fn test_parse_partial() {
-        let mut p = Parser::new();
         let d = b"*-1";
-        assert_eq!(Err(Error::Partial), p.parse(d));
+        assert_eq!(Err(Error::Partial), parse(d));
     }
 
     #[test]
     fn test_parse_partial_2() {
-        let mut p = Parser::new();
         let d = b"*12\r\n";
-        assert_eq!(Err(Error::Partial), p.parse(d));
+        assert_eq!(Err(Error::Partial), parse(d));
     }
 
     #[test]
     fn test_incomplete_blob_parsing() {
         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]
     fn test_complete_blob_parsing() {
         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());
 
-        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) },
             _ => "",
         };
 
         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 mut p = Parser::new();
 
-        let r = p.parse(d);
+        let r = parse(d);
         assert!(r.is_ok());
 
-        let x = match r.unwrap() {
+        let x = match r.unwrap().1 {
             Value::Array(x) => x,
             _ => panic!("Unxpected type"),
         };
@@ -197,12 +214,11 @@ mod test {
     #[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 mut p = Parser::new();
 
-        let r = p.parse(d);
+        let r = parse(d);
         assert!(r.is_ok());
 
-        let x = match r.unwrap() {
+        let x = match r.unwrap().1 {
             Value::Array(x) => x,
             _ => panic!("Unxpected type"),
         };
@@ -213,12 +229,11 @@ mod test {
     #[test]
     fn test_parse_float() {
         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());
 
-        let x = match r.unwrap() {
+        let x = match r.unwrap().1 {
             Value::Float(x) => x,
             _ => panic!("Unxpected type"),
         };
@@ -229,12 +244,11 @@ mod test {
     #[test]
     fn test_parse_integer() {
         let d = b":25887\r\n";
-        let mut p = Parser::new();
 
-        let r = p.parse(d);
+        let r = parse(d);
         assert!(r.is_ok());
 
-        let x = match r.unwrap() {
+        let x = match r.unwrap().1 {
             Value::Integer(x) => x,
             _ => panic!("Unxpected type"),
         };
@@ -245,12 +259,11 @@ mod test {
     #[test]
     fn test_parse_big_integer() {
         let d = b"(25887\r\n";
-        let mut p = Parser::new();
 
-        let r = p.parse(d);
+        let r = parse(d);
         assert!(r.is_ok());
 
-        let x = match r.unwrap() {
+        let x = match r.unwrap().1 {
             Value::BigInteger(x) => x,
             _ => panic!("Unxpected type"),
         };
@@ -261,12 +274,11 @@ mod test {
     #[test]
     fn test_parse_false() {
         let d = b"#f\r\n";
-        let mut p = Parser::new();
 
-        let r = p.parse(d);
+        let r = parse(d);
         assert!(r.is_ok());
 
-        let x = match r.unwrap() {
+        let x = match r.unwrap().1 {
             Value::Boolean(x) => x,
             _ => panic!("Unxpected type"),
         };
@@ -277,12 +289,11 @@ mod test {
     #[test]
     fn test_parse_true() {
         let d = b"#t\r\n";
-        let mut p = Parser::new();
 
-        let r = p.parse(d);
+        let r = parse(d);
         assert!(r.is_ok());
 
-        let x = match r.unwrap() {
+        let x = match r.unwrap().1 {
             Value::Boolean(x) => x,
             _ => panic!("Unxpected type"),
         };
@@ -293,20 +304,18 @@ mod test {
     #[test]
     fn test_parse_boolean_unexpected() {
         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]
     fn test_parse_str() {
         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());
 
-        let x = match r.unwrap() {
+        let x = match r.unwrap().1 {
             Value::String(x) => x,
             _ => panic!("Unxpected type"),
         };
@@ -317,12 +326,11 @@ mod test {
     #[test]
     fn test_parse_error() {
         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());
 
-        let x = match r.unwrap() {
+        let x = match r.unwrap().1 {
             Value::Error(a, b) => (a, b),
             _ => panic!("Unxpected type"),
         };

+ 40 - 27
parser/src/macros.rs

@@ -1,69 +1,82 @@
+macro_rules! ret {
+    ($bytes: ident, $value: expr) => {{
+        Ok(($bytes, $value))
+    }};
+}
 macro_rules! next {
-    ($self:ident, $bytes:ident) => {{
-        if $bytes.len() > $self.pos {
-            let b = unsafe { *$bytes.get_unchecked($self.pos) };
-            $self.pos += 1;
-            b
+    ($bytes:ident) => {{
+        let byte = if $bytes.len() > 0 {
+            unsafe { *$bytes.get_unchecked(0) }
         } else {
             return Err(Error::Partial);
-        }
+        };
+        (&$bytes[1..], byte)
     }};
 }
 
 macro_rules! read_len {
-    ($self:ident, $bytes:ident, $len:ident) => {{
+    ($bytes:ident, $len:ident) => {{
         let len: usize = $len.try_into().unwrap();
 
-        if ($bytes.len() - $self.pos < len) {
+        if ($bytes.len() < len) {
             return Err(Error::Partial);
         }
 
-        let start = $self.pos;
-
-        &$bytes[start..start + len]
+        (&$bytes[len..], &$bytes[0..len])
     }};
 }
 
 macro_rules! assert_nl {
-    ($self:ident, $bytes:ident) => {{
-        if (next!($self, $bytes) != b'\r' || next!($self, $bytes) != b'\n') {
+    ($bytes:ident) => {{
+        if ($bytes.len() < 2) {
+            return Err(Error::Partial);
+        }
+        if ($bytes[0] != b'\r' || $bytes[1] != b'\n') {
             return Err(Error::NewLine);
         }
+        &$bytes[2..]
     }};
 }
 
 macro_rules! read_until {
-    ($self:ident, $bytes:ident, $next:expr) => {{
-        let start = $self.pos;
+    ($bytes:ident, $next:expr) => {{
+        let len = $bytes.len();
+        let mut i = 0;
         loop {
-            if (next!($self, $bytes) == $next) {
+            if (i >= len) {
+                return Err(Error::Partial);
+            }
+
+            if ($bytes[i] == $next) {
                 break;
             }
+            i += 1;
         }
-        &$bytes[start..$self.pos - 1]
+        (&$bytes[i + 1..], &$bytes[0..i])
     }};
 }
 
 macro_rules! read_line {
-    ($self:ident, $bytes:ident) => {{
-        let start = $self.pos;
+    ($bytes:ident) => {{
+        let ($bytes, prev) = read_until!($bytes, b'\r');
+        let ($bytes, next) = next!($bytes);
 
-        read_until!($self, $bytes, b'\r');
-
-        if (next!($self, $bytes) != b'\n') {
+        if (next != b'\n') {
             return Err(Error::NewLine);
         }
 
-        &$bytes[start..$self.pos - 2]
+        ($bytes, prev)
     }};
 }
 
 macro_rules! read_line_number {
-    ($self:ident, $bytes:ident, $type:ident) => {{
-        let n = unsafe { std::str::from_utf8_unchecked(read_line!($self, $bytes)) };
-        match n.parse::<$type>() {
+    ($bytes:ident, $type:ident) => {{
+        let ($bytes, n) = read_line!($bytes);
+        let n = unsafe { std::str::from_utf8_unchecked(n) };
+        let n = match n.parse::<$type>() {
             Ok(x) => x,
             _ => return Err(Error::InvalidNumber),
-        }
+        };
+        ($bytes, n)
     }};
 }