rustis/commands/
bitmap_commands.rs

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