1use crate::ValkeyResult;
8use crate::error::GlideError;
9use bytes::Bytes;
10use num_bigint::BigInt;
11use redis::{Value, VerbatimFormat};
12
13#[derive(Clone, Debug, PartialEq)]
19pub enum ValkeyValue {
20 Nil,
22
23 Int(i64),
25
26 BulkString(Bytes),
28
29 Array(Vec<ValkeyValue>),
31
32 SimpleString(String),
34
35 Okay,
37
38 Map(Vec<(ValkeyValue, ValkeyValue)>),
40
41 Set(Vec<ValkeyValue>),
43
44 Double(f64),
46
47 Boolean(bool),
49
50 VerbatimString {
52 format: ValkeyVerbatimFormat,
54 text: String,
56 },
57
58 BigNumber(BigInt),
60
61 ServerError(ValkeyServerError),
63}
64
65#[derive(Clone, Debug, PartialEq, Eq)]
69pub enum ValkeyVerbatimFormat {
70 Unknown(String),
72
73 Markdown,
75
76 Text,
78}
79
80#[derive(Clone, Debug, PartialEq, Eq)]
84pub struct ValkeyServerError {
85 code: String,
86 detail: Option<String>,
87}
88
89impl ValkeyServerError {
90 pub fn err_code(&self) -> &str {
92 &self.code
93 }
94
95 pub fn details(&self) -> Option<&str> {
97 self.detail.as_deref()
98 }
99}
100
101impl ValkeyVerbatimFormat {
102 fn from_redis(format: VerbatimFormat) -> Self {
103 match format {
104 VerbatimFormat::Unknown(s) => ValkeyVerbatimFormat::Unknown(s),
105 VerbatimFormat::Markdown => ValkeyVerbatimFormat::Markdown,
106 VerbatimFormat::Text => ValkeyVerbatimFormat::Text,
107 }
108 }
109}
110
111impl ValkeyValue {
112 pub(crate) fn from_redis(value: Value) -> ValkeyResult<Self> {
113 let pairs = |ps: Vec<(Value, Value)>| -> ValkeyResult<Vec<(ValkeyValue, ValkeyValue)>> {
114 ps.into_iter()
115 .map(|(k, v)| Ok((ValkeyValue::from_redis(k)?, ValkeyValue::from_redis(v)?)))
116 .collect()
117 };
118 Ok(match value {
119 Value::Nil => ValkeyValue::Nil,
120 Value::Int(i) => ValkeyValue::Int(i),
121 Value::BulkString(b) => ValkeyValue::BulkString(b),
122 Value::Array(items) => ValkeyValue::Array(
123 items
124 .into_iter()
125 .map(ValkeyValue::from_redis)
126 .collect::<ValkeyResult<_>>()?,
127 ),
128 Value::SimpleString(s) => ValkeyValue::SimpleString(s),
129 Value::Okay => ValkeyValue::Okay,
130 Value::Map(ps) => ValkeyValue::Map(pairs(ps)?),
131 Value::Set(items) => ValkeyValue::Set(
132 items
133 .into_iter()
134 .map(ValkeyValue::from_redis)
135 .collect::<ValkeyResult<_>>()?,
136 ),
137 Value::Double(d) => ValkeyValue::Double(d),
138 Value::Boolean(b) => ValkeyValue::Boolean(b),
139 Value::VerbatimString { format, text } => ValkeyValue::VerbatimString {
140 format: ValkeyVerbatimFormat::from_redis(format),
141 text,
142 },
143 Value::BigNumber(n) => ValkeyValue::BigNumber(n),
144 Value::ServerError(e) => ValkeyValue::ServerError(ValkeyServerError {
145 code: e.err_code().to_string(),
146 detail: e.details().map(str::to_string),
147 }),
148
149 Value::Attribute { data, .. } => ValkeyValue::from_redis(*data)?,
153
154 Value::Push { .. } => {
157 return Err(GlideError::Request(
158 "unexpected Push value in command reply".into(),
159 ));
160 }
161 })
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168 use redis::{ErrorKind, RedisError};
169
170 #[test]
173 fn from_redis_maps_variants() {
174 let rv = Value::Array(vec![
175 Value::Nil,
176 Value::Int(-5),
177 Value::BulkString(Bytes::from_static(b"hi")),
178 Value::SimpleString("s".into()),
179 Value::Okay,
180 Value::Double(1.5),
181 Value::Boolean(true),
182 Value::BigNumber(BigInt::from(i64::MAX) + 1),
183 Value::VerbatimString {
184 format: VerbatimFormat::Markdown,
185 text: "md".into(),
186 },
187 Value::Map(vec![(Value::Int(1), Value::Int(2))]),
188 Value::Set(vec![Value::Int(9)]),
189 Value::Attribute {
190 data: Box::new(Value::Int(42)),
191 attributes: vec![(Value::SimpleString("k".into()), Value::Int(1))],
192 },
193 ]);
194 let vv = ValkeyValue::from_redis(rv).unwrap();
195 assert_eq!(
196 vv,
197 ValkeyValue::Array(vec![
198 ValkeyValue::Nil,
199 ValkeyValue::Int(-5),
200 ValkeyValue::BulkString(Bytes::from_static(b"hi")),
201 ValkeyValue::SimpleString("s".into()),
202 ValkeyValue::Okay,
203 ValkeyValue::Double(1.5),
204 ValkeyValue::Boolean(true),
205 ValkeyValue::BigNumber(BigInt::from(i64::MAX) + 1),
206 ValkeyValue::VerbatimString {
207 format: ValkeyVerbatimFormat::Markdown,
208 text: "md".into(),
209 },
210 ValkeyValue::Map(vec![(ValkeyValue::Int(1), ValkeyValue::Int(2))]),
211 ValkeyValue::Set(vec![ValkeyValue::Int(9)]),
212 ValkeyValue::Int(42),
213 ])
214 );
215 }
216
217 #[test]
218 fn from_redis_reads_server_error_code_and_detail() {
219 let error = RedisError::from((ErrorKind::ResponseError, "boom", "detail".to_string()));
220 let v = Value::ServerError(error.into());
221 match ValkeyValue::from_redis(v).unwrap() {
222 ValkeyValue::ServerError(e) => {
223 assert_eq!(e.err_code(), "ERR");
224 assert_eq!(e.details(), Some("boom detail"));
225 }
226 other => panic!("expected ServerError, got {other:?}"),
227 }
228 }
229
230 #[test]
231 fn from_redis_push_value_error() {
232 let v = Value::Push {
233 kind: redis::PushKind::Message,
234 data: vec![Value::Int(1)],
235 };
236 assert!(ValkeyValue::from_redis(v).is_err());
237 }
238}
239
240pub trait FromValkeyValue: Sized {
244 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<Self>;
246
247 fn from_valkey_value(value: &ValkeyValue) -> ValkeyResult<Self> {
249 Self::from_owned_valkey_value(value.clone())
250 }
251
252 #[doc(hidden)]
254 fn from_owned_valkey_values(items: Vec<ValkeyValue>) -> ValkeyResult<Vec<Self>> {
255 items
256 .into_iter()
257 .map(Self::from_owned_valkey_value)
258 .collect()
259 }
260
261 #[doc(hidden)]
263 fn from_owned_byte_vec(bytes: Vec<u8>) -> ValkeyResult<Vec<Self>> {
264 Self::from_owned_valkey_value(ValkeyValue::BulkString(Bytes::from(bytes))).map(|v| vec![v])
265 }
266}
267
268pub(crate) fn to_glide_error(value: ValkeyValue, msg: &str) -> GlideError {
270 GlideError::Request(format!("{msg} (response was {value:?})"))
271}
272
273fn into_map<K, V, M>(value: ValkeyValue, target_type: &str) -> ValkeyResult<M>
276where
277 K: FromValkeyValue,
278 V: FromValkeyValue,
279 M: FromIterator<(K, V)>,
280{
281 let pairs: Vec<(ValkeyValue, ValkeyValue)> = match value {
283 ValkeyValue::Nil => Vec::new(),
284 ValkeyValue::Map(pairs) => pairs,
285 ValkeyValue::Array(items) if items.len() % 2 == 0 => {
286 let mut it = items.into_iter();
287 let mut pairs = Vec::with_capacity(it.len() / 2);
288 while let (Some(k), Some(v)) = (it.next(), it.next()) {
289 pairs.push((k, v));
290 }
291 pairs
292 }
293 other => return Err(to_glide_error(other, target_type)),
294 };
295
296 pairs
297 .into_iter()
298 .map(|(k, v)| {
299 Ok((
300 K::from_owned_valkey_value(k)?,
301 V::from_owned_valkey_value(v)?,
302 ))
303 })
304 .collect()
305}
306
307fn into_set<T, C>(value: ValkeyValue, target_type: &str) -> ValkeyResult<C>
310where
311 T: FromValkeyValue,
312 C: FromIterator<T>,
313{
314 let items = match value {
315 ValkeyValue::Array(items) => items,
316 ValkeyValue::Set(items) => items,
317 ValkeyValue::Nil => Vec::new(),
318 other => return Err(to_glide_error(other, target_type)),
319 };
320
321 items.into_iter().map(T::from_owned_valkey_value).collect()
322}
323
324macro_rules! decode_valkey_int {
327 ($t:ty, $value:expr) => {
328 match $value {
329 ValkeyValue::Boolean(b) => Ok(<$t>::from(b)),
330 #[allow(clippy::unnecessary_fallible_conversions)]
331 ValkeyValue::Int(v) => <$t>::try_from(v).map_err(|_| {
332 to_glide_error(
333 ValkeyValue::Int(v),
334 concat!("Response integer out of range for ", stringify!($t), "."),
335 )
336 }),
337 ValkeyValue::Double(v)
340 if v.is_finite()
341 && v.fract() == 0.0
342 && v >= <$t>::MIN as f64
343 && v < <$t>::MAX as f64 + 1.0 =>
344 {
345 Ok(v as $t)
346 }
347 ValkeyValue::Double(v) => Err(to_glide_error(
348 ValkeyValue::Double(v),
349 concat!(
350 "Response double is not an integer in range for ",
351 stringify!($t),
352 "."
353 ),
354 )),
355 ValkeyValue::SimpleString(s) => {
356 let parsed = s.parse::<$t>().ok();
357 parsed.ok_or_else(|| {
358 to_glide_error(
359 ValkeyValue::SimpleString(s),
360 concat!("Could not convert string to ", stringify!($t), "."),
361 )
362 })
363 }
364 ValkeyValue::BulkString(bytes) => {
365 let parsed = std::str::from_utf8(&bytes)
366 .ok()
367 .and_then(|s| s.parse::<$t>().ok());
368 parsed.ok_or_else(|| {
369 to_glide_error(
370 ValkeyValue::BulkString(bytes),
371 concat!("Could not convert string to ", stringify!($t), "."),
372 )
373 })
374 }
375 other => Err(to_glide_error(
376 other,
377 concat!("Response type not convertible to ", stringify!($t), "."),
378 )),
379 }
380 };
381}
382
383macro_rules! impl_from_valkey_int {
384 ($($t:ty),* $(,)?) => {$(
385 impl FromValkeyValue for $t {
386 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<$t> {
387 decode_valkey_int!($t, value)
388 }
389 }
390 )*};
391}
392
393impl_from_valkey_int!(i8, i16, i32, i64, i128, u16, u32, u64, u128, isize, usize);
394
395macro_rules! impl_from_valkey_float {
396 ($($t:ty),* $(,)?) => {$(
397 impl FromValkeyValue for $t {
398 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<$t> {
399 match value {
400 ValkeyValue::Boolean(b) => Ok(<$t>::from(b)),
401 ValkeyValue::Int(v) => Ok(v as $t),
402 ValkeyValue::Double(v) => Ok(v as $t),
403 ValkeyValue::SimpleString(s) => {
404 let parsed = s.parse::<$t>().ok();
405 parsed.ok_or_else(|| {
406 to_glide_error(
407 ValkeyValue::SimpleString(s),
408 concat!("Could not convert string to ", stringify!($t), "."),
409 )
410 })
411 }
412 ValkeyValue::BulkString(bytes) => {
413 let parsed = std::str::from_utf8(&bytes)
414 .ok()
415 .and_then(|s| s.parse::<$t>().ok());
416 parsed.ok_or_else(|| {
417 to_glide_error(
418 ValkeyValue::BulkString(bytes),
419 concat!("Could not convert string to ", stringify!($t), "."),
420 )
421 })
422 }
423 other => Err(to_glide_error(
424 other,
425 concat!("Response type not convertible to ", stringify!($t), "."),
426 )),
427 }
428 }
429 }
430 )*};
431}
432
433impl_from_valkey_float!(f32, f64);
434
435impl FromValkeyValue for u8 {
436 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<u8> {
437 decode_valkey_int!(u8, value)
438 }
439
440 fn from_owned_byte_vec(bytes: Vec<u8>) -> ValkeyResult<Vec<u8>> {
442 Ok(bytes)
443 }
444}
445
446impl FromValkeyValue for bool {
448 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<bool> {
449 match value {
450 ValkeyValue::Nil => Ok(false),
451 ValkeyValue::Int(v) => Ok(v != 0),
452 ValkeyValue::Boolean(b) => Ok(b),
453 ValkeyValue::Okay => Ok(true),
454 ValkeyValue::SimpleString(ref s) if s == "1" => Ok(true),
455 ValkeyValue::SimpleString(ref s) if s == "0" => Ok(false),
456 ValkeyValue::BulkString(ref b) if b.as_ref() == b"1" => Ok(true),
457 ValkeyValue::BulkString(ref b) if b.as_ref() == b"0" => Ok(false),
458 other => Err(to_glide_error(other, "Response type not bool compatible.")),
459 }
460 }
461}
462
463impl FromValkeyValue for String {
465 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<String> {
466 match value {
467 ValkeyValue::BulkString(bytes) => String::from_utf8(bytes.to_vec())
468 .map_err(|_| GlideError::Request("Response was not valid UTF-8.".into())),
469 ValkeyValue::Okay => Ok("OK".to_string()),
470 ValkeyValue::SimpleString(s) => Ok(s),
471 ValkeyValue::VerbatimString { text, .. } => Ok(text),
472 ValkeyValue::Double(v) => Ok(v.to_string()),
473 ValkeyValue::Int(v) => Ok(v.to_string()),
474 other => Err(to_glide_error(
475 other,
476 "Response type not string compatible.",
477 )),
478 }
479 }
480}
481
482impl FromValkeyValue for Bytes {
484 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<Bytes> {
485 match value {
486 ValkeyValue::BulkString(bytes) => Ok(bytes),
487 ValkeyValue::SimpleString(s) => Ok(Bytes::from(s.into_bytes())),
488 ValkeyValue::VerbatimString { text, .. } => Ok(Bytes::from(text.into_bytes())),
489 other => Err(to_glide_error(other, "Response type not byte compatible.")),
490 }
491 }
492}
493
494impl FromValkeyValue for () {
495 fn from_owned_valkey_value(_value: ValkeyValue) -> ValkeyResult<()> {
496 Ok(())
497 }
498}
499
500impl FromValkeyValue for ValkeyValue {
502 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<ValkeyValue> {
503 Ok(value)
504 }
505}
506
507impl<T: FromValkeyValue> FromValkeyValue for Option<T> {
509 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<Option<T>> {
510 match value {
511 ValkeyValue::Nil => Ok(None),
512 other => Ok(Some(T::from_owned_valkey_value(other)?)),
513 }
514 }
515}
516
517impl<T: FromValkeyValue> FromValkeyValue for Vec<T> {
519 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<Vec<T>> {
520 match value {
521 ValkeyValue::BulkString(bytes) => T::from_owned_byte_vec(bytes.to_vec()),
522 ValkeyValue::Array(items) => T::from_owned_valkey_values(items),
523 ValkeyValue::Set(items) => T::from_owned_valkey_values(items),
524 ValkeyValue::Map(pairs) => {
525 let mut out = Vec::with_capacity(pairs.len());
527 for (k, v) in pairs {
528 out.push(T::from_owned_valkey_value(ValkeyValue::Map(vec![(k, v)]))?);
529 }
530 Ok(out)
531 }
532 ValkeyValue::Nil => Ok(Vec::new()),
533 other => Err(to_glide_error(
534 other,
535 "Response type not vector compatible.",
536 )),
537 }
538 }
539}
540
541impl<K, V, S> FromValkeyValue for std::collections::HashMap<K, V, S>
543where
544 K: FromValkeyValue + std::cmp::Eq + std::hash::Hash,
545 V: FromValkeyValue,
546 S: std::hash::BuildHasher + Default,
547{
548 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<Self> {
549 into_map(value, "Response type not hashmap compatible")
550 }
551}
552
553impl<T, S> FromValkeyValue for std::collections::HashSet<T, S>
555where
556 T: FromValkeyValue + std::cmp::Eq + std::hash::Hash,
557 S: std::hash::BuildHasher + Default,
558{
559 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<Self> {
560 into_set(value, "Response type not hashset compatible")
561 }
562}
563
564impl<K, V> FromValkeyValue for std::collections::BTreeMap<K, V>
566where
567 K: FromValkeyValue + std::cmp::Ord,
568 V: FromValkeyValue,
569{
570 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<Self> {
571 into_map(value, "Response type not btreemap compatible")
572 }
573}
574
575impl<T> FromValkeyValue for std::collections::BTreeSet<T>
577where
578 T: FromValkeyValue + std::cmp::Ord,
579{
580 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<Self> {
581 into_set(value, "Response type not btreeset compatible")
582 }
583}
584
585impl<T: FromValkeyValue, const N: usize> FromValkeyValue for [T; N] {
587 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<[T; N]> {
588 let items = Vec::<T>::from_owned_valkey_value(value)?;
589 let len = items.len();
590 items.try_into().map_err(|_| {
591 GlideError::Request(format!(
592 "Array response of wrong dimension (expected {N}, got {len})"
593 ))
594 })
595 }
596}
597
598impl<T: FromValkeyValue> FromValkeyValue for Box<[T]> {
600 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<Box<[T]>> {
601 Ok(Vec::<T>::from_owned_valkey_value(value)?.into_boxed_slice())
602 }
603}
604
605impl<T: FromValkeyValue> FromValkeyValue for std::sync::Arc<[T]> {
607 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<std::sync::Arc<[T]>> {
608 Ok(Vec::<T>::from_owned_valkey_value(value)?.into())
609 }
610}
611
612macro_rules! impl_from_valkey_tuple {
614 ($( ($($name:ident),+) ),+ $(,)?) => {$(
615 #[doc(hidden)]
616 impl<$($name: FromValkeyValue),*> FromValkeyValue for ($($name,)*) {
617 #[allow(non_snake_case, unused_variables)]
618 fn from_owned_valkey_value(value: ValkeyValue) -> ValkeyResult<($($name,)*)> {
619 match value {
620 ValkeyValue::Array(mut items) => {
621 let mut n = 0;
622 $(let $name = (); n += 1;)*
623 if items.len() != n {
624 return Err(GlideError::Request("Array response of wrong dimension".into()));
625 }
626 let mut i = 0;
627 Ok(($({ let $name = (); $name::from_owned_valkey_value(
628 std::mem::replace(&mut items[{ i += 1; i - 1 }], ValkeyValue::Nil))? },)*))
629 }
630 ValkeyValue::Map(items) => {
631 let mut n = 0;
632 $(let $name = (); n += 1;)*
633
634 if n != 2 || items.len() != 1 {
636 return Err(GlideError::Request("Map response of wrong dimension".into()));
637 }
638
639 let (k, v) = items.into_iter().next().expect("exactly one entry checked above");
640 let mut flat = [k, v];
641 let mut i = 0;
642 Ok(($({ let $name = (); $name::from_owned_valkey_value(
643 std::mem::replace(&mut flat[{ i += 1; i - 1 }], ValkeyValue::Nil))? },)*))
644 }
645 other => Err(to_glide_error(other, "Not an Array response")),
646 }
647 }
648 #[allow(non_snake_case, unused_variables)]
649 fn from_owned_valkey_values(items: Vec<ValkeyValue>) -> ValkeyResult<Vec<($($name,)*)>> {
650 let mut n = 0;
651 $(let $name = (); n += 1;)*
652
653 if items.is_empty() {
654 return Ok(Vec::new());
655 }
656
657 let mut items = items;
658
659 if items
661 .iter()
662 .all(|it| matches!(it, ValkeyValue::Array(ch) if ch.len() == n))
663 {
664 let mut rv = Vec::with_capacity(items.len());
665 for item in &mut items {
666 if let ValkeyValue::Array(ch) = item {
667 if let [$($name),*] = &mut ch[..] {
668 rv.push(($($name::from_owned_valkey_value(
669 std::mem::replace($name, ValkeyValue::Nil))?,)*));
670 }
671 }
672 }
673
674 return Ok(rv);
675 }
676
677 if items.len() % n != 0 {
679 return Err(GlideError::Request("Array response of wrong dimension".into()));
680 }
681
682 let mut rv = Vec::with_capacity(items.len() / n);
683 for chunk in items.chunks_mut(n) {
684 if let [$($name),*] = chunk {
685 rv.push(($($name::from_owned_valkey_value(
686 std::mem::replace($name, ValkeyValue::Nil))?,)*));
687 }
688 }
689
690 Ok(rv)
691 }
692 }
693 )+};
694}
695
696impl_from_valkey_tuple! {
697 (T1),
698 (T1, T2),
699 (T1, T2, T3),
700 (T1, T2, T3, T4),
701 (T1, T2, T3, T4, T5),
702 (T1, T2, T3, T4, T5, T6),
703 (T1, T2, T3, T4, T5, T6, T7),
704 (T1, T2, T3, T4, T5, T6, T7, T8),
705 (T1, T2, T3, T4, T5, T6, T7, T8, T9),
706 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10),
707 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11),
708 (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12),
709}
710
711#[cfg(test)]
712mod from_valkey_value_tests {
713 use super::*;
714 use std::collections::{HashMap, HashSet};
715
716 const NIL: ValkeyValue = ValkeyValue::Nil;
718 const INT: ValkeyValue = ValkeyValue::Int(7);
719 const OKAY: ValkeyValue = ValkeyValue::Okay;
720 const DOUBLE: ValkeyValue = ValkeyValue::Double(1.5);
721 const BOOLEAN: ValkeyValue = ValkeyValue::Boolean(true);
722 const BULK: ValkeyValue = ValkeyValue::BulkString(Bytes::from_static(b"hi"));
723 const BYTES_A: ValkeyValue = ValkeyValue::BulkString(Bytes::from_static(b"a"));
724 const BYTES_B: ValkeyValue = ValkeyValue::BulkString(Bytes::from_static(b"b"));
725 const BYTES_1: ValkeyValue = ValkeyValue::BulkString(Bytes::from_static(b"1"));
726 const BYTES_2: ValkeyValue = ValkeyValue::BulkString(Bytes::from_static(b"2"));
727
728 fn simple() -> ValkeyValue {
731 ValkeyValue::SimpleString("s".into())
732 }
733 fn verbatim() -> ValkeyValue {
734 ValkeyValue::VerbatimString {
735 format: ValkeyVerbatimFormat::Text,
736 text: "vt".into(),
737 }
738 }
739
740 fn decode<T: FromValkeyValue>(v: ValkeyValue) -> T {
741 T::from_owned_valkey_value(v).unwrap()
742 }
743
744 #[test]
745 fn from_owned_valkey_value_integer() {
746 assert_eq!(decode::<i64>(BOOLEAN), 1);
748 assert_eq!(decode::<u8>(ValkeyValue::Boolean(false)), 0);
749 assert_eq!(decode::<usize>(BOOLEAN), 1);
750
751 assert_eq!(decode::<i64>(INT), 7);
753 assert_eq!(decode::<u64>(INT), 7);
754 assert_eq!(decode::<u8>(ValkeyValue::Int(255)), 255);
755 assert_eq!(decode::<i128>(ValkeyValue::Int(i64::MIN)), i64::MIN as i128);
756 assert!(i128::from_owned_valkey_value(ValkeyValue::BigNumber(BigInt::from(1))).is_err());
757 assert!(u128::from_owned_valkey_value(ValkeyValue::BigNumber(BigInt::from(1))).is_err());
758
759 assert!(usize::from_owned_valkey_value(ValkeyValue::Int(-2)).is_err());
761 assert!(u8::from_owned_valkey_value(ValkeyValue::Int(300)).is_err());
762 assert!(i32::from_owned_valkey_value(ValkeyValue::Int(i64::MAX)).is_err());
763
764 assert_eq!(decode::<i64>(ValkeyValue::Double(10.0)), 10);
766 assert_eq!(decode::<i8>(ValkeyValue::Double(-128.0)), i8::MIN);
767 assert_eq!(decode::<i8>(ValkeyValue::Double(127.0)), i8::MAX);
768 assert_eq!(
769 decode::<i64>(ValkeyValue::Double(-9223372036854775808.0)),
770 i64::MIN
771 );
772
773 assert!(i64::from_owned_valkey_value(DOUBLE).is_err());
775 assert!(isize::from_owned_valkey_value(ValkeyValue::Double(10.6)).is_err());
776
777 assert!(i64::from_owned_valkey_value(ValkeyValue::Double(f64::NAN)).is_err());
779 assert!(i64::from_owned_valkey_value(ValkeyValue::Double(f64::INFINITY)).is_err());
780
781 assert!(i64::from_owned_valkey_value(ValkeyValue::Double(1e30)).is_err());
783 assert!(u64::from_owned_valkey_value(ValkeyValue::Double(-1.0)).is_err());
784 assert!(i8::from_owned_valkey_value(ValkeyValue::Double(128.0)).is_err());
785 assert!(u64::from_owned_valkey_value(ValkeyValue::Double(18446744073709551616.0)).is_err());
786 assert!(i64::from_owned_valkey_value(ValkeyValue::Double(9223372036854775807.0)).is_err());
787
788 assert_eq!(
790 decode::<i64>(ValkeyValue::BulkString(Bytes::from_static(b"42"))),
791 42
792 );
793 assert_eq!(decode::<i64>(ValkeyValue::SimpleString("100".into())), 100);
794 assert_eq!(
795 decode::<u64>(ValkeyValue::BulkString(Bytes::from_static(
796 b"18446744073709551615"
797 ))),
798 u64::MAX
799 );
800 assert_eq!(
801 decode::<i64>(ValkeyValue::BulkString(Bytes::from_static(b"+5"))),
802 5
803 );
804
805 assert!(i64::from_owned_valkey_value(OKAY).is_err());
807 assert!(i64::from_owned_valkey_value(BULK).is_err());
808
809 let bulk = |s: &'static str| ValkeyValue::BulkString(Bytes::from_static(s.as_bytes()));
811 assert!(u8::from_owned_valkey_value(bulk("300")).is_err());
812 assert!(usize::from_owned_valkey_value(bulk("-1")).is_err());
813 assert!(i64::from_owned_valkey_value(bulk("1.5")).is_err());
814 assert!(i64::from_owned_valkey_value(bulk(" 5")).is_err());
815 assert!(i64::from_owned_valkey_value(bulk("1e3")).is_err());
816 assert!(u8::from_owned_valkey_value(ValkeyValue::SimpleString("256".into())).is_err());
817 }
818
819 #[test]
820 fn from_owned_valkey_value_double() {
821 let bulk = |s: &'static str| ValkeyValue::BulkString(Bytes::from_static(s.as_bytes()));
822
823 assert_eq!(decode::<f64>(BOOLEAN), 1.0);
825 assert_eq!(decode::<f32>(ValkeyValue::Boolean(false)), 0.0);
826
827 assert_eq!(decode::<f64>(INT), 7.0);
829 assert_eq!(
830 decode::<f64>(ValkeyValue::Int((1 << 53) + 1)),
831 9007199254740992.0
832 );
833
834 assert_eq!(decode::<f64>(DOUBLE), 1.5);
836 assert_eq!(decode::<f32>(DOUBLE), 1.5);
837 assert_eq!(decode::<f32>(ValkeyValue::Double(1e300)), f32::INFINITY);
838
839 assert_eq!(decode::<f64>(bulk("4.25")), 4.25);
841 assert_eq!(
842 decode::<f64>(ValkeyValue::SimpleString("-2.5".into())),
843 -2.5
844 );
845 assert_eq!(decode::<f64>(bulk("inf")), f64::INFINITY);
846 assert!(decode::<f64>(bulk("nan")).is_nan());
847
848 assert!(f64::from_owned_valkey_value(NIL).is_err());
850 assert!(f64::from_owned_valkey_value(OKAY).is_err());
851 assert!(f64::from_owned_valkey_value(BULK).is_err());
852 assert!(f64::from_owned_valkey_value(simple()).is_err());
853 }
854
855 #[test]
856 fn from_owned_valkey_value_bool() {
857 let bulk_string_bool = ValkeyValue::BulkString(Bytes::from_static(b"0"));
858
859 assert!(decode::<bool>(INT)); assert!(!decode::<bool>(ValkeyValue::Int(0)));
861 assert!(decode::<bool>(BOOLEAN));
862 assert!(decode::<bool>(OKAY));
863 assert!(!decode::<bool>(NIL));
864 assert!(decode::<bool>(ValkeyValue::SimpleString("1".into())));
865 assert!(!decode::<bool>(bulk_string_bool));
866 }
867
868 #[test]
869 fn from_owned_valkey_value_string() {
870 assert_eq!(decode::<String>(BULK), "hi");
871 assert_eq!(decode::<String>(simple()), "s");
872 assert_eq!(decode::<String>(OKAY), "OK");
873 assert_eq!(decode::<String>(INT), "7");
874 assert_eq!(decode::<String>(DOUBLE), "1.5");
875 assert_eq!(decode::<String>(verbatim()), "vt");
876 }
877
878 #[test]
879 fn from_owned_valkey_value_bytes() {
880 assert_eq!(decode::<Bytes>(BULK), Bytes::from_static(b"hi"));
881 assert_eq!(decode::<Bytes>(simple()), Bytes::from_static(b"s"));
882 assert_eq!(decode::<Bytes>(verbatim()), Bytes::from_static(b"vt"));
883 }
884
885 #[test]
886 fn from_owned_valkey_value_u8() {
887 assert_eq!(decode::<u8>(INT), 7);
888
889 assert_eq!(decode::<Vec<u8>>(BULK), b"hi".to_vec());
891 assert_eq!(
892 decode::<Vec<u8>>(ValkeyValue::BulkString(Bytes::from_static(b""))),
893 Vec::<u8>::new()
894 );
895
896 assert_eq!(
898 decode::<Vec<u8>>(ValkeyValue::Array(vec![INT, INT])),
899 vec![7u8, 7u8]
900 );
901 }
902
903 #[test]
904 fn from_owned_valkey_value_vec() {
905 let v = ValkeyValue::Array(vec![BYTES_A, BYTES_B]);
906 assert_eq!(
907 decode::<Vec<String>>(v),
908 vec!["a".to_string(), "b".to_string()]
909 );
910
911 assert_eq!(decode::<Vec<String>>(BULK), vec!["hi".to_string()]);
912 assert_eq!(decode::<Vec<String>>(NIL), Vec::<String>::new());
913 }
914
915 #[test]
916 fn from_owned_valkey_value_array() {
917 let v = ValkeyValue::Array(vec![BYTES_A, BYTES_B]);
918 let a: [String; 2] = decode(v.clone());
919 assert_eq!(a, ["a".to_string(), "b".to_string()]);
920
921 assert!(<[String; 3]>::from_owned_valkey_value(v).is_err());
923 }
924
925 #[test]
926 fn from_owned_valkey_value_boxed_slice() {
927 let v = ValkeyValue::Array(vec![BYTES_A, BYTES_B]);
928 let b: Box<[String]> = decode(v);
929 assert_eq!(&b[..], ["a".to_string(), "b".to_string()]);
930 }
931
932 #[test]
933 fn from_owned_valkey_value_arc_slice() {
934 let v = ValkeyValue::Array(vec![BYTES_A, BYTES_B]);
935 let a: std::sync::Arc<[String]> = decode(v);
936 assert_eq!(&a[..], ["a".to_string(), "b".to_string()]);
937 }
938
939 #[test]
940 fn from_owned_valkey_value_option() {
941 let none: Option<String> = decode(NIL);
942 assert_eq!(none, None);
943
944 let some: Option<String> = decode(BULK);
945 assert_eq!(some.as_deref(), Some("hi"));
946 }
947
948 #[test]
949 fn from_owned_valkey_value_unit() {
950 let _: () = decode(OKAY);
951 let _: () = decode(NIL);
952 }
953
954 #[test]
955 fn from_owned_valkey_value_identity() {
956 assert_eq!(decode::<ValkeyValue>(INT), INT);
957 assert_eq!(decode::<ValkeyValue>(NIL), NIL);
958 assert_eq!(decode::<ValkeyValue>(simple()), simple());
959 }
960
961 #[test]
962 fn from_owned_valkey_value_hashmap() {
963 let from_map = ValkeyValue::Map(vec![(BULK, BULK)]);
964 let m: HashMap<String, String> = decode(from_map);
965 assert_eq!(m.get("hi").map(String::as_str), Some("hi"));
966
967 let from_flat = ValkeyValue::Array(vec![BYTES_A, BYTES_1, BYTES_B, BYTES_2]);
968 let m: HashMap<String, i64> = decode(from_flat);
969 assert_eq!(m.get("a"), Some(&1));
970 assert_eq!(m.get("b"), Some(&2));
971
972 let empty: HashMap<String, String> = decode(NIL);
973 assert!(empty.is_empty());
974 }
975
976 #[test]
977 fn from_owned_valkey_value_btreemap() {
978 use std::collections::BTreeMap;
979
980 let from_map = ValkeyValue::Map(vec![(BYTES_A, BYTES_1), (BYTES_B, BYTES_2)]);
981 let m: BTreeMap<String, i64> = decode(from_map);
982 assert_eq!(m.get("a"), Some(&1));
983 assert_eq!(m.get("b"), Some(&2));
984
985 let from_array = ValkeyValue::Array(vec![BYTES_A, BYTES_1, BYTES_B, BYTES_2]);
986 let m: BTreeMap<String, i64> = decode(from_array);
987 assert_eq!(m.get("a"), Some(&1));
988 assert_eq!(m.get("b"), Some(&2));
989
990 let empty: BTreeMap<String, String> = decode(NIL);
991 assert!(empty.is_empty());
992 }
993
994 #[test]
995 fn from_owned_valkey_value_hashset() {
996 let v = ValkeyValue::Set(vec![BYTES_A, BYTES_B]);
997 let s: HashSet<String> = decode(v);
998 assert_eq!(s, HashSet::from(["a".to_string(), "b".to_string()]));
999 }
1000
1001 #[test]
1002 fn from_owned_valkey_value_btreeset() {
1003 use std::collections::BTreeSet;
1004
1005 let v = ValkeyValue::Set(vec![BYTES_A, BYTES_B]);
1006 let s: BTreeSet<String> = decode(v);
1007 assert_eq!(s, BTreeSet::from(["a".to_string(), "b".to_string()]));
1008 }
1009
1010 #[test]
1011 fn from_owned_valkey_value_tuple() {
1012 let t: (String, i64) = decode(ValkeyValue::Array(vec![BULK, INT]));
1013 assert_eq!(t, ("hi".to_string(), 7));
1014
1015 let t: (String, i64, f64) = decode(ValkeyValue::Array(vec![BULK, INT, DOUBLE]));
1016 assert_eq!(t, ("hi".to_string(), 7, 1.5));
1017
1018 assert!(<(String, i64)>::from_owned_valkey_value(ValkeyValue::Array(vec![INT])).is_err());
1020
1021 let t: (String, i64) = decode(ValkeyValue::Map(vec![(BULK, INT)]));
1022 assert_eq!(t, ("hi".to_string(), 7));
1023
1024 let map_2 = ValkeyValue::Map(vec![(BULK, INT), (BYTES_A, INT)]);
1026 assert!(<(String, i64)>::from_owned_valkey_value(map_2).is_err());
1027 }
1028
1029 #[test]
1030 fn from_owned_valkey_value_vec_of_pairs() {
1031 let nested = ValkeyValue::Array(vec![
1033 ValkeyValue::Array(vec![BULK, DOUBLE]),
1034 ValkeyValue::Array(vec![BULK, DOUBLE]),
1035 ]);
1036 let pairs: Vec<(String, f64)> = decode(nested);
1037 assert_eq!(
1038 pairs,
1039 vec![("hi".to_string(), 1.5), ("hi".to_string(), 1.5)]
1040 );
1041
1042 let flat = ValkeyValue::Array(vec![BULK, DOUBLE, BULK, DOUBLE]);
1044 let pairs: Vec<(String, f64)> = decode(flat);
1045 assert_eq!(
1046 pairs,
1047 vec![("hi".to_string(), 1.5), ("hi".to_string(), 1.5)]
1048 );
1049
1050 assert!(
1052 <Vec<(String, f64)>>::from_owned_valkey_value(ValkeyValue::Array(vec![
1053 BULK, DOUBLE, BULK
1054 ]))
1055 .is_err()
1056 );
1057 }
1058
1059 #[test]
1060 fn from_owned_valkey_value_server_error() {
1061 let server_err = ValkeyServerError {
1062 code: "WRONGTYPE".into(),
1063 detail: Some("nope".into()),
1064 };
1065 let value = ValkeyValue::ServerError(server_err);
1066 let request_err = i64::from_owned_valkey_value(value).unwrap_err();
1067
1068 assert_eq!(request_err.class_name(), "RequestError");
1069 assert!(request_err.message().contains("WRONGTYPE"));
1070 }
1071}