1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
use super::Value;
use std::str::FromStr;
use nom::{crlf, digit, not_line_ending};

/// Core parser implementation.
pub struct Parser;

impl Parser {
    /// Parses RESP from a byte buffer.
    pub fn parse(data: &[u8]) -> Result<(&[u8], Value), ::nom::Err<&[u8]>> {
        named!(
            read_line<&str>,
            do_parse!(line: map_res!(not_line_ending, ::std::str::from_utf8) >> crlf >> (line))
        );

        named!(
            int<i64>,
            do_parse!(
                neg: opt!(tag!("-"))
                    >> value: map_res!(map_res!(digit, ::std::str::from_utf8), i64::from_str)
                    >> (if neg == None { value } else { -value })
            )
        );

        named!(
            parse_int<Value>,
            preceded!(
                tag!(":"),
                do_parse!(datum: int >> crlf >> (Value::Int(datum)))
            )
        );

        named!(
            parse_str<Value>,
            preceded!(
                tag!("+"),
                do_parse!(datum: read_line >> (Value::str(datum)))
            )
        );

        named!(
            parse_err<Value>,
            preceded!(
                tag!("-"),
                do_parse!(datum: read_line >> (Value::err(datum)))
            )
        );

        named!(
            parse_bstr<Value>,
            preceded!(
                tag!("$"),
                do_parse!(
                    len: int >> crlf >> datum: cond_with_error!(len > -1, take_str!(len))
                        >> cond_with_error!(len > -1, crlf)
                        >> (Value::b_str(datum))
                )
            )
        );

        named!(
            parse_array<Value>,
            preceded!(
                tag!("*"),
                do_parse!(
                    len: int >> crlf
                        >> data: cond_with_error!(len > -1, count!(parse_resp, len as usize))
                        >> (Value::Array(data))
                )
            )
        );

        named!(
            parse_resp<Value>,
            alt!(parse_int | parse_str | parse_err | parse_bstr | parse_array)
        );

        parse_resp(data)
    }

    /// Parses a RESP encoded string.
    ///
    /// # Examples
    ///
    /// ```
    /// use lib_resp::Parser;
    ///
    /// let age = Parser::parse_str(":-3").unwrap();
    ///
    /// println!("{:?}", age);
    /// ```
    pub fn parse_str(resp: &str) -> Result<Option<Value>, ()> {
        match Parser::parse(resp.as_bytes()) {
            Ok((_i, o)) => Ok(Some(o)),
            Err(e) => {
                if e.is_incomplete() {
                    Ok(None)
                } else {
                    Err(())
                }
            }
        }
    }
}