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