lib_resp/
value.rs

1use std::str;
2use std::convert::From;
3use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
4
5/// In-memory representation of a RESP value.
6#[derive(Clone, Eq, PartialEq)]
7pub enum Value {
8    /// An integer.
9    Int(i64),
10    /// A simple string.
11    Str(String),
12    /// An error.
13    Err(String),
14    /// A bulk string.
15    BStr(Option<String>),
16    /// An array.
17    Array(Option<Vec<Value>>),
18}
19
20impl Value {
21    // BStr constants
22    const ENCODED_NULL_BSTR: &'static str = "$-1\r\n";
23    const ENCODED_EMPTY_BSTR: &'static str = "$0\r\n\r\n";
24
25    // Array constants
26    const ENCODED_NULL_ARRAY: &'static str = "*-1\r\n";
27    const ENCODED_EMPTY_ARRAY: &'static str = "*0\r\n";
28
29    /// Encodes a `Value` as a string.
30    ///
31    /// # Examples
32    ///
33    /// ```
34    /// # use lib_resp::Value;
35    /// let error = Value::err("ERR");
36    ///
37    /// assert_eq!(error.encode(), "-ERR\r\n");
38    /// ```
39    pub fn encode(&self) -> String {
40        match self {
41            &Value::Int(ref datum) => {
42                let datum_str = &datum.to_string();
43
44                let mut encoded = String::with_capacity(datum_str.len() + 3);
45
46                encoded.push(':');
47
48                encoded.push_str(datum_str);
49
50                encoded.push_str("\r\n");
51
52                encoded
53            }
54
55            &Value::Str(ref datum) => {
56                let mut encoded = String::with_capacity(datum.len() + 3);
57
58                encoded.push('+');
59
60                encoded.push_str(datum);
61
62                encoded.push_str("\r\n");
63
64                encoded
65            }
66
67            &Value::Err(ref datum) => {
68                let mut encoded = String::with_capacity(datum.len() + 3);
69
70                encoded.push('-');
71
72                encoded.push_str(datum);
73
74                encoded.push_str("\r\n");
75
76                encoded
77            }
78
79            &Value::BStr(ref inner) => match inner {
80                &None => Value::ENCODED_NULL_BSTR.to_owned(),
81
82                &Some(ref datum) => match datum.len() {
83                    0 => Value::ENCODED_EMPTY_BSTR.to_owned(),
84
85                    len => {
86                        let len_str = &len.to_string();
87
88                        let mut encoded = String::with_capacity(len + len_str.len() + 5);
89
90                        encoded.push('$');
91
92                        encoded.push_str(len_str);
93
94                        encoded.push_str("\r\n");
95
96                        encoded.push_str(datum);
97
98                        encoded.push_str("\r\n");
99
100                        encoded
101                    }
102                },
103            },
104
105            &Value::Array(ref inner) => match inner {
106                &None => Value::ENCODED_NULL_ARRAY.to_owned(),
107
108                &Some(ref data) => match data.len() {
109                    0 => Value::ENCODED_EMPTY_ARRAY.to_owned(),
110
111                    len => {
112                        let len_str = len.to_string();
113
114                        let mut encoded_len = len_str.len() + 3;
115
116                        let encoded_values: Vec<String> = {
117                            data.iter()
118                                .map(|value| {
119                                    let encoded = value.encode();
120
121                                    encoded_len += encoded.len();
122
123                                    encoded
124                                })
125                                .collect()
126                        };
127
128                        let mut encoded = String::with_capacity(encoded_len);
129
130                        encoded.push('*');
131
132                        encoded.push_str(&len_str);
133
134                        encoded.push_str("\r\n");
135
136                        encoded.push_str(&encoded_values.concat());
137
138                        encoded
139                    }
140                },
141            },
142        }
143    }
144
145    /// Encodes a `Value` as a vector of bytes.
146    ///
147    /// # Examples
148    ///
149    /// ```
150    /// # use lib_resp::Value;
151    /// let error = Value::err("ERR");
152    ///
153    /// assert_eq!(&error.encode_bytes(), b"-ERR\r\n");
154    /// ```
155    #[inline(always)]
156    pub fn encode_bytes(&self) -> Vec<u8> {
157        self.encode().into_bytes()
158    }
159
160    /// Checks if a `Value` is null.
161    ///
162    /// NOTE: Only the `Array` and `BStr` types can represent a null value.
163    ///
164    /// # Examples
165    ///
166    /// ```
167    /// # use lib_resp::Value;
168    /// let name = Value::BStr(None);
169    ///
170    /// assert!(name.is_null());
171    /// ```
172    ///
173    /// ```
174    /// # use lib_resp::Value;
175    /// let name = Value::b_str(Some("Josh"));
176    ///
177    /// assert!(!name.is_null());
178    /// ```
179    #[inline]
180    pub fn is_null(&self) -> bool {
181        match self {
182            &Value::Array(None) | &Value::BStr(None) => true,
183
184            // No other types can represent null values
185            _ => false,
186        }
187    }
188
189    /// Checks is a `Value` is empty.
190    ///
191    /// # Examples
192    ///
193    /// ```
194    /// # use lib_resp::Value;
195    /// let error = Value::err("");
196    ///
197    /// assert!(error.is_empty());
198    /// ```
199    ///
200    /// ```
201    /// # use lib_resp::Value;
202    /// let error = Value::err("ERR");
203    ///
204    /// assert!(!error.is_empty())
205    /// ```
206    ///
207    /// Null values count as empty too:
208    ///
209    /// ```
210    /// # use lib_resp::Value;
211    /// let name = Value::BStr(None);
212    ///
213    /// assert!(name.is_empty());
214    /// ```
215    #[inline]
216    pub fn is_empty(&self) -> bool {
217        match self {
218            &Value::Int(_) => false,
219
220            &Value::Str(ref value) | &Value::Err(ref value) => value.is_empty(),
221
222            &Value::BStr(ref inner) => match inner {
223                &None => true,
224
225                &Some(ref value) => value.is_empty(),
226            },
227
228            &Value::Array(ref inner) => match inner {
229                &None => true,
230
231                &Some(ref items) => items.is_empty(),
232            },
233        }
234    }
235
236    /// Constructs a new integer value.
237    ///
238    /// NOTE: Using this function has no benefits, it's simply here for completeness.
239    ///
240    /// # Examples
241    ///
242    /// ```
243    /// # use lib_resp::Value;
244    /// let age = Value::int(-3);
245    ///
246    /// println!("{:?}", age);
247    /// ```
248    #[inline(always)]
249    pub fn int(value: i64) -> Self {
250        Value::Int(value)
251    }
252
253    /// Constructs a new simple string.
254    ///
255    /// # Examples
256    ///
257    /// ```
258    /// # use lib_resp::Value;
259    /// let status = Value::str("OK");
260    ///
261    /// println!("{:?}", status);
262    /// ```
263    #[inline(always)]
264    pub fn str<T>(value: T) -> Self
265    where
266        T: ToString,
267    {
268        Value::Str(value.to_string())
269    }
270
271    /// Constructs a new error.
272    ///
273    /// # Examples
274    ///
275    /// ```
276    /// # use lib_resp::Value;
277    /// let err = Value::err("ERR");
278    ///
279    /// println!("{:?}", err);
280    /// ```
281    #[inline(always)]
282    pub fn err<T>(error: T) -> Self
283    where
284        T: ToString,
285    {
286        Value::Err(error.to_string())
287    }
288
289    /// Constructs a new bulk string.
290    ///
291    /// # Examples
292    ///
293    /// ```
294    /// # use lib_resp::Value;
295    /// let b_str = Value::b_str(Some("foobar"));
296    ///
297    /// println!("{:?}", b_str);
298    /// ```
299    #[inline(always)]
300    pub fn b_str<T>(value: Option<T>) -> Self
301    where
302        T: ToString,
303    {
304        Value::BStr(value.map(|v| v.to_string()))
305    }
306
307    /// Constructs a new array value.
308    ///
309    /// NOTE: Using this function has no benefits, it's simply here for completeness.
310    ///
311    /// # Examples
312    ///
313    /// ```
314    /// # use lib_resp::Value;
315    /// let users = Value::array(Some(vec![
316    ///     Value::b_str(Some("foo")),
317    ///     Value::b_str(Some("bar")),
318    ///     Value::b_str(Some("baz"))
319    /// ]));
320    ///
321    /// println!("{:?}", users);
322    /// ```
323    #[inline(always)]
324    pub fn array(values: Option<Vec<Value>>) -> Self {
325        Value::Array(values)
326    }
327}
328
329impl Debug for Value {
330    fn fmt(&self, f: &mut Formatter) -> FmtResult {
331        match self {
332            &Value::Int(ref datum) => write!(f, "Int({})", datum),
333
334            &Value::Str(ref datum) => write!(f, r#"Str("{}")"#, datum),
335
336            &Value::Err(ref datum) => write!(f, r#"Err("{}")"#, datum),
337
338            &Value::BStr(ref value) => match value {
339                &None => write!(f, "BStr(None)"),
340
341                &Some(ref datum) => match datum.len() {
342                    0 => write!(f, "BStr(0)"),
343
344                    len => write!(f, r#"BStr({}, "{}")"#, len, datum),
345                },
346            },
347
348            &Value::Array(ref value) => {
349                write!(f, "Array[")?;
350
351                match value {
352                    &Some(ref data) => {
353                        write!(f, "{}](", data.len())?;
354
355                        for (i, datum) in data.iter().enumerate() {
356                            write!(f, "{:?}", datum)?;
357
358                            if data.len() - 1 > i {
359                                write!(f, ", ")?;
360                            }
361                        }
362
363                        write!(f, ")")
364                    }
365
366                    &None => write!(f, "-1]"),
367                }
368            }
369        }
370    }
371}
372
373impl Display for Value {
374    fn fmt(&self, f: &mut Formatter) -> FmtResult {
375        match self {
376            &Value::Int(ref datum) => write!(f, "(integer) {}", datum),
377
378            &Value::Str(ref datum) => write!(f, "{}", datum),
379
380            &Value::Err(ref datum) => write!(f, "(error) {}", datum),
381
382            &Value::BStr(ref value) => match value {
383                &Some(ref datum) => write!(f, r#""{}""#, datum),
384
385                &None => write!(f, r#""""#),
386            },
387
388            &Value::Array(ref value) => match value {
389                &Some(ref data) => {
390                    for (i, datum) in data.iter().enumerate() {
391                        let n = i + 1;
392
393                        write!(f, "{}) {}", n, datum)?;
394
395                        if n < data.len() {
396                            write!(f, "\r\n")?;
397                        }
398                    }
399
400                    Ok(())
401                }
402
403                &None => write!(f, "(empty list or set)"),
404            },
405        }
406    }
407}
408
409impl From<i64> for Value {
410    fn from(value: i64) -> Self {
411        Value::int(value)
412    }
413}