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                self.buf.advance_mut(cnt);
956            }
957
958            fn chunk_mut(&mut self) -> &mut bytes::buf::UninitSlice {
959                self.buf.chunk_mut()
960            }
961
962            // Vec specializes these methods, so we do too
963            fn put<T: bytes::buf::Buf>(&mut self, src: T)
964            where
965                Self: Sized,
966            {
967                self.buf.put(src);
968            }
969
970            fn put_slice(&mut self, src: &[u8]) {
971                self.buf.put_slice(src);
972            }
973
974            fn put_bytes(&mut self, val: u8, cnt: usize) {
975                self.buf.put_bytes(val, cnt);
976            }
977        }
978        impl Drop for Wrapper<'_> {
979            fn drop(&mut self) {
980                self.writer.write_all(&self.buf).unwrap()
981            }
982        }
983
984        Wrapper {
985            buf: Vec::with_capacity(capacity),
986            writer: Box::new(self.writer_for_next_arg()),
987        }
988    }
989}
990
991impl RedisWrite for Vec<Vec<u8>> {
992    fn write_arg(&mut self, arg: &[u8]) {
993        self.push(arg.to_owned());
994    }
995
996    fn write_arg_fmt(&mut self, arg: impl fmt::Display) {
997        self.push(arg.to_string().into_bytes())
998    }
999
1000    fn writer_for_next_arg(&mut self) -> impl io::Write + '_ {
1001        self.push(Vec::new());
1002        self.last_mut().unwrap()
1003    }
1004
1005    fn reserve_space_for_args(&mut self, additional: impl IntoIterator<Item = usize>) {
1006        // It would be nice to do this, but there's no way to store where we currently are.
1007        // Checking for the first empty Vec is not possible, as it's valid to write empty args.
1008        // self.extend(additional.iter().copied().map(Vec::with_capacity));
1009        // So we just reserve space for the extra args and have to forgo the extra optimisation
1010        self.reserve(additional.into_iter().count());
1011    }
1012
1013    #[cfg(feature = "bytes")]
1014    fn bufmut_for_next_arg(&mut self, capacity: usize) -> impl bytes::BufMut + '_ {
1015        self.push(Vec::with_capacity(capacity));
1016        self.last_mut().unwrap()
1017    }
1018}
1019
1020/// This trait marks that a value is serialized only into a single Redis value.
1021///
1022/// This should be implemented only for types that are serialized into exactly one value,
1023/// otherwise the compiler can't ensure the correctness of some commands.
1024pub trait ToSingleRedisArg: ToRedisArgs {}
1025
1026/// Used to convert a value into one or multiple redis argument
1027/// strings.  Most values will produce exactly one item but in
1028/// some cases it might make sense to produce more than one.
1029pub trait ToRedisArgs: Sized {
1030    /// This converts the value into a vector of bytes.  Each item
1031    /// is a single argument.  Most items generate a vector of a
1032    /// single item.
1033    ///
1034    /// The exception to this rule currently are vectors of items.
1035    fn to_redis_args(&self) -> Vec<Vec<u8>> {
1036        let mut out = Vec::new();
1037        self.write_redis_args(&mut out);
1038        out
1039    }
1040
1041    /// This writes the value into a vector of bytes.  Each item
1042    /// is a single argument.  Most items generate a single item.
1043    ///
1044    /// The exception to this rule currently are vectors of items.
1045    fn write_redis_args<W>(&self, out: &mut W)
1046    where
1047        W: ?Sized + RedisWrite;
1048
1049    /// Returns an information about the contained value with regards
1050    /// to it's numeric behavior in a redis context.  This is used in
1051    /// some high level concepts to switch between different implementations
1052    /// of redis functions (for instance `INCR` vs `INCRBYFLOAT`).
1053    fn describe_numeric_behavior(&self) -> NumericBehavior {
1054        NumericBehavior::NonNumeric
1055    }
1056
1057    /// Returns the number of arguments this value will generate.
1058    ///
1059    /// This is used in some high level functions to intelligently switch
1060    /// between `GET` and `MGET` variants. Also, for some commands like HEXPIREDAT
1061    /// which require a specific number of arguments, this method can be used to
1062    /// know the number of arguments.
1063    fn num_of_args(&self) -> usize {
1064        1
1065    }
1066
1067    /// This only exists internally as a workaround for the lack of
1068    /// specialization.
1069    #[doc(hidden)]
1070    fn write_args_from_slice<W>(items: &[Self], out: &mut W)
1071    where
1072        W: ?Sized + RedisWrite,
1073    {
1074        Self::make_arg_iter_ref(items.iter(), out)
1075    }
1076
1077    /// This only exists internally as a workaround for the lack of
1078    /// specialization.
1079    #[doc(hidden)]
1080    fn make_arg_iter_ref<'a, I, W>(items: I, out: &mut W)
1081    where
1082        W: ?Sized + RedisWrite,
1083        I: Iterator<Item = &'a Self>,
1084        Self: 'a,
1085    {
1086        for item in items {
1087            item.write_redis_args(out);
1088        }
1089    }
1090
1091    #[doc(hidden)]
1092    fn is_single_vec_arg(items: &[Self]) -> bool {
1093        items.len() == 1 && items[0].num_of_args() <= 1
1094    }
1095}
1096
1097macro_rules! itoa_based_to_redis_impl {
1098    ($t:ty, $numeric:expr) => {
1099        impl ToRedisArgs for $t {
1100            fn write_redis_args<W>(&self, out: &mut W)
1101            where
1102                W: ?Sized + RedisWrite,
1103            {
1104                let mut buf = ::itoa::Buffer::new();
1105                let s = buf.format(*self);
1106                out.write_arg(s.as_bytes())
1107            }
1108
1109            fn describe_numeric_behavior(&self) -> NumericBehavior {
1110                $numeric
1111            }
1112        }
1113
1114        impl ToSingleRedisArg for $t {}
1115    };
1116}
1117
1118macro_rules! non_zero_itoa_based_to_redis_impl {
1119    ($t:ty, $numeric:expr) => {
1120        impl ToRedisArgs for $t {
1121            fn write_redis_args<W>(&self, out: &mut W)
1122            where
1123                W: ?Sized + RedisWrite,
1124            {
1125                let mut buf = ::itoa::Buffer::new();
1126                let s = buf.format(self.get());
1127                out.write_arg(s.as_bytes())
1128            }
1129
1130            fn describe_numeric_behavior(&self) -> NumericBehavior {
1131                $numeric
1132            }
1133        }
1134
1135        impl ToSingleRedisArg for $t {}
1136    };
1137}
1138
1139macro_rules! ryu_based_to_redis_impl {
1140    ($t:ty, $numeric:expr) => {
1141        impl ToRedisArgs for $t {
1142            fn write_redis_args<W>(&self, out: &mut W)
1143            where
1144                W: ?Sized + RedisWrite,
1145            {
1146                let mut buf = ::ryu::Buffer::new();
1147                let s = buf.format(*self);
1148                out.write_arg(s.as_bytes())
1149            }
1150
1151            fn describe_numeric_behavior(&self) -> NumericBehavior {
1152                $numeric
1153            }
1154        }
1155
1156        impl ToSingleRedisArg for $t {}
1157    };
1158}
1159
1160impl ToRedisArgs for u8 {
1161    fn write_redis_args<W>(&self, out: &mut W)
1162    where
1163        W: ?Sized + RedisWrite,
1164    {
1165        let mut buf = ::itoa::Buffer::new();
1166        let s = buf.format(*self);
1167        out.write_arg(s.as_bytes())
1168    }
1169
1170    fn write_args_from_slice<W>(items: &[u8], out: &mut W)
1171    where
1172        W: ?Sized + RedisWrite,
1173    {
1174        out.write_arg(items);
1175    }
1176
1177    fn is_single_vec_arg(_items: &[u8]) -> bool {
1178        true
1179    }
1180}
1181
1182impl ToSingleRedisArg for u8 {}
1183
1184itoa_based_to_redis_impl!(i8, NumericBehavior::NumberIsInteger);
1185itoa_based_to_redis_impl!(i16, NumericBehavior::NumberIsInteger);
1186itoa_based_to_redis_impl!(u16, NumericBehavior::NumberIsInteger);
1187itoa_based_to_redis_impl!(i32, NumericBehavior::NumberIsInteger);
1188itoa_based_to_redis_impl!(u32, NumericBehavior::NumberIsInteger);
1189itoa_based_to_redis_impl!(i64, NumericBehavior::NumberIsInteger);
1190itoa_based_to_redis_impl!(u64, NumericBehavior::NumberIsInteger);
1191itoa_based_to_redis_impl!(i128, NumericBehavior::NumberIsInteger);
1192itoa_based_to_redis_impl!(u128, NumericBehavior::NumberIsInteger);
1193itoa_based_to_redis_impl!(isize, NumericBehavior::NumberIsInteger);
1194itoa_based_to_redis_impl!(usize, NumericBehavior::NumberIsInteger);
1195
1196non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU8, NumericBehavior::NumberIsInteger);
1197non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI8, NumericBehavior::NumberIsInteger);
1198non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU16, NumericBehavior::NumberIsInteger);
1199non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI16, NumericBehavior::NumberIsInteger);
1200non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU32, NumericBehavior::NumberIsInteger);
1201non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI32, NumericBehavior::NumberIsInteger);
1202non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU64, NumericBehavior::NumberIsInteger);
1203non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI64, NumericBehavior::NumberIsInteger);
1204non_zero_itoa_based_to_redis_impl!(core::num::NonZeroU128, NumericBehavior::NumberIsInteger);
1205non_zero_itoa_based_to_redis_impl!(core::num::NonZeroI128, NumericBehavior::NumberIsInteger);
1206non_zero_itoa_based_to_redis_impl!(core::num::NonZeroUsize, NumericBehavior::NumberIsInteger);
1207non_zero_itoa_based_to_redis_impl!(core::num::NonZeroIsize, NumericBehavior::NumberIsInteger);
1208
1209ryu_based_to_redis_impl!(f32, NumericBehavior::NumberIsFloat);
1210ryu_based_to_redis_impl!(f64, NumericBehavior::NumberIsFloat);
1211
1212#[cfg(any(
1213    feature = "rust_decimal",
1214    feature = "bigdecimal",
1215    feature = "num-bigint"
1216))]
1217macro_rules! bignum_to_redis_impl {
1218    ($t:ty) => {
1219        impl ToRedisArgs for $t {
1220            fn write_redis_args<W>(&self, out: &mut W)
1221            where
1222                W: ?Sized + RedisWrite,
1223            {
1224                out.write_arg(&self.to_string().into_bytes())
1225            }
1226        }
1227
1228        impl ToSingleRedisArg for $t {}
1229    };
1230}
1231
1232#[cfg(feature = "rust_decimal")]
1233bignum_to_redis_impl!(rust_decimal::Decimal);
1234#[cfg(feature = "bigdecimal")]
1235bignum_to_redis_impl!(bigdecimal::BigDecimal);
1236#[cfg(feature = "num-bigint")]
1237bignum_to_redis_impl!(num_bigint::BigInt);
1238#[cfg(feature = "num-bigint")]
1239bignum_to_redis_impl!(num_bigint::BigUint);
1240
1241impl ToRedisArgs for bool {
1242    fn write_redis_args<W>(&self, out: &mut W)
1243    where
1244        W: ?Sized + RedisWrite,
1245    {
1246        out.write_arg(if *self { b"1" } else { b"0" })
1247    }
1248}
1249
1250impl ToSingleRedisArg for bool {}
1251
1252impl ToRedisArgs for String {
1253    fn write_redis_args<W>(&self, out: &mut W)
1254    where
1255        W: ?Sized + RedisWrite,
1256    {
1257        out.write_arg(self.as_bytes())
1258    }
1259}
1260impl ToSingleRedisArg for String {}
1261
1262impl ToRedisArgs for &str {
1263    fn write_redis_args<W>(&self, out: &mut W)
1264    where
1265        W: ?Sized + RedisWrite,
1266    {
1267        out.write_arg(self.as_bytes())
1268    }
1269}
1270
1271impl ToSingleRedisArg for &str {}
1272
1273impl<'a, T> ToRedisArgs for Cow<'a, T>
1274where
1275    T: ToOwned + ?Sized,
1276    &'a T: ToRedisArgs,
1277    T::Owned: ToRedisArgs,
1278{
1279    fn write_redis_args<W>(&self, out: &mut W)
1280    where
1281        W: ?Sized + RedisWrite,
1282    {
1283        match self {
1284            Cow::Borrowed(inner) => inner.write_redis_args(out),
1285            Cow::Owned(inner) => inner.write_redis_args(out),
1286        }
1287    }
1288}
1289
1290impl<'a, T> ToSingleRedisArg for Cow<'a, T>
1291where
1292    T: ToOwned + ?Sized,
1293    &'a T: ToSingleRedisArg,
1294    T::Owned: ToSingleRedisArg,
1295{
1296}
1297
1298impl<T: ToRedisArgs> ToRedisArgs for Option<T> {
1299    fn write_redis_args<W>(&self, out: &mut W)
1300    where
1301        W: ?Sized + RedisWrite,
1302    {
1303        if let Some(ref x) = *self {
1304            x.write_redis_args(out);
1305        }
1306    }
1307
1308    fn describe_numeric_behavior(&self) -> NumericBehavior {
1309        match *self {
1310            Some(ref x) => x.describe_numeric_behavior(),
1311            None => NumericBehavior::NonNumeric,
1312        }
1313    }
1314
1315    fn num_of_args(&self) -> usize {
1316        match *self {
1317            Some(ref x) => x.num_of_args(),
1318            None => 0,
1319        }
1320    }
1321}
1322
1323macro_rules! impl_write_redis_args_for_collection {
1324    ($type:ty) => {
1325        impl<'a, T> ToRedisArgs for $type
1326        where
1327            T: ToRedisArgs,
1328        {
1329            #[inline]
1330            fn write_redis_args<W>(&self, out: &mut W)
1331            where
1332                W: ?Sized + RedisWrite,
1333            {
1334                ToRedisArgs::write_args_from_slice(self, out)
1335            }
1336
1337            fn num_of_args(&self) -> usize {
1338                if ToRedisArgs::is_single_vec_arg(&self[..]) {
1339                    return 1;
1340                }
1341                if self.len() == 1 {
1342                    self[0].num_of_args()
1343                } else {
1344                    self.len()
1345                }
1346            }
1347
1348            fn describe_numeric_behavior(&self) -> NumericBehavior {
1349                NumericBehavior::NonNumeric
1350            }
1351        }
1352    };
1353}
1354
1355macro_rules! deref_to_write_redis_args_impl {
1356    ($type:ty) => {
1357        impl<'a, T> ToRedisArgs for $type
1358        where
1359            T: ToRedisArgs,
1360        {
1361            #[inline]
1362            fn write_redis_args<W>(&self, out: &mut W)
1363            where
1364                W: ?Sized + RedisWrite,
1365            {
1366                (**self).write_redis_args(out)
1367            }
1368
1369            fn num_of_args(&self) -> usize {
1370                (**self).num_of_args()
1371            }
1372
1373            fn describe_numeric_behavior(&self) -> NumericBehavior {
1374                (**self).describe_numeric_behavior()
1375            }
1376        }
1377
1378        impl<'a, T> ToSingleRedisArg for $type where T: ToSingleRedisArg {}
1379    };
1380}
1381
1382deref_to_write_redis_args_impl! {&'a T}
1383deref_to_write_redis_args_impl! {&'a mut T}
1384deref_to_write_redis_args_impl! {Box<T>}
1385deref_to_write_redis_args_impl! {std::sync::Arc<T>}
1386deref_to_write_redis_args_impl! {std::rc::Rc<T>}
1387impl_write_redis_args_for_collection! {&'a [T]}
1388impl_write_redis_args_for_collection! {&'a mut [T]}
1389impl_write_redis_args_for_collection! {Box<[T]>}
1390impl_write_redis_args_for_collection! {std::sync::Arc<[T]>}
1391impl_write_redis_args_for_collection! {std::rc::Rc<[T]>}
1392impl_write_redis_args_for_collection! {Vec<T>}
1393impl ToSingleRedisArg for &[u8] {}
1394impl ToSingleRedisArg for &mut [u8] {}
1395impl ToSingleRedisArg for Vec<u8> {}
1396impl ToSingleRedisArg for Box<[u8]> {}
1397impl ToSingleRedisArg for std::rc::Rc<[u8]> {}
1398impl ToSingleRedisArg for std::sync::Arc<[u8]> {}
1399
1400/// @note: Redis cannot store empty sets so the application has to
1401/// check whether the set is empty and if so, not attempt to use that
1402/// result
1403macro_rules! impl_to_redis_args_for_set {
1404    (for <$($TypeParam:ident),+> $SetType:ty, where ($($WhereClause:tt)+) ) => {
1405        impl< $($TypeParam),+ > ToRedisArgs for $SetType
1406        where
1407            $($WhereClause)+
1408        {
1409            fn write_redis_args<W>(&self, out: &mut W)
1410            where
1411                W: ?Sized + RedisWrite,
1412            {
1413                ToRedisArgs::make_arg_iter_ref(self.iter(), out)
1414            }
1415
1416            fn num_of_args(&self) -> usize {
1417                self.len()
1418            }
1419        }
1420    };
1421}
1422
1423impl_to_redis_args_for_set!(
1424    for <T, S> std::collections::HashSet<T, S>,
1425    where (T: ToRedisArgs + Hash + Eq)
1426);
1427
1428impl_to_redis_args_for_set!(
1429    for <T> std::collections::BTreeSet<T>,
1430    where (T: ToRedisArgs + Hash + Eq + Ord)
1431);
1432
1433#[cfg(feature = "hashbrown")]
1434impl_to_redis_args_for_set!(
1435    for <T, S> hashbrown::HashSet<T, S>,
1436    where (T: ToRedisArgs + Hash + Eq)
1437);
1438
1439#[cfg(feature = "ahash")]
1440impl_to_redis_args_for_set!(
1441    for <T, S> ahash::AHashSet<T, S>,
1442    where (T: ToRedisArgs + Hash + Eq)
1443);
1444
1445/// @note: Redis cannot store empty maps so the application has to
1446/// check whether the set is empty and if so, not attempt to use that
1447/// result
1448macro_rules! impl_to_redis_args_for_map {
1449    (
1450        $(#[$meta:meta])*
1451        for <$($TypeParam:ident),+> $MapType:ty,
1452        where ($($WhereClause:tt)+)
1453    ) => {
1454        $(#[$meta])*
1455        impl< $($TypeParam),+ > ToRedisArgs for $MapType
1456        where
1457            $($WhereClause)+
1458        {
1459            fn write_redis_args<W>(&self, out: &mut W)
1460            where
1461                W: ?Sized + RedisWrite,
1462            {
1463                for (key, value) in self {
1464                    // Ensure key and value produce a single argument each
1465                    assert!(key.num_of_args() <= 1 && value.num_of_args() <= 1);
1466                    key.write_redis_args(out);
1467                    value.write_redis_args(out);
1468                }
1469            }
1470
1471            fn num_of_args(&self) -> usize {
1472                self.len()
1473            }
1474        }
1475    };
1476}
1477
1478impl_to_redis_args_for_map!(
1479    for <K, V, S> std::collections::HashMap<K, V, S>,
1480    where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1481);
1482
1483impl_to_redis_args_for_map!(
1484    /// this flattens BTreeMap into something that goes well with HMSET
1485    for <K, V> std::collections::BTreeMap<K, V>,
1486    where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1487);
1488
1489#[cfg(feature = "hashbrown")]
1490impl_to_redis_args_for_map!(
1491    for <K, V, S> hashbrown::HashMap<K, V, S>,
1492    where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1493);
1494
1495#[cfg(feature = "ahash")]
1496impl_to_redis_args_for_map!(
1497    for <K, V, S> ahash::AHashMap<K, V, S>,
1498    where (K: ToRedisArgs + Hash + Eq + Ord, V: ToRedisArgs)
1499);
1500
1501macro_rules! to_redis_args_for_tuple {
1502    () => ();
1503    ($(#[$meta:meta],)*$($name:ident,)+) => (
1504        $(#[$meta])*
1505        impl<$($name: ToRedisArgs),*> ToRedisArgs for ($($name,)*) {
1506            // we have local variables named T1 as dummies and those
1507            // variables are unused.
1508            #[allow(non_snake_case, unused_variables)]
1509            fn write_redis_args<W>(&self, out: &mut W) where W: ?Sized + RedisWrite {
1510                let ($(ref $name,)*) = *self;
1511                $($name.write_redis_args(out);)*
1512            }
1513
1514            #[allow(non_snake_case, unused_variables)]
1515            fn num_of_args(&self) -> usize {
1516                let mut n: usize = 0;
1517                $(let $name = (); n += 1;)*
1518                n
1519            }
1520        }
1521    )
1522}
1523
1524to_redis_args_for_tuple! { #[cfg_attr(docsrs, doc(fake_variadic))], #[doc = "This trait is implemented for tuples up to 12 items long."], T, }
1525to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, }
1526to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, }
1527to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, }
1528to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, }
1529to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, }
1530to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, }
1531to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, }
1532to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, }
1533to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, }
1534to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
1535to_redis_args_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
1536
1537impl<T: ToRedisArgs, const N: usize> ToRedisArgs for &[T; N] {
1538    fn write_redis_args<W>(&self, out: &mut W)
1539    where
1540        W: ?Sized + RedisWrite,
1541    {
1542        ToRedisArgs::write_args_from_slice(self.as_slice(), out)
1543    }
1544
1545    fn num_of_args(&self) -> usize {
1546        if ToRedisArgs::is_single_vec_arg(&self[..]) {
1547            return 1;
1548        }
1549        if self.len() == 1 {
1550            self[0].num_of_args()
1551        } else {
1552            self.len()
1553        }
1554    }
1555}
1556impl<const N: usize> ToSingleRedisArg for &[u8; N] {}
1557
1558fn vec_to_array<T, const N: usize>(
1559    items: Vec<T>,
1560    original_value: &Value,
1561) -> Result<[T; N], ParsingError> {
1562    match items.try_into() {
1563        Ok(array) => Ok(array),
1564        Err(items) => {
1565            let msg = format!(
1566                "Response has wrong dimension, expected {N}, got {}",
1567                items.len()
1568            );
1569            crate::errors::invalid_type_error!(original_value, msg)
1570        }
1571    }
1572}
1573
1574impl<T: FromRedisValue, const N: usize> FromRedisValue for [T; N] {
1575    fn from_redis_value_ref(value: &Value) -> Result<[T; N], ParsingError> {
1576        match *value {
1577            Value::BulkString(ref bytes) => match FromRedisValue::from_byte_slice(bytes) {
1578                Some(items) => vec_to_array(items, value),
1579                None => {
1580                    let msg = format!(
1581                        "Conversion to Array[{}; {N}] failed",
1582                        std::any::type_name::<T>()
1583                    );
1584                    crate::errors::invalid_type_error!(value, msg)
1585                }
1586            },
1587            Value::Array(ref items) => {
1588                let items = FromRedisValue::from_redis_value_refs(items)?;
1589                vec_to_array(items, value)
1590            }
1591            Value::Nil => vec_to_array(vec![], value),
1592            _ => crate::errors::invalid_type_error!(value, "Response type not array compatible"),
1593        }
1594    }
1595
1596    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
1597        Self::from_redis_value_ref(&v)
1598    }
1599}
1600
1601/// This trait is used to convert a redis value into a more appropriate
1602/// type.
1603///
1604/// While a redis `Value` can represent any response that comes
1605/// back from the redis server, usually you want to map this into something
1606/// that works better in rust.  For instance you might want to convert the
1607/// return value into a `String` or an integer.
1608///
1609/// This trait is well supported throughout the library and you can
1610/// implement it for your own types if you want.
1611///
1612/// In addition to what you can see from the docs, this is also implemented
1613/// for tuples up to size 12 and for `Vec<u8>`.
1614pub trait FromRedisValue: Sized {
1615    /// Given a redis `Value` this attempts to convert it into the given
1616    /// destination type.  If that fails because it's not compatible an
1617    /// appropriate error is generated.
1618    fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError> {
1619        // By default, fall back to `from_redis_value_ref`.
1620        // This function only needs to be implemented if it can benefit
1621        // from taking `v` by value.
1622        Self::from_redis_value(v.clone())
1623    }
1624
1625    /// Given a redis `Value` this attempts to convert it into the given
1626    /// destination type.  If that fails because it's not compatible an
1627    /// appropriate error is generated.
1628    fn from_redis_value(v: Value) -> Result<Self, ParsingError>;
1629
1630    /// Similar to `from_redis_value_ref` but constructs a vector of objects
1631    /// from another vector of values.  This primarily exists internally
1632    /// to customize the behavior for vectors of tuples.
1633    fn from_redis_value_refs(items: &[Value]) -> Result<Vec<Self>, ParsingError> {
1634        items
1635            .iter()
1636            .map(FromRedisValue::from_redis_value_ref)
1637            .collect()
1638    }
1639
1640    /// The same as `from_redis_value_refs`, but takes a `Vec<Value>` instead
1641    /// of a `&[Value]`.
1642    fn from_redis_values(items: Vec<Value>) -> Result<Vec<Self>, ParsingError> {
1643        items
1644            .into_iter()
1645            .map(FromRedisValue::from_redis_value)
1646            .collect()
1647    }
1648
1649    /// The same as `from_redis_values`, but returns a result for each
1650    /// conversion to make handling them case-by-case possible.
1651    fn from_each_redis_values(items: Vec<Value>) -> Vec<Result<Self, ParsingError>> {
1652        items
1653            .into_iter()
1654            .map(FromRedisValue::from_redis_value)
1655            .collect()
1656    }
1657
1658    /// Convert bytes to a single element vector.
1659    fn from_byte_slice(_vec: &[u8]) -> Option<Vec<Self>> {
1660        Self::from_redis_value(Value::BulkString(_vec.into()))
1661            .map(|rv| vec![rv])
1662            .ok()
1663    }
1664
1665    /// Convert bytes to a single element vector.
1666    fn from_byte_vec(_vec: Vec<u8>) -> Result<Vec<Self>, ParsingError> {
1667        Self::from_redis_value(Value::BulkString(_vec)).map(|rv| vec![rv])
1668    }
1669}
1670
1671fn get_inner_value(v: &Value) -> &Value {
1672    if let Value::Attribute {
1673        data,
1674        attributes: _,
1675    } = v
1676    {
1677        data.as_ref()
1678    } else {
1679        v
1680    }
1681}
1682
1683fn get_owned_inner_value(v: Value) -> Value {
1684    if let Value::Attribute {
1685        data,
1686        attributes: _,
1687    } = v
1688    {
1689        *data
1690    } else {
1691        v
1692    }
1693}
1694
1695macro_rules! from_redis_value_for_num_internal {
1696    ($t:ty, $v:expr) => {{
1697        let v = if let Value::Attribute {
1698            data,
1699            attributes: _,
1700        } = $v
1701        {
1702            data
1703        } else {
1704            $v
1705        };
1706        match *v {
1707            Value::Int(val) => Ok(val as $t),
1708            Value::SimpleString(ref s) => match s.parse::<$t>() {
1709                Ok(rv) => Ok(rv),
1710                Err(_) => crate::errors::invalid_type_error!(v, "Could not convert from string."),
1711            },
1712            Value::BulkString(ref bytes) => match from_utf8(bytes)?.parse::<$t>() {
1713                Ok(rv) => Ok(rv),
1714                Err(_) => crate::errors::invalid_type_error!(v, "Could not convert from string."),
1715            },
1716            Value::Double(val) => Ok(val as $t),
1717            _ => crate::errors::invalid_type_error!(v, "Response type not convertible to numeric."),
1718        }
1719    }};
1720}
1721
1722macro_rules! from_redis_value_for_num {
1723    ($t:ty) => {
1724        impl FromRedisValue for $t {
1725            fn from_redis_value_ref(v: &Value) -> Result<$t, ParsingError> {
1726                from_redis_value_for_num_internal!($t, v)
1727            }
1728
1729            fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
1730                Self::from_redis_value_ref(&v)
1731            }
1732        }
1733    };
1734}
1735
1736impl FromRedisValue for u8 {
1737    fn from_redis_value_ref(v: &Value) -> Result<u8, ParsingError> {
1738        from_redis_value_for_num_internal!(u8, v)
1739    }
1740
1741    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
1742        Self::from_redis_value_ref(&v)
1743    }
1744
1745    // this hack allows us to specialize Vec<u8> to work with binary data.
1746    fn from_byte_slice(vec: &[u8]) -> Option<Vec<u8>> {
1747        Some(vec.to_vec())
1748    }
1749    fn from_byte_vec(vec: Vec<u8>) -> Result<Vec<u8>, ParsingError> {
1750        Ok(vec)
1751    }
1752}
1753
1754from_redis_value_for_num!(i8);
1755from_redis_value_for_num!(i16);
1756from_redis_value_for_num!(u16);
1757from_redis_value_for_num!(i32);
1758from_redis_value_for_num!(u32);
1759from_redis_value_for_num!(i64);
1760from_redis_value_for_num!(u64);
1761from_redis_value_for_num!(i128);
1762from_redis_value_for_num!(u128);
1763from_redis_value_for_num!(f32);
1764from_redis_value_for_num!(f64);
1765from_redis_value_for_num!(isize);
1766from_redis_value_for_num!(usize);
1767
1768#[cfg(any(
1769    feature = "rust_decimal",
1770    feature = "bigdecimal",
1771    feature = "num-bigint"
1772))]
1773macro_rules! from_redis_value_for_bignum_internal {
1774    ($t:ty, $v:expr) => {{
1775        let v = $v;
1776        match *v {
1777            Value::Int(val) => <$t>::try_from(val).map_err(|_| {
1778                crate::errors::invalid_type_error_inner!(v, "Could not convert from integer.")
1779            }),
1780            Value::SimpleString(ref s) => match s.parse::<$t>() {
1781                Ok(rv) => Ok(rv),
1782                Err(_) => crate::errors::invalid_type_error!(v, "Could not convert from string."),
1783            },
1784            Value::BulkString(ref bytes) => match from_utf8(bytes)?.parse::<$t>() {
1785                Ok(rv) => Ok(rv),
1786                Err(_) => crate::errors::invalid_type_error!(v, "Could not convert from string."),
1787            },
1788            _ => crate::errors::invalid_type_error!(v, "Response type not convertible to numeric."),
1789        }
1790    }};
1791}
1792
1793#[cfg(any(
1794    feature = "rust_decimal",
1795    feature = "bigdecimal",
1796    feature = "num-bigint"
1797))]
1798macro_rules! from_redis_value_for_bignum {
1799    ($t:ty) => {
1800        impl FromRedisValue for $t {
1801            fn from_redis_value_ref(v: &Value) -> Result<$t, ParsingError> {
1802                from_redis_value_for_bignum_internal!($t, v)
1803            }
1804
1805            fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
1806                Self::from_redis_value_ref(&v)
1807            }
1808        }
1809    };
1810}
1811
1812#[cfg(feature = "rust_decimal")]
1813from_redis_value_for_bignum!(rust_decimal::Decimal);
1814#[cfg(feature = "bigdecimal")]
1815from_redis_value_for_bignum!(bigdecimal::BigDecimal);
1816#[cfg(feature = "num-bigint")]
1817from_redis_value_for_bignum!(num_bigint::BigInt);
1818#[cfg(feature = "num-bigint")]
1819from_redis_value_for_bignum!(num_bigint::BigUint);
1820
1821impl FromRedisValue for bool {
1822    fn from_redis_value_ref(v: &Value) -> Result<bool, ParsingError> {
1823        let v = get_inner_value(v);
1824        match *v {
1825            Value::Nil => Ok(false),
1826            Value::Int(val) => Ok(val != 0),
1827            Value::SimpleString(ref s) => {
1828                if &s[..] == "1" {
1829                    Ok(true)
1830                } else if &s[..] == "0" {
1831                    Ok(false)
1832                } else {
1833                    crate::errors::invalid_type_error!(v, "Response status not valid boolean");
1834                }
1835            }
1836            Value::BulkString(ref bytes) => {
1837                if bytes == b"1" {
1838                    Ok(true)
1839                } else if bytes == b"0" {
1840                    Ok(false)
1841                } else {
1842                    crate::errors::invalid_type_error!(v, "Response type not bool compatible.");
1843                }
1844            }
1845            Value::Boolean(b) => Ok(b),
1846            Value::Okay => Ok(true),
1847            _ => crate::errors::invalid_type_error!(v, "Response type not bool compatible."),
1848        }
1849    }
1850
1851    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
1852        Self::from_redis_value_ref(&v)
1853    }
1854}
1855
1856impl FromRedisValue for CString {
1857    fn from_redis_value_ref(v: &Value) -> Result<CString, ParsingError> {
1858        let v = get_inner_value(v);
1859        match *v {
1860            Value::BulkString(ref bytes) => Ok(CString::new(bytes.as_slice())?),
1861            Value::Okay => Ok(CString::new("OK")?),
1862            Value::SimpleString(ref val) => Ok(CString::new(val.as_bytes())?),
1863            _ => crate::errors::invalid_type_error!(v, "Response type not CString compatible."),
1864        }
1865    }
1866    fn from_redis_value(v: Value) -> Result<CString, ParsingError> {
1867        let v = get_owned_inner_value(v);
1868        match v {
1869            Value::BulkString(bytes) => Ok(CString::new(bytes)?),
1870            Value::Okay => Ok(CString::new("OK")?),
1871            Value::SimpleString(val) => Ok(CString::new(val)?),
1872            _ => crate::errors::invalid_type_error!(v, "Response type not CString compatible."),
1873        }
1874    }
1875}
1876
1877impl FromRedisValue for String {
1878    fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError> {
1879        let v = get_inner_value(v);
1880        match *v {
1881            Value::BulkString(ref bytes) => Ok(from_utf8(bytes)?.to_string()),
1882            Value::Okay => Ok("OK".to_string()),
1883            Value::SimpleString(ref val) => Ok(val.to_string()),
1884            Value::VerbatimString {
1885                format: _,
1886                ref text,
1887            } => Ok(text.to_string()),
1888            Value::Double(ref val) => Ok(val.to_string()),
1889            Value::Int(val) => Ok(val.to_string()),
1890            _ => crate::errors::invalid_type_error!(v, "Response type not string compatible."),
1891        }
1892    }
1893
1894    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
1895        let v = get_owned_inner_value(v);
1896        match v {
1897            Value::BulkString(bytes) => Ok(Self::from_utf8(bytes)?),
1898            Value::Okay => Ok("OK".to_string()),
1899            Value::SimpleString(val) => Ok(val),
1900            Value::VerbatimString { format: _, text } => Ok(text),
1901            Value::Double(val) => Ok(val.to_string()),
1902            Value::Int(val) => Ok(val.to_string()),
1903            _ => crate::errors::invalid_type_error!(v, "Response type not string compatible."),
1904        }
1905    }
1906}
1907
1908macro_rules! pointer_from_redis_value_impl {
1909    (
1910        $(#[$attr:meta])*
1911        $id:ident, $ty:ty, $func:expr
1912    ) => {
1913        $(#[$attr])*
1914        impl<$id:  FromRedisValue> FromRedisValue for $ty {
1915            fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError>
1916            {
1917                FromRedisValue::from_redis_value_ref(v).map($func)
1918            }
1919
1920            fn from_redis_value(v: Value) -> Result<Self, ParsingError>{
1921                FromRedisValue::from_redis_value(v).map($func)
1922            }
1923        }
1924    }
1925}
1926
1927pointer_from_redis_value_impl!(T, Box<T>, Box::new);
1928pointer_from_redis_value_impl!(T, std::sync::Arc<T>, std::sync::Arc::new);
1929pointer_from_redis_value_impl!(T, std::rc::Rc<T>, std::rc::Rc::new);
1930
1931/// Implement `FromRedisValue` for `$Type` (which should use the generic parameter `$T`).
1932///
1933/// The implementation parses the value into a vec, and then passes the value through `$convert`.
1934/// If `$convert` is omitted, it defaults to `Into::into`.
1935macro_rules! from_vec_from_redis_value {
1936    (<$T:ident> $Type:ty) => {
1937        from_vec_from_redis_value!(<$T> $Type; Into::into);
1938    };
1939
1940    (<$T:ident> $Type:ty; $convert:expr) => {
1941        impl<$T: FromRedisValue> FromRedisValue for $Type {
1942            fn from_redis_value_ref(v: &Value) -> Result<$Type, ParsingError> {
1943                match v {
1944                    // All binary data except u8 will try to parse into a single element vector.
1945                    // u8 has its own implementation of from_byte_slice.
1946                    Value::BulkString(bytes) => match FromRedisValue::from_byte_slice(bytes) {
1947                        Some(x) => Ok($convert(x)),
1948                        None => crate::errors::invalid_type_error!(
1949                            v,
1950                            format!("Conversion to {} failed.", std::any::type_name::<$Type>())
1951                        ),
1952                    },
1953                    Value::Array(items) => FromRedisValue::from_redis_value_refs(items).map($convert),
1954                    Value::Set(ref items) => FromRedisValue::from_redis_value_refs(items).map($convert),
1955                    Value::Map(ref items) => {
1956                        let mut n: Vec<T> = vec![];
1957                        for item in items {
1958                            match FromRedisValue::from_redis_value_ref(&Value::Map(vec![item.clone()])) {
1959                                Ok(v) => {
1960                                    n.push(v);
1961                                }
1962                                Err(e) => {
1963                                    return Err(e);
1964                                }
1965                            }
1966                        }
1967                        Ok($convert(n))
1968                    }
1969                    Value::Nil => Ok($convert(Vec::new())),
1970                    _ => crate::errors::invalid_type_error!(v, "Response type not vector compatible."),
1971                }
1972            }
1973            fn from_redis_value(v: Value) -> Result<$Type, ParsingError> {
1974                match v {
1975                    // Binary data is parsed into a single-element vector, except
1976                    // for the element type `u8`, which directly consumes the entire
1977                    // array of bytes.
1978                    Value::BulkString(bytes) => FromRedisValue::from_byte_vec(bytes).map($convert),
1979                    Value::Array(items) => FromRedisValue::from_redis_values(items).map($convert),
1980                    Value::Set(items) => FromRedisValue::from_redis_values(items).map($convert),
1981                    Value::Map(items) => {
1982                        let mut n: Vec<T> = vec![];
1983                        for item in items {
1984                            match FromRedisValue::from_redis_value(Value::Map(vec![item])) {
1985                                Ok(v) => {
1986                                    n.push(v);
1987                                }
1988                                Err(e) => {
1989                                    return Err(e);
1990                                }
1991                            }
1992                        }
1993                        Ok($convert(n))
1994                    }
1995                    Value::Nil => Ok($convert(Vec::new())),
1996                    _ => crate::errors::invalid_type_error!(v, "Response type not vector compatible."),
1997                }
1998            }
1999        }
2000    };
2001}
2002
2003from_vec_from_redis_value!(<T> Vec<T>);
2004from_vec_from_redis_value!(<T> std::sync::Arc<[T]>);
2005from_vec_from_redis_value!(<T> Box<[T]>; Vec::into_boxed_slice);
2006
2007macro_rules! impl_from_redis_value_for_map {
2008    (for <$($TypeParam:ident),+> $MapType:ty, where ($($WhereClause:tt)+)) => {
2009        impl< $($TypeParam),+ > FromRedisValue for $MapType
2010        where
2011            $($WhereClause)+
2012        {
2013            fn from_redis_value_ref(v: &Value) -> Result<$MapType, ParsingError> {
2014                let v = get_inner_value(v);
2015                match *v {
2016                    Value::Nil => Ok(Default::default()),
2017                    _ => v
2018                        .as_map_iter()
2019                        .ok_or_else(|| crate::errors::invalid_type_error_inner!(v, "Response type not map compatible"))?
2020                        .map(|(k, v)| {
2021                            Ok((from_redis_value_ref(k)?, from_redis_value_ref(v)?))
2022                        })
2023                        .collect(),
2024                }
2025            }
2026
2027            fn from_redis_value(v: Value) -> Result<$MapType, ParsingError> {
2028                let v = get_owned_inner_value(v);
2029                match v {
2030                    Value::Nil => Ok(Default::default()),
2031                    _ => v
2032                        .into_map_iter()
2033                        .map_err(|v| crate::errors::invalid_type_error_inner!(v, "Response type not map compatible"))?
2034                        .map(|(k, v)| {
2035                            Ok((from_redis_value(k)?, from_redis_value(v)?))
2036                        })
2037                        .collect(),
2038                }
2039            }
2040        }
2041    };
2042}
2043
2044impl_from_redis_value_for_map!(
2045    for <K, V, S> std::collections::HashMap<K, V, S>,
2046    where (K: FromRedisValue + Eq + Hash, V: FromRedisValue, S: BuildHasher + Default)
2047);
2048
2049impl_from_redis_value_for_map!(
2050    for <K, V> std::collections::BTreeMap<K, V>,
2051    where (K: FromRedisValue + Eq + Hash + Ord, V: FromRedisValue)
2052);
2053
2054#[cfg(feature = "hashbrown")]
2055impl_from_redis_value_for_map!(
2056    for <K, V, S> hashbrown::HashMap<K, V, S>,
2057    where (K: FromRedisValue + Eq + Hash, V: FromRedisValue, S: BuildHasher + Default)
2058);
2059
2060// `AHashMap::default` is not generic over `S` param so we can't be generic over it as well.
2061#[cfg(feature = "ahash")]
2062impl_from_redis_value_for_map!(
2063    for <K, V> ahash::AHashMap<K, V>,
2064    where (K: FromRedisValue + Eq + Hash, V: FromRedisValue)
2065);
2066
2067macro_rules! impl_from_redis_value_for_set {
2068    (for <$($TypeParam:ident),+> $SetType:ty, where ($($WhereClause:tt)+)) => {
2069        impl< $($TypeParam),+ > FromRedisValue for $SetType
2070        where
2071            $($WhereClause)+
2072        {
2073            fn from_redis_value_ref(v: &Value) -> Result<$SetType, ParsingError> {
2074                let v = get_inner_value(v);
2075                let items = v
2076                    .as_sequence()
2077                    .ok_or_else(|| crate::errors::invalid_type_error_inner!(v, "Response type not map compatible"))?;
2078                items.iter().map(|item| from_redis_value_ref(item)).collect()
2079            }
2080
2081            fn from_redis_value(v: Value) -> Result<$SetType, ParsingError> {
2082                let v = get_owned_inner_value(v);
2083                let items = v
2084                    .into_sequence()
2085                    .map_err(|v| crate::errors::invalid_type_error_inner!(v, "Response type not map compatible"))?;
2086                items
2087                    .into_iter()
2088                    .map(|item| from_redis_value(item))
2089                    .collect()
2090            }
2091        }
2092    };
2093}
2094
2095impl_from_redis_value_for_set!(
2096    for <T, S> std::collections::HashSet<T, S>,
2097    where (T: FromRedisValue + Eq + Hash, S: BuildHasher + Default)
2098);
2099
2100impl_from_redis_value_for_set!(
2101    for <T> std::collections::BTreeSet<T>,
2102    where (T: FromRedisValue + Eq + Ord)
2103);
2104
2105#[cfg(feature = "hashbrown")]
2106impl_from_redis_value_for_set!(
2107    for <T, S> hashbrown::HashSet<T, S>,
2108    where (T: FromRedisValue + Eq + Hash, S: BuildHasher + Default)
2109);
2110
2111// `AHashSet::from_iter` is not generic over `S` param so we can't be generic over it as well.
2112#[cfg(feature = "ahash")]
2113impl_from_redis_value_for_set!(
2114    for <T> ahash::AHashSet<T>,
2115    where (T: FromRedisValue + Eq + Hash)
2116);
2117
2118impl FromRedisValue for Value {
2119    fn from_redis_value_ref(v: &Value) -> Result<Value, ParsingError> {
2120        Ok(v.clone())
2121    }
2122
2123    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
2124        Ok(v)
2125    }
2126}
2127
2128impl FromRedisValue for () {
2129    fn from_redis_value_ref(v: &Value) -> Result<(), ParsingError> {
2130        match v {
2131            Value::ServerError(err) => Err(ParsingError::from(err.to_string())),
2132            _ => Ok(()),
2133        }
2134    }
2135
2136    fn from_redis_value(v: Value) -> Result<(), ParsingError> {
2137        Self::from_redis_value_ref(&v)
2138    }
2139}
2140
2141macro_rules! from_redis_value_for_tuple {
2142    () => ();
2143    ($(#[$meta:meta],)*$($name:ident,)+) => (
2144        $(#[$meta])*
2145        impl<$($name: FromRedisValue),*> FromRedisValue for ($($name,)*) {
2146            // we have local variables named T1 as dummies and those
2147            // variables are unused.
2148            #[allow(non_snake_case, unused_variables)]
2149            fn from_redis_value_ref(v: &Value) -> Result<($($name,)*), ParsingError> {
2150                let v = get_inner_value(v);
2151                // hacky way to count the tuple size
2152                let mut n = 0;
2153                $(let $name = (); n += 1;)*
2154
2155                match *v {
2156                    Value::Array(ref items) => {
2157                        if items.len() != n {
2158                            crate::errors::invalid_type_error!(v, "Array response of wrong dimension")
2159                        }
2160
2161                        // The { i += 1; i - 1} is rust's postfix increment :)
2162                        let mut i = 0;
2163                        Ok(($({let $name = (); from_redis_value_ref(
2164                             &items[{ i += 1; i - 1 }])?},)*))
2165                    }
2166
2167                    Value::Set(ref items) => {
2168                        if items.len() != n {
2169                            crate::errors::invalid_type_error!(v, "Set response of wrong dimension")
2170                        }
2171
2172                        // The { i += 1; i - 1} is rust's postfix increment :)
2173                        let mut i = 0;
2174                        Ok(($({let $name = (); from_redis_value_ref(
2175                             &items[{ i += 1; i - 1 }])?},)*))
2176                    }
2177
2178                    Value::Map(ref items) => {
2179                        if n != items.len() * 2 {
2180                            crate::errors::invalid_type_error!(v, "Map response of wrong dimension")
2181                        }
2182
2183                        let mut flatten_items = items.iter().map(|(a,b)|[a,b]).flatten();
2184
2185                        Ok(($({let $name = (); from_redis_value_ref(
2186                             &flatten_items.next().unwrap())?},)*))
2187                    }
2188
2189                    _ => crate::errors::invalid_type_error!(v, "Not a Array response")
2190                }
2191            }
2192
2193            // we have local variables named T1 as dummies and those
2194            // variables are unused.
2195            #[allow(non_snake_case, unused_variables)]
2196            fn from_redis_value(v: Value) -> Result<($($name,)*), ParsingError> {
2197                let v = get_owned_inner_value(v);
2198                // hacky way to count the tuple size
2199                let mut n = 0;
2200                $(let $name = (); n += 1;)*
2201                match v {
2202                    Value::Array(mut items) => {
2203                        if items.len() != n {
2204                            crate::errors::invalid_type_error!(Value::Array(items), "Array response of wrong dimension")
2205                        }
2206
2207                        // The { i += 1; i - 1} is rust's postfix increment :)
2208                        let mut i = 0;
2209                        Ok(($({let $name = (); from_redis_value(
2210                            ::std::mem::replace(&mut items[{ i += 1; i - 1 }], Value::Nil)
2211                        )?},)*))
2212                    }
2213
2214                    Value::Set(mut items) => {
2215                        if items.len() != n {
2216                            crate::errors::invalid_type_error!(Value::Array(items), "Set response of wrong dimension")
2217                        }
2218
2219                        // The { i += 1; i - 1} is rust's postfix increment :)
2220                        let mut i = 0;
2221                        Ok(($({let $name = (); from_redis_value(
2222                            ::std::mem::replace(&mut items[{ i += 1; i - 1 }], Value::Nil)
2223                        )?},)*))
2224                    }
2225
2226                    Value::Map(items) => {
2227                        if n != items.len() * 2 {
2228                            crate::errors::invalid_type_error!(Value::Map(items), "Map response of wrong dimension")
2229                        }
2230
2231                        let mut flatten_items = items.into_iter().map(|(a,b)|[a,b]).flatten();
2232
2233                        Ok(($({let $name = (); from_redis_value(
2234                            ::std::mem::replace(&mut flatten_items.next().unwrap(), Value::Nil)
2235                        )?},)*))
2236                    }
2237
2238                    _ => crate::errors::invalid_type_error!(v, "Not a Array response")
2239                }
2240            }
2241
2242            #[allow(non_snake_case, unused_variables)]
2243            fn from_redis_value_refs(items: &[Value]) -> Result<Vec<($($name,)*)>, ParsingError> {
2244                // hacky way to count the tuple size
2245                let mut n = 0;
2246                $(let $name = (); n += 1;)*
2247                if items.len() == 0 {
2248                    return Ok(vec![]);
2249                }
2250
2251                if items.iter().all(|item| item.is_collection_of_len(n)) {
2252                    return items.iter().map(|item| from_redis_value_ref(item)).collect();
2253                }
2254
2255                let mut rv = Vec::with_capacity(items.len() / n);
2256                if let [$($name),*] = items {
2257                    rv.push(($(from_redis_value_ref($name)?,)*));
2258                    return Ok(rv);
2259                }
2260                for chunk in items.chunks(n) {
2261                    match chunk {
2262                        [$($name),*] => rv.push(($(from_redis_value_ref($name)?,)*)),
2263                         _ => return Err(format!("Vector of length {} doesn't have arity of {n}", items.len()).into()),
2264                    }
2265                }
2266                Ok(rv)
2267            }
2268
2269            #[allow(non_snake_case, unused_variables)]
2270            fn from_each_redis_values(mut items: Vec<Value>) -> Vec<Result<($($name,)*), ParsingError>> {
2271                #[allow(unused_parens)]
2272                let extract = |val: ($(Result<$name, ParsingError>,)*)| -> Result<($($name,)*), ParsingError> {
2273                    let ($($name,)*) = val;
2274                    Ok(($($name?,)*))
2275                };
2276
2277                // hacky way to count the tuple size
2278                let mut n = 0;
2279                $(let $name = (); n += 1;)*
2280
2281                // let mut rv = vec![];
2282                if items.len() == 0 {
2283                    return vec![];
2284                }
2285                if items.iter().all(|item| item.is_collection_of_len(n)) {
2286                    return items.into_iter().map(|item| from_redis_value(item).map_err(|err|err.into())).collect();
2287                }
2288
2289                let mut rv = Vec::with_capacity(items.len() / n);
2290
2291                for chunk in items.chunks_mut(n) {
2292                    match chunk {
2293                        // Take each element out of the chunk with `std::mem::replace`, leaving a `Value::Nil`
2294                        // in its place. This allows each `Value` to be parsed without being copied.
2295                        // Since `items` is consumed by this function and not used later, this replacement
2296                        // is not observable to the rest of the code.
2297                        [$($name),*] => rv.push(extract(($(from_redis_value(std::mem::replace($name, Value::Nil)).into(),)*))),
2298                         _ => return vec![Err(format!("Vector of length {} doesn't have arity of {n}", items.len()).into())],
2299                    }
2300                }
2301                rv
2302            }
2303
2304            #[allow(non_snake_case, unused_variables)]
2305            fn from_redis_values(mut items: Vec<Value>) -> Result<Vec<($($name,)*)>, ParsingError> {
2306                // hacky way to count the tuple size
2307                let mut n = 0;
2308                $(let $name = (); n += 1;)*
2309
2310                // let mut rv = vec![];
2311                if items.len() == 0 {
2312                    return Ok(vec![])
2313                }
2314                if items.iter().all(|item| item.is_collection_of_len(n)) {
2315                    return items.into_iter().map(|item| from_redis_value(item)).collect();
2316                }
2317
2318                let mut rv = Vec::with_capacity(items.len() / n);
2319                for chunk in items.chunks_mut(n) {
2320                    match chunk {
2321                        // Take each element out of the chunk with `std::mem::replace`, leaving a `Value::Nil`
2322                        // in its place. This allows each `Value` to be parsed without being copied.
2323                        // Since `items` is consume by this function and not used later, this replacement
2324                        // is not observable to the rest of the code.
2325                        [$($name),*] => rv.push(($(from_redis_value(std::mem::replace($name, Value::Nil))?,)*)),
2326                         _ => return Err(format!("Vector of length {} doesn't have arity of {n}", items.len()).into()),
2327                    }
2328                }
2329                Ok(rv)
2330            }
2331        }
2332    )
2333}
2334
2335from_redis_value_for_tuple! { #[cfg_attr(docsrs, doc(fake_variadic))], #[doc = "This trait is implemented for tuples up to 12 items long."], T, }
2336from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, }
2337from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, }
2338from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, }
2339from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, }
2340from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, }
2341from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, }
2342from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, }
2343from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, }
2344from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, }
2345from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
2346from_redis_value_for_tuple! { #[doc(hidden)], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, }
2347
2348impl FromRedisValue for InfoDict {
2349    fn from_redis_value_ref(v: &Value) -> Result<InfoDict, ParsingError> {
2350        let v = get_inner_value(v);
2351        let s: String = from_redis_value_ref(v)?;
2352        Ok(InfoDict::new(&s))
2353    }
2354    fn from_redis_value(v: Value) -> Result<InfoDict, ParsingError> {
2355        let v = get_owned_inner_value(v);
2356        let s: String = from_redis_value(v)?;
2357        Ok(InfoDict::new(&s))
2358    }
2359}
2360
2361impl<T: FromRedisValue> FromRedisValue for Option<T> {
2362    fn from_redis_value_ref(v: &Value) -> Result<Option<T>, ParsingError> {
2363        let v = get_inner_value(v);
2364        if *v == Value::Nil {
2365            return Ok(None);
2366        }
2367        Ok(Some(from_redis_value_ref(v)?))
2368    }
2369    fn from_redis_value(v: Value) -> Result<Option<T>, ParsingError> {
2370        let v = get_owned_inner_value(v);
2371        if v == Value::Nil {
2372            return Ok(None);
2373        }
2374        Ok(Some(from_redis_value(v)?))
2375    }
2376}
2377
2378#[cfg(feature = "bytes")]
2379impl FromRedisValue for bytes::Bytes {
2380    fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError> {
2381        let v = get_inner_value(v);
2382        match v {
2383            Value::BulkString(bytes_vec) => Ok(bytes::Bytes::copy_from_slice(bytes_vec.as_ref())),
2384            _ => crate::errors::invalid_type_error!(v, "Not a bulk string"),
2385        }
2386    }
2387    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
2388        let v = get_owned_inner_value(v);
2389        match v {
2390            Value::BulkString(bytes_vec) => Ok(bytes_vec.into()),
2391            _ => crate::errors::invalid_type_error!(v, "Not a bulk string"),
2392        }
2393    }
2394}
2395
2396#[cfg(feature = "uuid")]
2397impl FromRedisValue for uuid::Uuid {
2398    fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError> {
2399        match *v {
2400            Value::BulkString(ref bytes) => Ok(uuid::Uuid::from_slice(bytes)?),
2401            _ => crate::errors::invalid_type_error!(v, "Response type not uuid compatible."),
2402        }
2403    }
2404
2405    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
2406        Self::from_redis_value_ref(&v)
2407    }
2408}
2409
2410#[cfg(feature = "uuid")]
2411impl ToRedisArgs for uuid::Uuid {
2412    fn write_redis_args<W>(&self, out: &mut W)
2413    where
2414        W: ?Sized + RedisWrite,
2415    {
2416        out.write_arg(self.as_bytes());
2417    }
2418}
2419
2420#[cfg(feature = "uuid")]
2421impl ToSingleRedisArg for uuid::Uuid {}
2422
2423/// A shortcut function to invoke `FromRedisValue::from_redis_value_ref`
2424/// to make the API slightly nicer.
2425pub fn from_redis_value_ref<T: FromRedisValue>(v: &Value) -> Result<T, ParsingError> {
2426    FromRedisValue::from_redis_value_ref(v)
2427}
2428
2429/// A shortcut function to invoke `FromRedisValue::from_redis_value`
2430/// to make the API slightly nicer.
2431pub fn from_redis_value<T: FromRedisValue>(v: Value) -> Result<T, ParsingError> {
2432    FromRedisValue::from_redis_value(v)
2433}
2434
2435/// Calculates a digest/hash of the given value for use with Redis value comparison operations.
2436/// This function uses the XXH3 algorithm, which is the same algorithm used by Redis for its DIGEST command.
2437/// The resulting digest can be used with `ValueComparison::IFDEQ` and `ValueComparison::IFDNE`.
2438///
2439/// # Example
2440/// ```rust
2441/// use redis::{calculate_value_digest, ValueComparison, SetOptions};
2442///
2443/// let value = "my_value";
2444/// let digest = calculate_value_digest(value);
2445///
2446/// // Use the digest in a value comparison
2447/// let opts = SetOptions::default()
2448///     .value_comparison(ValueComparison::ifdeq(&digest));
2449/// ```
2450pub fn calculate_value_digest<T: ToRedisArgs>(value: T) -> String {
2451    use xxhash_rust::xxh3::xxh3_64;
2452
2453    // Convert the value to Redis args format (bytes)
2454    let args = value.to_redis_args();
2455
2456    // For consistency with Redis behavior, hash the concatenated bytes
2457    // of all arguments, similar to how Redis would serialize the value
2458    let mut combined_bytes = Vec::new();
2459    for arg in args {
2460        combined_bytes.extend_from_slice(&arg);
2461    }
2462
2463    // Calculate XXH3 hash (64-bit) and format as hexadecimal string
2464    let hash = xxh3_64(&combined_bytes);
2465    format!("{:016x}", hash)
2466}
2467
2468/// Validates that the given string is a valid 16-byte hex digest.
2469pub fn is_valid_16_bytes_hex_digest(s: &str) -> bool {
2470    s.len() == 16 && s.chars().all(|c| c.is_ascii_hexdigit())
2471}
2472
2473/// Enum representing the communication protocol with the server.
2474///
2475/// This enum represents the types of data that the server can send to the client,
2476/// and the capabilities that the client can use.
2477#[derive(Clone, Eq, PartialEq, Default, Debug, Copy)]
2478#[non_exhaustive]
2479pub enum ProtocolVersion {
2480    /// <https://github.com/redis/redis-specifications/blob/master/protocol/RESP2.md>
2481    #[default]
2482    RESP2,
2483    /// <https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md>
2484    RESP3,
2485}
2486
2487impl ProtocolVersion {
2488    /// Returns true if the protocol can support RESP3 features.
2489    pub fn supports_resp3(&self) -> bool {
2490        !matches!(self, ProtocolVersion::RESP2)
2491    }
2492}
2493
2494/// Helper enum that is used to define option for the hash expire commands
2495#[derive(Clone, Copy)]
2496#[non_exhaustive]
2497pub enum ExpireOption {
2498    /// NONE -- Set expiration regardless of the field's current expiration.
2499    NONE,
2500    /// NX -- Only set expiration only when the field has no expiration.
2501    NX,
2502    /// XX -- Only set expiration only when the field has an existing expiration.
2503    XX,
2504    /// GT -- Only set expiration only when the new expiration is greater than current one.
2505    GT,
2506    /// LT -- Only set expiration only when the new expiration is less than current one.
2507    LT,
2508}
2509
2510impl ToRedisArgs for ExpireOption {
2511    fn write_redis_args<W>(&self, out: &mut W)
2512    where
2513        W: ?Sized + RedisWrite,
2514    {
2515        match self {
2516            ExpireOption::NX => out.write_arg(b"NX"),
2517            ExpireOption::XX => out.write_arg(b"XX"),
2518            ExpireOption::GT => out.write_arg(b"GT"),
2519            ExpireOption::LT => out.write_arg(b"LT"),
2520            _ => {}
2521        }
2522    }
2523}
2524
2525#[derive(Debug, Clone, PartialEq)]
2526/// A push message from the server.
2527pub struct PushInfo {
2528    /// Push Kind
2529    pub kind: PushKind,
2530    /// Data from push message
2531    pub data: Vec<Value>,
2532}
2533
2534impl PushInfo {
2535    pub(crate) fn disconnect() -> Self {
2536        PushInfo {
2537            kind: crate::PushKind::Disconnection,
2538            data: vec![],
2539        }
2540    }
2541}
2542
2543pub(crate) type SyncPushSender = std::sync::mpsc::Sender<PushInfo>;
2544
2545/// Possible types of value held in Redis: [Redis Docs](https://redis.io/docs/latest/commands/type/)
2546#[derive(Debug, Clone, PartialEq)]
2547#[non_exhaustive]
2548pub enum ValueType {
2549    /// Generally returned by anything that returns a single element. [Redis Docs](https://redis.io/docs/latest/develop/data-types/strings/)
2550    String,
2551    /// A list of String values. [Redis Docs](https://redis.io/docs/latest/develop/data-types/lists/)
2552    List,
2553    /// A set of unique String values. [Redis Docs](https://redis.io/docs/latest/develop/data-types/sets/)
2554    Set,
2555    /// A sorted set of String values. [Redis Docs](https://redis.io/docs/latest/develop/data-types/sorted-sets/)
2556    ZSet,
2557    /// A collection of field-value pairs. [Redis Docs](https://redis.io/docs/latest/develop/data-types/hashes/)
2558    Hash,
2559    /// A Redis Stream. [Redis Docs](https://redis.io/docs/latest/develop/data-types/stream)
2560    Stream,
2561    /// Any other value type not explicitly defined in [Redis Docs](https://redis.io/docs/latest/commands/type/)
2562    Unknown(String),
2563}
2564
2565impl<T: AsRef<str>> From<T> for ValueType {
2566    fn from(s: T) -> Self {
2567        match s.as_ref() {
2568            "string" => ValueType::String,
2569            "list" => ValueType::List,
2570            "set" => ValueType::Set,
2571            "zset" => ValueType::ZSet,
2572            "hash" => ValueType::Hash,
2573            "stream" => ValueType::Stream,
2574            s => ValueType::Unknown(s.to_string()),
2575        }
2576    }
2577}
2578
2579impl From<ValueType> for String {
2580    fn from(v: ValueType) -> Self {
2581        match v {
2582            ValueType::String => "string".to_string(),
2583            ValueType::List => "list".to_string(),
2584            ValueType::Set => "set".to_string(),
2585            ValueType::ZSet => "zset".to_string(),
2586            ValueType::Hash => "hash".to_string(),
2587            ValueType::Stream => "stream".to_string(),
2588            ValueType::Unknown(s) => s,
2589        }
2590    }
2591}
2592
2593impl FromRedisValue for ValueType {
2594    fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError> {
2595        match v {
2596            Value::SimpleString(s) => Ok(s.into()),
2597            _ => crate::errors::invalid_type_error!(v, "Value type should be a simple string"),
2598        }
2599    }
2600
2601    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
2602        match v {
2603            Value::SimpleString(s) => Ok(s.into()),
2604            _ => crate::errors::invalid_type_error!(v, "Value type should be a simple string"),
2605        }
2606    }
2607}
2608
2609/// Returned by typed commands which either return a positive integer or some negative integer indicating some kind of no-op.
2610#[derive(Debug, PartialEq, Clone)]
2611#[non_exhaustive]
2612pub enum IntegerReplyOrNoOp {
2613    /// A positive integer reply indicating success of some kind.
2614    IntegerReply(usize),
2615    /// The field/key you are trying to operate on does not exist.
2616    NotExists,
2617    /// 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.
2618    ExistsButNotRelevant,
2619}
2620
2621impl IntegerReplyOrNoOp {
2622    /// Returns the integer value of the reply.
2623    pub fn raw(&self) -> isize {
2624        match self {
2625            IntegerReplyOrNoOp::IntegerReply(s) => *s as isize,
2626            IntegerReplyOrNoOp::NotExists => -2,
2627            IntegerReplyOrNoOp::ExistsButNotRelevant => -1,
2628        }
2629    }
2630}
2631
2632impl FromRedisValue for IntegerReplyOrNoOp {
2633    fn from_redis_value_ref(v: &Value) -> Result<Self, ParsingError> {
2634        match v {
2635            Value::Int(s) => match s {
2636                -2 => Ok(IntegerReplyOrNoOp::NotExists),
2637                -1 => Ok(IntegerReplyOrNoOp::ExistsButNotRelevant),
2638                _ => Ok(IntegerReplyOrNoOp::IntegerReply(*s as usize)),
2639            },
2640            _ => crate::errors::invalid_type_error!(v, "Value should be an integer"),
2641        }
2642    }
2643
2644    fn from_redis_value(v: Value) -> Result<Self, ParsingError> {
2645        match v {
2646            Value::Int(s) => match s {
2647                -2 => Ok(IntegerReplyOrNoOp::NotExists),
2648                -1 => Ok(IntegerReplyOrNoOp::ExistsButNotRelevant),
2649                _ => Ok(IntegerReplyOrNoOp::IntegerReply(s as usize)),
2650            },
2651            _ => crate::errors::invalid_type_error!(v, "Value should be an integer"),
2652        }
2653    }
2654}
2655
2656impl PartialEq<isize> for IntegerReplyOrNoOp {
2657    fn eq(&self, other: &isize) -> bool {
2658        match self {
2659            IntegerReplyOrNoOp::IntegerReply(s) => *s as isize == *other,
2660            IntegerReplyOrNoOp::NotExists => *other == -2,
2661            IntegerReplyOrNoOp::ExistsButNotRelevant => *other == -1,
2662        }
2663    }
2664}
2665
2666impl PartialEq<usize> for IntegerReplyOrNoOp {
2667    fn eq(&self, other: &usize) -> bool {
2668        match self {
2669            IntegerReplyOrNoOp::IntegerReply(s) => *s == *other,
2670            _ => false,
2671        }
2672    }
2673}
2674
2675impl PartialEq<i32> for IntegerReplyOrNoOp {
2676    fn eq(&self, other: &i32) -> bool {
2677        match self {
2678            IntegerReplyOrNoOp::IntegerReply(s) => *s as i32 == *other,
2679            IntegerReplyOrNoOp::NotExists => *other == -2,
2680            IntegerReplyOrNoOp::ExistsButNotRelevant => *other == -1,
2681        }
2682    }
2683}
2684
2685impl PartialEq<u32> for IntegerReplyOrNoOp {
2686    fn eq(&self, other: &u32) -> bool {
2687        match self {
2688            IntegerReplyOrNoOp::IntegerReply(s) => *s as u32 == *other,
2689            _ => false,
2690        }
2691    }
2692}