1#[cfg(feature = "ahash")]
2pub(crate) use ahash::{AHashMap as HashMap, AHashSet as HashSet};
3use num_bigint::BigInt;
4use std::borrow::Cow;
5#[cfg(not(feature = "ahash"))]
6pub(crate) use std::collections::{HashMap, HashSet};
7use std::default::Default;
8use std::error;
9use std::ffi::{CString, NulError};
10use std::fmt;
11use std::hash::{BuildHasher, Hash};
12use std::io;
13use std::ops::Deref;
14use std::str::{from_utf8, Utf8Error};
15use std::string::FromUtf8Error;
16
17macro_rules! invalid_type_error {
18 ($v:expr, $det:expr) => {{
19 fail!(invalid_type_error_inner!($v, $det))
20 }};
21}
22
23macro_rules! invalid_type_error_inner {
24 ($v:expr, $det:expr) => {
25 RedisError::from((
26 ErrorKind::TypeError,
27 "Response was of incompatible type",
28 format!("{:?} (response was {:?})", $det, $v),
29 ))
30 };
31}
32
33pub enum Expiry {
35 EX(u64),
37 PX(u64),
39 EXAT(u64),
41 PXAT(u64),
43 PERSIST,
45}
46
47#[derive(Clone, Copy)]
49pub enum SetExpiry {
50 EX(u64),
52 PX(u64),
54 EXAT(u64),
56 PXAT(u64),
58 KEEPTTL,
60}
61
62#[derive(Clone, Copy)]
64pub enum ExistenceCheck {
65 NX,
67 XX,
69}
70
71#[derive(Clone, Copy)]
73pub enum FieldExistenceCheck {
74 FNX,
76 FXX,
78}
79
80#[derive(PartialEq, Eq, Clone, Debug, Copy)]
83pub enum NumericBehavior {
84 NonNumeric,
86 NumberIsInteger,
88 NumberIsFloat,
90}
91
92#[derive(PartialEq, Eq, Copy, Clone, Debug)]
94#[non_exhaustive]
95pub enum ErrorKind {
96 ResponseError,
98 ParseError,
100 AuthenticationFailed,
102 TypeError,
104 ExecAbortError,
106 BusyLoadingError,
108 NoScriptError,
110 InvalidClientConfig,
113 Moved,
115 Ask,
117 TryAgain,
119 ClusterDown,
121 CrossSlot,
123 MasterDown,
125 IoError,
129 ClientError,
131 ExtensionError,
134 ReadOnly,
136 MasterNameNotFoundBySentinel,
138 NoValidReplicasFoundBySentinel,
140 EmptySentinelList,
142 NotBusy,
144 ClusterConnectionNotFound,
146 NoSub,
148
149 #[cfg(feature = "json")]
150 Serialize,
152
153 RESP3NotSupported,
156}
157
158#[derive(PartialEq, Debug, Clone, Copy)]
159pub enum ServerErrorKind {
160 ResponseError,
161 ExecAbortError,
162 BusyLoadingError,
163 NoScriptError,
164 Moved,
165 Ask,
166 TryAgain,
167 ClusterDown,
168 CrossSlot,
169 MasterDown,
170 ReadOnly,
171 NotBusy,
172 NoSub,
173}
174
175#[derive(PartialEq, Debug, Clone)]
176pub enum ServerError {
177 ExtensionError {
178 code: String,
179 detail: Option<String>,
180 },
181 KnownError {
182 kind: ServerErrorKind,
183 detail: Option<String>,
184 },
185}
186
187impl ServerError {
188 pub fn kind(&self) -> Option<ServerErrorKind> {
189 match self {
190 ServerError::ExtensionError { .. } => None,
191 ServerError::KnownError { kind, .. } => Some(*kind),
192 }
193 }
194
195 pub fn code(&self) -> &str {
196 match self {
197 ServerError::ExtensionError { code, .. } => code,
198 ServerError::KnownError { kind, .. } => match kind {
199 ServerErrorKind::ResponseError => "ERR",
200 ServerErrorKind::ExecAbortError => "EXECABORT",
201 ServerErrorKind::BusyLoadingError => "LOADING",
202 ServerErrorKind::NoScriptError => "NOSCRIPT",
203 ServerErrorKind::Moved => "MOVED",
204 ServerErrorKind::Ask => "ASK",
205 ServerErrorKind::TryAgain => "TRYAGAIN",
206 ServerErrorKind::ClusterDown => "CLUSTERDOWN",
207 ServerErrorKind::CrossSlot => "CROSSSLOT",
208 ServerErrorKind::MasterDown => "MASTERDOWN",
209 ServerErrorKind::ReadOnly => "READONLY",
210 ServerErrorKind::NotBusy => "NOTBUSY",
211 ServerErrorKind::NoSub => "NOSUB",
212 },
213 }
214 }
215
216 pub fn details(&self) -> Option<&str> {
217 match self {
218 ServerError::ExtensionError { detail, .. } => detail.as_ref().map(|str| str.as_str()),
219 ServerError::KnownError { detail, .. } => detail.as_ref().map(|str| str.as_str()),
220 }
221 }
222}
223
224impl From<ServerError> for RedisError {
225 fn from(value: ServerError) -> Self {
226 match value {
228 ServerError::ExtensionError { code, detail } => make_extension_error(code, detail),
229 ServerError::KnownError { kind, detail } => {
230 let desc = "An error was signalled by the server";
231 let kind = match kind {
232 ServerErrorKind::ResponseError => ErrorKind::ResponseError,
233 ServerErrorKind::ExecAbortError => ErrorKind::ExecAbortError,
234 ServerErrorKind::BusyLoadingError => ErrorKind::BusyLoadingError,
235 ServerErrorKind::NoScriptError => ErrorKind::NoScriptError,
236 ServerErrorKind::Moved => ErrorKind::Moved,
237 ServerErrorKind::Ask => ErrorKind::Ask,
238 ServerErrorKind::TryAgain => ErrorKind::TryAgain,
239 ServerErrorKind::ClusterDown => ErrorKind::ClusterDown,
240 ServerErrorKind::CrossSlot => ErrorKind::CrossSlot,
241 ServerErrorKind::MasterDown => ErrorKind::MasterDown,
242 ServerErrorKind::ReadOnly => ErrorKind::ReadOnly,
243 ServerErrorKind::NotBusy => ErrorKind::NotBusy,
244 ServerErrorKind::NoSub => ErrorKind::NoSub,
245 };
246 match detail {
247 Some(detail) => RedisError::from((kind, desc, detail)),
248 None => RedisError::from((kind, desc)),
249 }
250 }
251 }
252 }
253}
254
255#[derive(PartialEq, Clone)]
257pub enum Value {
258 Nil,
260 Int(i64),
265 BulkString(Vec<u8>),
267 Array(Vec<Value>),
270 SimpleString(String),
272 Okay,
274 Map(Vec<(Value, Value)>),
276 Attribute {
278 data: Box<Value>,
280 attributes: Vec<(Value, Value)>,
282 },
283 Set(Vec<Value>),
285 Double(f64),
287 Boolean(bool),
289 VerbatimString {
291 format: VerbatimFormat,
293 text: String,
295 },
296 BigNumber(BigInt),
298 Push {
300 kind: PushKind,
302 data: Vec<Value>,
304 },
305 ServerError(ServerError),
307}
308
309#[derive(PartialEq, Clone, Debug)]
311pub enum VerbatimFormat {
312 Unknown(String),
314 Markdown,
316 Text,
318}
319
320#[derive(PartialEq, Clone, Debug)]
322pub enum PushKind {
323 Disconnection,
325 Other(String),
327 Invalidate,
329 Message,
331 PMessage,
333 SMessage,
335 Unsubscribe,
337 PUnsubscribe,
339 SUnsubscribe,
341 Subscribe,
343 PSubscribe,
345 SSubscribe,
347}
348
349impl PushKind {
350 #[cfg(feature = "aio")]
351 pub(crate) fn has_reply(&self) -> bool {
352 matches!(
353 self,
354 &PushKind::Unsubscribe
355 | &PushKind::PUnsubscribe
356 | &PushKind::SUnsubscribe
357 | &PushKind::Subscribe
358 | &PushKind::PSubscribe
359 | &PushKind::SSubscribe
360 )
361 }
362}
363
364impl fmt::Display for VerbatimFormat {
365 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366 match self {
367 VerbatimFormat::Markdown => write!(f, "mkd"),
368 VerbatimFormat::Unknown(val) => write!(f, "{val}"),
369 VerbatimFormat::Text => write!(f, "txt"),
370 }
371 }
372}
373
374impl fmt::Display for PushKind {
375 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
376 match self {
377 PushKind::Other(kind) => write!(f, "{kind}"),
378 PushKind::Invalidate => write!(f, "invalidate"),
379 PushKind::Message => write!(f, "message"),
380 PushKind::PMessage => write!(f, "pmessage"),
381 PushKind::SMessage => write!(f, "smessage"),
382 PushKind::Unsubscribe => write!(f, "unsubscribe"),
383 PushKind::PUnsubscribe => write!(f, "punsubscribe"),
384 PushKind::SUnsubscribe => write!(f, "sunsubscribe"),
385 PushKind::Subscribe => write!(f, "subscribe"),
386 PushKind::PSubscribe => write!(f, "psubscribe"),
387 PushKind::SSubscribe => write!(f, "ssubscribe"),
388 PushKind::Disconnection => write!(f, "disconnection"),
389 }
390 }
391}
392
393pub enum MapIter<'a> {
394 Array(std::slice::Iter<'a, Value>),
395 Map(std::slice::Iter<'a, (Value, Value)>),
396}
397
398impl<'a> Iterator for MapIter<'a> {
399 type Item = (&'a Value, &'a Value);
400
401 fn next(&mut self) -> Option<Self::Item> {
402 match self {
403 MapIter::Array(iter) => Some((iter.next()?, iter.next()?)),
404 MapIter::Map(iter) => {
405 let (k, v) = iter.next()?;
406 Some((k, v))
407 }
408 }
409 }
410
411 fn size_hint(&self) -> (usize, Option<usize>) {
412 match self {
413 MapIter::Array(iter) => iter.size_hint(),
414 MapIter::Map(iter) => iter.size_hint(),
415 }
416 }
417}
418
419pub enum OwnedMapIter {
420 Array(std::vec::IntoIter<Value>),
421 Map(std::vec::IntoIter<(Value, Value)>),
422}
423
424impl Iterator for OwnedMapIter {
425 type Item = (Value, Value);
426
427 fn next(&mut self) -> Option<Self::Item> {
428 match self {
429 OwnedMapIter::Array(iter) => Some((iter.next()?, iter.next()?)),
430 OwnedMapIter::Map(iter) => iter.next(),
431 }
432 }
433
434 fn size_hint(&self) -> (usize, Option<usize>) {
435 match self {
436 OwnedMapIter::Array(iter) => {
437 let (low, high) = iter.size_hint();
438 (low / 2, high.map(|h| h / 2))
439 }
440 OwnedMapIter::Map(iter) => iter.size_hint(),
441 }
442 }
443}
444
445impl Value {
453 pub fn looks_like_cursor(&self) -> bool {
458 match *self {
459 Value::Array(ref items) => {
460 if items.len() != 2 {
461 return false;
462 }
463 matches!(items[0], Value::BulkString(_)) && matches!(items[1], Value::Array(_))
464 }
465 _ => false,
466 }
467 }
468
469 pub fn as_sequence(&self) -> Option<&[Value]> {
471 match self {
472 Value::Array(items) => Some(&items[..]),
473 Value::Set(items) => Some(&items[..]),
474 Value::Nil => Some(&[]),
475 _ => None,
476 }
477 }
478
479 pub fn into_sequence(self) -> Result<Vec<Value>, Value> {
482 match self {
483 Value::Array(items) => Ok(items),
484 Value::Set(items) => Ok(items),
485 Value::Nil => Ok(vec![]),
486 _ => Err(self),
487 }
488 }
489
490 pub fn as_map_iter(&self) -> Option<MapIter<'_>> {
492 match self {
493 Value::Array(items) => {
494 if items.len() % 2 == 0 {
495 Some(MapIter::Array(items.iter()))
496 } else {
497 None
498 }
499 }
500 Value::Map(items) => Some(MapIter::Map(items.iter())),
501 _ => None,
502 }
503 }
504
505 pub fn into_map_iter(self) -> Result<OwnedMapIter, Value> {
508 match self {
509 Value::Array(items) => {
510 if items.len() % 2 == 0 {
511 Ok(OwnedMapIter::Array(items.into_iter()))
512 } else {
513 Err(Value::Array(items))
514 }
515 }
516 Value::Map(items) => Ok(OwnedMapIter::Map(items.into_iter())),
517 _ => Err(self),
518 }
519 }
520
521 pub fn extract_error(self) -> RedisResult<Self> {
523 match self {
524 Self::Array(val) => Ok(Self::Array(Self::extract_error_vec(val)?)),
525 Self::Map(map) => Ok(Self::Map(Self::extract_error_map(map)?)),
526 Self::Attribute { data, attributes } => {
527 let data = Box::new((*data).extract_error()?);
528 let attributes = Self::extract_error_map(attributes)?;
529 Ok(Value::Attribute { data, attributes })
530 }
531 Self::Set(set) => Ok(Self::Set(Self::extract_error_vec(set)?)),
532 Self::Push { kind, data } => Ok(Self::Push {
533 kind,
534 data: Self::extract_error_vec(data)?,
535 }),
536 Value::ServerError(err) => Err(err.into()),
537 _ => Ok(self),
538 }
539 }
540
541 pub(crate) fn extract_error_vec(vec: Vec<Self>) -> RedisResult<Vec<Self>> {
542 vec.into_iter()
543 .map(Self::extract_error)
544 .collect::<RedisResult<Vec<_>>>()
545 }
546
547 pub(crate) fn extract_error_map(map: Vec<(Self, Self)>) -> RedisResult<Vec<(Self, Self)>> {
548 let mut vec = Vec::with_capacity(map.len());
549 for (key, value) in map.into_iter() {
550 vec.push((key.extract_error()?, value.extract_error()?));
551 }
552 Ok(vec)
553 }
554
555 fn is_collection_of_len(&self, len: usize) -> bool {
556 match self {
557 Value::Array(values) => values.len() == len,
558 Value::Map(items) => items.len() * 2 == len,
559 Value::Set(values) => values.len() == len,
560 _ => false,
561 }
562 }
563}
564
565impl fmt::Debug for Value {
566 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
567 match *self {
568 Value::Nil => write!(fmt, "nil"),
569 Value::Int(val) => write!(fmt, "int({val:?})"),
570 Value::BulkString(ref val) => match from_utf8(val) {
571 Ok(x) => write!(fmt, "bulk-string('{x:?}')"),
572 Err(_) => write!(fmt, "binary-data({val:?})"),
573 },
574 Value::Array(ref values) => write!(fmt, "array({values:?})"),
575 Value::Push { ref kind, ref data } => write!(fmt, "push({kind:?}, {data:?})"),
576 Value::Okay => write!(fmt, "ok"),
577 Value::SimpleString(ref s) => write!(fmt, "simple-string({s:?})"),
578 Value::Map(ref values) => write!(fmt, "map({values:?})"),
579 Value::Attribute {
580 ref data,
581 attributes: _,
582 } => write!(fmt, "attribute({data:?})"),
583 Value::Set(ref values) => write!(fmt, "set({values:?})"),
584 Value::Double(ref d) => write!(fmt, "double({d:?})"),
585 Value::Boolean(ref b) => write!(fmt, "boolean({b:?})"),
586 Value::VerbatimString {
587 ref format,
588 ref text,
589 } => {
590 write!(fmt, "verbatim-string({format:?},{text:?})")
591 }
592 Value::BigNumber(ref m) => write!(fmt, "big-number({m:?})"),
593 Value::ServerError(ref err) => match err.details() {
594 Some(details) => write!(fmt, "Server error: `{}: {details}`", err.code()),
595 None => write!(fmt, "Server error: `{}`", err.code()),
596 },
597 }
598 }
599}
600
601pub struct RedisError {
606 repr: ErrorRepr,
607}
608
609#[cfg(feature = "json")]
610impl From<serde_json::Error> for RedisError {
611 fn from(serde_err: serde_json::Error) -> RedisError {
612 RedisError::from((
613 ErrorKind::Serialize,
614 "Serialization Error",
615 format!("{serde_err}"),
616 ))
617 }
618}
619
620#[derive(Debug)]
621enum ErrorRepr {
622 WithDescription(ErrorKind, &'static str),
623 WithDescriptionAndDetail(ErrorKind, &'static str, String),
624 ExtensionError(String, String),
625 IoError(io::Error),
626}
627
628impl PartialEq for RedisError {
629 fn eq(&self, other: &RedisError) -> bool {
630 match (&self.repr, &other.repr) {
631 (&ErrorRepr::WithDescription(kind_a, _), &ErrorRepr::WithDescription(kind_b, _)) => {
632 kind_a == kind_b
633 }
634 (
635 &ErrorRepr::WithDescriptionAndDetail(kind_a, _, _),
636 &ErrorRepr::WithDescriptionAndDetail(kind_b, _, _),
637 ) => kind_a == kind_b,
638 (ErrorRepr::ExtensionError(a, _), ErrorRepr::ExtensionError(b, _)) => *a == *b,
639 _ => false,
640 }
641 }
642}
643
644impl From<io::Error> for RedisError {
645 fn from(err: io::Error) -> RedisError {
646 RedisError {
647 repr: ErrorRepr::IoError(err),
648 }
649 }
650}
651
652impl From<Utf8Error> for RedisError {
653 fn from(_: Utf8Error) -> RedisError {
654 RedisError {
655 repr: ErrorRepr::WithDescription(ErrorKind::TypeError, "Invalid UTF-8"),
656 }
657 }
658}
659
660impl From<NulError> for RedisError {
661 fn from(err: NulError) -> RedisError {
662 RedisError {
663 repr: ErrorRepr::WithDescriptionAndDetail(
664 ErrorKind::TypeError,
665 "Value contains interior nul terminator",
666 err.to_string(),
667 ),
668 }
669 }
670}
671
672#[cfg(feature = "tls-native-tls")]
673impl From<native_tls::Error> for RedisError {
674 fn from(err: native_tls::Error) -> RedisError {
675 RedisError {
676 repr: ErrorRepr::WithDescriptionAndDetail(
677 ErrorKind::IoError,
678 "TLS error",
679 err.to_string(),
680 ),
681 }
682 }
683}
684
685#[cfg(feature = "tls-rustls")]
686impl From<rustls::Error> for RedisError {
687 fn from(err: rustls::Error) -> RedisError {
688 RedisError {
689 repr: ErrorRepr::WithDescriptionAndDetail(
690 ErrorKind::IoError,
691 "TLS error",
692 err.to_string(),
693 ),
694 }
695 }
696}
697
698#[cfg(feature = "tls-rustls")]
699impl From<rustls::pki_types::InvalidDnsNameError> for RedisError {
700 fn from(err: rustls::pki_types::InvalidDnsNameError) -> RedisError {
701 RedisError {
702 repr: ErrorRepr::WithDescriptionAndDetail(
703 ErrorKind::IoError,
704 "TLS Error",
705 err.to_string(),
706 ),
707 }
708 }
709}
710
711#[cfg(feature = "tls-rustls")]
712impl From<rustls_native_certs::Error> for RedisError {
713 fn from(err: rustls_native_certs::Error) -> RedisError {
714 RedisError {
715 repr: ErrorRepr::WithDescriptionAndDetail(
716 ErrorKind::IoError,
717 "Fetch certs Error",
718 err.to_string(),
719 ),
720 }
721 }
722}
723
724#[cfg(feature = "uuid")]
725impl From<uuid::Error> for RedisError {
726 fn from(err: uuid::Error) -> RedisError {
727 RedisError {
728 repr: ErrorRepr::WithDescriptionAndDetail(
729 ErrorKind::TypeError,
730 "Value is not a valid UUID",
731 err.to_string(),
732 ),
733 }
734 }
735}
736
737impl From<FromUtf8Error> for RedisError {
738 fn from(_: FromUtf8Error) -> RedisError {
739 RedisError {
740 repr: ErrorRepr::WithDescription(ErrorKind::TypeError, "Cannot convert from UTF-8"),
741 }
742 }
743}
744
745impl From<(ErrorKind, &'static str)> for RedisError {
746 fn from((kind, desc): (ErrorKind, &'static str)) -> RedisError {
747 RedisError {
748 repr: ErrorRepr::WithDescription(kind, desc),
749 }
750 }
751}
752
753impl From<(ErrorKind, &'static str, String)> for RedisError {
754 fn from((kind, desc, detail): (ErrorKind, &'static str, String)) -> RedisError {
755 RedisError {
756 repr: ErrorRepr::WithDescriptionAndDetail(kind, desc, detail),
757 }
758 }
759}
760
761impl error::Error for RedisError {
762 #[allow(deprecated)]
763 fn description(&self) -> &str {
764 match self.repr {
765 ErrorRepr::WithDescription(_, desc) => desc,
766 ErrorRepr::WithDescriptionAndDetail(_, desc, _) => desc,
767 ErrorRepr::ExtensionError(_, _) => "extension error",
768 ErrorRepr::IoError(ref err) => err.description(),
769 }
770 }
771
772 fn cause(&self) -> Option<&dyn error::Error> {
773 match self.repr {
774 ErrorRepr::IoError(ref err) => Some(err as &dyn error::Error),
775 _ => None,
776 }
777 }
778
779 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
780 match self.repr {
781 ErrorRepr::IoError(ref err) => Some(err),
782 _ => None,
783 }
784 }
785}
786
787impl fmt::Display for RedisError {
788 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
789 match self.repr {
790 ErrorRepr::WithDescription(kind, desc) => {
791 desc.fmt(f)?;
792 f.write_str("- ")?;
793 fmt::Debug::fmt(&kind, f)
794 }
795 ErrorRepr::WithDescriptionAndDetail(kind, desc, ref detail) => {
796 desc.fmt(f)?;
797 f.write_str(" - ")?;
798 fmt::Debug::fmt(&kind, f)?;
799 f.write_str(": ")?;
800 detail.fmt(f)
801 }
802 ErrorRepr::ExtensionError(ref code, ref detail) => {
803 code.fmt(f)?;
804 f.write_str(": ")?;
805 detail.fmt(f)
806 }
807 ErrorRepr::IoError(ref err) => err.fmt(f),
808 }
809 }
810}
811
812impl fmt::Debug for RedisError {
813 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
814 fmt::Display::fmt(self, f)
815 }
816}
817
818#[non_exhaustive]
820pub enum RetryMethod {
821 Reconnect,
823 NoRetry,
825 RetryImmediately,
827 WaitAndRetry,
829 AskRedirect,
831 MovedRedirect,
833 ReconnectFromInitialConnections,
835}
836
837impl RedisError {
839 pub fn kind(&self) -> ErrorKind {
841 match self.repr {
842 ErrorRepr::WithDescription(kind, _)
843 | ErrorRepr::WithDescriptionAndDetail(kind, _, _) => kind,
844 ErrorRepr::ExtensionError(_, _) => ErrorKind::ExtensionError,
845 ErrorRepr::IoError(_) => ErrorKind::IoError,
846 }
847 }
848
849 pub fn detail(&self) -> Option<&str> {
851 match self.repr {
852 ErrorRepr::WithDescriptionAndDetail(_, _, ref detail)
853 | ErrorRepr::ExtensionError(_, ref detail) => Some(detail.as_str()),
854 _ => None,
855 }
856 }
857
858 pub fn code(&self) -> Option<&str> {
860 match self.kind() {
861 ErrorKind::ResponseError => Some("ERR"),
862 ErrorKind::ExecAbortError => Some("EXECABORT"),
863 ErrorKind::BusyLoadingError => Some("LOADING"),
864 ErrorKind::NoScriptError => Some("NOSCRIPT"),
865 ErrorKind::Moved => Some("MOVED"),
866 ErrorKind::Ask => Some("ASK"),
867 ErrorKind::TryAgain => Some("TRYAGAIN"),
868 ErrorKind::ClusterDown => Some("CLUSTERDOWN"),
869 ErrorKind::CrossSlot => Some("CROSSSLOT"),
870 ErrorKind::MasterDown => Some("MASTERDOWN"),
871 ErrorKind::ReadOnly => Some("READONLY"),
872 ErrorKind::NotBusy => Some("NOTBUSY"),
873 _ => match self.repr {
874 ErrorRepr::ExtensionError(ref code, _) => Some(code),
875 _ => None,
876 },
877 }
878 }
879
880 pub fn category(&self) -> &str {
882 match self.kind() {
883 ErrorKind::ResponseError => "response error",
884 ErrorKind::AuthenticationFailed => "authentication failed",
885 ErrorKind::TypeError => "type error",
886 ErrorKind::ExecAbortError => "script execution aborted",
887 ErrorKind::BusyLoadingError => "busy loading",
888 ErrorKind::NoScriptError => "no script",
889 ErrorKind::InvalidClientConfig => "invalid client config",
890 ErrorKind::Moved => "key moved",
891 ErrorKind::Ask => "key moved (ask)",
892 ErrorKind::TryAgain => "try again",
893 ErrorKind::ClusterDown => "cluster down",
894 ErrorKind::CrossSlot => "cross-slot",
895 ErrorKind::MasterDown => "master down",
896 ErrorKind::IoError => "I/O error",
897 ErrorKind::ExtensionError => "extension error",
898 ErrorKind::ClientError => "client error",
899 ErrorKind::ReadOnly => "read-only",
900 ErrorKind::MasterNameNotFoundBySentinel => "master name not found by sentinel",
901 ErrorKind::NoValidReplicasFoundBySentinel => "no valid replicas found by sentinel",
902 ErrorKind::EmptySentinelList => "empty sentinel list",
903 ErrorKind::NotBusy => "not busy",
904 ErrorKind::ClusterConnectionNotFound => "connection to node in cluster not found",
905 #[cfg(feature = "json")]
906 ErrorKind::Serialize => "serializing",
907 ErrorKind::RESP3NotSupported => "resp3 is not supported by server",
908 ErrorKind::ParseError => "parse error",
909 ErrorKind::NoSub => {
910 "Server declined unsubscribe related command in non-subscribed mode"
911 }
912 }
913 }
914
915 pub fn is_io_error(&self) -> bool {
917 self.kind() == ErrorKind::IoError
918 }
919
920 pub(crate) fn as_io_error(&self) -> Option<&io::Error> {
921 match &self.repr {
922 ErrorRepr::IoError(e) => Some(e),
923 _ => None,
924 }
925 }
926
927 pub fn is_cluster_error(&self) -> bool {
929 matches!(
930 self.kind(),
931 ErrorKind::Moved | ErrorKind::Ask | ErrorKind::TryAgain | ErrorKind::ClusterDown
932 )
933 }
934
935 pub fn is_connection_refusal(&self) -> bool {
940 match self.repr {
941 ErrorRepr::IoError(ref err) => {
942 #[allow(clippy::match_like_matches_macro)]
943 match err.kind() {
944 io::ErrorKind::ConnectionRefused => true,
945 io::ErrorKind::NotFound => cfg!(unix),
949 _ => false,
950 }
951 }
952 _ => false,
953 }
954 }
955
956 pub fn is_timeout(&self) -> bool {
959 match self.repr {
960 ErrorRepr::IoError(ref err) => matches!(
961 err.kind(),
962 io::ErrorKind::TimedOut | io::ErrorKind::WouldBlock
963 ),
964 _ => false,
965 }
966 }
967
968 pub fn is_connection_dropped(&self) -> bool {
970 match self.repr {
971 ErrorRepr::IoError(ref err) => matches!(
972 err.kind(),
973 io::ErrorKind::BrokenPipe
974 | io::ErrorKind::ConnectionReset
975 | io::ErrorKind::UnexpectedEof
976 ),
977 _ => false,
978 }
979 }
980
981 pub fn is_unrecoverable_error(&self) -> bool {
983 match self.retry_method() {
984 RetryMethod::Reconnect => true,
985 RetryMethod::ReconnectFromInitialConnections => true,
986
987 RetryMethod::NoRetry => false,
988 RetryMethod::RetryImmediately => false,
989 RetryMethod::WaitAndRetry => false,
990 RetryMethod::AskRedirect => false,
991 RetryMethod::MovedRedirect => false,
992 }
993 }
994
995 pub fn redirect_node(&self) -> Option<(&str, u16)> {
999 match self.kind() {
1000 ErrorKind::Ask | ErrorKind::Moved => (),
1001 _ => return None,
1002 }
1003 let mut iter = self.detail()?.split_ascii_whitespace();
1004 let slot_id: u16 = iter.next()?.parse().ok()?;
1005 let addr = iter.next()?;
1006 Some((addr, slot_id))
1007 }
1008
1009 #[deprecated(note = "use code() instead")]
1015 pub fn extension_error_code(&self) -> Option<&str> {
1016 match self.repr {
1017 ErrorRepr::ExtensionError(ref code, _) => Some(code),
1018 _ => None,
1019 }
1020 }
1021
1022 #[cfg(feature = "connection-manager")] pub(crate) fn clone_mostly(&self, ioerror_description: &'static str) -> Self {
1031 let repr = match self.repr {
1032 ErrorRepr::WithDescription(kind, desc) => ErrorRepr::WithDescription(kind, desc),
1033 ErrorRepr::WithDescriptionAndDetail(kind, desc, ref detail) => {
1034 ErrorRepr::WithDescriptionAndDetail(kind, desc, detail.clone())
1035 }
1036 ErrorRepr::ExtensionError(ref code, ref detail) => {
1037 ErrorRepr::ExtensionError(code.clone(), detail.clone())
1038 }
1039 ErrorRepr::IoError(ref e) => ErrorRepr::IoError(io::Error::new(
1040 e.kind(),
1041 format!("{ioerror_description}: {e}"),
1042 )),
1043 };
1044 Self { repr }
1045 }
1046
1047 pub fn retry_method(&self) -> RetryMethod {
1054 match self.kind() {
1055 ErrorKind::Moved => RetryMethod::MovedRedirect,
1056 ErrorKind::Ask => RetryMethod::AskRedirect,
1057
1058 ErrorKind::TryAgain => RetryMethod::WaitAndRetry,
1059 ErrorKind::MasterDown => RetryMethod::WaitAndRetry,
1060 ErrorKind::ClusterDown => RetryMethod::WaitAndRetry,
1061 ErrorKind::BusyLoadingError => RetryMethod::WaitAndRetry,
1062 ErrorKind::MasterNameNotFoundBySentinel => RetryMethod::WaitAndRetry,
1063 ErrorKind::NoValidReplicasFoundBySentinel => RetryMethod::WaitAndRetry,
1064
1065 ErrorKind::ResponseError => RetryMethod::NoRetry,
1066 ErrorKind::ReadOnly => RetryMethod::NoRetry,
1067 ErrorKind::ExtensionError => RetryMethod::NoRetry,
1068 ErrorKind::ExecAbortError => RetryMethod::NoRetry,
1069 ErrorKind::TypeError => RetryMethod::NoRetry,
1070 ErrorKind::NoScriptError => RetryMethod::NoRetry,
1071 ErrorKind::InvalidClientConfig => RetryMethod::NoRetry,
1072 ErrorKind::CrossSlot => RetryMethod::NoRetry,
1073 ErrorKind::ClientError => RetryMethod::NoRetry,
1074 ErrorKind::EmptySentinelList => RetryMethod::NoRetry,
1075 ErrorKind::NotBusy => RetryMethod::NoRetry,
1076 #[cfg(feature = "json")]
1077 ErrorKind::Serialize => RetryMethod::NoRetry,
1078 ErrorKind::RESP3NotSupported => RetryMethod::NoRetry,
1079 ErrorKind::NoSub => RetryMethod::NoRetry,
1080
1081 ErrorKind::ParseError => RetryMethod::Reconnect,
1082 ErrorKind::AuthenticationFailed => RetryMethod::Reconnect,
1083 ErrorKind::ClusterConnectionNotFound => RetryMethod::ReconnectFromInitialConnections,
1084
1085 ErrorKind::IoError => match &self.repr {
1086 ErrorRepr::IoError(err) => match err.kind() {
1087 io::ErrorKind::ConnectionRefused => RetryMethod::Reconnect,
1088 io::ErrorKind::NotFound => RetryMethod::Reconnect,
1089 io::ErrorKind::ConnectionReset => RetryMethod::Reconnect,
1090 io::ErrorKind::ConnectionAborted => RetryMethod::Reconnect,
1091 io::ErrorKind::NotConnected => RetryMethod::Reconnect,
1092 io::ErrorKind::BrokenPipe => RetryMethod::Reconnect,
1093 io::ErrorKind::UnexpectedEof => RetryMethod::Reconnect,
1094
1095 io::ErrorKind::PermissionDenied => RetryMethod::NoRetry,
1096 io::ErrorKind::Unsupported => RetryMethod::NoRetry,
1097
1098 _ => RetryMethod::RetryImmediately,
1099 },
1100 _ => RetryMethod::RetryImmediately,
1101 },
1102 }
1103 }
1104}
1105
1106pub fn make_extension_error(code: String, detail: Option<String>) -> RedisError {
1120 RedisError {
1121 repr: ErrorRepr::ExtensionError(
1122 code,
1123 match detail {
1124 Some(x) => x,
1125 None => "Unknown extension error encountered".to_string(),
1126 },
1127 ),
1128 }
1129}
1130
1131pub type RedisResult<T> = Result<T, RedisError>;
1133
1134#[cfg(feature = "aio")]
1136pub type RedisFuture<'a, T> = futures_util::future::BoxFuture<'a, RedisResult<T>>;
1137
1138#[derive(Debug, Clone)]
1140pub struct InfoDict {
1141 map: HashMap<String, Value>,
1142}
1143
1144impl InfoDict {
1161 pub fn new(kvpairs: &str) -> InfoDict {
1166 let mut map = HashMap::new();
1167 for line in kvpairs.lines() {
1168 if line.is_empty() || line.starts_with('#') {
1169 continue;
1170 }
1171 let mut p = line.splitn(2, ':');
1172 let (k, v) = match (p.next(), p.next()) {
1173 (Some(k), Some(v)) => (k.to_string(), v.to_string()),
1174 _ => continue,
1175 };
1176 map.insert(k, Value::SimpleString(v));
1177 }
1178 InfoDict { map }
1179 }
1180
1181 pub fn get<T: FromRedisValue>(&self, key: &str) -> Option<T> {
1184 match self.find(&key) {
1185 Some(x) => from_redis_value(x).ok(),
1186 None => None,
1187 }
1188 }
1189
1190 pub fn find(&self, key: &&str) -> Option<&Value> {
1192 self.map.get(*key)
1193 }
1194
1195 pub fn contains_key(&self, key: &&str) -> bool {
1197 self.find(key).is_some()
1198 }
1199
1200 pub fn len(&self) -> usize {
1202 self.map.len()
1203 }
1204
1205 pub fn is_empty(&self) -> bool {
1207 self.map.is_empty()
1208 }
1209}
1210
1211impl Deref for InfoDict {
1212 type Target = HashMap<String, Value>;
1213
1214 fn deref(&self) -> &Self::Target {
1215 &self.map
1216 }
1217}
1218
1219#[derive(Debug, Clone, Eq, PartialEq)]
1223pub enum Role {
1224 Primary {
1226 replication_offset: u64,
1228 replicas: Vec<ReplicaInfo>,
1230 },
1231 Replica {
1233 primary_ip: String,
1235 primary_port: u16,
1237 replication_state: String,
1239 data_received: u64,
1241 },
1242 Sentinel {
1244 primary_names: Vec<String>,
1246 },
1247}
1248
1249#[derive(Debug, Clone, Eq, PartialEq)]
1253pub struct ReplicaInfo {
1254 pub ip: String,
1256 pub port: u16,
1258 pub replication_offset: i64,
1260}
1261
1262impl FromRedisValue for ReplicaInfo {
1263 fn from_redis_value(v: &Value) -> RedisResult<Self> {
1264 Self::from_owned_redis_value(v.clone())
1265 }
1266
1267 fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
1268 let v = match get_owned_inner_value(v).into_sequence() {
1269 Ok(v) => v,
1270 Err(v) => invalid_type_error!(v, "Replica response should be an array"),
1271 };
1272 if v.len() < 3 {
1273 invalid_type_error!(v, "Replica array is too short, expected 3 elements")
1274 }
1275 let mut v = v.into_iter();
1276 let ip = from_owned_redis_value(v.next().expect("len was checked"))?;
1277 let port = from_owned_redis_value(v.next().expect("len was checked"))?;
1278 let offset = from_owned_redis_value(v.next().expect("len was checked"))?;
1279 Ok(ReplicaInfo {
1280 ip,
1281 port,
1282 replication_offset: offset,
1283 })
1284 }
1285}
1286
1287impl FromRedisValue for Role {
1288 fn from_redis_value(v: &Value) -> RedisResult<Self> {
1289 Self::from_owned_redis_value(v.clone())
1290 }
1291
1292 fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
1293 let v = match get_owned_inner_value(v).into_sequence() {
1294 Ok(v) => v,
1295 Err(v) => invalid_type_error!(v, "Role response should be an array"),
1296 };
1297 if v.len() < 2 {
1298 invalid_type_error!(v, "Role array is too short, expected at least 2 elements")
1299 }
1300 match &v[0] {
1301 Value::BulkString(role) => match role.as_slice() {
1302 b"master" => Role::new_primary(v),
1303 b"slave" => Role::new_replica(v),
1304 b"sentinel" => Role::new_sentinel(v),
1305 _ => invalid_type_error!(v, "Role type is not master, slave or sentinel"),
1306 },
1307 _ => invalid_type_error!(v, "Role type is not a bulk string"),
1308 }
1309 }
1310}
1311
1312impl Role {
1313 fn new_primary(values: Vec<Value>) -> RedisResult<Self> {
1314 if values.len() < 3 {
1315 invalid_type_error!(
1316 values,
1317 "Role primary response too short, expected 3 elements"
1318 )
1319 }
1320
1321 let mut values = values.into_iter();
1322 _ = values.next();
1323
1324 let replication_offset = from_owned_redis_value(values.next().expect("len was checked"))?;
1325 let replicas = from_owned_redis_value(values.next().expect("len was checked"))?;
1326
1327 Ok(Role::Primary {
1328 replication_offset,
1329 replicas,
1330 })
1331 }
1332
1333 fn new_replica(values: Vec<Value>) -> RedisResult<Self> {
1334 if values.len() < 5 {
1335 invalid_type_error!(
1336 values,
1337 "Role replica response too short, expected 5 elements"
1338 )
1339 }
1340
1341 let mut values = values.into_iter();
1342 _ = values.next();
1343
1344 let primary_ip = from_owned_redis_value(values.next().expect("len was checked"))?;
1345 let primary_port = from_owned_redis_value(values.next().expect("len was checked"))?;
1346 let replication_state = from_owned_redis_value(values.next().expect("len was checked"))?;
1347 let data_received = from_owned_redis_value(values.next().expect("len was checked"))?;
1348
1349 Ok(Role::Replica {
1350 primary_ip,
1351 primary_port,
1352 replication_state,
1353 data_received,
1354 })
1355 }
1356
1357 fn new_sentinel(values: Vec<Value>) -> RedisResult<Self> {
1358 if values.len() < 2 {
1359 invalid_type_error!(
1360 values,
1361 "Role sentinel response too short, expected at least 2 elements"
1362 )
1363 }
1364 let second_val = values.into_iter().nth(1).expect("len was checked");
1365 let primary_names = from_owned_redis_value(second_val)?;
1366 Ok(Role::Sentinel { primary_names })
1367 }
1368}
1369
1370pub trait RedisWrite {
1372 fn write_arg(&mut self, arg: &[u8]);
1374
1375 fn write_arg_fmt(&mut self, arg: impl fmt::Display) {
1377 self.write_arg(arg.to_string().as_bytes())
1378 }
1379
1380 fn writer_for_next_arg(&mut self) -> impl std::io::Write + '_;
1389
1390 fn reserve_space_for_args(&mut self, additional: impl IntoIterator<Item = usize>) {
1422 let _do_nothing = additional;
1425 }
1426
1427 #[cfg(feature = "bytes")]
1428 fn bufmut_for_next_arg(&mut self, capacity: usize) -> impl bytes::BufMut + '_ {
1441 struct Wrapper<'a> {
1449 buf: Vec<u8>,
1451 writer: Box<dyn std::io::Write + 'a>,
1453 }
1454 unsafe impl bytes::BufMut for Wrapper<'_> {
1455 fn remaining_mut(&self) -> usize {
1456 self.buf.remaining_mut()
1457 }
1458
1459 unsafe fn advance_mut(&mut self, cnt: usize) {
1460 self.buf.advance_mut(cnt);
1461 }
1462
1463 fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
1464 self.buf.chunk_mut()
1465 }
1466
1467 fn put<T: bytes::buf::Buf>(&mut self, src: T)
1469 where
1470 Self: Sized,
1471 {
1472 self.buf.put(src);
1473 }
1474
1475 fn put_slice(&mut self, src: &[u8]) {
1476 self.buf.put_slice(src);
1477 }
1478
1479 fn put_bytes(&mut self, val: u8, cnt: usize) {
1480 self.buf.put_bytes(val, cnt);
1481 }
1482 }
1483 impl Drop for Wrapper<'_> {
1484 fn drop(&mut self) {
1485 self.writer.write_all(&self.buf).unwrap()
1486 }
1487 }
1488
1489 Wrapper {
1490 buf: Vec::with_capacity(capacity),
1491 writer: Box::new(self.writer_for_next_arg()),
1492 }
1493 }
1494}
1495
1496impl RedisWrite for Vec<Vec<u8>> {
1497 fn write_arg(&mut self, arg: &[u8]) {
1498 self.push(arg.to_owned());
1499 }
1500
1501 fn write_arg_fmt(&mut self, arg: impl fmt::Display) {
1502 self.push(arg.to_string().into_bytes())
1503 }
1504
1505 fn writer_for_next_arg(&mut self) -> impl std::io::Write + '_ {
1506 self.push(Vec::new());
1507 self.last_mut().unwrap()
1508 }
1509
1510 fn reserve_space_for_args(&mut self, additional: impl IntoIterator<Item = usize>) {
1511 self.reserve(additional.into_iter().count());
1516 }
1517
1518 #[cfg(feature = "bytes")]
1519 fn bufmut_for_next_arg(&mut self, capacity: usize) -> impl bytes::BufMut + '_ {
1520 self.push(Vec::with_capacity(capacity));
1521 self.last_mut().unwrap()
1522 }
1523}
1524
1525pub trait ToRedisArgs: Sized {
1529 fn to_redis_args(&self) -> Vec<Vec<u8>> {
1535 let mut out = Vec::new();
1536 self.write_redis_args(&mut out);
1537 out
1538 }
1539
1540 fn write_redis_args<W>(&self, out: &mut W)
1545 where
1546 W: ?Sized + RedisWrite;
1547
1548 fn describe_numeric_behavior(&self) -> NumericBehavior {
1553 NumericBehavior::NonNumeric
1554 }
1555
1556 fn num_of_args(&self) -> usize {
1563 1
1564 }
1565
1566 #[doc(hidden)]
1569 fn write_args_from_slice<W>(items: &[Self], out: &mut W)
1570 where
1571 W: ?Sized + RedisWrite,
1572 {
1573 Self::make_arg_iter_ref(items.iter(), out)
1574 }
1575
1576 #[doc(hidden)]
1579 fn make_arg_iter_ref<'a, I, W>(items: I, out: &mut W)
1580 where
1581 W: ?Sized + RedisWrite,
1582 I: Iterator<Item = &'a Self>,
1583 Self: 'a,
1584 {
1585 for item in items {
1586 item.write_redis_args(out);
1587 }
1588 }
1589
1590 #[doc(hidden)]
1591 fn is_single_vec_arg(items: &[Self]) -> bool {
1592 items.len() == 1 && items[0].num_of_args() <= 1
1593 }
1594}
1595
1596macro_rules! itoa_based_to_redis_impl {
1597 ($t:ty, $numeric:expr) => {
1598 impl ToRedisArgs for $t {
1599 fn write_redis_args<W>(&self, out: &mut W)
1600 where
1601 W: ?Sized + RedisWrite,
1602 {
1603 let mut buf = ::itoa::Buffer::new();
1604 let s = buf.format(*self);
1605 out.write_arg(s.as_bytes())
1606 }
1607
1608 fn describe_numeric_behavior(&self) -> NumericBehavior {
1609 $numeric
1610 }
1611 }
1612 };
1613}
1614
1615macro_rules! non_zero_itoa_based_to_redis_impl {
1616 ($t:ty, $numeric:expr) => {
1617 impl ToRedisArgs for $t {
1618 fn write_redis_args<W>(&self, out: &mut W)
1619 where
1620 W: ?Sized + RedisWrite,
1621 {
1622 let mut buf = ::itoa::Buffer::new();
1623 let s = buf.format(self.get());
1624 out.write_arg(s.as_bytes())
1625 }
1626
1627 fn describe_numeric_behavior(&self) -> NumericBehavior {
1628 $numeric
1629 }
1630 }
1631 };
1632}
1633
1634macro_rules! ryu_based_to_redis_impl {
1635 ($t:ty, $numeric:expr) => {
1636 impl ToRedisArgs for $t {
1637 fn write_redis_args<W>(&self, out: &mut W)
1638 where
1639 W: ?Sized + RedisWrite,
1640 {
1641 let mut buf = ::ryu::Buffer::new();
1642 let s = buf.format(*self);
1643 out.write_arg(s.as_bytes())
1644 }
1645
1646 fn describe_numeric_behavior(&self) -> NumericBehavior {
1647 $numeric
1648 }
1649 }
1650 };
1651}
1652
1653impl ToRedisArgs for u8 {
1654 fn write_redis_args<W>(&self, out: &mut W)
1655 where
1656 W: ?Sized + RedisWrite,
1657 {
1658 let mut buf = ::itoa::Buffer::new();
1659 let s = buf.format(*self);
1660 out.write_arg(s.as_bytes())
1661 }
1662
1663 fn write_args_from_slice<W>(items: &[u8], out: &mut W)
1664 where
1665 W: ?Sized + RedisWrite,
1666 {
1667 out.write_arg(items);
1668 }
1669
1670 fn is_single_vec_arg(_items: &[u8]) -> bool {
1671 true
1672 }
1673}
1674
1675itoa_based_to_redis_impl!(i8, NumericBehavior::NumberIsInteger);
1676itoa_based_to_redis_impl!(i16, NumericBehavior::NumberIsInteger);
1677itoa_based_to_redis_impl!(u16, NumericBehavior::NumberIsInteger);
1678itoa_based_to_redis_impl!(i32, NumericBehavior::NumberIsInteger);
1679itoa_based_to_redis_impl!(u32, NumericBehavior::NumberIsInteger);
1680itoa_based_to_redis_impl!(i64, NumericBehavior::NumberIsInteger);
1681itoa_based_to_redis_impl!(u64, NumericBehavior::NumberIsInteger);
1682itoa_based_to_redis_impl!(i128, NumericBehavior::NumberIsInteger);
1683itoa_based_to_redis_impl!(u128, NumericBehavior::NumberIsInteger);
1684itoa_based_to_redis_impl!(isize, NumericBehavior::NumberIsInteger);
1685itoa_based_to_redis_impl!(usize, NumericBehavior::NumberIsInteger);
1686
1687non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU8, NumericBehavior::NumberIsInteger);
1688non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI8, NumericBehavior::NumberIsInteger);
1689non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU16, NumericBehavior::NumberIsInteger);
1690non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI16, NumericBehavior::NumberIsInteger);
1691non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU32, NumericBehavior::NumberIsInteger);
1692non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI32, NumericBehavior::NumberIsInteger);
1693non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU64, NumericBehavior::NumberIsInteger);
1694non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI64, NumericBehavior::NumberIsInteger);
1695non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU128, NumericBehavior::NumberIsInteger);
1696non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI128, NumericBehavior::NumberIsInteger);
1697non_zero_itoa_based_to_redis_impl!(core::num::NonZeroUsize, NumericBehavior::NumberIsInteger);
1698non_zero_itoa_based_to_redis_impl!(core::num::NonZeroIsize, NumericBehavior::NumberIsInteger);
1699
1700ryu_based_to_redis_impl!(f32, NumericBehavior::NumberIsFloat);
1701ryu_based_to_redis_impl!(f64, NumericBehavior::NumberIsFloat);
1702
1703#[cfg(any(
1704 feature = "rust_decimal",
1705 feature = "bigdecimal",
1706 feature = "num-bigint"
1707))]
1708macro_rules! bignum_to_redis_impl {
1709 ($t:ty) => {
1710 impl ToRedisArgs for $t {
1711 fn write_redis_args<W>(&self, out: &mut W)
1712 where
1713 W: ?Sized + RedisWrite,
1714 {
1715 out.write_arg(&self.to_string().into_bytes())
1716 }
1717 }
1718 };
1719}
1720
1721#[cfg(feature = "rust_decimal")]
1722bignum_to_redis_impl!(rust_decimal::Decimal);
1723#[cfg(feature = "bigdecimal")]
1724bignum_to_redis_impl!(bigdecimal::BigDecimal);
1725#[cfg(feature = "num-bigint")]
1726bignum_to_redis_impl!(num_bigint::BigInt);
1727#[cfg(feature = "num-bigint")]
1728bignum_to_redis_impl!(num_bigint::BigUint);
1729
1730impl ToRedisArgs for bool {
1731 fn write_redis_args<W>(&self, out: &mut W)
1732 where
1733 W: ?Sized + RedisWrite,
1734 {
1735 out.write_arg(if *self { b"1" } else { b"0" })
1736 }
1737}
1738
1739impl ToRedisArgs for String {
1740 fn write_redis_args<W>(&self, out: &mut W)
1741 where
1742 W: ?Sized + RedisWrite,
1743 {
1744 out.write_arg(self.as_bytes())
1745 }
1746}
1747
1748impl ToRedisArgs for &str {
1749 fn write_redis_args<W>(&self, out: &mut W)
1750 where
1751 W: ?Sized + RedisWrite,
1752 {
1753 out.write_arg(self.as_bytes())
1754 }
1755}
1756
1757impl<'a, T> ToRedisArgs for Cow<'a, T>
1758where
1759 T: ToOwned + ?Sized,
1760 &'a T: ToRedisArgs,
1761 for<'b> &'b T::Owned: ToRedisArgs,
1762{
1763 fn write_redis_args<W>(&self, out: &mut W)
1764 where
1765 W: ?Sized + RedisWrite,
1766 {
1767 match self {
1768 Cow::Borrowed(inner) => inner.write_redis_args(out),
1769 Cow::Owned(inner) => inner.write_redis_args(out),
1770 }
1771 }
1772}
1773
1774impl<T: ToRedisArgs> ToRedisArgs for Vec<T> {
1775 fn write_redis_args<W>(&self, out: &mut W)
1776 where
1777 W: ?Sized + RedisWrite,
1778 {
1779 ToRedisArgs::write_args_from_slice(self, out)
1780 }
1781
1782 fn num_of_args(&self) -> usize {
1783 if ToRedisArgs::is_single_vec_arg(&self[..]) {
1784 return 1;
1785 }
1786 if self.len() == 1 {
1787 self[0].num_of_args()
1788 } else {
1789 self.len()
1790 }
1791 }
1792}
1793
1794impl<T: ToRedisArgs> ToRedisArgs for &[T] {
1795 fn write_redis_args<W>(&self, out: &mut W)
1796 where
1797 W: ?Sized + RedisWrite,
1798 {
1799 ToRedisArgs::write_args_from_slice(self, out)
1800 }
1801
1802 fn num_of_args(&self) -> usize {
1803 if ToRedisArgs::is_single_vec_arg(&self[..]) {
1804 return 1;
1805 }
1806 if self.len() == 1 {
1807 self[0].num_of_args()
1808 } else {
1809 self.len()
1810 }
1811 }
1812}
1813
1814impl<T: ToRedisArgs> ToRedisArgs for Option<T> {
1815 fn write_redis_args<W>(&self, out: &mut W)
1816 where
1817 W: ?Sized + RedisWrite,
1818 {
1819 if let Some(ref x) = *self {
1820 x.write_redis_args(out);
1821 }
1822 }
1823
1824 fn describe_numeric_behavior(&self) -> NumericBehavior {
1825 match *self {
1826 Some(ref x) => x.describe_numeric_behavior(),
1827 None => NumericBehavior::NonNumeric,
1828 }
1829 }
1830
1831 fn num_of_args(&self) -> usize {
1832 match *self {
1833 Some(ref x) => x.num_of_args(),
1834 None => 0,
1835 }
1836 }
1837}
1838
1839macro_rules! deref_to_write_redis_args_impl {
1840 (
1841 $(#[$attr:meta])*
1842 <$($desc:tt)+
1843 ) => {
1844 $(#[$attr])*
1845 impl <$($desc)+ {
1846 #[inline]
1847 fn write_redis_args<W>(&self, out: &mut W)
1848 where
1849 W: ?Sized + RedisWrite,
1850 {
1851 (**self).write_redis_args(out)
1852 }
1853
1854 fn num_of_args(&self) -> usize {
1855 (**self).num_of_args()
1856 }
1857
1858 fn describe_numeric_behavior(&self) -> NumericBehavior {
1859 (**self).describe_numeric_behavior()
1860 }
1861 }
1862 };
1863}
1864
1865deref_to_write_redis_args_impl! {
1866 <'a, T> ToRedisArgs for &'a T where T: ToRedisArgs
1867}
1868
1869deref_to_write_redis_args_impl! {
1870 <'a, T> ToRedisArgs for &'a mut T where T: ToRedisArgs
1871}
1872
1873deref_to_write_redis_args_impl! {
1874 <T> ToRedisArgs for Box<T> where T: ToRedisArgs
1875}
1876
1877deref_to_write_redis_args_impl! {
1878 <T> ToRedisArgs for std::sync::Arc<T> where T: ToRedisArgs
1879}
1880
1881deref_to_write_redis_args_impl! {
1882 <T> ToRedisArgs for std::rc::Rc<T> where T: ToRedisArgs
1883}
1884
1885macro_rules! impl_to_redis_args_for_set {
1889 (for <$($TypeParam:ident),+> $SetType:ty, where ($($WhereClause:tt)+) ) => {
1890 impl< $($TypeParam),+ > ToRedisArgs for $SetType
1891 where
1892 $($WhereClause)+
1893 {
1894 fn write_redis_args<W>(&self, out: &mut W)
1895 where
1896 W: ?Sized + RedisWrite,
1897 {
1898 ToRedisArgs::make_arg_iter_ref(self.iter(), out)
1899 }
1900
1901 fn num_of_args(&self) -> usize {
1902 self.len()
1903 }
1904 }
1905 };
1906}
1907
1908impl_to_redis_args_for_set!(
1909 for <T, S> std::collections::HashSet<T, S>,
1910 where (T: ToRedisArgs + Hash + Eq, S: BuildHasher + Default)
1911);
1912
1913impl_to_redis_args_for_set!(
1914 for <T> std::collections::BTreeSet<T>,
1915 where (T: ToRedisArgs + Hash + Eq + Ord)
1916);
1917
1918#[cfg(feature = "hashbrown")]
1919impl_to_redis_args_for_set!(
1920 for <T, S> hashbrown::HashSet<T, S>,
1921 where (T: ToRedisArgs + Hash + Eq, S: BuildHasher + Default)
1922);
1923
1924#[cfg(feature = "ahash")]
1925impl_to_redis_args_for_set!(
1926 for <T, S> ahash::AHashSet<T, S>,
1927 where (T: ToRedisArgs + Hash + Eq, S: BuildHasher + Default)
1928);
1929
1930macro_rules! impl_to_redis_args_for_map {
1934 (
1935 $(#[$meta:meta])*
1936 for <$($TypeParam:ident),+> $MapType:ty,
1937 where ($($WhereClause:tt)+)
1938 ) => {
1939 $(#[$meta])*
1940 impl< $($TypeParam),+ > ToRedisArgs for $MapType
1941 where
1942 $($WhereClause)+
1943 {
1944 fn write_redis_args<W>(&self, out: &mut W)
1945 where
1946 W: ?Sized + RedisWrite,
1947 {
1948 for (key, value) in self {
1949 assert!(key.num_of_args() <= 1 && value.num_of_args() <= 1);
1951 key.write_redis_args(out);
1952 value.write_redis_args(out);
1953 }
1954 }
1955
1956 fn num_of_args(&self) -> usize {
1957 self.len()
1958 }
1959 }
1960 };
1961}
1962impl_to_redis_args_for_map!(
1963 for <K, V> std::collections::HashMap<K, V>,
1964 where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1965);
1966
1967impl_to_redis_args_for_map!(
1968 for <K, V> std::collections::BTreeMap<K, V>,
1970 where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1971);
1972
1973#[cfg(feature = "hashbrown")]
1974impl_to_redis_args_for_map!(
1975 for <K, V> hashbrown::HashMap<K, V>,
1976 where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1977);
1978
1979macro_rules! to_redis_args_for_tuple {
1980 () => ();
1981 ($(#[$meta:meta],)*$($name:ident,)+) => (
1982 $(#[$meta])*
1983 impl<$($name: ToRedisArgs),*> ToRedisArgs for ($($name,)*) {
1984 #[allow(non_snake_case, unused_variables)]
1987 fn write_redis_args<W>(&self, out: &mut W) where W: ?Sized + RedisWrite {
1988 let ($(ref $name,)*) = *self;
1989 $($name.write_redis_args(out);)*
1990 }
1991
1992 #[allow(non_snake_case, unused_variables)]
1993 fn num_of_args(&self) -> usize {
1994 let mut n: usize = 0;
1995 $(let $name = (); n += 1;)*
1996 n
1997 }
1998 }
1999 )
2000}
2001
2002to_redis_args_for_tuple! { #[cfg_attr(docsrs, doc(fake_variadic))], #[doc = "This trait is implemented for tuples up to 12 items long."], T, }
2003to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, }
2004to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, }
2005to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, }
2006to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, }
2007to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, }
2008to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, }
2009to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, }
2010to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, }
2011to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, }
2012to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
2013to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
2014
2015impl<T: ToRedisArgs, const N: usize> ToRedisArgs for &[T; N] {
2016 fn write_redis_args<W>(&self, out: &mut W)
2017 where
2018 W: ?Sized + RedisWrite,
2019 {
2020 ToRedisArgs::write_args_from_slice(self.as_slice(), out)
2021 }
2022
2023 fn num_of_args(&self) -> usize {
2024 if ToRedisArgs::is_single_vec_arg(&self[..]) {
2025 return 1;
2026 }
2027 if self.len() == 1 {
2028 self[0].num_of_args()
2029 } else {
2030 self.len()
2031 }
2032 }
2033}
2034
2035fn vec_to_array<T, const N: usize>(items: Vec<T>, original_value: &Value) -> RedisResult<[T; N]> {
2036 match items.try_into() {
2037 Ok(array) => Ok(array),
2038 Err(items) => {
2039 let msg = format!(
2040 "Response has wrong dimension, expected {N}, got {}",
2041 items.len()
2042 );
2043 invalid_type_error!(original_value, msg)
2044 }
2045 }
2046}
2047
2048impl<T: FromRedisValue, const N: usize> FromRedisValue for [T; N] {
2049 fn from_redis_value(value: &Value) -> RedisResult<[T; N]> {
2050 match *value {
2051 Value::BulkString(ref bytes) => match FromRedisValue::from_byte_vec(bytes) {
2052 Some(items) => vec_to_array(items, value),
2053 None => {
2054 let msg = format!(
2055 "Conversion to Array[{}; {N}] failed",
2056 std::any::type_name::<T>()
2057 );
2058 invalid_type_error!(value, msg)
2059 }
2060 },
2061 Value::Array(ref items) => {
2062 let items = FromRedisValue::from_redis_values(items)?;
2063 vec_to_array(items, value)
2064 }
2065 Value::Nil => vec_to_array(vec![], value),
2066 _ => invalid_type_error!(value, "Response type not array compatible"),
2067 }
2068 }
2069}
2070
2071pub trait FromRedisValue: Sized {
2085 fn from_redis_value(v: &Value) -> RedisResult<Self>;
2089
2090 fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2094 Self::from_redis_value(&v)
2098 }
2099
2100 fn from_redis_values(items: &[Value]) -> RedisResult<Vec<Self>> {
2104 items.iter().map(FromRedisValue::from_redis_value).collect()
2105 }
2106
2107 fn from_owned_redis_values(items: Vec<Value>) -> RedisResult<Vec<Self>> {
2110 items
2111 .into_iter()
2112 .map(FromRedisValue::from_owned_redis_value)
2113 .collect()
2114 }
2115
2116 fn from_each_owned_redis_values(items: Vec<Value>) -> Vec<RedisResult<Self>> {
2119 items
2120 .into_iter()
2121 .map(FromRedisValue::from_owned_redis_value)
2122 .collect()
2123 }
2124
2125 fn from_byte_vec(_vec: &[u8]) -> Option<Vec<Self>> {
2127 Self::from_owned_redis_value(Value::BulkString(_vec.into()))
2128 .map(|rv| vec![rv])
2129 .ok()
2130 }
2131
2132 fn from_owned_byte_vec(_vec: Vec<u8>) -> RedisResult<Vec<Self>> {
2134 Self::from_owned_redis_value(Value::BulkString(_vec)).map(|rv| vec![rv])
2135 }
2136}
2137
2138fn get_inner_value(v: &Value) -> &Value {
2139 if let Value::Attribute {
2140 data,
2141 attributes: _,
2142 } = v
2143 {
2144 data.as_ref()
2145 } else {
2146 v
2147 }
2148}
2149
2150fn get_owned_inner_value(v: Value) -> Value {
2151 if let Value::Attribute {
2152 data,
2153 attributes: _,
2154 } = v
2155 {
2156 *data
2157 } else {
2158 v
2159 }
2160}
2161
2162macro_rules! from_redis_value_for_num_internal {
2163 ($t:ty, $v:expr) => {{
2164 let v = if let Value::Attribute {
2165 data,
2166 attributes: _,
2167 } = $v
2168 {
2169 data
2170 } else {
2171 $v
2172 };
2173 match *v {
2174 Value::Int(val) => Ok(val as $t),
2175 Value::SimpleString(ref s) => match s.parse::<$t>() {
2176 Ok(rv) => Ok(rv),
2177 Err(_) => invalid_type_error!(v, "Could not convert from string."),
2178 },
2179 Value::BulkString(ref bytes) => match from_utf8(bytes)?.parse::<$t>() {
2180 Ok(rv) => Ok(rv),
2181 Err(_) => invalid_type_error!(v, "Could not convert from string."),
2182 },
2183 Value::Double(val) => Ok(val as $t),
2184 _ => invalid_type_error!(v, "Response type not convertible to numeric."),
2185 }
2186 }};
2187}
2188
2189macro_rules! from_redis_value_for_num {
2190 ($t:ty) => {
2191 impl FromRedisValue for $t {
2192 fn from_redis_value(v: &Value) -> RedisResult<$t> {
2193 from_redis_value_for_num_internal!($t, v)
2194 }
2195 }
2196 };
2197}
2198
2199impl FromRedisValue for u8 {
2200 fn from_redis_value(v: &Value) -> RedisResult<u8> {
2201 from_redis_value_for_num_internal!(u8, v)
2202 }
2203
2204 fn from_byte_vec(vec: &[u8]) -> Option<Vec<u8>> {
2206 Some(vec.to_vec())
2207 }
2208 fn from_owned_byte_vec(vec: Vec<u8>) -> RedisResult<Vec<u8>> {
2209 Ok(vec)
2210 }
2211}
2212
2213from_redis_value_for_num!(i8);
2214from_redis_value_for_num!(i16);
2215from_redis_value_for_num!(u16);
2216from_redis_value_for_num!(i32);
2217from_redis_value_for_num!(u32);
2218from_redis_value_for_num!(i64);
2219from_redis_value_for_num!(u64);
2220from_redis_value_for_num!(i128);
2221from_redis_value_for_num!(u128);
2222from_redis_value_for_num!(f32);
2223from_redis_value_for_num!(f64);
2224from_redis_value_for_num!(isize);
2225from_redis_value_for_num!(usize);
2226
2227#[cfg(any(
2228 feature = "rust_decimal",
2229 feature = "bigdecimal",
2230 feature = "num-bigint"
2231))]
2232macro_rules! from_redis_value_for_bignum_internal {
2233 ($t:ty, $v:expr) => {{
2234 let v = $v;
2235 match *v {
2236 Value::Int(val) => <$t>::try_from(val)
2237 .map_err(|_| invalid_type_error_inner!(v, "Could not convert from integer.")),
2238 Value::SimpleString(ref s) => match s.parse::<$t>() {
2239 Ok(rv) => Ok(rv),
2240 Err(_) => invalid_type_error!(v, "Could not convert from string."),
2241 },
2242 Value::BulkString(ref bytes) => match from_utf8(bytes)?.parse::<$t>() {
2243 Ok(rv) => Ok(rv),
2244 Err(_) => invalid_type_error!(v, "Could not convert from string."),
2245 },
2246 _ => invalid_type_error!(v, "Response type not convertible to numeric."),
2247 }
2248 }};
2249}
2250
2251#[cfg(any(
2252 feature = "rust_decimal",
2253 feature = "bigdecimal",
2254 feature = "num-bigint"
2255))]
2256macro_rules! from_redis_value_for_bignum {
2257 ($t:ty) => {
2258 impl FromRedisValue for $t {
2259 fn from_redis_value(v: &Value) -> RedisResult<$t> {
2260 from_redis_value_for_bignum_internal!($t, v)
2261 }
2262 }
2263 };
2264}
2265
2266#[cfg(feature = "rust_decimal")]
2267from_redis_value_for_bignum!(rust_decimal::Decimal);
2268#[cfg(feature = "bigdecimal")]
2269from_redis_value_for_bignum!(bigdecimal::BigDecimal);
2270#[cfg(feature = "num-bigint")]
2271from_redis_value_for_bignum!(num_bigint::BigInt);
2272#[cfg(feature = "num-bigint")]
2273from_redis_value_for_bignum!(num_bigint::BigUint);
2274
2275impl FromRedisValue for bool {
2276 fn from_redis_value(v: &Value) -> RedisResult<bool> {
2277 let v = get_inner_value(v);
2278 match *v {
2279 Value::Nil => Ok(false),
2280 Value::Int(val) => Ok(val != 0),
2281 Value::SimpleString(ref s) => {
2282 if &s[..] == "1" {
2283 Ok(true)
2284 } else if &s[..] == "0" {
2285 Ok(false)
2286 } else {
2287 invalid_type_error!(v, "Response status not valid boolean");
2288 }
2289 }
2290 Value::BulkString(ref bytes) => {
2291 if bytes == b"1" {
2292 Ok(true)
2293 } else if bytes == b"0" {
2294 Ok(false)
2295 } else {
2296 invalid_type_error!(v, "Response type not bool compatible.");
2297 }
2298 }
2299 Value::Boolean(b) => Ok(b),
2300 Value::Okay => Ok(true),
2301 _ => invalid_type_error!(v, "Response type not bool compatible."),
2302 }
2303 }
2304}
2305
2306impl FromRedisValue for CString {
2307 fn from_redis_value(v: &Value) -> RedisResult<CString> {
2308 let v = get_inner_value(v);
2309 match *v {
2310 Value::BulkString(ref bytes) => Ok(CString::new(bytes.as_slice())?),
2311 Value::Okay => Ok(CString::new("OK")?),
2312 Value::SimpleString(ref val) => Ok(CString::new(val.as_bytes())?),
2313 _ => invalid_type_error!(v, "Response type not CString compatible."),
2314 }
2315 }
2316 fn from_owned_redis_value(v: Value) -> RedisResult<CString> {
2317 let v = get_owned_inner_value(v);
2318 match v {
2319 Value::BulkString(bytes) => Ok(CString::new(bytes)?),
2320 Value::Okay => Ok(CString::new("OK")?),
2321 Value::SimpleString(val) => Ok(CString::new(val)?),
2322 _ => invalid_type_error!(v, "Response type not CString compatible."),
2323 }
2324 }
2325}
2326
2327impl FromRedisValue for String {
2328 fn from_redis_value(v: &Value) -> RedisResult<Self> {
2329 let v = get_inner_value(v);
2330 match *v {
2331 Value::BulkString(ref bytes) => Ok(from_utf8(bytes)?.to_string()),
2332 Value::Okay => Ok("OK".to_string()),
2333 Value::SimpleString(ref val) => Ok(val.to_string()),
2334 Value::VerbatimString {
2335 format: _,
2336 ref text,
2337 } => Ok(text.to_string()),
2338 Value::Double(ref val) => Ok(val.to_string()),
2339 Value::Int(val) => Ok(val.to_string()),
2340 _ => invalid_type_error!(v, "Response type not string compatible."),
2341 }
2342 }
2343
2344 fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2345 let v = get_owned_inner_value(v);
2346 match v {
2347 Value::BulkString(bytes) => Ok(Self::from_utf8(bytes)?),
2348 Value::Okay => Ok("OK".to_string()),
2349 Value::SimpleString(val) => Ok(val),
2350 Value::VerbatimString { format: _, text } => Ok(text),
2351 Value::Double(val) => Ok(val.to_string()),
2352 Value::Int(val) => Ok(val.to_string()),
2353 _ => invalid_type_error!(v, "Response type not string compatible."),
2354 }
2355 }
2356}
2357
2358macro_rules! pointer_from_redis_value_impl {
2359 (
2360 $(#[$attr:meta])*
2361 $id:ident, $ty:ty, $func:expr
2362 ) => {
2363 $(#[$attr])*
2364 impl<$id: FromRedisValue> FromRedisValue for $ty {
2365 fn from_redis_value(v: &Value) -> RedisResult<Self>
2366 {
2367 FromRedisValue::from_redis_value(v).map($func)
2368 }
2369
2370 fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2371 FromRedisValue::from_owned_redis_value(v).map($func)
2372 }
2373 }
2374 }
2375}
2376
2377pointer_from_redis_value_impl!(T, Box<T>, Box::new);
2378pointer_from_redis_value_impl!(T, std::sync::Arc<T>, std::sync::Arc::new);
2379pointer_from_redis_value_impl!(T, std::rc::Rc<T>, std::rc::Rc::new);
2380
2381macro_rules! from_vec_from_redis_value {
2386 (<$T:ident> $Type:ty) => {
2387 from_vec_from_redis_value!(<$T> $Type; Into::into);
2388 };
2389
2390 (<$T:ident> $Type:ty; $convert:expr) => {
2391 impl<$T: FromRedisValue> FromRedisValue for $Type {
2392 fn from_redis_value(v: &Value) -> RedisResult<$Type> {
2393 match v {
2394 Value::BulkString(bytes) => match FromRedisValue::from_byte_vec(bytes) {
2397 Some(x) => Ok($convert(x)),
2398 None => invalid_type_error!(
2399 v,
2400 format!("Conversion to {} failed.", std::any::type_name::<$Type>())
2401 ),
2402 },
2403 Value::Array(items) => FromRedisValue::from_redis_values(items).map($convert),
2404 Value::Set(ref items) => FromRedisValue::from_redis_values(items).map($convert),
2405 Value::Map(ref items) => {
2406 let mut n: Vec<T> = vec![];
2407 for item in items {
2408 match FromRedisValue::from_redis_value(&Value::Map(vec![item.clone()])) {
2409 Ok(v) => {
2410 n.push(v);
2411 }
2412 Err(e) => {
2413 return Err(e);
2414 }
2415 }
2416 }
2417 Ok($convert(n))
2418 }
2419 Value::Nil => Ok($convert(Vec::new())),
2420 _ => invalid_type_error!(v, "Response type not vector compatible."),
2421 }
2422 }
2423 fn from_owned_redis_value(v: Value) -> RedisResult<$Type> {
2424 match v {
2425 Value::BulkString(bytes) => FromRedisValue::from_owned_byte_vec(bytes).map($convert),
2429 Value::Array(items) => FromRedisValue::from_owned_redis_values(items).map($convert),
2430 Value::Set(items) => FromRedisValue::from_owned_redis_values(items).map($convert),
2431 Value::Map(items) => {
2432 let mut n: Vec<T> = vec![];
2433 for item in items {
2434 match FromRedisValue::from_owned_redis_value(Value::Map(vec![item])) {
2435 Ok(v) => {
2436 n.push(v);
2437 }
2438 Err(e) => {
2439 return Err(e);
2440 }
2441 }
2442 }
2443 Ok($convert(n))
2444 }
2445 Value::Nil => Ok($convert(Vec::new())),
2446 _ => invalid_type_error!(v, "Response type not vector compatible."),
2447 }
2448 }
2449 }
2450 };
2451}
2452
2453from_vec_from_redis_value!(<T> Vec<T>);
2454from_vec_from_redis_value!(<T> std::sync::Arc<[T]>);
2455from_vec_from_redis_value!(<T> Box<[T]>; Vec::into_boxed_slice);
2456
2457macro_rules! impl_from_redis_value_for_map {
2458 (for <$($TypeParam:ident),+> $MapType:ty, where ($($WhereClause:tt)+)) => {
2459 impl< $($TypeParam),+ > FromRedisValue for $MapType
2460 where
2461 $($WhereClause)+
2462 {
2463 fn from_redis_value(v: &Value) -> RedisResult<$MapType> {
2464 let v = get_inner_value(v);
2465 match *v {
2466 Value::Nil => Ok(Default::default()),
2467 _ => v
2468 .as_map_iter()
2469 .ok_or_else(|| invalid_type_error_inner!(v, "Response type not map compatible"))?
2470 .map(|(k, v)| {
2471 Ok((from_redis_value(k)?, from_redis_value(v)?))
2472 })
2473 .collect(),
2474 }
2475 }
2476
2477 fn from_owned_redis_value(v: Value) -> RedisResult<$MapType> {
2478 let v = get_owned_inner_value(v);
2479 match v {
2480 Value::Nil => Ok(Default::default()),
2481 _ => v
2482 .into_map_iter()
2483 .map_err(|v| invalid_type_error_inner!(v, "Response type not map compatible"))?
2484 .map(|(k, v)| {
2485 Ok((from_owned_redis_value(k)?, from_owned_redis_value(v)?))
2486 })
2487 .collect(),
2488 }
2489 }
2490 }
2491 };
2492}
2493
2494impl_from_redis_value_for_map!(
2495 for <K, V, S> std::collections::HashMap<K, V, S>,
2496 where (K: FromRedisValue + Eq + Hash, V: FromRedisValue, S: BuildHasher + Default)
2497);
2498
2499#[cfg(feature = "hashbrown")]
2500impl_from_redis_value_for_map!(
2501 for <K, V, S> hashbrown::HashMap<K, V, S>,
2502 where (K: FromRedisValue + Eq + Hash, V: FromRedisValue, S: BuildHasher + Default)
2503);
2504
2505#[cfg(feature = "ahash")]
2506impl_from_redis_value_for_map!(
2507 for <K, V> ahash::AHashMap<K, V>,
2508 where (K: FromRedisValue + Eq + Hash, V: FromRedisValue)
2509);
2510
2511impl_from_redis_value_for_map!(
2512 for <K, V> std::collections::BTreeMap<K, V>,
2513 where (K: FromRedisValue + Eq + Hash + Ord, V: FromRedisValue)
2514);
2515
2516macro_rules! impl_from_redis_value_for_set {
2517 (for <$($TypeParam:ident),+> $SetType:ty, where ($($WhereClause:tt)+)) => {
2518 impl< $($TypeParam),+ > FromRedisValue for $SetType
2519 where
2520 $($WhereClause)+
2521 {
2522 fn from_redis_value(v: &Value) -> RedisResult<$SetType> {
2523 let v = get_inner_value(v);
2524 let items = v
2525 .as_sequence()
2526 .ok_or_else(|| invalid_type_error_inner!(v, "Response type not map compatible"))?;
2527 items.iter().map(|item| from_redis_value(item)).collect()
2528 }
2529
2530 fn from_owned_redis_value(v: Value) -> RedisResult<$SetType> {
2531 let v = get_owned_inner_value(v);
2532 let items = v
2533 .into_sequence()
2534 .map_err(|v| invalid_type_error_inner!(v, "Response type not map compatible"))?;
2535 items
2536 .into_iter()
2537 .map(|item| from_owned_redis_value(item))
2538 .collect()
2539 }
2540 }
2541 };
2542}
2543
2544impl_from_redis_value_for_set!(
2545 for <T, S> std::collections::HashSet<T, S>,
2546 where (T: FromRedisValue + Eq + Hash, S: BuildHasher + Default)
2547);
2548
2549impl_from_redis_value_for_set!(
2550 for <T> std::collections::BTreeSet<T>,
2551 where (T: FromRedisValue + Eq + Ord)
2552);
2553
2554#[cfg(feature = "hashbrown")]
2555impl_from_redis_value_for_set!(
2556 for <T, S> hashbrown::HashSet<T, S>,
2557 where (T: FromRedisValue + Eq + Hash, S: BuildHasher + Default)
2558);
2559
2560#[cfg(feature = "ahash")]
2561impl_from_redis_value_for_set!(
2562 for <T> ahash::AHashSet<T>,
2563 where (T: FromRedisValue + Eq + Hash)
2564);
2565
2566impl FromRedisValue for Value {
2567 fn from_redis_value(v: &Value) -> RedisResult<Value> {
2568 Ok(v.clone())
2569 }
2570 fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2571 Ok(v)
2572 }
2573}
2574
2575impl FromRedisValue for () {
2576 fn from_redis_value(_v: &Value) -> RedisResult<()> {
2577 Ok(())
2578 }
2579}
2580
2581macro_rules! from_redis_value_for_tuple {
2582 () => ();
2583 ($(#[$meta:meta],)*$($name:ident,)+) => (
2584 $(#[$meta])*
2585 impl<$($name: FromRedisValue),*> FromRedisValue for ($($name,)*) {
2586 #[allow(non_snake_case, unused_variables)]
2589 fn from_redis_value(v: &Value) -> RedisResult<($($name,)*)> {
2590 let v = get_inner_value(v);
2591 let mut n = 0;
2593 $(let $name = (); n += 1;)*
2594
2595 match *v {
2596 Value::Array(ref items) => {
2597 if items.len() != n {
2598 invalid_type_error!(v, "Array response of wrong dimension")
2599 }
2600
2601 let mut i = 0;
2603 Ok(($({let $name = (); from_redis_value(
2604 &items[{ i += 1; i - 1 }])?},)*))
2605 }
2606
2607 Value::Set(ref items) => {
2608 if items.len() != n {
2609 invalid_type_error!(v, "Set response of wrong dimension")
2610 }
2611
2612 let mut i = 0;
2614 Ok(($({let $name = (); from_redis_value(
2615 &items[{ i += 1; i - 1 }])?},)*))
2616 }
2617
2618 Value::Map(ref items) => {
2619 if n != items.len() * 2 {
2620 invalid_type_error!(v, "Map response of wrong dimension")
2621 }
2622
2623 let mut flatten_items = items.iter().map(|(a,b)|[a,b]).flatten();
2624
2625 Ok(($({let $name = (); from_redis_value(
2626 &flatten_items.next().unwrap())?},)*))
2627 }
2628
2629 _ => invalid_type_error!(v, "Not a Array response")
2630 }
2631 }
2632
2633 #[allow(non_snake_case, unused_variables)]
2636 fn from_owned_redis_value(v: Value) -> RedisResult<($($name,)*)> {
2637 let v = get_owned_inner_value(v);
2638 let mut n = 0;
2640 $(let $name = (); n += 1;)*
2641 match v {
2642 Value::Array(mut items) => {
2643 if items.len() != n {
2644 invalid_type_error!(Value::Array(items), "Array response of wrong dimension")
2645 }
2646
2647 let mut i = 0;
2649 Ok(($({let $name = (); from_owned_redis_value(
2650 ::std::mem::replace(&mut items[{ i += 1; i - 1 }], Value::Nil)
2651 )?},)*))
2652 }
2653
2654 Value::Set(mut items) => {
2655 if items.len() != n {
2656 invalid_type_error!(Value::Array(items), "Set response of wrong dimension")
2657 }
2658
2659 let mut i = 0;
2661 Ok(($({let $name = (); from_owned_redis_value(
2662 ::std::mem::replace(&mut items[{ i += 1; i - 1 }], Value::Nil)
2663 )?},)*))
2664 }
2665
2666 Value::Map(items) => {
2667 if n != items.len() * 2 {
2668 invalid_type_error!(Value::Map(items), "Map response of wrong dimension")
2669 }
2670
2671 let mut flatten_items = items.into_iter().map(|(a,b)|[a,b]).flatten();
2672
2673 Ok(($({let $name = (); from_owned_redis_value(
2674 ::std::mem::replace(&mut flatten_items.next().unwrap(), Value::Nil)
2675 )?},)*))
2676 }
2677
2678 _ => invalid_type_error!(v, "Not a Array response")
2679 }
2680 }
2681
2682 #[allow(non_snake_case, unused_variables)]
2683 fn from_redis_values(items: &[Value]) -> RedisResult<Vec<($($name,)*)>> {
2684 let mut n = 0;
2686 $(let $name = (); n += 1;)*
2687 if items.len() == 0 {
2688 return Ok(vec![]);
2689 }
2690
2691 if items.iter().all(|item|item.is_collection_of_len(n)) {
2692 return items.iter().map(|item|from_redis_value(item)).collect();
2693 }
2694
2695 let mut rv = Vec::with_capacity(items.len() / n);
2696 if let [$($name),*] = items{
2697 rv.push(($(from_redis_value($name)?),*),);
2698 return Ok(rv);
2699 }
2700 for chunk in items.chunks_exact(n) {
2701 match chunk {
2702 [$($name),*] => rv.push(($(from_redis_value($name)?),*),),
2703 _ => {},
2704 }
2705 }
2706 Ok(rv)
2707 }
2708
2709 #[allow(non_snake_case, unused_variables)]
2710 fn from_each_owned_redis_values(mut items: Vec<Value>) -> Vec<RedisResult<($($name,)*)>> {
2711
2712 #[allow(unused_parens)]
2713 let extract = |val: ($(RedisResult<$name>),*)| -> RedisResult<($($name,)*)> {
2714 let ($($name),*) = val;
2715 Ok(($($name?),*,))
2716 };
2717
2718 let mut n = 0;
2720 $(let $name = (); n += 1;)*
2721
2722 if items.len() == 0 {
2724 return vec![];
2725 }
2726 if items.iter().all(|item|item.is_collection_of_len(n)) {
2727 return items.into_iter().map(|item|from_owned_redis_value(item)).collect();
2728 }
2729
2730 let mut rv = Vec::with_capacity(items.len() / n);
2731
2732 for chunk in items.chunks_mut(n) {
2733 match chunk {
2734 [$($name),*] => rv.push(extract(($(from_owned_redis_value(std::mem::replace($name, Value::Nil))),*))),
2739 _ => unreachable!(),
2740 }
2741 }
2742 rv
2743 }
2744
2745 #[allow(non_snake_case, unused_variables)]
2746 fn from_owned_redis_values(mut items: Vec<Value>) -> RedisResult<Vec<($($name,)*)>> {
2747 let mut n = 0;
2749 $(let $name = (); n += 1;)*
2750
2751 if items.len() == 0 {
2753 return Ok(vec![])
2754 }
2755 if items.iter().all(|item|item.is_collection_of_len(n)) {
2756 return items.into_iter().map(|item|from_owned_redis_value(item)).collect();
2757 }
2758
2759 let mut rv = Vec::with_capacity(items.len() / n);
2760 for chunk in items.chunks_mut(n) {
2761 match chunk {
2762 [$($name),*] => rv.push(($(from_owned_redis_value(std::mem::replace($name, Value::Nil))?),*),),
2767 _ => unreachable!(),
2768 }
2769 }
2770 Ok(rv)
2771 }
2772 }
2773 )
2774}
2775
2776from_redis_value_for_tuple! { #[cfg_attr(docsrs, doc(fake_variadic))], #[doc = "This trait is implemented for tuples up to 12 items long."], T, }
2777from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, }
2778from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, }
2779from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, }
2780from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, }
2781from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, }
2782from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, }
2783from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, }
2784from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, }
2785from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, }
2786from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
2787from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
2788
2789impl FromRedisValue for InfoDict {
2790 fn from_redis_value(v: &Value) -> RedisResult<InfoDict> {
2791 let v = get_inner_value(v);
2792 let s: String = from_redis_value(v)?;
2793 Ok(InfoDict::new(&s))
2794 }
2795 fn from_owned_redis_value(v: Value) -> RedisResult<InfoDict> {
2796 let v = get_owned_inner_value(v);
2797 let s: String = from_owned_redis_value(v)?;
2798 Ok(InfoDict::new(&s))
2799 }
2800}
2801
2802impl<T: FromRedisValue> FromRedisValue for Option<T> {
2803 fn from_redis_value(v: &Value) -> RedisResult<Option<T>> {
2804 let v = get_inner_value(v);
2805 if *v == Value::Nil {
2806 return Ok(None);
2807 }
2808 Ok(Some(from_redis_value(v)?))
2809 }
2810 fn from_owned_redis_value(v: Value) -> RedisResult<Option<T>> {
2811 let v = get_owned_inner_value(v);
2812 if v == Value::Nil {
2813 return Ok(None);
2814 }
2815 Ok(Some(from_owned_redis_value(v)?))
2816 }
2817}
2818
2819#[cfg(feature = "bytes")]
2820impl FromRedisValue for bytes::Bytes {
2821 fn from_redis_value(v: &Value) -> RedisResult<Self> {
2822 let v = get_inner_value(v);
2823 match v {
2824 Value::BulkString(bytes_vec) => Ok(bytes::Bytes::copy_from_slice(bytes_vec.as_ref())),
2825 _ => invalid_type_error!(v, "Not a bulk string"),
2826 }
2827 }
2828 fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2829 let v = get_owned_inner_value(v);
2830 match v {
2831 Value::BulkString(bytes_vec) => Ok(bytes_vec.into()),
2832 _ => invalid_type_error!(v, "Not a bulk string"),
2833 }
2834 }
2835}
2836
2837#[cfg(feature = "uuid")]
2838impl FromRedisValue for uuid::Uuid {
2839 fn from_redis_value(v: &Value) -> RedisResult<Self> {
2840 match *v {
2841 Value::BulkString(ref bytes) => Ok(uuid::Uuid::from_slice(bytes)?),
2842 _ => invalid_type_error!(v, "Response type not uuid compatible."),
2843 }
2844 }
2845}
2846
2847#[cfg(feature = "uuid")]
2848impl ToRedisArgs for uuid::Uuid {
2849 fn write_redis_args<W>(&self, out: &mut W)
2850 where
2851 W: ?Sized + RedisWrite,
2852 {
2853 out.write_arg(self.as_bytes());
2854 }
2855}
2856
2857pub fn from_redis_value<T: FromRedisValue>(v: &Value) -> RedisResult<T> {
2860 FromRedisValue::from_redis_value(v)
2861}
2862
2863pub fn from_owned_redis_value<T: FromRedisValue>(v: Value) -> RedisResult<T> {
2866 FromRedisValue::from_owned_redis_value(v)
2867}
2868
2869#[derive(Clone, Eq, PartialEq, Default, Debug, Copy)]
2874pub enum ProtocolVersion {
2875 #[default]
2877 RESP2,
2878 RESP3,
2880}
2881
2882#[derive(Clone, Copy)]
2884pub enum ExpireOption {
2885 NONE,
2887 NX,
2889 XX,
2891 GT,
2893 LT,
2895}
2896
2897impl ToRedisArgs for ExpireOption {
2898 fn write_redis_args<W>(&self, out: &mut W)
2899 where
2900 W: ?Sized + RedisWrite,
2901 {
2902 match self {
2903 ExpireOption::NX => out.write_arg(b"NX"),
2904 ExpireOption::XX => out.write_arg(b"XX"),
2905 ExpireOption::GT => out.write_arg(b"GT"),
2906 ExpireOption::LT => out.write_arg(b"LT"),
2907 _ => {}
2908 }
2909 }
2910}
2911
2912#[derive(Debug, Clone, PartialEq)]
2913pub struct PushInfo {
2915 pub kind: PushKind,
2917 pub data: Vec<Value>,
2919}
2920
2921impl PushInfo {
2922 pub(crate) fn disconnect() -> Self {
2923 PushInfo {
2924 kind: crate::PushKind::Disconnection,
2925 data: vec![],
2926 }
2927 }
2928}
2929
2930pub(crate) type SyncPushSender = std::sync::mpsc::Sender<PushInfo>;
2931
2932#[cfg(any(feature = "aio", feature = "r2d2"))]
2934pub(crate) fn closed_connection_error() -> RedisError {
2935 RedisError::from(io::Error::from(io::ErrorKind::BrokenPipe))
2936}
2937
2938#[derive(Debug, Clone, PartialEq)]
2940pub enum ValueType {
2941 String,
2943 List,
2945 Set,
2947 ZSet,
2949 Hash,
2951 Stream,
2953 Unknown(String),
2955}
2956
2957impl<T: AsRef<str>> From<T> for ValueType {
2958 fn from(s: T) -> Self {
2959 match s.as_ref() {
2960 "string" => ValueType::String,
2961 "list" => ValueType::List,
2962 "set" => ValueType::Set,
2963 "zset" => ValueType::ZSet,
2964 "hash" => ValueType::Hash,
2965 "stream" => ValueType::Stream,
2966 s => ValueType::Unknown(s.to_string()),
2967 }
2968 }
2969}
2970
2971impl From<ValueType> for String {
2972 fn from(v: ValueType) -> Self {
2973 match v {
2974 ValueType::String => "string".to_string(),
2975 ValueType::List => "list".to_string(),
2976 ValueType::Set => "set".to_string(),
2977 ValueType::ZSet => "zset".to_string(),
2978 ValueType::Hash => "hash".to_string(),
2979 ValueType::Stream => "stream".to_string(),
2980 ValueType::Unknown(s) => s,
2981 }
2982 }
2983}
2984
2985impl FromRedisValue for ValueType {
2986 fn from_redis_value(v: &Value) -> RedisResult<Self> {
2987 match v {
2988 Value::SimpleString(s) => Ok(s.into()),
2989 _ => invalid_type_error!(v, "Value type should be a simple string"),
2990 }
2991 }
2992
2993 fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2994 match v {
2995 Value::SimpleString(s) => Ok(s.into()),
2996 _ => invalid_type_error!(v, "Value type should be a simple string"),
2997 }
2998 }
2999}
3000
3001#[derive(Debug, PartialEq, Clone)]
3003pub enum IntegerReplyOrNoOp {
3004 IntegerReply(usize),
3006 NotExists,
3008 ExistsButNotRelevant,
3010}
3011
3012impl IntegerReplyOrNoOp {
3013 pub fn raw(&self) -> isize {
3015 match self {
3016 IntegerReplyOrNoOp::IntegerReply(s) => *s as isize,
3017 IntegerReplyOrNoOp::NotExists => -2,
3018 IntegerReplyOrNoOp::ExistsButNotRelevant => -1,
3019 }
3020 }
3021}
3022
3023impl FromRedisValue for IntegerReplyOrNoOp {
3024 fn from_redis_value(v: &Value) -> RedisResult<Self> {
3025 match v {
3026 Value::Int(s) => match s {
3027 -2 => Ok(IntegerReplyOrNoOp::NotExists),
3028 -1 => Ok(IntegerReplyOrNoOp::ExistsButNotRelevant),
3029 _ => Ok(IntegerReplyOrNoOp::IntegerReply(*s as usize)),
3030 },
3031 _ => invalid_type_error!(v, "Value should be an integer"),
3032 }
3033 }
3034
3035 fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
3036 match v {
3037 Value::Int(s) => match s {
3038 -2 => Ok(IntegerReplyOrNoOp::NotExists),
3039 -1 => Ok(IntegerReplyOrNoOp::ExistsButNotRelevant),
3040 _ => Ok(IntegerReplyOrNoOp::IntegerReply(s as usize)),
3041 },
3042 _ => invalid_type_error!(v, "Value should be an integer"),
3043 }
3044 }
3045}
3046
3047impl PartialEq<isize> for IntegerReplyOrNoOp {
3048 fn eq(&self, other: &isize) -> bool {
3049 match self {
3050 IntegerReplyOrNoOp::IntegerReply(s) => *s as isize == *other,
3051 IntegerReplyOrNoOp::NotExists => *other == -2,
3052 IntegerReplyOrNoOp::ExistsButNotRelevant => *other == -1,
3053 }
3054 }
3055}
3056
3057impl PartialEq<usize> for IntegerReplyOrNoOp {
3058 fn eq(&self, other: &usize) -> bool {
3059 match self {
3060 IntegerReplyOrNoOp::IntegerReply(s) => *s == *other,
3061 _ => false,
3062 }
3063 }
3064}
3065
3066impl PartialEq<i32> for IntegerReplyOrNoOp {
3067 fn eq(&self, other: &i32) -> bool {
3068 match self {
3069 IntegerReplyOrNoOp::IntegerReply(s) => *s as i32 == *other,
3070 IntegerReplyOrNoOp::NotExists => *other == -2,
3071 IntegerReplyOrNoOp::ExistsButNotRelevant => *other == -1,
3072 }
3073 }
3074}
3075
3076impl PartialEq<u32> for IntegerReplyOrNoOp {
3077 fn eq(&self, other: &u32) -> bool {
3078 match self {
3079 IntegerReplyOrNoOp::IntegerReply(s) => *s as u32 == *other,
3080 _ => false,
3081 }
3082 }
3083}