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}