redis_oxide/protocol/
resp2.rs1use crate::core::{
7 error::{RedisError, RedisResult},
8 value::RespValue,
9};
10use bytes::{Buf, BufMut, Bytes, BytesMut};
11use std::io::Cursor;
12
13const CRLF: &[u8] = b"\r\n";
14
15pub struct RespEncoder;
17
18impl RespEncoder {
19 pub fn encode(value: &RespValue, buf: &mut BytesMut) -> RedisResult<()> {
21 match value {
22 RespValue::SimpleString(s) => {
23 buf.put_u8(b'+');
24 buf.put_slice(s.as_bytes());
25 buf.put_slice(CRLF);
26 }
27 RespValue::Error(e) => {
28 buf.put_u8(b'-');
29 buf.put_slice(e.as_bytes());
30 buf.put_slice(CRLF);
31 }
32 RespValue::Integer(i) => {
33 buf.put_u8(b':');
34 buf.put_slice(i.to_string().as_bytes());
35 buf.put_slice(CRLF);
36 }
37 RespValue::BulkString(data) => {
38 buf.put_u8(b'$');
39 buf.put_slice(data.len().to_string().as_bytes());
40 buf.put_slice(CRLF);
41 buf.put_slice(data);
42 buf.put_slice(CRLF);
43 }
44 RespValue::Null => {
45 buf.put_slice(b"$-1\r\n");
46 }
47 RespValue::Array(arr) => {
48 buf.put_u8(b'*');
49 buf.put_slice(arr.len().to_string().as_bytes());
50 buf.put_slice(CRLF);
51 for item in arr {
52 Self::encode(item, buf)?;
53 }
54 }
55 }
56 Ok(())
57 }
58
59 fn encode_bulk_argument(data: &[u8], buf: &mut BytesMut) {
60 buf.put_u8(b'$');
61 buf.put_slice(data.len().to_string().as_bytes());
62 buf.put_slice(CRLF);
63 buf.put_slice(data);
64 buf.put_slice(CRLF);
65 }
66
67 fn encode_command_arg(arg: &RespValue, buf: &mut BytesMut) -> RedisResult<()> {
68 match arg {
69 RespValue::SimpleString(s) | RespValue::Error(s) => {
70 Self::encode_bulk_argument(s.as_bytes(), buf);
71 }
72 RespValue::Integer(i) => {
73 Self::encode_bulk_argument(i.to_string().as_bytes(), buf);
74 }
75 RespValue::BulkString(data) => {
76 Self::encode_bulk_argument(data, buf);
77 }
78 RespValue::Null => {
79 buf.put_slice(b"$-1\r\n");
80 }
81 RespValue::Array(_) => {
82 Self::encode(arg, buf)?;
83 }
84 }
85 Ok(())
86 }
87
88 pub fn encode_command(command: &str, args: &[RespValue]) -> RedisResult<Bytes> {
90 let mut buf = BytesMut::new();
91
92 let total_len = 1 + args.len();
94 buf.put_u8(b'*');
95 buf.put_slice(total_len.to_string().as_bytes());
96 buf.put_slice(CRLF);
97
98 buf.put_u8(b'$');
100 buf.put_slice(command.len().to_string().as_bytes());
101 buf.put_slice(CRLF);
102 buf.put_slice(command.as_bytes());
103 buf.put_slice(CRLF);
104
105 for arg in args {
107 Self::encode_command_arg(arg, &mut buf)?;
108 }
109
110 Ok(buf.freeze())
111 }
112}
113
114pub struct RespDecoder;
116
117impl RespDecoder {
118 pub fn decode(buf: &mut Cursor<&[u8]>) -> RedisResult<Option<RespValue>> {
120 if !buf.has_remaining() {
121 return Ok(None);
122 }
123
124 let type_byte = buf.chunk()[0];
125
126 match type_byte {
127 b'+' => Self::decode_simple_string(buf),
128 b'-' => Self::decode_error(buf),
129 b':' => Self::decode_integer(buf),
130 b'$' => Self::decode_bulk_string(buf),
131 b'*' => Self::decode_array(buf),
132 _ => Err(RedisError::Protocol(format!(
133 "Invalid RESP type byte: {}",
134 type_byte as char
135 ))),
136 }
137 }
138
139 fn decode_simple_string(buf: &mut Cursor<&[u8]>) -> RedisResult<Option<RespValue>> {
140 buf.advance(1); if let Some(line) = Self::read_line(buf)? {
143 Ok(Some(RespValue::SimpleString(
144 String::from_utf8(line.to_vec())
145 .map_err(|e| RedisError::Protocol(format!("Invalid UTF-8: {}", e)))?,
146 )))
147 } else {
148 Ok(None)
149 }
150 }
151
152 fn decode_error(buf: &mut Cursor<&[u8]>) -> RedisResult<Option<RespValue>> {
153 buf.advance(1); if let Some(line) = Self::read_line(buf)? {
156 Ok(Some(RespValue::Error(
157 String::from_utf8(line.to_vec())
158 .map_err(|e| RedisError::Protocol(format!("Invalid UTF-8: {}", e)))?,
159 )))
160 } else {
161 Ok(None)
162 }
163 }
164
165 fn decode_integer(buf: &mut Cursor<&[u8]>) -> RedisResult<Option<RespValue>> {
166 buf.advance(1); if let Some(line) = Self::read_line(buf)? {
169 let num_str = String::from_utf8(line.to_vec())
170 .map_err(|e| RedisError::Protocol(format!("Invalid UTF-8: {}", e)))?;
171 let num = num_str
172 .parse::<i64>()
173 .map_err(|e| RedisError::Protocol(format!("Invalid integer: {}", e)))?;
174 Ok(Some(RespValue::Integer(num)))
175 } else {
176 Ok(None)
177 }
178 }
179
180 fn decode_bulk_string(buf: &mut Cursor<&[u8]>) -> RedisResult<Option<RespValue>> {
181 buf.advance(1); let len_line = match Self::read_line(buf)? {
184 Some(line) => line,
185 None => return Ok(None),
186 };
187
188 let len_str = String::from_utf8(len_line.to_vec())
189 .map_err(|e| RedisError::Protocol(format!("Invalid UTF-8: {}", e)))?;
190 let len = len_str
191 .parse::<i64>()
192 .map_err(|e| RedisError::Protocol(format!("Invalid bulk string length: {}", e)))?;
193
194 if len == -1 {
195 return Ok(Some(RespValue::Null));
196 }
197
198 let len = len as usize;
199
200 if buf.remaining() < len + 2 {
202 return Ok(None);
203 }
204
205 let data = buf.chunk()[..len].to_vec();
206 buf.advance(len);
207
208 if buf.remaining() < 2 {
210 return Ok(None);
211 }
212 buf.advance(2);
213
214 Ok(Some(RespValue::BulkString(Bytes::from(data))))
215 }
216
217 fn decode_array(buf: &mut Cursor<&[u8]>) -> RedisResult<Option<RespValue>> {
218 buf.advance(1); let len_line = match Self::read_line(buf)? {
221 Some(line) => line,
222 None => return Ok(None),
223 };
224
225 let len_str = String::from_utf8(len_line.to_vec())
226 .map_err(|e| RedisError::Protocol(format!("Invalid UTF-8: {}", e)))?;
227 let len = len_str
228 .parse::<i64>()
229 .map_err(|e| RedisError::Protocol(format!("Invalid array length: {}", e)))?;
230
231 if len == -1 {
232 return Ok(Some(RespValue::Null));
233 }
234
235 let len = len as usize;
236 let mut arr = Vec::with_capacity(len);
237
238 for _ in 0..len {
239 match Self::decode(buf)? {
240 Some(value) => arr.push(value),
241 None => return Ok(None),
242 }
243 }
244
245 Ok(Some(RespValue::Array(arr)))
246 }
247
248 fn read_line(buf: &mut Cursor<&[u8]>) -> RedisResult<Option<Vec<u8>>> {
249 let start = buf.position() as usize;
250 let slice = buf.get_ref();
251
252 for i in start..slice.len().saturating_sub(1) {
254 if slice[i] == b'\r' && slice[i + 1] == b'\n' {
255 let line = slice[start..i].to_vec();
256 buf.set_position((i + 2) as u64);
257 return Ok(Some(line));
258 }
259 }
260
261 Ok(None)
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use super::*;
268
269 #[test]
270 fn test_encode_simple_string() {
271 let mut buf = BytesMut::new();
272 let value = RespValue::SimpleString("OK".to_string());
273 RespEncoder::encode(&value, &mut buf).unwrap();
274 assert_eq!(&buf[..], b"+OK\r\n");
275 }
276
277 #[test]
278 fn test_encode_error() {
279 let mut buf = BytesMut::new();
280 let value = RespValue::Error("ERR unknown command".to_string());
281 RespEncoder::encode(&value, &mut buf).unwrap();
282 assert_eq!(&buf[..], b"-ERR unknown command\r\n");
283 }
284
285 #[test]
286 fn test_encode_integer() {
287 let mut buf = BytesMut::new();
288 let value = RespValue::Integer(1000);
289 RespEncoder::encode(&value, &mut buf).unwrap();
290 assert_eq!(&buf[..], b":1000\r\n");
291 }
292
293 #[test]
294 fn test_encode_bulk_string() {
295 let mut buf = BytesMut::new();
296 let value = RespValue::BulkString(Bytes::from("foobar"));
297 RespEncoder::encode(&value, &mut buf).unwrap();
298 assert_eq!(&buf[..], b"$6\r\nfoobar\r\n");
299 }
300
301 #[test]
302 fn test_encode_null() {
303 let mut buf = BytesMut::new();
304 let value = RespValue::Null;
305 RespEncoder::encode(&value, &mut buf).unwrap();
306 assert_eq!(&buf[..], b"$-1\r\n");
307 }
308
309 #[test]
310 fn test_encode_array() {
311 let mut buf = BytesMut::new();
312 let value = RespValue::Array(vec![
313 RespValue::BulkString(Bytes::from("foo")),
314 RespValue::BulkString(Bytes::from("bar")),
315 ]);
316 RespEncoder::encode(&value, &mut buf).unwrap();
317 assert_eq!(&buf[..], b"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n");
318 }
319
320 #[test]
321 fn test_encode_command() {
322 let bytes =
323 RespEncoder::encode_command("GET", &[RespValue::BulkString(Bytes::from("mykey"))])
324 .unwrap();
325 assert_eq!(&bytes[..], b"*2\r\n$3\r\nGET\r\n$5\r\nmykey\r\n");
326 }
327
328 #[test]
329 fn test_encode_command_arguments_are_bulk_strings() {
330 let bytes = RespEncoder::encode_command(
331 "LRANGE",
332 &[
333 RespValue::from("items"),
334 RespValue::from(0),
335 RespValue::from(-1),
336 ],
337 )
338 .unwrap();
339
340 assert_eq!(
341 &bytes[..],
342 b"*4\r\n$6\r\nLRANGE\r\n$5\r\nitems\r\n$1\r\n0\r\n$2\r\n-1\r\n"
343 );
344 }
345
346 #[test]
347 fn test_decode_simple_string() {
348 let data = b"+OK\r\n";
349 let mut cursor = Cursor::new(&data[..]);
350 let value = RespDecoder::decode(&mut cursor).unwrap().unwrap();
351 assert_eq!(value, RespValue::SimpleString("OK".to_string()));
352 }
353
354 #[test]
355 fn test_decode_error() {
356 let data = b"-ERR unknown\r\n";
357 let mut cursor = Cursor::new(&data[..]);
358 let value = RespDecoder::decode(&mut cursor).unwrap().unwrap();
359 assert_eq!(value, RespValue::Error("ERR unknown".to_string()));
360 }
361
362 #[test]
363 fn test_decode_integer() {
364 let data = b":1000\r\n";
365 let mut cursor = Cursor::new(&data[..]);
366 let value = RespDecoder::decode(&mut cursor).unwrap().unwrap();
367 assert_eq!(value, RespValue::Integer(1000));
368 }
369
370 #[test]
371 fn test_decode_bulk_string() {
372 let data = b"$6\r\nfoobar\r\n";
373 let mut cursor = Cursor::new(&data[..]);
374 let value = RespDecoder::decode(&mut cursor).unwrap().unwrap();
375 assert_eq!(value, RespValue::BulkString(Bytes::from("foobar")));
376 }
377
378 #[test]
379 fn test_decode_null() {
380 let data = b"$-1\r\n";
381 let mut cursor = Cursor::new(&data[..]);
382 let value = RespDecoder::decode(&mut cursor).unwrap().unwrap();
383 assert_eq!(value, RespValue::Null);
384 }
385
386 #[test]
387 fn test_decode_array() {
388 let data = b"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n";
389 let mut cursor = Cursor::new(&data[..]);
390 let value = RespDecoder::decode(&mut cursor).unwrap().unwrap();
391 assert_eq!(
392 value,
393 RespValue::Array(vec![
394 RespValue::BulkString(Bytes::from("foo")),
395 RespValue::BulkString(Bytes::from("bar")),
396 ])
397 );
398 }
399
400 #[test]
401 fn test_decode_incomplete_data() {
402 let data = b"+OK\r";
403 let mut cursor = Cursor::new(&data[..]);
404 let result = RespDecoder::decode(&mut cursor).unwrap();
405 assert!(result.is_none());
406 }
407
408 #[test]
409 fn test_roundtrip() {
410 let original = RespValue::Array(vec![
411 RespValue::SimpleString("OK".to_string()),
412 RespValue::Integer(42),
413 RespValue::BulkString(Bytes::from("test")),
414 RespValue::Null,
415 ]);
416
417 let mut buf = BytesMut::new();
418 RespEncoder::encode(&original, &mut buf).unwrap();
419
420 let mut cursor = Cursor::new(&buf[..]);
421 let decoded = RespDecoder::decode(&mut cursor).unwrap().unwrap();
422
423 assert_eq!(original, decoded);
424 }
425}