1use crate::{
2 context::call_reply::{CallResult, VerbatimStringFormat},
3 CallReply, RedisError, RedisString,
4};
5use std::{
6 collections::{BTreeMap, BTreeSet, HashMap, HashSet},
7 hash::Hash,
8};
9
10#[derive(Debug, PartialEq, Eq, Hash, Clone, PartialOrd, Ord)]
11pub enum RedisValueKey {
12 Integer(i64),
13 String(String),
14 BulkRedisString(RedisString),
15 BulkString(Vec<u8>),
16 Bool(bool),
17}
18
19#[derive(Debug, PartialEq, Clone)]
20pub enum RedisValue {
21 SimpleStringStatic(&'static str),
22 SimpleString(String),
23 BulkString(String),
24 BulkRedisString(RedisString),
25 StringBuffer(Vec<u8>),
26 Integer(i64),
27 Bool(bool),
28 Float(f64),
29 BigNumber(String),
30 VerbatimString((VerbatimStringFormat, Vec<u8>)),
31 Array(Vec<RedisValue>),
32 StaticError(&'static str),
33 Map(HashMap<RedisValueKey, RedisValue>),
34 Set(HashSet<RedisValueKey>),
35 OrderedMap(BTreeMap<RedisValueKey, RedisValue>),
36 OrderedSet(BTreeSet<RedisValueKey>),
37 Null,
38 NoReply, }
40
41impl TryFrom<RedisValue> for String {
42 type Error = RedisError;
43 fn try_from(val: RedisValue) -> Result<Self, RedisError> {
44 match val {
45 RedisValue::SimpleStringStatic(s) => Ok(s.to_string()),
46 RedisValue::SimpleString(s) => Ok(s),
47 RedisValue::BulkString(s) => Ok(s),
48 RedisValue::BulkRedisString(s) => Ok(s.try_as_str()?.to_string()),
49 RedisValue::StringBuffer(s) => Ok(std::str::from_utf8(&s)?.to_string()),
50 _ => Err(RedisError::Str("Can not convert result to String")),
51 }
52 }
53}
54
55impl From<String> for RedisValueKey {
56 fn from(s: String) -> Self {
57 Self::String(s)
58 }
59}
60
61impl From<i64> for RedisValueKey {
62 fn from(i: i64) -> Self {
63 Self::Integer(i)
64 }
65}
66
67impl From<RedisString> for RedisValueKey {
68 fn from(rs: RedisString) -> Self {
69 Self::BulkRedisString(rs)
70 }
71}
72
73impl From<Vec<u8>> for RedisValueKey {
74 fn from(s: Vec<u8>) -> Self {
75 Self::BulkString(s)
76 }
77}
78
79impl From<&str> for RedisValueKey {
80 fn from(s: &str) -> Self {
81 s.to_owned().into()
82 }
83}
84
85impl From<&String> for RedisValueKey {
86 fn from(s: &String) -> Self {
87 s.clone().into()
88 }
89}
90
91impl From<bool> for RedisValueKey {
92 fn from(b: bool) -> Self {
93 Self::Bool(b)
94 }
95}
96
97impl From<()> for RedisValue {
98 fn from(_: ()) -> Self {
99 Self::Null
100 }
101}
102
103impl From<i64> for RedisValue {
104 fn from(i: i64) -> Self {
105 Self::Integer(i)
106 }
107}
108
109impl From<bool> for RedisValue {
110 fn from(b: bool) -> Self {
111 Self::Bool(b)
112 }
113}
114
115impl From<usize> for RedisValue {
116 fn from(i: usize) -> Self {
117 (i as i64).into()
118 }
119}
120
121impl From<f64> for RedisValue {
122 fn from(f: f64) -> Self {
123 Self::Float(f)
124 }
125}
126
127impl From<String> for RedisValue {
128 fn from(s: String) -> Self {
129 Self::BulkString(s)
130 }
131}
132
133impl From<RedisString> for RedisValue {
134 fn from(s: RedisString) -> Self {
135 Self::BulkRedisString(s)
136 }
137}
138
139impl From<Vec<u8>> for RedisValue {
140 fn from(s: Vec<u8>) -> Self {
141 Self::StringBuffer(s)
142 }
143}
144
145impl From<&RedisString> for RedisValue {
146 fn from(s: &RedisString) -> Self {
147 s.clone().into()
148 }
149}
150
151impl From<&str> for RedisValue {
152 fn from(s: &str) -> Self {
153 s.to_owned().into()
154 }
155}
156
157impl From<&String> for RedisValue {
158 fn from(s: &String) -> Self {
159 s.clone().into()
160 }
161}
162
163impl<T: Into<Self>> From<Option<T>> for RedisValue {
164 fn from(s: Option<T>) -> Self {
165 s.map_or(Self::Null, Into::into)
166 }
167}
168
169impl<T: Into<Self>> From<Vec<T>> for RedisValue {
170 fn from(items: Vec<T>) -> Self {
171 Self::Array(items.into_iter().map(Into::into).collect())
172 }
173}
174
175impl<K: Into<RedisValueKey>, V: Into<RedisValue>> From<HashMap<K, V>> for RedisValue {
176 fn from(items: HashMap<K, V>) -> Self {
177 Self::Map(
178 items
179 .into_iter()
180 .map(|(k, v)| (k.into(), v.into()))
181 .collect(),
182 )
183 }
184}
185
186impl<K: Into<RedisValueKey>, V: Into<RedisValue>> From<BTreeMap<K, V>> for RedisValue {
187 fn from(items: BTreeMap<K, V>) -> Self {
188 Self::OrderedMap(
189 items
190 .into_iter()
191 .map(|(k, v)| (k.into(), v.into()))
192 .collect(),
193 )
194 }
195}
196
197impl<K: Into<RedisValueKey>> From<HashSet<K>> for RedisValue {
198 fn from(items: HashSet<K>) -> Self {
199 Self::Set(items.into_iter().map(Into::into).collect())
200 }
201}
202
203impl<K: Into<RedisValueKey>> From<BTreeSet<K>> for RedisValue {
204 fn from(items: BTreeSet<K>) -> Self {
205 Self::OrderedSet(items.into_iter().map(Into::into).collect())
206 }
207}
208
209impl<'root> TryFrom<&CallReply<'root>> for RedisValueKey {
210 type Error = RedisError;
211 fn try_from(reply: &CallReply<'root>) -> Result<Self, Self::Error> {
212 match reply {
213 CallReply::I64(reply) => Ok(RedisValueKey::Integer(reply.to_i64())),
214 CallReply::String(reply) => Ok(reply
215 .to_string()
216 .map_or(RedisValueKey::BulkString(reply.as_bytes().to_vec()), |v| {
217 RedisValueKey::String(v)
218 })),
219 CallReply::Bool(b) => Ok(RedisValueKey::Bool(b.to_bool())),
220 _ => Err(RedisError::String(format!(
221 "Given CallReply can not be used as a map key or a set element, {:?}",
222 reply
223 ))),
224 }
225 }
226}
227
228impl<'root> From<&CallReply<'root>> for RedisValue {
229 fn from(reply: &CallReply<'root>) -> Self {
230 match reply {
231 CallReply::Unknown => RedisValue::StaticError("Error on method call"),
232 CallReply::Array(reply) => {
233 RedisValue::Array(reply.iter().map(|v| (&v).into()).collect())
234 }
235 CallReply::I64(reply) => RedisValue::Integer(reply.to_i64()),
236 CallReply::String(reply) => reply
237 .to_string()
238 .map(RedisValue::SimpleString)
239 .unwrap_or_else(|| RedisValue::StringBuffer(reply.as_bytes().to_vec())),
240 CallReply::Null(_) => RedisValue::Null,
241 CallReply::Map(reply) => RedisValue::Map(
242 reply
243 .iter()
244 .map(|(key, val)| {
245 (
246 (&key).try_into().unwrap_or_else(|e| {
247 panic!("Got unhashable map key from Redis, {key:?}, {e}")
248 }),
249 (&val).into(),
250 )
251 })
252 .collect(),
253 ),
254 CallReply::Set(reply) => RedisValue::Set(
255 reply
256 .iter()
257 .map(|v| {
258 (&v).try_into().unwrap_or_else(|e| {
259 panic!("Got unhashable set element from Redis, {v:?}, {e}")
260 })
261 })
262 .collect(),
263 ),
264 CallReply::Bool(reply) => RedisValue::Bool(reply.to_bool()),
265 CallReply::Double(reply) => RedisValue::Float(reply.to_double()),
266 CallReply::BigNumber(reply) => reply
267 .to_string()
268 .map(RedisValue::BigNumber)
269 .unwrap_or_else(|| {
270 RedisValue::StaticError("Invalid BigNumber: not valid UTF-8")
272 }),
273 CallReply::VerbatimString(reply) => reply
274 .to_parts()
275 .map(RedisValue::VerbatimString)
276 .unwrap_or_else(|| {
277 RedisValue::StaticError("Invalid VerbatimString: format not valid UTF-8")
279 }),
280 }
281 }
282}
283
284impl<'root> From<&CallResult<'root>> for RedisValue {
285 fn from(reply: &CallResult<'root>) -> Self {
286 reply.as_ref().map_or_else(
287 |e| {
288 RedisValue::StringBuffer(e.as_bytes().to_vec())
292 },
293 |v| (v).into(),
294 )
295 }
296}
297
298impl<'root> TryFrom<&CallResult<'root>> for RedisValueKey {
299 type Error = RedisError;
300 fn try_from(reply: &CallResult<'root>) -> Result<Self, Self::Error> {
301 reply.as_ref().map_or_else(
302 |e| {
303 Err(RedisError::String(
304 format!("Got an error reply which can not be translated into a map key or set element, {:?}", e),
305 ))
306 },
307 |v| v.try_into(),
308 )
309 }
310}
311
312#[cfg(test)]
315mod tests {
316 use super::RedisValue;
317
318 #[test]
319 fn from_vec_string() {
320 assert_eq!(
321 RedisValue::from(vec!["foo".to_string()]),
322 RedisValue::Array(vec![RedisValue::BulkString("foo".to_owned())])
323 );
324 }
325
326 #[test]
327 fn from_vec_str() {
328 assert_eq!(
329 RedisValue::from(vec!["foo"]),
330 RedisValue::Array(vec![RedisValue::BulkString("foo".to_owned())])
331 );
332 }
333
334 #[test]
335 fn from_vec_string_ref() {
336 assert_eq!(
337 RedisValue::from(vec![&"foo".to_string()]),
338 RedisValue::Array(vec![RedisValue::BulkString("foo".to_owned())])
339 );
340 }
341
342 #[test]
343 fn from_option_str() {
344 assert_eq!(
345 RedisValue::from(Some("foo")),
346 RedisValue::BulkString("foo".to_owned())
347 );
348 }
349
350 #[test]
351 fn from_vec() {
352 let v: Vec<u8> = vec![0, 3, 5, 21, 255];
353 assert_eq!(
354 RedisValue::from(v),
355 RedisValue::StringBuffer(vec![0, 3, 5, 21, 255])
356 );
357 }
358
359 #[test]
360 fn from_option_none() {
361 assert_eq!(RedisValue::from(None::<()>), RedisValue::Null,);
362 }
363}