1use std::collections::{BTreeMap, BTreeSet};
2use std::collections::{HashMap, HashSet};
3use std::convert::From;
4use std::default::Default;
5use std::error;
6use std::fmt;
7use std::hash::{BuildHasher, Hash};
8use std::io;
9use std::str::{from_utf8, Utf8Error};
10use std::string::FromUtf8Error;
11
12macro_rules! invalid_type_error {
13 ($v:expr, $det:expr) => {{
14 fail!(invalid_type_error_inner!($v, $det))
15 }};
16}
17
18macro_rules! invalid_type_error_inner {
19 ($v:expr, $det:expr) => {
20 RedisError::from((
21 ErrorKind::TypeError,
22 "Response was of incompatible type",
23 format!("{:?} (response was {:?})", $det, $v),
24 ))
25 };
26}
27
28#[derive(PartialEq, Eq, Clone, Debug, Copy)]
31pub enum NumericBehavior {
32 NonNumeric,
34 NumberIsInteger,
36 NumberIsFloat,
38}
39
40#[derive(PartialEq, Eq, Copy, Clone, Debug)]
42#[non_exhaustive]
43pub enum ErrorKind {
44 ResponseError,
46 AuthenticationFailed,
48 TypeError,
50 ExecAbortError,
52 BusyLoadingError,
54 NoScriptError,
56 InvalidClientConfig,
59 Moved,
61 Ask,
63 TryAgain,
65 ClusterDown,
67 CrossSlot,
69 MasterDown,
71 IoError,
75 ClientError,
77 ExtensionError,
80 ReadOnly,
82}
83
84#[derive(PartialEq, Eq, Clone)]
86pub enum Value {
87 Nil,
89 Int(i64),
94 Data(Vec<u8>),
96 Bulk(Vec<Value>),
99 Status(String),
101 Okay,
103}
104
105pub struct MapIter<'a>(std::slice::Iter<'a, Value>);
106
107impl<'a> Iterator for MapIter<'a> {
108 type Item = (&'a Value, &'a Value);
109
110 fn next(&mut self) -> Option<Self::Item> {
111 Some((self.0.next()?, self.0.next()?))
112 }
113
114 fn size_hint(&self) -> (usize, Option<usize>) {
115 let (low, high) = self.0.size_hint();
116 (low / 2, high.map(|h| h / 2))
117 }
118}
119
120impl Value {
128 pub fn looks_like_cursor(&self) -> bool {
133 match *self {
134 Value::Bulk(ref items) => {
135 if items.len() != 2 {
136 return false;
137 }
138 match items[0] {
139 Value::Data(_) => {}
140 _ => {
141 return false;
142 }
143 };
144 match items[1] {
145 Value::Bulk(_) => {}
146 _ => {
147 return false;
148 }
149 }
150 true
151 }
152 _ => false,
153 }
154 }
155
156 pub fn as_sequence(&self) -> Option<&[Value]> {
158 match self {
159 Value::Bulk(items) => Some(&items[..]),
160 Value::Nil => Some(&[]),
161 _ => None,
162 }
163 }
164
165 pub fn as_map_iter(&self) -> Option<MapIter<'_>> {
167 match self {
168 Value::Bulk(items) => Some(MapIter(items.iter())),
169 _ => None,
170 }
171 }
172}
173
174impl fmt::Debug for Value {
175 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
176 match *self {
177 Value::Nil => write!(fmt, "nil"),
178 Value::Int(val) => write!(fmt, "int({:?})", val),
179 Value::Data(ref val) => match from_utf8(val) {
180 Ok(x) => write!(fmt, "string-data('{:?}')", x),
181 Err(_) => write!(fmt, "binary-data({:?})", val),
182 },
183 Value::Bulk(ref values) => {
184 write!(fmt, "bulk(")?;
185 let mut is_first = true;
186 for val in values.iter() {
187 if !is_first {
188 write!(fmt, ", ")?;
189 }
190 write!(fmt, "{:?}", val)?;
191 is_first = false;
192 }
193 write!(fmt, ")")
194 }
195 Value::Okay => write!(fmt, "ok"),
196 Value::Status(ref s) => write!(fmt, "status({:?})", s),
197 }
198 }
199}
200
201pub struct RedisError {
205 repr: ErrorRepr,
206}
207
208#[derive(Debug)]
209enum ErrorRepr {
210 WithDescription(ErrorKind, &'static str),
211 WithDescriptionAndDetail(ErrorKind, &'static str, String),
212 ExtensionError(String, String),
213 IoError(io::Error),
214}
215
216impl PartialEq for RedisError {
217 fn eq(&self, other: &RedisError) -> bool {
218 match (&self.repr, &other.repr) {
219 (&ErrorRepr::WithDescription(kind_a, _), &ErrorRepr::WithDescription(kind_b, _)) => {
220 kind_a == kind_b
221 }
222 (
223 &ErrorRepr::WithDescriptionAndDetail(kind_a, _, _),
224 &ErrorRepr::WithDescriptionAndDetail(kind_b, _, _),
225 ) => kind_a == kind_b,
226 (&ErrorRepr::ExtensionError(ref a, _), &ErrorRepr::ExtensionError(ref b, _)) => {
227 *a == *b
228 }
229 _ => false,
230 }
231 }
232}
233
234impl From<io::Error> for RedisError {
235 fn from(err: io::Error) -> RedisError {
236 RedisError {
237 repr: ErrorRepr::IoError(err),
238 }
239 }
240}
241
242impl From<Utf8Error> for RedisError {
243 fn from(_: Utf8Error) -> RedisError {
244 RedisError {
245 repr: ErrorRepr::WithDescription(ErrorKind::TypeError, "Invalid UTF-8"),
246 }
247 }
248}
249
250#[cfg(feature = "tls")]
251impl From<native_tls::Error> for RedisError {
252 fn from(err: native_tls::Error) -> RedisError {
253 RedisError {
254 repr: ErrorRepr::WithDescriptionAndDetail(
255 ErrorKind::IoError,
256 "TLS error",
257 err.to_string(),
258 ),
259 }
260 }
261}
262
263impl From<FromUtf8Error> for RedisError {
264 fn from(_: FromUtf8Error) -> RedisError {
265 RedisError {
266 repr: ErrorRepr::WithDescription(ErrorKind::TypeError, "Cannot convert from UTF-8"),
267 }
268 }
269}
270
271impl From<(ErrorKind, &'static str)> for RedisError {
272 fn from((kind, desc): (ErrorKind, &'static str)) -> RedisError {
273 RedisError {
274 repr: ErrorRepr::WithDescription(kind, desc),
275 }
276 }
277}
278
279impl From<(ErrorKind, &'static str, String)> for RedisError {
280 fn from((kind, desc, detail): (ErrorKind, &'static str, String)) -> RedisError {
281 RedisError {
282 repr: ErrorRepr::WithDescriptionAndDetail(kind, desc, detail),
283 }
284 }
285}
286
287impl error::Error for RedisError {
288 #[allow(deprecated)]
289 fn description(&self) -> &str {
290 match self.repr {
291 ErrorRepr::WithDescription(_, desc) => desc,
292 ErrorRepr::WithDescriptionAndDetail(_, desc, _) => desc,
293 ErrorRepr::ExtensionError(_, _) => "extension error",
294 ErrorRepr::IoError(ref err) => err.description(),
295 }
296 }
297
298 fn cause(&self) -> Option<&dyn error::Error> {
299 match self.repr {
300 ErrorRepr::IoError(ref err) => Some(err as &dyn error::Error),
301 _ => None,
302 }
303 }
304}
305
306impl fmt::Display for RedisError {
307 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
308 match self.repr {
309 ErrorRepr::WithDescription(_, desc) => desc.fmt(f),
310 ErrorRepr::WithDescriptionAndDetail(_, desc, ref detail) => {
311 desc.fmt(f)?;
312 f.write_str(": ")?;
313 detail.fmt(f)
314 }
315 ErrorRepr::ExtensionError(ref code, ref detail) => {
316 code.fmt(f)?;
317 f.write_str(": ")?;
318 detail.fmt(f)
319 }
320 ErrorRepr::IoError(ref err) => err.fmt(f),
321 }
322 }
323}
324
325impl fmt::Debug for RedisError {
326 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
327 fmt::Display::fmt(self, f)
328 }
329}
330
331impl RedisError {
333 pub fn kind(&self) -> ErrorKind {
335 match self.repr {
336 ErrorRepr::WithDescription(kind, _)
337 | ErrorRepr::WithDescriptionAndDetail(kind, _, _) => kind,
338 ErrorRepr::ExtensionError(_, _) => ErrorKind::ExtensionError,
339 ErrorRepr::IoError(_) => ErrorKind::IoError,
340 }
341 }
342
343 pub fn detail(&self) -> Option<&str> {
345 match self.repr {
346 ErrorRepr::WithDescriptionAndDetail(_, _, ref detail)
347 | ErrorRepr::ExtensionError(_, ref detail) => Some(detail.as_str()),
348 _ => None,
349 }
350 }
351
352 pub fn code(&self) -> Option<&str> {
354 match self.kind() {
355 ErrorKind::ResponseError => Some("ERR"),
356 ErrorKind::ExecAbortError => Some("EXECABORT"),
357 ErrorKind::BusyLoadingError => Some("LOADING"),
358 ErrorKind::NoScriptError => Some("NOSCRIPT"),
359 ErrorKind::Moved => Some("MOVED"),
360 ErrorKind::Ask => Some("ASK"),
361 ErrorKind::TryAgain => Some("TRYAGAIN"),
362 ErrorKind::ClusterDown => Some("CLUSTERDOWN"),
363 ErrorKind::CrossSlot => Some("CROSSSLOT"),
364 ErrorKind::MasterDown => Some("MASTERDOWN"),
365 ErrorKind::ReadOnly => Some("READONLY"),
366 _ => match self.repr {
367 ErrorRepr::ExtensionError(ref code, _) => Some(&code),
368 _ => None,
369 },
370 }
371 }
372
373 pub fn category(&self) -> &str {
375 match self.kind() {
376 ErrorKind::ResponseError => "response error",
377 ErrorKind::AuthenticationFailed => "authentication failed",
378 ErrorKind::TypeError => "type error",
379 ErrorKind::ExecAbortError => "script execution aborted",
380 ErrorKind::BusyLoadingError => "busy loading",
381 ErrorKind::NoScriptError => "no script",
382 ErrorKind::InvalidClientConfig => "invalid client config",
383 ErrorKind::Moved => "key moved",
384 ErrorKind::Ask => "key moved (ask)",
385 ErrorKind::TryAgain => "try again",
386 ErrorKind::ClusterDown => "cluster down",
387 ErrorKind::CrossSlot => "cross-slot",
388 ErrorKind::MasterDown => "master down",
389 ErrorKind::IoError => "I/O error",
390 ErrorKind::ExtensionError => "extension error",
391 ErrorKind::ClientError => "client error",
392 ErrorKind::ReadOnly => "read-only",
393 }
394 }
395
396 pub fn is_io_error(&self) -> bool {
398 self.as_io_error().is_some()
399 }
400
401 pub(crate) fn as_io_error(&self) -> Option<&io::Error> {
402 match &self.repr {
403 ErrorRepr::IoError(e) => Some(e),
404 _ => None,
405 }
406 }
407
408 pub fn is_cluster_error(&self) -> bool {
410 matches!(
411 self.kind(),
412 ErrorKind::Moved | ErrorKind::Ask | ErrorKind::TryAgain | ErrorKind::ClusterDown
413 )
414 }
415
416 pub fn is_connection_refusal(&self) -> bool {
421 match self.repr {
422 ErrorRepr::IoError(ref err) => {
423 #[allow(clippy::match_like_matches_macro)]
424 match err.kind() {
425 io::ErrorKind::ConnectionRefused => true,
426 io::ErrorKind::NotFound => cfg!(unix),
430 _ => false,
431 }
432 }
433 _ => false,
434 }
435 }
436
437 pub fn is_timeout(&self) -> bool {
440 match self.repr {
441 ErrorRepr::IoError(ref err) => matches!(
442 err.kind(),
443 io::ErrorKind::TimedOut | io::ErrorKind::WouldBlock
444 ),
445 _ => false,
446 }
447 }
448
449 pub fn is_connection_dropped(&self) -> bool {
451 match self.repr {
452 ErrorRepr::IoError(ref err) => matches!(
453 err.kind(),
454 io::ErrorKind::BrokenPipe | io::ErrorKind::ConnectionReset
455 ),
456 _ => false,
457 }
458 }
459
460 pub fn redirect_node(&self) -> Option<(&str, u16)> {
464 match self.kind() {
465 ErrorKind::Ask | ErrorKind::Moved => (),
466 _ => return None,
467 }
468 let mut iter = self.detail()?.split_ascii_whitespace();
469 let slot_id: u16 = iter.next()?.parse().ok()?;
470 let addr = iter.next()?;
471 Some((addr, slot_id))
472 }
473
474 #[deprecated(note = "use code() instead")]
480 pub fn extension_error_code(&self) -> Option<&str> {
481 match self.repr {
482 ErrorRepr::ExtensionError(ref code, _) => Some(&code),
483 _ => None,
484 }
485 }
486
487 #[cfg(feature = "connection-manager")] pub(crate) fn clone_mostly(&self, ioerror_description: &'static str) -> Self {
496 let repr = match self.repr {
497 ErrorRepr::WithDescription(kind, desc) => ErrorRepr::WithDescription(kind, desc),
498 ErrorRepr::WithDescriptionAndDetail(kind, desc, ref detail) => {
499 ErrorRepr::WithDescriptionAndDetail(kind, desc, detail.clone())
500 }
501 ErrorRepr::ExtensionError(ref code, ref detail) => {
502 ErrorRepr::ExtensionError(code.clone(), detail.clone())
503 }
504 ErrorRepr::IoError(ref e) => ErrorRepr::IoError(io::Error::new(
505 e.kind(),
506 format!("{}: {}", ioerror_description, e),
507 )),
508 };
509 Self { repr }
510 }
511}
512
513pub fn make_extension_error(code: &str, detail: Option<&str>) -> RedisError {
514 RedisError {
515 repr: ErrorRepr::ExtensionError(
516 code.to_string(),
517 match detail {
518 Some(x) => x.to_string(),
519 None => "Unknown extension error encountered".to_string(),
520 },
521 ),
522 }
523}
524
525pub type RedisResult<T> = Result<T, RedisError>;
527
528#[cfg(feature = "aio")]
530pub type RedisFuture<'a, T> = futures_util::future::BoxFuture<'a, RedisResult<T>>;
531
532#[derive(Debug)]
534pub struct InfoDict {
535 map: HashMap<String, Value>,
536}
537
538impl InfoDict {
555 pub fn new(kvpairs: &str) -> InfoDict {
560 let mut map = HashMap::new();
561 for line in kvpairs.lines() {
562 if line.is_empty() || line.starts_with('#') {
563 continue;
564 }
565 let mut p = line.splitn(2, ':');
566 let k = unwrap_or!(p.next(), continue).to_string();
567 let v = unwrap_or!(p.next(), continue).to_string();
568 map.insert(k, Value::Status(v));
569 }
570 InfoDict { map }
571 }
572
573 pub fn get<T: FromRedisValue>(&self, key: &str) -> Option<T> {
576 match self.find(&key) {
577 Some(ref x) => from_redis_value(*x).ok(),
578 None => None,
579 }
580 }
581
582 pub fn find(&self, key: &&str) -> Option<&Value> {
584 self.map.get(*key)
585 }
586
587 pub fn contains_key(&self, key: &&str) -> bool {
589 self.find(key).is_some()
590 }
591
592 pub fn len(&self) -> usize {
594 self.map.len()
595 }
596
597 pub fn is_empty(&self) -> bool {
599 self.map.is_empty()
600 }
601}
602
603pub trait RedisWrite {
605 fn write_arg(&mut self, arg: &[u8]);
607
608 fn write_arg_fmt(&mut self, arg: impl fmt::Display) {
610 self.write_arg(&arg.to_string().as_bytes())
611 }
612}
613
614impl RedisWrite for Vec<Vec<u8>> {
615 fn write_arg(&mut self, arg: &[u8]) {
616 self.push(arg.to_owned());
617 }
618
619 fn write_arg_fmt(&mut self, arg: impl fmt::Display) {
620 self.push(arg.to_string().into_bytes())
621 }
622}
623
624pub trait ToRedisArgs: Sized {
628 fn to_redis_args(&self) -> Vec<Vec<u8>> {
634 let mut out = Vec::new();
635 self.write_redis_args(&mut out);
636 out
637 }
638
639 fn write_redis_args<W>(&self, out: &mut W)
644 where
645 W: ?Sized + RedisWrite;
646
647 fn describe_numeric_behavior(&self) -> NumericBehavior {
652 NumericBehavior::NonNumeric
653 }
654
655 fn is_single_arg(&self) -> bool {
660 true
661 }
662
663 #[doc(hidden)]
666 fn make_arg_vec<W>(items: &[Self], out: &mut W)
667 where
668 W: ?Sized + RedisWrite,
669 {
670 for item in items.iter() {
671 item.write_redis_args(out);
672 }
673 }
674
675 #[doc(hidden)]
678 fn make_arg_iter_ref<'a, I, W>(items: I, out: &mut W)
679 where
680 W: ?Sized + RedisWrite,
681 I: Iterator<Item = &'a Self>,
682 Self: 'a,
683 {
684 for item in items {
685 item.write_redis_args(out);
686 }
687 }
688
689 #[doc(hidden)]
690 fn is_single_vec_arg(items: &[Self]) -> bool {
691 items.len() == 1 && items[0].is_single_arg()
692 }
693}
694
695macro_rules! itoa_based_to_redis_impl {
696 ($t:ty, $numeric:expr) => {
697 impl ToRedisArgs for $t {
698 fn write_redis_args<W>(&self, out: &mut W)
699 where
700 W: ?Sized + RedisWrite,
701 {
702 let mut buf = ::itoa::Buffer::new();
703 let s = buf.format(*self);
704 out.write_arg(s.as_bytes())
705 }
706
707 fn describe_numeric_behavior(&self) -> NumericBehavior {
708 $numeric
709 }
710 }
711 };
712}
713
714macro_rules! non_zero_itoa_based_to_redis_impl {
715 ($t:ty, $numeric:expr) => {
716 impl ToRedisArgs for $t {
717 fn write_redis_args<W>(&self, out: &mut W)
718 where
719 W: ?Sized + RedisWrite,
720 {
721 let mut buf = ::itoa::Buffer::new();
722 let s = buf.format(self.get());
723 out.write_arg(s.as_bytes())
724 }
725
726 fn describe_numeric_behavior(&self) -> NumericBehavior {
727 $numeric
728 }
729 }
730 };
731}
732
733macro_rules! ryu_based_to_redis_impl {
734 ($t:ty, $numeric:expr) => {
735 impl ToRedisArgs for $t {
736 fn write_redis_args<W>(&self, out: &mut W)
737 where
738 W: ?Sized + RedisWrite,
739 {
740 let mut buf = ::ryu::Buffer::new();
741 let s = buf.format(*self);
742 out.write_arg(s.as_bytes())
743 }
744
745 fn describe_numeric_behavior(&self) -> NumericBehavior {
746 $numeric
747 }
748 }
749 };
750}
751
752impl ToRedisArgs for u8 {
753 fn write_redis_args<W>(&self, out: &mut W)
754 where
755 W: ?Sized + RedisWrite,
756 {
757 let mut buf = ::itoa::Buffer::new();
758 let s = buf.format(*self);
759 out.write_arg(s.as_bytes())
760 }
761
762 fn make_arg_vec<W>(items: &[u8], out: &mut W)
763 where
764 W: ?Sized + RedisWrite,
765 {
766 out.write_arg(items);
767 }
768
769 fn is_single_vec_arg(_items: &[u8]) -> bool {
770 true
771 }
772}
773
774itoa_based_to_redis_impl!(i8, NumericBehavior::NumberIsInteger);
775itoa_based_to_redis_impl!(i16, NumericBehavior::NumberIsInteger);
776itoa_based_to_redis_impl!(u16, NumericBehavior::NumberIsInteger);
777itoa_based_to_redis_impl!(i32, NumericBehavior::NumberIsInteger);
778itoa_based_to_redis_impl!(u32, NumericBehavior::NumberIsInteger);
779itoa_based_to_redis_impl!(i64, NumericBehavior::NumberIsInteger);
780itoa_based_to_redis_impl!(u64, NumericBehavior::NumberIsInteger);
781itoa_based_to_redis_impl!(isize, NumericBehavior::NumberIsInteger);
782itoa_based_to_redis_impl!(usize, NumericBehavior::NumberIsInteger);
783
784non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU8, NumericBehavior::NumberIsInteger);
785non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI8, NumericBehavior::NumberIsInteger);
786non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU16, NumericBehavior::NumberIsInteger);
787non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI16, NumericBehavior::NumberIsInteger);
788non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU32, NumericBehavior::NumberIsInteger);
789non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI32, NumericBehavior::NumberIsInteger);
790non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU64, NumericBehavior::NumberIsInteger);
791non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI64, NumericBehavior::NumberIsInteger);
792non_zero_itoa_based_to_redis_impl!(core::num::NonZeroUsize, NumericBehavior::NumberIsInteger);
793non_zero_itoa_based_to_redis_impl!(core::num::NonZeroIsize, NumericBehavior::NumberIsInteger);
794
795ryu_based_to_redis_impl!(f32, NumericBehavior::NumberIsFloat);
796ryu_based_to_redis_impl!(f64, NumericBehavior::NumberIsFloat);
797
798impl ToRedisArgs for bool {
799 fn write_redis_args<W>(&self, out: &mut W)
800 where
801 W: ?Sized + RedisWrite,
802 {
803 out.write_arg(if *self { b"1" } else { b"0" })
804 }
805}
806
807impl ToRedisArgs for String {
808 fn write_redis_args<W>(&self, out: &mut W)
809 where
810 W: ?Sized + RedisWrite,
811 {
812 out.write_arg(self.as_bytes())
813 }
814}
815
816impl<'a> ToRedisArgs for &'a str {
817 fn write_redis_args<W>(&self, out: &mut W)
818 where
819 W: ?Sized + RedisWrite,
820 {
821 out.write_arg(self.as_bytes())
822 }
823}
824
825impl<T: ToRedisArgs> ToRedisArgs for Vec<T> {
826 fn write_redis_args<W>(&self, out: &mut W)
827 where
828 W: ?Sized + RedisWrite,
829 {
830 ToRedisArgs::make_arg_vec(self, out)
831 }
832
833 fn is_single_arg(&self) -> bool {
834 ToRedisArgs::is_single_vec_arg(&self[..])
835 }
836}
837
838impl<'a, T: ToRedisArgs> ToRedisArgs for &'a [T] {
839 fn write_redis_args<W>(&self, out: &mut W)
840 where
841 W: ?Sized + RedisWrite,
842 {
843 ToRedisArgs::make_arg_vec(*self, out)
844 }
845
846 fn is_single_arg(&self) -> bool {
847 ToRedisArgs::is_single_vec_arg(*self)
848 }
849}
850
851impl<T: ToRedisArgs> ToRedisArgs for Option<T> {
852 fn write_redis_args<W>(&self, out: &mut W)
853 where
854 W: ?Sized + RedisWrite,
855 {
856 if let Some(ref x) = *self {
857 x.write_redis_args(out);
858 }
859 }
860
861 fn describe_numeric_behavior(&self) -> NumericBehavior {
862 match *self {
863 Some(ref x) => x.describe_numeric_behavior(),
864 None => NumericBehavior::NonNumeric,
865 }
866 }
867
868 fn is_single_arg(&self) -> bool {
869 match *self {
870 Some(ref x) => x.is_single_arg(),
871 None => false,
872 }
873 }
874}
875
876impl<T: ToRedisArgs> ToRedisArgs for &T {
877 fn write_redis_args<W>(&self, out: &mut W)
878 where
879 W: ?Sized + RedisWrite,
880 {
881 (*self).write_redis_args(out)
882 }
883}
884
885impl<T: ToRedisArgs + Hash + Eq, S: BuildHasher + Default> ToRedisArgs for HashSet<T, S> {
889 fn write_redis_args<W>(&self, out: &mut W)
890 where
891 W: ?Sized + RedisWrite,
892 {
893 ToRedisArgs::make_arg_iter_ref(self.iter(), out)
894 }
895
896 fn is_single_arg(&self) -> bool {
897 self.len() <= 1
898 }
899}
900
901impl<T: ToRedisArgs + Hash + Eq + Ord> ToRedisArgs for BTreeSet<T> {
905 fn write_redis_args<W>(&self, out: &mut W)
906 where
907 W: ?Sized + RedisWrite,
908 {
909 ToRedisArgs::make_arg_iter_ref(self.iter(), out)
910 }
911
912 fn is_single_arg(&self) -> bool {
913 self.len() <= 1
914 }
915}
916
917impl<T: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs> ToRedisArgs for BTreeMap<T, V> {
922 fn write_redis_args<W>(&self, out: &mut W)
923 where
924 W: ?Sized + RedisWrite,
925 {
926 for (key, value) in self {
927 assert!(key.is_single_arg() && value.is_single_arg());
929
930 key.write_redis_args(out);
931 value.write_redis_args(out);
932 }
933 }
934
935 fn is_single_arg(&self) -> bool {
936 self.len() <= 1
937 }
938}
939
940macro_rules! to_redis_args_for_tuple {
941 () => ();
942 ($($name:ident,)+) => (
943 #[doc(hidden)]
944 impl<$($name: ToRedisArgs),*> ToRedisArgs for ($($name,)*) {
945 #[allow(non_snake_case, unused_variables)]
948 fn write_redis_args<W>(&self, out: &mut W) where W: ?Sized + RedisWrite {
949 let ($(ref $name,)*) = *self;
950 $($name.write_redis_args(out);)*
951 }
952
953 #[allow(non_snake_case, unused_variables)]
954 fn is_single_arg(&self) -> bool {
955 let mut n = 0u32;
956 $(let $name = (); n += 1;)*
957 n == 1
958 }
959 }
960 to_redis_args_for_tuple_peel!($($name,)*);
961 )
962}
963
964macro_rules! to_redis_args_for_tuple_peel {
968 ($name:ident, $($other:ident,)*) => (to_redis_args_for_tuple!($($other,)*);)
969}
970
971to_redis_args_for_tuple! { T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
972
973macro_rules! to_redis_args_for_array {
974 ($($N:expr)+) => {
975 $(
976 impl<'a, T: ToRedisArgs> ToRedisArgs for &'a [T; $N] {
977 fn write_redis_args<W>(&self, out: &mut W) where W: ?Sized + RedisWrite {
978 ToRedisArgs::make_arg_vec(*self, out)
979 }
980
981 fn is_single_arg(&self) -> bool {
982 ToRedisArgs::is_single_vec_arg(*self)
983 }
984 }
985 )+
986 }
987}
988
989to_redis_args_for_array! {
990 0 1 2 3 4 5 6 7 8 9
991 10 11 12 13 14 15 16 17 18 19
992 20 21 22 23 24 25 26 27 28 29
993 30 31 32
994}
995
996pub trait FromRedisValue: Sized {
1008 fn from_redis_value(v: &Value) -> RedisResult<Self>;
1012
1013 fn from_redis_values(items: &[Value]) -> RedisResult<Vec<Self>> {
1017 Ok(items
1018 .iter()
1019 .filter_map(|item| FromRedisValue::from_redis_value(item).ok())
1020 .collect())
1021 }
1022
1023 #[doc(hidden)]
1026 fn from_byte_vec(_vec: &[u8]) -> Option<Vec<Self>> {
1027 None
1028 }
1029}
1030
1031macro_rules! from_redis_value_for_num_internal {
1032 ($t:ty, $v:expr) => {{
1033 let v = $v;
1034 match *v {
1035 Value::Int(val) => Ok(val as $t),
1036 Value::Status(ref s) => match s.parse::<$t>() {
1037 Ok(rv) => Ok(rv),
1038 Err(_) => invalid_type_error!(v, "Could not convert from string."),
1039 },
1040 Value::Data(ref bytes) => match from_utf8(bytes)?.parse::<$t>() {
1041 Ok(rv) => Ok(rv),
1042 Err(_) => invalid_type_error!(v, "Could not convert from string."),
1043 },
1044 _ => invalid_type_error!(v, "Response type not convertible to numeric."),
1045 }
1046 }};
1047}
1048
1049macro_rules! from_redis_value_for_num {
1050 ($t:ty) => {
1051 impl FromRedisValue for $t {
1052 fn from_redis_value(v: &Value) -> RedisResult<$t> {
1053 from_redis_value_for_num_internal!($t, v)
1054 }
1055 }
1056 };
1057}
1058
1059impl FromRedisValue for u8 {
1060 fn from_redis_value(v: &Value) -> RedisResult<u8> {
1061 from_redis_value_for_num_internal!(u8, v)
1062 }
1063
1064 fn from_byte_vec(vec: &[u8]) -> Option<Vec<u8>> {
1065 Some(vec.to_vec())
1066 }
1067}
1068
1069from_redis_value_for_num!(i8);
1070from_redis_value_for_num!(i16);
1071from_redis_value_for_num!(u16);
1072from_redis_value_for_num!(i32);
1073from_redis_value_for_num!(u32);
1074from_redis_value_for_num!(i64);
1075from_redis_value_for_num!(u64);
1076from_redis_value_for_num!(i128);
1077from_redis_value_for_num!(u128);
1078from_redis_value_for_num!(f32);
1079from_redis_value_for_num!(f64);
1080from_redis_value_for_num!(isize);
1081from_redis_value_for_num!(usize);
1082
1083impl FromRedisValue for bool {
1084 fn from_redis_value(v: &Value) -> RedisResult<bool> {
1085 match *v {
1086 Value::Nil => Ok(false),
1087 Value::Int(val) => Ok(val != 0),
1088 Value::Status(ref s) => {
1089 if &s[..] == "1" {
1090 Ok(true)
1091 } else if &s[..] == "0" {
1092 Ok(false)
1093 } else {
1094 invalid_type_error!(v, "Response status not valid boolean");
1095 }
1096 }
1097 Value::Data(ref bytes) => {
1098 if bytes == b"1" {
1099 Ok(true)
1100 } else if bytes == b"0" {
1101 Ok(false)
1102 } else {
1103 invalid_type_error!(v, "Response type not bool compatible.");
1104 }
1105 }
1106 Value::Okay => Ok(true),
1107 _ => invalid_type_error!(v, "Response type not bool compatible."),
1108 }
1109 }
1110}
1111
1112impl FromRedisValue for String {
1113 fn from_redis_value(v: &Value) -> RedisResult<String> {
1114 match *v {
1115 Value::Data(ref bytes) => Ok(from_utf8(bytes)?.to_string()),
1116 Value::Okay => Ok("OK".to_string()),
1117 Value::Status(ref val) => Ok(val.to_string()),
1118 _ => invalid_type_error!(v, "Response type not string compatible."),
1119 }
1120 }
1121}
1122
1123impl<T: FromRedisValue> FromRedisValue for Vec<T> {
1124 fn from_redis_value(v: &Value) -> RedisResult<Vec<T>> {
1125 match *v {
1126 Value::Data(ref bytes) => match FromRedisValue::from_byte_vec(bytes) {
1129 Some(x) => Ok(x),
1130 None => invalid_type_error!(v, "Response type not vector compatible."),
1131 },
1132 Value::Bulk(ref items) => FromRedisValue::from_redis_values(items),
1133 Value::Nil => Ok(vec![]),
1134 _ => invalid_type_error!(v, "Response type not vector compatible."),
1135 }
1136 }
1137}
1138
1139impl<K: FromRedisValue + Eq + Hash, V: FromRedisValue, S: BuildHasher + Default> FromRedisValue
1140 for HashMap<K, V, S>
1141{
1142 fn from_redis_value(v: &Value) -> RedisResult<HashMap<K, V, S>> {
1143 v.as_map_iter()
1144 .ok_or_else(|| invalid_type_error_inner!(v, "Response type not hashmap compatible"))?
1145 .map(|(k, v)| Ok((from_redis_value(k)?, from_redis_value(v)?)))
1146 .collect()
1147 }
1148}
1149
1150impl<K: FromRedisValue + Eq + Hash, V: FromRedisValue> FromRedisValue for BTreeMap<K, V>
1151where
1152 K: Ord,
1153{
1154 fn from_redis_value(v: &Value) -> RedisResult<BTreeMap<K, V>> {
1155 v.as_map_iter()
1156 .ok_or_else(|| invalid_type_error_inner!(v, "Response type not btreemap compatible"))?
1157 .map(|(k, v)| Ok((from_redis_value(k)?, from_redis_value(v)?)))
1158 .collect()
1159 }
1160}
1161
1162impl<T: FromRedisValue + Eq + Hash, S: BuildHasher + Default> FromRedisValue for HashSet<T, S> {
1163 fn from_redis_value(v: &Value) -> RedisResult<HashSet<T, S>> {
1164 let items = v
1165 .as_sequence()
1166 .ok_or_else(|| invalid_type_error_inner!(v, "Response type not hashset compatible"))?;
1167 items.iter().map(|item| from_redis_value(item)).collect()
1168 }
1169}
1170
1171impl<T: FromRedisValue + Eq + Hash> FromRedisValue for BTreeSet<T>
1172where
1173 T: Ord,
1174{
1175 fn from_redis_value(v: &Value) -> RedisResult<BTreeSet<T>> {
1176 let items = v
1177 .as_sequence()
1178 .ok_or_else(|| invalid_type_error_inner!(v, "Response type not btreeset compatible"))?;
1179 items.iter().map(|item| from_redis_value(item)).collect()
1180 }
1181}
1182
1183impl FromRedisValue for Value {
1184 fn from_redis_value(v: &Value) -> RedisResult<Value> {
1185 Ok(v.clone())
1186 }
1187}
1188
1189impl FromRedisValue for () {
1190 fn from_redis_value(_v: &Value) -> RedisResult<()> {
1191 Ok(())
1192 }
1193}
1194
1195macro_rules! from_redis_value_for_tuple {
1196 () => ();
1197 ($($name:ident,)+) => (
1198 #[doc(hidden)]
1199 impl<$($name: FromRedisValue),*> FromRedisValue for ($($name,)*) {
1200 #[allow(non_snake_case, unused_variables)]
1203 fn from_redis_value(v: &Value) -> RedisResult<($($name,)*)> {
1204 match *v {
1205 Value::Bulk(ref items) => {
1206 let mut n = 0;
1208 $(let $name = (); n += 1;)*
1209 if items.len() != n {
1210 invalid_type_error!(v, "Bulk response of wrong dimension")
1211 }
1212
1213 let mut i = 0;
1216 Ok(($({let $name = (); from_redis_value(
1217 &items[{ i += 1; i - 1 }])?},)*))
1218 }
1219 _ => invalid_type_error!(v, "Not a bulk response")
1220 }
1221 }
1222
1223 #[allow(non_snake_case, unused_variables)]
1224 fn from_redis_values(items: &[Value]) -> RedisResult<Vec<($($name,)*)>> {
1225 let mut n = 0;
1227 $(let $name = (); n += 1;)*
1228 if items.len() % n != 0 {
1229 invalid_type_error!(items, "Bulk response of wrong dimension")
1230 }
1231
1232 let mut rv = vec![];
1235 if items.len() == 0 {
1236 return Ok(rv)
1237 }
1238 for chunk in items.chunks_exact(n) {
1239 match chunk {
1240 [$($name),*] => rv.push(($(from_redis_value($name)?),*),),
1241 _ => unreachable!(),
1242 }
1243 }
1244 Ok(rv)
1245 }
1246 }
1247 from_redis_value_for_tuple_peel!($($name,)*);
1248 )
1249}
1250
1251macro_rules! from_redis_value_for_tuple_peel {
1255 ($name:ident, $($other:ident,)*) => (from_redis_value_for_tuple!($($other,)*);)
1256}
1257
1258from_redis_value_for_tuple! { T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
1259
1260impl FromRedisValue for InfoDict {
1261 fn from_redis_value(v: &Value) -> RedisResult<InfoDict> {
1262 let s: String = from_redis_value(v)?;
1263 Ok(InfoDict::new(&s))
1264 }
1265}
1266
1267impl<T: FromRedisValue> FromRedisValue for Option<T> {
1268 fn from_redis_value(v: &Value) -> RedisResult<Option<T>> {
1269 if let Value::Nil = *v {
1270 return Ok(None);
1271 }
1272 Ok(Some(from_redis_value(v)?))
1273 }
1274}
1275
1276#[cfg(feature = "bytes")]
1277impl FromRedisValue for bytes::Bytes {
1278 fn from_redis_value(v: &Value) -> RedisResult<Self> {
1279 match v {
1280 Value::Data(bytes_vec) => Ok(bytes::Bytes::copy_from_slice(bytes_vec.as_ref())),
1281 _ => invalid_type_error!(v, "Not binary data"),
1282 }
1283 }
1284}
1285
1286pub fn from_redis_value<T: FromRedisValue>(v: &Value) -> RedisResult<T> {
1289 FromRedisValue::from_redis_value(v)
1290}