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}