td_rredis/
parser.rs

1use std::io::{Read, BufReader};
2
3use types::{RedisResult, Value, ErrorKind, make_extension_error};
4
5
6/// The internal redis response parser.
7pub struct Parser<T> {
8    reader: T,
9}
10
11/// The parser can be used to parse redis responses into values.  Generally
12/// you normally do not use this directly as it's already done for you by
13/// the client but in some more complex situations it might be useful to be
14/// able to parse the redis responses.
15impl<'a, T: Read> Parser<T> {
16    /// Creates a new parser that parses the data behind the reader.  More
17    /// than one value can be behind the reader in which case the parser can
18    /// be invoked multiple times.  In other words: the stream does not have
19    /// to be terminated.
20    pub fn new(reader: T) -> Parser<T> {
21        Parser { reader: reader }
22    }
23
24    // public api
25
26    /// parses a single value out of the stream.  If there are multiple
27    /// values you can call this multiple times.  If the reader is not yet
28    /// ready this will block.
29    pub fn parse_value(&mut self) -> RedisResult<Value> {
30        let b = try!(self.read_byte());
31        match b as char {
32            '+' => self.parse_status(),
33            ':' => self.parse_int(),
34            '$' => self.parse_data(),
35            '*' => self.parse_bulk(),
36            '-' => self.parse_error(),
37            _ => fail!((ErrorKind::PatternError, "Invalid response when parsing value")),
38        }
39    }
40
41    // internal helpers
42
43    #[inline]
44    fn expect_char(&mut self, refchar: char) -> RedisResult<()> {
45        if try!(self.read_byte()) as char == refchar {
46            Ok(())
47        } else {
48            fail!((ErrorKind::PatternError, "Invalid byte in response"));
49        }
50    }
51
52    #[inline]
53    fn expect_newline(&mut self) -> RedisResult<()> {
54        match try!(self.read_byte()) as char {
55            '\r' => self.expect_char('\n'),
56            _ => fail!((ErrorKind::PatternError, "Invalid byte in response")),
57        }
58    }
59
60    fn read_line(&mut self) -> RedisResult<Vec<u8>> {
61        let mut rv = vec![];
62
63        loop {
64            let b = try!(self.read_byte());
65            match b as char {
66                '\r' => {
67                    try!(self.expect_char('\n'));
68                    break;
69                }
70                _ => rv.push(b),
71            };
72        }
73
74        Ok(rv)
75    }
76
77    fn read_string_line(&mut self) -> RedisResult<String> {
78        match String::from_utf8(try!(self.read_line())) {
79            Err(_) => fail!((ErrorKind::PatternError, "Expected valid string, got garbage")),
80            Ok(value) => Ok(value),
81        }
82    }
83
84    fn read_byte(&mut self) -> RedisResult<u8> {
85        let buf: &mut [u8; 1] = &mut [0];
86        let nread = try!(self.reader.read(buf));
87
88        if nread < 1 {
89            fail!((ErrorKind::PatternError, "Could not read enough bytes"))
90        } else {
91            Ok(buf[0])
92        }
93    }
94
95    fn read(&mut self, bytes: usize) -> RedisResult<Vec<u8>> {
96        let mut rv = vec![0; bytes];
97        let mut i = 0;
98        while i < bytes {
99            let res_nread = {
100                let ref mut buf = &mut rv[i..];
101                self.reader.read(buf)
102            };
103            match res_nread {
104                Ok(nread) if nread > 0 => i += nread,
105                Ok(_) => return fail!((ErrorKind::PatternError, "Could not read enough bytes")),
106                Err(e) => return Err(From::from(e)),
107            }
108        }
109        Ok(rv)
110    }
111
112    fn read_int_line(&mut self) -> RedisResult<i64> {
113        let line = try!(self.read_string_line());
114        match line.trim().parse::<i64>() {
115            Err(_) => fail!((ErrorKind::PatternError, "Expected integer, got garbage")),
116            Ok(value) => Ok(value),
117        }
118    }
119
120    fn parse_status(&mut self) -> RedisResult<Value> {
121        let line = try!(self.read_string_line());
122        if line == "OK" {
123            Ok(Value::Okay)
124        } else {
125            Ok(Value::Status(line))
126        }
127    }
128
129    fn parse_int(&mut self) -> RedisResult<Value> {
130        Ok(Value::Int(try!(self.read_int_line())))
131    }
132
133    fn parse_data(&mut self) -> RedisResult<Value> {
134        let length = try!(self.read_int_line());
135        if length < 0 {
136            Ok(Value::Nil)
137        } else {
138            let data = try!(self.read(length as usize));
139            try!(self.expect_newline());
140            Ok(Value::Data(data))
141        }
142    }
143
144    fn parse_bulk(&mut self) -> RedisResult<Value> {
145        let length = try!(self.read_int_line());
146        if length < 0 {
147            Ok(Value::Nil)
148        } else {
149            let mut rv = vec![];
150            rv.reserve(length as usize);
151            for _ in 0..length {
152                rv.push(try!(self.parse_value()));
153            }
154            Ok(Value::Bulk(rv))
155        }
156    }
157
158    fn parse_error(&mut self) -> RedisResult<Value> {
159        let desc = "An error was signalled by the server";
160        let line = try!(self.read_string_line());
161        let mut pieces = line.splitn(2, ' ');
162        let kind = match pieces.next().unwrap() {
163            "ERR" => ErrorKind::ResponseError,
164            "EXECABORT" => ErrorKind::ExecAbortError,
165            "LOADING" => ErrorKind::BusyLoadingError,
166            "NOSCRIPT" => ErrorKind::NoScriptError,
167            code => {
168                fail!(make_extension_error(code, pieces.next()));
169            }
170        };
171        match pieces.next() {
172            Some(detail) => fail!((kind, desc, detail.to_string())),
173            None => fail!((kind, desc)),
174        }
175    }
176}
177
178
179/// Parses bytes into a redis value.
180///
181/// This is the most straightforward way to parse something into a low
182/// level redis value instead of having to use a whole parser.
183pub fn parse_redis_value(bytes: &[u8]) -> RedisResult<Value> {
184    let mut parser = Parser::new(BufReader::new(bytes));
185    parser.parse_value()
186}