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!(isize, NumericBehavior::NumberIsInteger);
1674itoa_based_to_redis_impl!(usize, NumericBehavior::NumberIsInteger);
1675
1676non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU8, NumericBehavior::NumberIsInteger);
1677non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI8, NumericBehavior::NumberIsInteger);
1678non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU16, NumericBehavior::NumberIsInteger);
1679non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI16, NumericBehavior::NumberIsInteger);
1680non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU32, NumericBehavior::NumberIsInteger);
1681non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI32, NumericBehavior::NumberIsInteger);
1682non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU64, NumericBehavior::NumberIsInteger);
1683non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI64, NumericBehavior::NumberIsInteger);
1684non_zero_itoa_based_to_redis_impl!(core::num::NonZeroUsize, NumericBehavior::NumberIsInteger);
1685non_zero_itoa_based_to_redis_impl!(core::num::NonZeroIsize, NumericBehavior::NumberIsInteger);
1686
1687ryu_based_to_redis_impl!(f32, NumericBehavior::NumberIsFloat);
1688ryu_based_to_redis_impl!(f64, NumericBehavior::NumberIsFloat);
1689
1690#[cfg(any(
1691    feature = "rust_decimal",
1692    feature = "bigdecimal",
1693    feature = "num-bigint"
1694))]
1695macro_rules! bignum_to_redis_impl {
1696    ($t:ty) => {
1697        impl ToRedisArgs for $t {
1698            fn write_redis_args<W>(&self, out: &mut W)
1699            where
1700                W: ?Sized + RedisWrite,
1701            {
1702                out.write_arg(&self.to_string().into_bytes())
1703            }
1704        }
1705    };
1706}
1707
1708#[cfg(feature = "rust_decimal")]
1709bignum_to_redis_impl!(rust_decimal::Decimal);
1710#[cfg(feature = "bigdecimal")]
1711bignum_to_redis_impl!(bigdecimal::BigDecimal);
1712#[cfg(feature = "num-bigint")]
1713bignum_to_redis_impl!(num_bigint::BigInt);
1714#[cfg(feature = "num-bigint")]
1715bignum_to_redis_impl!(num_bigint::BigUint);
1716
1717impl ToRedisArgs for bool {
1718    fn write_redis_args<W>(&self, out: &mut W)
1719    where
1720        W: ?Sized + RedisWrite,
1721    {
1722        out.write_arg(if *self { b"1" } else { b"0" })
1723    }
1724}
1725
1726impl ToRedisArgs for String {
1727    fn write_redis_args<W>(&self, out: &mut W)
1728    where
1729        W: ?Sized + RedisWrite,
1730    {
1731        out.write_arg(self.as_bytes())
1732    }
1733}
1734
1735impl ToRedisArgs for &str {
1736    fn write_redis_args<W>(&self, out: &mut W)
1737    where
1738        W: ?Sized + RedisWrite,
1739    {
1740        out.write_arg(self.as_bytes())
1741    }
1742}
1743
1744impl<'a, T> ToRedisArgs for Cow<'a, T>
1745where
1746    T: ToOwned + ?Sized,
1747    &'a T: ToRedisArgs,
1748    for<'b> &'b T::Owned: ToRedisArgs,
1749{
1750    fn write_redis_args<W>(&self, out: &mut W)
1751    where
1752        W: ?Sized + RedisWrite,
1753    {
1754        match self {
1755            Cow::Borrowed(inner) => inner.write_redis_args(out),
1756            Cow::Owned(inner) => inner.write_redis_args(out),
1757        }
1758    }
1759}
1760
1761impl<T: ToRedisArgs> ToRedisArgs for Vec<T> {
1762    fn write_redis_args<W>(&self, out: &mut W)
1763    where
1764        W: ?Sized + RedisWrite,
1765    {
1766        ToRedisArgs::write_args_from_slice(self, out)
1767    }
1768
1769    fn num_of_args(&self) -> usize {
1770        if ToRedisArgs::is_single_vec_arg(&self[..]) {
1771            return 1;
1772        }
1773        if self.len() == 1 {
1774            self[0].num_of_args()
1775        } else {
1776            self.len()
1777        }
1778    }
1779}
1780
1781impl<T: ToRedisArgs> ToRedisArgs for &[T] {
1782    fn write_redis_args<W>(&self, out: &mut W)
1783    where
1784        W: ?Sized + RedisWrite,
1785    {
1786        ToRedisArgs::write_args_from_slice(self, out)
1787    }
1788
1789    fn num_of_args(&self) -> usize {
1790        if ToRedisArgs::is_single_vec_arg(&self[..]) {
1791            return 1;
1792        }
1793        if self.len() == 1 {
1794            self[0].num_of_args()
1795        } else {
1796            self.len()
1797        }
1798    }
1799}
1800
1801impl<T: ToRedisArgs> ToRedisArgs for Option<T> {
1802    fn write_redis_args<W>(&self, out: &mut W)
1803    where
1804        W: ?Sized + RedisWrite,
1805    {
1806        if let Some(ref x) = *self {
1807            x.write_redis_args(out);
1808        }
1809    }
1810
1811    fn describe_numeric_behavior(&self) -> NumericBehavior {
1812        match *self {
1813            Some(ref x) => x.describe_numeric_behavior(),
1814            None => NumericBehavior::NonNumeric,
1815        }
1816    }
1817
1818    fn num_of_args(&self) -> usize {
1819        match *self {
1820            Some(ref x) => x.num_of_args(),
1821            None => 0,
1822        }
1823    }
1824}
1825
1826macro_rules! deref_to_write_redis_args_impl {
1827    (
1828        $(#[$attr:meta])*
1829        <$($desc:tt)+
1830    ) => {
1831        $(#[$attr])*
1832        impl <$($desc)+ {
1833            #[inline]
1834            fn write_redis_args<W>(&self, out: &mut W)
1835                where
1836                W: ?Sized + RedisWrite,
1837            {
1838                (**self).write_redis_args(out)
1839            }
1840
1841            fn num_of_args(&self) -> usize {
1842                (**self).num_of_args()
1843            }
1844
1845            fn describe_numeric_behavior(&self) -> NumericBehavior {
1846                (**self).describe_numeric_behavior()
1847            }
1848        }
1849    };
1850}
1851
1852deref_to_write_redis_args_impl! {
1853    <'a, T> ToRedisArgs for &'a T where T: ToRedisArgs
1854}
1855
1856deref_to_write_redis_args_impl! {
1857    <'a, T> ToRedisArgs for &'a mut T where T: ToRedisArgs
1858}
1859
1860deref_to_write_redis_args_impl! {
1861    <T> ToRedisArgs for Box<T> where T: ToRedisArgs
1862}
1863
1864deref_to_write_redis_args_impl! {
1865    <T> ToRedisArgs for std::sync::Arc<T> where T: ToRedisArgs
1866}
1867
1868deref_to_write_redis_args_impl! {
1869    <T> ToRedisArgs for std::rc::Rc<T> where T: ToRedisArgs
1870}
1871
1872/// @note: Redis cannot store empty sets so the application has to
1873/// check whether the set is empty and if so, not attempt to use that
1874/// result
1875macro_rules! impl_to_redis_args_for_set {
1876    (for <$($TypeParam:ident),+> $SetType:ty, where ($($WhereClause:tt)+) ) => {
1877        impl< $($TypeParam),+ > ToRedisArgs for $SetType
1878        where
1879            $($WhereClause)+
1880        {
1881            fn write_redis_args<W>(&self, out: &mut W)
1882            where
1883                W: ?Sized + RedisWrite,
1884            {
1885                ToRedisArgs::make_arg_iter_ref(self.iter(), out)
1886            }
1887
1888            fn num_of_args(&self) -> usize {
1889                self.len()
1890            }
1891        }
1892    };
1893}
1894
1895impl_to_redis_args_for_set!(
1896    for <T, S> std::collections::HashSet<T, S>,
1897    where (T: ToRedisArgs + Hash + Eq, S: BuildHasher + Default)
1898);
1899
1900impl_to_redis_args_for_set!(
1901    for <T> std::collections::BTreeSet<T>,
1902    where (T: ToRedisArgs + Hash + Eq + Ord)
1903);
1904
1905#[cfg(feature = "hashbrown")]
1906impl_to_redis_args_for_set!(
1907    for <T, S> hashbrown::HashSet<T, S>,
1908    where (T: ToRedisArgs + Hash + Eq, S: BuildHasher + Default)
1909);
1910
1911#[cfg(feature = "ahash")]
1912impl_to_redis_args_for_set!(
1913    for <T, S> ahash::AHashSet<T, S>,
1914    where (T: ToRedisArgs + Hash + Eq, S: BuildHasher + Default)
1915);
1916
1917/// @note: Redis cannot store empty maps so the application has to
1918/// check whether the set is empty and if so, not attempt to use that
1919/// result
1920macro_rules! impl_to_redis_args_for_map {
1921    (
1922        $(#[$meta:meta])*
1923        for <$($TypeParam:ident),+> $MapType:ty,
1924        where ($($WhereClause:tt)+)
1925    ) => {
1926        $(#[$meta])*
1927        impl< $($TypeParam),+ > ToRedisArgs for $MapType
1928        where
1929            $($WhereClause)+
1930        {
1931            fn write_redis_args<W>(&self, out: &mut W)
1932            where
1933                W: ?Sized + RedisWrite,
1934            {
1935                for (key, value) in self {
1936                    // Ensure key and value produce a single argument each
1937                    assert!(key.num_of_args() <= 1 && value.num_of_args() <= 1);
1938                    key.write_redis_args(out);
1939                    value.write_redis_args(out);
1940                }
1941            }
1942
1943            fn num_of_args(&self) -> usize {
1944                self.len()
1945            }
1946        }
1947    };
1948}
1949impl_to_redis_args_for_map!(
1950    for <K, V> std::collections::HashMap<K, V>,
1951    where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1952);
1953
1954impl_to_redis_args_for_map!(
1955    /// this flattens BTreeMap into something that goes well with HMSET
1956    for <K, V> std::collections::BTreeMap<K, V>,
1957    where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1958);
1959
1960#[cfg(feature = "hashbrown")]
1961impl_to_redis_args_for_map!(
1962    for <K, V> hashbrown::HashMap<K, V>,
1963    where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1964);
1965
1966macro_rules! to_redis_args_for_tuple {
1967    () => ();
1968    ($(#[$meta:meta],)*$($name:ident,)+) => (
1969        $(#[$meta])*
1970        impl<$($name: ToRedisArgs),*> ToRedisArgs for ($($name,)*) {
1971            // we have local variables named T1 as dummies and those
1972            // variables are unused.
1973            #[allow(non_snake_case, unused_variables)]
1974            fn write_redis_args<W>(&self, out: &mut W) where W: ?Sized + RedisWrite {
1975                let ($(ref $name,)*) = *self;
1976                $($name.write_redis_args(out);)*
1977            }
1978
1979            #[allow(non_snake_case, unused_variables)]
1980            fn num_of_args(&self) -> usize {
1981                let mut n: usize = 0;
1982                $(let $name = (); n += 1;)*
1983                n
1984            }
1985        }
1986    )
1987}
1988
1989to_redis_args_for_tuple! { #[cfg_attr(docsrs, doc(fake_variadic))], #[doc = "This trait is implemented for tuples up to 12 items long."], T, }
1990to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, }
1991to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, }
1992to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, }
1993to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, }
1994to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, }
1995to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, }
1996to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, }
1997to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, }
1998to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, }
1999to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
2000to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
2001
2002impl<T: ToRedisArgs, const N: usize> ToRedisArgs for &[T; N] {
2003    fn write_redis_args<W>(&self, out: &mut W)
2004    where
2005        W: ?Sized + RedisWrite,
2006    {
2007        ToRedisArgs::write_args_from_slice(self.as_slice(), out)
2008    }
2009
2010    fn num_of_args(&self) -> usize {
2011        if ToRedisArgs::is_single_vec_arg(&self[..]) {
2012            return 1;
2013        }
2014        if self.len() == 1 {
2015            self[0].num_of_args()
2016        } else {
2017            self.len()
2018        }
2019    }
2020}
2021
2022fn vec_to_array<T, const N: usize>(items: Vec<T>, original_value: &Value) -> RedisResult<[T; N]> {
2023    match items.try_into() {
2024        Ok(array) => Ok(array),
2025        Err(items) => {
2026            let msg = format!(
2027                "Response has wrong dimension, expected {N}, got {}",
2028                items.len()
2029            );
2030            invalid_type_error!(original_value, msg)
2031        }
2032    }
2033}
2034
2035impl<T: FromRedisValue, const N: usize> FromRedisValue for [T; N] {
2036    fn from_redis_value(value: &Value) -> RedisResult<[T; N]> {
2037        match *value {
2038            Value::BulkString(ref bytes) => match FromRedisValue::from_byte_vec(bytes) {
2039                Some(items) => vec_to_array(items, value),
2040                None => {
2041                    let msg = format!(
2042                        "Conversion to Array[{}; {N}] failed",
2043                        std::any::type_name::<T>()
2044                    );
2045                    invalid_type_error!(value, msg)
2046                }
2047            },
2048            Value::Array(ref items) => {
2049                let items = FromRedisValue::from_redis_values(items)?;
2050                vec_to_array(items, value)
2051            }
2052            Value::Nil => vec_to_array(vec![], value),
2053            _ => invalid_type_error!(value, "Response type not array compatible"),
2054        }
2055    }
2056}
2057
2058/// This trait is used to convert a redis value into a more appropriate
2059/// type.
2060///
2061/// While a redis `Value` can represent any response that comes
2062/// back from the redis server, usually you want to map this into something
2063/// that works better in rust.  For instance you might want to convert the
2064/// return value into a `String` or an integer.
2065///
2066/// This trait is well supported throughout the library and you can
2067/// implement it for your own types if you want.
2068///
2069/// In addition to what you can see from the docs, this is also implemented
2070/// for tuples up to size 12 and for `Vec<u8>`.
2071pub trait FromRedisValue: Sized {
2072    /// Given a redis `Value` this attempts to convert it into the given
2073    /// destination type.  If that fails because it's not compatible an
2074    /// appropriate error is generated.
2075    fn from_redis_value(v: &Value) -> RedisResult<Self>;
2076
2077    /// Given a redis `Value` this attempts to convert it into the given
2078    /// destination type.  If that fails because it's not compatible an
2079    /// appropriate error is generated.
2080    fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2081        // By default, fall back to `from_redis_value`.
2082        // This function only needs to be implemented if it can benefit
2083        // from taking `v` by value.
2084        Self::from_redis_value(&v)
2085    }
2086
2087    /// Similar to `from_redis_value` but constructs a vector of objects
2088    /// from another vector of values.  This primarily exists internally
2089    /// to customize the behavior for vectors of tuples.
2090    fn from_redis_values(items: &[Value]) -> RedisResult<Vec<Self>> {
2091        items.iter().map(FromRedisValue::from_redis_value).collect()
2092    }
2093
2094    /// The same as `from_redis_values`, but takes a `Vec<Value>` instead
2095    /// of a `&[Value]`.
2096    fn from_owned_redis_values(items: Vec<Value>) -> RedisResult<Vec<Self>> {
2097        items
2098            .into_iter()
2099            .map(FromRedisValue::from_owned_redis_value)
2100            .collect()
2101    }
2102
2103    /// Convert bytes to a single element vector.
2104    fn from_byte_vec(_vec: &[u8]) -> Option<Vec<Self>> {
2105        Self::from_owned_redis_value(Value::BulkString(_vec.into()))
2106            .map(|rv| vec![rv])
2107            .ok()
2108    }
2109
2110    /// Convert bytes to a single element vector.
2111    fn from_owned_byte_vec(_vec: Vec<u8>) -> RedisResult<Vec<Self>> {
2112        Self::from_owned_redis_value(Value::BulkString(_vec)).map(|rv| vec![rv])
2113    }
2114}
2115
2116fn get_inner_value(v: &Value) -> &Value {
2117    if let Value::Attribute {
2118        data,
2119        attributes: _,
2120    } = v
2121    {
2122        data.as_ref()
2123    } else {
2124        v
2125    }
2126}
2127
2128fn get_owned_inner_value(v: Value) -> Value {
2129    if let Value::Attribute {
2130        data,
2131        attributes: _,
2132    } = v
2133    {
2134        *data
2135    } else {
2136        v
2137    }
2138}
2139
2140macro_rules! from_redis_value_for_num_internal {
2141    ($t:ty, $v:expr) => {{
2142        let v = if let Value::Attribute {
2143            data,
2144            attributes: _,
2145        } = $v
2146        {
2147            data
2148        } else {
2149            $v
2150        };
2151        match *v {
2152            Value::Int(val) => Ok(val as $t),
2153            Value::SimpleString(ref s) => match s.parse::<$t>() {
2154                Ok(rv) => Ok(rv),
2155                Err(_) => invalid_type_error!(v, "Could not convert from string."),
2156            },
2157            Value::BulkString(ref bytes) => match from_utf8(bytes)?.parse::<$t>() {
2158                Ok(rv) => Ok(rv),
2159                Err(_) => invalid_type_error!(v, "Could not convert from string."),
2160            },
2161            Value::Double(val) => Ok(val as $t),
2162            _ => invalid_type_error!(v, "Response type not convertible to numeric."),
2163        }
2164    }};
2165}
2166
2167macro_rules! from_redis_value_for_num {
2168    ($t:ty) => {
2169        impl FromRedisValue for $t {
2170            fn from_redis_value(v: &Value) -> RedisResult<$t> {
2171                from_redis_value_for_num_internal!($t, v)
2172            }
2173        }
2174    };
2175}
2176
2177impl FromRedisValue for u8 {
2178    fn from_redis_value(v: &Value) -> RedisResult<u8> {
2179        from_redis_value_for_num_internal!(u8, v)
2180    }
2181
2182    // this hack allows us to specialize Vec<u8> to work with binary data.
2183    fn from_byte_vec(vec: &[u8]) -> Option<Vec<u8>> {
2184        Some(vec.to_vec())
2185    }
2186    fn from_owned_byte_vec(vec: Vec<u8>) -> RedisResult<Vec<u8>> {
2187        Ok(vec)
2188    }
2189}
2190
2191from_redis_value_for_num!(i8);
2192from_redis_value_for_num!(i16);
2193from_redis_value_for_num!(u16);
2194from_redis_value_for_num!(i32);
2195from_redis_value_for_num!(u32);
2196from_redis_value_for_num!(i64);
2197from_redis_value_for_num!(u64);
2198from_redis_value_for_num!(i128);
2199from_redis_value_for_num!(u128);
2200from_redis_value_for_num!(f32);
2201from_redis_value_for_num!(f64);
2202from_redis_value_for_num!(isize);
2203from_redis_value_for_num!(usize);
2204
2205#[cfg(any(
2206    feature = "rust_decimal",
2207    feature = "bigdecimal",
2208    feature = "num-bigint"
2209))]
2210macro_rules! from_redis_value_for_bignum_internal {
2211    ($t:ty, $v:expr) => {{
2212        let v = $v;
2213        match *v {
2214            Value::Int(val) => <$t>::try_from(val)
2215                .map_err(|_| invalid_type_error_inner!(v, "Could not convert from integer.")),
2216            Value::SimpleString(ref s) => match s.parse::<$t>() {
2217                Ok(rv) => Ok(rv),
2218                Err(_) => invalid_type_error!(v, "Could not convert from string."),
2219            },
2220            Value::BulkString(ref bytes) => match from_utf8(bytes)?.parse::<$t>() {
2221                Ok(rv) => Ok(rv),
2222                Err(_) => invalid_type_error!(v, "Could not convert from string."),
2223            },
2224            _ => invalid_type_error!(v, "Response type not convertible to numeric."),
2225        }
2226    }};
2227}
2228
2229#[cfg(any(
2230    feature = "rust_decimal",
2231    feature = "bigdecimal",
2232    feature = "num-bigint"
2233))]
2234macro_rules! from_redis_value_for_bignum {
2235    ($t:ty) => {
2236        impl FromRedisValue for $t {
2237            fn from_redis_value(v: &Value) -> RedisResult<$t> {
2238                from_redis_value_for_bignum_internal!($t, v)
2239            }
2240        }
2241    };
2242}
2243
2244#[cfg(feature = "rust_decimal")]
2245from_redis_value_for_bignum!(rust_decimal::Decimal);
2246#[cfg(feature = "bigdecimal")]
2247from_redis_value_for_bignum!(bigdecimal::BigDecimal);
2248#[cfg(feature = "num-bigint")]
2249from_redis_value_for_bignum!(num_bigint::BigInt);
2250#[cfg(feature = "num-bigint")]
2251from_redis_value_for_bignum!(num_bigint::BigUint);
2252
2253impl FromRedisValue for bool {
2254    fn from_redis_value(v: &Value) -> RedisResult<bool> {
2255        let v = get_inner_value(v);
2256        match *v {
2257            Value::Nil => Ok(false),
2258            Value::Int(val) => Ok(val != 0),
2259            Value::SimpleString(ref s) => {
2260                if &s[..] == "1" {
2261                    Ok(true)
2262                } else if &s[..] == "0" {
2263                    Ok(false)
2264                } else {
2265                    invalid_type_error!(v, "Response status not valid boolean");
2266                }
2267            }
2268            Value::BulkString(ref bytes) => {
2269                if bytes == b"1" {
2270                    Ok(true)
2271                } else if bytes == b"0" {
2272                    Ok(false)
2273                } else {
2274                    invalid_type_error!(v, "Response type not bool compatible.");
2275                }
2276            }
2277            Value::Boolean(b) => Ok(b),
2278            Value::Okay => Ok(true),
2279            _ => invalid_type_error!(v, "Response type not bool compatible."),
2280        }
2281    }
2282}
2283
2284impl FromRedisValue for CString {
2285    fn from_redis_value(v: &Value) -> RedisResult<CString> {
2286        let v = get_inner_value(v);
2287        match *v {
2288            Value::BulkString(ref bytes) => Ok(CString::new(bytes.as_slice())?),
2289            Value::Okay => Ok(CString::new("OK")?),
2290            Value::SimpleString(ref val) => Ok(CString::new(val.as_bytes())?),
2291            _ => invalid_type_error!(v, "Response type not CString compatible."),
2292        }
2293    }
2294    fn from_owned_redis_value(v: Value) -> RedisResult<CString> {
2295        let v = get_owned_inner_value(v);
2296        match v {
2297            Value::BulkString(bytes) => Ok(CString::new(bytes)?),
2298            Value::Okay => Ok(CString::new("OK")?),
2299            Value::SimpleString(val) => Ok(CString::new(val)?),
2300            _ => invalid_type_error!(v, "Response type not CString compatible."),
2301        }
2302    }
2303}
2304
2305impl FromRedisValue for String {
2306    fn from_redis_value(v: &Value) -> RedisResult<Self> {
2307        let v = get_inner_value(v);
2308        match *v {
2309            Value::BulkString(ref bytes) => Ok(from_utf8(bytes)?.to_string()),
2310            Value::Okay => Ok("OK".to_string()),
2311            Value::SimpleString(ref val) => Ok(val.to_string()),
2312            Value::VerbatimString {
2313                format: _,
2314                ref text,
2315            } => Ok(text.to_string()),
2316            Value::Double(ref val) => Ok(val.to_string()),
2317            Value::Int(val) => Ok(val.to_string()),
2318            _ => invalid_type_error!(v, "Response type not string compatible."),
2319        }
2320    }
2321
2322    fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2323        let v = get_owned_inner_value(v);
2324        match v {
2325            Value::BulkString(bytes) => Ok(Self::from_utf8(bytes)?),
2326            Value::Okay => Ok("OK".to_string()),
2327            Value::SimpleString(val) => Ok(val),
2328            Value::VerbatimString { format: _, text } => Ok(text),
2329            Value::Double(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
2336macro_rules! pointer_from_redis_value_impl {
2337    (
2338        $(#[$attr:meta])*
2339        $id:ident, $ty:ty, $func:expr
2340    ) => {
2341        $(#[$attr])*
2342        impl<$id:  FromRedisValue> FromRedisValue for $ty {
2343            fn from_redis_value(v: &Value) -> RedisResult<Self>
2344            {
2345                FromRedisValue::from_redis_value(v).map($func)
2346            }
2347
2348            fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2349                FromRedisValue::from_owned_redis_value(v).map($func)
2350            }
2351        }
2352    }
2353}
2354
2355pointer_from_redis_value_impl!(T, Box<T>, Box::new);
2356pointer_from_redis_value_impl!(T, std::sync::Arc<T>, std::sync::Arc::new);
2357pointer_from_redis_value_impl!(T, std::rc::Rc<T>, std::rc::Rc::new);
2358
2359/// Implement `FromRedisValue` for `$Type` (which should use the generic parameter `$T`).
2360///
2361/// The implementation parses the value into a vec, and then passes the value through `$convert`.
2362/// If `$convert` is omitted, it defaults to `Into::into`.
2363macro_rules! from_vec_from_redis_value {
2364    (<$T:ident> $Type:ty) => {
2365        from_vec_from_redis_value!(<$T> $Type; Into::into);
2366    };
2367
2368    (<$T:ident> $Type:ty; $convert:expr) => {
2369        impl<$T: FromRedisValue> FromRedisValue for $Type {
2370            fn from_redis_value(v: &Value) -> RedisResult<$Type> {
2371                match v {
2372                    // All binary data except u8 will try to parse into a single element vector.
2373                    // u8 has its own implementation of from_byte_vec.
2374                    Value::BulkString(bytes) => match FromRedisValue::from_byte_vec(bytes) {
2375                        Some(x) => Ok($convert(x)),
2376                        None => invalid_type_error!(
2377                            v,
2378                            format!("Conversion to {} failed.", std::any::type_name::<$Type>())
2379                        ),
2380                    },
2381                    Value::Array(items) => FromRedisValue::from_redis_values(items).map($convert),
2382                    Value::Set(ref items) => FromRedisValue::from_redis_values(items).map($convert),
2383                    Value::Map(ref items) => {
2384                        let mut n: Vec<T> = vec![];
2385                        for item in items {
2386                            match FromRedisValue::from_redis_value(&Value::Map(vec![item.clone()])) {
2387                                Ok(v) => {
2388                                    n.push(v);
2389                                }
2390                                Err(e) => {
2391                                    return Err(e);
2392                                }
2393                            }
2394                        }
2395                        Ok($convert(n))
2396                    }
2397                    Value::Nil => Ok($convert(Vec::new())),
2398                    _ => invalid_type_error!(v, "Response type not vector compatible."),
2399                }
2400            }
2401            fn from_owned_redis_value(v: Value) -> RedisResult<$Type> {
2402                match v {
2403                    // Binary data is parsed into a single-element vector, except
2404                    // for the element type `u8`, which directly consumes the entire
2405                    // array of bytes.
2406                    Value::BulkString(bytes) => FromRedisValue::from_owned_byte_vec(bytes).map($convert),
2407                    Value::Array(items) => FromRedisValue::from_owned_redis_values(items).map($convert),
2408                    Value::Set(items) => FromRedisValue::from_owned_redis_values(items).map($convert),
2409                    Value::Map(items) => {
2410                        let mut n: Vec<T> = vec![];
2411                        for item in items {
2412                            match FromRedisValue::from_owned_redis_value(Value::Map(vec![item])) {
2413                                Ok(v) => {
2414                                    n.push(v);
2415                                }
2416                                Err(e) => {
2417                                    return Err(e);
2418                                }
2419                            }
2420                        }
2421                        Ok($convert(n))
2422                    }
2423                    Value::Nil => Ok($convert(Vec::new())),
2424                    _ => invalid_type_error!(v, "Response type not vector compatible."),
2425                }
2426            }
2427        }
2428    };
2429}
2430
2431from_vec_from_redis_value!(<T> Vec<T>);
2432from_vec_from_redis_value!(<T> std::sync::Arc<[T]>);
2433from_vec_from_redis_value!(<T> Box<[T]>; Vec::into_boxed_slice);
2434
2435macro_rules! impl_from_redis_value_for_map {
2436    (for <$($TypeParam:ident),+> $MapType:ty, where ($($WhereClause:tt)+)) => {
2437        impl< $($TypeParam),+ > FromRedisValue for $MapType
2438        where
2439            $($WhereClause)+
2440        {
2441            fn from_redis_value(v: &Value) -> RedisResult<$MapType> {
2442                let v = get_inner_value(v);
2443                match *v {
2444                    Value::Nil => Ok(Default::default()),
2445                    _ => v
2446                        .as_map_iter()
2447                        .ok_or_else(|| invalid_type_error_inner!(v, "Response type not map compatible"))?
2448                        .map(|(k, v)| {
2449                            Ok((from_redis_value(k)?, from_redis_value(v)?))
2450                        })
2451                        .collect(),
2452                }
2453            }
2454
2455            fn from_owned_redis_value(v: Value) -> RedisResult<$MapType> {
2456                let v = get_owned_inner_value(v);
2457                match v {
2458                    Value::Nil => Ok(Default::default()),
2459                    _ => v
2460                        .into_map_iter()
2461                        .map_err(|v| invalid_type_error_inner!(v, "Response type not map compatible"))?
2462                        .map(|(k, v)| {
2463                            Ok((from_owned_redis_value(k)?, from_owned_redis_value(v)?))
2464                        })
2465                        .collect(),
2466                }
2467            }
2468        }
2469    };
2470}
2471
2472impl_from_redis_value_for_map!(
2473    for <K, V, S> std::collections::HashMap<K, V, S>,
2474    where (K: FromRedisValue + Eq + Hash, V: FromRedisValue, S: BuildHasher + Default)
2475);
2476
2477#[cfg(feature = "hashbrown")]
2478impl_from_redis_value_for_map!(
2479    for <K, V, S> hashbrown::HashMap<K, V, S>,
2480    where (K: FromRedisValue + Eq + Hash, V: FromRedisValue, S: BuildHasher + Default)
2481);
2482
2483#[cfg(feature = "ahash")]
2484impl_from_redis_value_for_map!(
2485    for <K, V> ahash::AHashMap<K, V>,
2486    where (K: FromRedisValue + Eq + Hash, V: FromRedisValue)
2487);
2488
2489impl_from_redis_value_for_map!(
2490    for <K, V> std::collections::BTreeMap<K, V>,
2491    where (K: FromRedisValue + Eq + Hash + Ord, V: FromRedisValue)
2492);
2493
2494macro_rules! impl_from_redis_value_for_set {
2495    (for <$($TypeParam:ident),+> $SetType:ty, where ($($WhereClause:tt)+)) => {
2496        impl< $($TypeParam),+ > FromRedisValue for $SetType
2497        where
2498            $($WhereClause)+
2499        {
2500            fn from_redis_value(v: &Value) -> RedisResult<$SetType> {
2501                let v = get_inner_value(v);
2502                let items = v
2503                    .as_sequence()
2504                    .ok_or_else(|| invalid_type_error_inner!(v, "Response type not map compatible"))?;
2505                items.iter().map(|item| from_redis_value(item)).collect()
2506            }
2507
2508            fn from_owned_redis_value(v: Value) -> RedisResult<$SetType> {
2509                let v = get_owned_inner_value(v);
2510                let items = v
2511                    .into_sequence()
2512                    .map_err(|v| invalid_type_error_inner!(v, "Response type not map compatible"))?;
2513                items
2514                    .into_iter()
2515                    .map(|item| from_owned_redis_value(item))
2516                    .collect()
2517            }
2518        }
2519    };
2520}
2521
2522impl_from_redis_value_for_set!(
2523    for <T, S> std::collections::HashSet<T, S>,
2524    where (T: FromRedisValue + Eq + Hash, S: BuildHasher + Default)
2525);
2526
2527impl_from_redis_value_for_set!(
2528    for <T> std::collections::BTreeSet<T>,
2529    where (T: FromRedisValue + Eq + Ord)
2530);
2531
2532#[cfg(feature = "hashbrown")]
2533impl_from_redis_value_for_set!(
2534    for <T, S> hashbrown::HashSet<T, S>,
2535    where (T: FromRedisValue + Eq + Hash, S: BuildHasher + Default)
2536);
2537
2538#[cfg(feature = "ahash")]
2539impl_from_redis_value_for_set!(
2540    for <T> ahash::AHashSet<T>,
2541    where (T: FromRedisValue + Eq + Hash)
2542);
2543
2544impl FromRedisValue for Value {
2545    fn from_redis_value(v: &Value) -> RedisResult<Value> {
2546        Ok(v.clone())
2547    }
2548    fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2549        Ok(v)
2550    }
2551}
2552
2553impl FromRedisValue for () {
2554    fn from_redis_value(_v: &Value) -> RedisResult<()> {
2555        Ok(())
2556    }
2557}
2558
2559macro_rules! from_redis_value_for_tuple {
2560    () => ();
2561    ($(#[$meta:meta],)*$($name:ident,)+) => (
2562        $(#[$meta])*
2563        impl<$($name: FromRedisValue),*> FromRedisValue for ($($name,)*) {
2564            // we have local variables named T1 as dummies and those
2565            // variables are unused.
2566            #[allow(non_snake_case, unused_variables)]
2567            fn from_redis_value(v: &Value) -> RedisResult<($($name,)*)> {
2568                let v = get_inner_value(v);
2569                match *v {
2570                    Value::Array(ref items) => {
2571                        // hacky way to count the tuple size
2572                        let mut n = 0;
2573                        $(let $name = (); n += 1;)*
2574                        if items.len() != n {
2575                            invalid_type_error!(v, "Array response of wrong dimension")
2576                        }
2577
2578                        // this is pretty ugly too.  The { i += 1; i - 1} is rust's
2579                        // postfix increment :)
2580                        let mut i = 0;
2581                        Ok(($({let $name = (); from_redis_value(
2582                             &items[{ i += 1; i - 1 }])?},)*))
2583                    }
2584
2585                    Value::Map(ref items) => {
2586                        // hacky way to count the tuple size
2587                        let mut n = 0;
2588                        $(let $name = (); n += 1;)*
2589                        if n != 2 {
2590                            invalid_type_error!(v, "Map response of wrong dimension")
2591                        }
2592
2593                        let mut flatten_items = vec![];
2594                        for (k,v) in items {
2595                            flatten_items.push(k);
2596                            flatten_items.push(v);
2597                        }
2598
2599                        // this is pretty ugly too.  The { i += 1; i - 1} is rust's
2600                        // postfix increment :)
2601                        let mut i = 0;
2602                        Ok(($({let $name = (); from_redis_value(
2603                             &flatten_items[{ i += 1; i - 1 }])?},)*))
2604                    }
2605
2606                    _ => invalid_type_error!(v, "Not a Array response")
2607                }
2608            }
2609
2610            // we have local variables named T1 as dummies and those
2611            // variables are unused.
2612            #[allow(non_snake_case, unused_variables)]
2613            fn from_owned_redis_value(v: Value) -> RedisResult<($($name,)*)> {
2614                let v = get_owned_inner_value(v);
2615                match v {
2616                    Value::Array(mut items) => {
2617                        // hacky way to count the tuple size
2618                        let mut n = 0;
2619                        $(let $name = (); n += 1;)*
2620                        if items.len() != n {
2621                            invalid_type_error!(Value::Array(items), "Array response of wrong dimension")
2622                        }
2623
2624                        // this is pretty ugly too.  The { i += 1; i - 1} is rust's
2625                        // postfix increment :)
2626                        let mut i = 0;
2627                        Ok(($({let $name = (); from_owned_redis_value(
2628                            ::std::mem::replace(&mut items[{ i += 1; i - 1 }], Value::Nil)
2629                        )?},)*))
2630                    }
2631
2632                    Value::Map(items) => {
2633                        // hacky way to count the tuple size
2634                        let mut n = 0;
2635                        $(let $name = (); n += 1;)*
2636                        if n != 2 {
2637                            invalid_type_error!(Value::Map(items), "Map response of wrong dimension")
2638                        }
2639
2640                        let mut flatten_items = vec![];
2641                        for (k,v) in items {
2642                            flatten_items.push(k);
2643                            flatten_items.push(v);
2644                        }
2645
2646                        // this is pretty ugly too.  The { i += 1; i - 1} is rust's
2647                        // postfix increment :)
2648                        let mut i = 0;
2649                        Ok(($({let $name = (); from_redis_value(
2650                             &flatten_items[{ i += 1; i - 1 }])?},)*))
2651                    }
2652
2653                    _ => invalid_type_error!(v, "Not a Array response")
2654                }
2655            }
2656
2657            #[allow(non_snake_case, unused_variables)]
2658            fn from_redis_values(items: &[Value]) -> RedisResult<Vec<($($name,)*)>> {
2659                // hacky way to count the tuple size
2660                let mut n = 0;
2661                $(let $name = (); n += 1;)*
2662                let mut rv = vec![];
2663                if items.len() == 0 {
2664                    return Ok(rv)
2665                }
2666                //It's uglier then before!
2667                for item in items {
2668                    match item {
2669                        Value::Array(ch) => {
2670                           if  let [$($name),*] = &ch[..] {
2671                            rv.push(($(from_redis_value(&$name)?),*),)
2672                           };
2673                        },
2674                        _ => {},
2675
2676                    }
2677                }
2678                if !rv.is_empty(){
2679                    return Ok(rv);
2680                }
2681
2682                if let  [$($name),*] = items{
2683                    rv.push(($(from_redis_value($name)?),*),);
2684                    return Ok(rv);
2685                }
2686                 for chunk in items.chunks_exact(n) {
2687                    match chunk {
2688                        [$($name),*] => rv.push(($(from_redis_value($name)?),*),),
2689                         _ => {},
2690                    }
2691                }
2692                Ok(rv)
2693            }
2694
2695            #[allow(non_snake_case, unused_variables)]
2696            fn from_owned_redis_values(mut items: Vec<Value>) -> RedisResult<Vec<($($name,)*)>> {
2697                // hacky way to count the tuple size
2698                let mut n = 0;
2699                $(let $name = (); n += 1;)*
2700
2701                let mut rv = vec![];
2702                if items.len() == 0 {
2703                    return Ok(rv)
2704                }
2705                //It's uglier then before!
2706                for item in items.iter_mut() {
2707                    match item {
2708                        Value::Array(ref mut ch) => {
2709                        if  let [$($name),*] = &mut ch[..] {
2710                            rv.push(($(from_owned_redis_value(std::mem::replace($name, Value::Nil))?),*),);
2711                           };
2712                        },
2713                        _ => {},
2714                    }
2715                }
2716                if !rv.is_empty(){
2717                    return Ok(rv);
2718                }
2719
2720                let mut rv = Vec::with_capacity(items.len() / n);
2721                if items.len() == 0 {
2722                    return Ok(rv)
2723                }
2724                for chunk in items.chunks_mut(n) {
2725                    match chunk {
2726                        // Take each element out of the chunk with `std::mem::replace`, leaving a `Value::Nil`
2727                        // in its place. This allows each `Value` to be parsed without being copied.
2728                        // Since `items` is consume by this function and not used later, this replacement
2729                        // is not observable to the rest of the code.
2730                        [$($name),*] => rv.push(($(from_owned_redis_value(std::mem::replace($name, Value::Nil))?),*),),
2731                         _ => unreachable!(),
2732                    }
2733                }
2734                Ok(rv)
2735            }
2736        }
2737    )
2738}
2739
2740from_redis_value_for_tuple! { #[cfg_attr(docsrs, doc(fake_variadic))], #[doc = "This trait is implemented for tuples up to 12 items long."], T, }
2741from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, }
2742from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, }
2743from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, }
2744from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, }
2745from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, }
2746from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, }
2747from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, }
2748from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, }
2749from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, }
2750from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
2751from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
2752
2753impl FromRedisValue for InfoDict {
2754    fn from_redis_value(v: &Value) -> RedisResult<InfoDict> {
2755        let v = get_inner_value(v);
2756        let s: String = from_redis_value(v)?;
2757        Ok(InfoDict::new(&s))
2758    }
2759    fn from_owned_redis_value(v: Value) -> RedisResult<InfoDict> {
2760        let v = get_owned_inner_value(v);
2761        let s: String = from_owned_redis_value(v)?;
2762        Ok(InfoDict::new(&s))
2763    }
2764}
2765
2766impl<T: FromRedisValue> FromRedisValue for Option<T> {
2767    fn from_redis_value(v: &Value) -> RedisResult<Option<T>> {
2768        let v = get_inner_value(v);
2769        if *v == Value::Nil {
2770            return Ok(None);
2771        }
2772        Ok(Some(from_redis_value(v)?))
2773    }
2774    fn from_owned_redis_value(v: Value) -> RedisResult<Option<T>> {
2775        let v = get_owned_inner_value(v);
2776        if v == Value::Nil {
2777            return Ok(None);
2778        }
2779        Ok(Some(from_owned_redis_value(v)?))
2780    }
2781}
2782
2783#[cfg(feature = "bytes")]
2784impl FromRedisValue for bytes::Bytes {
2785    fn from_redis_value(v: &Value) -> RedisResult<Self> {
2786        let v = get_inner_value(v);
2787        match v {
2788            Value::BulkString(bytes_vec) => Ok(bytes::Bytes::copy_from_slice(bytes_vec.as_ref())),
2789            _ => invalid_type_error!(v, "Not a bulk string"),
2790        }
2791    }
2792    fn from_owned_redis_value(v: Value) -> RedisResult<Self> {
2793        let v = get_owned_inner_value(v);
2794        match v {
2795            Value::BulkString(bytes_vec) => Ok(bytes_vec.into()),
2796            _ => invalid_type_error!(v, "Not a bulk string"),
2797        }
2798    }
2799}
2800
2801#[cfg(feature = "uuid")]
2802impl FromRedisValue for uuid::Uuid {
2803    fn from_redis_value(v: &Value) -> RedisResult<Self> {
2804        match *v {
2805            Value::BulkString(ref bytes) => Ok(uuid::Uuid::from_slice(bytes)?),
2806            _ => invalid_type_error!(v, "Response type not uuid compatible."),
2807        }
2808    }
2809}
2810
2811#[cfg(feature = "uuid")]
2812impl ToRedisArgs for uuid::Uuid {
2813    fn write_redis_args<W>(&self, out: &mut W)
2814    where
2815        W: ?Sized + RedisWrite,
2816    {
2817        out.write_arg(self.as_bytes());
2818    }
2819}
2820
2821/// A shortcut function to invoke `FromRedisValue::from_redis_value`
2822/// to make the API slightly nicer.
2823pub fn from_redis_value<T: FromRedisValue>(v: &Value) -> RedisResult<T> {
2824    FromRedisValue::from_redis_value(v)
2825}
2826
2827/// A shortcut function to invoke `FromRedisValue::from_owned_redis_value`
2828/// to make the API slightly nicer.
2829pub fn from_owned_redis_value<T: FromRedisValue>(v: Value) -> RedisResult<T> {
2830    FromRedisValue::from_owned_redis_value(v)
2831}
2832
2833/// Enum representing the communication protocol with the server.
2834///
2835/// This enum represents the types of data that the server can send to the client,
2836/// and the capabilities that the client can use.
2837#[derive(Clone, Eq, PartialEq, Default, Debug, Copy)]
2838pub enum ProtocolVersion {
2839    /// <https://github.com/redis/redis-specifications/blob/master/protocol/RESP2.md>
2840    #[default]
2841    RESP2,
2842    /// <https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md>
2843    RESP3,
2844}
2845
2846/// Helper enum that is used to define option for the hash expire commands
2847#[derive(Clone, Copy)]
2848pub enum ExpireOption {
2849    /// NONE -- Set expiration regardless of the field's current expiration.
2850    NONE,
2851    /// NX -- Only set expiration only when the field has no expiration.
2852    NX,
2853    /// XX -- Only set expiration only when the field has an existing expiration.
2854    XX,
2855    /// GT -- Only set expiration only when the new expiration is greater than current one.
2856    GT,
2857    /// LT -- Only set expiration only when the new expiration is less than current one.
2858    LT,
2859}
2860
2861impl ToRedisArgs for ExpireOption {
2862    fn write_redis_args<W>(&self, out: &mut W)
2863    where
2864        W: ?Sized + RedisWrite,
2865    {
2866        match self {
2867            ExpireOption::NX => out.write_arg(b"NX"),
2868            ExpireOption::XX => out.write_arg(b"XX"),
2869            ExpireOption::GT => out.write_arg(b"GT"),
2870            ExpireOption::LT => out.write_arg(b"LT"),
2871            _ => {}
2872        }
2873    }
2874}
2875
2876#[derive(Debug, Clone, PartialEq)]
2877/// A push message from the server.
2878pub struct PushInfo {
2879    /// Push Kind
2880    pub kind: PushKind,
2881    /// Data from push message
2882    pub data: Vec<Value>,
2883}
2884
2885impl PushInfo {
2886    pub(crate) fn disconnect() -> Self {
2887        PushInfo {
2888            kind: crate::PushKind::Disconnection,
2889            data: vec![],
2890        }
2891    }
2892}
2893
2894pub(crate) type SyncPushSender = std::sync::mpsc::Sender<PushInfo>;
2895
2896// A consistent error value for connections closed without a reason.
2897#[cfg(any(feature = "aio", feature = "r2d2"))]
2898pub(crate) fn closed_connection_error() -> RedisError {
2899    RedisError::from(io::Error::from(io::ErrorKind::BrokenPipe))
2900}