redis_driver/commands/
bitmap_commands.rs

1use crate::{
2    prepare_command,
3    resp::{cmd, ArgsOrCollection, CommandArg, CommandArgs, IntoArgs, SingleArgOrCollection},
4    PreparedCommand,
5};
6
7/// A group of Redis commands related to [`Bitmaps`](https://redis.io/docs/data-types/bitmaps/)
8/// & [`Bitfields`](https://redis.io/docs/data-types/bitfields/)
9///
10/// # See Also
11/// [Redis Generic Commands](https://redis.io/commands/?group=bitmap)
12pub trait BitmapCommands {
13    /// Count the number of set bits (population counting) in a string.
14    ///
15    /// # Return
16    /// The number of bits set to 1.
17    ///
18    /// # See Also
19    /// [<https://redis.io/commands/bitcount/>](https://redis.io/commands/bitcount/)
20    #[must_use]
21    fn bitcount<K>(&mut self, key: K, range: BitRange) -> PreparedCommand<Self, usize>
22    where
23        Self: Sized,
24        K: Into<CommandArg>,
25    {
26        prepare_command(self, cmd("BITCOUNT").arg(key).arg(range))
27    }
28
29    /// The command treats a Redis string as an array of bits,
30    /// and is capable of addressing specific integer fields
31    /// of varying bit widths and arbitrary non (necessary) aligned offset.
32    ///
33    /// # Return
34    /// A collection with each entry being the corresponding result of the sub command
35    /// given at the same position. OVERFLOW subcommands don't count as generating a reply.
36    ///
37    /// # See Also
38    /// [<https://redis.io/commands/bitfield/>](https://redis.io/commands/bitfield/)
39    #[must_use]
40    fn bitfield<K, C, E, O>(&mut self, key: K, sub_commands: C) -> PreparedCommand<Self, Vec<u64>>
41    where
42        Self: Sized,
43        K: Into<CommandArg>,
44        E: Into<CommandArg>,
45        O: Into<CommandArg>,
46        C: ArgsOrCollection<BitFieldSubCommand<E, O>>,
47    {
48        prepare_command(self, cmd("BITFIELD").arg(key).arg(sub_commands))
49    }
50
51    /// Read-only variant of the BITFIELD command.
52    /// It is like the original BITFIELD but only accepts GET subcommand
53    /// and can safely be used in read-only replicas.
54    ///
55    /// # Return
56    /// A collection with each entry being the corresponding result of the sub command
57    /// given at the same position.
58    ///
59    /// # See Also
60    /// [<https://redis.io/commands/bitfield_ro/>](https://redis.io/commands/bitfield_ro/)
61    #[must_use]
62    fn bitfield_readonly<K, C, E, O>(
63        &mut self,
64        key: K,
65        get_commands: C,
66    ) -> PreparedCommand<Self, Vec<u64>>
67    where
68        Self: Sized,
69        K: Into<CommandArg>,
70        E: Into<CommandArg>,
71        O: Into<CommandArg>,
72        C: ArgsOrCollection<BitFieldGetSubCommand<E, O>>,
73    {
74        prepare_command(self, cmd("BITFIELD_RO").arg(key).arg(get_commands))
75    }
76
77    /// Perform a bitwise operation between multiple keys (containing string values)
78    /// and store the result in the destination key.
79    ///
80    /// # Return
81    /// The size of the string stored in the destination key,
82    /// that is equal to the size of the longest input string.
83    ///
84    /// # See Also
85    /// [<https://redis.io/commands/bitop/>](https://redis.io/commands/bitop/)
86    #[must_use]
87    fn bitop<D, K, KK>(
88        &mut self,
89        operation: BitOperation,
90        dest_key: D,
91        keys: KK,
92    ) -> PreparedCommand<Self, usize>
93    where
94        Self: Sized,
95        D: Into<CommandArg>,
96        K: Into<CommandArg>,
97        KK: SingleArgOrCollection<K>,
98    {
99        prepare_command(self, cmd("BITOP").arg(operation).arg(dest_key).arg(keys))
100    }
101
102    /// Perform a bitwise operation between multiple keys (containing string values)
103    /// and store the result in the destination key.
104    ///
105    /// # Return
106    /// The position of the first bit set to 1 or 0 according to the request.
107    ///
108    /// # See Also
109    /// [<https://redis.io/commands/bitpos/>](https://redis.io/commands/bitpos/)
110    #[must_use]
111    fn bitpos<K>(&mut self, key: K, bit: u64, range: BitRange) -> PreparedCommand<Self, usize>
112    where
113        Self: Sized,
114        K: Into<CommandArg>,
115    {
116        prepare_command(self, cmd("BITPOS").arg(key).arg(bit).arg(range))
117    }
118
119    /// Returns the bit value at offset in the string value stored at key.
120    ///
121    /// # Return
122    /// The bit value stored at offset.
123    ///
124    /// # See Also
125    /// [<https://redis.io/commands/getbit/>](https://redis.io/commands/getbit/)
126    #[must_use]
127    fn getbit<K>(&mut self, key: K, offset: u64) -> PreparedCommand<Self, u64>
128    where
129        Self: Sized,
130        K: Into<CommandArg>,
131    {
132        prepare_command(self, cmd("GETBIT").arg(key).arg(offset))
133    }
134
135    /// Sets or clears the bit at offset in the string value stored at key.
136    ///
137    /// # Return
138    /// The original bit value stored at offset.
139    ///
140    /// # See Also
141    /// [<https://redis.io/commands/setbit/>](https://redis.io/commands/setbit/)
142    #[must_use]
143    fn setbit<K>(&mut self, key: K, offset: u64, value: u64) -> PreparedCommand<Self, u64>
144    where
145        Self: Sized,
146        K: Into<CommandArg>,
147    {
148        prepare_command(self, cmd("SETBIT").arg(key).arg(offset).arg(value))
149    }
150}
151
152/// Interval options for the [`bitcount`](crate::BitmapCommands::bitcount) command
153#[derive(Default)]
154pub struct BitRange {
155    command_args: CommandArgs,
156}
157
158impl BitRange {
159    #[must_use]
160    pub fn range(start: isize, end: isize) -> Self {
161        Self {
162            command_args: CommandArgs::default().arg(start).arg(end),
163        }
164    }
165
166    #[must_use]
167    pub fn unit(self, unit: BitUnit) -> Self {
168        Self {
169            command_args: self.command_args.arg(unit),
170        }
171    }
172}
173
174impl IntoArgs for BitRange {
175    fn into_args(self, args: CommandArgs) -> CommandArgs {
176        args.arg(self.command_args)
177    }
178}
179
180pub enum BitUnit {
181    Byte,
182    Bit,
183}
184
185impl IntoArgs for BitUnit {
186    fn into_args(self, args: CommandArgs) -> CommandArgs {
187        args.arg(match self {
188            BitUnit::Byte => "BYTE",
189            BitUnit::Bit => "BIT",
190        })
191    }
192}
193
194/// Sub-command for the [`bitfield`](crate::BitmapCommands::bitfield) command
195pub enum BitFieldSubCommand<E = &'static str, O = &'static str>
196where
197    E: Into<CommandArg>,
198    O: Into<CommandArg>,
199{
200    Get(BitFieldGetSubCommand<E, O>),
201    Set(E, O, u64),
202    IncrBy(E, O, i64),
203    Overflow(BitFieldOverflow),
204}
205
206impl<E, O> BitFieldSubCommand<E, O>
207where
208    E: Into<CommandArg>,
209    O: Into<CommandArg>,
210{
211    #[must_use]
212    pub fn get(encoding: E, offset: O) -> Self {
213        Self::Get(BitFieldGetSubCommand::new(encoding, offset))
214    }
215
216    #[must_use]
217    pub fn set(encoding: E, offset: O, value: u64) -> Self {
218        Self::Set(encoding, offset, value)
219    }
220
221    #[must_use]
222    pub fn incr_by(encoding: E, offset: O, increment: i64) -> Self {
223        Self::IncrBy(encoding, offset, increment)
224    }
225
226    #[must_use]
227    pub fn overflow(overflow: BitFieldOverflow) -> Self {
228        Self::Overflow(overflow)
229    }
230}
231
232impl<E, O> IntoArgs for BitFieldSubCommand<E, O>
233where
234    E: Into<CommandArg>,
235    O: Into<CommandArg>,
236{
237    fn into_args(self, args: CommandArgs) -> CommandArgs {
238        match self {
239            BitFieldSubCommand::Get(g) => g.into_args(args),
240            BitFieldSubCommand::Set(encoding, offset, value) => {
241                args.arg("SET").arg(encoding).arg(offset).arg(value)
242            }
243            BitFieldSubCommand::IncrBy(encoding, offset, increment) => {
244                args.arg("INCRBY").arg(encoding).arg(offset).arg(increment)
245            }
246            BitFieldSubCommand::Overflow(overflow) => args.arg("OVERFLOW").arg(overflow),
247        }
248    }
249}
250
251pub struct BitFieldGetSubCommand<E = &'static str, O = &'static str>
252where
253    E: Into<CommandArg>,
254    O: Into<CommandArg>,
255{
256    encoding: E,
257    offset: O,
258}
259
260impl<E, O> BitFieldGetSubCommand<E, O>
261where
262    E: Into<CommandArg>,
263    O: Into<CommandArg>,
264{
265    #[must_use]
266    pub fn new(encoding: E, offset: O) -> Self {
267        Self { encoding, offset }
268    }
269}
270
271impl<E, O> IntoArgs for BitFieldGetSubCommand<E, O>
272where
273    E: Into<CommandArg>,
274    O: Into<CommandArg>,
275{
276    fn into_args(self, args: CommandArgs) -> CommandArgs {
277        args.arg("GET").arg(self.encoding).arg(self.offset)
278    }
279}
280
281pub enum BitFieldOverflow {
282    Wrap,
283    Sat,
284    Fail,
285}
286
287impl IntoArgs for BitFieldOverflow {
288    fn into_args(self, args: CommandArgs) -> CommandArgs {
289        args.arg(match self {
290            BitFieldOverflow::Wrap => "WRAP",
291            BitFieldOverflow::Sat => "SAT",
292            BitFieldOverflow::Fail => "FAIL",
293        })
294    }
295}
296
297/// Bit operation for the [`bitop`](crate::BitmapCommands::bitop) command.
298pub enum BitOperation {
299    And,
300    Or,
301    Xor,
302    Not,
303}
304
305impl IntoArgs for BitOperation {
306    fn into_args(self, args: CommandArgs) -> CommandArgs {
307        args.arg(match self {
308            BitOperation::And => "AND",
309            BitOperation::Or => "OR",
310            BitOperation::Xor => "XOR",
311            BitOperation::Not => "NOT",
312        })
313    }
314}