Skip to main content

resp_proto/
value.rs

1//! RESP value types and parsing/encoding.
2//!
3//! RESP2 defines the following value types:
4//! - Simple String: `+OK\r\n`
5//! - Error: `-ERR message\r\n`
6//! - Integer: `:1000\r\n`
7//! - Bulk String: `$6\r\nfoobar\r\n`
8//! - Null Bulk String: `$-1\r\n`
9//! - Array: `*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n`
10//!
11//! RESP3 adds the following types (enabled with the `resp3` feature):
12//! - Null: `_\r\n`
13//! - Boolean: `#t\r\n` or `#f\r\n`
14//! - Double: `,3.14159\r\n`
15//! - Big Number: `(12345678901234567890\r\n`
16//! - Bulk Error: `!<len>\r\n<error>\r\n`
17//! - Verbatim String: `=<len>\r\ntxt:<data>\r\n`
18//! - Map: `%<len>\r\n<key><val>...`
19//! - Set: `~<len>\r\n<elem>...`
20//! - Push: `><len>\r\n<elem>...`
21//! - Attribute: `|<len>\r\n<attrs>...<value>`
22
23use crate::error::ParseError;
24use bytes::Bytes;
25use std::io::Write;
26
27/// Default maximum key length in bytes.
28///
29/// This matches the memcache protocol default of 250 bytes.
30pub const DEFAULT_MAX_KEY_LEN: usize = 250;
31
32/// Default maximum number of elements in a collection (array, map, set, etc.).
33///
34/// This limit prevents denial-of-service attacks where a malicious client sends
35/// a message claiming to have billions of elements, causing the server to attempt
36/// a massive allocation.
37pub const DEFAULT_MAX_COLLECTION_ELEMENTS: usize = 1024;
38
39/// Default maximum size of a bulk string in bytes (1MB).
40///
41/// This limit prevents denial-of-service attacks where a malicious client sends
42/// a message claiming to have a huge bulk string, causing the server to attempt
43/// a massive allocation.
44///
45/// For cache implementations, you may want to set this to match your segment size
46/// minus header overhead using `ParseOptions::max_bulk_string_len()`.
47pub const DEFAULT_MAX_BULK_STRING_LEN: usize = 1024 * 1024;
48
49/// Default maximum nesting depth for recursive structures (arrays, maps, sets, etc.).
50///
51/// This limit prevents denial-of-service attacks where deeply nested structures
52/// cause stack overflow or excessive memory allocation through cumulative
53/// Vec::with_capacity() calls.
54///
55/// The value of 8 is sufficient for typical Redis use cases (commands, responses,
56/// pub/sub messages) which rarely exceed 2-3 levels of nesting.
57pub const DEFAULT_MAX_DEPTH: usize = 8;
58
59/// Default maximum total items across all collections in a single parse.
60///
61/// This is the critical DoS protection limit. Without this, nested collections
62/// could cause exponential memory allocation: MAX_ITEMS^MAX_DEPTH elements.
63///
64/// This limit caps the total number of collection elements across ALL levels
65/// of nesting in a single parse operation to prevent such attacks.
66pub const DEFAULT_MAX_TOTAL_ITEMS: usize = 1024;
67
68/// Configuration options for RESP value parsing.
69///
70/// These options allow customizing the DoS protection limits for different
71/// deployment scenarios. More restrictive limits provide better protection
72/// against resource exhaustion attacks.
73#[derive(Debug, Clone, Copy)]
74pub struct ParseOptions {
75    /// Maximum key length in bytes.
76    pub max_key_len: usize,
77    /// Maximum number of elements in a single collection.
78    pub max_collection_elements: usize,
79    /// Maximum size of a bulk string in bytes.
80    pub max_bulk_string_len: usize,
81    /// Maximum nesting depth for recursive structures.
82    pub max_depth: usize,
83    /// Maximum total items across all collections in a single parse.
84    ///
85    /// This is the critical limit for preventing exponential allocation attacks
86    /// from nested collections. Without this, an attacker could send nested
87    /// arrays where total items = max_collection_elements^max_depth.
88    pub max_total_items: usize,
89}
90
91impl Default for ParseOptions {
92    fn default() -> Self {
93        Self {
94            max_key_len: DEFAULT_MAX_KEY_LEN,
95            max_collection_elements: DEFAULT_MAX_COLLECTION_ELEMENTS,
96            max_bulk_string_len: DEFAULT_MAX_BULK_STRING_LEN,
97            max_depth: DEFAULT_MAX_DEPTH,
98            max_total_items: DEFAULT_MAX_TOTAL_ITEMS,
99        }
100    }
101}
102
103impl ParseOptions {
104    /// Create new parse options with default values.
105    pub const fn new() -> Self {
106        Self {
107            max_key_len: DEFAULT_MAX_KEY_LEN,
108            max_collection_elements: DEFAULT_MAX_COLLECTION_ELEMENTS,
109            max_bulk_string_len: DEFAULT_MAX_BULK_STRING_LEN,
110            max_depth: DEFAULT_MAX_DEPTH,
111            max_total_items: DEFAULT_MAX_TOTAL_ITEMS,
112        }
113    }
114
115    /// Set the maximum key length.
116    pub const fn max_key_len(mut self, len: usize) -> Self {
117        self.max_key_len = len;
118        self
119    }
120
121    /// Set the maximum collection element count.
122    pub const fn max_collection_elements(mut self, count: usize) -> Self {
123        self.max_collection_elements = count;
124        self
125    }
126
127    /// Set the maximum bulk string length.
128    pub const fn max_bulk_string_len(mut self, len: usize) -> Self {
129        self.max_bulk_string_len = len;
130        self
131    }
132
133    /// Set the maximum nesting depth.
134    pub const fn max_depth(mut self, depth: usize) -> Self {
135        self.max_depth = depth;
136        self
137    }
138
139    /// Set the maximum total items across all collections.
140    pub const fn max_total_items(mut self, count: usize) -> Self {
141        self.max_total_items = count;
142        self
143    }
144}
145
146/// A RESP protocol value.
147///
148/// This enum supports both RESP2 and RESP3 types. RESP3 types are only
149/// available when the `resp3` feature is enabled.
150#[derive(Debug, Clone, PartialEq)]
151pub enum Value {
152    /// Simple string: `+OK\r\n`
153    SimpleString(Bytes),
154    /// Error: `-ERR message\r\n`
155    Error(Bytes),
156    /// Integer: `:1000\r\n`
157    Integer(i64),
158    /// Bulk string: `$6\r\nfoobar\r\n`
159    BulkString(Bytes),
160    /// Null value.
161    /// RESP2: `$-1\r\n` or `*-1\r\n`
162    /// RESP3: `_\r\n`
163    Null,
164    /// Array: `*2\r\n...`
165    Array(Vec<Value>),
166
167    // ========================================================================
168    // RESP3 Types (feature-gated)
169    // ========================================================================
170    /// Boolean: `#t\r\n` or `#f\r\n`
171    #[cfg(feature = "resp3")]
172    Boolean(bool),
173    /// Double-precision floating point: `,3.14159\r\n`
174    #[cfg(feature = "resp3")]
175    Double(f64),
176    /// Big number (arbitrary precision): `(12345678901234567890\r\n`
177    /// Stored as the raw decimal string representation.
178    #[cfg(feature = "resp3")]
179    BigNumber(Bytes),
180    /// Bulk error: `!<len>\r\n<error>\r\n`
181    #[cfg(feature = "resp3")]
182    BulkError(Bytes),
183    /// Verbatim string: `=<len>\r\ntxt:<data>\r\n`
184    /// The format is a 3-byte encoding type (e.g., "txt", "mkd").
185    #[cfg(feature = "resp3")]
186    VerbatimString {
187        /// 3-byte format identifier (e.g., b"txt", b"mkd")
188        format: [u8; 3],
189        /// The actual data
190        data: Bytes,
191    },
192    /// Map: `%<len>\r\n<key><val>...`
193    #[cfg(feature = "resp3")]
194    Map(Vec<(Value, Value)>),
195    /// Set: `~<len>\r\n<elem>...`
196    #[cfg(feature = "resp3")]
197    Set(Vec<Value>),
198    /// Push message (server-initiated): `><len>\r\n<elem>...`
199    #[cfg(feature = "resp3")]
200    Push(Vec<Value>),
201    /// Attribute (metadata attached to next value): `|<len>\r\n<attrs>...<value>`
202    #[cfg(feature = "resp3")]
203    Attribute {
204        /// Metadata key-value pairs
205        attrs: Vec<(Value, Value)>,
206        /// The actual value this metadata is attached to
207        value: Box<Value>,
208    },
209}
210
211impl Value {
212    // ========================================================================
213    // Constructors
214    // ========================================================================
215
216    /// Create a simple string value.
217    #[inline]
218    pub fn simple_string(s: &[u8]) -> Self {
219        Value::SimpleString(Bytes::copy_from_slice(s))
220    }
221
222    /// Create an error value.
223    #[inline]
224    pub fn error(msg: &[u8]) -> Self {
225        Value::Error(Bytes::copy_from_slice(msg))
226    }
227
228    /// Create an integer value.
229    #[inline]
230    pub fn integer(n: i64) -> Self {
231        Value::Integer(n)
232    }
233
234    /// Create a bulk string value.
235    #[inline]
236    pub fn bulk_string(data: &[u8]) -> Self {
237        Value::BulkString(Bytes::copy_from_slice(data))
238    }
239
240    /// Create a null value.
241    #[inline]
242    pub fn null() -> Self {
243        Value::Null
244    }
245
246    /// Create an array value.
247    #[inline]
248    pub fn array(elements: Vec<Value>) -> Self {
249        Value::Array(elements)
250    }
251
252    // RESP3 constructors (feature-gated)
253
254    /// Create a boolean value (RESP3).
255    #[cfg(feature = "resp3")]
256    #[inline]
257    pub fn boolean(b: bool) -> Self {
258        Value::Boolean(b)
259    }
260
261    /// Create a double value (RESP3).
262    #[cfg(feature = "resp3")]
263    #[inline]
264    pub fn double(d: f64) -> Self {
265        Value::Double(d)
266    }
267
268    /// Create a big number value from a decimal string (RESP3).
269    #[cfg(feature = "resp3")]
270    #[inline]
271    pub fn big_number(num: &[u8]) -> Self {
272        Value::BigNumber(Bytes::copy_from_slice(num))
273    }
274
275    /// Create a bulk error value (RESP3).
276    #[cfg(feature = "resp3")]
277    #[inline]
278    pub fn bulk_error(msg: &[u8]) -> Self {
279        Value::BulkError(Bytes::copy_from_slice(msg))
280    }
281
282    /// Create a verbatim string value (RESP3).
283    #[cfg(feature = "resp3")]
284    #[inline]
285    pub fn verbatim_string(format: [u8; 3], data: &[u8]) -> Self {
286        Value::VerbatimString {
287            format,
288            data: Bytes::copy_from_slice(data),
289        }
290    }
291
292    /// Create a map value (RESP3).
293    #[cfg(feature = "resp3")]
294    #[inline]
295    pub fn map(entries: Vec<(Value, Value)>) -> Self {
296        Value::Map(entries)
297    }
298
299    /// Create a set value (RESP3).
300    #[cfg(feature = "resp3")]
301    #[inline]
302    pub fn set(elements: Vec<Value>) -> Self {
303        Value::Set(elements)
304    }
305
306    /// Create a push message value (RESP3).
307    #[cfg(feature = "resp3")]
308    #[inline]
309    pub fn push(elements: Vec<Value>) -> Self {
310        Value::Push(elements)
311    }
312
313    /// Create an attribute value (RESP3).
314    #[cfg(feature = "resp3")]
315    #[inline]
316    pub fn attribute(attrs: Vec<(Value, Value)>, value: Value) -> Self {
317        Value::Attribute {
318            attrs,
319            value: Box::new(value),
320        }
321    }
322
323    // ========================================================================
324    // Type checks
325    // ========================================================================
326
327    /// Returns true if this is a null value.
328    #[inline]
329    pub fn is_null(&self) -> bool {
330        matches!(self, Value::Null)
331    }
332
333    /// Returns true if this is an error value.
334    #[inline]
335    pub fn is_error(&self) -> bool {
336        matches!(self, Value::Error(_))
337    }
338
339    /// Returns true if this is a simple string.
340    #[inline]
341    pub fn is_simple_string(&self) -> bool {
342        matches!(self, Value::SimpleString(_))
343    }
344
345    /// Returns true if this is a bulk string.
346    #[inline]
347    pub fn is_bulk_string(&self) -> bool {
348        matches!(self, Value::BulkString(_))
349    }
350
351    /// Returns true if this is an integer.
352    #[inline]
353    pub fn is_integer(&self) -> bool {
354        matches!(self, Value::Integer(_))
355    }
356
357    /// Returns true if this is an array.
358    #[inline]
359    pub fn is_array(&self) -> bool {
360        matches!(self, Value::Array(_))
361    }
362
363    // RESP3 type checks (feature-gated)
364
365    /// Returns true if this is a boolean value (RESP3).
366    #[cfg(feature = "resp3")]
367    #[inline]
368    pub fn is_boolean(&self) -> bool {
369        matches!(self, Value::Boolean(_))
370    }
371
372    /// Returns true if this is a double value (RESP3).
373    #[cfg(feature = "resp3")]
374    #[inline]
375    pub fn is_double(&self) -> bool {
376        matches!(self, Value::Double(_))
377    }
378
379    /// Returns true if this is a big number value (RESP3).
380    #[cfg(feature = "resp3")]
381    #[inline]
382    pub fn is_big_number(&self) -> bool {
383        matches!(self, Value::BigNumber(_))
384    }
385
386    /// Returns true if this is a bulk error value (RESP3).
387    #[cfg(feature = "resp3")]
388    #[inline]
389    pub fn is_bulk_error(&self) -> bool {
390        matches!(self, Value::BulkError(_))
391    }
392
393    /// Returns true if this is a verbatim string value (RESP3).
394    #[cfg(feature = "resp3")]
395    #[inline]
396    pub fn is_verbatim_string(&self) -> bool {
397        matches!(self, Value::VerbatimString { .. })
398    }
399
400    /// Returns true if this is a map value (RESP3).
401    #[cfg(feature = "resp3")]
402    #[inline]
403    pub fn is_map(&self) -> bool {
404        matches!(self, Value::Map(_))
405    }
406
407    /// Returns true if this is a set value (RESP3).
408    #[cfg(feature = "resp3")]
409    #[inline]
410    pub fn is_set(&self) -> bool {
411        matches!(self, Value::Set(_))
412    }
413
414    /// Returns true if this is a push message (RESP3).
415    #[cfg(feature = "resp3")]
416    #[inline]
417    pub fn is_push(&self) -> bool {
418        matches!(self, Value::Push(_))
419    }
420
421    /// Returns true if this is an attribute value (RESP3).
422    #[cfg(feature = "resp3")]
423    #[inline]
424    pub fn is_attribute(&self) -> bool {
425        matches!(self, Value::Attribute { .. })
426    }
427
428    // ========================================================================
429    // Accessors
430    // ========================================================================
431
432    /// Returns the value as bytes if it's a string type (simple or bulk).
433    #[inline]
434    pub fn as_bytes(&self) -> Option<&[u8]> {
435        match self {
436            Value::SimpleString(s) | Value::BulkString(s) | Value::Error(s) => Some(s),
437            _ => None,
438        }
439    }
440
441    /// Returns the value as an integer.
442    #[inline]
443    pub fn as_integer(&self) -> Option<i64> {
444        match self {
445            Value::Integer(i) => Some(*i),
446            _ => None,
447        }
448    }
449
450    /// Returns the value as an array.
451    #[inline]
452    pub fn as_array(&self) -> Option<&[Value]> {
453        match self {
454            Value::Array(arr) => Some(arr),
455            _ => None,
456        }
457    }
458
459    // RESP3 accessors (feature-gated)
460
461    /// Returns the value as a boolean (RESP3).
462    #[cfg(feature = "resp3")]
463    #[inline]
464    pub fn as_bool(&self) -> Option<bool> {
465        match self {
466            Value::Boolean(b) => Some(*b),
467            _ => None,
468        }
469    }
470
471    /// Returns the value as a double (RESP3).
472    #[cfg(feature = "resp3")]
473    #[inline]
474    pub fn as_double(&self) -> Option<f64> {
475        match self {
476            Value::Double(d) => Some(*d),
477            _ => None,
478        }
479    }
480
481    /// Returns the value as a big number decimal string (RESP3).
482    #[cfg(feature = "resp3")]
483    #[inline]
484    pub fn as_big_number(&self) -> Option<&[u8]> {
485        match self {
486            Value::BigNumber(n) => Some(n),
487            _ => None,
488        }
489    }
490
491    /// Returns the value as a map (RESP3).
492    #[cfg(feature = "resp3")]
493    #[inline]
494    pub fn as_map(&self) -> Option<&[(Value, Value)]> {
495        match self {
496            Value::Map(m) => Some(m),
497            _ => None,
498        }
499    }
500
501    /// Returns the value as a set (RESP3).
502    #[cfg(feature = "resp3")]
503    #[inline]
504    pub fn as_set(&self) -> Option<&[Value]> {
505        match self {
506            Value::Set(s) => Some(s),
507            _ => None,
508        }
509    }
510
511    /// Returns the value as a push message (RESP3).
512    #[cfg(feature = "resp3")]
513    #[inline]
514    pub fn as_push(&self) -> Option<&[Value]> {
515        match self {
516            Value::Push(p) => Some(p),
517            _ => None,
518        }
519    }
520
521    /// Returns the verbatim string format and data (RESP3).
522    #[cfg(feature = "resp3")]
523    #[inline]
524    pub fn as_verbatim_string(&self) -> Option<(&[u8; 3], &[u8])> {
525        match self {
526            Value::VerbatimString { format, data } => Some((format, data)),
527            _ => None,
528        }
529    }
530
531    // ========================================================================
532    // Parsing
533    // ========================================================================
534
535    /// Parse a RESP value from a byte buffer.
536    ///
537    /// Returns the parsed value and the number of bytes consumed.
538    ///
539    /// # Errors
540    ///
541    /// Returns `ParseError::Incomplete` if more data is needed to complete parsing.
542    /// Returns other errors for malformed data.
543    #[inline]
544    pub fn parse(data: &[u8]) -> Result<(Self, usize), ParseError> {
545        Self::parse_with_options(data, &ParseOptions::default())
546    }
547
548    /// Parse a RESP value from raw bytes with custom options.
549    ///
550    /// This allows configuring DoS protection limits like maximum collection size
551    /// and bulk string length.
552    pub fn parse_with_options(
553        data: &[u8],
554        options: &ParseOptions,
555    ) -> Result<(Self, usize), ParseError> {
556        let mut total_items = 0;
557        Self::parse_internal(data, options, 0, &mut total_items)
558    }
559
560    /// Parse a RESP value zero-copy from a `Bytes` buffer.
561    ///
562    /// String variants (`BulkString`, `SimpleString`, etc.) are returned as
563    /// `Bytes::slice()` references into the input — no allocation or copy.
564    /// Returns the parsed value and the number of bytes consumed.
565    #[inline]
566    pub fn parse_bytes(data: Bytes) -> Result<(Self, usize), ParseError> {
567        Self::parse_bytes_with_options(data, &ParseOptions::default())
568    }
569
570    /// Parse a RESP value zero-copy from a `Bytes` buffer with custom options.
571    pub fn parse_bytes_with_options(
572        data: Bytes,
573        options: &ParseOptions,
574    ) -> Result<(Self, usize), ParseError> {
575        let mut total_items = 0;
576        Self::parse_bytes_internal(&data, options, 0, &mut total_items)
577    }
578
579    /// Internal zero-copy parsing function.
580    fn parse_bytes_internal(
581        data: &Bytes,
582        options: &ParseOptions,
583        depth: usize,
584        total_items: &mut usize,
585    ) -> Result<(Self, usize), ParseError> {
586        if data.is_empty() {
587            return Err(ParseError::Incomplete);
588        }
589
590        match data[0] {
591            b'+' => parse_simple_string_bytes(data),
592            b'-' => parse_error_bytes(data),
593            b':' => parse_integer(&data[..]),
594            b'$' => parse_bulk_string_bytes(data, options),
595            b'*' => parse_array_bytes(data, options, depth, total_items),
596            #[cfg(feature = "resp3")]
597            b'_' => parse_null(&data[..]),
598            #[cfg(feature = "resp3")]
599            b'#' => parse_boolean(&data[..]),
600            #[cfg(feature = "resp3")]
601            b',' => parse_double(&data[..]),
602            #[cfg(feature = "resp3")]
603            b'(' => parse_big_number_bytes(data),
604            #[cfg(feature = "resp3")]
605            b'!' => parse_bulk_error_bytes(data, options),
606            #[cfg(feature = "resp3")]
607            b'=' => parse_verbatim_string_bytes(data, options),
608            #[cfg(feature = "resp3")]
609            b'%' => parse_map_bytes(data, options, depth, total_items),
610            #[cfg(feature = "resp3")]
611            b'~' => parse_set_bytes(data, options, depth, total_items),
612            #[cfg(feature = "resp3")]
613            b'>' => parse_push_bytes(data, options, depth, total_items),
614            #[cfg(feature = "resp3")]
615            b'|' => parse_attribute_bytes(data, options, depth, total_items),
616            other => Err(ParseError::InvalidPrefix(other)),
617        }
618    }
619
620    /// Internal parsing function that tracks nesting depth and total items.
621    fn parse_internal(
622        data: &[u8],
623        options: &ParseOptions,
624        depth: usize,
625        total_items: &mut usize,
626    ) -> Result<(Self, usize), ParseError> {
627        if data.is_empty() {
628            return Err(ParseError::Incomplete);
629        }
630
631        match data[0] {
632            // RESP2 types
633            b'+' => parse_simple_string(data),
634            b'-' => parse_error(data),
635            b':' => parse_integer(data),
636            b'$' => parse_bulk_string(data, options),
637            b'*' => parse_array(data, options, depth, total_items),
638            // RESP3 types
639            #[cfg(feature = "resp3")]
640            b'_' => parse_null(data),
641            #[cfg(feature = "resp3")]
642            b'#' => parse_boolean(data),
643            #[cfg(feature = "resp3")]
644            b',' => parse_double(data),
645            #[cfg(feature = "resp3")]
646            b'(' => parse_big_number(data),
647            #[cfg(feature = "resp3")]
648            b'!' => parse_bulk_error(data, options),
649            #[cfg(feature = "resp3")]
650            b'=' => parse_verbatim_string(data, options),
651            #[cfg(feature = "resp3")]
652            b'%' => parse_map(data, options, depth, total_items),
653            #[cfg(feature = "resp3")]
654            b'~' => parse_set(data, options, depth, total_items),
655            #[cfg(feature = "resp3")]
656            b'>' => parse_push(data, options, depth, total_items),
657            #[cfg(feature = "resp3")]
658            b'|' => parse_attribute(data, options, depth, total_items),
659            other => Err(ParseError::InvalidPrefix(other)),
660        }
661    }
662
663    // ========================================================================
664    // Encoding
665    // ========================================================================
666
667    /// Encode this value into a byte buffer.
668    ///
669    /// Returns the number of bytes written.
670    ///
671    /// # Panics
672    ///
673    /// Panics if the buffer is too small. Use `encoded_len()` to check the required size.
674    #[inline]
675    pub fn encode(&self, buf: &mut [u8]) -> usize {
676        match self {
677            Value::SimpleString(s) => encode_simple_string(buf, s),
678            Value::Error(msg) => encode_error(buf, msg),
679            Value::Integer(n) => encode_integer(buf, *n),
680            Value::BulkString(data) => encode_bulk_string(buf, data),
681            Value::Null => encode_resp2_null(buf),
682            Value::Array(elements) => encode_array(buf, elements),
683            #[cfg(feature = "resp3")]
684            Value::Boolean(b) => encode_boolean(buf, *b),
685            #[cfg(feature = "resp3")]
686            Value::Double(d) => encode_double(buf, *d),
687            #[cfg(feature = "resp3")]
688            Value::BigNumber(n) => encode_big_number(buf, n),
689            #[cfg(feature = "resp3")]
690            Value::BulkError(msg) => encode_bulk_error(buf, msg),
691            #[cfg(feature = "resp3")]
692            Value::VerbatimString { format, data } => encode_verbatim_string(buf, format, data),
693            #[cfg(feature = "resp3")]
694            Value::Map(entries) => encode_map(buf, entries),
695            #[cfg(feature = "resp3")]
696            Value::Set(elements) => encode_set(buf, elements),
697            #[cfg(feature = "resp3")]
698            Value::Push(elements) => encode_push(buf, elements),
699            #[cfg(feature = "resp3")]
700            Value::Attribute { attrs, value } => encode_attribute(buf, attrs, value),
701        }
702    }
703
704    /// Calculate the encoded length of this value.
705    pub fn encoded_len(&self) -> usize {
706        match self {
707            Value::SimpleString(s) => 1 + s.len() + 2, // +<data>\r\n
708            Value::Error(msg) => 1 + msg.len() + 2,    // -<data>\r\n
709            Value::Integer(n) => {
710                let mut buf = itoa::Buffer::new();
711                1 + buf.format(*n).len() + 2 // :<int>\r\n
712            }
713            Value::BulkString(data) => {
714                let mut buf = itoa::Buffer::new();
715                1 + buf.format(data.len()).len() + 2 + data.len() + 2 // $<len>\r\n<data>\r\n
716            }
717            Value::Null => 5, // $-1\r\n
718            Value::Array(elements) => {
719                let mut buf = itoa::Buffer::new();
720                let header_len = 1 + buf.format(elements.len()).len() + 2;
721                header_len + elements.iter().map(|e| e.encoded_len()).sum::<usize>()
722            }
723            // RESP3 types
724            #[cfg(feature = "resp3")]
725            Value::Boolean(_) => 4, // #t\r\n or #f\r\n
726            #[cfg(feature = "resp3")]
727            Value::Double(d) => {
728                // ,<float>\r\n - use ryu for efficient length calculation
729                let mut buf = ryu::Buffer::new();
730                1 + buf.format(*d).len() + 2
731            }
732            #[cfg(feature = "resp3")]
733            Value::BigNumber(n) => 1 + n.len() + 2, // (<num>\r\n
734            #[cfg(feature = "resp3")]
735            Value::BulkError(msg) => {
736                let mut buf = itoa::Buffer::new();
737                1 + buf.format(msg.len()).len() + 2 + msg.len() + 2 // !<len>\r\n<msg>\r\n
738            }
739            #[cfg(feature = "resp3")]
740            Value::VerbatimString { data, .. } => {
741                let mut buf = itoa::Buffer::new();
742                // =<len>\r\n<fmt>:<data>\r\n where len = 3 + 1 + data.len()
743                let total_len = 4 + data.len(); // "fmt:" (3 + 1) + data
744                1 + buf.format(total_len).len() + 2 + total_len + 2
745            }
746            #[cfg(feature = "resp3")]
747            Value::Map(entries) => {
748                let mut buf = itoa::Buffer::new();
749                let header_len = 1 + buf.format(entries.len()).len() + 2;
750                header_len
751                    + entries
752                        .iter()
753                        .map(|(k, v)| k.encoded_len() + v.encoded_len())
754                        .sum::<usize>()
755            }
756            #[cfg(feature = "resp3")]
757            Value::Set(elements) => {
758                let mut buf = itoa::Buffer::new();
759                let header_len = 1 + buf.format(elements.len()).len() + 2;
760                header_len + elements.iter().map(|e| e.encoded_len()).sum::<usize>()
761            }
762            #[cfg(feature = "resp3")]
763            Value::Push(elements) => {
764                let mut buf = itoa::Buffer::new();
765                let header_len = 1 + buf.format(elements.len()).len() + 2;
766                header_len + elements.iter().map(|e| e.encoded_len()).sum::<usize>()
767            }
768            #[cfg(feature = "resp3")]
769            Value::Attribute { attrs, value } => {
770                let mut buf = itoa::Buffer::new();
771                let header_len = 1 + buf.format(attrs.len()).len() + 2;
772                let attrs_len = attrs
773                    .iter()
774                    .map(|(k, v)| k.encoded_len() + v.encoded_len())
775                    .sum::<usize>();
776                header_len + attrs_len + value.encoded_len()
777            }
778        }
779    }
780
781    /// Encode null value in RESP3 format: `_\r\n`
782    #[cfg(feature = "resp3")]
783    #[inline]
784    pub fn encode_resp3_null(buf: &mut [u8]) -> usize {
785        buf[..3].copy_from_slice(b"_\r\n");
786        3
787    }
788}
789
790// ============================================================================
791// Parsing helpers
792// ============================================================================
793
794/// Find the position of \r\n in the data.
795#[inline]
796fn find_crlf(data: &[u8]) -> Option<usize> {
797    memchr::memchr(b'\r', data).and_then(|pos| {
798        if pos + 1 < data.len() && data[pos + 1] == b'\n' {
799            Some(pos)
800        } else {
801            None
802        }
803    })
804}
805
806/// Parse a simple string: +OK\r\n
807fn parse_simple_string(data: &[u8]) -> Result<(Value, usize), ParseError> {
808    let end = find_crlf(data).ok_or(ParseError::Incomplete)?;
809    let content = Bytes::copy_from_slice(&data[1..end]);
810    Ok((Value::SimpleString(content), end + 2))
811}
812
813/// Parse an error: -ERR message\r\n
814fn parse_error(data: &[u8]) -> Result<(Value, usize), ParseError> {
815    let end = find_crlf(data).ok_or(ParseError::Incomplete)?;
816    let content = Bytes::copy_from_slice(&data[1..end]);
817    Ok((Value::Error(content), end + 2))
818}
819
820/// Parse an integer: :1000\r\n
821fn parse_integer(data: &[u8]) -> Result<(Value, usize), ParseError> {
822    let end = find_crlf(data).ok_or(ParseError::Incomplete)?;
823    let s = std::str::from_utf8(&data[1..end])
824        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
825    let value: i64 = s
826        .parse()
827        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
828    Ok((Value::Integer(value), end + 2))
829}
830
831/// Parse a bulk string: $6\r\nfoobar\r\n or $-1\r\n
832fn parse_bulk_string(data: &[u8], options: &ParseOptions) -> Result<(Value, usize), ParseError> {
833    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
834    let len_str = std::str::from_utf8(&data[1..len_end])
835        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
836    let len: i64 = len_str
837        .parse()
838        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
839
840    if len < 0 {
841        // Null bulk string
842        return Ok((Value::Null, len_end + 2));
843    }
844
845    let len = len as usize;
846    if len > options.max_bulk_string_len {
847        return Err(ParseError::Protocol("bulk string too large".to_string()));
848    }
849
850    let data_start = len_end + 2;
851    let data_end = data_start
852        .checked_add(len)
853        .ok_or_else(|| ParseError::InvalidInteger("length overflow".to_string()))?;
854    let total_end = data_end
855        .checked_add(2)
856        .ok_or_else(|| ParseError::InvalidInteger("length overflow".to_string()))?;
857
858    if data.len() < total_end {
859        return Err(ParseError::Incomplete);
860    }
861
862    // Verify trailing \r\n
863    if data[data_end] != b'\r' || data[data_end + 1] != b'\n' {
864        return Err(ParseError::Protocol("missing trailing CRLF".to_string()));
865    }
866
867    let content = Bytes::copy_from_slice(&data[data_start..data_end]);
868    Ok((Value::BulkString(content), total_end))
869}
870
871/// Parse an array: *2\r\n...
872fn parse_array(
873    data: &[u8],
874    options: &ParseOptions,
875    depth: usize,
876    total_items: &mut usize,
877) -> Result<(Value, usize), ParseError> {
878    if depth >= options.max_depth {
879        return Err(ParseError::NestingTooDeep(depth));
880    }
881
882    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
883    let len_str = std::str::from_utf8(&data[1..len_end])
884        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
885    let len: i64 = len_str
886        .parse()
887        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
888
889    if len < 0 {
890        // Null array (treated as null)
891        return Ok((Value::Null, len_end + 2));
892    }
893
894    let len = len as usize;
895    if len > options.max_collection_elements {
896        return Err(ParseError::CollectionTooLarge(len));
897    }
898
899    // Check total items budget (prevents exponential allocation attacks)
900    *total_items = total_items
901        .checked_add(len)
902        .ok_or(ParseError::CollectionTooLarge(usize::MAX))?;
903    if *total_items > options.max_total_items {
904        return Err(ParseError::CollectionTooLarge(*total_items));
905    }
906
907    let mut pos = len_end + 2;
908    let mut elements = Vec::with_capacity(len);
909
910    for _ in 0..len {
911        if pos >= data.len() {
912            return Err(ParseError::Incomplete);
913        }
914        let (value, consumed) =
915            Value::parse_internal(&data[pos..], options, depth + 1, total_items)?;
916        elements.push(value);
917        pos += consumed;
918    }
919
920    Ok((Value::Array(elements), pos))
921}
922
923// ============================================================================
924// Zero-copy (Bytes) parsing helpers
925// ============================================================================
926
927/// Parse a simple string zero-copy: +OK\r\n
928fn parse_simple_string_bytes(data: &Bytes) -> Result<(Value, usize), ParseError> {
929    let end = find_crlf(data).ok_or(ParseError::Incomplete)?;
930    let content = data.slice(1..end);
931    Ok((Value::SimpleString(content), end + 2))
932}
933
934/// Parse an error zero-copy: -ERR message\r\n
935fn parse_error_bytes(data: &Bytes) -> Result<(Value, usize), ParseError> {
936    let end = find_crlf(data).ok_or(ParseError::Incomplete)?;
937    let content = data.slice(1..end);
938    Ok((Value::Error(content), end + 2))
939}
940
941/// Parse a bulk string zero-copy: $6\r\nfoobar\r\n or $-1\r\n
942fn parse_bulk_string_bytes(
943    data: &Bytes,
944    options: &ParseOptions,
945) -> Result<(Value, usize), ParseError> {
946    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
947    let len_str = std::str::from_utf8(&data[1..len_end])
948        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
949    let len: i64 = len_str
950        .parse()
951        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
952
953    if len < 0 {
954        return Ok((Value::Null, len_end + 2));
955    }
956
957    let len = len as usize;
958    if len > options.max_bulk_string_len {
959        return Err(ParseError::Protocol("bulk string too large".to_string()));
960    }
961
962    let data_start = len_end + 2;
963    let data_end = data_start
964        .checked_add(len)
965        .ok_or_else(|| ParseError::InvalidInteger("length overflow".to_string()))?;
966    let total_end = data_end
967        .checked_add(2)
968        .ok_or_else(|| ParseError::InvalidInteger("length overflow".to_string()))?;
969
970    if data.len() < total_end {
971        return Err(ParseError::Incomplete);
972    }
973
974    if data[data_end] != b'\r' || data[data_end + 1] != b'\n' {
975        return Err(ParseError::Protocol("missing trailing CRLF".to_string()));
976    }
977
978    let content = data.slice(data_start..data_end);
979    Ok((Value::BulkString(content), total_end))
980}
981
982/// Parse an array zero-copy: *2\r\n...
983fn parse_array_bytes(
984    data: &Bytes,
985    options: &ParseOptions,
986    depth: usize,
987    total_items: &mut usize,
988) -> Result<(Value, usize), ParseError> {
989    if depth >= options.max_depth {
990        return Err(ParseError::NestingTooDeep(depth));
991    }
992
993    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
994    let len_str = std::str::from_utf8(&data[1..len_end])
995        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
996    let len: i64 = len_str
997        .parse()
998        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
999
1000    if len < 0 {
1001        return Ok((Value::Null, len_end + 2));
1002    }
1003
1004    let len = len as usize;
1005    if len > options.max_collection_elements {
1006        return Err(ParseError::CollectionTooLarge(len));
1007    }
1008
1009    *total_items = total_items
1010        .checked_add(len)
1011        .ok_or(ParseError::CollectionTooLarge(usize::MAX))?;
1012    if *total_items > options.max_total_items {
1013        return Err(ParseError::CollectionTooLarge(*total_items));
1014    }
1015
1016    let mut pos = len_end + 2;
1017    let mut elements = Vec::with_capacity(len);
1018
1019    for _ in 0..len {
1020        if pos >= data.len() {
1021            return Err(ParseError::Incomplete);
1022        }
1023        let sub = data.slice(pos..);
1024        let (value, consumed) = Value::parse_bytes_internal(&sub, options, depth + 1, total_items)?;
1025        elements.push(value);
1026        pos += consumed;
1027    }
1028
1029    Ok((Value::Array(elements), pos))
1030}
1031
1032/// Parse RESP3 big number zero-copy: (12345678901234567890\r\n
1033#[cfg(feature = "resp3")]
1034fn parse_big_number_bytes(data: &Bytes) -> Result<(Value, usize), ParseError> {
1035    let end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1036    let content = data.slice(1..end);
1037    Ok((Value::BigNumber(content), end + 2))
1038}
1039
1040/// Parse RESP3 bulk error zero-copy: !<len>\r\n<error>\r\n
1041#[cfg(feature = "resp3")]
1042fn parse_bulk_error_bytes(
1043    data: &Bytes,
1044    options: &ParseOptions,
1045) -> Result<(Value, usize), ParseError> {
1046    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1047    let len_str = std::str::from_utf8(&data[1..len_end])
1048        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
1049    let len: usize = len_str
1050        .parse()
1051        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
1052
1053    if len > options.max_bulk_string_len {
1054        return Err(ParseError::Protocol("bulk error too large".to_string()));
1055    }
1056
1057    let data_start = len_end + 2;
1058    let data_end = data_start
1059        .checked_add(len)
1060        .ok_or_else(|| ParseError::InvalidInteger("length overflow".to_string()))?;
1061    let total_end = data_end
1062        .checked_add(2)
1063        .ok_or_else(|| ParseError::InvalidInteger("length overflow".to_string()))?;
1064
1065    if data.len() < total_end {
1066        return Err(ParseError::Incomplete);
1067    }
1068
1069    if data[data_end] != b'\r' || data[data_end + 1] != b'\n' {
1070        return Err(ParseError::Protocol("missing trailing CRLF".to_string()));
1071    }
1072
1073    let content = data.slice(data_start..data_end);
1074    Ok((Value::BulkError(content), total_end))
1075}
1076
1077/// Parse RESP3 verbatim string zero-copy: =<len>\r\ntxt:<data>\r\n
1078#[cfg(feature = "resp3")]
1079fn parse_verbatim_string_bytes(
1080    data: &Bytes,
1081    options: &ParseOptions,
1082) -> Result<(Value, usize), ParseError> {
1083    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1084    let len_str = std::str::from_utf8(&data[1..len_end])
1085        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
1086    let len: usize = len_str
1087        .parse()
1088        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
1089
1090    if len > options.max_bulk_string_len {
1091        return Err(ParseError::Protocol(
1092            "verbatim string too large".to_string(),
1093        ));
1094    }
1095
1096    let data_start = len_end + 2;
1097    let data_end = data_start
1098        .checked_add(len)
1099        .ok_or_else(|| ParseError::InvalidInteger("length overflow".to_string()))?;
1100    let total_end = data_end
1101        .checked_add(2)
1102        .ok_or_else(|| ParseError::InvalidInteger("length overflow".to_string()))?;
1103
1104    if data.len() < total_end {
1105        return Err(ParseError::Incomplete);
1106    }
1107
1108    if len < 4 || data[data_start + 3] != b':' {
1109        return Err(ParseError::InvalidVerbatimFormat);
1110    }
1111
1112    if data[data_end] != b'\r' || data[data_end + 1] != b'\n' {
1113        return Err(ParseError::Protocol("missing trailing CRLF".to_string()));
1114    }
1115
1116    let format: [u8; 3] = data[data_start..data_start + 3]
1117        .try_into()
1118        .map_err(|_| ParseError::InvalidVerbatimFormat)?;
1119    let content = data.slice(data_start + 4..data_end);
1120
1121    Ok((
1122        Value::VerbatimString {
1123            format,
1124            data: content,
1125        },
1126        total_end,
1127    ))
1128}
1129
1130/// Parse RESP3 map zero-copy: %<len>\r\n<key><val>...
1131#[cfg(feature = "resp3")]
1132fn parse_map_bytes(
1133    data: &Bytes,
1134    options: &ParseOptions,
1135    depth: usize,
1136    total_items: &mut usize,
1137) -> Result<(Value, usize), ParseError> {
1138    if depth >= options.max_depth {
1139        return Err(ParseError::NestingTooDeep(depth));
1140    }
1141
1142    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1143    let len_str = std::str::from_utf8(&data[1..len_end])
1144        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
1145    let len: usize = len_str
1146        .parse()
1147        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
1148
1149    if len > options.max_collection_elements {
1150        return Err(ParseError::CollectionTooLarge(len));
1151    }
1152
1153    let items_to_add = len
1154        .checked_mul(2)
1155        .ok_or(ParseError::CollectionTooLarge(usize::MAX))?;
1156    *total_items = total_items
1157        .checked_add(items_to_add)
1158        .ok_or(ParseError::CollectionTooLarge(usize::MAX))?;
1159    if *total_items > options.max_total_items {
1160        return Err(ParseError::CollectionTooLarge(*total_items));
1161    }
1162
1163    let mut pos = len_end + 2;
1164    let mut entries = Vec::with_capacity(len);
1165
1166    for _ in 0..len {
1167        if pos >= data.len() {
1168            return Err(ParseError::Incomplete);
1169        }
1170        let sub = data.slice(pos..);
1171        let (key, key_consumed) =
1172            Value::parse_bytes_internal(&sub, options, depth + 1, total_items)?;
1173        pos += key_consumed;
1174
1175        if pos >= data.len() {
1176            return Err(ParseError::Incomplete);
1177        }
1178        let sub = data.slice(pos..);
1179        let (value, val_consumed) =
1180            Value::parse_bytes_internal(&sub, options, depth + 1, total_items)?;
1181        pos += val_consumed;
1182
1183        entries.push((key, value));
1184    }
1185
1186    Ok((Value::Map(entries), pos))
1187}
1188
1189/// Parse RESP3 set zero-copy: ~<len>\r\n<elem>...
1190#[cfg(feature = "resp3")]
1191fn parse_set_bytes(
1192    data: &Bytes,
1193    options: &ParseOptions,
1194    depth: usize,
1195    total_items: &mut usize,
1196) -> Result<(Value, usize), ParseError> {
1197    if depth >= options.max_depth {
1198        return Err(ParseError::NestingTooDeep(depth));
1199    }
1200
1201    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1202    let len_str = std::str::from_utf8(&data[1..len_end])
1203        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
1204    let len: usize = len_str
1205        .parse()
1206        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
1207
1208    if len > options.max_collection_elements {
1209        return Err(ParseError::CollectionTooLarge(len));
1210    }
1211
1212    *total_items = total_items
1213        .checked_add(len)
1214        .ok_or(ParseError::CollectionTooLarge(usize::MAX))?;
1215    if *total_items > options.max_total_items {
1216        return Err(ParseError::CollectionTooLarge(*total_items));
1217    }
1218
1219    let mut pos = len_end + 2;
1220    let mut elements = Vec::with_capacity(len);
1221
1222    for _ in 0..len {
1223        if pos >= data.len() {
1224            return Err(ParseError::Incomplete);
1225        }
1226        let sub = data.slice(pos..);
1227        let (value, consumed) = Value::parse_bytes_internal(&sub, options, depth + 1, total_items)?;
1228        elements.push(value);
1229        pos += consumed;
1230    }
1231
1232    Ok((Value::Set(elements), pos))
1233}
1234
1235/// Parse RESP3 push message zero-copy: ><len>\r\n<elem>...
1236#[cfg(feature = "resp3")]
1237fn parse_push_bytes(
1238    data: &Bytes,
1239    options: &ParseOptions,
1240    depth: usize,
1241    total_items: &mut usize,
1242) -> Result<(Value, usize), ParseError> {
1243    if depth >= options.max_depth {
1244        return Err(ParseError::NestingTooDeep(depth));
1245    }
1246
1247    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1248    let len_str = std::str::from_utf8(&data[1..len_end])
1249        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
1250    let len: usize = len_str
1251        .parse()
1252        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
1253
1254    if len > options.max_collection_elements {
1255        return Err(ParseError::CollectionTooLarge(len));
1256    }
1257
1258    *total_items = total_items
1259        .checked_add(len)
1260        .ok_or(ParseError::CollectionTooLarge(usize::MAX))?;
1261    if *total_items > options.max_total_items {
1262        return Err(ParseError::CollectionTooLarge(*total_items));
1263    }
1264
1265    let mut pos = len_end + 2;
1266    let mut elements = Vec::with_capacity(len);
1267
1268    for _ in 0..len {
1269        if pos >= data.len() {
1270            return Err(ParseError::Incomplete);
1271        }
1272        let sub = data.slice(pos..);
1273        let (value, consumed) = Value::parse_bytes_internal(&sub, options, depth + 1, total_items)?;
1274        elements.push(value);
1275        pos += consumed;
1276    }
1277
1278    Ok((Value::Push(elements), pos))
1279}
1280
1281/// Parse RESP3 attribute zero-copy: |<len>\r\n<attrs>...<value>
1282#[cfg(feature = "resp3")]
1283fn parse_attribute_bytes(
1284    data: &Bytes,
1285    options: &ParseOptions,
1286    depth: usize,
1287    total_items: &mut usize,
1288) -> Result<(Value, usize), ParseError> {
1289    if depth >= options.max_depth {
1290        return Err(ParseError::NestingTooDeep(depth));
1291    }
1292
1293    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1294    let len_str = std::str::from_utf8(&data[1..len_end])
1295        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
1296    let len: usize = len_str
1297        .parse()
1298        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
1299
1300    if len > options.max_collection_elements {
1301        return Err(ParseError::CollectionTooLarge(len));
1302    }
1303
1304    let items_to_add = len
1305        .checked_mul(2)
1306        .and_then(|n| n.checked_add(1))
1307        .ok_or(ParseError::CollectionTooLarge(usize::MAX))?;
1308    *total_items = total_items
1309        .checked_add(items_to_add)
1310        .ok_or(ParseError::CollectionTooLarge(usize::MAX))?;
1311    if *total_items > options.max_total_items {
1312        return Err(ParseError::CollectionTooLarge(*total_items));
1313    }
1314
1315    let mut pos = len_end + 2;
1316    let mut attrs = Vec::with_capacity(len);
1317
1318    for _ in 0..len {
1319        if pos >= data.len() {
1320            return Err(ParseError::Incomplete);
1321        }
1322        let sub = data.slice(pos..);
1323        let (key, key_consumed) =
1324            Value::parse_bytes_internal(&sub, options, depth + 1, total_items)?;
1325        pos += key_consumed;
1326
1327        if pos >= data.len() {
1328            return Err(ParseError::Incomplete);
1329        }
1330        let sub = data.slice(pos..);
1331        let (val, val_consumed) =
1332            Value::parse_bytes_internal(&sub, options, depth + 1, total_items)?;
1333        pos += val_consumed;
1334
1335        attrs.push((key, val));
1336    }
1337
1338    if pos >= data.len() {
1339        return Err(ParseError::Incomplete);
1340    }
1341    let sub = data.slice(pos..);
1342    let (value, val_consumed) = Value::parse_bytes_internal(&sub, options, depth + 1, total_items)?;
1343    pos += val_consumed;
1344
1345    Ok((
1346        Value::Attribute {
1347            attrs,
1348            value: Box::new(value),
1349        },
1350        pos,
1351    ))
1352}
1353
1354// ============================================================================
1355// Encoding helpers
1356// ============================================================================
1357
1358/// Encode a simple string: +<data>\r\n
1359fn encode_simple_string(buf: &mut [u8], s: &[u8]) -> usize {
1360    buf[0] = b'+';
1361    buf[1..1 + s.len()].copy_from_slice(s);
1362    buf[1 + s.len()] = b'\r';
1363    buf[2 + s.len()] = b'\n';
1364    3 + s.len()
1365}
1366
1367/// Encode an error: -<data>\r\n
1368fn encode_error(buf: &mut [u8], msg: &[u8]) -> usize {
1369    buf[0] = b'-';
1370    buf[1..1 + msg.len()].copy_from_slice(msg);
1371    buf[1 + msg.len()] = b'\r';
1372    buf[2 + msg.len()] = b'\n';
1373    3 + msg.len()
1374}
1375
1376/// Encode an integer: :<n>\r\n
1377fn encode_integer(buf: &mut [u8], n: i64) -> usize {
1378    buf[0] = b':';
1379    let mut cursor = std::io::Cursor::new(&mut buf[1..]);
1380    write!(cursor, "{}\r\n", n).unwrap();
1381    1 + cursor.position() as usize
1382}
1383
1384/// Encode a bulk string: $<len>\r\n<data>\r\n
1385fn encode_bulk_string(buf: &mut [u8], data: &[u8]) -> usize {
1386    buf[0] = b'$';
1387    let mut cursor = std::io::Cursor::new(&mut buf[1..]);
1388    write!(cursor, "{}\r\n", data.len()).unwrap();
1389    let header_len = 1 + cursor.position() as usize;
1390
1391    buf[header_len..header_len + data.len()].copy_from_slice(data);
1392    buf[header_len + data.len()] = b'\r';
1393    buf[header_len + data.len() + 1] = b'\n';
1394    header_len + data.len() + 2
1395}
1396
1397/// Encode null (RESP2 format): $-1\r\n
1398fn encode_resp2_null(buf: &mut [u8]) -> usize {
1399    buf[..5].copy_from_slice(b"$-1\r\n");
1400    5
1401}
1402
1403/// Encode an array: *<len>\r\n<elements>
1404fn encode_array(buf: &mut [u8], elements: &[Value]) -> usize {
1405    buf[0] = b'*';
1406    let mut cursor = std::io::Cursor::new(&mut buf[1..]);
1407    write!(cursor, "{}\r\n", elements.len()).unwrap();
1408    let mut pos = 1 + cursor.position() as usize;
1409
1410    for element in elements {
1411        pos += element.encode(&mut buf[pos..]);
1412    }
1413    pos
1414}
1415
1416// ============================================================================
1417// RESP3 Parsing helpers
1418// ============================================================================
1419
1420/// Parse RESP3 null: _\r\n
1421#[cfg(feature = "resp3")]
1422fn parse_null(data: &[u8]) -> Result<(Value, usize), ParseError> {
1423    if data.len() < 3 {
1424        return Err(ParseError::Incomplete);
1425    }
1426    if data[1] != b'\r' || data[2] != b'\n' {
1427        return Err(ParseError::Protocol("expected CRLF after null".to_string()));
1428    }
1429    Ok((Value::Null, 3))
1430}
1431
1432/// Parse RESP3 boolean: #t\r\n or #f\r\n
1433#[cfg(feature = "resp3")]
1434fn parse_boolean(data: &[u8]) -> Result<(Value, usize), ParseError> {
1435    if data.len() < 4 {
1436        return Err(ParseError::Incomplete);
1437    }
1438    let value = match data[1] {
1439        b't' => true,
1440        b'f' => false,
1441        _ => return Err(ParseError::InvalidBoolean),
1442    };
1443    if data[2] != b'\r' || data[3] != b'\n' {
1444        return Err(ParseError::Protocol(
1445            "expected CRLF after boolean".to_string(),
1446        ));
1447    }
1448    Ok((Value::Boolean(value), 4))
1449}
1450
1451/// Parse RESP3 double: ,3.14159\r\n
1452#[cfg(feature = "resp3")]
1453fn parse_double(data: &[u8]) -> Result<(Value, usize), ParseError> {
1454    let end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1455    let s =
1456        std::str::from_utf8(&data[1..end]).map_err(|e| ParseError::InvalidDouble(e.to_string()))?;
1457
1458    // Handle special values
1459    let value = match s {
1460        "inf" => f64::INFINITY,
1461        "-inf" => f64::NEG_INFINITY,
1462        "nan" => f64::NAN,
1463        _ => s
1464            .parse()
1465            .map_err(|e: std::num::ParseFloatError| ParseError::InvalidDouble(e.to_string()))?,
1466    };
1467    Ok((Value::Double(value), end + 2))
1468}
1469
1470/// Parse RESP3 big number: (12345678901234567890\r\n
1471#[cfg(feature = "resp3")]
1472fn parse_big_number(data: &[u8]) -> Result<(Value, usize), ParseError> {
1473    let end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1474    let content = Bytes::copy_from_slice(&data[1..end]);
1475    Ok((Value::BigNumber(content), end + 2))
1476}
1477
1478/// Parse RESP3 bulk error: !<len>\r\n<error>\r\n
1479#[cfg(feature = "resp3")]
1480fn parse_bulk_error(data: &[u8], options: &ParseOptions) -> Result<(Value, usize), ParseError> {
1481    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1482    let len_str = std::str::from_utf8(&data[1..len_end])
1483        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
1484    let len: usize = len_str
1485        .parse()
1486        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
1487
1488    if len > options.max_bulk_string_len {
1489        return Err(ParseError::Protocol("bulk error too large".to_string()));
1490    }
1491
1492    let data_start = len_end + 2;
1493    let data_end = data_start
1494        .checked_add(len)
1495        .ok_or_else(|| ParseError::InvalidInteger("length overflow".to_string()))?;
1496    let total_end = data_end
1497        .checked_add(2)
1498        .ok_or_else(|| ParseError::InvalidInteger("length overflow".to_string()))?;
1499
1500    if data.len() < total_end {
1501        return Err(ParseError::Incomplete);
1502    }
1503
1504    if data[data_end] != b'\r' || data[data_end + 1] != b'\n' {
1505        return Err(ParseError::Protocol("missing trailing CRLF".to_string()));
1506    }
1507
1508    let content = Bytes::copy_from_slice(&data[data_start..data_end]);
1509    Ok((Value::BulkError(content), total_end))
1510}
1511
1512/// Parse RESP3 verbatim string: =<len>\r\ntxt:<data>\r\n
1513#[cfg(feature = "resp3")]
1514fn parse_verbatim_string(
1515    data: &[u8],
1516    options: &ParseOptions,
1517) -> Result<(Value, usize), ParseError> {
1518    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1519    let len_str = std::str::from_utf8(&data[1..len_end])
1520        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
1521    let len: usize = len_str
1522        .parse()
1523        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
1524
1525    if len > options.max_bulk_string_len {
1526        return Err(ParseError::Protocol(
1527            "verbatim string too large".to_string(),
1528        ));
1529    }
1530
1531    let data_start = len_end + 2;
1532    let data_end = data_start
1533        .checked_add(len)
1534        .ok_or_else(|| ParseError::InvalidInteger("length overflow".to_string()))?;
1535    let total_end = data_end
1536        .checked_add(2)
1537        .ok_or_else(|| ParseError::InvalidInteger("length overflow".to_string()))?;
1538
1539    if data.len() < total_end {
1540        return Err(ParseError::Incomplete);
1541    }
1542
1543    // Format is: fmt:data where fmt is 3 bytes
1544    if len < 4 || data[data_start + 3] != b':' {
1545        return Err(ParseError::InvalidVerbatimFormat);
1546    }
1547
1548    if data[data_end] != b'\r' || data[data_end + 1] != b'\n' {
1549        return Err(ParseError::Protocol("missing trailing CRLF".to_string()));
1550    }
1551
1552    let format: [u8; 3] = data[data_start..data_start + 3]
1553        .try_into()
1554        .map_err(|_| ParseError::InvalidVerbatimFormat)?;
1555    let content = Bytes::copy_from_slice(&data[data_start + 4..data_end]);
1556
1557    Ok((
1558        Value::VerbatimString {
1559            format,
1560            data: content,
1561        },
1562        total_end,
1563    ))
1564}
1565
1566/// Parse RESP3 map: %<len>\r\n<key><val>...
1567#[cfg(feature = "resp3")]
1568fn parse_map(
1569    data: &[u8],
1570    options: &ParseOptions,
1571    depth: usize,
1572    total_items: &mut usize,
1573) -> Result<(Value, usize), ParseError> {
1574    if depth >= options.max_depth {
1575        return Err(ParseError::NestingTooDeep(depth));
1576    }
1577
1578    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1579    let len_str = std::str::from_utf8(&data[1..len_end])
1580        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
1581    let len: usize = len_str
1582        .parse()
1583        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
1584
1585    if len > options.max_collection_elements {
1586        return Err(ParseError::CollectionTooLarge(len));
1587    }
1588
1589    // Check total items budget (map entries count as 2 items each: key + value)
1590    let items_to_add = len
1591        .checked_mul(2)
1592        .ok_or(ParseError::CollectionTooLarge(usize::MAX))?;
1593    *total_items = total_items
1594        .checked_add(items_to_add)
1595        .ok_or(ParseError::CollectionTooLarge(usize::MAX))?;
1596    if *total_items > options.max_total_items {
1597        return Err(ParseError::CollectionTooLarge(*total_items));
1598    }
1599
1600    let mut pos = len_end + 2;
1601    let mut entries = Vec::with_capacity(len);
1602
1603    for _ in 0..len {
1604        if pos >= data.len() {
1605            return Err(ParseError::Incomplete);
1606        }
1607        let (key, key_consumed) =
1608            Value::parse_internal(&data[pos..], options, depth + 1, total_items)?;
1609        pos += key_consumed;
1610
1611        if pos >= data.len() {
1612            return Err(ParseError::Incomplete);
1613        }
1614        let (value, val_consumed) =
1615            Value::parse_internal(&data[pos..], options, depth + 1, total_items)?;
1616        pos += val_consumed;
1617
1618        entries.push((key, value));
1619    }
1620
1621    Ok((Value::Map(entries), pos))
1622}
1623
1624/// Parse RESP3 set: ~<len>\r\n<elem>...
1625#[cfg(feature = "resp3")]
1626fn parse_set(
1627    data: &[u8],
1628    options: &ParseOptions,
1629    depth: usize,
1630    total_items: &mut usize,
1631) -> Result<(Value, usize), ParseError> {
1632    if depth >= options.max_depth {
1633        return Err(ParseError::NestingTooDeep(depth));
1634    }
1635
1636    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1637    let len_str = std::str::from_utf8(&data[1..len_end])
1638        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
1639    let len: usize = len_str
1640        .parse()
1641        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
1642
1643    if len > options.max_collection_elements {
1644        return Err(ParseError::CollectionTooLarge(len));
1645    }
1646
1647    // Check total items budget
1648    *total_items = total_items
1649        .checked_add(len)
1650        .ok_or(ParseError::CollectionTooLarge(usize::MAX))?;
1651    if *total_items > options.max_total_items {
1652        return Err(ParseError::CollectionTooLarge(*total_items));
1653    }
1654
1655    let mut pos = len_end + 2;
1656    let mut elements = Vec::with_capacity(len);
1657
1658    for _ in 0..len {
1659        if pos >= data.len() {
1660            return Err(ParseError::Incomplete);
1661        }
1662        let (value, consumed) =
1663            Value::parse_internal(&data[pos..], options, depth + 1, total_items)?;
1664        elements.push(value);
1665        pos += consumed;
1666    }
1667
1668    Ok((Value::Set(elements), pos))
1669}
1670
1671/// Parse RESP3 push message: ><len>\r\n<elem>...
1672#[cfg(feature = "resp3")]
1673fn parse_push(
1674    data: &[u8],
1675    options: &ParseOptions,
1676    depth: usize,
1677    total_items: &mut usize,
1678) -> Result<(Value, usize), ParseError> {
1679    if depth >= options.max_depth {
1680        return Err(ParseError::NestingTooDeep(depth));
1681    }
1682
1683    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1684    let len_str = std::str::from_utf8(&data[1..len_end])
1685        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
1686    let len: usize = len_str
1687        .parse()
1688        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
1689
1690    if len > options.max_collection_elements {
1691        return Err(ParseError::CollectionTooLarge(len));
1692    }
1693
1694    // Check total items budget
1695    *total_items = total_items
1696        .checked_add(len)
1697        .ok_or(ParseError::CollectionTooLarge(usize::MAX))?;
1698    if *total_items > options.max_total_items {
1699        return Err(ParseError::CollectionTooLarge(*total_items));
1700    }
1701
1702    let mut pos = len_end + 2;
1703    let mut elements = Vec::with_capacity(len);
1704
1705    for _ in 0..len {
1706        if pos >= data.len() {
1707            return Err(ParseError::Incomplete);
1708        }
1709        let (value, consumed) =
1710            Value::parse_internal(&data[pos..], options, depth + 1, total_items)?;
1711        elements.push(value);
1712        pos += consumed;
1713    }
1714
1715    Ok((Value::Push(elements), pos))
1716}
1717
1718/// Parse RESP3 attribute: |<len>\r\n<attrs>...<value>
1719#[cfg(feature = "resp3")]
1720fn parse_attribute(
1721    data: &[u8],
1722    options: &ParseOptions,
1723    depth: usize,
1724    total_items: &mut usize,
1725) -> Result<(Value, usize), ParseError> {
1726    if depth >= options.max_depth {
1727        return Err(ParseError::NestingTooDeep(depth));
1728    }
1729
1730    let len_end = find_crlf(data).ok_or(ParseError::Incomplete)?;
1731    let len_str = std::str::from_utf8(&data[1..len_end])
1732        .map_err(|e| ParseError::InvalidInteger(e.to_string()))?;
1733    let len: usize = len_str
1734        .parse()
1735        .map_err(|e: std::num::ParseIntError| ParseError::InvalidInteger(e.to_string()))?;
1736
1737    if len > options.max_collection_elements {
1738        return Err(ParseError::CollectionTooLarge(len));
1739    }
1740
1741    // Check total items budget (attribute entries count as 2 items each: key + value, plus 1 for the value)
1742    let items_to_add = len
1743        .checked_mul(2)
1744        .and_then(|n| n.checked_add(1))
1745        .ok_or(ParseError::CollectionTooLarge(usize::MAX))?;
1746    *total_items = total_items
1747        .checked_add(items_to_add)
1748        .ok_or(ParseError::CollectionTooLarge(usize::MAX))?;
1749    if *total_items > options.max_total_items {
1750        return Err(ParseError::CollectionTooLarge(*total_items));
1751    }
1752
1753    let mut pos = len_end + 2;
1754    let mut attrs = Vec::with_capacity(len);
1755
1756    for _ in 0..len {
1757        if pos >= data.len() {
1758            return Err(ParseError::Incomplete);
1759        }
1760        let (key, key_consumed) =
1761            Value::parse_internal(&data[pos..], options, depth + 1, total_items)?;
1762        pos += key_consumed;
1763
1764        if pos >= data.len() {
1765            return Err(ParseError::Incomplete);
1766        }
1767        let (val, val_consumed) =
1768            Value::parse_internal(&data[pos..], options, depth + 1, total_items)?;
1769        pos += val_consumed;
1770
1771        attrs.push((key, val));
1772    }
1773
1774    // Parse the actual value that follows the attributes
1775    if pos >= data.len() {
1776        return Err(ParseError::Incomplete);
1777    }
1778    let (value, val_consumed) =
1779        Value::parse_internal(&data[pos..], options, depth + 1, total_items)?;
1780    pos += val_consumed;
1781
1782    Ok((
1783        Value::Attribute {
1784            attrs,
1785            value: Box::new(value),
1786        },
1787        pos,
1788    ))
1789}
1790
1791// ============================================================================
1792// RESP3 Encoding helpers
1793// ============================================================================
1794
1795/// Encode RESP3 boolean: #t\r\n or #f\r\n
1796#[cfg(feature = "resp3")]
1797fn encode_boolean(buf: &mut [u8], b: bool) -> usize {
1798    buf[0] = b'#';
1799    buf[1] = if b { b't' } else { b'f' };
1800    buf[2] = b'\r';
1801    buf[3] = b'\n';
1802    4
1803}
1804
1805/// Encode RESP3 double: ,<float>\r\n
1806#[cfg(feature = "resp3")]
1807fn encode_double(buf: &mut [u8], d: f64) -> usize {
1808    buf[0] = b',';
1809    let s = if d.is_infinite() {
1810        if d.is_sign_positive() { "inf" } else { "-inf" }
1811    } else if d.is_nan() {
1812        "nan"
1813    } else {
1814        // Use ryu for efficient float formatting
1815        let mut ryu_buf = ryu::Buffer::new();
1816        let formatted = ryu_buf.format(d);
1817        buf[1..1 + formatted.len()].copy_from_slice(formatted.as_bytes());
1818        buf[1 + formatted.len()] = b'\r';
1819        buf[2 + formatted.len()] = b'\n';
1820        return 3 + formatted.len();
1821    };
1822    buf[1..1 + s.len()].copy_from_slice(s.as_bytes());
1823    buf[1 + s.len()] = b'\r';
1824    buf[2 + s.len()] = b'\n';
1825    3 + s.len()
1826}
1827
1828/// Encode RESP3 big number: (<num>\r\n
1829#[cfg(feature = "resp3")]
1830fn encode_big_number(buf: &mut [u8], n: &[u8]) -> usize {
1831    buf[0] = b'(';
1832    buf[1..1 + n.len()].copy_from_slice(n);
1833    buf[1 + n.len()] = b'\r';
1834    buf[2 + n.len()] = b'\n';
1835    3 + n.len()
1836}
1837
1838/// Encode RESP3 bulk error: !<len>\r\n<msg>\r\n
1839#[cfg(feature = "resp3")]
1840fn encode_bulk_error(buf: &mut [u8], msg: &[u8]) -> usize {
1841    buf[0] = b'!';
1842    let mut cursor = std::io::Cursor::new(&mut buf[1..]);
1843    write!(cursor, "{}\r\n", msg.len()).unwrap();
1844    let header_len = 1 + cursor.position() as usize;
1845
1846    buf[header_len..header_len + msg.len()].copy_from_slice(msg);
1847    buf[header_len + msg.len()] = b'\r';
1848    buf[header_len + msg.len() + 1] = b'\n';
1849    header_len + msg.len() + 2
1850}
1851
1852/// Encode RESP3 verbatim string: =<len>\r\n<fmt>:<data>\r\n
1853#[cfg(feature = "resp3")]
1854fn encode_verbatim_string(buf: &mut [u8], format: &[u8; 3], data: &[u8]) -> usize {
1855    buf[0] = b'=';
1856    let total_len = 4 + data.len(); // "fmt:" + data
1857    let mut cursor = std::io::Cursor::new(&mut buf[1..]);
1858    write!(cursor, "{}\r\n", total_len).unwrap();
1859    let header_len = 1 + cursor.position() as usize;
1860
1861    buf[header_len..header_len + 3].copy_from_slice(format);
1862    buf[header_len + 3] = b':';
1863    buf[header_len + 4..header_len + 4 + data.len()].copy_from_slice(data);
1864    buf[header_len + 4 + data.len()] = b'\r';
1865    buf[header_len + 5 + data.len()] = b'\n';
1866    header_len + 6 + data.len()
1867}
1868
1869/// Encode RESP3 map: %<len>\r\n<key><val>...
1870#[cfg(feature = "resp3")]
1871fn encode_map(buf: &mut [u8], entries: &[(Value, Value)]) -> usize {
1872    buf[0] = b'%';
1873    let mut cursor = std::io::Cursor::new(&mut buf[1..]);
1874    write!(cursor, "{}\r\n", entries.len()).unwrap();
1875    let mut pos = 1 + cursor.position() as usize;
1876
1877    for (key, value) in entries {
1878        pos += key.encode(&mut buf[pos..]);
1879        pos += value.encode(&mut buf[pos..]);
1880    }
1881    pos
1882}
1883
1884/// Encode RESP3 set: ~<len>\r\n<elem>...
1885#[cfg(feature = "resp3")]
1886fn encode_set(buf: &mut [u8], elements: &[Value]) -> usize {
1887    buf[0] = b'~';
1888    let mut cursor = std::io::Cursor::new(&mut buf[1..]);
1889    write!(cursor, "{}\r\n", elements.len()).unwrap();
1890    let mut pos = 1 + cursor.position() as usize;
1891
1892    for element in elements {
1893        pos += element.encode(&mut buf[pos..]);
1894    }
1895    pos
1896}
1897
1898/// Encode RESP3 push: ><len>\r\n<elem>...
1899#[cfg(feature = "resp3")]
1900fn encode_push(buf: &mut [u8], elements: &[Value]) -> usize {
1901    buf[0] = b'>';
1902    let mut cursor = std::io::Cursor::new(&mut buf[1..]);
1903    write!(cursor, "{}\r\n", elements.len()).unwrap();
1904    let mut pos = 1 + cursor.position() as usize;
1905
1906    for element in elements {
1907        pos += element.encode(&mut buf[pos..]);
1908    }
1909    pos
1910}
1911
1912/// Encode RESP3 attribute: |<len>\r\n<attrs>...<value>
1913#[cfg(feature = "resp3")]
1914fn encode_attribute(buf: &mut [u8], attrs: &[(Value, Value)], value: &Value) -> usize {
1915    buf[0] = b'|';
1916    let mut cursor = std::io::Cursor::new(&mut buf[1..]);
1917    write!(cursor, "{}\r\n", attrs.len()).unwrap();
1918    let mut pos = 1 + cursor.position() as usize;
1919
1920    for (key, val) in attrs {
1921        pos += key.encode(&mut buf[pos..]);
1922        pos += val.encode(&mut buf[pos..]);
1923    }
1924    pos += value.encode(&mut buf[pos..]);
1925    pos
1926}
1927
1928// ============================================================================
1929// Common response values (for server use)
1930// ============================================================================
1931
1932impl Value {
1933    /// OK simple string response.
1934    pub const OK: &'static [u8] = b"+OK\r\n";
1935
1936    /// PONG simple string response.
1937    pub const PONG: &'static [u8] = b"+PONG\r\n";
1938
1939    /// Null bulk string response.
1940    pub const NULL_BULK: &'static [u8] = b"$-1\r\n";
1941
1942    /// Empty array response.
1943    pub const EMPTY_ARRAY: &'static [u8] = b"*0\r\n";
1944
1945    /// Encode an OK response directly to a buffer.
1946    #[inline]
1947    pub fn encode_ok(buf: &mut [u8]) -> usize {
1948        buf[..5].copy_from_slice(Self::OK);
1949        5
1950    }
1951
1952    /// Encode a PONG response directly to a buffer.
1953    #[inline]
1954    pub fn encode_pong(buf: &mut [u8]) -> usize {
1955        buf[..7].copy_from_slice(Self::PONG);
1956        7
1957    }
1958
1959    /// Encode a null bulk string response directly to a buffer.
1960    #[inline]
1961    pub fn encode_null_bulk(buf: &mut [u8]) -> usize {
1962        buf[..5].copy_from_slice(Self::NULL_BULK);
1963        5
1964    }
1965
1966    /// Encode an integer response directly to a buffer.
1967    #[inline]
1968    pub fn encode_int(buf: &mut [u8], n: i64) -> usize {
1969        encode_integer(buf, n)
1970    }
1971
1972    /// Encode a bulk string response directly to a buffer (zero-copy for data).
1973    #[inline]
1974    pub fn encode_bulk(buf: &mut [u8], data: &[u8]) -> usize {
1975        encode_bulk_string(buf, data)
1976    }
1977
1978    /// Encode an error response directly to a buffer.
1979    #[inline]
1980    pub fn encode_err(buf: &mut [u8], msg: &[u8]) -> usize {
1981        encode_error(buf, msg)
1982    }
1983}
1984
1985#[cfg(test)]
1986mod tests {
1987    use super::*;
1988
1989    #[test]
1990    fn test_parse_simple_string() {
1991        let (value, consumed) = Value::parse(b"+OK\r\n").unwrap();
1992        assert_eq!(value, Value::SimpleString(Bytes::from_static(b"OK")));
1993        assert_eq!(consumed, 5);
1994    }
1995
1996    #[test]
1997    fn test_parse_error() {
1998        let (value, consumed) = Value::parse(b"-ERR unknown command\r\n").unwrap();
1999        assert_eq!(
2000            value,
2001            Value::Error(Bytes::from_static(b"ERR unknown command"))
2002        );
2003        assert_eq!(consumed, 22);
2004    }
2005
2006    #[test]
2007    fn test_parse_integer() {
2008        let (value, consumed) = Value::parse(b":1000\r\n").unwrap();
2009        assert_eq!(value, Value::Integer(1000));
2010        assert_eq!(consumed, 7);
2011
2012        let (value, _) = Value::parse(b":-42\r\n").unwrap();
2013        assert_eq!(value, Value::Integer(-42));
2014    }
2015
2016    #[test]
2017    fn test_parse_bulk_string() {
2018        let (value, consumed) = Value::parse(b"$6\r\nfoobar\r\n").unwrap();
2019        assert_eq!(value, Value::BulkString(Bytes::from_static(b"foobar")));
2020        assert_eq!(consumed, 12);
2021    }
2022
2023    #[test]
2024    fn test_parse_null() {
2025        let (value, consumed) = Value::parse(b"$-1\r\n").unwrap();
2026        assert_eq!(value, Value::Null);
2027        assert_eq!(consumed, 5);
2028    }
2029
2030    #[test]
2031    fn test_parse_array() {
2032        let (value, consumed) = Value::parse(b"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n").unwrap();
2033        assert_eq!(
2034            value,
2035            Value::Array(vec![
2036                Value::BulkString(Bytes::from_static(b"foo")),
2037                Value::BulkString(Bytes::from_static(b"bar")),
2038            ])
2039        );
2040        assert_eq!(consumed, 22);
2041    }
2042
2043    #[test]
2044    fn test_parse_empty_array() {
2045        let (value, consumed) = Value::parse(b"*0\r\n").unwrap();
2046        assert_eq!(value, Value::Array(vec![]));
2047        assert_eq!(consumed, 4);
2048    }
2049
2050    #[test]
2051    fn test_parse_incomplete() {
2052        assert!(matches!(
2053            Value::parse(b"$6\r\nfoo"),
2054            Err(ParseError::Incomplete)
2055        ));
2056        assert!(matches!(Value::parse(b"+OK"), Err(ParseError::Incomplete)));
2057        assert!(matches!(Value::parse(b""), Err(ParseError::Incomplete)));
2058    }
2059
2060    #[test]
2061    fn test_encode_simple_string() {
2062        let mut buf = [0u8; 64];
2063        let len = Value::simple_string(b"OK").encode(&mut buf);
2064        assert_eq!(&buf[..len], b"+OK\r\n");
2065    }
2066
2067    #[test]
2068    fn test_encode_error() {
2069        let mut buf = [0u8; 64];
2070        let len = Value::error(b"ERR unknown").encode(&mut buf);
2071        assert_eq!(&buf[..len], b"-ERR unknown\r\n");
2072    }
2073
2074    #[test]
2075    fn test_encode_integer() {
2076        let mut buf = [0u8; 64];
2077        let len = Value::integer(42).encode(&mut buf);
2078        assert_eq!(&buf[..len], b":42\r\n");
2079
2080        let len = Value::integer(-100).encode(&mut buf);
2081        assert_eq!(&buf[..len], b":-100\r\n");
2082    }
2083
2084    #[test]
2085    fn test_encode_bulk_string() {
2086        let mut buf = [0u8; 64];
2087        let len = Value::bulk_string(b"hello").encode(&mut buf);
2088        assert_eq!(&buf[..len], b"$5\r\nhello\r\n");
2089    }
2090
2091    #[test]
2092    fn test_encode_null() {
2093        let mut buf = [0u8; 64];
2094        let len = Value::null().encode(&mut buf);
2095        assert_eq!(&buf[..len], b"$-1\r\n");
2096    }
2097
2098    #[test]
2099    fn test_encode_array() {
2100        let mut buf = [0u8; 64];
2101        let arr = Value::array(vec![Value::bulk_string(b"foo"), Value::bulk_string(b"bar")]);
2102        let len = arr.encode(&mut buf);
2103        assert_eq!(&buf[..len], b"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n");
2104    }
2105
2106    #[test]
2107    fn test_roundtrip() {
2108        let values = vec![
2109            Value::simple_string(b"OK"),
2110            Value::error(b"ERR test"),
2111            Value::integer(12345),
2112            Value::bulk_string(b"hello world"),
2113            Value::null(),
2114            Value::array(vec![
2115                Value::integer(1),
2116                Value::bulk_string(b"two"),
2117                Value::null(),
2118            ]),
2119        ];
2120
2121        for original in values {
2122            let mut buf = [0u8; 256];
2123            let len = original.encode(&mut buf);
2124            let (parsed, consumed) = Value::parse(&buf[..len]).unwrap();
2125            assert_eq!(original, parsed);
2126            assert_eq!(len, consumed);
2127        }
2128    }
2129
2130    #[test]
2131    fn test_encoded_len() {
2132        let values = vec![
2133            Value::simple_string(b"OK"),
2134            Value::error(b"ERR test"),
2135            Value::integer(12345),
2136            Value::bulk_string(b"hello world"),
2137            Value::null(),
2138            Value::array(vec![Value::integer(1), Value::bulk_string(b"two")]),
2139        ];
2140
2141        for value in values {
2142            let mut buf = [0u8; 256];
2143            let actual_len = value.encode(&mut buf);
2144            assert_eq!(value.encoded_len(), actual_len);
2145        }
2146    }
2147
2148    // ========================================================================
2149    // Type Check Tests
2150    // ========================================================================
2151
2152    #[test]
2153    fn test_is_null() {
2154        assert!(Value::Null.is_null());
2155        assert!(!Value::integer(1).is_null());
2156    }
2157
2158    #[test]
2159    fn test_is_error() {
2160        assert!(Value::error(b"ERR").is_error());
2161        assert!(!Value::simple_string(b"OK").is_error());
2162    }
2163
2164    #[test]
2165    fn test_is_simple_string() {
2166        assert!(Value::simple_string(b"OK").is_simple_string());
2167        assert!(!Value::bulk_string(b"OK").is_simple_string());
2168    }
2169
2170    #[test]
2171    fn test_is_bulk_string() {
2172        assert!(Value::bulk_string(b"data").is_bulk_string());
2173        assert!(!Value::simple_string(b"data").is_bulk_string());
2174    }
2175
2176    #[test]
2177    fn test_is_integer() {
2178        assert!(Value::integer(42).is_integer());
2179        assert!(!Value::bulk_string(b"42").is_integer());
2180    }
2181
2182    #[test]
2183    fn test_is_array() {
2184        assert!(Value::array(vec![]).is_array());
2185        assert!(!Value::null().is_array());
2186    }
2187
2188    // ========================================================================
2189    // Accessor Tests
2190    // ========================================================================
2191
2192    #[test]
2193    fn test_as_bytes() {
2194        assert_eq!(Value::simple_string(b"OK").as_bytes(), Some(&b"OK"[..]));
2195        assert_eq!(Value::bulk_string(b"data").as_bytes(), Some(&b"data"[..]));
2196        assert_eq!(Value::error(b"ERR").as_bytes(), Some(&b"ERR"[..]));
2197        assert_eq!(Value::integer(42).as_bytes(), None);
2198        assert_eq!(Value::null().as_bytes(), None);
2199    }
2200
2201    #[test]
2202    fn test_as_integer() {
2203        assert_eq!(Value::integer(42).as_integer(), Some(42));
2204        assert_eq!(Value::integer(-100).as_integer(), Some(-100));
2205        assert_eq!(Value::bulk_string(b"42").as_integer(), None);
2206    }
2207
2208    #[test]
2209    fn test_as_array() {
2210        let arr = Value::array(vec![Value::integer(1), Value::integer(2)]);
2211        assert_eq!(arr.as_array().map(|a| a.len()), Some(2));
2212        assert_eq!(Value::null().as_array(), None);
2213    }
2214
2215    // ========================================================================
2216    // Static Response Tests
2217    // ========================================================================
2218
2219    #[test]
2220    fn test_encode_ok() {
2221        let mut buf = [0u8; 16];
2222        let len = Value::encode_ok(&mut buf);
2223        assert_eq!(&buf[..len], b"+OK\r\n");
2224    }
2225
2226    #[test]
2227    fn test_encode_pong() {
2228        let mut buf = [0u8; 16];
2229        let len = Value::encode_pong(&mut buf);
2230        assert_eq!(&buf[..len], b"+PONG\r\n");
2231    }
2232
2233    #[test]
2234    fn test_encode_null_bulk() {
2235        let mut buf = [0u8; 16];
2236        let len = Value::encode_null_bulk(&mut buf);
2237        assert_eq!(&buf[..len], b"$-1\r\n");
2238    }
2239
2240    #[test]
2241    fn test_encode_int() {
2242        let mut buf = [0u8; 32];
2243        let len = Value::encode_int(&mut buf, 42);
2244        assert_eq!(&buf[..len], b":42\r\n");
2245
2246        let len = Value::encode_int(&mut buf, -100);
2247        assert_eq!(&buf[..len], b":-100\r\n");
2248    }
2249
2250    #[test]
2251    fn test_encode_bulk() {
2252        let mut buf = [0u8; 32];
2253        let len = Value::encode_bulk(&mut buf, b"hello");
2254        assert_eq!(&buf[..len], b"$5\r\nhello\r\n");
2255    }
2256
2257    #[test]
2258    fn test_encode_err() {
2259        let mut buf = [0u8; 64];
2260        let len = Value::encode_err(&mut buf, b"ERR unknown command");
2261        assert_eq!(&buf[..len], b"-ERR unknown command\r\n");
2262    }
2263
2264    // ========================================================================
2265    // Static Constants Tests
2266    // ========================================================================
2267
2268    #[test]
2269    fn test_static_constants() {
2270        assert_eq!(Value::OK, b"+OK\r\n");
2271        assert_eq!(Value::PONG, b"+PONG\r\n");
2272        assert_eq!(Value::NULL_BULK, b"$-1\r\n");
2273        assert_eq!(Value::EMPTY_ARRAY, b"*0\r\n");
2274    }
2275
2276    // ========================================================================
2277    // Error Path Tests
2278    // ========================================================================
2279
2280    #[test]
2281    fn test_parse_invalid_prefix() {
2282        // Use an invalid prefix byte
2283        let result = Value::parse(b"Q12345\r\n");
2284        assert!(matches!(result, Err(ParseError::InvalidPrefix(b'Q'))));
2285    }
2286
2287    #[test]
2288    fn test_parse_bulk_string_missing_crlf() {
2289        // Bulk string without proper trailing CRLF (has wrong bytes after data)
2290        let result = Value::parse(b"$5\r\nhelloXY");
2291        assert!(matches!(result, Err(ParseError::Protocol(_))));
2292    }
2293
2294    #[test]
2295    fn test_parse_null_array() {
2296        // Null array (negative length)
2297        let (value, consumed) = Value::parse(b"*-1\r\n").unwrap();
2298        assert_eq!(value, Value::Null);
2299        assert_eq!(consumed, 5);
2300    }
2301
2302    #[test]
2303    fn test_parse_array_collection_too_large() {
2304        // Array claiming to have too many elements
2305        let result = Value::parse(b"*99999999\r\n");
2306        assert!(matches!(result, Err(ParseError::CollectionTooLarge(_))));
2307    }
2308
2309    #[test]
2310    fn test_parse_nested_array() {
2311        // Array containing another array
2312        let data = b"*2\r\n*2\r\n:1\r\n:2\r\n*2\r\n:3\r\n:4\r\n";
2313        let (value, consumed) = Value::parse(data).unwrap();
2314        assert_eq!(
2315            value,
2316            Value::Array(vec![
2317                Value::Array(vec![Value::Integer(1), Value::Integer(2)]),
2318                Value::Array(vec![Value::Integer(3), Value::Integer(4)]),
2319            ])
2320        );
2321        assert_eq!(consumed, data.len());
2322    }
2323
2324    #[test]
2325    fn test_value_clone() {
2326        let v1 = Value::array(vec![Value::integer(1), Value::bulk_string(b"test")]);
2327        let v2 = v1.clone();
2328        assert_eq!(v1, v2);
2329    }
2330
2331    #[test]
2332    fn test_value_debug() {
2333        let value = Value::integer(42);
2334        let debug_str = format!("{:?}", value);
2335        assert!(debug_str.contains("Integer"));
2336        assert!(debug_str.contains("42"));
2337    }
2338
2339    #[test]
2340    fn test_large_integer() {
2341        let (value, _) = Value::parse(b":9223372036854775807\r\n").unwrap();
2342        assert_eq!(value, Value::Integer(i64::MAX));
2343
2344        let (value, _) = Value::parse(b":-9223372036854775808\r\n").unwrap();
2345        assert_eq!(value, Value::Integer(i64::MIN));
2346    }
2347
2348    #[test]
2349    fn test_empty_bulk_string() {
2350        let (value, consumed) = Value::parse(b"$0\r\n\r\n").unwrap();
2351        assert_eq!(value, Value::BulkString(Bytes::new()));
2352        assert_eq!(consumed, 6);
2353    }
2354
2355    #[test]
2356    fn test_binary_bulk_string() {
2357        // Bulk string with binary data including null bytes
2358        let (value, _) = Value::parse(b"$5\r\n\x00\x01\x02\x03\x04\r\n").unwrap();
2359        assert_eq!(
2360            value,
2361            Value::BulkString(Bytes::from_static(&[0, 1, 2, 3, 4]))
2362        );
2363    }
2364
2365    // ========================================================================
2366    // RESP3 Tests
2367    // ========================================================================
2368
2369    #[cfg(feature = "resp3")]
2370    mod resp3_tests {
2371        use super::*;
2372
2373        #[test]
2374        fn test_parse_resp3_null() {
2375            let (value, consumed) = Value::parse(b"_\r\n").unwrap();
2376            assert_eq!(value, Value::Null);
2377            assert_eq!(consumed, 3);
2378        }
2379
2380        #[test]
2381        fn test_parse_boolean() {
2382            let (value, consumed) = Value::parse(b"#t\r\n").unwrap();
2383            assert_eq!(value, Value::Boolean(true));
2384            assert_eq!(consumed, 4);
2385
2386            let (value, consumed) = Value::parse(b"#f\r\n").unwrap();
2387            assert_eq!(value, Value::Boolean(false));
2388            assert_eq!(consumed, 4);
2389        }
2390
2391        #[test]
2392        fn test_parse_double() {
2393            let (value, consumed) = Value::parse(b",1.23456\r\n").unwrap();
2394            if let Value::Double(d) = value {
2395                assert!((d - 1.23456).abs() < 0.00001);
2396            } else {
2397                panic!("Expected Double");
2398            }
2399            assert_eq!(consumed, 10);
2400
2401            // Test special values
2402            let (value, _) = Value::parse(b",inf\r\n").unwrap();
2403            assert_eq!(value, Value::Double(f64::INFINITY));
2404
2405            let (value, _) = Value::parse(b",-inf\r\n").unwrap();
2406            assert_eq!(value, Value::Double(f64::NEG_INFINITY));
2407
2408            let (value, _) = Value::parse(b",nan\r\n").unwrap();
2409            if let Value::Double(d) = value {
2410                assert!(d.is_nan());
2411            } else {
2412                panic!("Expected Double");
2413            }
2414        }
2415
2416        #[test]
2417        fn test_parse_big_number() {
2418            let (value, consumed) = Value::parse(b"(12345678901234567890\r\n").unwrap();
2419            assert_eq!(
2420                value,
2421                Value::BigNumber(Bytes::from_static(b"12345678901234567890"))
2422            );
2423            assert_eq!(consumed, 23);
2424        }
2425
2426        #[test]
2427        fn test_parse_bulk_error() {
2428            let (value, consumed) = Value::parse(b"!21\r\nSYNTAX invalid syntax\r\n").unwrap();
2429            assert_eq!(
2430                value,
2431                Value::BulkError(Bytes::from_static(b"SYNTAX invalid syntax"))
2432            );
2433            assert_eq!(consumed, 28);
2434        }
2435
2436        #[test]
2437        fn test_parse_verbatim_string() {
2438            let (value, consumed) = Value::parse(b"=15\r\ntxt:Hello World\r\n").unwrap();
2439            assert_eq!(
2440                value,
2441                Value::VerbatimString {
2442                    format: *b"txt",
2443                    data: Bytes::from_static(b"Hello World"),
2444                }
2445            );
2446            assert_eq!(consumed, 22);
2447        }
2448
2449        #[test]
2450        fn test_parse_map() {
2451            // %2\r\n+first\r\n:1\r\n+second\r\n:2\r\n
2452            // = 4 + 8 + 4 + 9 + 4 = 29 bytes
2453            let (value, consumed) =
2454                Value::parse(b"%2\r\n+first\r\n:1\r\n+second\r\n:2\r\n").unwrap();
2455            assert_eq!(
2456                value,
2457                Value::Map(vec![
2458                    (
2459                        Value::SimpleString(Bytes::from_static(b"first")),
2460                        Value::Integer(1)
2461                    ),
2462                    (
2463                        Value::SimpleString(Bytes::from_static(b"second")),
2464                        Value::Integer(2)
2465                    ),
2466                ])
2467            );
2468            assert_eq!(consumed, 29);
2469        }
2470
2471        #[test]
2472        fn test_parse_set() {
2473            // ~3\r\n:1\r\n:2\r\n:3\r\n = 4 + 4 + 4 + 4 = 16 bytes
2474            let (value, consumed) = Value::parse(b"~3\r\n:1\r\n:2\r\n:3\r\n").unwrap();
2475            assert_eq!(
2476                value,
2477                Value::Set(vec![
2478                    Value::Integer(1),
2479                    Value::Integer(2),
2480                    Value::Integer(3),
2481                ])
2482            );
2483            assert_eq!(consumed, 16);
2484        }
2485
2486        #[test]
2487        fn test_parse_push() {
2488            let (value, consumed) = Value::parse(b">2\r\n+message\r\n+hello\r\n").unwrap();
2489            assert_eq!(
2490                value,
2491                Value::Push(vec![
2492                    Value::SimpleString(Bytes::from_static(b"message")),
2493                    Value::SimpleString(Bytes::from_static(b"hello")),
2494                ])
2495            );
2496            assert_eq!(consumed, 22);
2497        }
2498
2499        #[test]
2500        fn test_parse_attribute() {
2501            // |1\r\n+key\r\n+value\r\n+actual\r\n
2502            // = 4 + 6 + 8 + 9 = 27 bytes
2503            let (value, consumed) = Value::parse(b"|1\r\n+key\r\n+value\r\n+actual\r\n").unwrap();
2504            assert_eq!(
2505                value,
2506                Value::Attribute {
2507                    attrs: vec![(
2508                        Value::SimpleString(Bytes::from_static(b"key")),
2509                        Value::SimpleString(Bytes::from_static(b"value"))
2510                    )],
2511                    value: Box::new(Value::SimpleString(Bytes::from_static(b"actual"))),
2512                }
2513            );
2514            assert_eq!(consumed, 27);
2515        }
2516
2517        #[test]
2518        fn test_encode_boolean() {
2519            let mut buf = [0u8; 64];
2520            let len = Value::boolean(true).encode(&mut buf);
2521            assert_eq!(&buf[..len], b"#t\r\n");
2522
2523            let len = Value::boolean(false).encode(&mut buf);
2524            assert_eq!(&buf[..len], b"#f\r\n");
2525        }
2526
2527        #[test]
2528        fn test_encode_double() {
2529            let mut buf = [0u8; 64];
2530            let len = Value::double(1.5).encode(&mut buf);
2531            // ryu format may vary slightly, just check the structure
2532            assert_eq!(buf[0], b',');
2533            assert!(buf[len - 2] == b'\r' && buf[len - 1] == b'\n');
2534
2535            // Test special values
2536            let len = Value::double(f64::INFINITY).encode(&mut buf);
2537            assert_eq!(&buf[..len], b",inf\r\n");
2538
2539            let len = Value::double(f64::NEG_INFINITY).encode(&mut buf);
2540            assert_eq!(&buf[..len], b",-inf\r\n");
2541        }
2542
2543        #[test]
2544        fn test_encode_big_number() {
2545            let mut buf = [0u8; 64];
2546            let len = Value::big_number(b"12345678901234567890").encode(&mut buf);
2547            assert_eq!(&buf[..len], b"(12345678901234567890\r\n");
2548        }
2549
2550        #[test]
2551        fn test_encode_bulk_error() {
2552            let mut buf = [0u8; 64];
2553            let len = Value::bulk_error(b"SYNTAX error").encode(&mut buf);
2554            assert_eq!(&buf[..len], b"!12\r\nSYNTAX error\r\n");
2555        }
2556
2557        #[test]
2558        fn test_encode_verbatim_string() {
2559            let mut buf = [0u8; 64];
2560            let len = Value::verbatim_string(*b"txt", b"Hello").encode(&mut buf);
2561            assert_eq!(&buf[..len], b"=9\r\ntxt:Hello\r\n");
2562        }
2563
2564        #[test]
2565        fn test_encode_map() {
2566            let mut buf = [0u8; 64];
2567            let len =
2568                Value::map(vec![(Value::simple_string(b"a"), Value::integer(1))]).encode(&mut buf);
2569            assert_eq!(&buf[..len], b"%1\r\n+a\r\n:1\r\n");
2570        }
2571
2572        #[test]
2573        fn test_encode_set() {
2574            let mut buf = [0u8; 64];
2575            let len = Value::set(vec![Value::integer(1), Value::integer(2)]).encode(&mut buf);
2576            assert_eq!(&buf[..len], b"~2\r\n:1\r\n:2\r\n");
2577        }
2578
2579        #[test]
2580        fn test_encode_push() {
2581            let mut buf = [0u8; 64];
2582            let len = Value::push(vec![
2583                Value::simple_string(b"message"),
2584                Value::simple_string(b"hello"),
2585            ])
2586            .encode(&mut buf);
2587            assert_eq!(&buf[..len], b">2\r\n+message\r\n+hello\r\n");
2588        }
2589
2590        #[test]
2591        fn test_resp3_roundtrip() {
2592            let values = vec![
2593                Value::boolean(true),
2594                Value::boolean(false),
2595                Value::double(3.5), // Use exact floats to avoid ryu formatting issues
2596                Value::double(100.0),
2597                Value::double(f64::INFINITY),
2598                Value::double(f64::NEG_INFINITY),
2599                Value::big_number(b"99999999999999999999"),
2600                Value::bulk_error(b"ERR something went wrong"),
2601                Value::verbatim_string(*b"txt", b"Hello World"),
2602                Value::map(vec![
2603                    (Value::simple_string(b"key1"), Value::integer(1)),
2604                    (Value::simple_string(b"key2"), Value::integer(2)),
2605                ]),
2606                Value::set(vec![
2607                    Value::integer(1),
2608                    Value::integer(2),
2609                    Value::integer(3),
2610                ]),
2611                Value::push(vec![
2612                    Value::simple_string(b"subscribe"),
2613                    Value::simple_string(b"channel"),
2614                ]),
2615            ];
2616
2617            for original in values {
2618                let mut buf = [0u8; 512];
2619                let len = original.encode(&mut buf);
2620                let (parsed, consumed) = Value::parse(&buf[..len]).unwrap();
2621                // For Double, compare values directly since infinity is exact
2622                if let (Value::Double(d1), Value::Double(d2)) = (&original, &parsed) {
2623                    if d1.is_nan() {
2624                        assert!(d2.is_nan());
2625                    } else if d1.is_infinite() {
2626                        assert_eq!(d1, d2, "Infinities should be exactly equal");
2627                    } else {
2628                        // For finite doubles, use relative tolerance
2629                        let diff = (d1 - d2).abs();
2630                        let tolerance = d1.abs() * 1e-10;
2631                        assert!(diff <= tolerance, "Doubles differ: {} vs {}", d1, d2);
2632                    }
2633                } else {
2634                    assert_eq!(original, parsed);
2635                }
2636                assert_eq!(len, consumed);
2637            }
2638        }
2639
2640        #[test]
2641        fn test_resp3_encoded_len() {
2642            let values = vec![
2643                Value::boolean(true),
2644                Value::double(1.23456),
2645                Value::big_number(b"12345"),
2646                Value::bulk_error(b"ERR test"),
2647                Value::verbatim_string(*b"txt", b"hello"),
2648                Value::map(vec![(Value::simple_string(b"a"), Value::integer(1))]),
2649                Value::set(vec![Value::integer(1), Value::integer(2)]),
2650                Value::push(vec![Value::simple_string(b"msg")]),
2651            ];
2652
2653            for value in values {
2654                let mut buf = [0u8; 512];
2655                let actual_len = value.encode(&mut buf);
2656                assert_eq!(
2657                    value.encoded_len(),
2658                    actual_len,
2659                    "Length mismatch for {:?}",
2660                    value
2661                );
2662            }
2663        }
2664    }
2665
2666    // ========================================================================
2667    // Edge Case Tests
2668    // ========================================================================
2669
2670    #[test]
2671    fn test_parse_cr_without_lf() {
2672        // Simple string with \r but not followed by \n
2673        let result = Value::parse(b"+OK\rX");
2674        assert!(matches!(result, Err(ParseError::Incomplete)));
2675    }
2676
2677    #[test]
2678    fn test_parse_array_incomplete_elements() {
2679        // Array with 3 elements but only 2 provided
2680        let result = Value::parse(b"*3\r\n:1\r\n:2\r\n");
2681        assert!(matches!(result, Err(ParseError::Incomplete)));
2682    }
2683
2684    #[test]
2685    fn test_parse_array_truncated_after_length() {
2686        // Array length parsed but no elements follow
2687        let result = Value::parse(b"*2\r\n");
2688        assert!(matches!(result, Err(ParseError::Incomplete)));
2689    }
2690
2691    #[test]
2692    fn test_parse_bulk_string_truncated_content() {
2693        // Bulk string with length 10 but only 5 bytes of content
2694        let result = Value::parse(b"$10\r\nhello");
2695        assert!(matches!(result, Err(ParseError::Incomplete)));
2696    }
2697
2698    #[test]
2699    fn test_parse_nested_array_incomplete() {
2700        // Outer array expects 2 elements, inner array is complete, second element missing
2701        let result = Value::parse(b"*2\r\n*1\r\n:1\r\n");
2702        assert!(matches!(result, Err(ParseError::Incomplete)));
2703    }
2704
2705    #[test]
2706    fn test_parse_integer_no_crlf() {
2707        // Integer without terminating CRLF
2708        let result = Value::parse(b":12345");
2709        assert!(matches!(result, Err(ParseError::Incomplete)));
2710    }
2711
2712    #[test]
2713    fn test_parse_error_no_crlf() {
2714        // Error without terminating CRLF
2715        let result = Value::parse(b"-ERR something");
2716        assert!(matches!(result, Err(ParseError::Incomplete)));
2717    }
2718
2719    #[test]
2720    fn test_parse_simple_string_only_cr() {
2721        // Simple string with only \r at end (no \n)
2722        let result = Value::parse(b"+OK\r");
2723        assert!(matches!(result, Err(ParseError::Incomplete)));
2724    }
2725
2726    // ========================================================================
2727    // DoS Protection Tests
2728    // ========================================================================
2729
2730    #[test]
2731    fn test_parse_bulk_string_too_large() {
2732        // Bulk string claiming to be larger than DEFAULT_MAX_BULK_STRING_LEN (512MB)
2733        // Use a length that's clearly over the limit
2734        let data = b"$536870913\r\n"; // 512MB + 1
2735        let result = Value::parse(data);
2736        assert!(matches!(result, Err(ParseError::Protocol(_))));
2737    }
2738
2739    #[test]
2740    fn test_parse_bulk_string_huge_length() {
2741        // Very large bulk string length
2742        let data = b"$99999999999999\r\n";
2743        let result = Value::parse(data);
2744        // Should fail with Protocol error (too large) or InvalidInteger (can't parse)
2745        assert!(result.is_err());
2746    }
2747
2748    #[test]
2749    fn test_parse_array_at_limit() {
2750        // Array at collection limit should work
2751        // We can't actually test 1M elements, but ensure the limit check exists
2752        let data = b"*1000001\r\n"; // Just over 1M
2753        let result = Value::parse(data);
2754        assert!(matches!(result, Err(ParseError::CollectionTooLarge(_))));
2755    }
2756
2757    #[test]
2758    fn test_parse_integer_overflow_protection() {
2759        // Integer that would overflow i64
2760        let data = b":99999999999999999999\r\n";
2761        let result = Value::parse(data);
2762        assert!(matches!(result, Err(ParseError::InvalidInteger(_))));
2763    }
2764
2765    #[test]
2766    fn test_custom_parse_options() {
2767        // Test with very restrictive custom options
2768        let options = ParseOptions::new()
2769            .max_collection_elements(2)
2770            .max_bulk_string_len(10);
2771
2772        // Array at limit should work
2773        let data = b"*2\r\n:1\r\n:2\r\n";
2774        let result = Value::parse_with_options(data, &options);
2775        assert!(result.is_ok());
2776
2777        // Array over limit should fail
2778        let data = b"*3\r\n:1\r\n:2\r\n:3\r\n";
2779        let result = Value::parse_with_options(data, &options);
2780        assert!(matches!(result, Err(ParseError::CollectionTooLarge(3))));
2781
2782        // Bulk string at limit should work
2783        let data = b"$10\r\n0123456789\r\n";
2784        let result = Value::parse_with_options(data, &options);
2785        assert!(result.is_ok());
2786
2787        // Bulk string over limit should fail
2788        let data = b"$11\r\n01234567890\r\n";
2789        let result = Value::parse_with_options(data, &options);
2790        assert!(matches!(result, Err(ParseError::Protocol(_))));
2791    }
2792
2793    #[test]
2794    fn test_total_items_budget_flat_array() {
2795        // Total items budget prevents allocating too many items
2796        let options = ParseOptions::new()
2797            .max_collection_elements(100)
2798            .max_total_items(10);
2799
2800        // 5 items is within budget
2801        let data = b"*5\r\n:1\r\n:2\r\n:3\r\n:4\r\n:5\r\n";
2802        let result = Value::parse_with_options(data, &options);
2803        assert!(result.is_ok());
2804
2805        // 11 items exceeds total budget of 10
2806        let data = b"*11\r\n:1\r\n:2\r\n:3\r\n:4\r\n:5\r\n:6\r\n:7\r\n:8\r\n:9\r\n:10\r\n:11\r\n";
2807        let result = Value::parse_with_options(data, &options);
2808        assert!(matches!(result, Err(ParseError::CollectionTooLarge(_))));
2809    }
2810
2811    #[test]
2812    fn test_total_items_budget_nested_arrays() {
2813        // Test that nested arrays accumulate against the total budget
2814        // This is the critical test for preventing exponential allocation attacks
2815        let options = ParseOptions::new()
2816            .max_collection_elements(100)
2817            .max_total_items(10)
2818            .max_depth(8);
2819
2820        // Nested arrays: outer has 2 elements, each inner has 3 elements
2821        // Total items: 2 (outer) + 3 (first inner) + 3 (second inner) = 8
2822        let data = b"*2\r\n*3\r\n:1\r\n:2\r\n:3\r\n*3\r\n:4\r\n:5\r\n:6\r\n";
2823        let result = Value::parse_with_options(data, &options);
2824        assert!(result.is_ok());
2825
2826        // Nested arrays that exceed total budget:
2827        // outer has 3 elements, each inner has 3 elements
2828        // Total items: 3 (outer) + 3 + 3 + 3 = 12 > 10
2829        let data =
2830            b"*3\r\n*3\r\n:1\r\n:2\r\n:3\r\n*3\r\n:4\r\n:5\r\n:6\r\n*3\r\n:7\r\n:8\r\n:9\r\n";
2831        let result = Value::parse_with_options(data, &options);
2832        assert!(matches!(result, Err(ParseError::CollectionTooLarge(_))));
2833    }
2834
2835    #[test]
2836    fn test_nesting_depth_limit() {
2837        // Test that nesting depth is enforced
2838        let options = ParseOptions::new()
2839            .max_collection_elements(100)
2840            .max_total_items(1000)
2841            .max_depth(2);
2842
2843        // Depth 1: single array (depth 0 at start, array at depth 1)
2844        let data = b"*1\r\n:1\r\n";
2845        let result = Value::parse_with_options(data, &options);
2846        assert!(result.is_ok());
2847
2848        // Depth 2: nested array (outer at depth 1, inner at depth 2)
2849        let data = b"*1\r\n*1\r\n:1\r\n";
2850        let result = Value::parse_with_options(data, &options);
2851        assert!(result.is_ok());
2852
2853        // Depth 3: exceeds max_depth of 2
2854        let data = b"*1\r\n*1\r\n*1\r\n:1\r\n";
2855        let result = Value::parse_with_options(data, &options);
2856        assert!(matches!(result, Err(ParseError::NestingTooDeep(_))));
2857    }
2858
2859    #[test]
2860    fn test_exponential_attack_prevented() {
2861        // This test verifies that the total items budget prevents exponential
2862        // allocation attacks. Without the budget, this would try to allocate:
2863        // 100 * 100 * 100 = 1,000,000 items. With the budget, it fails early.
2864        let options = ParseOptions::new()
2865            .max_collection_elements(100)
2866            .max_total_items(1000)
2867            .max_depth(8);
2868
2869        // Create a deeply nested structure where each level has 100 elements
2870        // Level 0: array of 100 elements
2871        // Level 1: first element is array of 100 elements
2872        // This alone is 100 + 100 = 200 items
2873        // If the first element's first element is also an array of 100...
2874        // We'd have 100 + 100 + 100 = 300 items
2875        // The budget prevents this from growing to 100^depth
2876
2877        // Build: *100\r\n*100\r\n*100\r\n... (3 levels)
2878        let mut data = Vec::new();
2879        // Outer array: 100 elements (first is another array, rest are integers)
2880        data.extend_from_slice(b"*100\r\n");
2881        // Second level: 100 elements
2882        data.extend_from_slice(b"*100\r\n");
2883        // Third level: 100 elements
2884        data.extend_from_slice(b"*100\r\n");
2885        // Fill third level with integers
2886        for i in 0..100 {
2887            let s = format!(":{}\r\n", i);
2888            data.extend_from_slice(s.as_bytes());
2889        }
2890        // Fill rest of second level with integers (99 more)
2891        for i in 0..99 {
2892            let s = format!(":{}\r\n", i);
2893            data.extend_from_slice(s.as_bytes());
2894        }
2895        // Fill rest of first level with integers (99 more)
2896        for i in 0..99 {
2897            let s = format!(":{}\r\n", i);
2898            data.extend_from_slice(s.as_bytes());
2899        }
2900
2901        let result = Value::parse_with_options(&data, &options);
2902        // Should fail because total items = 100 + 100 + 100 = 300 > 1000? No wait...
2903        // 100 + 100 + 100 = 300, which is less than 1000
2904        // But we set budget to 1000, so this should pass
2905        // Let me recalculate: we want to show it would fail with a smaller budget
2906        // Actually this test is fine - it shows that even with depth 8,
2907        // the total items budget (300) is tracked correctly
2908        assert!(result.is_ok());
2909
2910        // Now test with a tighter budget that would fail
2911        let strict_options = ParseOptions::new()
2912            .max_collection_elements(100)
2913            .max_total_items(250) // Less than 300
2914            .max_depth(8);
2915
2916        let result = Value::parse_with_options(&data, &strict_options);
2917        assert!(matches!(result, Err(ParseError::CollectionTooLarge(_))));
2918    }
2919}