Skip to main content

redis/
types.rs

1use crate::errors::ParsingError;
2#[cfg(feature = "ahash")]
3pub(crate) use ahash::{AHashMap as HashMap, AHashSet as HashSet};
4#[cfg(feature = "num-bigint")]
5use num_bigint::BigInt;
6use std::borrow::Cow;
7#[cfg(not(feature = "ahash"))]
8pub(crate) use std::collections::{HashMap, HashSet};
9use std::default::Default;
10use std::ffi::CString;
11use std::fmt;
12use std::hash::{BuildHasher, Hash};
13use std::io;
14use std::ops::Deref;
15use std::str::from_utf8;
16
17use crate::errors::{RedisError, ServerError};
18
19/// Helper enum that is used to define expiry time
20#[non_exhaustive]
21pub enum Expiry {
22    /// EX seconds -- Set the specified expire time, in seconds.
23    EX(u64),
24    /// PX milliseconds -- Set the specified expire time, in milliseconds.
25    PX(u64),
26    /// EXAT timestamp-seconds -- Set the specified Unix time at which the key will expire, in seconds.
27    EXAT(u64),
28    /// PXAT timestamp-milliseconds -- Set the specified Unix time at which the key will expire, in milliseconds.
29    PXAT(u64),
30    /// PERSIST -- Remove the time to live associated with the key.
31    PERSIST,
32}
33
34/// Helper enum that is used to define expiry time for SET command
35#[derive(Clone, Copy)]
36#[non_exhaustive]
37pub enum SetExpiry {
38    /// EX seconds -- Set the specified expire time, in seconds.
39    EX(u64),
40    /// PX milliseconds -- Set the specified expire time, in milliseconds.
41    PX(u64),
42    /// EXAT timestamp-seconds -- Set the specified Unix time at which the key will expire, in seconds.
43    EXAT(u64),
44    /// PXAT timestamp-milliseconds -- Set the specified Unix time at which the key will expire, in milliseconds.
45    PXAT(u64),
46    /// KEEPTTL -- Retain the time to live associated with the key.
47    KEEPTTL,
48}
49
50impl ToRedisArgs for SetExpiry {
51    fn write_redis_args<W>(&self, out: &mut W)
52    where
53        W: ?Sized + RedisWrite,
54    {
55        match self {
56            SetExpiry::EX(secs) => {
57                out.write_arg(b"EX");
58                out.write_arg(format!("{secs}").as_bytes());
59            }
60            SetExpiry::PX(millis) => {
61                out.write_arg(b"PX");
62                out.write_arg(format!("{millis}").as_bytes());
63            }
64            SetExpiry::EXAT(unix_time) => {
65                out.write_arg(b"EXAT");
66                out.write_arg(format!("{unix_time}").as_bytes());
67            }
68            SetExpiry::PXAT(unix_time) => {
69                out.write_arg(b"PXAT");
70                out.write_arg(format!("{unix_time}").as_bytes());
71            }
72            SetExpiry::KEEPTTL => {
73                out.write_arg(b"KEEPTTL");
74            }
75        }
76    }
77}
78
79/// Helper enum that is used to define existence checks
80#[derive(Clone, Copy)]
81#[non_exhaustive]
82pub enum ExistenceCheck {
83    /// NX -- Only set the key if it does not already exist.
84    NX,
85    /// XX -- Only set the key if it already exists.
86    XX,
87}
88
89impl ToRedisArgs for ExistenceCheck {
90    fn write_redis_args<W>(&self, out: &mut W)
91    where
92        W: ?Sized + RedisWrite,
93    {
94        match self {
95            ExistenceCheck::NX => {
96                out.write_arg(b"NX");
97            }
98            ExistenceCheck::XX => {
99                out.write_arg(b"XX");
100            }
101        }
102    }
103}
104
105/// Helper enum that is used to define field existence checks
106#[derive(Clone, Copy)]
107#[non_exhaustive]
108pub enum FieldExistenceCheck {
109    /// FNX -- Only set the fields if all do not already exist.
110    FNX,
111    /// FXX -- Only set the fields if all already exist.
112    FXX,
113}
114
115impl ToRedisArgs for FieldExistenceCheck {
116    fn write_redis_args<W>(&self, out: &mut W)
117    where
118        W: ?Sized + RedisWrite,
119    {
120        match self {
121            FieldExistenceCheck::FNX => out.write_arg(b"FNX"),
122            FieldExistenceCheck::FXX => out.write_arg(b"FXX"),
123        }
124    }
125}
126
127/// Helper enum that is used in some situations to describe
128/// the behavior of arguments in a numeric context.
129#[derive(PartialEq, Eq, Clone, Debug, Copy)]
130#[non_exhaustive]
131pub enum NumericBehavior {
132    /// This argument is not numeric.
133    NonNumeric,
134    /// This argument is an integer.
135    NumberIsInteger,
136    /// This argument is a floating point value.
137    NumberIsFloat,
138}
139
140/// Internal low-level redis value enum.
141#[derive(PartialEq, Clone, Default)]
142#[non_exhaustive]
143pub enum Value {
144    /// A nil response from the server.
145    #[default]
146    Nil,
147    /// An integer response.  Note that there are a few situations
148    /// in which redis actually returns a string for an integer which
149    /// is why this library generally treats integers and strings
150    /// the same for all numeric responses.
151    Int(i64),
152    /// An arbitrary binary data, usually represents a binary-safe string.
153    BulkString(Vec<u8>),
154    /// A response containing an array with more data. This is generally used by redis
155    /// to express nested structures.
156    Array(Vec<Value>),
157    /// A simple string response, without line breaks and not binary safe.
158    SimpleString(String),
159    /// A status response which represents the string "OK".
160    Okay,
161    /// Unordered key,value list from the server. Use `as_map_iter` function.
162    Map(Vec<(Value, Value)>),
163    /// Attribute value from the server. Client will give data instead of whole Attribute type.
164    Attribute {
165        /// Data that attributes belong to.
166        data: Box<Value>,
167        /// Key,Value list of attributes.
168        attributes: Vec<(Value, Value)>,
169    },
170    /// Unordered set value from the server.
171    Set(Vec<Value>),
172    /// A floating number response from the server.
173    Double(f64),
174    /// A boolean response from the server.
175    Boolean(bool),
176    /// First String is format and other is the string
177    VerbatimString {
178        /// Text's format type
179        format: VerbatimFormat,
180        /// Remaining string check format before using!
181        text: String,
182    },
183    #[cfg(feature = "num-bigint")]
184    /// Very large number that out of the range of the signed 64 bit numbers
185    BigNumber(BigInt),
186    #[cfg(not(feature = "num-bigint"))]
187    /// Very large number that out of the range of the signed 64 bit numbers
188    BigNumber(Vec<u8>),
189    /// Push data from the server.
190    Push {
191        /// Push Kind
192        kind: PushKind,
193        /// Remaining data from push message
194        data: Vec<Value>,
195    },
196    /// Represents an error message from the server
197    ServerError(ServerError),
198}
199
200/// Helper enum that is used to define comparisons between values and their digests
201///
202/// # Example
203/// ```rust
204/// use redis::ValueComparison;
205///
206/// // Create comparisons using constructor methods
207/// let eq_comparison = ValueComparison::ifeq("my_value");
208/// let ne_comparison = ValueComparison::ifne("other_value");
209/// let deq_comparison = ValueComparison::ifdeq("digest_hash");
210/// let dne_comparison = ValueComparison::ifdne("other_digest");
211/// ```
212#[derive(Clone, Debug)]
213#[non_exhaustive]
214pub enum ValueComparison {
215    /// Value is equal
216    IFEQ(String),
217    /// Value is not equal
218    IFNE(String),
219    /// Value's digest is equal
220    IFDEQ(String),
221    /// Value's digest is not equal
222    IFDNE(String),
223}
224
225impl ValueComparison {
226    /// Create a new IFEQ (if equal) comparison
227    ///
228    /// Performs the operation only if the key's current value is equal to the provided value.
229    ///
230    /// For SET: Sets the key only if its current value matches. Non-existent keys are not created.
231    /// For DEL_EX: Deletes the key only if its current value matches. Non-existent keys are ignored.
232    pub fn ifeq(value: impl ToSingleRedisArg) -> Self {
233        ValueComparison::IFEQ(Self::arg_to_string(value))
234    }
235
236    /// Create a new IFNE (if not equal) comparison
237    ///
238    /// Performs the operation only if the key's current value is not equal to the provided value.
239    ///
240    /// For SET: Sets the key only if its current value doesn't match. Non-existent keys are created.
241    /// For DEL_EX: Deletes the key only if its current value doesn't match. Non-existent keys are ignored.
242    pub fn ifne(value: impl ToSingleRedisArg) -> Self {
243        ValueComparison::IFNE(Self::arg_to_string(value))
244    }
245
246    /// Create a new IFDEQ (if digest equal) comparison
247    ///
248    /// Performs the operation only if the digest of the key's current value is equal to the provided digest.
249    ///
250    /// For SET: Sets the key only if its current value's digest matches. Non-existent keys are not created.
251    /// For DEL_EX: Deletes the key only if its current value's digest matches. Non-existent keys are ignored.
252    ///
253    /// Use [`calculate_value_digest`] to compute the digest of a value.
254    pub fn ifdeq(digest: impl ToSingleRedisArg) -> Self {
255        ValueComparison::IFDEQ(Self::arg_to_string(digest))
256    }
257
258    /// Create a new IFDNE (if digest not equal) comparison
259    ///
260    /// Performs the operation only if the digest of the key's current value is not equal to the provided digest.
261    ///
262    /// For SET: Sets the key only if its current value's digest doesn't match. Non-existent keys are created.
263    /// For DEL_EX: Deletes the key only if its current value's digest doesn't match. Non-existent keys are ignored.
264    ///
265    /// Use [`calculate_value_digest`] to compute the digest of a value.
266    pub fn ifdne(digest: impl ToSingleRedisArg) -> Self {
267        ValueComparison::IFDNE(Self::arg_to_string(digest))
268    }
269
270    fn arg_to_string(value: impl ToSingleRedisArg) -> String {
271        let args = value.to_redis_args();
272        String::from_utf8_lossy(&args[0]).into_owned()
273    }
274}
275
276impl ToRedisArgs for ValueComparison {
277    fn write_redis_args<W>(&self, out: &mut W)
278    where
279        W: ?Sized + RedisWrite,
280    {
281        match self {
282            ValueComparison::IFEQ(value) => {
283                out.write_arg(b"IFEQ");
284                out.write_arg(value.as_bytes());
285            }
286            ValueComparison::IFNE(value) => {
287                out.write_arg(b"IFNE");
288                out.write_arg(value.as_bytes());
289            }
290            ValueComparison::IFDEQ(digest) => {
291                out.write_arg(b"IFDEQ");
292                out.write_arg(digest.as_bytes());
293            }
294            ValueComparison::IFDNE(digest) => {
295                out.write_arg(b"IFDNE");
296                out.write_arg(digest.as_bytes());
297            }
298        }
299    }
300}
301
302/// `VerbatimString`'s format types defined by spec
303#[derive(PartialEq, Clone, Debug)]
304#[non_exhaustive]
305pub enum VerbatimFormat {
306    /// Unknown type to catch future formats.
307    Unknown(String),
308    /// `mkd` format
309    Markdown,
310    /// `txt` format
311    Text,
312}
313
314/// `Push` type's currently known kinds.
315#[derive(PartialEq, Clone, Debug)]
316#[non_exhaustive]
317pub enum PushKind {
318    /// `Disconnection` is sent from the **library** when connection is closed.
319    Disconnection,
320    /// Other kind to catch future kinds.
321    Other(String),
322    /// `invalidate` is received when a key is changed/deleted.
323    Invalidate,
324    /// `message` is received when pubsub message published by another client.
325    Message,
326    /// `pmessage` is received when pubsub message published by another client and client subscribed to topic via pattern.
327    PMessage,
328    /// `smessage` is received when pubsub message published by another client and client subscribed to it with sharding.
329    SMessage,
330    /// `unsubscribe` is received when client unsubscribed from a channel.
331    Unsubscribe,
332    /// `punsubscribe` is received when client unsubscribed from a pattern.
333    PUnsubscribe,
334    /// `sunsubscribe` is received when client unsubscribed from a shard channel.
335    SUnsubscribe,
336    /// `subscribe` is received when client subscribed to a channel.
337    Subscribe,
338    /// `psubscribe` is received when client subscribed to a pattern.
339    PSubscribe,
340    /// `ssubscribe` is received when client subscribed to a shard channel.
341    SSubscribe,
342}
343
344impl PushKind {
345    #[cfg(feature = "aio")]
346    pub(crate) fn has_reply(&self) -> bool {
347        matches!(
348            self,
349            &PushKind::Unsubscribe
350                | &PushKind::PUnsubscribe
351                | &PushKind::SUnsubscribe
352                | &PushKind::Subscribe
353                | &PushKind::PSubscribe
354                | &PushKind::SSubscribe
355        )
356    }
357}
358
359impl fmt::Display for VerbatimFormat {
360    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361        match self {
362            VerbatimFormat::Markdown => write!(f, "mkd"),
363            VerbatimFormat::Unknown(val) => write!(f, "{val}"),
364            VerbatimFormat::Text => write!(f, "txt"),
365        }
366    }
367}
368
369impl fmt::Display for PushKind {
370    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
371        match self {
372            PushKind::Other(kind) => write!(f, "{kind}"),
373            PushKind::Invalidate => write!(f, "invalidate"),
374            PushKind::Message => write!(f, "message"),
375            PushKind::PMessage => write!(f, "pmessage"),
376            PushKind::SMessage => write!(f, "smessage"),
377            PushKind::Unsubscribe => write!(f, "unsubscribe"),
378            PushKind::PUnsubscribe => write!(f, "punsubscribe"),
379            PushKind::SUnsubscribe => write!(f, "sunsubscribe"),
380            PushKind::Subscribe => write!(f, "subscribe"),
381            PushKind::PSubscribe => write!(f, "psubscribe"),
382            PushKind::SSubscribe => write!(f, "ssubscribe"),
383            PushKind::Disconnection => write!(f, "disconnection"),
384        }
385    }
386}
387
388#[non_exhaustive]
389pub enum MapIter<'a> {
390    Array(std::slice::Iter<'a, Value>),
391    Map(std::slice::Iter<'a, (Value, Value)>),
392}
393
394impl<'a> Iterator for MapIter<'a> {
395    type Item = (&'a Value, &'a Value);
396
397    fn next(&mut self) -> Option<Self::Item> {
398        match self {
399            MapIter::Array(iter) => Some((iter.next()?, iter.next()?)),
400            MapIter::Map(iter) => {
401                let (k, v) = iter.next()?;
402                Some((k, v))
403            }
404        }
405    }
406
407    fn size_hint(&self) -> (usize, Option<usize>) {
408        match self {
409            MapIter::Array(iter) => iter.size_hint(),
410            MapIter::Map(iter) => iter.size_hint(),
411        }
412    }
413}
414
415#[non_exhaustive]
416pub enum OwnedMapIter {
417    Array(std::vec::IntoIter<Value>),
418    Map(std::vec::IntoIter<(Value, Value)>),
419}
420
421impl Iterator for OwnedMapIter {
422    type Item = (Value, Value);
423
424    fn next(&mut self) -> Option<Self::Item> {
425        match self {
426            OwnedMapIter::Array(iter) => Some((iter.next()?, iter.next()?)),
427            OwnedMapIter::Map(iter) => iter.next(),
428        }
429    }
430
431    fn size_hint(&self) -> (usize, Option<usize>) {
432        match self {
433            OwnedMapIter::Array(iter) => {
434                let (low, high) = iter.size_hint();
435                (low / 2, high.map(|h| h / 2))
436            }
437            OwnedMapIter::Map(iter) => iter.size_hint(),
438        }
439    }
440}
441
442/// Values are generally not used directly unless you are using the
443/// more low level functionality in the library.  For the most part
444/// this is hidden with the help of the `FromRedisValue` trait.
445///
446/// While on the redis protocol there is an error type this is already
447/// separated at an early point so the value only holds the remaining
448/// types.
449impl Value {
450    /// Checks if the return value looks like it fulfils the cursor
451    /// protocol.  That means the result is an array item of length
452    /// two with the first one being a cursor and the second an
453    /// array response.
454    pub fn looks_like_cursor(&self) -> bool {
455        match *self {
456            Value::Array(ref items) => {
457                if items.len() != 2 {
458                    return false;
459                }
460                matches!(items[0], Value::BulkString(_)) && matches!(items[1], Value::Array(_))
461            }
462            _ => false,
463        }
464    }
465
466    /// Returns an `&[Value]` if `self` is compatible with a sequence type
467    pub fn as_sequence(&self) -> Option<&[Value]> {
468        match self {
469            Value::Array(items) => Some(&items[..]),
470            Value::Set(items) => Some(&items[..]),
471            Value::Nil => Some(&[]),
472            _ => None,
473        }
474    }
475
476    /// Returns a `Vec<Value>` if `self` is compatible with a sequence type,
477    /// otherwise returns `Err(self)`.
478    pub fn into_sequence(self) -> Result<Vec<Value>, Value> {
479        match self {
480            Value::Array(items) => Ok(items),
481            Value::Set(items) => Ok(items),
482            Value::Nil => Ok(vec![]),
483            _ => Err(self),
484        }
485    }
486
487    /// Returns an iterator of `(&Value, &Value)` if `self` is compatible with a map type
488    pub fn as_map_iter(&self) -> Option<MapIter<'_>> {
489        match self {
490            Value::Array(items) => {
491                if items.len() % 2 == 0 {
492                    Some(MapIter::Array(items.iter()))
493                } else {
494                    None
495                }
496            }
497            Value::Map(items) => Some(MapIter::Map(items.iter())),
498            _ => None,
499        }
500    }
501
502    /// Returns an iterator of `(Value, Value)` if `self` is compatible with a map type.
503    /// If not, returns `Err(self)`.
504    pub fn into_map_iter(self) -> Result<OwnedMapIter, Value> {
505        match self {
506            Value::Array(items) => {
507                if items.len() % 2 == 0 {
508                    Ok(OwnedMapIter::Array(items.into_iter()))
509                } else {
510                    Err(Value::Array(items))
511                }
512            }
513            Value::Map(items) => Ok(OwnedMapIter::Map(items.into_iter())),
514            _ => Err(self),
515        }
516    }
517
518    /// If value contains a server error, return it as an Err. Otherwise wrap the value in Ok.
519    pub fn extract_error(self) -> RedisResult<Self> {
520        match self {
521            Self::Array(val) => Ok(Self::Array(Self::extract_error_vec(val)?)),
522            Self::Map(map) => Ok(Self::Map(Self::extract_error_map(map)?)),
523            Self::Attribute { data, attributes } => {
524                let data = Box::new((*data).extract_error()?);
525                let attributes = Self::extract_error_map(attributes)?;
526                Ok(Value::Attribute { data, attributes })
527            }
528            Self::Set(set) => Ok(Self::Set(Self::extract_error_vec(set)?)),
529            Self::Push { kind, data } => Ok(Self::Push {
530                kind,
531                data: Self::extract_error_vec(data)?,
532            }),
533            Value::ServerError(err) => Err(err.into()),
534            _ => Ok(self),
535        }
536    }
537
538    pub(crate) fn extract_error_vec(vec: Vec<Self>) -> RedisResult<Vec<Self>> {
539        vec.into_iter()
540            .map(Self::extract_error)
541            .collect::<RedisResult<Vec<_>>>()
542    }
543
544    pub(crate) fn extract_error_map(map: Vec<(Self, Self)>) -> RedisResult<Vec<(Self, Self)>> {
545        let mut vec = Vec::with_capacity(map.len());
546        for (key, value) in map.into_iter() {
547            vec.push((key.extract_error()?, value.extract_error()?));
548        }
549        Ok(vec)
550    }
551
552    fn is_collection_of_len(&self, len: usize) -> bool {
553        match self {
554            Value::Array(values) => values.len() == len,
555            Value::Map(items) => items.len() * 2 == len,
556            Value::Set(values) => values.len() == len,
557            _ => false,
558        }
559    }
560
561    #[cfg(feature = "cluster-async")]
562    pub(crate) fn is_error_that_requires_action(&self) -> bool {
563        matches!(self, Self::ServerError(error) if error.requires_action())
564    }
565}
566
567impl fmt::Debug for Value {
568    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
569        match *self {
570            Value::Nil => write!(fmt, "nil"),
571            Value::Int(val) => write!(fmt, "int({val:?})"),
572            Value::BulkString(ref val) => match from_utf8(val) {
573                Ok(x) => write!(fmt, "bulk-string('{x:?}')"),
574                Err(_) => write!(fmt, "binary-data({val:?})"),
575            },
576            Value::Array(ref values) => write!(fmt, "array({values:?})"),
577            Value::Push { ref kind, ref data } => write!(fmt, "push({kind:?}, {data:?})"),
578            Value::Okay => write!(fmt, "ok"),
579            Value::SimpleString(ref s) => write!(fmt, "simple-string({s:?})"),
580            Value::Map(ref values) => write!(fmt, "map({values:?})"),
581            Value::Attribute {
582                ref data,
583                attributes: _,
584            } => write!(fmt, "attribute({data:?})"),
585            Value::Set(ref values) => write!(fmt, "set({values:?})"),
586            Value::Double(ref d) => write!(fmt, "double({d:?})"),
587            Value::Boolean(ref b) => write!(fmt, "boolean({b:?})"),
588            Value::VerbatimString {
589                ref format,
590                ref text,
591            } => {
592                write!(fmt, "verbatim-string({format:?},{text:?})")
593            }
594            Value::BigNumber(ref m) => write!(fmt, "big-number({m:?})"),
595            Value::ServerError(ref err) => match err.details() {
596                Some(details) => write!(fmt, "Server error: `{}: {details}`", err.code()),
597                None => write!(fmt, "Server error: `{}`", err.code()),
598            },
599        }
600    }
601}
602
603/// Library generic result type.
604pub type RedisResult<T> = Result<T, RedisError>;
605
606impl<T: FromRedisValue> FromRedisValue for RedisResult<T> {
607    fn from_redis_value_ref(value: &Value) -> Result<Self, ParsingError> {
608        match value {
609            Value::ServerError(err) => Ok(Err(err.clone().into())),
610            _ => from_redis_value_ref(value).map(|result| Ok(result)),
611        }
612    }
613
614    fn from_redis_value(value: Value) -> Result<Self, ParsingError> {
615        match value {
616            Value::ServerError(err) => Ok(Err(err.into())),
617            _ => from_redis_value(value).map(|result| Ok(result)),
618        }
619    }
620}
621
622/// Library generic future type.
623#[cfg(feature = "aio")]
624pub type RedisFuture<'a, T> = futures_util::future::BoxFuture<'a, RedisResult<T>>;
625
626/// An info dictionary type.
627#[derive(Debug, Clone)]
628pub struct InfoDict {
629    map: HashMap<String, Value>,
630}
631
632/// This type provides convenient access to key/value data returned by
633/// the "INFO" command.  It acts like a regular mapping but also has
634/// a convenience method `get` which can return data in the appropriate
635/// type.
636///
637/// For instance this can be used to query the server for the role it's
638/// in (master, slave) etc:
639///
640/// ```rust,no_run
641/// # fn do_something() -> redis::RedisResult<()> {
642/// # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
643/// # let mut con = client.get_connection().unwrap();
644/// let info : redis::InfoDict = redis::cmd("INFO").query(&mut con)?;
645/// let role : Option<String> = info.get("role");
646/// # Ok(()) }
647/// ```
648impl InfoDict {
649    /// Creates a new info dictionary from a string in the response of
650    /// the INFO command.  Each line is a key, value pair with the
651    /// key and value separated by a colon (`:`).  Lines starting with a
652    /// hash (`#`) are ignored.
653    pub fn new(kvpairs: &str) -> InfoDict {
654        let mut map = HashMap::new();
655        for line in kvpairs.lines() {
656            if line.is_empty() || line.starts_with('#') {
657                continue;
658            }
659            let mut p = line.splitn(2, ':');
660            let (k, v) = match (p.next(), p.next()) {
661                (Some(k), Some(v)) => (k.to_string(), v.to_string()),
662                _ => continue,
663            };
664            map.insert(k, Value::SimpleString(v));
665        }
666        InfoDict { map }
667    }
668
669    /// Fetches a value by key and converts it into the given type.
670    /// Typical types are `String`, `bool` and integer types.
671    pub fn get<T: FromRedisValue>(&self, key: &str) -> Option<T> {
672        match self.find(&key) {
673            Some(x) => from_redis_value_ref(x).ok(),
674            None => None,
675        }
676    }
677
678    /// Looks up a key in the info dict.
679    pub fn find(&self, key: &&str) -> Option<&Value> {
680        self.map.get(*key)
681    }
682
683    /// Checks if a key is contained in the info dicf.
684    pub fn contains_key(&self, key: &&str) -> bool {
685        self.find(key).is_some()
686    }
687
688    /// Returns the size of the info dict.
689    pub fn len(&self) -> usize {
690        self.map.len()
691    }
692
693    /// Checks if the dict is empty.
694    pub fn is_empty(&self) -> bool {
695        self.map.is_empty()
696    }
697}
698
699impl Deref for InfoDict {
700    type Target = HashMap<String, Value>;
701
702    fn deref(&self) -> &Self::Target {
703        &self.map
704    }
705}
706
707/// High level representation of response to the [`ROLE`][1] command.
708///
709/// [1]: https://redis.io/docs/latest/commands/role/
710#[derive(Debug, Clone, Eq, PartialEq)]
711#[non_exhaustive]
712pub enum Role {
713    /// Represents a primary role, which is `master` in legacy Redis terminology.
714    Primary {
715        /// The current primary replication offset
716        replication_offset: u64,
717        /// List of replica, each represented by a tuple of IP, port and the last acknowledged replication offset.
718        replicas: Vec<ReplicaInfo>,
719    },
720    /// Represents a replica role, which is `slave` in legacy Redis terminology.
721    Replica {
722        /// The IP of the primary.
723        primary_ip: String,
724        /// The port of the primary.
725        primary_port: u16,
726        /// The state of the replication from the point of view of the primary.
727        replication_state: String,
728        /// The amount of data received from the replica so far in terms of primary replication offset.
729        data_received: u64,
730    },
731    /// Represents a sentinel role.
732    Sentinel {
733        /// List of primary names monitored by this Sentinel instance.
734        primary_names: Vec<String>,
735    },
736}
737
738/// Replication information for a replica, as returned by the [`ROLE`][1] command.
739///
740/// [1]: https://redis.io/docs/latest/commands/role/
741#[derive(Debug, Clone, Eq, PartialEq)]
742pub struct ReplicaInfo {
743    /// The IP of the replica.
744    pub ip: String,
745    /// The port of the replica.
746    pub port: u16,
747    /// The last acknowledged replication offset.
748    pub replication_offset: i64,
749}
750
751impl FromRedisValue for ReplicaInfo {
752    fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError> {
753        Self::from_redis_value(v.clone())
754    }
755
756    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
757        let v = match get_owned_inner_value(v).into_sequence() {
758            Ok(v) => v,
759            Err(v) => crate::errors::invalid_type_error!(v, "Replica response should be an array"),
760        };
761        if v.len() < 3 {
762            crate::errors::invalid_type_error!(v, "Replica array is too short, expected 3 elements")
763        }
764        let mut v = v.into_iter();
765        let ip = from_redis_value(v.next().expect("len was checked"))?;
766        let port = from_redis_value(v.next().expect("len was checked"))?;
767        let offset = from_redis_value(v.next().expect("len was checked"))?;
768        Ok(ReplicaInfo {
769            ip,
770            port,
771            replication_offset: offset,
772        })
773    }
774}
775
776impl FromRedisValue for Role {
777    fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError> {
778        Self::from_redis_value(v.clone())
779    }
780
781    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
782        let v = match get_owned_inner_value(v).into_sequence() {
783            Ok(v) => v,
784            Err(v) => crate::errors::invalid_type_error!(v, "Role response should be an array"),
785        };
786        if v.len() < 2 {
787            crate::errors::invalid_type_error!(
788                v,
789                "Role array is too short, expected at least 2 elements"
790            )
791        }
792        match &v[0] {
793            Value::BulkString(role) => match role.as_slice() {
794                b"master" => Role::new_primary(v),
795                b"slave" => Role::new_replica(v),
796                b"sentinel" => Role::new_sentinel(v),
797                _ => crate::errors::invalid_type_error!(
798                    v,
799                    "Role type is not master, slave or sentinel"
800                ),
801            },
802            _ => crate::errors::invalid_type_error!(v, "Role type is not a bulk string"),
803        }
804    }
805}
806
807impl Role {
808    fn new_primary(values: Vec<Value>) -> Result<Self, ParsingError> {
809        if values.len() < 3 {
810            crate::errors::invalid_type_error!(
811                values,
812                "Role primary response too short, expected 3 elements"
813            )
814        }
815
816        let mut values = values.into_iter();
817        _ = values.next();
818
819        let replication_offset = from_redis_value(values.next().expect("len was checked"))?;
820        let replicas = from_redis_value(values.next().expect("len was checked"))?;
821
822        Ok(Role::Primary {
823            replication_offset,
824            replicas,
825        })
826    }
827
828    fn new_replica(values: Vec<Value>) -> Result<Self, ParsingError> {
829        if values.len() < 5 {
830            crate::errors::invalid_type_error!(
831                values,
832                "Role replica response too short, expected 5 elements"
833            )
834        }
835
836        let mut values = values.into_iter();
837        _ = values.next();
838
839        let primary_ip = from_redis_value(values.next().expect("len was checked"))?;
840        let primary_port = from_redis_value(values.next().expect("len was checked"))?;
841        let replication_state = from_redis_value(values.next().expect("len was checked"))?;
842        let data_received = from_redis_value(values.next().expect("len was checked"))?;
843
844        Ok(Role::Replica {
845            primary_ip,
846            primary_port,
847            replication_state,
848            data_received,
849        })
850    }
851
852    fn new_sentinel(values: Vec<Value>) -> Result<Self, ParsingError> {
853        if values.len() < 2 {
854            crate::errors::invalid_type_error!(
855                values,
856                "Role sentinel response too short, expected at least 2 elements"
857            )
858        }
859        let second_val = values.into_iter().nth(1).expect("len was checked");
860        let primary_names = from_redis_value(second_val)?;
861        Ok(Role::Sentinel { primary_names })
862    }
863}
864
865/// Abstraction trait for redis command abstractions.
866pub trait RedisWrite {
867    /// Accepts a serialized redis command.
868    fn write_arg(&mut self, arg: &[u8]);
869
870    /// Accepts a serialized redis command.
871    fn write_arg_fmt(&mut self, arg: impl fmt::Display) {
872        self.write_arg(arg.to_string().as_bytes())
873    }
874
875    /// Appends an empty argument to the command, and returns a
876    /// [`std::io::Write`] instance that can write to it.
877    ///
878    /// Writing multiple arguments into this buffer is unsupported. The resulting
879    /// data will be interpreted as one argument by Redis.
880    ///
881    /// Writing no data is supported and is similar to having an empty bytestring
882    /// as an argument.
883    fn writer_for_next_arg(&mut self) -> impl io::Write + '_;
884
885    /// Reserve space for `additional` arguments in the command
886    ///
887    /// `additional` is a list of the byte sizes of the arguments.
888    ///
889    /// # Examples
890    /// Sending some Protobufs with `prost` to Redis.
891    /// ```rust,ignore
892    /// use prost::Message;
893    ///
894    /// let to_send: Vec<SomeType> = todo!();
895    /// let mut cmd = Cmd::new();
896    ///
897    /// // Calculate and reserve the space for the args
898    /// cmd.reserve_space_for_args(to_send.iter().map(Message::encoded_len));
899    ///
900    /// // Write the args to the buffer
901    /// for arg in to_send {
902    ///     // Encode the type directly into the Cmd buffer
903    ///     // Supplying the required capacity again is not needed for Cmd,
904    ///     // but can be useful for other implementers like Vec<Vec<u8>>.
905    ///     arg.encode(cmd.bufmut_for_next_arg(arg.encoded_len()));
906    /// }
907    ///
908    /// ```
909    ///
910    /// # Implementation note
911    /// The default implementation provided by this trait is a no-op. It's therefore strongly
912    /// recommended to implement this function. Depending on the internal buffer it might only
913    /// be possible to use the numbers of arguments (`additional.len()`) or the total expected
914    /// capacity (`additional.iter().sum()`). Implementors should assume that the caller will
915    /// be wrong and might over or under specify the amount of arguments and space required.
916    fn reserve_space_for_args(&mut self, additional: impl IntoIterator<Item = usize>) {
917        // _additional would show up in the documentation, so we assign it
918        // to make it used.
919        let _do_nothing = additional;
920    }
921
922    #[cfg(feature = "bytes")]
923    /// Appends an empty argument to the command, and returns a
924    /// [`bytes::BufMut`] instance that can write to it.
925    ///
926    /// `capacity` should be equal or greater to the amount of bytes
927    /// expected, as some implementations might not be able to resize
928    /// the returned buffer.
929    ///
930    /// Writing multiple arguments into this buffer is unsupported. The resulting
931    /// data will be interpreted as one argument by Redis.
932    ///
933    /// Writing no data is supported and is similar to having an empty bytestring
934    /// as an argument.
935    fn bufmut_for_next_arg(&mut self, capacity: usize) -> impl bytes::BufMut + '_ {
936        // This default implementation is not the most efficient, but does
937        // allow for implementers to skip this function. This means that
938        // upstream libraries that implement this trait don't suddenly
939        // stop working because someone enabled one of the async features.
940
941        /// Has a temporary buffer that is written to [`writer_for_next_arg`]
942        /// on drop.
943        struct Wrapper<'a> {
944            /// The buffer, implements [`bytes::BufMut`] allowing passthrough
945            buf: Vec<u8>,
946            /// The writer to the command, used on drop
947            writer: Box<dyn io::Write + 'a>,
948        }
949        unsafe impl bytes::BufMut for Wrapper<'_> {
950            fn remaining_mut(&self) -> usize {
951                self.buf.remaining_mut()
952            }
953
954            unsafe fn advance_mut(&mut self, cnt: usize) {
955                unsafe {
956                    self.buf.advance_mut(cnt);
957                }
958            }
959
960            fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
961                self.buf.chunk_mut()
962            }
963
964            // Vec specializes these methods, so we do too
965            fn put<T: bytes::buf::Buf>(&mut self, src: T)
966            where
967                Self: Sized,
968            {
969                self.buf.put(src);
970            }
971
972            fn put_slice(&mut self, src: &[u8]) {
973                self.buf.put_slice(src);
974            }
975
976            fn put_bytes(&mut self, val: u8, cnt: usize) {
977                self.buf.put_bytes(val, cnt);
978            }
979        }
980        impl Drop for Wrapper<'_> {
981            fn drop(&mut self) {
982                self.writer.write_all(&self.buf).unwrap()
983            }
984        }
985
986        Wrapper {
987            buf: Vec::with_capacity(capacity),
988            writer: Box::new(self.writer_for_next_arg()),
989        }
990    }
991}
992
993impl RedisWrite for Vec<Vec<u8>> {
994    fn write_arg(&mut self, arg: &[u8]) {
995        self.push(arg.to_owned());
996    }
997
998    fn write_arg_fmt(&mut self, arg: impl fmt::Display) {
999        self.push(arg.to_string().into_bytes())
1000    }
1001
1002    fn writer_for_next_arg(&mut self) -> impl io::Write + '_ {
1003        self.push(Vec::new());
1004        self.last_mut().unwrap()
1005    }
1006
1007    fn reserve_space_for_args(&mut self, additional: impl IntoIterator<Item = usize>) {
1008        // It would be nice to do this, but there's no way to store where we currently are.
1009        // Checking for the first empty Vec is not possible, as it's valid to write empty args.
1010        // self.extend(additional.iter().copied().map(Vec::with_capacity));
1011        // So we just reserve space for the extra args and have to forgo the extra optimisation
1012        self.reserve(additional.into_iter().count());
1013    }
1014
1015    #[cfg(feature = "bytes")]
1016    fn bufmut_for_next_arg(&mut self, capacity: usize) -> impl bytes::BufMut + '_ {
1017        self.push(Vec::with_capacity(capacity));
1018        self.last_mut().unwrap()
1019    }
1020}
1021
1022/// This trait marks that a value is serialized only into a single Redis value.
1023///
1024/// This should be implemented only for types that are serialized into exactly one value,
1025/// otherwise the compiler can't ensure the correctness of some commands.
1026pub trait ToSingleRedisArg: ToRedisArgs {}
1027
1028/// Used to convert a value into one or multiple redis argument
1029/// strings.  Most values will produce exactly one item but in
1030/// some cases it might make sense to produce more than one.
1031pub trait ToRedisArgs: Sized {
1032    /// This converts the value into a vector of bytes.  Each item
1033    /// is a single argument.  Most items generate a vector of a
1034    /// single item.
1035    ///
1036    /// The exception to this rule currently are vectors of items.
1037    fn to_redis_args(&self) -> Vec<Vec<u8>> {
1038        let mut out = Vec::new();
1039        self.write_redis_args(&mut out);
1040        out
1041    }
1042
1043    /// This writes the value into a vector of bytes.  Each item
1044    /// is a single argument.  Most items generate a single item.
1045    ///
1046    /// The exception to this rule currently are vectors of items.
1047    fn write_redis_args<W>(&self, out: &mut W)
1048    where
1049        W: ?Sized + RedisWrite;
1050
1051    /// Returns an information about the contained value with regards
1052    /// to it's numeric behavior in a redis context.  This is used in
1053    /// some high level concepts to switch between different implementations
1054    /// of redis functions (for instance `INCR` vs `INCRBYFLOAT`).
1055    fn describe_numeric_behavior(&self) -> NumericBehavior {
1056        NumericBehavior::NonNumeric
1057    }
1058
1059    /// Returns the number of arguments this value will generate.
1060    ///
1061    /// This is used in some high level functions to intelligently switch
1062    /// between `GET` and `MGET` variants. Also, for some commands like HEXPIREDAT
1063    /// which require a specific number of arguments, this method can be used to
1064    /// know the number of arguments.
1065    fn num_of_args(&self) -> usize {
1066        1
1067    }
1068
1069    /// This only exists internally as a workaround for the lack of
1070    /// specialization.
1071    #[doc(hidden)]
1072    fn write_args_from_slice<W>(items: &[Self], out: &mut W)
1073    where
1074        W: ?Sized + RedisWrite,
1075    {
1076        Self::make_arg_iter_ref(items.iter(), out)
1077    }
1078
1079    /// This only exists internally as a workaround for the lack of
1080    /// specialization.
1081    #[doc(hidden)]
1082    fn make_arg_iter_ref<'a, I, W>(items: I, out: &mut W)
1083    where
1084        W: ?Sized + RedisWrite,
1085        I: Iterator<Item = &'a Self>,
1086        Self: 'a,
1087    {
1088        for item in items {
1089            item.write_redis_args(out);
1090        }
1091    }
1092
1093    #[doc(hidden)]
1094    fn is_single_vec_arg(items: &[Self]) -> bool {
1095        items.len() == 1 && items[0].num_of_args() <= 1
1096    }
1097}
1098
1099macro_rules! itoa_based_to_redis_impl {
1100    ($t:ty, $numeric:expr) => {
1101        impl ToRedisArgs for $t {
1102            fn write_redis_args<W>(&self, out: &mut W)
1103            where
1104                W: ?Sized + RedisWrite,
1105            {
1106                let mut buf = ::itoa::Buffer::new();
1107                let s = buf.format(*self);
1108                out.write_arg(s.as_bytes())
1109            }
1110
1111            fn describe_numeric_behavior(&self) -> NumericBehavior {
1112                $numeric
1113            }
1114        }
1115
1116        impl ToSingleRedisArg for $t {}
1117    };
1118}
1119
1120macro_rules! non_zero_itoa_based_to_redis_impl {
1121    ($t:ty, $numeric:expr) => {
1122        impl ToRedisArgs for $t {
1123            fn write_redis_args<W>(&self, out: &mut W)
1124            where
1125                W: ?Sized + RedisWrite,
1126            {
1127                let mut buf = ::itoa::Buffer::new();
1128                let s = buf.format(self.get());
1129                out.write_arg(s.as_bytes())
1130            }
1131
1132            fn describe_numeric_behavior(&self) -> NumericBehavior {
1133                $numeric
1134            }
1135        }
1136
1137        impl ToSingleRedisArg for $t {}
1138    };
1139}
1140
1141macro_rules! ryu_based_to_redis_impl {
1142    ($t:ty, $numeric:expr) => {
1143        impl ToRedisArgs for $t {
1144            fn write_redis_args<W>(&self, out: &mut W)
1145            where
1146                W: ?Sized + RedisWrite,
1147            {
1148                let mut buf = ::ryu::Buffer::new();
1149                let s = buf.format(*self);
1150                out.write_arg(s.as_bytes())
1151            }
1152
1153            fn describe_numeric_behavior(&self) -> NumericBehavior {
1154                $numeric
1155            }
1156        }
1157
1158        impl ToSingleRedisArg for $t {}
1159    };
1160}
1161
1162impl ToRedisArgs for u8 {
1163    fn write_redis_args<W>(&self, out: &mut W)
1164    where
1165        W: ?Sized + RedisWrite,
1166    {
1167        let mut buf = ::itoa::Buffer::new();
1168        let s = buf.format(*self);
1169        out.write_arg(s.as_bytes())
1170    }
1171
1172    fn write_args_from_slice<W>(items: &[u8], out: &mut W)
1173    where
1174        W: ?Sized + RedisWrite,
1175    {
1176        out.write_arg(items);
1177    }
1178
1179    fn is_single_vec_arg(_items: &[u8]) -> bool {
1180        true
1181    }
1182}
1183
1184impl ToSingleRedisArg for u8 {}
1185
1186itoa_based_to_redis_impl!(i8, NumericBehavior::NumberIsInteger);
1187itoa_based_to_redis_impl!(i16, NumericBehavior::NumberIsInteger);
1188itoa_based_to_redis_impl!(u16, NumericBehavior::NumberIsInteger);
1189itoa_based_to_redis_impl!(i32, NumericBehavior::NumberIsInteger);
1190itoa_based_to_redis_impl!(u32, NumericBehavior::NumberIsInteger);
1191itoa_based_to_redis_impl!(i64, NumericBehavior::NumberIsInteger);
1192itoa_based_to_redis_impl!(u64, NumericBehavior::NumberIsInteger);
1193itoa_based_to_redis_impl!(i128, NumericBehavior::NumberIsInteger);
1194itoa_based_to_redis_impl!(u128, NumericBehavior::NumberIsInteger);
1195itoa_based_to_redis_impl!(isize, NumericBehavior::NumberIsInteger);
1196itoa_based_to_redis_impl!(usize, NumericBehavior::NumberIsInteger);
1197
1198non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU8, NumericBehavior::NumberIsInteger);
1199non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI8, NumericBehavior::NumberIsInteger);
1200non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU16, NumericBehavior::NumberIsInteger);
1201non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI16, NumericBehavior::NumberIsInteger);
1202non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU32, NumericBehavior::NumberIsInteger);
1203non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI32, NumericBehavior::NumberIsInteger);
1204non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU64, NumericBehavior::NumberIsInteger);
1205non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI64, NumericBehavior::NumberIsInteger);
1206non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU128, NumericBehavior::NumberIsInteger);
1207non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI128, NumericBehavior::NumberIsInteger);
1208non_zero_itoa_based_to_redis_impl!(core::num::NonZeroUsize, NumericBehavior::NumberIsInteger);
1209non_zero_itoa_based_to_redis_impl!(core::num::NonZeroIsize, NumericBehavior::NumberIsInteger);
1210
1211ryu_based_to_redis_impl!(f32, NumericBehavior::NumberIsFloat);
1212ryu_based_to_redis_impl!(f64, NumericBehavior::NumberIsFloat);
1213
1214#[cfg(any(
1215    feature = "rust_decimal",
1216    feature = "bigdecimal",
1217    feature = "num-bigint"
1218))]
1219macro_rules! bignum_to_redis_impl {
1220    ($t:ty) => {
1221        impl ToRedisArgs for $t {
1222            fn write_redis_args<W>(&self, out: &mut W)
1223            where
1224                W: ?Sized + RedisWrite,
1225            {
1226                out.write_arg(&self.to_string().into_bytes())
1227            }
1228        }
1229
1230        impl ToSingleRedisArg for $t {}
1231    };
1232}
1233
1234#[cfg(feature = "rust_decimal")]
1235bignum_to_redis_impl!(rust_decimal::Decimal);
1236#[cfg(feature = "bigdecimal")]
1237bignum_to_redis_impl!(bigdecimal::BigDecimal);
1238#[cfg(feature = "num-bigint")]
1239bignum_to_redis_impl!(num_bigint::BigInt);
1240#[cfg(feature = "num-bigint")]
1241bignum_to_redis_impl!(num_bigint::BigUint);
1242
1243impl ToRedisArgs for bool {
1244    fn write_redis_args<W>(&self, out: &mut W)
1245    where
1246        W: ?Sized + RedisWrite,
1247    {
1248        out.write_arg(if *self { b"1" } else { b"0" })
1249    }
1250}
1251
1252impl ToSingleRedisArg for bool {}
1253
1254impl ToRedisArgs for String {
1255    fn write_redis_args<W>(&self, out: &mut W)
1256    where
1257        W: ?Sized + RedisWrite,
1258    {
1259        out.write_arg(self.as_bytes())
1260    }
1261}
1262impl ToSingleRedisArg for String {}
1263
1264impl ToRedisArgs for &str {
1265    fn write_redis_args<W>(&self, out: &mut W)
1266    where
1267        W: ?Sized + RedisWrite,
1268    {
1269        out.write_arg(self.as_bytes())
1270    }
1271}
1272
1273impl ToSingleRedisArg for &str {}
1274
1275impl<'a, T> ToRedisArgs for Cow<'a, T>
1276where
1277    T: ToOwned + ?Sized,
1278    &'a T: ToRedisArgs,
1279    T::Owned: ToRedisArgs,
1280{
1281    fn write_redis_args<W>(&self, out: &mut W)
1282    where
1283        W: ?Sized + RedisWrite,
1284    {
1285        match self {
1286            Cow::Borrowed(inner) => inner.write_redis_args(out),
1287            Cow::Owned(inner) => inner.write_redis_args(out),
1288        }
1289    }
1290}
1291
1292impl<'a, T> ToSingleRedisArg for Cow<'a, T>
1293where
1294    T: ToOwned + ?Sized,
1295    &'a T: ToSingleRedisArg,
1296    T::Owned: ToSingleRedisArg,
1297{
1298}
1299
1300impl<T: ToRedisArgs> ToRedisArgs for Option<T> {
1301    fn write_redis_args<W>(&self, out: &mut W)
1302    where
1303        W: ?Sized + RedisWrite,
1304    {
1305        if let Some(ref x) = *self {
1306            x.write_redis_args(out);
1307        }
1308    }
1309
1310    fn describe_numeric_behavior(&self) -> NumericBehavior {
1311        match *self {
1312            Some(ref x) => x.describe_numeric_behavior(),
1313            None => NumericBehavior::NonNumeric,
1314        }
1315    }
1316
1317    fn num_of_args(&self) -> usize {
1318        match *self {
1319            Some(ref x) => x.num_of_args(),
1320            None => 0,
1321        }
1322    }
1323}
1324
1325macro_rules! impl_write_redis_args_for_collection {
1326    ($type:ty) => {
1327        impl<'a, T> ToRedisArgs for $type
1328        where
1329            T: ToRedisArgs,
1330        {
1331            #[inline]
1332            fn write_redis_args<W>(&self, out: &mut W)
1333            where
1334                W: ?Sized + RedisWrite,
1335            {
1336                ToRedisArgs::write_args_from_slice(self, out)
1337            }
1338
1339            fn num_of_args(&self) -> usize {
1340                if ToRedisArgs::is_single_vec_arg(&self[..]) {
1341                    return 1;
1342                }
1343                if self.len() == 1 {
1344                    self[0].num_of_args()
1345                } else {
1346                    self.len()
1347                }
1348            }
1349
1350            fn describe_numeric_behavior(&self) -> NumericBehavior {
1351                NumericBehavior::NonNumeric
1352            }
1353        }
1354    };
1355}
1356
1357macro_rules! deref_to_write_redis_args_impl {
1358    ($type:ty) => {
1359        impl<'a, T> ToRedisArgs for $type
1360        where
1361            T: ToRedisArgs,
1362        {
1363            #[inline]
1364            fn write_redis_args<W>(&self, out: &mut W)
1365            where
1366                W: ?Sized + RedisWrite,
1367            {
1368                (**self).write_redis_args(out)
1369            }
1370
1371            fn num_of_args(&self) -> usize {
1372                (**self).num_of_args()
1373            }
1374
1375            fn describe_numeric_behavior(&self) -> NumericBehavior {
1376                (**self).describe_numeric_behavior()
1377            }
1378        }
1379
1380        impl<'a, T> ToSingleRedisArg for $type where T: ToSingleRedisArg {}
1381    };
1382}
1383
1384deref_to_write_redis_args_impl! {&'a T}
1385deref_to_write_redis_args_impl! {&'a mut T}
1386deref_to_write_redis_args_impl! {Box<T>}
1387deref_to_write_redis_args_impl! {std::sync::Arc<T>}
1388deref_to_write_redis_args_impl! {std::rc::Rc<T>}
1389impl_write_redis_args_for_collection! {&'a [T]}
1390impl_write_redis_args_for_collection! {&'a mut [T]}
1391impl_write_redis_args_for_collection! {Box<[T]>}
1392impl_write_redis_args_for_collection! {std::sync::Arc<[T]>}
1393impl_write_redis_args_for_collection! {std::rc::Rc<[T]>}
1394impl_write_redis_args_for_collection! {Vec<T>}
1395impl ToSingleRedisArg for &[u8] {}
1396impl ToSingleRedisArg for &mut [u8] {}
1397impl ToSingleRedisArg for Vec<u8> {}
1398impl ToSingleRedisArg for Box<[u8]> {}
1399impl ToSingleRedisArg for std::rc::Rc<[u8]> {}
1400impl ToSingleRedisArg for std::sync::Arc<[u8]> {}
1401
1402/// @note: Redis cannot store empty sets so the application has to
1403/// check whether the set is empty and if so, not attempt to use that
1404/// result
1405macro_rules! impl_to_redis_args_for_set {
1406    (for <$($TypeParam:ident),+> $SetType:ty, where ($($WhereClause:tt)+) ) => {
1407        impl< $($TypeParam),+ > ToRedisArgs for $SetType
1408        where
1409            $($WhereClause)+
1410        {
1411            fn write_redis_args<W>(&self, out: &mut W)
1412            where
1413                W: ?Sized + RedisWrite,
1414            {
1415                ToRedisArgs::make_arg_iter_ref(self.iter(), out)
1416            }
1417
1418            fn num_of_args(&self) -> usize {
1419                self.len()
1420            }
1421        }
1422    };
1423}
1424
1425impl_to_redis_args_for_set!(
1426    for <T, S> std::collections::HashSet<T, S>,
1427    where (T: ToRedisArgs + Hash + Eq)
1428);
1429
1430impl_to_redis_args_for_set!(
1431    for <T> std::collections::BTreeSet<T>,
1432    where (T: ToRedisArgs + Hash + Eq + Ord)
1433);
1434
1435#[cfg(feature = "hashbrown")]
1436impl_to_redis_args_for_set!(
1437    for <T, S> hashbrown::HashSet<T, S>,
1438    where (T: ToRedisArgs + Hash + Eq)
1439);
1440
1441#[cfg(feature = "ahash")]
1442impl_to_redis_args_for_set!(
1443    for <T, S> ahash::AHashSet<T, S>,
1444    where (T: ToRedisArgs + Hash + Eq)
1445);
1446
1447/// @note: Redis cannot store empty maps so the application has to
1448/// check whether the set is empty and if so, not attempt to use that
1449/// result
1450macro_rules! impl_to_redis_args_for_map {
1451    (
1452        $(#[$meta:meta])*
1453        for <$($TypeParam:ident),+> $MapType:ty,
1454        where ($($WhereClause:tt)+)
1455    ) => {
1456        $(#[$meta])*
1457        impl< $($TypeParam),+ > ToRedisArgs for $MapType
1458        where
1459            $($WhereClause)+
1460        {
1461            fn write_redis_args<W>(&self, out: &mut W)
1462            where
1463                W: ?Sized + RedisWrite,
1464            {
1465                for (key, value) in self {
1466                    // Ensure key and value produce a single argument each
1467                    assert!(key.num_of_args() <= 1 && value.num_of_args() <= 1);
1468                    key.write_redis_args(out);
1469                    value.write_redis_args(out);
1470                }
1471            }
1472
1473            fn num_of_args(&self) -> usize {
1474                self.len()
1475            }
1476        }
1477    };
1478}
1479
1480impl_to_redis_args_for_map!(
1481    for <K, V, S> std::collections::HashMap<K, V, S>,
1482    where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1483);
1484
1485impl_to_redis_args_for_map!(
1486    /// this flattens BTreeMap into something that goes well with HMSET
1487    for <K, V> std::collections::BTreeMap<K, V>,
1488    where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1489);
1490
1491#[cfg(feature = "hashbrown")]
1492impl_to_redis_args_for_map!(
1493    for <K, V, S> hashbrown::HashMap<K, V, S>,
1494    where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1495);
1496
1497#[cfg(feature = "ahash")]
1498impl_to_redis_args_for_map!(
1499    for <K, V, S> ahash::AHashMap<K, V, S>,
1500    where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1501);
1502
1503macro_rules! to_redis_args_for_tuple {
1504    () => ();
1505    ($(#[$meta:meta],)*$($name:ident,)+) => (
1506        $(#[$meta])*
1507        impl<$($name: ToRedisArgs),*> ToRedisArgs for ($($name,)*) {
1508            // we have local variables named T1 as dummies and those
1509            // variables are unused.
1510            #[allow(non_snake_case, unused_variables)]
1511            fn write_redis_args<W>(&self, out: &mut W) where W: ?Sized + RedisWrite {
1512                let ($(ref $name,)*) = *self;
1513                $($name.write_redis_args(out);)*
1514            }
1515
1516            #[allow(non_snake_case, unused_variables)]
1517            fn num_of_args(&self) -> usize {
1518                let mut n: usize = 0;
1519                $(let $name = (); n += 1;)*
1520                n
1521            }
1522        }
1523    )
1524}
1525
1526to_redis_args_for_tuple! { #[cfg_attr(docsrs, doc(fake_variadic))], #[doc = "This trait is implemented for tuples up to 12 items long."], T, }
1527to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, }
1528to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, }
1529to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, }
1530to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, }
1531to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, }
1532to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, }
1533to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, }
1534to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, }
1535to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, }
1536to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
1537to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
1538
1539impl<T: ToRedisArgs, const N: usize> ToRedisArgs for &[T; N] {
1540    fn write_redis_args<W>(&self, out: &mut W)
1541    where
1542        W: ?Sized + RedisWrite,
1543    {
1544        ToRedisArgs::write_args_from_slice(self.as_slice(), out)
1545    }
1546
1547    fn num_of_args(&self) -> usize {
1548        if ToRedisArgs::is_single_vec_arg(&self[..]) {
1549            return 1;
1550        }
1551        if self.len() == 1 {
1552            self[0].num_of_args()
1553        } else {
1554            self.len()
1555        }
1556    }
1557}
1558impl<const N: usize> ToSingleRedisArg for &[u8; N] {}
1559
1560fn vec_to_array<T, const N: usize>(
1561    items: Vec<T>,
1562    original_value: &Value,
1563) -> Result<[T; N], ParsingError> {
1564    match items.try_into() {
1565        Ok(array) => Ok(array),
1566        Err(items) => {
1567            let msg = format!(
1568                "Response has wrong dimension, expected {N}, got {}",
1569                items.len()
1570            );
1571            crate::errors::invalid_type_error!(original_value, msg)
1572        }
1573    }
1574}
1575
1576impl<T: FromRedisValue, const N: usize> FromRedisValue for [T; N] {
1577    fn from_redis_value_ref(value: &Value) -> Result<[T; N], ParsingError> {
1578        match *value {
1579            Value::BulkString(ref bytes) => match FromRedisValue::from_byte_slice(bytes) {
1580                Some(items) => vec_to_array(items, value),
1581                None => {
1582                    let msg = format!(
1583                        "Conversion to Array[{}; {N}] failed",
1584                        std::any::type_name::<T>()
1585                    );
1586                    crate::errors::invalid_type_error!(value, msg)
1587                }
1588            },
1589            Value::Array(ref items) => {
1590                let items = FromRedisValue::from_redis_value_refs(items)?;
1591                vec_to_array(items, value)
1592            }
1593            Value::Nil => vec_to_array(vec![], value),
1594            _ => crate::errors::invalid_type_error!(value, "Response type not array compatible"),
1595        }
1596    }
1597
1598    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
1599        Self::from_redis_value_ref(&v)
1600    }
1601}
1602
1603/// This trait is used to convert a redis value into a more appropriate
1604/// type.
1605///
1606/// While a redis `Value` can represent any response that comes
1607/// back from the redis server, usually you want to map this into something
1608/// that works better in rust.  For instance you might want to convert the
1609/// return value into a `String` or an integer.
1610///
1611/// This trait is well supported throughout the library and you can
1612/// implement it for your own types if you want.
1613///
1614/// In addition to what you can see from the docs, this is also implemented
1615/// for tuples up to size 12 and for `Vec<u8>`.
1616pub trait FromRedisValue: Sized {
1617    /// Given a redis `Value` this attempts to convert it into the given
1618    /// destination type.  If that fails because it's not compatible an
1619    /// appropriate error is generated.
1620    fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError> {
1621        // By default, fall back to `from_redis_value_ref`.
1622        // This function only needs to be implemented if it can benefit
1623        // from taking `v` by value.
1624        Self::from_redis_value(v.clone())
1625    }
1626
1627    /// Given a redis `Value` this attempts to convert it into the given
1628    /// destination type.  If that fails because it's not compatible an
1629    /// appropriate error is generated.
1630    fn from_redis_value(v: Value) -> Result<Self, ParsingError>;
1631
1632    /// Similar to `from_redis_value_ref` but constructs a vector of objects
1633    /// from another vector of values.  This primarily exists internally
1634    /// to customize the behavior for vectors of tuples.
1635    fn from_redis_value_refs(items: &[Value]) -> Result<Vec<Self>, ParsingError> {
1636        items
1637            .iter()
1638            .map(FromRedisValue::from_redis_value_ref)
1639            .collect()
1640    }
1641
1642    /// The same as `from_redis_value_refs`, but takes a `Vec<Value>` instead
1643    /// of a `&[Value]`.
1644    fn from_redis_values(items: Vec<Value>) -> Result<Vec<Self>, ParsingError> {
1645        items
1646            .into_iter()
1647            .map(FromRedisValue::from_redis_value)
1648            .collect()
1649    }
1650
1651    /// The same as `from_redis_values`, but returns a result for each
1652    /// conversion to make handling them case-by-case possible.
1653    fn from_each_redis_values(items: Vec<Value>) -> Vec<Result<Self, ParsingError>> {
1654        items
1655            .into_iter()
1656            .map(FromRedisValue::from_redis_value)
1657            .collect()
1658    }
1659
1660    /// Convert bytes to a single element vector.
1661    fn from_byte_slice(_vec: &[u8]) -> Option<Vec<Self>> {
1662        Self::from_redis_value(Value::BulkString(_vec.into()))
1663            .map(|rv| vec![rv])
1664            .ok()
1665    }
1666
1667    /// Convert bytes to a single element vector.
1668    fn from_byte_vec(_vec: Vec<u8>) -> Result<Vec<Self>, ParsingError> {
1669        Self::from_redis_value(Value::BulkString(_vec)).map(|rv| vec![rv])
1670    }
1671}
1672
1673fn get_inner_value(v: &Value) -> &Value {
1674    if let Value::Attribute {
1675        data,
1676        attributes: _,
1677    } = v
1678    {
1679        data.as_ref()
1680    } else {
1681        v
1682    }
1683}
1684
1685fn get_owned_inner_value(v: Value) -> Value {
1686    if let Value::Attribute {
1687        data,
1688        attributes: _,
1689    } = v
1690    {
1691        *data
1692    } else {
1693        v
1694    }
1695}
1696
1697macro_rules! from_redis_value_for_num_internal {
1698    ($t:ty, $v:expr) => {{
1699        let v = if let Value::Attribute {
1700            data,
1701            attributes: _,
1702        } = $v
1703        {
1704            data
1705        } else {
1706            $v
1707        };
1708        match *v {
1709            Value::Int(val) => Ok(val as $t),
1710            Value::SimpleString(ref s) => match s.parse::<$t>() {
1711                Ok(rv) => Ok(rv),
1712                Err(_) => crate::errors::invalid_type_error!(v, "Could not convert from string."),
1713            },
1714            Value::BulkString(ref bytes) => match from_utf8(bytes)?.parse::<$t>() {
1715                Ok(rv) => Ok(rv),
1716                Err(_) => crate::errors::invalid_type_error!(v, "Could not convert from string."),
1717            },
1718            Value::Double(val) => Ok(val as $t),
1719            _ => crate::errors::invalid_type_error!(v, "Response type not convertible to numeric."),
1720        }
1721    }};
1722}
1723
1724macro_rules! from_redis_value_for_num {
1725    ($t:ty) => {
1726        impl FromRedisValue for $t {
1727            fn from_redis_value_ref(v: &Value) -> Result<$t, ParsingError> {
1728                from_redis_value_for_num_internal!($t, v)
1729            }
1730
1731            fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
1732                Self::from_redis_value_ref(&v)
1733            }
1734        }
1735    };
1736}
1737
1738impl FromRedisValue for u8 {
1739    fn from_redis_value_ref(v: &Value) -> Result<u8, ParsingError> {
1740        from_redis_value_for_num_internal!(u8, v)
1741    }
1742
1743    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
1744        Self::from_redis_value_ref(&v)
1745    }
1746
1747    // this hack allows us to specialize Vec<u8> to work with binary data.
1748    fn from_byte_slice(vec: &[u8]) -> Option<Vec<u8>> {
1749        Some(vec.to_vec())
1750    }
1751    fn from_byte_vec(vec: Vec<u8>) -> Result<Vec<u8>, ParsingError> {
1752        Ok(vec)
1753    }
1754}
1755
1756from_redis_value_for_num!(i8);
1757from_redis_value_for_num!(i16);
1758from_redis_value_for_num!(u16);
1759from_redis_value_for_num!(i32);
1760from_redis_value_for_num!(u32);
1761from_redis_value_for_num!(i64);
1762from_redis_value_for_num!(u64);
1763from_redis_value_for_num!(i128);
1764from_redis_value_for_num!(u128);
1765from_redis_value_for_num!(f32);
1766from_redis_value_for_num!(f64);
1767from_redis_value_for_num!(isize);
1768from_redis_value_for_num!(usize);
1769
1770#[cfg(any(
1771    feature = "rust_decimal",
1772    feature = "bigdecimal",
1773    feature = "num-bigint"
1774))]
1775macro_rules! from_redis_value_for_bignum_internal {
1776    ($t:ty, $v:expr) => {{
1777        let v = $v;
1778        match *v {
1779            Value::Int(val) => <$t>::try_from(val).map_err(|_| {
1780                crate::errors::invalid_type_error_inner!(v, "Could not convert from integer.")
1781            }),
1782            Value::SimpleString(ref s) => match s.parse::<$t>() {
1783                Ok(rv) => Ok(rv),
1784                Err(_) => crate::errors::invalid_type_error!(v, "Could not convert from string."),
1785            },
1786            Value::BulkString(ref bytes) => match from_utf8(bytes)?.parse::<$t>() {
1787                Ok(rv) => Ok(rv),
1788                Err(_) => crate::errors::invalid_type_error!(v, "Could not convert from string."),
1789            },
1790            _ => crate::errors::invalid_type_error!(v, "Response type not convertible to numeric."),
1791        }
1792    }};
1793}
1794
1795#[cfg(any(
1796    feature = "rust_decimal",
1797    feature = "bigdecimal",
1798    feature = "num-bigint"
1799))]
1800macro_rules! from_redis_value_for_bignum {
1801    ($t:ty) => {
1802        impl FromRedisValue for $t {
1803            fn from_redis_value_ref(v: &Value) -> Result<$t, ParsingError> {
1804                from_redis_value_for_bignum_internal!($t, v)
1805            }
1806
1807            fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
1808                Self::from_redis_value_ref(&v)
1809            }
1810        }
1811    };
1812}
1813
1814#[cfg(feature = "rust_decimal")]
1815from_redis_value_for_bignum!(rust_decimal::Decimal);
1816#[cfg(feature = "bigdecimal")]
1817from_redis_value_for_bignum!(bigdecimal::BigDecimal);
1818#[cfg(feature = "num-bigint")]
1819from_redis_value_for_bignum!(num_bigint::BigInt);
1820#[cfg(feature = "num-bigint")]
1821from_redis_value_for_bignum!(num_bigint::BigUint);
1822
1823impl FromRedisValue for bool {
1824    fn from_redis_value_ref(v: &Value) -> Result<bool, ParsingError> {
1825        let v = get_inner_value(v);
1826        match *v {
1827            Value::Nil => Ok(false),
1828            Value::Int(val) => Ok(val != 0),
1829            Value::SimpleString(ref s) => {
1830                if &s[..] == "1" {
1831                    Ok(true)
1832                } else if &s[..] == "0" {
1833                    Ok(false)
1834                } else {
1835                    crate::errors::invalid_type_error!(v, "Response status not valid boolean");
1836                }
1837            }
1838            Value::BulkString(ref bytes) => {
1839                if bytes == b"1" {
1840                    Ok(true)
1841                } else if bytes == b"0" {
1842                    Ok(false)
1843                } else {
1844                    crate::errors::invalid_type_error!(v, "Response type not bool compatible.");
1845                }
1846            }
1847            Value::Boolean(b) => Ok(b),
1848            Value::Okay => Ok(true),
1849            _ => crate::errors::invalid_type_error!(v, "Response type not bool compatible."),
1850        }
1851    }
1852
1853    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
1854        Self::from_redis_value_ref(&v)
1855    }
1856}
1857
1858impl FromRedisValue for CString {
1859    fn from_redis_value_ref(v: &Value) -> Result<CString, ParsingError> {
1860        let v = get_inner_value(v);
1861        match *v {
1862            Value::BulkString(ref bytes) => Ok(CString::new(bytes.as_slice())?),
1863            Value::Okay => Ok(CString::new("OK")?),
1864            Value::SimpleString(ref val) => Ok(CString::new(val.as_bytes())?),
1865            _ => crate::errors::invalid_type_error!(v, "Response type not CString compatible."),
1866        }
1867    }
1868    fn from_redis_value(v: Value) -> Result<CString, ParsingError> {
1869        let v = get_owned_inner_value(v);
1870        match v {
1871            Value::BulkString(bytes) => Ok(CString::new(bytes)?),
1872            Value::Okay => Ok(CString::new("OK")?),
1873            Value::SimpleString(val) => Ok(CString::new(val)?),
1874            _ => crate::errors::invalid_type_error!(v, "Response type not CString compatible."),
1875        }
1876    }
1877}
1878
1879impl FromRedisValue for String {
1880    fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError> {
1881        let v = get_inner_value(v);
1882        match *v {
1883            Value::BulkString(ref bytes) => Ok(from_utf8(bytes)?.to_string()),
1884            Value::Okay => Ok("OK".to_string()),
1885            Value::SimpleString(ref val) => Ok(val.to_string()),
1886            Value::VerbatimString {
1887                format: _,
1888                ref text,
1889            } => Ok(text.to_string()),
1890            Value::Double(ref val) => Ok(val.to_string()),
1891            Value::Int(val) => Ok(val.to_string()),
1892            _ => crate::errors::invalid_type_error!(v, "Response type not string compatible."),
1893        }
1894    }
1895
1896    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
1897        let v = get_owned_inner_value(v);
1898        match v {
1899            Value::BulkString(bytes) => Ok(Self::from_utf8(bytes)?),
1900            Value::Okay => Ok("OK".to_string()),
1901            Value::SimpleString(val) => Ok(val),
1902            Value::VerbatimString { format: _, text } => Ok(text),
1903            Value::Double(val) => Ok(val.to_string()),
1904            Value::Int(val) => Ok(val.to_string()),
1905            _ => crate::errors::invalid_type_error!(v, "Response type not string compatible."),
1906        }
1907    }
1908}
1909
1910macro_rules! pointer_from_redis_value_impl {
1911    (
1912        $(#[$attr:meta])*
1913        $id:ident, $ty:ty, $func:expr
1914    ) => {
1915        $(#[$attr])*
1916        impl<$id:  FromRedisValue> FromRedisValue for $ty {
1917            fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError>
1918            {
1919                FromRedisValue::from_redis_value_ref(v).map($func)
1920            }
1921
1922            fn from_redis_value(v: Value) -> Result<Self, ParsingError>{
1923                FromRedisValue::from_redis_value(v).map($func)
1924            }
1925        }
1926    }
1927}
1928
1929pointer_from_redis_value_impl!(T, Box<T>, Box::new);
1930pointer_from_redis_value_impl!(T, std::sync::Arc<T>, std::sync::Arc::new);
1931pointer_from_redis_value_impl!(T, std::rc::Rc<T>, std::rc::Rc::new);
1932
1933/// Implement `FromRedisValue` for `$Type` (which should use the generic parameter `$T`).
1934///
1935/// The implementation parses the value into a vec, and then passes the value through `$convert`.
1936/// If `$convert` is omitted, it defaults to `Into::into`.
1937macro_rules! from_vec_from_redis_value {
1938    (<$T:ident> $Type:ty) => {
1939        from_vec_from_redis_value!(<$T> $Type; Into::into);
1940    };
1941
1942    (<$T:ident> $Type:ty; $convert:expr) => {
1943        impl<$T: FromRedisValue> FromRedisValue for $Type {
1944            fn from_redis_value_ref(v: &Value) -> Result<$Type, ParsingError> {
1945                match v {
1946                    // All binary data except u8 will try to parse into a single element vector.
1947                    // u8 has its own implementation of from_byte_slice.
1948                    Value::BulkString(bytes) => match FromRedisValue::from_byte_slice(bytes) {
1949                        Some(x) => Ok($convert(x)),
1950                        None => crate::errors::invalid_type_error!(
1951                            v,
1952                            format!("Conversion to {} failed.", std::any::type_name::<$Type>())
1953                        ),
1954                    },
1955                    Value::Array(items) => FromRedisValue::from_redis_value_refs(items).map($convert),
1956                    Value::Set(items) => FromRedisValue::from_redis_value_refs(items).map($convert),
1957                    Value::Map(items) => {
1958                        let mut n: Vec<T> = vec![];
1959                        for item in items {
1960                            match FromRedisValue::from_redis_value_ref(&Value::Map(vec![item.clone()])) {
1961                                Ok(v) => {
1962                                    n.push(v);
1963                                }
1964                                Err(e) => {
1965                                    return Err(e);
1966                                }
1967                            }
1968                        }
1969                        Ok($convert(n))
1970                    }
1971                    Value::Nil => Ok($convert(Vec::new())),
1972                    _ => crate::errors::invalid_type_error!(v, "Response type not vector compatible."),
1973                }
1974            }
1975            fn from_redis_value(v: Value) -> Result<$Type, ParsingError> {
1976                match v {
1977                    // Binary data is parsed into a single-element vector, except
1978                    // for the element type `u8`, which directly consumes the entire
1979                    // array of bytes.
1980                    Value::BulkString(bytes) => FromRedisValue::from_byte_vec(bytes).map($convert),
1981                    Value::Array(items) => FromRedisValue::from_redis_values(items).map($convert),
1982                    Value::Set(items) => FromRedisValue::from_redis_values(items).map($convert),
1983                    Value::Map(items) => {
1984                        let mut n: Vec<T> = vec![];
1985                        for item in items {
1986                            match FromRedisValue::from_redis_value(Value::Map(vec![item])) {
1987                                Ok(v) => {
1988                                    n.push(v);
1989                                }
1990                                Err(e) => {
1991                                    return Err(e);
1992                                }
1993                            }
1994                        }
1995                        Ok($convert(n))
1996                    }
1997                    Value::Nil => Ok($convert(Vec::new())),
1998                    _ => crate::errors::invalid_type_error!(v, "Response type not vector compatible."),
1999                }
2000            }
2001        }
2002    };
2003}
2004
2005from_vec_from_redis_value!(<T> Vec<T>);
2006from_vec_from_redis_value!(<T> std::sync::Arc<[T]>);
2007from_vec_from_redis_value!(<T> Box<[T]>; Vec::into_boxed_slice);
2008
2009macro_rules! impl_from_redis_value_for_map {
2010    (for <$($TypeParam:ident),+> $MapType:ty, where ($($WhereClause:tt)+)) => {
2011        impl< $($TypeParam),+ > FromRedisValue for $MapType
2012        where
2013            $($WhereClause)+
2014        {
2015            fn from_redis_value_ref(v: &Value) -> Result<$MapType, ParsingError> {
2016                let v = get_inner_value(v);
2017                match *v {
2018                    Value::Nil => Ok(Default::default()),
2019                    _ => v
2020                        .as_map_iter()
2021                        .ok_or_else(|| crate::errors::invalid_type_error_inner!(v, "Response type not map compatible"))?
2022                        .map(|(k, v)| {
2023                            Ok((from_redis_value_ref(k)?, from_redis_value_ref(v)?))
2024                        })
2025                        .collect(),
2026                }
2027            }
2028
2029            fn from_redis_value(v: Value) -> Result<$MapType, ParsingError> {
2030                let v = get_owned_inner_value(v);
2031                match v {
2032                    Value::Nil => Ok(Default::default()),
2033                    _ => v
2034                        .into_map_iter()
2035                        .map_err(|v| crate::errors::invalid_type_error_inner!(v, "Response type not map compatible"))?
2036                        .map(|(k, v)| {
2037                            Ok((from_redis_value(k)?, from_redis_value(v)?))
2038                        })
2039                        .collect(),
2040                }
2041            }
2042        }
2043    };
2044}
2045
2046impl_from_redis_value_for_map!(
2047    for <K, V, S> std::collections::HashMap<K, V, S>,
2048    where (K: FromRedisValue + Eq + Hash, V: FromRedisValue, S: BuildHasher + Default)
2049);
2050
2051impl_from_redis_value_for_map!(
2052    for <K, V> std::collections::BTreeMap<K, V>,
2053    where (K: FromRedisValue + Eq + Hash + Ord, V: FromRedisValue)
2054);
2055
2056#[cfg(feature = "hashbrown")]
2057impl_from_redis_value_for_map!(
2058    for <K, V, S> hashbrown::HashMap<K, V, S>,
2059    where (K: FromRedisValue + Eq + Hash, V: FromRedisValue, S: BuildHasher + Default)
2060);
2061
2062// `AHashMap::default` is not generic over `S` param so we can't be generic over it as well.
2063#[cfg(feature = "ahash")]
2064impl_from_redis_value_for_map!(
2065    for <K, V> ahash::AHashMap<K, V>,
2066    where (K: FromRedisValue + Eq + Hash, V: FromRedisValue)
2067);
2068
2069macro_rules! impl_from_redis_value_for_set {
2070    (for <$($TypeParam:ident),+> $SetType:ty, where ($($WhereClause:tt)+)) => {
2071        impl< $($TypeParam),+ > FromRedisValue for $SetType
2072        where
2073            $($WhereClause)+
2074        {
2075            fn from_redis_value_ref(v: &Value) -> Result<$SetType, ParsingError> {
2076                let v = get_inner_value(v);
2077                let items = v
2078                    .as_sequence()
2079                    .ok_or_else(|| crate::errors::invalid_type_error_inner!(v, "Response type not map compatible"))?;
2080                items.iter().map(|item| from_redis_value_ref(item)).collect()
2081            }
2082
2083            fn from_redis_value(v: Value) -> Result<$SetType, ParsingError> {
2084                let v = get_owned_inner_value(v);
2085                let items = v
2086                    .into_sequence()
2087                    .map_err(|v| crate::errors::invalid_type_error_inner!(v, "Response type not map compatible"))?;
2088                items
2089                    .into_iter()
2090                    .map(|item| from_redis_value(item))
2091                    .collect()
2092            }
2093        }
2094    };
2095}
2096
2097impl_from_redis_value_for_set!(
2098    for <T, S> std::collections::HashSet<T, S>,
2099    where (T: FromRedisValue + Eq + Hash, S: BuildHasher + Default)
2100);
2101
2102impl_from_redis_value_for_set!(
2103    for <T> std::collections::BTreeSet<T>,
2104    where (T: FromRedisValue + Eq + Ord)
2105);
2106
2107#[cfg(feature = "hashbrown")]
2108impl_from_redis_value_for_set!(
2109    for <T, S> hashbrown::HashSet<T, S>,
2110    where (T: FromRedisValue + Eq + Hash, S: BuildHasher + Default)
2111);
2112
2113// `AHashSet::from_iter` is not generic over `S` param so we can't be generic over it as well.
2114#[cfg(feature = "ahash")]
2115impl_from_redis_value_for_set!(
2116    for <T> ahash::AHashSet<T>,
2117    where (T: FromRedisValue + Eq + Hash)
2118);
2119
2120impl FromRedisValue for Value {
2121    fn from_redis_value_ref(v: &Value) -> Result<Value, ParsingError> {
2122        Ok(v.clone())
2123    }
2124
2125    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
2126        Ok(v)
2127    }
2128}
2129
2130impl FromRedisValue for () {
2131    fn from_redis_value_ref(v: &Value) -> Result<(), ParsingError> {
2132        match v {
2133            Value::ServerError(err) => Err(ParsingError::from(err.to_string())),
2134            _ => Ok(()),
2135        }
2136    }
2137
2138    fn from_redis_value(v: Value) -> Result<(), ParsingError> {
2139        Self::from_redis_value_ref(&v)
2140    }
2141}
2142
2143macro_rules! from_redis_value_for_tuple {
2144    () => ();
2145    ($(#[$meta:meta],)*$($name:ident,)+) => (
2146        $(#[$meta])*
2147        impl<$($name: FromRedisValue),*> FromRedisValue for ($($name,)*) {
2148            // we have local variables named T1 as dummies and those
2149            // variables are unused.
2150            #[allow(non_snake_case, unused_variables)]
2151            fn from_redis_value_ref(v: &Value) -> Result<($($name,)*), ParsingError> {
2152                let v = get_inner_value(v);
2153                // hacky way to count the tuple size
2154                let mut n = 0;
2155                $(let $name = (); n += 1;)*
2156
2157                match *v {
2158                    Value::Array(ref items) => {
2159                        if items.len() != n {
2160                            crate::errors::invalid_type_error!(v, "Array response of wrong dimension")
2161                        }
2162
2163                        // The { i += 1; i - 1} is rust's postfix increment :)
2164                        let mut i = 0;
2165                        Ok(($({let $name = (); from_redis_value_ref(
2166                             &items[{ i += 1; i - 1 }])?},)*))
2167                    }
2168
2169                    Value::Set(ref items) => {
2170                        if items.len() != n {
2171                            crate::errors::invalid_type_error!(v, "Set response of wrong dimension")
2172                        }
2173
2174                        // The { i += 1; i - 1} is rust's postfix increment :)
2175                        let mut i = 0;
2176                        Ok(($({let $name = (); from_redis_value_ref(
2177                             &items[{ i += 1; i - 1 }])?},)*))
2178                    }
2179
2180                    Value::Map(ref items) => {
2181                        if n != items.len() * 2 {
2182                            crate::errors::invalid_type_error!(v, "Map response of wrong dimension")
2183                        }
2184
2185                        let mut flatten_items = items.iter().map(|(a,b)|[a,b]).flatten();
2186
2187                        Ok(($({let $name = (); from_redis_value_ref(
2188                             &flatten_items.next().unwrap())?},)*))
2189                    }
2190
2191                    _ => crate::errors::invalid_type_error!(v, "Not a Array response")
2192                }
2193            }
2194
2195            // we have local variables named T1 as dummies and those
2196            // variables are unused.
2197            #[allow(non_snake_case, unused_variables)]
2198            fn from_redis_value(v: Value) -> Result<($($name,)*), ParsingError> {
2199                let v = get_owned_inner_value(v);
2200                // hacky way to count the tuple size
2201                let mut n = 0;
2202                $(let $name = (); n += 1;)*
2203                match v {
2204                    Value::Array(mut items) => {
2205                        if items.len() != n {
2206                            crate::errors::invalid_type_error!(Value::Array(items), "Array response of wrong dimension")
2207                        }
2208
2209                        // The { i += 1; i - 1} is rust's postfix increment :)
2210                        let mut i = 0;
2211                        Ok(($({let $name = (); from_redis_value(
2212                            ::std::mem::replace(&mut items[{ i += 1; i - 1 }], Value::Nil)
2213                        )?},)*))
2214                    }
2215
2216                    Value::Set(mut items) => {
2217                        if items.len() != n {
2218                            crate::errors::invalid_type_error!(Value::Array(items), "Set response of wrong dimension")
2219                        }
2220
2221                        // The { i += 1; i - 1} is rust's postfix increment :)
2222                        let mut i = 0;
2223                        Ok(($({let $name = (); from_redis_value(
2224                            ::std::mem::replace(&mut items[{ i += 1; i - 1 }], Value::Nil)
2225                        )?},)*))
2226                    }
2227
2228                    Value::Map(items) => {
2229                        if n != items.len() * 2 {
2230                            crate::errors::invalid_type_error!(Value::Map(items), "Map response of wrong dimension")
2231                        }
2232
2233                        let mut flatten_items = items.into_iter().map(|(a,b)|[a,b]).flatten();
2234
2235                        Ok(($({let $name = (); from_redis_value(
2236                            ::std::mem::replace(&mut flatten_items.next().unwrap(), Value::Nil)
2237                        )?},)*))
2238                    }
2239
2240                    _ => crate::errors::invalid_type_error!(v, "Not a Array response")
2241                }
2242            }
2243
2244            #[allow(non_snake_case, unused_variables)]
2245            fn from_redis_value_refs(items: &[Value]) -> Result<Vec<($($name,)*)>, ParsingError> {
2246                // hacky way to count the tuple size
2247                let mut n = 0;
2248                $(let $name = (); n += 1;)*
2249                if items.len() == 0 {
2250                    return Ok(vec![]);
2251                }
2252
2253                if items.iter().all(|item| item.is_collection_of_len(n)) {
2254                    return items.iter().map(|item| from_redis_value_ref(item)).collect();
2255                }
2256
2257                let mut rv = Vec::with_capacity(items.len() / n);
2258                if let [$($name),*] = items {
2259                    rv.push(($(from_redis_value_ref($name)?,)*));
2260                    return Ok(rv);
2261                }
2262                for chunk in items.chunks(n) {
2263                    match chunk {
2264                        [$($name),*] => rv.push(($(from_redis_value_ref($name)?,)*)),
2265                         _ => return Err(format!("Vector of length {} doesn't have arity of {n}", items.len()).into()),
2266                    }
2267                }
2268                Ok(rv)
2269            }
2270
2271            #[allow(non_snake_case, unused_variables)]
2272            fn from_each_redis_values(mut items: Vec<Value>) -> Vec<Result<($($name,)*), ParsingError>> {
2273                #[allow(unused_parens)]
2274                let extract = |val: ($(Result<$name, ParsingError>,)*)| -> Result<($($name,)*), ParsingError> {
2275                    let ($($name,)*) = val;
2276                    Ok(($($name?,)*))
2277                };
2278
2279                // hacky way to count the tuple size
2280                let mut n = 0;
2281                $(let $name = (); n += 1;)*
2282
2283                // let mut rv = vec![];
2284                if items.len() == 0 {
2285                    return vec![];
2286                }
2287                if items.iter().all(|item| item.is_collection_of_len(n)) {
2288                    return items.into_iter().map(|item| from_redis_value(item).map_err(|err|err.into())).collect();
2289                }
2290
2291                let mut rv = Vec::with_capacity(items.len() / n);
2292
2293                for chunk in items.chunks_mut(n) {
2294                    match chunk {
2295                        // Take each element out of the chunk with `std::mem::replace`, leaving a `Value::Nil`
2296                        // in its place. This allows each `Value` to be parsed without being copied.
2297                        // Since `items` is consumed by this function and not used later, this replacement
2298                        // is not observable to the rest of the code.
2299                        [$($name),*] => rv.push(extract(($(from_redis_value(std::mem::replace($name, Value::Nil)).into(),)*))),
2300                         _ => return vec![Err(format!("Vector of length {} doesn't have arity of {n}", items.len()).into())],
2301                    }
2302                }
2303                rv
2304            }
2305
2306            #[allow(non_snake_case, unused_variables)]
2307            fn from_redis_values(mut items: Vec<Value>) -> Result<Vec<($($name,)*)>, ParsingError> {
2308                // hacky way to count the tuple size
2309                let mut n = 0;
2310                $(let $name = (); n += 1;)*
2311
2312                // let mut rv = vec![];
2313                if items.len() == 0 {
2314                    return Ok(vec![])
2315                }
2316                if items.iter().all(|item| item.is_collection_of_len(n)) {
2317                    return items.into_iter().map(|item| from_redis_value(item)).collect();
2318                }
2319
2320                let mut rv = Vec::with_capacity(items.len() / n);
2321                for chunk in items.chunks_mut(n) {
2322                    match chunk {
2323                        // Take each element out of the chunk with `std::mem::replace`, leaving a `Value::Nil`
2324                        // in its place. This allows each `Value` to be parsed without being copied.
2325                        // Since `items` is consume by this function and not used later, this replacement
2326                        // is not observable to the rest of the code.
2327                        [$($name),*] => rv.push(($(from_redis_value(std::mem::replace($name, Value::Nil))?,)*)),
2328                         _ => return Err(format!("Vector of length {} doesn't have arity of {n}", items.len()).into()),
2329                    }
2330                }
2331                Ok(rv)
2332            }
2333        }
2334    )
2335}
2336
2337from_redis_value_for_tuple! { #[cfg_attr(docsrs, doc(fake_variadic))], #[doc = "This trait is implemented for tuples up to 12 items long."], T, }
2338from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, }
2339from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, }
2340from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, }
2341from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, }
2342from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, }
2343from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, }
2344from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, }
2345from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, }
2346from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, }
2347from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
2348from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
2349
2350impl FromRedisValue for InfoDict {
2351    fn from_redis_value_ref(v: &Value) -> Result<InfoDict, ParsingError> {
2352        let v = get_inner_value(v);
2353        let s: String = from_redis_value_ref(v)?;
2354        Ok(InfoDict::new(&s))
2355    }
2356    fn from_redis_value(v: Value) -> Result<InfoDict, ParsingError> {
2357        let v = get_owned_inner_value(v);
2358        let s: String = from_redis_value(v)?;
2359        Ok(InfoDict::new(&s))
2360    }
2361}
2362
2363impl<T: FromRedisValue> FromRedisValue for Option<T> {
2364    fn from_redis_value_ref(v: &Value) -> Result<Option<T>, ParsingError> {
2365        let v = get_inner_value(v);
2366        if *v == Value::Nil {
2367            return Ok(None);
2368        }
2369        Ok(Some(from_redis_value_ref(v)?))
2370    }
2371    fn from_redis_value(v: Value) -> Result<Option<T>, ParsingError> {
2372        let v = get_owned_inner_value(v);
2373        if v == Value::Nil {
2374            return Ok(None);
2375        }
2376        Ok(Some(from_redis_value(v)?))
2377    }
2378}
2379
2380#[cfg(feature = "bytes")]
2381impl FromRedisValue for bytes::Bytes {
2382    fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError> {
2383        let v = get_inner_value(v);
2384        match v {
2385            Value::BulkString(bytes_vec) => Ok(bytes::Bytes::copy_from_slice(bytes_vec.as_ref())),
2386            _ => crate::errors::invalid_type_error!(v, "Not a bulk string"),
2387        }
2388    }
2389    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
2390        let v = get_owned_inner_value(v);
2391        match v {
2392            Value::BulkString(bytes_vec) => Ok(bytes_vec.into()),
2393            _ => crate::errors::invalid_type_error!(v, "Not a bulk string"),
2394        }
2395    }
2396}
2397
2398#[cfg(feature = "uuid")]
2399impl FromRedisValue for uuid::Uuid {
2400    fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError> {
2401        match *v {
2402            Value::BulkString(ref bytes) => Ok(uuid::Uuid::from_slice(bytes)?),
2403            _ => crate::errors::invalid_type_error!(v, "Response type not uuid compatible."),
2404        }
2405    }
2406
2407    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
2408        Self::from_redis_value_ref(&v)
2409    }
2410}
2411
2412#[cfg(feature = "uuid")]
2413impl ToRedisArgs for uuid::Uuid {
2414    fn write_redis_args<W>(&self, out: &mut W)
2415    where
2416        W: ?Sized + RedisWrite,
2417    {
2418        out.write_arg(self.as_bytes());
2419    }
2420}
2421
2422#[cfg(feature = "uuid")]
2423impl ToSingleRedisArg for uuid::Uuid {}
2424
2425/// A shortcut function to invoke `FromRedisValue::from_redis_value_ref`
2426/// to make the API slightly nicer.
2427pub fn from_redis_value_ref<T: FromRedisValue>(v: &Value) -> Result<T, ParsingError> {
2428    FromRedisValue::from_redis_value_ref(v)
2429}
2430
2431/// A shortcut function to invoke `FromRedisValue::from_redis_value`
2432/// to make the API slightly nicer.
2433pub fn from_redis_value<T: FromRedisValue>(v: Value) -> Result<T, ParsingError> {
2434    FromRedisValue::from_redis_value(v)
2435}
2436
2437/// Calculates a digest/hash of the given value for use with Redis value comparison operations.
2438/// This function uses the XXH3 algorithm, which is the same algorithm used by Redis for its DIGEST command.
2439/// The resulting digest can be used with `ValueComparison::IFDEQ` and `ValueComparison::IFDNE`.
2440///
2441/// # Example
2442/// ```rust
2443/// use redis::{calculate_value_digest, ValueComparison, SetOptions};
2444///
2445/// let value = "my_value";
2446/// let digest = calculate_value_digest(value);
2447///
2448/// // Use the digest in a value comparison
2449/// let opts = SetOptions::default()
2450///     .value_comparison(ValueComparison::ifdeq(&digest));
2451/// ```
2452pub fn calculate_value_digest<T: ToRedisArgs>(value: T) -> String {
2453    use xxhash_rust::xxh3::xxh3_64;
2454
2455    // Convert the value to Redis args format (bytes)
2456    let args = value.to_redis_args();
2457
2458    // For consistency with Redis behavior, hash the concatenated bytes
2459    // of all arguments, similar to how Redis would serialize the value
2460    let mut combined_bytes = Vec::new();
2461    for arg in args {
2462        combined_bytes.extend_from_slice(&arg);
2463    }
2464
2465    // Calculate XXH3 hash (64-bit) and format as hexadecimal string
2466    let hash = xxh3_64(&combined_bytes);
2467    format!("{:016x}", hash)
2468}
2469
2470/// Validates that the given string is a valid 16-byte hex digest.
2471pub fn is_valid_16_bytes_hex_digest(s: &str) -> bool {
2472    s.len() == 16 && s.chars().all(|c| c.is_ascii_hexdigit())
2473}
2474
2475/// Enum representing the communication protocol with the server.
2476///
2477/// This enum represents the types of data that the server can send to the client,
2478/// and the capabilities that the client can use.
2479#[derive(Clone, Eq, PartialEq, Default, Debug, Copy)]
2480#[non_exhaustive]
2481pub enum ProtocolVersion {
2482    /// <https://github.com/redis/redis-specifications/blob/master/protocol/RESP2.md>
2483    #[default]
2484    RESP2,
2485    /// <https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md>
2486    RESP3,
2487}
2488
2489impl ProtocolVersion {
2490    /// Returns true if the protocol can support RESP3 features.
2491    pub fn supports_resp3(&self) -> bool {
2492        !matches!(self, ProtocolVersion::RESP2)
2493    }
2494}
2495
2496/// Helper enum that is used to define option for the hash expire commands
2497#[derive(Clone, Copy)]
2498#[non_exhaustive]
2499pub enum ExpireOption {
2500    /// NONE -- Set expiration regardless of the field's current expiration.
2501    NONE,
2502    /// NX -- Only set expiration only when the field has no expiration.
2503    NX,
2504    /// XX -- Only set expiration only when the field has an existing expiration.
2505    XX,
2506    /// GT -- Only set expiration only when the new expiration is greater than current one.
2507    GT,
2508    /// LT -- Only set expiration only when the new expiration is less than current one.
2509    LT,
2510}
2511
2512impl ToRedisArgs for ExpireOption {
2513    fn write_redis_args<W>(&self, out: &mut W)
2514    where
2515        W: ?Sized + RedisWrite,
2516    {
2517        match self {
2518            ExpireOption::NX => out.write_arg(b"NX"),
2519            ExpireOption::XX => out.write_arg(b"XX"),
2520            ExpireOption::GT => out.write_arg(b"GT"),
2521            ExpireOption::LT => out.write_arg(b"LT"),
2522            _ => {}
2523        }
2524    }
2525}
2526
2527#[derive(Debug, Clone, PartialEq)]
2528/// A push message from the server.
2529pub struct PushInfo {
2530    /// Push Kind
2531    pub kind: PushKind,
2532    /// Data from push message
2533    pub data: Vec<Value>,
2534}
2535
2536impl PushInfo {
2537    pub(crate) fn disconnect() -> Self {
2538        PushInfo {
2539            kind: crate::PushKind::Disconnection,
2540            data: vec![],
2541        }
2542    }
2543}
2544
2545pub(crate) type SyncPushSender = std::sync::mpsc::Sender<PushInfo>;
2546
2547/// Possible types of value held in Redis: [Redis Docs](https://redis.io/docs/latest/commands/type/)
2548#[derive(Debug, Clone, PartialEq)]
2549#[non_exhaustive]
2550pub enum ValueType {
2551    /// Generally returned by anything that returns a single element. [Redis Docs](https://redis.io/docs/latest/develop/data-types/strings/)
2552    String,
2553    /// A list of String values. [Redis Docs](https://redis.io/docs/latest/develop/data-types/lists/)
2554    List,
2555    /// A set of unique String values. [Redis Docs](https://redis.io/docs/latest/develop/data-types/sets/)
2556    Set,
2557    /// A sorted set of String values. [Redis Docs](https://redis.io/docs/latest/develop/data-types/sorted-sets/)
2558    ZSet,
2559    /// A collection of field-value pairs. [Redis Docs](https://redis.io/docs/latest/develop/data-types/hashes/)
2560    Hash,
2561    /// A Redis Stream. [Redis Docs](https://redis.io/docs/latest/develop/data-types/stream)
2562    Stream,
2563    /// Any other value type not explicitly defined in [Redis Docs](https://redis.io/docs/latest/commands/type/)
2564    Unknown(String),
2565}
2566
2567impl<T: AsRef<str>> From<T> for ValueType {
2568    fn from(s: T) -> Self {
2569        match s.as_ref() {
2570            "string" => ValueType::String,
2571            "list" => ValueType::List,
2572            "set" => ValueType::Set,
2573            "zset" => ValueType::ZSet,
2574            "hash" => ValueType::Hash,
2575            "stream" => ValueType::Stream,
2576            s => ValueType::Unknown(s.to_string()),
2577        }
2578    }
2579}
2580
2581impl From<ValueType> for String {
2582    fn from(v: ValueType) -> Self {
2583        match v {
2584            ValueType::String => "string".to_string(),
2585            ValueType::List => "list".to_string(),
2586            ValueType::Set => "set".to_string(),
2587            ValueType::ZSet => "zset".to_string(),
2588            ValueType::Hash => "hash".to_string(),
2589            ValueType::Stream => "stream".to_string(),
2590            ValueType::Unknown(s) => s,
2591        }
2592    }
2593}
2594
2595impl FromRedisValue for ValueType {
2596    fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError> {
2597        match v {
2598            Value::SimpleString(s) => Ok(s.into()),
2599            _ => crate::errors::invalid_type_error!(v, "Value type should be a simple string"),
2600        }
2601    }
2602
2603    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
2604        match v {
2605            Value::SimpleString(s) => Ok(s.into()),
2606            _ => crate::errors::invalid_type_error!(v, "Value type should be a simple string"),
2607        }
2608    }
2609}
2610
2611/// Returned by typed commands which either return a positive integer or some negative integer indicating some kind of no-op.
2612#[derive(Debug, PartialEq, Clone)]
2613#[non_exhaustive]
2614pub enum IntegerReplyOrNoOp {
2615    /// A positive integer reply indicating success of some kind.
2616    IntegerReply(usize),
2617    /// The field/key you are trying to operate on does not exist.
2618    NotExists,
2619    /// The field/key you are trying to operate on exists but is not of the correct type or does not have some property you are trying to affect.
2620    ExistsButNotRelevant,
2621}
2622
2623impl IntegerReplyOrNoOp {
2624    /// Returns the integer value of the reply.
2625    pub fn raw(&self) -> isize {
2626        match self {
2627            IntegerReplyOrNoOp::IntegerReply(s) => *s as isize,
2628            IntegerReplyOrNoOp::NotExists => -2,
2629            IntegerReplyOrNoOp::ExistsButNotRelevant => -1,
2630        }
2631    }
2632}
2633
2634impl FromRedisValue for IntegerReplyOrNoOp {
2635    fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError> {
2636        match v {
2637            Value::Int(s) => match s {
2638                -2 => Ok(IntegerReplyOrNoOp::NotExists),
2639                -1 => Ok(IntegerReplyOrNoOp::ExistsButNotRelevant),
2640                _ => Ok(IntegerReplyOrNoOp::IntegerReply(*s as usize)),
2641            },
2642            _ => crate::errors::invalid_type_error!(v, "Value should be an integer"),
2643        }
2644    }
2645
2646    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
2647        match v {
2648            Value::Int(s) => match s {
2649                -2 => Ok(IntegerReplyOrNoOp::NotExists),
2650                -1 => Ok(IntegerReplyOrNoOp::ExistsButNotRelevant),
2651                _ => Ok(IntegerReplyOrNoOp::IntegerReply(s as usize)),
2652            },
2653            _ => crate::errors::invalid_type_error!(v, "Value should be an integer"),
2654        }
2655    }
2656}
2657
2658impl PartialEq<isize> for IntegerReplyOrNoOp {
2659    fn eq(&self, other: &isize) -> bool {
2660        match self {
2661            IntegerReplyOrNoOp::IntegerReply(s) => *s as isize == *other,
2662            IntegerReplyOrNoOp::NotExists => *other == -2,
2663            IntegerReplyOrNoOp::ExistsButNotRelevant => *other == -1,
2664        }
2665    }
2666}
2667
2668impl PartialEq<usize> for IntegerReplyOrNoOp {
2669    fn eq(&self, other: &usize) -> bool {
2670        match self {
2671            IntegerReplyOrNoOp::IntegerReply(s) => *s == *other,
2672            _ => false,
2673        }
2674    }
2675}
2676
2677impl PartialEq<i32> for IntegerReplyOrNoOp {
2678    fn eq(&self, other: &i32) -> bool {
2679        match self {
2680            IntegerReplyOrNoOp::IntegerReply(s) => *s as i32 == *other,
2681            IntegerReplyOrNoOp::NotExists => *other == -2,
2682            IntegerReplyOrNoOp::ExistsButNotRelevant => *other == -1,
2683        }
2684    }
2685}
2686
2687impl PartialEq<u32> for IntegerReplyOrNoOp {
2688    fn eq(&self, other: &u32) -> bool {
2689        match self {
2690            IntegerReplyOrNoOp::IntegerReply(s) => *s as u32 == *other,
2691            _ => false,
2692        }
2693    }
2694}