Skip to main content

ruvio_client/
value.rs

1/// One RESP2 value.
2#[derive(Debug, Clone, PartialEq, Eq)]
3pub enum RespValue {
4    /// A simple string, such as `OK`.
5    Simple(String),
6    /// An error reply. [`crate::Client::execute`] returns this as [`crate::Error::Server`].
7    Error(String),
8    /// A signed integer.
9    Integer(i64),
10    /// A bulk string, including the empty bulk.
11    Bulk(Vec<u8>),
12    /// An array of values.
13    Array(Vec<RespValue>),
14    /// A null bulk or a null array.
15    Null,
16}
17
18impl RespValue {
19    /// UTF-8 text of a simple string, error, or bulk string. An integer is its
20    /// decimal form. `None` when the value is null or an array (including a
21    /// Pub/Sub push).
22    pub fn as_string(&self) -> Result<Option<String>, crate::Error> {
23        match self {
24            RespValue::Null | RespValue::Array(_) => Ok(None),
25            RespValue::Integer(value) => Ok(Some(value.to_string())),
26            RespValue::Simple(text) | RespValue::Error(text) => Ok(Some(text.clone())),
27            RespValue::Bulk(bytes) => {
28                let text = String::from_utf8(bytes.clone())
29                    .map_err(|_| crate::Error::Protocol("bulk string is not UTF-8".to_owned()))?;
30
31                Ok(Some(text))
32            }
33        }
34    }
35
36    /// The integer, or `None` for any other kind.
37    pub fn as_integer(&self) -> Option<i64> {
38        match self {
39            RespValue::Integer(value) => Some(*value),
40            _ => None,
41        }
42    }
43
44    /// The array items, or `None` for any other kind.
45    pub fn as_array(&self) -> Option<&[RespValue]> {
46        match self {
47            RespValue::Array(items) => Some(items),
48            _ => None,
49        }
50    }
51
52    /// True for a null bulk or a null array.
53    pub fn is_null(&self) -> bool {
54        matches!(self, RespValue::Null)
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::RespValue;
61
62    #[test]
63    fn as_string_does_not_fail_on_an_array_or_integer() {
64        let message = RespValue::Array(vec![
65            RespValue::Bulk(b"message".to_vec()),
66            RespValue::Bulk(b"news".to_vec()),
67            RespValue::Bulk(b"hello".to_vec()),
68        ]);
69
70        assert_eq!(message.as_string().unwrap(), None);
71        assert_eq!(
72            message.as_array().unwrap()[2]
73                .as_string()
74                .unwrap()
75                .as_deref(),
76            Some("hello")
77        );
78        assert_eq!(
79            RespValue::Integer(3).as_string().unwrap().as_deref(),
80            Some("3")
81        );
82    }
83}