redis/
types.rs

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
33/// Helper enum that is used to define expiry time
34pub enum Expiry {
35    /// EX seconds -- Set the specified expire time, in seconds.
36    EX(u64),
37    /// PX milliseconds -- Set the specified expire time, in milliseconds.
38    PX(u64),
39    /// EXAT timestamp-seconds -- Set the specified Unix time at which the key will expire, in seconds.
40    EXAT(u64),
41    /// PXAT timestamp-milliseconds -- Set the specified Unix time at which the key will expire, in milliseconds.
42    PXAT(u64),
43    /// PERSIST -- Remove the time to live associated with the key.
44    PERSIST,
45}
46
47/// Helper enum that is used to define expiry time for SET command
48#[derive(Clone, Copy)]
49pub enum SetExpiry {
50    /// EX seconds -- Set the specified expire time, in seconds.
51    EX(u64),
52    /// PX milliseconds -- Set the specified expire time, in milliseconds.
53    PX(u64),
54    /// EXAT timestamp-seconds -- Set the specified Unix time at which the key will expire, in seconds.
55    EXAT(u64),
56    /// PXAT timestamp-milliseconds -- Set the specified Unix time at which the key will expire, in milliseconds.
57    PXAT(u64),
58    /// KEEPTTL -- Retain the time to live associated with the key.
59    KEEPTTL,
60}
61
62/// Helper enum that is used to define existence checks
63#[derive(Clone, Copy)]
64pub enum ExistenceCheck {
65    /// NX -- Only set the key if it does not already exist.
66    NX,
67    /// XX -- Only set the key if it already exists.
68    XX,
69}
70
71/// Helper enum that is used to define field existence checks
72#[derive(Clone, Copy)]
73pub enum FieldExistenceCheck {
74    /// FNX -- Only set the fields if all do not already exist.
75    FNX,
76    /// FXX -- Only set the fields if all already exist.
77    FXX,
78}
79
80/// Helper enum that is used in some situations to describe
81/// the behavior of arguments in a numeric context.
82#[derive(PartialEq, Eq, Clone, Debug, Copy)]
83pub enum NumericBehavior {
84    /// This argument is not numeric.
85    NonNumeric,
86    /// This argument is an integer.
87    NumberIsInteger,
88    /// This argument is a floating point value.
89    NumberIsFloat,
90}
91
92/// An enum of all error kinds.
93#[derive(PartialEq, Eq, Copy, Clone, Debug)]
94#[non_exhaustive]
95pub enum ErrorKind {
96    /// The server generated an invalid response.
97    ResponseError,
98    /// The parser failed to parse the server response.
99    ParseError,
100    /// The authentication with the server failed.
101    AuthenticationFailed,
102    /// Operation failed because of a type mismatch.
103    TypeError,
104    /// A script execution was aborted.
105    ExecAbortError,
106    /// The server cannot response because it's loading a dump.
107    BusyLoadingError,
108    /// A script that was requested does not actually exist.
109    NoScriptError,
110    /// An error that was caused because the parameter to the
111    /// client were wrong.
112    InvalidClientConfig,
113    /// Raised if a key moved to a different node.
114    Moved,
115    /// Raised if a key moved to a different node but we need to ask.
116    Ask,
117    /// Raised if a request needs to be retried.
118    TryAgain,
119    /// Raised if a redis cluster is down.
120    ClusterDown,
121    /// A request spans multiple slots
122    CrossSlot,
123    /// A cluster master is unavailable.
124    MasterDown,
125    /// This kind is returned if the redis error is one that is
126    /// not native to the system.  This is usually the case if
127    /// the cause is another error.
128    IoError,
129    /// An error raised that was identified on the client before execution.
130    ClientError,
131    /// An extension error.  This is an error created by the server
132    /// that is not directly understood by the library.
133    ExtensionError,
134    /// Attempt to write to a read-only server
135    ReadOnly,
136    /// Requested name not found among masters returned by the sentinels
137    MasterNameNotFoundBySentinel,
138    /// No valid replicas found in the sentinels, for a given master name
139    NoValidReplicasFoundBySentinel,
140    /// At least one sentinel connection info is required
141    EmptySentinelList,
142    /// Attempted to kill a script/function while they werent' executing
143    NotBusy,
144    /// Used when a cluster connection cannot find a connection to a valid node.
145    ClusterConnectionNotFound,
146    /// Attempted to unsubscribe on a connection that is not in subscribed mode.
147    NoSub,
148
149    #[cfg(feature = "json")]
150    /// Error Serializing a struct to JSON form
151    Serialize,
152
153    /// Redis Servers prior to v6.0.0 doesn't support RESP3.
154    /// Try disabling resp3 option
155    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        // TODO - Consider changing RedisError to explicitly represent whether an error came from the server or not. Today it is only implied.
227        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/// Internal low-level redis value enum.
256#[derive(PartialEq, Clone)]
257pub enum Value {
258    /// A nil response from the server.
259    Nil,
260    /// An integer response.  Note that there are a few situations
261    /// in which redis actually returns a string for an integer which
262    /// is why this library generally treats integers and strings
263    /// the same for all numeric responses.
264    Int(i64),
265    /// An arbitrary binary data, usually represents a binary-safe string.
266    BulkString(Vec<u8>),
267    /// A response containing an array with more data. This is generally used by redis
268    /// to express nested structures.
269    Array(Vec<Value>),
270    /// A simple string response, without line breaks and not binary safe.
271    SimpleString(String),
272    /// A status response which represents the string "OK".
273    Okay,
274    /// Unordered key,value list from the server. Use `as_map_iter` function.
275    Map(Vec<(Value, Value)>),
276    /// Attribute value from the server. Client will give data instead of whole Attribute type.
277    Attribute {
278        /// Data that attributes belong to.
279        data: Box<Value>,
280        /// Key,Value list of attributes.
281        attributes: Vec<(Value, Value)>,
282    },
283    /// Unordered set value from the server.
284    Set(Vec<Value>),
285    /// A floating number response from the server.
286    Double(f64),
287    /// A boolean response from the server.
288    Boolean(bool),
289    /// First String is format and other is the string
290    VerbatimString {
291        /// Text's format type
292        format: VerbatimFormat,
293        /// Remaining string check format before using!
294        text: String,
295    },
296    /// Very large number that out of the range of the signed 64 bit numbers
297    BigNumber(BigInt),
298    /// Push data from the server.
299    Push {
300        /// Push Kind
301        kind: PushKind,
302        /// Remaining data from push message
303        data: Vec<Value>,
304    },
305    /// Represents an error message from the server
306    ServerError(ServerError),
307}
308
309/// `VerbatimString`'s format types defined by spec
310#[derive(PartialEq, Clone, Debug)]
311pub enum VerbatimFormat {
312    /// Unknown type to catch future formats.
313    Unknown(String),
314    /// `mkd` format
315    Markdown,
316    /// `txt` format
317    Text,
318}
319
320/// `Push` type's currently known kinds.
321#[derive(PartialEq, Clone, Debug)]
322pub enum PushKind {
323    /// `Disconnection` is sent from the **library** when connection is closed.
324    Disconnection,
325    /// Other kind to catch future kinds.
326    Other(String),
327    /// `invalidate` is received when a key is changed/deleted.
328    Invalidate,
329    /// `message` is received when pubsub message published by another client.
330    Message,
331    /// `pmessage` is received when pubsub message published by another client and client subscribed to topic via pattern.
332    PMessage,
333    /// `smessage` is received when pubsub message published by another client and client subscribed to it with sharding.
334    SMessage,
335    /// `unsubscribe` is received when client unsubscribed from a channel.
336    Unsubscribe,
337    /// `punsubscribe` is received when client unsubscribed from a pattern.
338    PUnsubscribe,
339    /// `sunsubscribe` is received when client unsubscribed from a shard channel.
340    SUnsubscribe,
341    /// `subscribe` is received when client subscribed to a channel.
342    Subscribe,
343    /// `psubscribe` is received when client subscribed to a pattern.
344    PSubscribe,
345    /// `ssubscribe` is received when client subscribed to a shard channel.
346    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
445/// Values are generally not used directly unless you are using the
446/// more low level functionality in the library.  For the most part
447/// this is hidden with the help of the `FromRedisValue` trait.
448///
449/// While on the redis protocol there is an error type this is already
450/// separated at an early point so the value only holds the remaining
451/// types.
452impl Value {
453    /// Checks if the return value looks like it fulfils the cursor
454    /// protocol.  That means the result is an array item of length
455    /// two with the first one being a cursor and the second an
456    /// array response.
457    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    /// Returns an `&[Value]` if `self` is compatible with a sequence type
470    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    /// Returns a `Vec<Value>` if `self` is compatible with a sequence type,
480    /// otherwise returns `Err(self)`.
481    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    /// Returns an iterator of `(&Value, &Value)` if `self` is compatible with a map type
491    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    /// Returns an iterator of `(Value, Value)` if `self` is compatible with a map type.
506    /// If not, returns `Err(self)`.
507    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    /// If value contains a server error, return it as an Err. Otherwise wrap the value in Ok.
522    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
556impl fmt::Debug for Value {
557    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
558        match *self {
559            Value::Nil => write!(fmt, "nil"),
560            Value::Int(val) => write!(fmt, "int({val:?})"),
561            Value::BulkString(ref val) => match from_utf8(val) {
562                Ok(x) => write!(fmt, "bulk-string('{x:?}')"),
563                Err(_) => write!(fmt, "binary-data({val:?})"),
564            },
565            Value::Array(ref values) => write!(fmt, "array({values:?})"),
566            Value::Push { ref kind, ref data } => write!(fmt, "push({kind:?}, {data:?})"),
567            Value::Okay => write!(fmt, "ok"),
568            Value::SimpleString(ref s) => write!(fmt, "simple-string({s:?})"),
569            Value::Map(ref values) => write!(fmt, "map({values:?})"),
570            Value::Attribute {
571                ref data,
572                attributes: _,
573            } => write!(fmt, "attribute({data:?})"),
574            Value::Set(ref values) => write!(fmt, "set({values:?})"),
575            Value::Double(ref d) => write!(fmt, "double({d:?})"),
576            Value::Boolean(ref b) => write!(fmt, "boolean({b:?})"),
577            Value::VerbatimString {
578                ref format,
579                ref text,
580            } => {
581                write!(fmt, "verbatim-string({:?},{:?})", format, text)
582            }
583            Value::BigNumber(ref m) => write!(fmt, "big-number({:?})", m),
584            Value::ServerError(ref err) => match err.details() {
585                Some(details) => write!(fmt, "Server error: `{}: {details}`", err.code()),
586                None => write!(fmt, "Server error: `{}`", err.code()),
587            },
588        }
589    }
590}
591
592/// Represents a redis error.
593///
594/// For the most part you should be using the Error trait to interact with this
595/// rather than the actual struct.
596pub struct RedisError {
597    repr: ErrorRepr,
598}
599
600#[cfg(feature = "json")]
601impl From<serde_json::Error> for RedisError {
602    fn from(serde_err: serde_json::Error) -> RedisError {
603        RedisError::from((
604            ErrorKind::Serialize,
605            "Serialization Error",
606            format!("{serde_err}"),
607        ))
608    }
609}
610
611#[derive(Debug)]
612enum ErrorRepr {
613    WithDescription(ErrorKind, &'static str),
614    WithDescriptionAndDetail(ErrorKind, &'static str, String),
615    ExtensionError(String, String),
616    IoError(io::Error),
617}
618
619impl PartialEq for RedisError {
620    fn eq(&self, other: &RedisError) -> bool {
621        match (&self.repr, &other.repr) {
622            (&ErrorRepr::WithDescription(kind_a, _), &ErrorRepr::WithDescription(kind_b, _)) => {
623                kind_a == kind_b
624            }
625            (
626                &ErrorRepr::WithDescriptionAndDetail(kind_a, _, _),
627                &ErrorRepr::WithDescriptionAndDetail(kind_b, _, _),
628            ) => kind_a == kind_b,
629            (ErrorRepr::ExtensionError(a, _), ErrorRepr::ExtensionError(b, _)) => *a == *b,
630            _ => false,
631        }
632    }
633}
634
635impl From<io::Error> for RedisError {
636    fn from(err: io::Error) -> RedisError {
637        RedisError {
638            repr: ErrorRepr::IoError(err),
639        }
640    }
641}
642
643impl From<Utf8Error> for RedisError {
644    fn from(_: Utf8Error) -> RedisError {
645        RedisError {
646            repr: ErrorRepr::WithDescription(ErrorKind::TypeError, "Invalid UTF-8"),
647        }
648    }
649}
650
651impl From<NulError> for RedisError {
652    fn from(err: NulError) -> RedisError {
653        RedisError {
654            repr: ErrorRepr::WithDescriptionAndDetail(
655                ErrorKind::TypeError,
656                "Value contains interior nul terminator",
657                err.to_string(),
658            ),
659        }
660    }
661}
662
663#[cfg(feature = "tls-native-tls")]
664impl From<native_tls::Error> for RedisError {
665    fn from(err: native_tls::Error) -> RedisError {
666        RedisError {
667            repr: ErrorRepr::WithDescriptionAndDetail(
668                ErrorKind::IoError,
669                "TLS error",
670                err.to_string(),
671            ),
672        }
673    }
674}
675
676#[cfg(feature = "tls-rustls")]
677impl From<rustls::Error> for RedisError {
678    fn from(err: rustls::Error) -> RedisError {
679        RedisError {
680            repr: ErrorRepr::WithDescriptionAndDetail(
681                ErrorKind::IoError,
682                "TLS error",
683                err.to_string(),
684            ),
685        }
686    }
687}
688
689#[cfg(feature = "tls-rustls")]
690impl From<rustls::pki_types::InvalidDnsNameError> for RedisError {
691    fn from(err: rustls::pki_types::InvalidDnsNameError) -> RedisError {
692        RedisError {
693            repr: ErrorRepr::WithDescriptionAndDetail(
694                ErrorKind::IoError,
695                "TLS Error",
696                err.to_string(),
697            ),
698        }
699    }
700}
701
702#[cfg(feature = "tls-rustls")]
703impl From<rustls_native_certs::Error> for RedisError {
704    fn from(err: rustls_native_certs::Error) -> RedisError {
705        RedisError {
706            repr: ErrorRepr::WithDescriptionAndDetail(
707                ErrorKind::IoError,
708                "Fetch certs Error",
709                err.to_string(),
710            ),
711        }
712    }
713}
714
715#[cfg(feature = "uuid")]
716impl From<uuid::Error> for RedisError {
717    fn from(err: uuid::Error) -> RedisError {
718        RedisError {
719            repr: ErrorRepr::WithDescriptionAndDetail(
720                ErrorKind::TypeError,
721                "Value is not a valid UUID",
722                err.to_string(),
723            ),
724        }
725    }
726}
727
728impl From<FromUtf8Error> for RedisError {
729    fn from(_: FromUtf8Error) -> RedisError {
730        RedisError {
731            repr: ErrorRepr::WithDescription(ErrorKind::TypeError, "Cannot convert from UTF-8"),
732        }
733    }
734}
735
736impl From<(ErrorKind, &'static str)> for RedisError {
737    fn from((kind, desc): (ErrorKind, &'static str)) -> RedisError {
738        RedisError {
739            repr: ErrorRepr::WithDescription(kind, desc),
740        }
741    }
742}
743
744impl From<(ErrorKind, &'static str, String)> for RedisError {
745    fn from((kind, desc, detail): (ErrorKind, &'static str, String)) -> RedisError {
746        RedisError {
747            repr: ErrorRepr::WithDescriptionAndDetail(kind, desc, detail),
748        }
749    }
750}
751
752impl error::Error for RedisError {
753    #[allow(deprecated)]
754    fn description(&self) -> &str {
755        match self.repr {
756            ErrorRepr::WithDescription(_, desc) => desc,
757            ErrorRepr::WithDescriptionAndDetail(_, desc, _) => desc,
758            ErrorRepr::ExtensionError(_, _) => "extension error",
759            ErrorRepr::IoError(ref err) => err.description(),
760        }
761    }
762
763    fn cause(&self) -> Option<&dyn error::Error> {
764        match self.repr {
765            ErrorRepr::IoError(ref err) => Some(err as &dyn error::Error),
766            _ => None,
767        }
768    }
769
770    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
771        match self.repr {
772            ErrorRepr::IoError(ref err) => Some(err),
773            _ => None,
774        }
775    }
776}
777
778impl fmt::Display for RedisError {
779    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
780        match self.repr {
781            ErrorRepr::WithDescription(kind, desc) => {
782                desc.fmt(f)?;
783                f.write_str("- ")?;
784                fmt::Debug::fmt(&kind, f)
785            }
786            ErrorRepr::WithDescriptionAndDetail(kind, desc, ref detail) => {
787                desc.fmt(f)?;
788                f.write_str(" - ")?;
789                fmt::Debug::fmt(&kind, f)?;
790                f.write_str(": ")?;
791                detail.fmt(f)
792            }
793            ErrorRepr::ExtensionError(ref code, ref detail) => {
794                code.fmt(f)?;
795                f.write_str(": ")?;
796                detail.fmt(f)
797            }
798            ErrorRepr::IoError(ref err) => err.fmt(f),
799        }
800    }
801}
802
803impl fmt::Debug for RedisError {
804    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
805        fmt::Display::fmt(self, f)
806    }
807}
808
809/// What method should be used if retrying this request.
810#[non_exhaustive]
811pub enum RetryMethod {
812    /// Create a fresh connection, since the current connection is no longer usable.
813    Reconnect,
814    /// Don't retry, this is a permanent error.
815    NoRetry,
816    /// Retry immediately, this doesn't require a wait.
817    RetryImmediately,
818    /// Retry after sleeping to avoid overloading the external service.
819    WaitAndRetry,
820    /// The key has moved to a different node but we have to ask which node, this is only relevant for clusters.
821    AskRedirect,
822    /// The key has moved to a different node, this is only relevant for clusters.
823    MovedRedirect,
824    /// Reconnect the initial connection to the master cluster, this is only relevant for clusters.
825    ReconnectFromInitialConnections,
826}
827
828/// Indicates a general failure in the library.
829impl RedisError {
830    /// Returns the kind of the error.
831    pub fn kind(&self) -> ErrorKind {
832        match self.repr {
833            ErrorRepr::WithDescription(kind, _)
834            | ErrorRepr::WithDescriptionAndDetail(kind, _, _) => kind,
835            ErrorRepr::ExtensionError(_, _) => ErrorKind::ExtensionError,
836            ErrorRepr::IoError(_) => ErrorKind::IoError,
837        }
838    }
839
840    /// Returns the error detail.
841    pub fn detail(&self) -> Option<&str> {
842        match self.repr {
843            ErrorRepr::WithDescriptionAndDetail(_, _, ref detail)
844            | ErrorRepr::ExtensionError(_, ref detail) => Some(detail.as_str()),
845            _ => None,
846        }
847    }
848
849    /// Returns the raw error code if available.
850    pub fn code(&self) -> Option<&str> {
851        match self.kind() {
852            ErrorKind::ResponseError => Some("ERR"),
853            ErrorKind::ExecAbortError => Some("EXECABORT"),
854            ErrorKind::BusyLoadingError => Some("LOADING"),
855            ErrorKind::NoScriptError => Some("NOSCRIPT"),
856            ErrorKind::Moved => Some("MOVED"),
857            ErrorKind::Ask => Some("ASK"),
858            ErrorKind::TryAgain => Some("TRYAGAIN"),
859            ErrorKind::ClusterDown => Some("CLUSTERDOWN"),
860            ErrorKind::CrossSlot => Some("CROSSSLOT"),
861            ErrorKind::MasterDown => Some("MASTERDOWN"),
862            ErrorKind::ReadOnly => Some("READONLY"),
863            ErrorKind::NotBusy => Some("NOTBUSY"),
864            _ => match self.repr {
865                ErrorRepr::ExtensionError(ref code, _) => Some(code),
866                _ => None,
867            },
868        }
869    }
870
871    /// Returns the name of the error category for display purposes.
872    pub fn category(&self) -> &str {
873        match self.kind() {
874            ErrorKind::ResponseError => "response error",
875            ErrorKind::AuthenticationFailed => "authentication failed",
876            ErrorKind::TypeError => "type error",
877            ErrorKind::ExecAbortError => "script execution aborted",
878            ErrorKind::BusyLoadingError => "busy loading",
879            ErrorKind::NoScriptError => "no script",
880            ErrorKind::InvalidClientConfig => "invalid client config",
881            ErrorKind::Moved => "key moved",
882            ErrorKind::Ask => "key moved (ask)",
883            ErrorKind::TryAgain => "try again",
884            ErrorKind::ClusterDown => "cluster down",
885            ErrorKind::CrossSlot => "cross-slot",
886            ErrorKind::MasterDown => "master down",
887            ErrorKind::IoError => "I/O error",
888            ErrorKind::ExtensionError => "extension error",
889            ErrorKind::ClientError => "client error",
890            ErrorKind::ReadOnly => "read-only",
891            ErrorKind::MasterNameNotFoundBySentinel => "master name not found by sentinel",
892            ErrorKind::NoValidReplicasFoundBySentinel => "no valid replicas found by sentinel",
893            ErrorKind::EmptySentinelList => "empty sentinel list",
894            ErrorKind::NotBusy => "not busy",
895            ErrorKind::ClusterConnectionNotFound => "connection to node in cluster not found",
896            #[cfg(feature = "json")]
897            ErrorKind::Serialize => "serializing",
898            ErrorKind::RESP3NotSupported => "resp3 is not supported by server",
899            ErrorKind::ParseError => "parse error",
900            ErrorKind::NoSub => {
901                "Server declined unsubscribe related command in non-subscribed mode"
902            }
903        }
904    }
905
906    /// Indicates that this failure is an IO failure.
907    pub fn is_io_error(&self) -> bool {
908        self.kind() == ErrorKind::IoError
909    }
910
911    pub(crate) fn as_io_error(&self) -> Option<&io::Error> {
912        match &self.repr {
913            ErrorRepr::IoError(e) => Some(e),
914            _ => None,
915        }
916    }
917
918    /// Indicates that this is a cluster error.
919    pub fn is_cluster_error(&self) -> bool {
920        matches!(
921            self.kind(),
922            ErrorKind::Moved | ErrorKind::Ask | ErrorKind::TryAgain | ErrorKind::ClusterDown
923        )
924    }
925
926    /// Returns true if this error indicates that the connection was
927    /// refused.  You should generally not rely much on this function
928    /// unless you are writing unit tests that want to detect if a
929    /// local server is available.
930    pub fn is_connection_refusal(&self) -> bool {
931        match self.repr {
932            ErrorRepr::IoError(ref err) => {
933                #[allow(clippy::match_like_matches_macro)]
934                match err.kind() {
935                    io::ErrorKind::ConnectionRefused => true,
936                    // if we connect to a unix socket and the file does not
937                    // exist yet, then we want to treat this as if it was a
938                    // connection refusal.
939                    io::ErrorKind::NotFound => cfg!(unix),
940                    _ => false,
941                }
942            }
943            _ => false,
944        }
945    }
946
947    /// Returns true if error was caused by I/O time out.
948    /// Note that this may not be accurate depending on platform.
949    pub fn is_timeout(&self) -> bool {
950        match self.repr {
951            ErrorRepr::IoError(ref err) => matches!(
952                err.kind(),
953                io::ErrorKind::TimedOut | io::ErrorKind::WouldBlock
954            ),
955            _ => false,
956        }
957    }
958
959    /// Returns true if error was caused by a dropped connection.
960    pub fn is_connection_dropped(&self) -> bool {
961        match self.repr {
962            ErrorRepr::IoError(ref err) => matches!(
963                err.kind(),
964                io::ErrorKind::BrokenPipe
965                    | io::ErrorKind::ConnectionReset
966                    | io::ErrorKind::UnexpectedEof
967            ),
968            _ => false,
969        }
970    }
971
972    /// Returns true if the error is likely to not be recoverable, and the connection must be replaced.
973    pub fn is_unrecoverable_error(&self) -> bool {
974        match self.retry_method() {
975            RetryMethod::Reconnect => true,
976            RetryMethod::ReconnectFromInitialConnections => true,
977
978            RetryMethod::NoRetry => false,
979            RetryMethod::RetryImmediately => false,
980            RetryMethod::WaitAndRetry => false,
981            RetryMethod::AskRedirect => false,
982            RetryMethod::MovedRedirect => false,
983        }
984    }
985
986    /// Returns the node the error refers to.
987    ///
988    /// This returns `(addr, slot_id)`.
989    pub fn redirect_node(&self) -> Option<(&str, u16)> {
990        match self.kind() {
991            ErrorKind::Ask | ErrorKind::Moved => (),
992            _ => return None,
993        }
994        let mut iter = self.detail()?.split_ascii_whitespace();
995        let slot_id: u16 = iter.next()?.parse().ok()?;
996        let addr = iter.next()?;
997        Some((addr, slot_id))
998    }
999
1000    /// Returns the extension error code.
1001    ///
1002    /// This method should not be used because every time the redis library
1003    /// adds support for a new error code it would disappear form this method.
1004    /// `code()` always returns the code.
1005    #[deprecated(note = "use code() instead")]
1006    pub fn extension_error_code(&self) -> Option<&str> {
1007        match self.repr {
1008            ErrorRepr::ExtensionError(ref code, _) => Some(code),
1009            _ => None,
1010        }
1011    }
1012
1013    /// Clone the `RedisError`, throwing away non-cloneable parts of an `IoError`.
1014    ///
1015    /// Deriving `Clone` is not possible because the wrapped `io::Error` is not
1016    /// cloneable.
1017    ///
1018    /// The `ioerror_description` parameter will be prepended to the message in
1019    /// case an `IoError` is found.
1020    #[cfg(feature = "connection-manager")] // Used to avoid "unused method" warning
1021    pub(crate) fn clone_mostly(&self, ioerror_description: &'static str) -> Self {
1022        let repr = match self.repr {
1023            ErrorRepr::WithDescription(kind, desc) => ErrorRepr::WithDescription(kind, desc),
1024            ErrorRepr::WithDescriptionAndDetail(kind, desc, ref detail) => {
1025                ErrorRepr::WithDescriptionAndDetail(kind, desc, detail.clone())
1026            }
1027            ErrorRepr::ExtensionError(ref code, ref detail) => {
1028                ErrorRepr::ExtensionError(code.clone(), detail.clone())
1029            }
1030            ErrorRepr::IoError(ref e) => ErrorRepr::IoError(io::Error::new(
1031                e.kind(),
1032                format!("{ioerror_description}: {e}"),
1033            )),
1034        };
1035        Self { repr }
1036    }
1037
1038    /// Specifies what method (if any) should be used to retry this request.
1039    ///
1040    /// If you are using the cluster api retrying of requests is already handled by the library.
1041    ///
1042    /// This isn't precise, and internally the library uses multiple other considerations rather
1043    /// than just the error kind on when to retry.
1044    pub fn retry_method(&self) -> RetryMethod {
1045        match self.kind() {
1046            ErrorKind::Moved => RetryMethod::MovedRedirect,
1047            ErrorKind::Ask => RetryMethod::AskRedirect,
1048
1049            ErrorKind::TryAgain => RetryMethod::WaitAndRetry,
1050            ErrorKind::MasterDown => RetryMethod::WaitAndRetry,
1051            ErrorKind::ClusterDown => RetryMethod::WaitAndRetry,
1052            ErrorKind::BusyLoadingError => RetryMethod::WaitAndRetry,
1053            ErrorKind::MasterNameNotFoundBySentinel => RetryMethod::WaitAndRetry,
1054            ErrorKind::NoValidReplicasFoundBySentinel => RetryMethod::WaitAndRetry,
1055
1056            ErrorKind::ResponseError => RetryMethod::NoRetry,
1057            ErrorKind::ReadOnly => RetryMethod::NoRetry,
1058            ErrorKind::ExtensionError => RetryMethod::NoRetry,
1059            ErrorKind::ExecAbortError => RetryMethod::NoRetry,
1060            ErrorKind::TypeError => RetryMethod::NoRetry,
1061            ErrorKind::NoScriptError => RetryMethod::NoRetry,
1062            ErrorKind::InvalidClientConfig => RetryMethod::NoRetry,
1063            ErrorKind::CrossSlot => RetryMethod::NoRetry,
1064            ErrorKind::ClientError => RetryMethod::NoRetry,
1065            ErrorKind::EmptySentinelList => RetryMethod::NoRetry,
1066            ErrorKind::NotBusy => RetryMethod::NoRetry,
1067            #[cfg(feature = "json")]
1068            ErrorKind::Serialize => RetryMethod::NoRetry,
1069            ErrorKind::RESP3NotSupported => RetryMethod::NoRetry,
1070            ErrorKind::NoSub => RetryMethod::NoRetry,
1071
1072            ErrorKind::ParseError => RetryMethod::Reconnect,
1073            ErrorKind::AuthenticationFailed => RetryMethod::Reconnect,
1074            ErrorKind::ClusterConnectionNotFound => RetryMethod::ReconnectFromInitialConnections,
1075
1076            ErrorKind::IoError => match &self.repr {
1077                ErrorRepr::IoError(err) => match err.kind() {
1078                    io::ErrorKind::ConnectionRefused => RetryMethod::Reconnect,
1079                    io::ErrorKind::NotFound => RetryMethod::Reconnect,
1080                    io::ErrorKind::ConnectionReset => RetryMethod::Reconnect,
1081                    io::ErrorKind::ConnectionAborted => RetryMethod::Reconnect,
1082                    io::ErrorKind::NotConnected => RetryMethod::Reconnect,
1083                    io::ErrorKind::BrokenPipe => RetryMethod::Reconnect,
1084                    io::ErrorKind::UnexpectedEof => RetryMethod::Reconnect,
1085
1086                    io::ErrorKind::PermissionDenied => RetryMethod::NoRetry,
1087                    io::ErrorKind::Unsupported => RetryMethod::NoRetry,
1088
1089                    _ => RetryMethod::RetryImmediately,
1090                },
1091                _ => RetryMethod::RetryImmediately,
1092            },
1093        }
1094    }
1095}
1096
1097/// Creates a new Redis error with the `ExtensionError` kind.
1098///
1099/// This function is used to create Redis errors for extension error codes
1100/// that are not directly understood by the library.
1101///
1102/// # Arguments
1103///
1104/// * `code` - The error code string returned by the Redis server
1105/// * `detail` - Optional detailed error message. If None, a default message is used.
1106///
1107/// # Returns
1108///
1109/// A `RedisError` with the `ExtensionError` kind.
1110pub fn make_extension_error(code: String, detail: Option<String>) -> RedisError {
1111    RedisError {
1112        repr: ErrorRepr::ExtensionError(
1113            code,
1114            match detail {
1115                Some(x) => x,
1116                None => "Unknown extension error encountered".to_string(),
1117            },
1118        ),
1119    }
1120}
1121
1122/// Library generic result type.
1123pub type RedisResult<T> = Result<T, RedisError>;
1124
1125/// Library generic future type.
1126#[cfg(feature = "aio")]
1127pub type RedisFuture<'a, T> = futures_util::future::BoxFuture<'a, RedisResult<T>>;
1128
1129/// An info dictionary type.
1130#[derive(Debug, Clone)]
1131pub struct InfoDict {
1132    map: HashMap<String, Value>,
1133}
1134
1135/// This type provides convenient access to key/value data returned by
1136/// the "INFO" command.  It acts like a regular mapping but also has
1137/// a convenience method `get` which can return data in the appropriate
1138/// type.
1139///
1140/// For instance this can be used to query the server for the role it's
1141/// in (master, slave) etc:
1142///
1143/// ```rust,no_run
1144/// # fn do_something() -> redis::RedisResult<()> {
1145/// # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
1146/// # let mut con = client.get_connection().unwrap();
1147/// let info : redis::InfoDict = redis::cmd("INFO").query(&mut con)?;
1148/// let role : Option<String> = info.get("role");
1149/// # Ok(()) }
1150/// ```
1151impl InfoDict {
1152    /// Creates a new info dictionary from a string in the response of
1153    /// the INFO command.  Each line is a key, value pair with the
1154    /// key and value separated by a colon (`:`).  Lines starting with a
1155    /// hash (`#`) are ignored.
1156    pub fn new(kvpairs: &str) -> InfoDict {
1157        let mut map = HashMap::new();
1158        for line in kvpairs.lines() {
1159            if line.is_empty() || line.starts_with('#') {
1160                continue;
1161            }
1162            let mut p = line.splitn(2, ':');
1163            let (k, v) = match (p.next(), p.next()) {
1164                (Some(k), Some(v)) => (k.to_string(), v.to_string()),
1165                _ => continue,
1166            };
1167            map.insert(k, Value::SimpleString(v));
1168        }
1169        InfoDict { map }
1170    }
1171
1172    /// Fetches a value by key and converts it into the given type.
1173    /// Typical types are `String`, `bool` and integer types.
1174    pub fn get<T: FromRedisValue>(&self, key: &str) -> Option<T> {
1175        match self.find(&key) {
1176            Some(x) => from_redis_value(x).ok(),
1177            None => None,
1178        }
1179    }
1180
1181    /// Looks up a key in the info dict.
1182    pub fn find(&self, key: &&str) -> Option<&Value> {
1183        self.map.get(*key)
1184    }
1185
1186    /// Checks if a key is contained in the info dicf.
1187    pub fn contains_key(&self, key: &&str) -> bool {
1188        self.find(key).is_some()
1189    }
1190
1191    /// Returns the size of the info dict.
1192    pub fn len(&self) -> usize {
1193        self.map.len()
1194    }
1195
1196    /// Checks if the dict is empty.
1197    pub fn is_empty(&self) -> bool {
1198        self.map.is_empty()
1199    }
1200}
1201
1202impl Deref for InfoDict {
1203    type Target = HashMap<String, Value>;
1204
1205    fn deref(&self) -> &Self::Target {
1206        &self.map
1207    }
1208}
1209
1210/// High level representation of response to the [`ROLE`][1] command.
1211///
1212/// [1]: https://redis.io/docs/latest/commands/role/
1213#[derive(Debug, Clone, Eq, PartialEq)]
1214pub enum Role {
1215    /// Represents a primary role, which is `master` in legacy Redis terminology.
1216    Primary {
1217        /// The current primary replication offset
1218        replication_offset: u64,
1219        /// List of replica, each represented by a tuple of IP, port and the last acknowledged replication offset.
1220        replicas: Vec<ReplicaInfo>,
1221    },
1222    /// Represents a replica role, which is `slave` in legacy Redis terminology.
1223    Replica {
1224        /// The IP of the primary.
1225        primary_ip: String,
1226        /// The port of the primary.
1227        primary_port: u16,
1228        /// The state of the replication from the point of view of the primary.
1229        replication_state: String,
1230        /// The amount of data received from the replica so far in terms of primary replication offset.
1231        data_received: u64,
1232    },
1233    /// Represents a sentinel role.
1234    Sentinel {
1235        /// List of primary names monitored by this Sentinel instance.
1236        primary_names: Vec<String>,
1237    },
1238}
1239
1240/// Replication information for a replica, as returned by the [`ROLE`][1] command.
1241///
1242/// [1]: https://redis.io/docs/latest/commands/role/
1243#[derive(Debug, Clone, Eq, PartialEq)]
1244pub struct ReplicaInfo {
1245    /// The IP of the replica.
1246    pub ip: String,
1247    /// The port of the replica.
1248    pub port: u16,
1249    /// The last acknowledged replication offset.
1250    pub replication_offset: i64,
1251}
1252
1253impl FromRedisValue for ReplicaInfo {
1254    fn from_redis_value(v: &Value) -> RedisResult<Self> {
1255        Self::from_owned_redis_value(v.clone())
1256    }
1257
1258    fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
1259        let v = match get_owned_inner_value(v).into_sequence() {
1260            Ok(v) => v,
1261            Err(v) => invalid_type_error!(v, "Replica response should be an array"),
1262        };
1263        if v.len() < 3 {
1264            invalid_type_error!(v, "Replica array is too short, expected 3 elements")
1265        }
1266        let mut v = v.into_iter();
1267        let ip = from_owned_redis_value(v.next().expect("len was checked"))?;
1268        let port = from_owned_redis_value(v.next().expect("len was checked"))?;
1269        let offset = from_owned_redis_value(v.next().expect("len was checked"))?;
1270        Ok(ReplicaInfo {
1271            ip,
1272            port,
1273            replication_offset: offset,
1274        })
1275    }
1276}
1277
1278impl FromRedisValue for Role {
1279    fn from_redis_value(v: &Value) -> RedisResult<Self> {
1280        Self::from_owned_redis_value(v.clone())
1281    }
1282
1283    fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
1284        let v = match get_owned_inner_value(v).into_sequence() {
1285            Ok(v) => v,
1286            Err(v) => invalid_type_error!(v, "Role response should be an array"),
1287        };
1288        if v.len() < 2 {
1289            invalid_type_error!(v, "Role array is too short, expected at least 2 elements")
1290        }
1291        match &v[0] {
1292            Value::BulkString(role) => match role.as_slice() {
1293                b"master" => Role::new_primary(v),
1294                b"slave" => Role::new_replica(v),
1295                b"sentinel" => Role::new_sentinel(v),
1296                _ => invalid_type_error!(v, "Role type is not master, slave or sentinel"),
1297            },
1298            _ => invalid_type_error!(v, "Role type is not a bulk string"),
1299        }
1300    }
1301}
1302
1303impl Role {
1304    fn new_primary(values: Vec<Value>) -> RedisResult<Self> {
1305        if values.len() < 3 {
1306            invalid_type_error!(
1307                values,
1308                "Role primary response too short, expected 3 elements"
1309            )
1310        }
1311
1312        let mut values = values.into_iter();
1313        _ = values.next();
1314
1315        let replication_offset = from_owned_redis_value(values.next().expect("len was checked"))?;
1316        let replicas = from_owned_redis_value(values.next().expect("len was checked"))?;
1317
1318        Ok(Role::Primary {
1319            replication_offset,
1320            replicas,
1321        })
1322    }
1323
1324    fn new_replica(values: Vec<Value>) -> RedisResult<Self> {
1325        if values.len() < 5 {
1326            invalid_type_error!(
1327                values,
1328                "Role replica response too short, expected 5 elements"
1329            )
1330        }
1331
1332        let mut values = values.into_iter();
1333        _ = values.next();
1334
1335        let primary_ip = from_owned_redis_value(values.next().expect("len was checked"))?;
1336        let primary_port = from_owned_redis_value(values.next().expect("len was checked"))?;
1337        let replication_state = from_owned_redis_value(values.next().expect("len was checked"))?;
1338        let data_received = from_owned_redis_value(values.next().expect("len was checked"))?;
1339
1340        Ok(Role::Replica {
1341            primary_ip,
1342            primary_port,
1343            replication_state,
1344            data_received,
1345        })
1346    }
1347
1348    fn new_sentinel(values: Vec<Value>) -> RedisResult<Self> {
1349        if values.len() < 2 {
1350            invalid_type_error!(
1351                values,
1352                "Role sentinel response too short, expected at least 2 elements"
1353            )
1354        }
1355        let second_val = values.into_iter().nth(1).expect("len was checked");
1356        let primary_names = from_owned_redis_value(second_val)?;
1357        Ok(Role::Sentinel { primary_names })
1358    }
1359}
1360
1361/// Abstraction trait for redis command abstractions.
1362pub trait RedisWrite {
1363    /// Accepts a serialized redis command.
1364    fn write_arg(&mut self, arg: &[u8]);
1365
1366    /// Accepts a serialized redis command.
1367    fn write_arg_fmt(&mut self, arg: impl fmt::Display) {
1368        self.write_arg(arg.to_string().as_bytes())
1369    }
1370
1371    /// Appends an empty argument to the command, and returns a
1372    /// [`std::io::Write`] instance that can write to it.
1373    ///
1374    /// Writing multiple arguments into this buffer is unsupported. The resulting
1375    /// data will be interpreted as one argument by Redis.
1376    ///
1377    /// Writing no data is supported and is similar to having an empty bytestring
1378    /// as an argument.
1379    fn writer_for_next_arg(&mut self) -> impl std::io::Write + '_;
1380
1381    /// Reserve space for `additional` arguments in the command
1382    ///
1383    /// `additional` is a list of the byte sizes of the arguments.
1384    ///
1385    /// # Examples
1386    /// Sending some Protobufs with `prost` to Redis.
1387    /// ```rust,ignore
1388    /// use prost::Message;
1389    ///
1390    /// let to_send: Vec<SomeType> = todo!();
1391    /// let mut cmd = Cmd::new();
1392    ///
1393    /// // Calculate and reserve the space for the args
1394    /// cmd.reserve_space_for_args(to_send.iter().map(Message::encoded_len));
1395    ///
1396    /// // Write the args to the buffer
1397    /// for arg in to_send {
1398    ///     // Encode the type directly into the Cmd buffer
1399    ///     // Supplying the required capacity again is not needed for Cmd,
1400    ///     // but can be useful for other implementers like Vec<Vec<u8>>.
1401    ///     arg.encode(cmd.bufmut_for_next_arg(arg.encoded_len()));
1402    /// }
1403    ///
1404    /// ```
1405    ///
1406    /// # Implementation note
1407    /// The default implementation provided by this trait is a no-op. It's therefore strongly
1408    /// recommended to implement this function. Depending on the internal buffer it might only
1409    /// be possible to use the numbers of arguments (`additional.len()`) or the total expected
1410    /// capacity (`additional.iter().sum()`). Implementors should assume that the caller will
1411    /// be wrong and might over or under specify the amount of arguments and space required.
1412    fn reserve_space_for_args(&mut self, additional: impl IntoIterator<Item = usize>) {
1413        // _additional would show up in the documentation, so we assign it
1414        // to make it used.
1415        let _do_nothing = additional;
1416    }
1417
1418    #[cfg(feature = "bytes")]
1419    /// Appends an empty argument to the command, and returns a
1420    /// [`bytes::BufMut`] instance that can write to it.
1421    ///
1422    /// `capacity` should be equal or greater to the amount of bytes
1423    /// expected, as some implementations might not be able to resize
1424    /// the returned buffer.
1425    ///
1426    /// Writing multiple arguments into this buffer is unsupported. The resulting
1427    /// data will be interpreted as one argument by Redis.
1428    ///
1429    /// Writing no data is supported and is similar to having an empty bytestring
1430    /// as an argument.
1431    fn bufmut_for_next_arg(&mut self, capacity: usize) -> impl bytes::BufMut + '_ {
1432        // This default implementation is not the most efficient, but does
1433        // allow for implementers to skip this function. This means that
1434        // upstream libraries that implement this trait don't suddenly
1435        // stop working because someone enabled one of the async features.
1436
1437        /// Has a temporary buffer that is written to [`writer_for_next_arg`]
1438        /// on drop.
1439        struct Wrapper<'a> {
1440            /// The buffer, implements [`bytes::BufMut`] allowing passthrough
1441            buf: Vec<u8>,
1442            /// The writer to the command, used on drop
1443            writer: Box<dyn std::io::Write + 'a>,
1444        }
1445        unsafe impl bytes::BufMut for Wrapper<'_> {
1446            fn remaining_mut(&self) -> usize {
1447                self.buf.remaining_mut()
1448            }
1449
1450            unsafe fn advance_mut(&mut self, cnt: usize) {
1451                self.buf.advance_mut(cnt);
1452            }
1453
1454            fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
1455                self.buf.chunk_mut()
1456            }
1457
1458            // Vec specializes these methods, so we do too
1459            fn put<T: bytes::buf::Buf>(&mut self, src: T)
1460            where
1461                Self: Sized,
1462            {
1463                self.buf.put(src);
1464            }
1465
1466            fn put_slice(&mut self, src: &[u8]) {
1467                self.buf.put_slice(src);
1468            }
1469
1470            fn put_bytes(&mut self, val: u8, cnt: usize) {
1471                self.buf.put_bytes(val, cnt);
1472            }
1473        }
1474        impl Drop for Wrapper<'_> {
1475            fn drop(&mut self) {
1476                self.writer.write_all(&self.buf).unwrap()
1477            }
1478        }
1479
1480        Wrapper {
1481            buf: Vec::with_capacity(capacity),
1482            writer: Box::new(self.writer_for_next_arg()),
1483        }
1484    }
1485}
1486
1487impl RedisWrite for Vec<Vec<u8>> {
1488    fn write_arg(&mut self, arg: &[u8]) {
1489        self.push(arg.to_owned());
1490    }
1491
1492    fn write_arg_fmt(&mut self, arg: impl fmt::Display) {
1493        self.push(arg.to_string().into_bytes())
1494    }
1495
1496    fn writer_for_next_arg(&mut self) -> impl std::io::Write + '_ {
1497        self.push(Vec::new());
1498        self.last_mut().unwrap()
1499    }
1500
1501    fn reserve_space_for_args(&mut self, additional: impl IntoIterator<Item = usize>) {
1502        // It would be nice to do this, but there's no way to store where we currently are.
1503        // Checking for the first empty Vec is not possible, as it's valid to write empty args.
1504        // self.extend(additional.iter().copied().map(Vec::with_capacity));
1505        // So we just reserve space for the extra args and have to forgo the extra optimisation
1506        self.reserve(additional.into_iter().count());
1507    }
1508
1509    #[cfg(feature = "bytes")]
1510    fn bufmut_for_next_arg(&mut self, capacity: usize) -> impl bytes::BufMut + '_ {
1511        self.push(Vec::with_capacity(capacity));
1512        self.last_mut().unwrap()
1513    }
1514}
1515
1516/// Used to convert a value into one or multiple redis argument
1517/// strings.  Most values will produce exactly one item but in
1518/// some cases it might make sense to produce more than one.
1519pub trait ToRedisArgs: Sized {
1520    /// This converts the value into a vector of bytes.  Each item
1521    /// is a single argument.  Most items generate a vector of a
1522    /// single item.
1523    ///
1524    /// The exception to this rule currently are vectors of items.
1525    fn to_redis_args(&self) -> Vec<Vec<u8>> {
1526        let mut out = Vec::new();
1527        self.write_redis_args(&mut out);
1528        out
1529    }
1530
1531    /// This writes the value into a vector of bytes.  Each item
1532    /// is a single argument.  Most items generate a single item.
1533    ///
1534    /// The exception to this rule currently are vectors of items.
1535    fn write_redis_args<W>(&self, out: &mut W)
1536    where
1537        W: ?Sized + RedisWrite;
1538
1539    /// Returns an information about the contained value with regards
1540    /// to it's numeric behavior in a redis context.  This is used in
1541    /// some high level concepts to switch between different implementations
1542    /// of redis functions (for instance `INCR` vs `INCRBYFLOAT`).
1543    fn describe_numeric_behavior(&self) -> NumericBehavior {
1544        NumericBehavior::NonNumeric
1545    }
1546
1547    /// Returns the number of arguments this value will generate.
1548    ///
1549    /// This is used in some high level functions to intelligently switch
1550    /// between `GET` and `MGET` variants. Also, for some commands like HEXPIREDAT
1551    /// which require a specific number of arguments, this method can be used to
1552    /// know the number of arguments.
1553    fn num_of_args(&self) -> usize {
1554        1
1555    }
1556
1557    /// This only exists internally as a workaround for the lack of
1558    /// specialization.
1559    #[doc(hidden)]
1560    fn write_args_from_slice<W>(items: &[Self], out: &mut W)
1561    where
1562        W: ?Sized + RedisWrite,
1563    {
1564        Self::make_arg_iter_ref(items.iter(), out)
1565    }
1566
1567    /// This only exists internally as a workaround for the lack of
1568    /// specialization.
1569    #[doc(hidden)]
1570    fn make_arg_iter_ref<'a, I, W>(items: I, out: &mut W)
1571    where
1572        W: ?Sized + RedisWrite,
1573        I: Iterator<Item = &'a Self>,
1574        Self: 'a,
1575    {
1576        for item in items {
1577            item.write_redis_args(out);
1578        }
1579    }
1580
1581    #[doc(hidden)]
1582    fn is_single_vec_arg(items: &[Self]) -> bool {
1583        items.len() == 1 && items[0].num_of_args() <= 1
1584    }
1585}
1586
1587macro_rules! itoa_based_to_redis_impl {
1588    ($t:ty, $numeric:expr) => {
1589        impl ToRedisArgs for $t {
1590            fn write_redis_args<W>(&self, out: &mut W)
1591            where
1592                W: ?Sized + RedisWrite,
1593            {
1594                let mut buf = ::itoa::Buffer::new();
1595                let s = buf.format(*self);
1596                out.write_arg(s.as_bytes())
1597            }
1598
1599            fn describe_numeric_behavior(&self) -> NumericBehavior {
1600                $numeric
1601            }
1602        }
1603    };
1604}
1605
1606macro_rules! non_zero_itoa_based_to_redis_impl {
1607    ($t:ty, $numeric:expr) => {
1608        impl ToRedisArgs for $t {
1609            fn write_redis_args<W>(&self, out: &mut W)
1610            where
1611                W: ?Sized + RedisWrite,
1612            {
1613                let mut buf = ::itoa::Buffer::new();
1614                let s = buf.format(self.get());
1615                out.write_arg(s.as_bytes())
1616            }
1617
1618            fn describe_numeric_behavior(&self) -> NumericBehavior {
1619                $numeric
1620            }
1621        }
1622    };
1623}
1624
1625macro_rules! ryu_based_to_redis_impl {
1626    ($t:ty, $numeric:expr) => {
1627        impl ToRedisArgs for $t {
1628            fn write_redis_args<W>(&self, out: &mut W)
1629            where
1630                W: ?Sized + RedisWrite,
1631            {
1632                let mut buf = ::ryu::Buffer::new();
1633                let s = buf.format(*self);
1634                out.write_arg(s.as_bytes())
1635            }
1636
1637            fn describe_numeric_behavior(&self) -> NumericBehavior {
1638                $numeric
1639            }
1640        }
1641    };
1642}
1643
1644impl ToRedisArgs for u8 {
1645    fn write_redis_args<W>(&self, out: &mut W)
1646    where
1647        W: ?Sized + RedisWrite,
1648    {
1649        let mut buf = ::itoa::Buffer::new();
1650        let s = buf.format(*self);
1651        out.write_arg(s.as_bytes())
1652    }
1653
1654    fn write_args_from_slice<W>(items: &[u8], out: &mut W)
1655    where
1656        W: ?Sized + RedisWrite,
1657    {
1658        out.write_arg(items);
1659    }
1660
1661    fn is_single_vec_arg(_items: &[u8]) -> bool {
1662        true
1663    }
1664}
1665
1666itoa_based_to_redis_impl!(i8, NumericBehavior::NumberIsInteger);
1667itoa_based_to_redis_impl!(i16, NumericBehavior::NumberIsInteger);
1668itoa_based_to_redis_impl!(u16, NumericBehavior::NumberIsInteger);
1669itoa_based_to_redis_impl!(i32, NumericBehavior::NumberIsInteger);
1670itoa_based_to_redis_impl!(u32, NumericBehavior::NumberIsInteger);
1671itoa_based_to_redis_impl!(i64, NumericBehavior::NumberIsInteger);
1672itoa_based_to_redis_impl!(u64, NumericBehavior::NumberIsInteger);
1673itoa_based_to_redis_impl!(i128, NumericBehavior::NumberIsInteger);
1674itoa_based_to_redis_impl!(u128, NumericBehavior::NumberIsInteger);
1675itoa_based_to_redis_impl!(isize, NumericBehavior::NumberIsInteger);
1676itoa_based_to_redis_impl!(usize, NumericBehavior::NumberIsInteger);
1677
1678non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU8, NumericBehavior::NumberIsInteger);
1679non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI8, NumericBehavior::NumberIsInteger);
1680non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU16, NumericBehavior::NumberIsInteger);
1681non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI16, NumericBehavior::NumberIsInteger);
1682non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU32, NumericBehavior::NumberIsInteger);
1683non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI32, NumericBehavior::NumberIsInteger);
1684non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU64, NumericBehavior::NumberIsInteger);
1685non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI64, NumericBehavior::NumberIsInteger);
1686non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU128, NumericBehavior::NumberIsInteger);
1687non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI128, NumericBehavior::NumberIsInteger);
1688non_zero_itoa_based_to_redis_impl!(core::num::NonZeroUsize, NumericBehavior::NumberIsInteger);
1689non_zero_itoa_based_to_redis_impl!(core::num::NonZeroIsize, NumericBehavior::NumberIsInteger);
1690
1691ryu_based_to_redis_impl!(f32, NumericBehavior::NumberIsFloat);
1692ryu_based_to_redis_impl!(f64, NumericBehavior::NumberIsFloat);
1693
1694#[cfg(any(
1695    feature = "rust_decimal",
1696    feature = "bigdecimal",
1697    feature = "num-bigint"
1698))]
1699macro_rules! bignum_to_redis_impl {
1700    ($t:ty) => {
1701        impl ToRedisArgs for $t {
1702            fn write_redis_args<W>(&self, out: &mut W)
1703            where
1704                W: ?Sized + RedisWrite,
1705            {
1706                out.write_arg(&self.to_string().into_bytes())
1707            }
1708        }
1709    };
1710}
1711
1712#[cfg(feature = "rust_decimal")]
1713bignum_to_redis_impl!(rust_decimal::Decimal);
1714#[cfg(feature = "bigdecimal")]
1715bignum_to_redis_impl!(bigdecimal::BigDecimal);
1716#[cfg(feature = "num-bigint")]
1717bignum_to_redis_impl!(num_bigint::BigInt);
1718#[cfg(feature = "num-bigint")]
1719bignum_to_redis_impl!(num_bigint::BigUint);
1720
1721impl ToRedisArgs for bool {
1722    fn write_redis_args<W>(&self, out: &mut W)
1723    where
1724        W: ?Sized + RedisWrite,
1725    {
1726        out.write_arg(if *self { b"1" } else { b"0" })
1727    }
1728}
1729
1730impl ToRedisArgs for String {
1731    fn write_redis_args<W>(&self, out: &mut W)
1732    where
1733        W: ?Sized + RedisWrite,
1734    {
1735        out.write_arg(self.as_bytes())
1736    }
1737}
1738
1739impl ToRedisArgs for &str {
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<'a, T> ToRedisArgs for Cow<'a, T>
1749where
1750    T: ToOwned + ?Sized,
1751    &'a T: ToRedisArgs,
1752    for<'b> &'b T::Owned: ToRedisArgs,
1753{
1754    fn write_redis_args<W>(&self, out: &mut W)
1755    where
1756        W: ?Sized + RedisWrite,
1757    {
1758        match self {
1759            Cow::Borrowed(inner) => inner.write_redis_args(out),
1760            Cow::Owned(inner) => inner.write_redis_args(out),
1761        }
1762    }
1763}
1764
1765impl<T: ToRedisArgs> ToRedisArgs for Vec<T> {
1766    fn write_redis_args<W>(&self, out: &mut W)
1767    where
1768        W: ?Sized + RedisWrite,
1769    {
1770        ToRedisArgs::write_args_from_slice(self, out)
1771    }
1772
1773    fn num_of_args(&self) -> usize {
1774        if ToRedisArgs::is_single_vec_arg(&self[..]) {
1775            return 1;
1776        }
1777        if self.len() == 1 {
1778            self[0].num_of_args()
1779        } else {
1780            self.len()
1781        }
1782    }
1783}
1784
1785impl<T: ToRedisArgs> ToRedisArgs for &[T] {
1786    fn write_redis_args<W>(&self, out: &mut W)
1787    where
1788        W: ?Sized + RedisWrite,
1789    {
1790        ToRedisArgs::write_args_from_slice(self, out)
1791    }
1792
1793    fn num_of_args(&self) -> usize {
1794        if ToRedisArgs::is_single_vec_arg(&self[..]) {
1795            return 1;
1796        }
1797        if self.len() == 1 {
1798            self[0].num_of_args()
1799        } else {
1800            self.len()
1801        }
1802    }
1803}
1804
1805impl<T: ToRedisArgs> ToRedisArgs for Option<T> {
1806    fn write_redis_args<W>(&self, out: &mut W)
1807    where
1808        W: ?Sized + RedisWrite,
1809    {
1810        if let Some(ref x) = *self {
1811            x.write_redis_args(out);
1812        }
1813    }
1814
1815    fn describe_numeric_behavior(&self) -> NumericBehavior {
1816        match *self {
1817            Some(ref x) => x.describe_numeric_behavior(),
1818            None => NumericBehavior::NonNumeric,
1819        }
1820    }
1821
1822    fn num_of_args(&self) -> usize {
1823        match *self {
1824            Some(ref x) => x.num_of_args(),
1825            None => 0,
1826        }
1827    }
1828}
1829
1830macro_rules! deref_to_write_redis_args_impl {
1831    (
1832        $(#[$attr:meta])*
1833        <$($desc:tt)+
1834    ) => {
1835        $(#[$attr])*
1836        impl <$($desc)+ {
1837            #[inline]
1838            fn write_redis_args<W>(&self, out: &mut W)
1839                where
1840                W: ?Sized + RedisWrite,
1841            {
1842                (**self).write_redis_args(out)
1843            }
1844
1845            fn num_of_args(&self) -> usize {
1846                (**self).num_of_args()
1847            }
1848
1849            fn describe_numeric_behavior(&self) -> NumericBehavior {
1850                (**self).describe_numeric_behavior()
1851            }
1852        }
1853    };
1854}
1855
1856deref_to_write_redis_args_impl! {
1857    <'a, T> ToRedisArgs for &'a T where T: ToRedisArgs
1858}
1859
1860deref_to_write_redis_args_impl! {
1861    <'a, T> ToRedisArgs for &'a mut T where T: ToRedisArgs
1862}
1863
1864deref_to_write_redis_args_impl! {
1865    <T> ToRedisArgs for Box<T> where T: ToRedisArgs
1866}
1867
1868deref_to_write_redis_args_impl! {
1869    <T> ToRedisArgs for std::sync::Arc<T> where T: ToRedisArgs
1870}
1871
1872deref_to_write_redis_args_impl! {
1873    <T> ToRedisArgs for std::rc::Rc<T> where T: ToRedisArgs
1874}
1875
1876/// @note: Redis cannot store empty sets so the application has to
1877/// check whether the set is empty and if so, not attempt to use that
1878/// result
1879macro_rules! impl_to_redis_args_for_set {
1880    (for <$($TypeParam:ident),+> $SetType:ty, where ($($WhereClause:tt)+) ) => {
1881        impl< $($TypeParam),+ > ToRedisArgs for $SetType
1882        where
1883            $($WhereClause)+
1884        {
1885            fn write_redis_args<W>(&self, out: &mut W)
1886            where
1887                W: ?Sized + RedisWrite,
1888            {
1889                ToRedisArgs::make_arg_iter_ref(self.iter(), out)
1890            }
1891
1892            fn num_of_args(&self) -> usize {
1893                self.len()
1894            }
1895        }
1896    };
1897}
1898
1899impl_to_redis_args_for_set!(
1900    for <T, S> std::collections::HashSet<T, S>,
1901    where (T: ToRedisArgs + Hash + Eq, S: BuildHasher + Default)
1902);
1903
1904impl_to_redis_args_for_set!(
1905    for <T> std::collections::BTreeSet<T>,
1906    where (T: ToRedisArgs + Hash + Eq + Ord)
1907);
1908
1909#[cfg(feature = "hashbrown")]
1910impl_to_redis_args_for_set!(
1911    for <T, S> hashbrown::HashSet<T, S>,
1912    where (T: ToRedisArgs + Hash + Eq, S: BuildHasher + Default)
1913);
1914
1915#[cfg(feature = "ahash")]
1916impl_to_redis_args_for_set!(
1917    for <T, S> ahash::AHashSet<T, S>,
1918    where (T: ToRedisArgs + Hash + Eq, S: BuildHasher + Default)
1919);
1920
1921/// @note: Redis cannot store empty maps so the application has to
1922/// check whether the set is empty and if so, not attempt to use that
1923/// result
1924macro_rules! impl_to_redis_args_for_map {
1925    (
1926        $(#[$meta:meta])*
1927        for <$($TypeParam:ident),+> $MapType:ty,
1928        where ($($WhereClause:tt)+)
1929    ) => {
1930        $(#[$meta])*
1931        impl< $($TypeParam),+ > ToRedisArgs for $MapType
1932        where
1933            $($WhereClause)+
1934        {
1935            fn write_redis_args<W>(&self, out: &mut W)
1936            where
1937                W: ?Sized + RedisWrite,
1938            {
1939                for (key, value) in self {
1940                    // Ensure key and value produce a single argument each
1941                    assert!(key.num_of_args() <= 1 && value.num_of_args() <= 1);
1942                    key.write_redis_args(out);
1943                    value.write_redis_args(out);
1944                }
1945            }
1946
1947            fn num_of_args(&self) -> usize {
1948                self.len()
1949            }
1950        }
1951    };
1952}
1953impl_to_redis_args_for_map!(
1954    for <K, V> std::collections::HashMap<K, V>,
1955    where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1956);
1957
1958impl_to_redis_args_for_map!(
1959    /// this flattens BTreeMap into something that goes well with HMSET
1960    for <K, V> std::collections::BTreeMap<K, V>,
1961    where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1962);
1963
1964#[cfg(feature = "hashbrown")]
1965impl_to_redis_args_for_map!(
1966    for <K, V> hashbrown::HashMap<K, V>,
1967    where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1968);
1969
1970macro_rules! to_redis_args_for_tuple {
1971    () => ();
1972    ($(#[$meta:meta],)*$($name:ident,)+) => (
1973        $(#[$meta])*
1974        impl<$($name: ToRedisArgs),*> ToRedisArgs for ($($name,)*) {
1975            // we have local variables named T1 as dummies and those
1976            // variables are unused.
1977            #[allow(non_snake_case, unused_variables)]
1978            fn write_redis_args<W>(&self, out: &mut W) where W: ?Sized + RedisWrite {
1979                let ($(ref $name,)*) = *self;
1980                $($name.write_redis_args(out);)*
1981            }
1982
1983            #[allow(non_snake_case, unused_variables)]
1984            fn num_of_args(&self) -> usize {
1985                let mut n: usize = 0;
1986                $(let $name = (); n += 1;)*
1987                n
1988            }
1989        }
1990    )
1991}
1992
1993to_redis_args_for_tuple! { #[cfg_attr(docsrs, doc(fake_variadic))], #[doc = "This trait is implemented for tuples up to 12 items long."], T, }
1994to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, }
1995to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, }
1996to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, }
1997to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, }
1998to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, }
1999to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, }
2000to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, }
2001to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, }
2002to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, }
2003to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
2004to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
2005
2006impl<T: ToRedisArgs, const N: usize> ToRedisArgs for &[T; N] {
2007    fn write_redis_args<W>(&self, out: &mut W)
2008    where
2009        W: ?Sized + RedisWrite,
2010    {
2011        ToRedisArgs::write_args_from_slice(self.as_slice(), out)
2012    }
2013
2014    fn num_of_args(&self) -> usize {
2015        if ToRedisArgs::is_single_vec_arg(&self[..]) {
2016            return 1;
2017        }
2018        if self.len() == 1 {
2019            self[0].num_of_args()
2020        } else {
2021            self.len()
2022        }
2023    }
2024}
2025
2026fn vec_to_array<T, const N: usize>(items: Vec<T>, original_value: &Value) -> RedisResult<[T; N]> {
2027    match items.try_into() {
2028        Ok(array) => Ok(array),
2029        Err(items) => {
2030            let msg = format!(
2031                "Response has wrong dimension, expected {N}, got {}",
2032                items.len()
2033            );
2034            invalid_type_error!(original_value, msg)
2035        }
2036    }
2037}
2038
2039impl<T: FromRedisValue, const N: usize> FromRedisValue for [T; N] {
2040    fn from_redis_value(value: &Value) -> RedisResult<[T; N]> {
2041        match *value {
2042            Value::BulkString(ref bytes) => match FromRedisValue::from_byte_vec(bytes) {
2043                Some(items) => vec_to_array(items, value),
2044                None => {
2045                    let msg = format!(
2046                        "Conversion to Array[{}; {N}] failed",
2047                        std::any::type_name::<T>()
2048                    );
2049                    invalid_type_error!(value, msg)
2050                }
2051            },
2052            Value::Array(ref items) => {
2053                let items = FromRedisValue::from_redis_values(items)?;
2054                vec_to_array(items, value)
2055            }
2056            Value::Nil => vec_to_array(vec![], value),
2057            _ => invalid_type_error!(value, "Response type not array compatible"),
2058        }
2059    }
2060}
2061
2062/// This trait is used to convert a redis value into a more appropriate
2063/// type.
2064///
2065/// While a redis `Value` can represent any response that comes
2066/// back from the redis server, usually you want to map this into something
2067/// that works better in rust.  For instance you might want to convert the
2068/// return value into a `String` or an integer.
2069///
2070/// This trait is well supported throughout the library and you can
2071/// implement it for your own types if you want.
2072///
2073/// In addition to what you can see from the docs, this is also implemented
2074/// for tuples up to size 12 and for `Vec<u8>`.
2075pub trait FromRedisValue: Sized {
2076    /// Given a redis `Value` this attempts to convert it into the given
2077    /// destination type.  If that fails because it's not compatible an
2078    /// appropriate error is generated.
2079    fn from_redis_value(v: &Value) -> RedisResult<Self>;
2080
2081    /// Given a redis `Value` this attempts to convert it into the given
2082    /// destination type.  If that fails because it's not compatible an
2083    /// appropriate error is generated.
2084    fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2085        // By default, fall back to `from_redis_value`.
2086        // This function only needs to be implemented if it can benefit
2087        // from taking `v` by value.
2088        Self::from_redis_value(&v)
2089    }
2090
2091    /// Similar to `from_redis_value` but constructs a vector of objects
2092    /// from another vector of values.  This primarily exists internally
2093    /// to customize the behavior for vectors of tuples.
2094    fn from_redis_values(items: &[Value]) -> RedisResult<Vec<Self>> {
2095        items.iter().map(FromRedisValue::from_redis_value).collect()
2096    }
2097
2098    /// The same as `from_redis_values`, but takes a `Vec<Value>` instead
2099    /// of a `&[Value]`.
2100    fn from_owned_redis_values(items: Vec<Value>) -> RedisResult<Vec<Self>> {
2101        items
2102            .into_iter()
2103            .map(FromRedisValue::from_owned_redis_value)
2104            .collect()
2105    }
2106
2107    /// The same as `from_owned_redis_values`, but returns a result for each
2108    /// conversion to make handling them case-by-case possible.
2109    fn from_each_owned_redis_values(items: Vec<Value>) -> Vec<RedisResult<Self>> {
2110        items
2111            .into_iter()
2112            .map(FromRedisValue::from_owned_redis_value)
2113            .collect()
2114    }
2115
2116    /// Convert bytes to a single element vector.
2117    fn from_byte_vec(_vec: &[u8]) -> Option<Vec<Self>> {
2118        Self::from_owned_redis_value(Value::BulkString(_vec.into()))
2119            .map(|rv| vec![rv])
2120            .ok()
2121    }
2122
2123    /// Convert bytes to a single element vector.
2124    fn from_owned_byte_vec(_vec: Vec<u8>) -> RedisResult<Vec<Self>> {
2125        Self::from_owned_redis_value(Value::BulkString(_vec)).map(|rv| vec![rv])
2126    }
2127}
2128
2129fn get_inner_value(v: &Value) -> &Value {
2130    if let Value::Attribute {
2131        data,
2132        attributes: _,
2133    } = v
2134    {
2135        data.as_ref()
2136    } else {
2137        v
2138    }
2139}
2140
2141fn get_owned_inner_value(v: Value) -> Value {
2142    if let Value::Attribute {
2143        data,
2144        attributes: _,
2145    } = v
2146    {
2147        *data
2148    } else {
2149        v
2150    }
2151}
2152
2153macro_rules! from_redis_value_for_num_internal {
2154    ($t:ty, $v:expr) => {{
2155        let v = if let Value::Attribute {
2156            data,
2157            attributes: _,
2158        } = $v
2159        {
2160            data
2161        } else {
2162            $v
2163        };
2164        match *v {
2165            Value::Int(val) => Ok(val as $t),
2166            Value::SimpleString(ref s) => match s.parse::<$t>() {
2167                Ok(rv) => Ok(rv),
2168                Err(_) => invalid_type_error!(v, "Could not convert from string."),
2169            },
2170            Value::BulkString(ref bytes) => match from_utf8(bytes)?.parse::<$t>() {
2171                Ok(rv) => Ok(rv),
2172                Err(_) => invalid_type_error!(v, "Could not convert from string."),
2173            },
2174            Value::Double(val) => Ok(val as $t),
2175            _ => invalid_type_error!(v, "Response type not convertible to numeric."),
2176        }
2177    }};
2178}
2179
2180macro_rules! from_redis_value_for_num {
2181    ($t:ty) => {
2182        impl FromRedisValue for $t {
2183            fn from_redis_value(v: &Value) -> RedisResult<$t> {
2184                from_redis_value_for_num_internal!($t, v)
2185            }
2186        }
2187    };
2188}
2189
2190impl FromRedisValue for u8 {
2191    fn from_redis_value(v: &Value) -> RedisResult<u8> {
2192        from_redis_value_for_num_internal!(u8, v)
2193    }
2194
2195    // this hack allows us to specialize Vec<u8> to work with binary data.
2196    fn from_byte_vec(vec: &[u8]) -> Option<Vec<u8>> {
2197        Some(vec.to_vec())
2198    }
2199    fn from_owned_byte_vec(vec: Vec<u8>) -> RedisResult<Vec<u8>> {
2200        Ok(vec)
2201    }
2202}
2203
2204from_redis_value_for_num!(i8);
2205from_redis_value_for_num!(i16);
2206from_redis_value_for_num!(u16);
2207from_redis_value_for_num!(i32);
2208from_redis_value_for_num!(u32);
2209from_redis_value_for_num!(i64);
2210from_redis_value_for_num!(u64);
2211from_redis_value_for_num!(i128);
2212from_redis_value_for_num!(u128);
2213from_redis_value_for_num!(f32);
2214from_redis_value_for_num!(f64);
2215from_redis_value_for_num!(isize);
2216from_redis_value_for_num!(usize);
2217
2218#[cfg(any(
2219    feature = "rust_decimal",
2220    feature = "bigdecimal",
2221    feature = "num-bigint"
2222))]
2223macro_rules! from_redis_value_for_bignum_internal {
2224    ($t:ty, $v:expr) => {{
2225        let v = $v;
2226        match *v {
2227            Value::Int(val) => <$t>::try_from(val)
2228                .map_err(|_| invalid_type_error_inner!(v, "Could not convert from integer.")),
2229            Value::SimpleString(ref s) => match s.parse::<$t>() {
2230                Ok(rv) => Ok(rv),
2231                Err(_) => invalid_type_error!(v, "Could not convert from string."),
2232            },
2233            Value::BulkString(ref bytes) => match from_utf8(bytes)?.parse::<$t>() {
2234                Ok(rv) => Ok(rv),
2235                Err(_) => invalid_type_error!(v, "Could not convert from string."),
2236            },
2237            _ => invalid_type_error!(v, "Response type not convertible to numeric."),
2238        }
2239    }};
2240}
2241
2242#[cfg(any(
2243    feature = "rust_decimal",
2244    feature = "bigdecimal",
2245    feature = "num-bigint"
2246))]
2247macro_rules! from_redis_value_for_bignum {
2248    ($t:ty) => {
2249        impl FromRedisValue for $t {
2250            fn from_redis_value(v: &Value) -> RedisResult<$t> {
2251                from_redis_value_for_bignum_internal!($t, v)
2252            }
2253        }
2254    };
2255}
2256
2257#[cfg(feature = "rust_decimal")]
2258from_redis_value_for_bignum!(rust_decimal::Decimal);
2259#[cfg(feature = "bigdecimal")]
2260from_redis_value_for_bignum!(bigdecimal::BigDecimal);
2261#[cfg(feature = "num-bigint")]
2262from_redis_value_for_bignum!(num_bigint::BigInt);
2263#[cfg(feature = "num-bigint")]
2264from_redis_value_for_bignum!(num_bigint::BigUint);
2265
2266impl FromRedisValue for bool {
2267    fn from_redis_value(v: &Value) -> RedisResult<bool> {
2268        let v = get_inner_value(v);
2269        match *v {
2270            Value::Nil => Ok(false),
2271            Value::Int(val) => Ok(val != 0),
2272            Value::SimpleString(ref s) => {
2273                if &s[..] == "1" {
2274                    Ok(true)
2275                } else if &s[..] == "0" {
2276                    Ok(false)
2277                } else {
2278                    invalid_type_error!(v, "Response status not valid boolean");
2279                }
2280            }
2281            Value::BulkString(ref bytes) => {
2282                if bytes == b"1" {
2283                    Ok(true)
2284                } else if bytes == b"0" {
2285                    Ok(false)
2286                } else {
2287                    invalid_type_error!(v, "Response type not bool compatible.");
2288                }
2289            }
2290            Value::Boolean(b) => Ok(b),
2291            Value::Okay => Ok(true),
2292            _ => invalid_type_error!(v, "Response type not bool compatible."),
2293        }
2294    }
2295}
2296
2297impl FromRedisValue for CString {
2298    fn from_redis_value(v: &Value) -> RedisResult<CString> {
2299        let v = get_inner_value(v);
2300        match *v {
2301            Value::BulkString(ref bytes) => Ok(CString::new(bytes.as_slice())?),
2302            Value::Okay => Ok(CString::new("OK")?),
2303            Value::SimpleString(ref val) => Ok(CString::new(val.as_bytes())?),
2304            _ => invalid_type_error!(v, "Response type not CString compatible."),
2305        }
2306    }
2307    fn from_owned_redis_value(v: Value) -> RedisResult<CString> {
2308        let v = get_owned_inner_value(v);
2309        match v {
2310            Value::BulkString(bytes) => Ok(CString::new(bytes)?),
2311            Value::Okay => Ok(CString::new("OK")?),
2312            Value::SimpleString(val) => Ok(CString::new(val)?),
2313            _ => invalid_type_error!(v, "Response type not CString compatible."),
2314        }
2315    }
2316}
2317
2318impl FromRedisValue for String {
2319    fn from_redis_value(v: &Value) -> RedisResult<Self> {
2320        let v = get_inner_value(v);
2321        match *v {
2322            Value::BulkString(ref bytes) => Ok(from_utf8(bytes)?.to_string()),
2323            Value::Okay => Ok("OK".to_string()),
2324            Value::SimpleString(ref val) => Ok(val.to_string()),
2325            Value::VerbatimString {
2326                format: _,
2327                ref text,
2328            } => Ok(text.to_string()),
2329            Value::Double(ref val) => Ok(val.to_string()),
2330            Value::Int(val) => Ok(val.to_string()),
2331            _ => invalid_type_error!(v, "Response type not string compatible."),
2332        }
2333    }
2334
2335    fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2336        let v = get_owned_inner_value(v);
2337        match v {
2338            Value::BulkString(bytes) => Ok(Self::from_utf8(bytes)?),
2339            Value::Okay => Ok("OK".to_string()),
2340            Value::SimpleString(val) => Ok(val),
2341            Value::VerbatimString { format: _, text } => Ok(text),
2342            Value::Double(val) => Ok(val.to_string()),
2343            Value::Int(val) => Ok(val.to_string()),
2344            _ => invalid_type_error!(v, "Response type not string compatible."),
2345        }
2346    }
2347}
2348
2349macro_rules! pointer_from_redis_value_impl {
2350    (
2351        $(#[$attr:meta])*
2352        $id:ident, $ty:ty, $func:expr
2353    ) => {
2354        $(#[$attr])*
2355        impl<$id:  FromRedisValue> FromRedisValue for $ty {
2356            fn from_redis_value(v: &Value) -> RedisResult<Self>
2357            {
2358                FromRedisValue::from_redis_value(v).map($func)
2359            }
2360
2361            fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2362                FromRedisValue::from_owned_redis_value(v).map($func)
2363            }
2364        }
2365    }
2366}
2367
2368pointer_from_redis_value_impl!(T, Box<T>, Box::new);
2369pointer_from_redis_value_impl!(T, std::sync::Arc<T>, std::sync::Arc::new);
2370pointer_from_redis_value_impl!(T, std::rc::Rc<T>, std::rc::Rc::new);
2371
2372/// Implement `FromRedisValue` for `$Type` (which should use the generic parameter `$T`).
2373///
2374/// The implementation parses the value into a vec, and then passes the value through `$convert`.
2375/// If `$convert` is omitted, it defaults to `Into::into`.
2376macro_rules! from_vec_from_redis_value {
2377    (<$T:ident> $Type:ty) => {
2378        from_vec_from_redis_value!(<$T> $Type; Into::into);
2379    };
2380
2381    (<$T:ident> $Type:ty; $convert:expr) => {
2382        impl<$T: FromRedisValue> FromRedisValue for $Type {
2383            fn from_redis_value(v: &Value) -> RedisResult<$Type> {
2384                match v {
2385                    // All binary data except u8 will try to parse into a single element vector.
2386                    // u8 has its own implementation of from_byte_vec.
2387                    Value::BulkString(bytes) => match FromRedisValue::from_byte_vec(bytes) {
2388                        Some(x) => Ok($convert(x)),
2389                        None => invalid_type_error!(
2390                            v,
2391                            format!("Conversion to {} failed.", std::any::type_name::<$Type>())
2392                        ),
2393                    },
2394                    Value::Array(items) => FromRedisValue::from_redis_values(items).map($convert),
2395                    Value::Set(ref items) => FromRedisValue::from_redis_values(items).map($convert),
2396                    Value::Map(ref items) => {
2397                        let mut n: Vec<T> = vec![];
2398                        for item in items {
2399                            match FromRedisValue::from_redis_value(&Value::Map(vec![item.clone()])) {
2400                                Ok(v) => {
2401                                    n.push(v);
2402                                }
2403                                Err(e) => {
2404                                    return Err(e);
2405                                }
2406                            }
2407                        }
2408                        Ok($convert(n))
2409                    }
2410                    Value::Nil => Ok($convert(Vec::new())),
2411                    _ => invalid_type_error!(v, "Response type not vector compatible."),
2412                }
2413            }
2414            fn from_owned_redis_value(v: Value) -> RedisResult<$Type> {
2415                match v {
2416                    // Binary data is parsed into a single-element vector, except
2417                    // for the element type `u8`, which directly consumes the entire
2418                    // array of bytes.
2419                    Value::BulkString(bytes) => FromRedisValue::from_owned_byte_vec(bytes).map($convert),
2420                    Value::Array(items) => FromRedisValue::from_owned_redis_values(items).map($convert),
2421                    Value::Set(items) => FromRedisValue::from_owned_redis_values(items).map($convert),
2422                    Value::Map(items) => {
2423                        let mut n: Vec<T> = vec![];
2424                        for item in items {
2425                            match FromRedisValue::from_owned_redis_value(Value::Map(vec![item])) {
2426                                Ok(v) => {
2427                                    n.push(v);
2428                                }
2429                                Err(e) => {
2430                                    return Err(e);
2431                                }
2432                            }
2433                        }
2434                        Ok($convert(n))
2435                    }
2436                    Value::Nil => Ok($convert(Vec::new())),
2437                    _ => invalid_type_error!(v, "Response type not vector compatible."),
2438                }
2439            }
2440        }
2441    };
2442}
2443
2444from_vec_from_redis_value!(<T> Vec<T>);
2445from_vec_from_redis_value!(<T> std::sync::Arc<[T]>);
2446from_vec_from_redis_value!(<T> Box<[T]>; Vec::into_boxed_slice);
2447
2448macro_rules! impl_from_redis_value_for_map {
2449    (for <$($TypeParam:ident),+> $MapType:ty, where ($($WhereClause:tt)+)) => {
2450        impl< $($TypeParam),+ > FromRedisValue for $MapType
2451        where
2452            $($WhereClause)+
2453        {
2454            fn from_redis_value(v: &Value) -> RedisResult<$MapType> {
2455                let v = get_inner_value(v);
2456                match *v {
2457                    Value::Nil => Ok(Default::default()),
2458                    _ => v
2459                        .as_map_iter()
2460                        .ok_or_else(|| invalid_type_error_inner!(v, "Response type not map compatible"))?
2461                        .map(|(k, v)| {
2462                            Ok((from_redis_value(k)?, from_redis_value(v)?))
2463                        })
2464                        .collect(),
2465                }
2466            }
2467
2468            fn from_owned_redis_value(v: Value) -> RedisResult<$MapType> {
2469                let v = get_owned_inner_value(v);
2470                match v {
2471                    Value::Nil => Ok(Default::default()),
2472                    _ => v
2473                        .into_map_iter()
2474                        .map_err(|v| invalid_type_error_inner!(v, "Response type not map compatible"))?
2475                        .map(|(k, v)| {
2476                            Ok((from_owned_redis_value(k)?, from_owned_redis_value(v)?))
2477                        })
2478                        .collect(),
2479                }
2480            }
2481        }
2482    };
2483}
2484
2485impl_from_redis_value_for_map!(
2486    for <K, V, S> std::collections::HashMap<K, V, S>,
2487    where (K: FromRedisValue + Eq + Hash, V: FromRedisValue, S: BuildHasher + Default)
2488);
2489
2490#[cfg(feature = "hashbrown")]
2491impl_from_redis_value_for_map!(
2492    for <K, V, S> hashbrown::HashMap<K, V, S>,
2493    where (K: FromRedisValue + Eq + Hash, V: FromRedisValue, S: BuildHasher + Default)
2494);
2495
2496#[cfg(feature = "ahash")]
2497impl_from_redis_value_for_map!(
2498    for <K, V> ahash::AHashMap<K, V>,
2499    where (K: FromRedisValue + Eq + Hash, V: FromRedisValue)
2500);
2501
2502impl_from_redis_value_for_map!(
2503    for <K, V> std::collections::BTreeMap<K, V>,
2504    where (K: FromRedisValue + Eq + Hash + Ord, V: FromRedisValue)
2505);
2506
2507macro_rules! impl_from_redis_value_for_set {
2508    (for <$($TypeParam:ident),+> $SetType:ty, where ($($WhereClause:tt)+)) => {
2509        impl< $($TypeParam),+ > FromRedisValue for $SetType
2510        where
2511            $($WhereClause)+
2512        {
2513            fn from_redis_value(v: &Value) -> RedisResult<$SetType> {
2514                let v = get_inner_value(v);
2515                let items = v
2516                    .as_sequence()
2517                    .ok_or_else(|| invalid_type_error_inner!(v, "Response type not map compatible"))?;
2518                items.iter().map(|item| from_redis_value(item)).collect()
2519            }
2520
2521            fn from_owned_redis_value(v: Value) -> RedisResult<$SetType> {
2522                let v = get_owned_inner_value(v);
2523                let items = v
2524                    .into_sequence()
2525                    .map_err(|v| invalid_type_error_inner!(v, "Response type not map compatible"))?;
2526                items
2527                    .into_iter()
2528                    .map(|item| from_owned_redis_value(item))
2529                    .collect()
2530            }
2531        }
2532    };
2533}
2534
2535impl_from_redis_value_for_set!(
2536    for <T, S> std::collections::HashSet<T, S>,
2537    where (T: FromRedisValue + Eq + Hash, S: BuildHasher + Default)
2538);
2539
2540impl_from_redis_value_for_set!(
2541    for <T> std::collections::BTreeSet<T>,
2542    where (T: FromRedisValue + Eq + Ord)
2543);
2544
2545#[cfg(feature = "hashbrown")]
2546impl_from_redis_value_for_set!(
2547    for <T, S> hashbrown::HashSet<T, S>,
2548    where (T: FromRedisValue + Eq + Hash, S: BuildHasher + Default)
2549);
2550
2551#[cfg(feature = "ahash")]
2552impl_from_redis_value_for_set!(
2553    for <T> ahash::AHashSet<T>,
2554    where (T: FromRedisValue + Eq + Hash)
2555);
2556
2557impl FromRedisValue for Value {
2558    fn from_redis_value(v: &Value) -> RedisResult<Value> {
2559        Ok(v.clone())
2560    }
2561    fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2562        Ok(v)
2563    }
2564}
2565
2566impl FromRedisValue for () {
2567    fn from_redis_value(_v: &Value) -> RedisResult<()> {
2568        Ok(())
2569    }
2570}
2571
2572macro_rules! from_redis_value_for_tuple {
2573    () => ();
2574    ($(#[$meta:meta],)*$($name:ident,)+) => (
2575        $(#[$meta])*
2576        impl<$($name: FromRedisValue),*> FromRedisValue for ($($name,)*) {
2577            // we have local variables named T1 as dummies and those
2578            // variables are unused.
2579            #[allow(non_snake_case, unused_variables)]
2580            fn from_redis_value(v: &Value) -> RedisResult<($($name,)*)> {
2581                let v = get_inner_value(v);
2582                match *v {
2583                    Value::Array(ref items) => {
2584                        // hacky way to count the tuple size
2585                        let mut n = 0;
2586                        $(let $name = (); n += 1;)*
2587                        if items.len() != n {
2588                            invalid_type_error!(v, "Array response of wrong dimension")
2589                        }
2590
2591                        // this is pretty ugly too.  The { i += 1; i - 1} is rust's
2592                        // postfix increment :)
2593                        let mut i = 0;
2594                        Ok(($({let $name = (); from_redis_value(
2595                             &items[{ i += 1; i - 1 }])?},)*))
2596                    }
2597
2598                    Value::Map(ref items) => {
2599                        // hacky way to count the tuple size
2600                        let mut n = 0;
2601                        $(let $name = (); n += 1;)*
2602                        if n != 2 {
2603                            invalid_type_error!(v, "Map response of wrong dimension")
2604                        }
2605
2606                        let mut flatten_items = vec![];
2607                        for (k,v) in items {
2608                            flatten_items.push(k);
2609                            flatten_items.push(v);
2610                        }
2611
2612                        // this is pretty ugly too.  The { i += 1; i - 1} is rust's
2613                        // postfix increment :)
2614                        let mut i = 0;
2615                        Ok(($({let $name = (); from_redis_value(
2616                             &flatten_items[{ i += 1; i - 1 }])?},)*))
2617                    }
2618
2619                    _ => invalid_type_error!(v, "Not a Array response")
2620                }
2621            }
2622
2623            // we have local variables named T1 as dummies and those
2624            // variables are unused.
2625            #[allow(non_snake_case, unused_variables)]
2626            fn from_owned_redis_value(v: Value) -> RedisResult<($($name,)*)> {
2627                let v = get_owned_inner_value(v);
2628                match v {
2629                    Value::Array(mut items) => {
2630                        // hacky way to count the tuple size
2631                        let mut n = 0;
2632                        $(let $name = (); n += 1;)*
2633                        if items.len() != n {
2634                            invalid_type_error!(Value::Array(items), "Array response of wrong dimension")
2635                        }
2636
2637                        // this is pretty ugly too.  The { i += 1; i - 1} is rust's
2638                        // postfix increment :)
2639                        let mut i = 0;
2640                        Ok(($({let $name = (); from_owned_redis_value(
2641                            ::std::mem::replace(&mut items[{ i += 1; i - 1 }], Value::Nil)
2642                        )?},)*))
2643                    }
2644
2645                    Value::Map(items) => {
2646                        // hacky way to count the tuple size
2647                        let mut n = 0;
2648                        $(let $name = (); n += 1;)*
2649                        if n != 2 {
2650                            invalid_type_error!(Value::Map(items), "Map response of wrong dimension")
2651                        }
2652
2653                        let mut flatten_items = vec![];
2654                        for (k,v) in items {
2655                            flatten_items.push(k);
2656                            flatten_items.push(v);
2657                        }
2658
2659                        // this is pretty ugly too.  The { i += 1; i - 1} is rust's
2660                        // postfix increment :)
2661                        let mut i = 0;
2662                        Ok(($({let $name = (); from_redis_value(
2663                             &flatten_items[{ i += 1; i - 1 }])?},)*))
2664                    }
2665
2666                    _ => invalid_type_error!(v, "Not a Array response")
2667                }
2668            }
2669
2670            #[allow(non_snake_case, unused_variables)]
2671            fn from_redis_values(items: &[Value]) -> RedisResult<Vec<($($name,)*)>> {
2672                // hacky way to count the tuple size
2673                let mut n = 0;
2674                $(let $name = (); n += 1;)*
2675                let mut rv = vec![];
2676                if items.len() == 0 {
2677                    return Ok(rv)
2678                }
2679                //It's uglier then before!
2680                for item in items {
2681                    match item {
2682                        Value::Array(ch) => {
2683                           if  let [$($name),*] = &ch[..] {
2684                            rv.push(($(from_redis_value(&$name)?),*),)
2685                           };
2686                        },
2687                        _ => {},
2688
2689                    }
2690                }
2691                if !rv.is_empty(){
2692                    return Ok(rv);
2693                }
2694
2695                if let  [$($name),*] = items{
2696                    rv.push(($(from_redis_value($name)?),*),);
2697                    return Ok(rv);
2698                }
2699                 for chunk in items.chunks_exact(n) {
2700                    match chunk {
2701                        [$($name),*] => rv.push(($(from_redis_value($name)?),*),),
2702                         _ => {},
2703                    }
2704                }
2705                Ok(rv)
2706            }
2707
2708            #[allow(non_snake_case, unused_variables)]
2709            fn from_each_owned_redis_values(mut items: Vec<Value>) -> Vec<RedisResult<($($name,)*)>> {
2710
2711                #[allow(unused_parens)]
2712                let extract = |val: ($(RedisResult<$name>),*)| -> RedisResult<($($name,)*)> {
2713                    let ($($name),*) = val;
2714                    Ok(($($name?),*,))
2715                };
2716
2717                // hacky way to count the tuple size
2718                let mut n = 0;
2719                $(let $name = (); n += 1;)*
2720
2721                let mut rv = vec![];
2722                if items.len() == 0 {
2723                    return rv
2724                }
2725                //It's uglier then before!
2726                for item in items.iter_mut() {
2727                    match item {
2728                        Value::Array(ref mut ch) => {
2729                            if let [$($name),*] = &mut ch[..] {
2730                                rv.push(extract(($(from_owned_redis_value(std::mem::replace($name, Value::Nil))),*)));
2731                            };
2732                        },
2733                        _ => {},
2734                    }
2735                }
2736                if !rv.is_empty(){
2737                    return rv;
2738                }
2739
2740                let mut rv = Vec::with_capacity(items.len() / n);
2741
2742                for chunk in items.chunks_mut(n) {
2743                    match chunk {
2744                        // Take each element out of the chunk with `std::mem::replace`, leaving a `Value::Nil`
2745                        // in its place. This allows each `Value` to be parsed without being copied.
2746                        // Since `items` is consumed by this function and not used later, this replacement
2747                        // is not observable to the rest of the code.
2748                        [$($name),*] => rv.push(extract(($(from_owned_redis_value(std::mem::replace($name, Value::Nil))),*))),
2749                         _ => unreachable!(),
2750                    }
2751                }
2752                rv
2753            }
2754
2755            #[allow(non_snake_case, unused_variables)]
2756            fn from_owned_redis_values(mut items: Vec<Value>) -> RedisResult<Vec<($($name,)*)>> {
2757                // hacky way to count the tuple size
2758                let mut n = 0;
2759                $(let $name = (); n += 1;)*
2760
2761                let mut rv = vec![];
2762                if items.len() == 0 {
2763                    return Ok(rv)
2764                }
2765                //It's uglier then before!
2766                for item in items.iter_mut() {
2767                    match item {
2768                        Value::Array(ref mut ch) => {
2769                        if  let [$($name),*] = &mut ch[..] {
2770                            rv.push(($(from_owned_redis_value(std::mem::replace($name, Value::Nil))?),*),);
2771                           };
2772                        },
2773                        _ => {},
2774                    }
2775                }
2776                if !rv.is_empty(){
2777                    return Ok(rv);
2778                }
2779
2780                let mut rv = Vec::with_capacity(items.len() / n);
2781                if items.len() == 0 {
2782                    return Ok(rv)
2783                }
2784                for chunk in items.chunks_mut(n) {
2785                    match chunk {
2786                        // Take each element out of the chunk with `std::mem::replace`, leaving a `Value::Nil`
2787                        // in its place. This allows each `Value` to be parsed without being copied.
2788                        // Since `items` is consume by this function and not used later, this replacement
2789                        // is not observable to the rest of the code.
2790                        [$($name),*] => rv.push(($(from_owned_redis_value(std::mem::replace($name, Value::Nil))?),*),),
2791                         _ => unreachable!(),
2792                    }
2793                }
2794                Ok(rv)
2795            }
2796        }
2797    )
2798}
2799
2800from_redis_value_for_tuple! { #[cfg_attr(docsrs, doc(fake_variadic))], #[doc = "This trait is implemented for tuples up to 12 items long."], T, }
2801from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, }
2802from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, }
2803from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, }
2804from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, }
2805from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, }
2806from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, }
2807from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, }
2808from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, }
2809from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, }
2810from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
2811from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
2812
2813impl FromRedisValue for InfoDict {
2814    fn from_redis_value(v: &Value) -> RedisResult<InfoDict> {
2815        let v = get_inner_value(v);
2816        let s: String = from_redis_value(v)?;
2817        Ok(InfoDict::new(&s))
2818    }
2819    fn from_owned_redis_value(v: Value) -> RedisResult<InfoDict> {
2820        let v = get_owned_inner_value(v);
2821        let s: String = from_owned_redis_value(v)?;
2822        Ok(InfoDict::new(&s))
2823    }
2824}
2825
2826impl<T: FromRedisValue> FromRedisValue for Option<T> {
2827    fn from_redis_value(v: &Value) -> RedisResult<Option<T>> {
2828        let v = get_inner_value(v);
2829        if *v == Value::Nil {
2830            return Ok(None);
2831        }
2832        Ok(Some(from_redis_value(v)?))
2833    }
2834    fn from_owned_redis_value(v: Value) -> RedisResult<Option<T>> {
2835        let v = get_owned_inner_value(v);
2836        if v == Value::Nil {
2837            return Ok(None);
2838        }
2839        Ok(Some(from_owned_redis_value(v)?))
2840    }
2841}
2842
2843#[cfg(feature = "bytes")]
2844impl FromRedisValue for bytes::Bytes {
2845    fn from_redis_value(v: &Value) -> RedisResult<Self> {
2846        let v = get_inner_value(v);
2847        match v {
2848            Value::BulkString(bytes_vec) => Ok(bytes::Bytes::copy_from_slice(bytes_vec.as_ref())),
2849            _ => invalid_type_error!(v, "Not a bulk string"),
2850        }
2851    }
2852    fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2853        let v = get_owned_inner_value(v);
2854        match v {
2855            Value::BulkString(bytes_vec) => Ok(bytes_vec.into()),
2856            _ => invalid_type_error!(v, "Not a bulk string"),
2857        }
2858    }
2859}
2860
2861#[cfg(feature = "uuid")]
2862impl FromRedisValue for uuid::Uuid {
2863    fn from_redis_value(v: &Value) -> RedisResult<Self> {
2864        match *v {
2865            Value::BulkString(ref bytes) => Ok(uuid::Uuid::from_slice(bytes)?),
2866            _ => invalid_type_error!(v, "Response type not uuid compatible."),
2867        }
2868    }
2869}
2870
2871#[cfg(feature = "uuid")]
2872impl ToRedisArgs for uuid::Uuid {
2873    fn write_redis_args<W>(&self, out: &mut W)
2874    where
2875        W: ?Sized + RedisWrite,
2876    {
2877        out.write_arg(self.as_bytes());
2878    }
2879}
2880
2881/// A shortcut function to invoke `FromRedisValue::from_redis_value`
2882/// to make the API slightly nicer.
2883pub fn from_redis_value<T: FromRedisValue>(v: &Value) -> RedisResult<T> {
2884    FromRedisValue::from_redis_value(v)
2885}
2886
2887/// A shortcut function to invoke `FromRedisValue::from_owned_redis_value`
2888/// to make the API slightly nicer.
2889pub fn from_owned_redis_value<T: FromRedisValue>(v: Value) -> RedisResult<T> {
2890    FromRedisValue::from_owned_redis_value(v)
2891}
2892
2893/// Enum representing the communication protocol with the server.
2894///
2895/// This enum represents the types of data that the server can send to the client,
2896/// and the capabilities that the client can use.
2897#[derive(Clone, Eq, PartialEq, Default, Debug, Copy)]
2898pub enum ProtocolVersion {
2899    /// <https://github.com/redis/redis-specifications/blob/master/protocol/RESP2.md>
2900    #[default]
2901    RESP2,
2902    /// <https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md>
2903    RESP3,
2904}
2905
2906/// Helper enum that is used to define option for the hash expire commands
2907#[derive(Clone, Copy)]
2908pub enum ExpireOption {
2909    /// NONE -- Set expiration regardless of the field's current expiration.
2910    NONE,
2911    /// NX -- Only set expiration only when the field has no expiration.
2912    NX,
2913    /// XX -- Only set expiration only when the field has an existing expiration.
2914    XX,
2915    /// GT -- Only set expiration only when the new expiration is greater than current one.
2916    GT,
2917    /// LT -- Only set expiration only when the new expiration is less than current one.
2918    LT,
2919}
2920
2921impl ToRedisArgs for ExpireOption {
2922    fn write_redis_args<W>(&self, out: &mut W)
2923    where
2924        W: ?Sized + RedisWrite,
2925    {
2926        match self {
2927            ExpireOption::NX => out.write_arg(b"NX"),
2928            ExpireOption::XX => out.write_arg(b"XX"),
2929            ExpireOption::GT => out.write_arg(b"GT"),
2930            ExpireOption::LT => out.write_arg(b"LT"),
2931            _ => {}
2932        }
2933    }
2934}
2935
2936#[derive(Debug, Clone, PartialEq)]
2937/// A push message from the server.
2938pub struct PushInfo {
2939    /// Push Kind
2940    pub kind: PushKind,
2941    /// Data from push message
2942    pub data: Vec<Value>,
2943}
2944
2945impl PushInfo {
2946    pub(crate) fn disconnect() -> Self {
2947        PushInfo {
2948            kind: crate::PushKind::Disconnection,
2949            data: vec![],
2950        }
2951    }
2952}
2953
2954pub(crate) type SyncPushSender = std::sync::mpsc::Sender<PushInfo>;
2955
2956// A consistent error value for connections closed without a reason.
2957#[cfg(any(feature = "aio", feature = "r2d2"))]
2958pub(crate) fn closed_connection_error() -> RedisError {
2959    RedisError::from(io::Error::from(io::ErrorKind::BrokenPipe))
2960}
2961
2962/// Possible types of value held in Redis: [Redis Docs](https://redis.io/docs/latest/commands/type/)
2963#[derive(Debug, Clone, PartialEq)]
2964pub enum ValueType {
2965    /// Generally returned by anything that returns a single element. [Redis Docs](https://redis.io/docs/latest/develop/data-types/strings/)
2966    String,
2967    /// A list of String values. [Redis Docs](https://redis.io/docs/latest/develop/data-types/lists/)
2968    List,
2969    /// A set of unique String values. [Redis Docs](https://redis.io/docs/latest/develop/data-types/sets/)
2970    Set,
2971    /// A sorted set of String values. [Redis Docs](https://redis.io/docs/latest/develop/data-types/sorted-sets/)
2972    ZSet,
2973    /// A collection of field-value pairs. [Redis Docs](https://redis.io/docs/latest/develop/data-types/hashes/)
2974    Hash,
2975    /// A Redis Stream. [Redis Docs](https://redis.io/docs/latest/develop/data-types/stream)
2976    Stream,
2977    /// Any other value type not explicitly defined in [Redis Docs](https://redis.io/docs/latest/commands/type/)
2978    Unknown(String),
2979}
2980
2981impl FromRedisValue for ValueType {
2982    fn from_redis_value(v: &Value) -> RedisResult<Self> {
2983        match v {
2984            Value::SimpleString(s) => match s.as_str() {
2985                "string" => Ok(ValueType::String),
2986                "list" => Ok(ValueType::List),
2987                "set" => Ok(ValueType::Set),
2988                "zset" => Ok(ValueType::ZSet),
2989                "hash" => Ok(ValueType::Hash),
2990                "stream" => Ok(ValueType::Stream),
2991                _ => Ok(ValueType::Unknown(s.clone())),
2992            },
2993            _ => invalid_type_error!(v, "Value type should be a simple string"),
2994        }
2995    }
2996
2997    fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2998        match v {
2999            Value::SimpleString(s) => match s.as_str() {
3000                "string" => Ok(ValueType::String),
3001                "list" => Ok(ValueType::List),
3002                "set" => Ok(ValueType::Set),
3003                "zset" => Ok(ValueType::ZSet),
3004                "hash" => Ok(ValueType::Hash),
3005                "stream" => Ok(ValueType::Stream),
3006                _ => Ok(ValueType::Unknown(s)),
3007            },
3008            _ => invalid_type_error!(v, "Value type should be a simple string"),
3009        }
3010    }
3011}
3012
3013/// Returned by typed commands which either return a positive integer or some negative integer indicating some kind of no-op.
3014#[derive(Debug, PartialEq, Clone)]
3015pub enum IntegerReplyOrNoOp {
3016    /// A positive integer reply indicating success of some kind.
3017    IntegerReply(usize),
3018    /// The field/key you are trying to operate on does not exist.
3019    NotExists,
3020    /// The field/key you are trying to operate on exists but is not of the correct type or does not have some property you are trying to affect.
3021    ExistsButNotRelevant,
3022}
3023
3024impl IntegerReplyOrNoOp {
3025    /// Returns the integer value of the reply.
3026    pub fn raw(&self) -> isize {
3027        match self {
3028            IntegerReplyOrNoOp::IntegerReply(s) => *s as isize,
3029            IntegerReplyOrNoOp::NotExists => -2,
3030            IntegerReplyOrNoOp::ExistsButNotRelevant => -1,
3031        }
3032    }
3033}
3034
3035impl FromRedisValue for IntegerReplyOrNoOp {
3036    fn from_redis_value(v: &Value) -> RedisResult<Self> {
3037        match v {
3038            Value::Int(s) => match s {
3039                -2 => Ok(IntegerReplyOrNoOp::NotExists),
3040                -1 => Ok(IntegerReplyOrNoOp::ExistsButNotRelevant),
3041                _ => Ok(IntegerReplyOrNoOp::IntegerReply(*s as usize)),
3042            },
3043            _ => invalid_type_error!(v, "Value should be an integer"),
3044        }
3045    }
3046
3047    fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
3048        match v {
3049            Value::Int(s) => match s {
3050                -2 => Ok(IntegerReplyOrNoOp::NotExists),
3051                -1 => Ok(IntegerReplyOrNoOp::ExistsButNotRelevant),
3052                _ => Ok(IntegerReplyOrNoOp::IntegerReply(s as usize)),
3053            },
3054            _ => invalid_type_error!(v, "Value should be an integer"),
3055        }
3056    }
3057}
3058
3059impl PartialEq<isize> for IntegerReplyOrNoOp {
3060    fn eq(&self, other: &isize) -> bool {
3061        match self {
3062            IntegerReplyOrNoOp::IntegerReply(s) => *s as isize == *other,
3063            IntegerReplyOrNoOp::NotExists => *other == -2,
3064            IntegerReplyOrNoOp::ExistsButNotRelevant => *other == -1,
3065        }
3066    }
3067}
3068
3069impl PartialEq<usize> for IntegerReplyOrNoOp {
3070    fn eq(&self, other: &usize) -> bool {
3071        match self {
3072            IntegerReplyOrNoOp::IntegerReply(s) => *s == *other,
3073            _ => false,
3074        }
3075    }
3076}
3077
3078impl PartialEq<i32> for IntegerReplyOrNoOp {
3079    fn eq(&self, other: &i32) -> bool {
3080        match self {
3081            IntegerReplyOrNoOp::IntegerReply(s) => *s as i32 == *other,
3082            IntegerReplyOrNoOp::NotExists => *other == -2,
3083            IntegerReplyOrNoOp::ExistsButNotRelevant => *other == -1,
3084        }
3085    }
3086}
3087
3088impl PartialEq<u32> for IntegerReplyOrNoOp {
3089    fn eq(&self, other: &u32) -> bool {
3090        match self {
3091            IntegerReplyOrNoOp::IntegerReply(s) => *s as u32 == *other,
3092            _ => false,
3093        }
3094    }
3095}