1use super::{RedisResult, RedisError, RedisErrorKind};
2use std::error::Error;
3use std::fmt;
4use std::cmp::PartialEq;
5use std::str::FromStr;
6use std::collections::HashMap;
7use std::hash::Hash;
8use core::num::ParseIntError;
9use crate::base::RespInternalValue;
10
11
12#[derive(PartialEq, Eq, Clone, Debug)]
15pub enum RedisValue {
16 Nil,
17 Ok,
18 Status(String),
19 Int(i64),
20 BulkString(Vec<u8>),
21 Array(Vec<RedisValue>),
22}
23
24impl RedisValue {
25 pub(crate) fn from_resp_value(resp_value: RespInternalValue) -> RedisResult<RedisValue> {
26 match resp_value {
27 RespInternalValue::Nil => Ok(RedisValue::Nil),
28 RespInternalValue::Error(x) => Err(RedisError::new(RedisErrorKind::ReceiveError, x)),
29 RespInternalValue::Status(x) => match x.as_str() {
30 "OK" => Ok(RedisValue::Ok),
31 _ => Ok(RedisValue::Status(x))
32 },
33 RespInternalValue::Int(x) => Ok(RedisValue::Int(x)),
34 RespInternalValue::BulkString(x) => Ok(RedisValue::BulkString(x)),
35 RespInternalValue::Array(x) => {
36 let mut res: Vec<RedisValue> = Vec::with_capacity(x.len());
37 for val in x.into_iter() {
38 res.push(Self::from_resp_value(val)?);
39 }
40 Ok(RedisValue::Array(res))
41 }
42 }
43 }
44}
45
46pub trait FromRedisValue: Sized {
81 fn from_redis_value(value: &RedisValue) -> RedisResult<Self>;
82
83 fn from_redis_u8(_: u8) -> Option<Self> {
84 None
85 }
86}
87
88pub fn from_redis_value<T: FromRedisValue>(value: &RedisValue) -> RedisResult<T> {
100 T::from_redis_value(value)
101 .map_err(|err|
102 RedisError::new(
103 err.error.clone(),
104 format!("Couldn't convert the Redis value: \"{:?}\". Reason: \"{}\"", value, err.description()
105 ),
106 )
107 )
108}
109
110impl FromRedisValue for RedisValue {
111 fn from_redis_value(value: &RedisValue) -> RedisResult<Self> {
112 Ok(value.clone())
113 }
114}
115
116impl FromRedisValue for u8 {
117 fn from_redis_value(value: &RedisValue) -> RedisResult<Self> {
118 int_from_redis_value::<u8>(value)
119 }
120
121 fn from_redis_u8(num: u8) -> Option<Self> {
122 Some(num)
123 }
124}
125
126impl FromRedisValue for String {
127 fn from_redis_value(value: &RedisValue) -> RedisResult<Self> {
128 match value {
129 RedisValue::Status(x) => Ok(x.clone()),
130 RedisValue::BulkString(x) => {
131 String::from_utf8(x.clone()).map_err(|err| to_conversion_error(err))
132 }
133 _ => Err(conversion_error_from_value(value, "String"))
134 }
135 }
136}
137
138impl<T: FromRedisValue> FromRedisValue for Vec<T> {
139 fn from_redis_value(value: &RedisValue) -> RedisResult<Self> {
140 match value {
141 RedisValue::BulkString(bulk_data) => {
142 let mut result: Vec<T> = Vec::with_capacity(bulk_data.len());
143 for num in bulk_data.iter() {
144 match T::from_redis_u8(*num) {
145 Some(x) => result.push(x),
146 _ => return Err(conversion_error_from_value(bulk_data, "Vec"))
147 }
148 }
149 Ok(result)
150 }
151 RedisValue::Array(x) => {
152 let mut result: Vec<T> = Vec::with_capacity(x.len());
153 for val in x.iter() {
154 match from_redis_value(val) {
155 Ok(x) => result.push(x),
156 Err(err) => return Err(err),
157 }
158 }
159 Ok(result)
160 }
161 _ => Err(conversion_error_from_value(value, "Array"))
162 }
163 }
164}
165
166impl<K: FromRedisValue + Eq + Hash, V: FromRedisValue> FromRedisValue for HashMap<K, V> {
167 fn from_redis_value(value: &RedisValue) -> RedisResult<Self> {
168 match value {
169 RedisValue::Array(key_values) => {
170 const KEY_VALUE_CHUNK_LEN: usize = 2;
171 const KEY_POS: usize = 0;
172 const VALUE_POS: usize = 1;
173
174 if key_values.len() % KEY_VALUE_CHUNK_LEN != 0 {
176 return Err(conversion_error_from_value(value, "HashMap"));
177 }
178
179 let mut result =
180 HashMap::with_capacity(key_values.len() / KEY_VALUE_CHUNK_LEN);
181
182 for chunk in key_values.chunks_exact(KEY_VALUE_CHUNK_LEN) {
183 let key: K = from_redis_value(&chunk[KEY_POS])?;
184 let value: V = from_redis_value(&chunk[VALUE_POS])?;
185 result.insert(key, value);
186 }
187
188 Ok(result)
189 }
190 _ => Err(conversion_error_from_value(value, "HashMap"))
191 }
192 }
193}
194
195impl<T1, T2> FromRedisValue for (T1, T2)
197 where T1: FromRedisValue + fmt::Debug,
198 T2: FromRedisValue + fmt::Debug {
199 fn from_redis_value(value: &RedisValue) -> RedisResult<Self> {
200 let values: Vec<RedisValue> = from_redis_value(value)?;
201 if values.len() != 2 {
202 return Err(
203 RedisError::new(
204 RedisErrorKind::ParseError,
205 format!("Couldn't convert the Redis value: \"{:?}\" to tuple of 2 elements",
206 values)));
207 }
208
209 let first: T1 = from_redis_value(&values[0])?;
210 let second: T2 = from_redis_value(&values[1])?;
211
212 Ok((first, second))
213 }
214}
215
216fn to_conversion_error<T>(err: T) -> RedisError
217 where T: Error {
218 RedisError::new(RedisErrorKind::IncorrectConversion, err.description().to_string())
219}
220
221fn conversion_error_from_value<T>(src_value: &T, dst_type: &str) -> RedisError
222 where T: fmt::Debug {
223 RedisError::new(RedisErrorKind::IncorrectConversion,
224 format!("{:?} is not convertible to {}", src_value, dst_type))
225}
226
227fn int_from_redis_value<T>(value: &RedisValue) -> RedisResult<T>
228 where T: ToIntConvertible {
229 match value {
230 RedisValue::Int(x) => Ok(T::convert_from_int(*x)),
231 RedisValue::BulkString(x) => {
232 match String::from_utf8(x.clone()) {
233 Ok(xstr) =>
234 T::convert_from_str(xstr)
235 .map_err(|_| conversion_error_from_value(&x, "i64")),
236 Err(_) => Err(conversion_error_from_value(x, "i64"))
237 }
238 }
239 _ => Err(conversion_error_from_value(value, "i64"))
240 }
241}
242
243trait ToIntConvertible: Sized + FromStr {
244 fn convert_from_str(val: String) -> Result<Self, ParseIntError>;
245 fn convert_from_int(val: i64) -> Self;
246}
247
248impl ToIntConvertible for u8 {
249 fn convert_from_str(val: String) -> Result<u8, ParseIntError> { val.parse::<u8>() }
250 fn convert_from_int(val: i64) -> u8 { val as u8 }
251}
252
253macro_rules! declare_to_int_convertible {
254 ($itype:ty) => {
255 impl ToIntConvertible for $itype {
256 fn convert_from_str(val: String) -> Result<$itype, ParseIntError> { val.parse::<$itype>() }
257 fn convert_from_int(val: i64) -> $itype { val as $itype }
258 }
259
260 impl FromRedisValue for $itype {
261 fn from_redis_value(value: &RedisValue) -> RedisResult<Self> {
262 int_from_redis_value::<$itype>(value)
263 }
264 }
265 };
266}
267
268declare_to_int_convertible!(i8);
269declare_to_int_convertible!(i16);
270declare_to_int_convertible!(u16);
271declare_to_int_convertible!(i32);
272declare_to_int_convertible!(u32);
273declare_to_int_convertible!(i64);
274declare_to_int_convertible!(u64);
275declare_to_int_convertible!(isize);
276declare_to_int_convertible!(usize);
277
278#[cfg(test)]
279mod tests {
280 use super::*;
281
282 #[test]
283 fn common_test_from_redis_value() {
284 #[derive(PartialEq, Debug)]
285 struct ArrayNode { data: String }
286
287 impl FromRedisValue for ArrayNode {
288 fn from_redis_value(value: &RedisValue) -> RedisResult<Self> {
289 Ok(ArrayNode { data: from_redis_value(value)? })
290 }
291 }
292
293 let value = RedisValue::Array(
294 vec![RedisValue::BulkString(String::from("data1").into_bytes()),
295 RedisValue::BulkString(String::from("data2").into_bytes())]);
296
297 let origin = vec![ArrayNode { data: String::from("data1") },
298 ArrayNode { data: String::from("data2") }];
299 assert_eq!(origin, from_redis_value::<Vec<ArrayNode>>(&value).unwrap());
300 }
301
302 #[test]
303 fn test_from_nil_value() {
304 let val = RedisValue::Nil;
305 assert!(from_redis_value::<i64>(&val).is_err(), "expected Err");
306 assert!(from_redis_value::<String>(&val).is_err(), "expected Err");
307 assert!(from_redis_value::<Vec<i64>>(&val).is_err(), "expected Err");
308 }
309
310 #[test]
311 fn test_from_ok_value() {
312 let val = RedisValue::Ok;
313 assert!(from_redis_value::<i64>(&val).is_err(), "expected Err");
314 assert!(from_redis_value::<String>(&val).is_err(), "expected Err");
315 assert!(from_redis_value::<Vec<i64>>(&val).is_err(), "expected Err");
316 }
317
318 #[test]
319 fn test_from_status_value() {
320 let val = RedisValue::Status(String::from("Status"));
321 assert_eq!(String::from("Status"), from_redis_value::<String>(&val).unwrap());
322 assert!(from_redis_value::<i64>(&val).is_err(), "expected Err");
323 assert!(from_redis_value::<Vec<i64>>(&val).is_err(), "expected Err");
324 }
325
326 #[test]
327 fn test_from_int_value() {
328 let src: i64 = std::i64::MAX - 5;
329 let val = RedisValue::Int(src);
330 assert_eq!(src as i8, from_redis_value::<i8>(&val).unwrap());
331 assert_eq!(src as u8, from_redis_value::<u8>(&val).unwrap());
332 assert_eq!(src as i16, from_redis_value::<i16>(&val).unwrap());
333 assert_eq!(src as u16, from_redis_value::<u16>(&val).unwrap());
334 assert_eq!(src as i32, from_redis_value::<i32>(&val).unwrap());
335 assert_eq!(src as u32, from_redis_value::<u32>(&val).unwrap());
336 assert_eq!(src as i64, from_redis_value::<i64>(&val).unwrap());
337 assert_eq!(src as u64, from_redis_value::<u64>(&val).unwrap());
338 assert!(from_redis_value::<String>(&val).is_err(), "expected Err");
339 assert!(from_redis_value::<Vec<i64>>(&val).is_err(), "expected Err");
340 }
341
342 #[test]
343 fn test_from_bulkstring_value() {
344 let raw_data = vec![1, 2, 250, 251, 255];
345 let string_data = String::from("BulkString");
346 let val1 = RedisValue::BulkString(raw_data.clone());
347 let val2 = RedisValue::BulkString(string_data.clone().into_bytes());
348
349 assert!(from_redis_value::<String>(&val1).is_err(),
350 "expected Err on cannot convert raw data to String");
351 assert_eq!(raw_data, from_redis_value::<Vec<u8>>(&val1).unwrap());
352 assert!(from_redis_value::<Vec<i8>>(&val1).is_err(), "expected Err");
353 assert!(from_redis_value::<Vec<i64>>(&val1).is_err(), "expected Err");
354 assert!(from_redis_value::<i64>(&val1).is_err(), "expected Err");
355
356 assert_eq!(string_data, from_redis_value::<String>(&val2).unwrap());
357 assert_eq!(string_data.into_bytes(), from_redis_value::<Vec<u8>>(&val2).unwrap());
358 }
359
360 #[test]
361 fn test_from_array_value() {
362 let data
363 = vec![RedisValue::Nil,
364 RedisValue::Ok,
365 RedisValue::Status(String::from("Status")),
366 RedisValue::Int(12345),
367 RedisValue::BulkString(vec![1, 2, 3, 4, 5]),
368 RedisValue::Array(
369 vec![RedisValue::Int(9876),
370 RedisValue::BulkString(String::from("BulkString").into_bytes())])];
371
372 let val1 = RedisValue::Array(data.clone());
373 assert_eq!(data, from_redis_value::<Vec<RedisValue>>(&val1).unwrap());
374 }
375}