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) => RedisValue::SimpleString(reply.to_string().unwrap()),
237 CallReply::Null(_) => RedisValue::Null,
238 CallReply::Map(reply) => RedisValue::Map(
239 reply
240 .iter()
241 .map(|(key, val)| {
242 (
243 (&key).try_into().unwrap_or_else(|e| {
244 panic!("Got unhashable map key from Redis, {key:?}, {e}")
245 }),
246 (&val).into(),
247 )
248 })
249 .collect(),
250 ),
251 CallReply::Set(reply) => RedisValue::Set(
252 reply
253 .iter()
254 .map(|v| {
255 (&v).try_into().unwrap_or_else(|e| {
256 panic!("Got unhashable set element from Redis, {v:?}, {e}")
257 })
258 })
259 .collect(),
260 ),
261 CallReply::Bool(reply) => RedisValue::Bool(reply.to_bool()),
262 CallReply::Double(reply) => RedisValue::Float(reply.to_double()),
263 CallReply::BigNumber(reply) => RedisValue::BigNumber(reply.to_string().unwrap()),
264 CallReply::VerbatimString(reply) => {
265 RedisValue::VerbatimString(reply.to_parts().unwrap())
266 }
267 }
268 }
269}
270
271impl<'root> From<&CallResult<'root>> for RedisValue {
272 fn from(reply: &CallResult<'root>) -> Self {
273 reply.as_ref().map_or_else(
274 |e| {
275 RedisValue::StringBuffer(e.as_bytes().to_vec())
279 },
280 |v| (v).into(),
281 )
282 }
283}
284
285impl<'root> TryFrom<&CallResult<'root>> for RedisValueKey {
286 type Error = RedisError;
287 fn try_from(reply: &CallResult<'root>) -> Result<Self, Self::Error> {
288 reply.as_ref().map_or_else(
289 |e| {
290 Err(RedisError::String(
291 format!("Got an error reply which can not be translated into a map key or set element, {:?}", e),
292 ))
293 },
294 |v| v.try_into(),
295 )
296 }
297}
298
299#[cfg(test)]
302mod tests {
303 use super::RedisValue;
304
305 #[test]
306 fn from_vec_string() {
307 assert_eq!(
308 RedisValue::from(vec!["foo".to_string()]),
309 RedisValue::Array(vec![RedisValue::BulkString("foo".to_owned())])
310 );
311 }
312
313 #[test]
314 fn from_vec_str() {
315 assert_eq!(
316 RedisValue::from(vec!["foo"]),
317 RedisValue::Array(vec![RedisValue::BulkString("foo".to_owned())])
318 );
319 }
320
321 #[test]
322 fn from_vec_string_ref() {
323 assert_eq!(
324 RedisValue::from(vec![&"foo".to_string()]),
325 RedisValue::Array(vec![RedisValue::BulkString("foo".to_owned())])
326 );
327 }
328
329 #[test]
330 fn from_option_str() {
331 assert_eq!(
332 RedisValue::from(Some("foo")),
333 RedisValue::BulkString("foo".to_owned())
334 );
335 }
336
337 #[test]
338 fn from_vec() {
339 let v: Vec<u8> = vec![0, 3, 5, 21, 255];
340 assert_eq!(
341 RedisValue::from(v),
342 RedisValue::StringBuffer(vec![0, 3, 5, 21, 255])
343 );
344 }
345
346 #[test]
347 fn from_option_none() {
348 assert_eq!(RedisValue::from(None::<()>), RedisValue::Null,);
349 }
350}