rustis/commands/
bitmap_commands.rs

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