Skip to main content

redis/
types.rs

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