Skip to main content

beyond_resp/
value.rs

1use bytes::Bytes;
2
3/// Protocol version — controls null wire encoding and enables RESP3 types.
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
5pub enum Version {
6    #[default]
7    Resp2,
8    Resp3,
9}
10
11/// A parsed RESP value covering all RESP2 and RESP3 wire types.
12///
13/// `PartialEq` is derived; `f64::NAN != f64::NAN` per IEEE 754 is correct behaviour.
14#[derive(Debug, Clone, PartialEq)]
15pub enum Value {
16    // ── RESP2 ──────────────────────────────────────────────────────────────
17
18    /// `+<str>\r\n` — short non-binary status string, e.g. `"OK"`
19    SimpleString(Bytes),
20    /// `-<msg>\r\n` — error (raw bytes, includes the kind prefix e.g. `"ERR bad"`)
21    SimpleError(Bytes),
22    /// `:<n>\r\n` — 64-bit signed integer
23    Integer(i64),
24    /// `$<len>\r\n<data>\r\n` — binary-safe bulk string
25    BulkString(Bytes),
26    /// `*<count>\r\n<elements>` — ordered array
27    Array(Vec<Value>),
28
29    // ── Unified null (RESP2: $-1\r\n / *-1\r\n ; RESP3: _\r\n) ────────────
30    Null,
31
32    // ── RESP3 ──────────────────────────────────────────────────────────────
33
34    /// `#t\r\n` / `#f\r\n`
35    Boolean(bool),
36    /// `,<value>\r\n` — IEEE 754 double; encodes `inf`, `-inf`, `nan`
37    Double(f64),
38    /// `(<decimal>\r\n` — arbitrary-precision integer as raw decimal bytes (no bignum dep)
39    BigNumber(Bytes),
40    /// `!<len>\r\n<data>\r\n` — binary-safe error payload
41    BulkError(Bytes),
42    /// `=<len>\r\n<enc>:<data>\r\n` — string with 3-byte encoding hint
43    VerbatimString { encoding: [u8; 3], data: Bytes },
44    /// `%<count>\r\n<key><value>...` — key-value map
45    Map(Vec<(Value, Value)>),
46    /// `|<count>\r\n<key><value>...<reply>` — attribute metadata + actual reply
47    Attribute { attrs: Vec<(Value, Value)>, value: Box<Value> },
48    /// `~<count>\r\n<elements>` — unordered unique set
49    Set(Vec<Value>),
50    /// `><count>\r\n<elements>` — out-of-band push message
51    Push(Vec<Value>),
52}
53
54impl Value {
55    /// Returns `true` if this value is an error type.
56    pub fn is_error(&self) -> bool {
57        matches!(self, Self::SimpleError(_) | Self::BulkError(_))
58    }
59
60    /// Returns `true` if this value is null.
61    pub fn is_null(&self) -> bool {
62        matches!(self, Self::Null)
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    #[test]
71    fn is_error_covers_all_variants() {
72        assert!(Value::SimpleError(Bytes::from("ERR msg")).is_error());
73        assert!(Value::BulkError(Bytes::from("SYNTAX detail")).is_error());
74        assert!(!Value::SimpleString(Bytes::from("OK")).is_error());
75        assert!(!Value::Integer(0).is_error());
76        assert!(!Value::Null.is_error());
77        assert!(!Value::Boolean(false).is_error());
78    }
79
80    #[test]
81    fn is_null_only_for_null_variant() {
82        assert!(Value::Null.is_null());
83        assert!(!Value::Integer(0).is_null());
84        assert!(!Value::SimpleString(Bytes::from("")).is_null());
85        assert!(!Value::Boolean(false).is_null());
86        assert!(!Value::BulkString(Bytes::new()).is_null());
87    }
88}