redis_oxide/protocol/
resp3.rs

1//! RESP3 (Redis Serialization Protocol version 3) implementation
2//!
3//! RESP3 is the new protocol introduced in Redis 6.0 that extends RESP2 with
4//! additional data types and improved semantics. This module provides full
5//! RESP3 support while maintaining backward compatibility with RESP2.
6//!
7//! # New RESP3 Data Types
8//!
9//! - **Map**: Key-value pairs (similar to hash tables)
10//! - **Set**: Unordered collection of unique elements
11//! - **Attribute**: Metadata attached to other types
12//! - **Push**: Server-initiated messages (pub/sub, monitoring)
13//! - **Boolean**: True/false values
14//! - **Double**: IEEE 754 floating point numbers
15//! - **BigNumber**: Arbitrary precision numbers
16//! - **VerbatimString**: Strings with encoding information
17//! - **Null**: Explicit null value
18//!
19//! # Examples
20//!
21//! ```no_run
22//! use redis_oxide::protocol::resp3::{Resp3Value, Resp3Encoder, Resp3Decoder};
23//! use std::collections::HashMap;
24//!
25//! // Create a RESP3 map
26//! let mut map = HashMap::new();
27//! map.insert("name".to_string(), Resp3Value::BlobString("Alice".to_string()));
28//! map.insert("age".to_string(), Resp3Value::Number(30));
29//! let value = Resp3Value::Map(map);
30//!
31//! // Encode to bytes
32//! let mut encoder = Resp3Encoder::new();
33//! let encoded = encoder.encode(&value)?;
34//!
35//! // Decode back
36//! let mut decoder = Resp3Decoder::new();
37//! let decoded = decoder.decode(&encoded)?;
38//! # Ok::<(), Box<dyn std::error::Error>>(())
39//! ```
40
41use crate::core::{
42    error::{RedisError, RedisResult},
43    value::RespValue,
44};
45use bytes::{Buf, BufMut, Bytes, BytesMut};
46use std::collections::{HashMap, HashSet};
47use std::io::Cursor;
48
49/// RESP3 protocol data types
50#[derive(Debug, Clone, PartialEq)]
51pub enum Resp3Value {
52    /// Simple string: +OK\r\n
53    SimpleString(String),
54    /// Simple error: -ERR message\r\n
55    SimpleError(String),
56    /// Number (integer): :123\r\n
57    Number(i64),
58    /// Blob string: $5\r\nhello\r\n
59    BlobString(String),
60    /// Array: *3\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$3\r\nbaz\r\n
61    Array(Vec<Resp3Value>),
62    /// Null: _\r\n
63    Null,
64    /// Boolean: #t\r\n or #f\r\n
65    Boolean(bool),
66    /// Double: ,1.23\r\n
67    Double(f64),
68    /// Big number: (3492890328409238509324850943850943825024385\r\n
69    BigNumber(String),
70    /// Blob error: !21\r\nSYNTAX invalid syntax\r\n
71    BlobError(String),
72    /// Verbatim string: =15\r\ntxt:Some string\r\n
73    VerbatimString {
74        /// The encoding type (e.g., "txt", "mkd")
75        encoding: String,
76        /// The actual string data
77        data: String,
78    },
79    /// Map: %2\r\n+first\r\n:1\r\n+second\r\n:2\r\n
80    Map(HashMap<String, Resp3Value>),
81    /// Set: ~3\r\n+orange\r\n+apple\r\n+one\r\n
82    Set(HashSet<Resp3Value>),
83    /// Attribute: |1\r\n+ttl\r\n:3600\r\n+key\r\n+value\r\n
84    Attribute {
85        /// The attribute key-value pairs
86        attrs: HashMap<String, Resp3Value>,
87        /// The actual data with attributes attached
88        data: Box<Resp3Value>,
89    },
90    /// Push: >4\r\n+pubsub\r\n+message\r\n+channel\r\n+hello\r\n
91    Push(Vec<Resp3Value>),
92}
93
94impl std::hash::Hash for Resp3Value {
95    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
96        match self {
97            Self::SimpleString(s) => {
98                0u8.hash(state);
99                s.hash(state);
100            }
101            Self::SimpleError(s) => {
102                1u8.hash(state);
103                s.hash(state);
104            }
105            Self::Number(n) => {
106                2u8.hash(state);
107                n.hash(state);
108            }
109            Self::BlobString(s) => {
110                3u8.hash(state);
111                s.hash(state);
112            }
113            Self::Array(arr) => {
114                4u8.hash(state);
115                arr.hash(state);
116            }
117            Self::Null => {
118                5u8.hash(state);
119            }
120            Self::Boolean(b) => {
121                6u8.hash(state);
122                b.hash(state);
123            }
124            Self::Double(f) => {
125                7u8.hash(state);
126                f.to_bits().hash(state);
127            }
128            Self::BigNumber(s) => {
129                8u8.hash(state);
130                s.hash(state);
131            }
132            Self::BlobError(s) => {
133                9u8.hash(state);
134                s.hash(state);
135            }
136            Self::VerbatimString { encoding, data } => {
137                10u8.hash(state);
138                encoding.hash(state);
139                data.hash(state);
140            }
141            Self::Map(map) => {
142                11u8.hash(state);
143                // Hash maps in a deterministic way
144                let mut pairs: Vec<_> = map.iter().collect();
145                pairs.sort_by_key(|(k, _)| *k);
146                pairs.hash(state);
147            }
148            Self::Set(set) => {
149                12u8.hash(state);
150                // Hash sets in a deterministic way
151                let mut items: Vec<_> = set.iter().collect();
152                items.sort_by(|a, b| format!("{:?}", a).cmp(&format!("{:?}", b)));
153                items.hash(state);
154            }
155            Self::Attribute { attrs, data } => {
156                13u8.hash(state);
157                let mut pairs: Vec<_> = attrs.iter().collect();
158                pairs.sort_by_key(|(k, _)| *k);
159                pairs.hash(state);
160                data.hash(state);
161            }
162            Self::Push(arr) => {
163                14u8.hash(state);
164                arr.hash(state);
165            }
166        }
167    }
168}
169
170impl Eq for Resp3Value {}
171
172impl Resp3Value {
173    /// Convert to a string if possible
174    ///
175    /// # Errors
176    ///
177    /// Returns an error if the value cannot be converted to a string.
178    pub fn as_string(&self) -> RedisResult<String> {
179        match self {
180            Self::SimpleString(s) | Self::BlobString(s) => Ok(s.clone()),
181            Self::VerbatimString { data, .. } => Ok(data.clone()),
182            Self::Number(n) => Ok(n.to_string()),
183            Self::Double(f) => Ok(f.to_string()),
184            Self::Boolean(b) => Ok(b.to_string()),
185            Self::BigNumber(s) => Ok(s.clone()),
186            Self::Null => Err(RedisError::Type("Value is null".to_string())),
187            _ => Err(RedisError::Type(format!(
188                "Cannot convert {:?} to string",
189                self
190            ))),
191        }
192    }
193
194    /// Convert to an integer if possible
195    ///
196    /// # Errors
197    ///
198    /// Returns an error if the value cannot be converted to an integer.
199    pub fn as_int(&self) -> RedisResult<i64> {
200        match self {
201            Self::Number(n) => Ok(*n),
202            Self::SimpleString(s) | Self::BlobString(s) => s
203                .parse::<i64>()
204                .map_err(|e| RedisError::Type(format!("Cannot parse '{}' to i64: {}", s, e))),
205            Self::Double(f) => Ok(*f as i64),
206            Self::Boolean(true) => Ok(1),
207            Self::Boolean(false) => Ok(0),
208            _ => Err(RedisError::Type(format!(
209                "Cannot convert {:?} to integer",
210                self
211            ))),
212        }
213    }
214
215    /// Convert to a float if possible
216    ///
217    /// # Errors
218    ///
219    /// Returns an error if the value cannot be converted to a float.
220    pub fn as_float(&self) -> RedisResult<f64> {
221        match self {
222            Self::Double(f) => Ok(*f),
223            Self::Number(n) => Ok(*n as f64),
224            Self::SimpleString(s) | Self::BlobString(s) => s
225                .parse::<f64>()
226                .map_err(|e| RedisError::Type(format!("Cannot parse '{}' to f64: {}", s, e))),
227            _ => Err(RedisError::Type(format!(
228                "Cannot convert {:?} to float",
229                self
230            ))),
231        }
232    }
233
234    /// Convert to a boolean if possible
235    ///
236    /// # Errors
237    ///
238    /// Returns an error if the value cannot be converted to a boolean.
239    pub fn as_bool(&self) -> RedisResult<bool> {
240        match self {
241            Self::Boolean(b) => Ok(*b),
242            Self::Number(1) => Ok(true),
243            Self::Number(0) => Ok(false),
244            Self::SimpleString(s) if s == "OK" => Ok(true),
245            _ => Err(RedisError::Type(format!(
246                "Cannot convert {:?} to bool",
247                self
248            ))),
249        }
250    }
251
252    /// Check if the value is null
253    #[must_use]
254    pub const fn is_null(&self) -> bool {
255        matches!(self, Self::Null)
256    }
257
258    /// Get the type name of the value
259    #[must_use]
260    pub const fn type_name(&self) -> &'static str {
261        match self {
262            Self::SimpleString(_) => "simple-string",
263            Self::SimpleError(_) => "simple-error",
264            Self::Number(_) => "number",
265            Self::BlobString(_) => "blob-string",
266            Self::Array(_) => "array",
267            Self::Null => "null",
268            Self::Boolean(_) => "boolean",
269            Self::Double(_) => "double",
270            Self::BigNumber(_) => "big-number",
271            Self::BlobError(_) => "blob-error",
272            Self::VerbatimString { .. } => "verbatim-string",
273            Self::Map(_) => "map",
274            Self::Set(_) => "set",
275            Self::Attribute { .. } => "attribute",
276            Self::Push(_) => "push",
277        }
278    }
279}
280
281/// Convert RESP3 value to RESP2 value for backward compatibility
282impl From<Resp3Value> for RespValue {
283    fn from(value: Resp3Value) -> Self {
284        match value {
285            Resp3Value::SimpleString(s) => Self::SimpleString(s),
286            Resp3Value::SimpleError(s) => Self::Error(s),
287            Resp3Value::Number(n) => Self::Integer(n),
288            Resp3Value::BlobString(s) => Self::BulkString(Bytes::from(s.into_bytes())),
289            Resp3Value::Array(arr) => Self::Array(arr.into_iter().map(Into::into).collect()),
290            Resp3Value::Null => Self::Null,
291            Resp3Value::Boolean(true) => Self::Integer(1),
292            Resp3Value::Boolean(false) => Self::Integer(0),
293            Resp3Value::Double(f) => Self::BulkString(Bytes::from(f.to_string().into_bytes())),
294            Resp3Value::BigNumber(s) => Self::BulkString(Bytes::from(s.into_bytes())),
295            Resp3Value::BlobError(s) => Self::Error(s),
296            Resp3Value::VerbatimString { data, .. } => {
297                Self::BulkString(Bytes::from(data.into_bytes()))
298            }
299            Resp3Value::Map(map) => {
300                let mut arr = Vec::new();
301                for (k, v) in map {
302                    arr.push(Self::BulkString(Bytes::from(k.into_bytes())));
303                    arr.push(v.into());
304                }
305                Self::Array(arr)
306            }
307            Resp3Value::Set(set) => Self::Array(set.into_iter().map(Into::into).collect()),
308            Resp3Value::Attribute { data, .. } => (*data).into(),
309            Resp3Value::Push(arr) => Self::Array(arr.into_iter().map(Into::into).collect()),
310        }
311    }
312}
313
314/// Convert RESP2 value to RESP3 value
315impl From<RespValue> for Resp3Value {
316    fn from(value: RespValue) -> Self {
317        match value {
318            RespValue::SimpleString(s) => Self::SimpleString(s),
319            RespValue::Error(s) => Self::SimpleError(s),
320            RespValue::Integer(n) => Self::Number(n),
321            RespValue::BulkString(b) => Self::BlobString(String::from_utf8_lossy(&b).to_string()),
322            RespValue::Array(arr) => Self::Array(arr.into_iter().map(Into::into).collect()),
323            RespValue::Null => Self::Null,
324        }
325    }
326}
327
328/// RESP3 protocol encoder
329pub struct Resp3Encoder {
330    buffer: BytesMut,
331}
332
333impl Resp3Encoder {
334    /// Create a new RESP3 encoder
335    #[must_use]
336    pub fn new() -> Self {
337        Self {
338            buffer: BytesMut::new(),
339        }
340    }
341
342    /// Encode a RESP3 value to bytes
343    ///
344    /// # Errors
345    ///
346    /// Returns an error if encoding fails.
347    pub fn encode(&mut self, value: &Resp3Value) -> RedisResult<Bytes> {
348        self.buffer.clear();
349        self.encode_value(value)?;
350        Ok(self.buffer.split().freeze())
351    }
352
353    fn encode_value(&mut self, value: &Resp3Value) -> RedisResult<()> {
354        match value {
355            Resp3Value::SimpleString(s) => {
356                self.buffer.put_u8(b'+');
357                self.buffer.extend_from_slice(s.as_bytes());
358                self.buffer.extend_from_slice(b"\r\n");
359            }
360            Resp3Value::SimpleError(s) => {
361                self.buffer.put_u8(b'-');
362                self.buffer.extend_from_slice(s.as_bytes());
363                self.buffer.extend_from_slice(b"\r\n");
364            }
365            Resp3Value::Number(n) => {
366                self.buffer.put_u8(b':');
367                self.buffer.extend_from_slice(n.to_string().as_bytes());
368                self.buffer.extend_from_slice(b"\r\n");
369            }
370            Resp3Value::BlobString(s) => {
371                self.buffer.put_u8(b'$');
372                self.buffer
373                    .extend_from_slice(s.len().to_string().as_bytes());
374                self.buffer.extend_from_slice(b"\r\n");
375                self.buffer.extend_from_slice(s.as_bytes());
376                self.buffer.extend_from_slice(b"\r\n");
377            }
378            Resp3Value::Array(arr) => {
379                self.buffer.put_u8(b'*');
380                self.buffer
381                    .extend_from_slice(arr.len().to_string().as_bytes());
382                self.buffer.extend_from_slice(b"\r\n");
383                for item in arr {
384                    self.encode_value(item)?;
385                }
386            }
387            Resp3Value::Null => {
388                self.buffer.extend_from_slice(b"_\r\n");
389            }
390            Resp3Value::Boolean(b) => {
391                self.buffer.put_u8(b'#');
392                self.buffer.put_u8(if *b { b't' } else { b'f' });
393                self.buffer.extend_from_slice(b"\r\n");
394            }
395            Resp3Value::Double(f) => {
396                self.buffer.put_u8(b',');
397                self.buffer.extend_from_slice(f.to_string().as_bytes());
398                self.buffer.extend_from_slice(b"\r\n");
399            }
400            Resp3Value::BigNumber(s) => {
401                self.buffer.put_u8(b'(');
402                self.buffer.extend_from_slice(s.as_bytes());
403                self.buffer.extend_from_slice(b"\r\n");
404            }
405            Resp3Value::BlobError(s) => {
406                self.buffer.put_u8(b'!');
407                self.buffer
408                    .extend_from_slice(s.len().to_string().as_bytes());
409                self.buffer.extend_from_slice(b"\r\n");
410                self.buffer.extend_from_slice(s.as_bytes());
411                self.buffer.extend_from_slice(b"\r\n");
412            }
413            Resp3Value::VerbatimString { encoding, data } => {
414                let content = format!("{}:{}", encoding, data);
415                self.buffer.put_u8(b'=');
416                self.buffer
417                    .extend_from_slice(content.len().to_string().as_bytes());
418                self.buffer.extend_from_slice(b"\r\n");
419                self.buffer.extend_from_slice(content.as_bytes());
420                self.buffer.extend_from_slice(b"\r\n");
421            }
422            Resp3Value::Map(map) => {
423                self.buffer.put_u8(b'%');
424                self.buffer
425                    .extend_from_slice(map.len().to_string().as_bytes());
426                self.buffer.extend_from_slice(b"\r\n");
427                for (k, v) in map {
428                    self.encode_value(&Resp3Value::BlobString(k.clone()))?;
429                    self.encode_value(v)?;
430                }
431            }
432            Resp3Value::Set(set) => {
433                self.buffer.put_u8(b'~');
434                self.buffer
435                    .extend_from_slice(set.len().to_string().as_bytes());
436                self.buffer.extend_from_slice(b"\r\n");
437                for item in set {
438                    self.encode_value(item)?;
439                }
440            }
441            Resp3Value::Attribute { attrs, data } => {
442                self.buffer.put_u8(b'|');
443                self.buffer
444                    .extend_from_slice(attrs.len().to_string().as_bytes());
445                self.buffer.extend_from_slice(b"\r\n");
446                for (k, v) in attrs {
447                    self.encode_value(&Resp3Value::BlobString(k.clone()))?;
448                    self.encode_value(v)?;
449                }
450                self.encode_value(data)?;
451            }
452            Resp3Value::Push(arr) => {
453                self.buffer.put_u8(b'>');
454                self.buffer
455                    .extend_from_slice(arr.len().to_string().as_bytes());
456                self.buffer.extend_from_slice(b"\r\n");
457                for item in arr {
458                    self.encode_value(item)?;
459                }
460            }
461        }
462        Ok(())
463    }
464}
465
466impl Default for Resp3Encoder {
467    fn default() -> Self {
468        Self::new()
469    }
470}
471
472/// RESP3 protocol decoder
473pub struct Resp3Decoder {
474    buffer: BytesMut,
475}
476
477impl Resp3Decoder {
478    /// Create a new RESP3 decoder
479    #[must_use]
480    pub fn new() -> Self {
481        Self {
482            buffer: BytesMut::new(),
483        }
484    }
485
486    /// Decode bytes into a RESP3 value
487    ///
488    /// # Errors
489    ///
490    /// Returns an error if decoding fails or data is incomplete.
491    pub fn decode(&mut self, data: &[u8]) -> RedisResult<Resp3Value> {
492        self.buffer.extend_from_slice(data);
493        let mut cursor = Cursor::new(&self.buffer[..]);
494        let value = self.decode_value(&mut cursor)?;
495        let consumed = cursor.position() as usize;
496        self.buffer.advance(consumed);
497        Ok(value)
498    }
499
500    fn decode_value(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
501        if !cursor.has_remaining() {
502            return Err(RedisError::Protocol("Incomplete data".to_string()));
503        }
504
505        let type_byte = cursor.get_u8();
506        match type_byte {
507            b'+' => self.decode_simple_string(cursor),
508            b'-' => self.decode_simple_error(cursor),
509            b':' => self.decode_number(cursor),
510            b'$' => self.decode_blob_string(cursor),
511            b'*' => self.decode_array(cursor),
512            b'_' => self.decode_null(cursor),
513            b'#' => self.decode_boolean(cursor),
514            b',' => self.decode_double(cursor),
515            b'(' => self.decode_big_number(cursor),
516            b'!' => self.decode_blob_error(cursor),
517            b'=' => self.decode_verbatim_string(cursor),
518            b'%' => self.decode_map(cursor),
519            b'~' => self.decode_set(cursor),
520            b'|' => self.decode_attribute(cursor),
521            b'>' => self.decode_push(cursor),
522            _ => Err(RedisError::Protocol(format!(
523                "Unknown RESP3 type byte: {}",
524                type_byte as char
525            ))),
526        }
527    }
528
529    fn decode_simple_string(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
530        let line = self.read_line(cursor)?;
531        Ok(Resp3Value::SimpleString(line))
532    }
533
534    fn decode_simple_error(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
535        let line = self.read_line(cursor)?;
536        Ok(Resp3Value::SimpleError(line))
537    }
538
539    fn decode_number(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
540        let line = self.read_line(cursor)?;
541        let num = line
542            .parse::<i64>()
543            .map_err(|e| RedisError::Protocol(format!("Invalid number: {}", e)))?;
544        Ok(Resp3Value::Number(num))
545    }
546
547    fn decode_blob_string(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
548        let len_line = self.read_line(cursor)?;
549        let len = len_line
550            .parse::<i64>()
551            .map_err(|e| RedisError::Protocol(format!("Invalid blob string length: {}", e)))?;
552
553        if len == -1 {
554            return Ok(Resp3Value::Null);
555        }
556
557        if len < 0 {
558            return Err(RedisError::Protocol(
559                "Invalid blob string length".to_string(),
560            ));
561        }
562
563        let len = len as usize;
564        if cursor.remaining() < len + 2 {
565            return Err(RedisError::Protocol("Incomplete blob string".to_string()));
566        }
567
568        let mut data = vec![0u8; len];
569        cursor.copy_to_slice(&mut data);
570
571        // Skip \r\n
572        if cursor.remaining() < 2 || cursor.get_u8() != b'\r' || cursor.get_u8() != b'\n' {
573            return Err(RedisError::Protocol(
574                "Invalid blob string terminator".to_string(),
575            ));
576        }
577
578        let string = String::from_utf8(data)
579            .map_err(|e| RedisError::Protocol(format!("Invalid UTF-8 in blob string: {}", e)))?;
580
581        Ok(Resp3Value::BlobString(string))
582    }
583
584    fn decode_array(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
585        let len_line = self.read_line(cursor)?;
586        let len = len_line
587            .parse::<i64>()
588            .map_err(|e| RedisError::Protocol(format!("Invalid array length: {}", e)))?;
589
590        if len == -1 {
591            return Ok(Resp3Value::Null);
592        }
593
594        if len < 0 {
595            return Err(RedisError::Protocol("Invalid array length".to_string()));
596        }
597
598        let len = len as usize;
599        let mut array = Vec::with_capacity(len);
600        for _ in 0..len {
601            array.push(self.decode_value(cursor)?);
602        }
603
604        Ok(Resp3Value::Array(array))
605    }
606
607    fn decode_null(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
608        let line = self.read_line(cursor)?;
609        if line.is_empty() {
610            Ok(Resp3Value::Null)
611        } else {
612            Err(RedisError::Protocol("Invalid null format".to_string()))
613        }
614    }
615
616    fn decode_boolean(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
617        let line = self.read_line(cursor)?;
618        match line.as_str() {
619            "t" => Ok(Resp3Value::Boolean(true)),
620            "f" => Ok(Resp3Value::Boolean(false)),
621            _ => Err(RedisError::Protocol(format!("Invalid boolean: {}", line))),
622        }
623    }
624
625    fn decode_double(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
626        let line = self.read_line(cursor)?;
627        let num = line
628            .parse::<f64>()
629            .map_err(|e| RedisError::Protocol(format!("Invalid double: {}", e)))?;
630        Ok(Resp3Value::Double(num))
631    }
632
633    fn decode_big_number(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
634        let line = self.read_line(cursor)?;
635        Ok(Resp3Value::BigNumber(line))
636    }
637
638    fn decode_blob_error(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
639        let len_line = self.read_line(cursor)?;
640        let len = len_line
641            .parse::<usize>()
642            .map_err(|e| RedisError::Protocol(format!("Invalid blob error length: {}", e)))?;
643
644        if cursor.remaining() < len + 2 {
645            return Err(RedisError::Protocol("Incomplete blob error".to_string()));
646        }
647
648        let mut data = vec![0u8; len];
649        cursor.copy_to_slice(&mut data);
650
651        // Skip \r\n
652        if cursor.remaining() < 2 || cursor.get_u8() != b'\r' || cursor.get_u8() != b'\n' {
653            return Err(RedisError::Protocol(
654                "Invalid blob error terminator".to_string(),
655            ));
656        }
657
658        let string = String::from_utf8(data)
659            .map_err(|e| RedisError::Protocol(format!("Invalid UTF-8 in blob error: {}", e)))?;
660
661        Ok(Resp3Value::BlobError(string))
662    }
663
664    fn decode_verbatim_string(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
665        let len_line = self.read_line(cursor)?;
666        let len = len_line
667            .parse::<usize>()
668            .map_err(|e| RedisError::Protocol(format!("Invalid verbatim string length: {}", e)))?;
669
670        if cursor.remaining() < len + 2 {
671            return Err(RedisError::Protocol(
672                "Incomplete verbatim string".to_string(),
673            ));
674        }
675
676        let mut data = vec![0u8; len];
677        cursor.copy_to_slice(&mut data);
678
679        // Skip \r\n
680        if cursor.remaining() < 2 || cursor.get_u8() != b'\r' || cursor.get_u8() != b'\n' {
681            return Err(RedisError::Protocol(
682                "Invalid verbatim string terminator".to_string(),
683            ));
684        }
685
686        let content = String::from_utf8(data).map_err(|e| {
687            RedisError::Protocol(format!("Invalid UTF-8 in verbatim string: {}", e))
688        })?;
689
690        // Parse encoding:data format
691        if let Some(colon_pos) = content.find(':') {
692            let encoding = content[..colon_pos].to_string();
693            let data = content[colon_pos + 1..].to_string();
694            Ok(Resp3Value::VerbatimString { encoding, data })
695        } else {
696            Err(RedisError::Protocol(
697                "Invalid verbatim string format".to_string(),
698            ))
699        }
700    }
701
702    fn decode_map(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
703        let len_line = self.read_line(cursor)?;
704        let len = len_line
705            .parse::<usize>()
706            .map_err(|e| RedisError::Protocol(format!("Invalid map length: {}", e)))?;
707
708        let mut map = HashMap::new();
709        for _ in 0..len {
710            let key = self.decode_value(cursor)?;
711            let value = self.decode_value(cursor)?;
712            let key_str = key.as_string()?;
713            map.insert(key_str, value);
714        }
715
716        Ok(Resp3Value::Map(map))
717    }
718
719    fn decode_set(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
720        let len_line = self.read_line(cursor)?;
721        let len = len_line
722            .parse::<usize>()
723            .map_err(|e| RedisError::Protocol(format!("Invalid set length: {}", e)))?;
724
725        let mut set = HashSet::new();
726        for _ in 0..len {
727            let value = self.decode_value(cursor)?;
728            set.insert(value);
729        }
730
731        Ok(Resp3Value::Set(set))
732    }
733
734    fn decode_attribute(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
735        let len_line = self.read_line(cursor)?;
736        let len = len_line
737            .parse::<usize>()
738            .map_err(|e| RedisError::Protocol(format!("Invalid attribute length: {}", e)))?;
739
740        let mut attrs = HashMap::new();
741        for _ in 0..len {
742            let key = self.decode_value(cursor)?;
743            let value = self.decode_value(cursor)?;
744            let key_str = key.as_string()?;
745            attrs.insert(key_str, value);
746        }
747
748        let data = Box::new(self.decode_value(cursor)?);
749        Ok(Resp3Value::Attribute { attrs, data })
750    }
751
752    fn decode_push(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<Resp3Value> {
753        let len_line = self.read_line(cursor)?;
754        let len = len_line
755            .parse::<usize>()
756            .map_err(|e| RedisError::Protocol(format!("Invalid push length: {}", e)))?;
757
758        let mut array = Vec::with_capacity(len);
759        for _ in 0..len {
760            array.push(self.decode_value(cursor)?);
761        }
762
763        Ok(Resp3Value::Push(array))
764    }
765
766    fn read_line(&self, cursor: &mut Cursor<&[u8]>) -> RedisResult<String> {
767        let start = cursor.position() as usize;
768        let data = cursor.get_ref();
769
770        for i in start..data.len() - 1 {
771            if data[i] == b'\r' && data[i + 1] == b'\n' {
772                let line = String::from_utf8(data[start..i].to_vec())
773                    .map_err(|e| RedisError::Protocol(format!("Invalid UTF-8 in line: {}", e)))?;
774                cursor.set_position((i + 2) as u64);
775                return Ok(line);
776            }
777        }
778
779        Err(RedisError::Protocol("Incomplete line".to_string()))
780    }
781}
782
783impl Default for Resp3Decoder {
784    fn default() -> Self {
785        Self::new()
786    }
787}
788
789#[cfg(test)]
790mod tests {
791    use super::*;
792
793    #[test]
794    fn test_encode_decode_simple_string() {
795        let mut encoder = Resp3Encoder::new();
796        let value = Resp3Value::SimpleString("OK".to_string());
797        let encoded = encoder.encode(&value).unwrap();
798
799        let mut decoder = Resp3Decoder::new();
800        let decoded = decoder.decode(&encoded).unwrap();
801
802        assert_eq!(value, decoded);
803    }
804
805    #[test]
806    fn test_encode_decode_number() {
807        let mut encoder = Resp3Encoder::new();
808        let value = Resp3Value::Number(42);
809        let encoded = encoder.encode(&value).unwrap();
810
811        let mut decoder = Resp3Decoder::new();
812        let decoded = decoder.decode(&encoded).unwrap();
813
814        assert_eq!(value, decoded);
815    }
816
817    #[test]
818    fn test_encode_decode_boolean() {
819        let mut encoder = Resp3Encoder::new();
820        let value = Resp3Value::Boolean(true);
821        let encoded = encoder.encode(&value).unwrap();
822
823        let mut decoder = Resp3Decoder::new();
824        let decoded = decoder.decode(&encoded).unwrap();
825
826        assert_eq!(value, decoded);
827    }
828
829    #[test]
830    fn test_encode_decode_double() {
831        let mut encoder = Resp3Encoder::new();
832        let value = Resp3Value::Double(3.14);
833        let encoded = encoder.encode(&value).unwrap();
834
835        let mut decoder = Resp3Decoder::new();
836        let decoded = decoder.decode(&encoded).unwrap();
837
838        assert_eq!(value, decoded);
839    }
840
841    #[test]
842    fn test_encode_decode_map() {
843        let mut encoder = Resp3Encoder::new();
844        let mut map = HashMap::new();
845        map.insert("key1".to_string(), Resp3Value::Number(1));
846        map.insert(
847            "key2".to_string(),
848            Resp3Value::SimpleString("value2".to_string()),
849        );
850        let value = Resp3Value::Map(map);
851        let encoded = encoder.encode(&value).unwrap();
852
853        let mut decoder = Resp3Decoder::new();
854        let decoded = decoder.decode(&encoded).unwrap();
855
856        assert_eq!(value, decoded);
857    }
858
859    #[test]
860    fn test_encode_decode_set() {
861        let mut encoder = Resp3Encoder::new();
862        let mut set = HashSet::new();
863        set.insert(Resp3Value::SimpleString("apple".to_string()));
864        set.insert(Resp3Value::SimpleString("banana".to_string()));
865        let value = Resp3Value::Set(set);
866        let encoded = encoder.encode(&value).unwrap();
867
868        let mut decoder = Resp3Decoder::new();
869        let decoded = decoder.decode(&encoded).unwrap();
870
871        assert_eq!(value, decoded);
872    }
873
874    #[test]
875    fn test_encode_decode_array() {
876        let mut encoder = Resp3Encoder::new();
877        let value = Resp3Value::Array(vec![
878            Resp3Value::SimpleString("hello".to_string()),
879            Resp3Value::Number(42),
880            Resp3Value::Boolean(true),
881        ]);
882        let encoded = encoder.encode(&value).unwrap();
883
884        let mut decoder = Resp3Decoder::new();
885        let decoded = decoder.decode(&encoded).unwrap();
886
887        assert_eq!(value, decoded);
888    }
889
890    #[test]
891    fn test_resp2_compatibility() {
892        let resp2_value = RespValue::SimpleString("test".to_string());
893        let resp3_value: Resp3Value = resp2_value.clone().into();
894        let back_to_resp2: RespValue = resp3_value.into();
895
896        assert_eq!(resp2_value, back_to_resp2);
897    }
898
899    #[test]
900    fn test_value_conversions() {
901        let value = Resp3Value::Number(42);
902        assert_eq!(value.as_int().unwrap(), 42);
903        assert_eq!(value.as_string().unwrap(), "42");
904
905        let value = Resp3Value::Boolean(true);
906        assert!(value.as_bool().unwrap());
907        assert_eq!(value.as_int().unwrap(), 1);
908
909        let value = Resp3Value::Double(std::f64::consts::PI);
910        assert!(
911            (value.as_float().unwrap() - std::f64::consts::PI).abs() < 1e-10,
912            "Float value differs from PI"
913        );
914    }
915}