yo_kv/bitmaps.rs
1//! The bitmap commands, which are string commands wearing a different hat.
2//!
3//! A bitmap in Redis is a string, and that is not an implementation detail a
4//! caller can ignore: `SET k "A"` then `GETBIT k 1` answers 1, because `A` is
5//! `0x41` and the second bit from the top of that byte is set. So there is no
6//! bitmap type here either, and everything in this file works on the same
7//! string records [`strings`](crate::strings) writes. The kernels are in
8//! [`bits`]; this is where a key turns into bytes, where a write
9//! is allowed to grow a value and where Redis's edges live.
10//!
11//! Three of those edges are worth stating up front, because all three have been
12//! measured on a real server rather than reasoned about.
13//!
14//! A write always leaves the value `raw`. `SET n 12345` reports `int` and a
15//! `SETBIT n 0 0` that changes nothing at all still reports `raw` afterwards,
16//! because Redis unshares the object before it looks at a bit. A read does not:
17//! `GETBIT n 3` on the same key leaves it `int`. That is why the in place fast
18//! path below only takes a record that is already raw.
19//!
20//! A write creates the key and pads it with zero bytes, even when the bit being
21//! written is zero and the byte is past the end. `SETBIT nokey 0 0` on an empty
22//! database leaves a one byte string behind.
23//!
24//! A `BITFIELD` is checked all the way through before any of it runs, so a bad
25//! field type in the last subcommand leaves the key untouched and, if it was not
26//! there, uncreated. That ordering is the wire layer's to keep, and it is why
27//! [`Keyspace::bitfield`] takes a list of already parsed subcommands rather than
28//! words to parse.
29
30use crate::bits::{self, Field, Op, Overflow};
31use crate::keyspace::Keyspace;
32use crate::strings::{STRING_MAX, check_len};
33use crate::value::{self, Kind, Str};
34use yo_common::num::{self, DIGITS_MAX};
35use yo_common::{Code, Error, Result};
36use yo_index::RawMap;
37
38/// What Redis says about an offset that is not a number or is off the end.
39const BAD_BIT_OFFSET: &str = "bit offset is not an integer or out of range";
40/// What Redis says when a write would make a string too long.
41const TOO_LONG: &str = "string exceeds maximum allowed size (proto-max-bulk-len)";
42
43/// The highest bit `SETBIT` and `GETBIT` take.
44///
45/// It is 4 Gi bits, which is 512 MiB, which is Redis's string ceiling. Ours is a
46/// segment and smaller than that, so a write between the two limits is refused
47/// by the length check with the "string exceeds maximum allowed size" sentence
48/// rather than by this one. Both are Redis's own sentences and the boundary
49/// between them is where we diverge.
50pub const BIT_OFFSET_MAX: u64 = 4 * 1024 * 1024 * 1024 - 1;
51
52/// Whether a range's two ends count bytes or bits.
53///
54/// `BITCOUNT` and `BITPOS` both take an optional `BYTE` or `BIT` word after
55/// their two indexes, and both default to `BYTE`. The word is only allowed once
56/// both indexes are there: `BITPOS k 0 5 BIT` is not a bit ranged search from
57/// bit five, it is an error, because `BIT` is read as the end index.
58#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
59pub enum Unit {
60 /// Indexes count bytes. The default.
61 #[default]
62 Byte,
63 /// Indexes count bits.
64 Bit,
65}
66
67/// One `BITFIELD` subcommand.
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69pub struct Sub {
70 /// Which of the three it is, and what it carries.
71 pub op: SubOp,
72 /// The width and signedness of the field.
73 pub field: Field,
74 /// Where the field starts, in bits.
75 ///
76 /// The `#n` form a client can send is `n` times the width, and multiplying
77 /// it out is the wire layer's job.
78 pub at: u64,
79 /// What to do if the value will not fit. Ignored by `GET`.
80 pub on: Overflow,
81}
82
83/// The three things a `BITFIELD` subcommand does.
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85pub enum SubOp {
86 /// `GET`, which never writes and never creates the key.
87 Get,
88 /// `SET`, answering the value that was there before.
89 Set(i64),
90 /// `INCRBY`, answering the value afterwards.
91 Incr(i64),
92}
93
94impl SubOp {
95 /// Whether this one writes, which is what decides how far the value grows.
96 const fn writes(self) -> bool {
97 !matches!(self, SubOp::Get)
98 }
99}
100
101impl Keyspace {
102 /// `GETBIT key offset`.
103 ///
104 /// A missing key, and any offset past the end of a key that is there, read
105 /// as zero. Nothing is created and nothing is re-encoded.
106 pub fn getbit(&mut self, key: &[u8], offset: u64) -> Result<bool> {
107 if offset > BIT_OFFSET_MAX {
108 return Err(Error::new(Code::Invalid, BAD_BIT_OFFSET));
109 }
110 self.reap(key);
111 self.string_only(key)?;
112 // A bitmap is a string, so it can have been demoted like any other, and
113 // the bit being asked about is somewhere in it. Warmed rather than
114 // thawed: reading a bit out of a cold bitmap is a read like any other
115 // and the doorkeeper decides whether it earns its way back.
116 self.warm(key)?;
117 let mut digits = [0u8; DIGITS_MAX];
118 let bytes = self.bitmap(key, &mut digits);
119 let byte = (offset / 8) as usize;
120 Ok(bytes.get(byte).is_some_and(|b| b & mask(offset) != 0))
121 }
122
123 /// `SETBIT key offset value`, answering the bit that was there before.
124 ///
125 /// The value grows to hold the offset, padded with zero bytes, and keeps
126 /// whatever deadline it had. A key that was not there is created, even when
127 /// the bit being written is zero.
128 pub fn setbit(&mut self, key: &[u8], offset: u64, bit: bool) -> Result<bool> {
129 if offset > BIT_OFFSET_MAX {
130 return Err(Error::new(Code::Invalid, BAD_BIT_OFFSET));
131 }
132 let byte = (offset / 8) as usize;
133 check_len(key, byte + 1)?;
134 self.thaw(key)?;
135 let now = self.clock.now_ms();
136 let hash = RawMap::hash_of(key);
137
138 // The fast path: the key is there, it is raw already, and the byte is
139 // inside it, so the write is one probe and one byte. This is the shape a
140 // bitmap is used in, a fixed size map of ids that was sized once and is
141 // written to for the rest of its life, and it is the only path that does
142 // not touch the arena. The kind check sits inside the probe for the
143 // reason `INCR`'s does: the byte holding it is already loaded here.
144 let mut dead = false;
145 if let Some(rec) = self.map.value_mut_hashed(hash, key) {
146 if value::kind(rec) != Kind::String {
147 return Err(crate::keyspace::wrong_type());
148 }
149 if value::is_expired(rec, now) {
150 dead = true;
151 } else if let Some(b) = value::raw_in_place(rec).and_then(|it| it.get_mut(byte)) {
152 let had = *b & mask(offset) != 0;
153 if bit {
154 *b |= mask(offset);
155 } else {
156 *b &= !mask(offset);
157 }
158 return Ok(had);
159 }
160 }
161 if dead {
162 self.drop_key(key);
163 self.expired += 1;
164 }
165
166 // The slow path, which is every first write to a key and every write
167 // that makes it longer. Through the one scratch buffer, the way `APPEND`
168 // and `SETRANGE` go, since the old bytes are needed in hand while
169 // `store_raw` wants the database.
170 let mut bytes = std::mem::take(&mut self.scratch);
171 bytes.clear();
172 let deadline = match self.map.get(key) {
173 Some(rec) => {
174 value::read(rec).write_to(&mut bytes);
175 value::expire_at(rec)
176 }
177 None => None,
178 };
179 if bytes.len() <= byte {
180 bytes.resize(byte + 1, 0);
181 }
182 let had = bytes[byte] & mask(offset) != 0;
183 if bit {
184 bytes[byte] |= mask(offset);
185 } else {
186 bytes[byte] &= !mask(offset);
187 }
188 self.store_raw(key, &bytes, deadline);
189 self.scratch = bytes;
190 Ok(had)
191 }
192
193 /// `BITCOUNT key [start end [BYTE | BIT]]`.
194 ///
195 /// A missing key, an empty string and a range that ends before it starts all
196 /// answer zero. The two indexes may be negative, counting from the end, and
197 /// both are clamped rather than refused.
198 pub fn bitcount(&mut self, key: &[u8], range: Option<(i64, i64, Unit)>) -> Result<u64> {
199 self.reap(key);
200 self.string_only(key)?;
201 self.warm(key)?;
202 let mut digits = [0u8; DIGITS_MAX];
203 let bytes = self.bitmap(key, &mut digits);
204 let Some((start, end, unit)) = range else {
205 return Ok(bits::count(bytes));
206 };
207 match window(bytes.len(), start, end, unit) {
208 Some((from, to)) => Ok(bits::count_range(bytes, from, to)),
209 None => Ok(0),
210 }
211 }
212
213 /// `BITPOS key bit [start [end [BYTE | BIT]]]`.
214 ///
215 /// Answers minus one when there is no such bit, with the one exception Redis
216 /// carved out: looking for a zero with no end index given, over a range that
217 /// is all ones, answers the first bit past the end of the string. The idea is
218 /// that a string is followed by an infinity of zeros unless the caller said
219 /// where to stop. Giving an explicit end turns that back into minus one, and
220 /// so does asking about a range that is empty once it has been clamped.
221 pub fn bitpos(
222 &mut self,
223 key: &[u8],
224 bit: bool,
225 start: Option<i64>,
226 end: Option<i64>,
227 unit: Unit,
228 ) -> Result<i64> {
229 self.reap(key);
230 self.string_only(key)?;
231 self.warm(key)?;
232 let here = self.map.get(key).is_some();
233 let mut digits = [0u8; DIGITS_MAX];
234 let bytes = self.bitmap(key, &mut digits);
235 if bytes.is_empty() {
236 // A missing key is all zeros, so a zero is at bit nought and a one is
237 // nowhere. An empty string that is really there answers minus one
238 // either way, since there is no bit nought to point at.
239 return Ok(if !bit && !here { 0 } else { -1 });
240 }
241 let all = bytes.len() as u64 * 8;
242 let (from, to) = match (start, end) {
243 (None, _) => (0, all),
244 (Some(s), None) => match window(bytes.len(), s, -1, unit) {
245 Some(r) => r,
246 None => return Ok(-1),
247 },
248 (Some(s), Some(e)) => match window(bytes.len(), s, e, unit) {
249 Some(r) => r,
250 None => return Ok(-1),
251 },
252 };
253 match bits::find(bytes, bit, from, to) {
254 Some(at) => Ok(at as i64),
255 None if !bit && end.is_none() => Ok(all as i64),
256 None => Ok(-1),
257 }
258 }
259
260 /// `BITOP op dest src [src ...]`, answering the length of the result.
261 ///
262 /// A result with no bytes in it deletes the destination, and any other
263 /// result creates it whatever it holds, so a `BITOP AND` over sources that
264 /// share nothing leaves a destination full of zero bytes rather than no
265 /// destination at all. Sources that are shorter than the longest read as
266 /// zeros past their end, and a source that is not there reads as empty.
267 ///
268 /// # Panics
269 ///
270 /// If `srcs` is empty, or holds more than one key for [`Op::Not`]. Both are
271 /// refused with a message on the wire before this is called.
272 pub fn bitop<'k, I>(&mut self, op: Op, dest: &[u8], srcs: I) -> Result<usize>
273 where
274 I: Iterator<Item = &'k [u8]> + Clone,
275 {
276 for src in srcs.clone() {
277 self.reap(src);
278 self.string_only(src)?;
279 // Every source at once, so every one of them has to be in memory
280 // rather than in the one buffer a fault serves out of. `BITOP` over
281 // demoted sources brings them back, which is also what a client
282 // running it in a loop wants.
283 self.thaw(src)?;
284 }
285 // The sources have to be copied out before the destination can be
286 // written, since they are borrowed from the map and the write wants the
287 // database back. They go end to end into the scratch buffer with their
288 // boundaries in `rows`, and the result goes on the end of the same
289 // buffer, so a `BITOP` over any number of sources is one buffer and no
290 // allocation past whatever growing that buffer costs.
291 let mut flat = std::mem::take(&mut self.scratch);
292 let mut ends = std::mem::take(&mut self.rows);
293 flat.clear();
294 ends.clear();
295 let mut digits = [0u8; DIGITS_MAX];
296 for src in srcs.clone() {
297 let bytes = self.bitmap(src, &mut digits);
298 flat.extend_from_slice(bytes);
299 ends.push(flat.len());
300 }
301 // As long as the longest source, `NOT` included: complementing a source
302 // cannot make it longer, and there is only ever the one of them.
303 let len = bits::width(parts(&flat, &ends));
304 if len > STRING_MAX {
305 self.scratch = flat;
306 self.rows = ends;
307 return Err(Error::new(Code::Invalid, TOO_LONG));
308 }
309
310 let split = flat.len();
311 flat.resize(split + len, 0);
312 // The sources and the destination are in the same buffer, so they have
313 // to be split apart before one can be read while the other is written.
314 let (read, write) = flat.split_at_mut(split);
315 bits::combine(op, parts(read, &ends), write);
316
317 let outcome = if len == 0 {
318 self.del(dest);
319 Ok(0)
320 } else {
321 self.reap(dest);
322 match self.string_only(dest) {
323 Ok(()) => {
324 self.store_raw(dest, &flat[split..], None);
325 Ok(len)
326 }
327 Err(e) => Err(e),
328 }
329 };
330 self.scratch = flat;
331 self.rows = ends;
332 outcome
333 }
334
335 /// `BITFIELD key [subcommand ...]`, answering one reply per subcommand.
336 ///
337 /// A `None` in the answers is the nil an `OVERFLOW FAIL` subcommand gives
338 /// when its value would not fit; that one does not write and the ones around
339 /// it still do. The subcommands are expected to have been checked already,
340 /// which is what makes it safe for this to be the point of no return.
341 ///
342 /// The value grows once, before anything runs, to hold the last bit any
343 /// writing subcommand touches. That happens even if every one of those
344 /// writes then fails its overflow check, which is Redis's behaviour and
345 /// falls out of it growing the string before it looks at the values.
346 pub fn bitfield(&mut self, key: &[u8], ops: &[Sub]) -> Result<Vec<Option<i64>>> {
347 let grow = ops.iter().filter(|s| s.op.writes()).map(reach).max();
348 self.bitfield_with(key, grow, |bytes| {
349 ops.iter().map(|&sub| apply(bytes, sub)).collect()
350 })
351 }
352
353 /// `BITFIELD`, with the subcommands run against the value in place.
354 ///
355 /// This is the form the wire uses. It hands over the bytes and lets the
356 /// caller walk its own arguments a second time, calling [`apply`] on each,
357 /// which is what lets a `BITFIELD` with two hundred subcommands write two
358 /// hundred replies without a list of them existing anywhere.
359 ///
360 /// `grow` is how many bytes the value has to reach, which is the last byte
361 /// any writing subcommand touches, and `None` for a call that only reads.
362 /// The growing happens once and before anything runs, even if every one of
363 /// those writes then fails its overflow check, because that is what Redis
364 /// does: it makes the string long enough while it is looking up the key and
365 /// only then starts on the values. A call that only reads stores nothing,
366 /// which is what keeps `BITFIELD k GET u8 0` from turning an `embstr` into a
367 /// `raw`.
368 pub fn bitfield_with<T>(
369 &mut self,
370 key: &[u8],
371 grow: Option<usize>,
372 run: impl FnOnce(&mut [u8]) -> T,
373 ) -> Result<T> {
374 self.reap(key);
375 self.string_only(key)?;
376 // Every path here materialises the value and most of them write it
377 // back, so this thaws rather than asking the doorkeeper about a value
378 // that is going to be resident when the command ends anyway.
379 self.thaw(key)?;
380 let need = grow.unwrap_or(0);
381 check_len(key, need)?;
382
383 // Every path materialises the value, including the read only one, so
384 // that an int encoded key reads as the digits it prints as.
385 let mut bytes = std::mem::take(&mut self.scratch);
386 bytes.clear();
387 let deadline = match self.map.get(key) {
388 Some(rec) => {
389 value::read(rec).write_to(&mut bytes);
390 value::expire_at(rec)
391 }
392 None => None,
393 };
394 if bytes.len() < need {
395 bytes.resize(need, 0);
396 }
397 let out = run(&mut bytes);
398 if grow.is_some() {
399 self.store_raw(key, &bytes, deadline);
400 }
401 self.scratch = bytes;
402 Ok(out)
403 }
404
405 /// The bytes of a string key, as the bit commands want to see them.
406 ///
407 /// A missing key is empty, which is what every one of these commands treats
408 /// it as. An int encoded key is the digits it would print as, because that
409 /// is the string it is: `SET n 65` then `GETBIT n 1` is asking about the
410 /// character `6`. The digits are written into the caller's buffer so that the
411 /// ordinary case, a raw string, is still a borrow and not a copy.
412 fn bitmap<'a>(&'a self, key: &[u8], digits: &'a mut [u8; DIGITS_MAX]) -> &'a [u8] {
413 match self.peek(key) {
414 None => &[],
415 Some(Str::Bytes(b)) => b,
416 Some(Str::Int(n)) => num::i64_digits(digits, n),
417 }
418 }
419}
420
421/// The sources of a `BITOP`, out of the buffer they were copied into.
422///
423/// The boundaries are the end of each source, so the first one starts at nought
424/// and each of the others starts where the one before it ended. Written as a
425/// zip over two views of the same list rather than as a running offset, because
426/// the iterator has to be cloneable and a clone of a running offset would carry
427/// whatever the original had reached.
428fn parts<'a>(flat: &'a [u8], ends: &'a [usize]) -> impl Iterator<Item = &'a [u8]> + Clone {
429 std::iter::once(0)
430 .chain(ends.iter().copied())
431 .zip(ends.iter().copied())
432 .map(|(from, to)| &flat[from..to])
433}
434
435/// Run one subcommand against a value, answering what the client is owed.
436///
437/// `None` is the nil an `OVERFLOW FAIL` subcommand gives when its value would
438/// not fit; that one writes nothing and the ones around it still do. A `SET`
439/// answers what was there before and an `INCRBY` answers what is there now,
440/// which is not symmetry anybody would have chosen but is what Redis does.
441///
442/// The bytes have to be long enough already, which is [`reach`]'s job.
443#[must_use]
444pub fn apply(bytes: &mut [u8], sub: Sub) -> Option<i64> {
445 let had = bits::get(bytes, sub.at, sub.field);
446 match sub.op {
447 SubOp::Get => Some(had),
448 SubOp::Set(val) => bits::setting(sub.field, val, sub.on).map(|next| {
449 bits::set(bytes, sub.at, sub.field, next);
450 had
451 }),
452 SubOp::Incr(by) => bits::adding(sub.field, had, by, sub.on).inspect(|&next| {
453 bits::set(bytes, sub.at, sub.field, next);
454 }),
455 }
456}
457
458/// How many bytes a value needs before `sub` can be written into it.
459#[must_use]
460pub const fn reach(sub: &Sub) -> usize {
461 (sub.field.last_bit(sub.at) / 8 + 1) as usize
462}
463
464/// The bit `offset` names inside its byte.
465///
466/// Bit zero is the top bit, which is the convention all of these commands use.
467#[inline]
468const fn mask(offset: u64) -> u8 {
469 0x80 >> (offset % 8)
470}
471
472/// A start and end index turned into a half open range of bits.
473///
474/// `None` for a range that holds nothing, which is what an empty value, an
475/// out of range start or a backwards range all come to. Negative indexes count
476/// from the end and both ends are clamped, so `BITCOUNT k -100 100` over a three
477/// byte string is the whole string rather than an error.
478fn window(len: usize, start: i64, end: i64, unit: Unit) -> Option<(u64, u64)> {
479 let items = match unit {
480 Unit::Byte => len as i64,
481 Unit::Bit => (len as i64).checked_mul(8)?,
482 };
483 if items == 0 {
484 return None;
485 }
486 // The two ends are not clamped the same way, and the difference is what
487 // makes `BITCOUNT k 10 20` over a three byte string answer zero rather than
488 // counting its last byte. A negative index counts back from the end and
489 // stops at the front, the end index is pulled back to the last item, and a
490 // start past the last item is left where it is so that the range comes out
491 // backwards and is thrown away below.
492 let back = |i: i64| if i < 0 { (items + i).max(0) } else { i };
493 let (from, to) = (back(start), back(end).min(items - 1));
494 if from > to {
495 return None;
496 }
497 let scale = match unit {
498 Unit::Byte => 8,
499 Unit::Bit => 1,
500 };
501 Some(((from * scale) as u64, ((to + 1) * scale) as u64))
502}
503
504/// The largest value a bit range can name, for a caller checking its own limit.
505///
506/// Nothing here uses it; it is the ceiling [`STRING_MAX`] imposes expressed in
507/// bits, which is what a client asking "how big can this bitmap be" wants.
508#[must_use]
509pub const fn max_bits() -> u64 {
510 STRING_MAX as u64 * 8
511}
512
513#[cfg(test)]
514mod tests {
515 use super::*;
516 use crate::keyspace::Keyspace;
517
518 fn db() -> Keyspace {
519 Keyspace::new()
520 }
521
522 /// The source list `bitop` takes, out of the keys a test wants to name.
523 fn keys<'k>(names: &'k [&'k [u8]]) -> impl Iterator<Item = &'k [u8]> + Clone {
524 names.iter().copied()
525 }
526
527 #[test]
528 fn a_bit_is_set_and_read_back() {
529 let mut db = db();
530 assert!(!db.setbit(b"k", 7, true).expect("a bit"));
531 assert!(db.getbit(b"k", 7).expect("a bit"));
532 assert!(!db.getbit(b"k", 6).expect("a bit"));
533 assert_eq!(db.strlen(b"k").expect("a length"), 1);
534 assert_eq!(
535 db.get(b"k").expect("a value").expect("bytes").to_vec(),
536 b"\x01"
537 );
538 // The answer is what was there, not what is there now.
539 assert!(db.setbit(b"k", 7, false).expect("a bit"));
540 assert!(!db.setbit(b"k", 7, false).expect("a bit"));
541 }
542
543 #[test]
544 fn a_write_creates_and_pads_even_when_the_bit_is_zero() {
545 let mut db = db();
546 assert!(!db.setbit(b"k", 0, false).expect("a bit"));
547 assert!(db.exists(b"k"));
548 assert_eq!(db.strlen(b"k").expect("a length"), 1);
549 db.setbit(b"k", 40, true).expect("a bit");
550 assert_eq!(db.strlen(b"k").expect("a length"), 6);
551 }
552
553 #[test]
554 fn a_write_leaves_the_value_raw_and_a_read_does_not() {
555 let mut db = db();
556 db.set_plain(b"n", b"12345").expect("a set");
557 assert_eq!(db.encoding(b"n"), Some(value::Encoding::Int));
558 // Reading a bit out of an int is reading a bit out of its digits.
559 assert!(db.getbit(b"n", 3).expect("a bit"));
560 assert_eq!(db.encoding(b"n"), Some(value::Encoding::Int));
561 // Writing one, even a write that changes nothing, does not leave an int.
562 assert!(!db.setbit(b"n", 0, false).expect("a bit"));
563 assert_eq!(db.encoding(b"n"), Some(value::Encoding::Raw));
564 assert_eq!(
565 db.get(b"n").expect("a value").expect("bytes").to_vec(),
566 b"12345"
567 );
568 }
569
570 #[test]
571 fn a_write_keeps_the_deadline() {
572 let mut db = db();
573 db.setex(b"k", 100, b"abc").expect("a set");
574 db.setbit(b"k", 40, true).expect("a bit");
575 assert_eq!(db.strlen(b"k").expect("a length"), 6);
576 assert!(db.expire_at(b"k").is_some());
577 // And so does the fast path, which does not go near the deadline.
578 db.setbit(b"k", 1, true).expect("a bit");
579 assert!(db.expire_at(b"k").is_some());
580 }
581
582 #[test]
583 fn counting_takes_the_ranges_a_real_server_takes() {
584 let mut db = db();
585 db.set_plain(b"k", b"foobar").expect("a set");
586 let count = |db: &mut Keyspace, r| db.bitcount(b"k", r).expect("a count");
587 assert_eq!(count(&mut db, None), 26);
588 assert_eq!(count(&mut db, Some((0, 0, Unit::Byte))), 4);
589 assert_eq!(count(&mut db, Some((1, 1, Unit::Byte))), 6);
590 assert_eq!(count(&mut db, Some((0, -5, Unit::Byte))), 10);
591 assert_eq!(count(&mut db, Some((5, 30, Unit::Bit))), 17);
592 // Redis's own documentation says 22 for this one. A real 8.10.1 says 25,
593 // and 25 is what counting the first 44 bits of `foobar` by hand gives,
594 // so the documentation is wrong and this is not a divergence.
595 assert_eq!(count(&mut db, Some((0, -5, Unit::Bit))), 25);
596 // Clamped at both ends, empty when it is backwards.
597 assert_eq!(count(&mut db, Some((-100, 100, Unit::Byte))), 26);
598 assert_eq!(count(&mut db, Some((2, 1, Unit::Byte))), 0);
599 assert_eq!(count(&mut db, Some((5, 3, Unit::Bit))), 0);
600 // A start past the end is nothing, not the whole string.
601 assert_eq!(count(&mut db, Some((10, 20, Unit::Byte))), 0);
602 assert_eq!(db.bitcount(b"gone", None).expect("a count"), 0);
603 }
604
605 #[test]
606 fn searching_takes_the_ranges_a_real_server_takes() {
607 let mut db = db();
608 db.set_plain(b"ones", b"\xff\xff\xff").expect("a set");
609 db.set_plain(b"mix", b"\x00\xff\x00").expect("a set");
610 let pos = |db: &mut Keyspace, k: &[u8], bit, s, e| {
611 db.bitpos(k, bit, s, e, Unit::Byte).expect("a position")
612 };
613 assert_eq!(pos(&mut db, b"mix", true, None, None), 8);
614 assert_eq!(pos(&mut db, b"mix", false, None, None), 0);
615 assert_eq!(pos(&mut db, b"mix", true, Some(2), None), -1);
616 assert_eq!(pos(&mut db, b"mix", true, Some(-1), Some(-1)), -1);
617 assert_eq!(pos(&mut db, b"mix", false, Some(-100), None), 0);
618 // The one exception: no end given, all ones, so the answer is the first
619 // bit past the end of the string.
620 assert_eq!(pos(&mut db, b"ones", false, None, None), 24);
621 assert_eq!(pos(&mut db, b"ones", false, Some(-1), None), 24);
622 // An explicit end takes that away again.
623 assert_eq!(pos(&mut db, b"ones", false, Some(0), Some(-1)), -1);
624 assert_eq!(pos(&mut db, b"ones", false, Some(0), Some(100)), -1);
625 // And so does a range that is empty once it has been clamped.
626 assert_eq!(pos(&mut db, b"ones", false, Some(10), None), -1);
627 assert_eq!(pos(&mut db, b"ones", false, Some(3), None), -1);
628 assert_eq!(pos(&mut db, b"ones", true, Some(10), None), -1);
629 assert_eq!(pos(&mut db, b"ones", false, Some(2), Some(1)), -1);
630 assert_eq!(
631 db.bitpos(b"ones", false, Some(5), Some(20), Unit::Bit)
632 .expect("a position"),
633 -1
634 );
635 }
636
637 #[test]
638 fn searching_an_absent_or_empty_key() {
639 let mut db = db();
640 let pos = |db: &mut Keyspace, k: &[u8], bit| {
641 db.bitpos(k, bit, None, None, Unit::Byte)
642 .expect("a position")
643 };
644 // A key that is not there is all zeros, so a zero is at the front.
645 assert_eq!(pos(&mut db, b"gone", false), 0);
646 assert_eq!(pos(&mut db, b"gone", true), -1);
647 // A key that is there and empty has no bits at all.
648 db.set_plain(b"empty", b"").expect("a set");
649 assert_eq!(pos(&mut db, b"empty", false), -1);
650 assert_eq!(pos(&mut db, b"empty", true), -1);
651 assert_eq!(
652 db.bitcount(b"empty", Some((0, -1, Unit::Byte)))
653 .expect("a count"),
654 0
655 );
656 }
657
658 #[test]
659 fn combining_writes_a_destination_and_deletes_an_empty_one() {
660 let mut db = db();
661 db.set_plain(b"a", b"\xf0\x0f\xff").expect("a set");
662 db.set_plain(b"b", b"\xff\x00").expect("a set");
663 let n = db
664 .bitop(Op::And, b"d", keys(&[b"a", b"b"]))
665 .expect("a length");
666 assert_eq!(n, 3);
667 assert_eq!(
668 db.get(b"d").expect("a value").expect("bytes").to_vec(),
669 b"\xf0\x00\x00"
670 );
671 // A destination full of nothing is still a destination.
672 db.set_plain(b"z", b"\x00\x00").expect("a set");
673 let n = db
674 .bitop(Op::And, b"d", keys(&[b"a", b"z"]))
675 .expect("a length");
676 assert_eq!(n, 3);
677 assert!(db.exists(b"d"));
678 // Sources that are all missing take the destination with them.
679 let n = db
680 .bitop(Op::Or, b"d", keys(&[b"no1", b"no2"]))
681 .expect("a length");
682 assert_eq!(n, 0);
683 assert!(!db.exists(b"d"));
684 }
685
686 #[test]
687 fn combining_reads_an_int_key_as_its_digits() {
688 let mut db = db();
689 db.set_plain(b"n", b"12345").expect("a set");
690 db.bitop(Op::Or, b"d", keys(&[b"n"])).expect("a length");
691 assert_eq!(
692 db.get(b"d").expect("a value").expect("bytes").to_vec(),
693 b"12345"
694 );
695 }
696
697 #[test]
698 fn a_field_is_read_written_and_incremented() {
699 let mut db = db();
700 let u8f = Field::new(false, 8).expect("a width");
701 let sub = |op, at| Sub {
702 op,
703 field: u8f,
704 at,
705 on: Overflow::Wrap,
706 };
707 let out = db
708 .bitfield(b"k", &[sub(SubOp::Set(255), 0), sub(SubOp::Get, 0)])
709 .expect("replies");
710 assert_eq!(out, vec![Some(0), Some(255)]);
711 assert_eq!(db.strlen(b"k").expect("a length"), 1);
712
713 let out = db
714 .bitfield(b"k", &[sub(SubOp::Incr(10), 0)])
715 .expect("replies");
716 assert_eq!(out, vec![Some(9)], "wrapped round");
717
718 // A failing write answers nothing and leaves the field alone, and the
719 // subcommands around it still run.
720 let fail = Sub {
721 on: Overflow::Fail,
722 ..sub(SubOp::Incr(250), 0)
723 };
724 let out = db
725 .bitfield(b"k", &[fail, sub(SubOp::Get, 0)])
726 .expect("replies");
727 assert_eq!(out, vec![None, Some(9)]);
728 }
729
730 #[test]
731 fn a_read_only_bitfield_creates_nothing_and_re_encodes_nothing() {
732 let mut db = db();
733 let f = Field::new(true, 16).expect("a width");
734 let get = Sub {
735 op: SubOp::Get,
736 field: f,
737 at: 0,
738 on: Overflow::Wrap,
739 };
740 assert_eq!(
741 db.bitfield(b"gone", &[get]).expect("replies"),
742 vec![Some(0)]
743 );
744 assert!(!db.exists(b"gone"));
745
746 db.set_plain(b"s", b"hello").expect("a set");
747 assert_eq!(db.encoding(b"s"), Some(value::Encoding::Embstr));
748 db.bitfield(b"s", &[get]).expect("replies");
749 assert_eq!(
750 db.encoding(b"s"),
751 Some(value::Encoding::Embstr),
752 "still short"
753 );
754 }
755
756 #[test]
757 fn a_write_grows_the_value_even_when_every_write_fails() {
758 let mut db = db();
759 let f = Field::new(false, 8).expect("a width");
760 let sub = Sub {
761 op: SubOp::Set(300),
762 field: f,
763 at: 64,
764 on: Overflow::Fail,
765 };
766 assert_eq!(db.bitfield(b"k", &[sub]).expect("replies"), vec![None]);
767 assert_eq!(db.strlen(b"k").expect("a length"), 9);
768 }
769
770 #[test]
771 fn a_bit_command_on_the_wrong_type_says_so() {
772 let mut db = db();
773 let member: &[u8] = b"x";
774 db.sadd(b"s", std::iter::once(member)).expect("a member");
775 assert!(db.getbit(b"s", 0).is_err());
776 assert!(db.setbit(b"s", 0, true).is_err());
777 assert!(db.bitcount(b"s", None).is_err());
778 assert!(db.bitpos(b"s", true, None, None, Unit::Byte).is_err());
779 assert!(db.bitop(Op::Or, b"d", keys(&[b"s"])).is_err());
780 let f = Field::new(false, 8).expect("a width");
781 let sub = Sub {
782 op: SubOp::Get,
783 field: f,
784 at: 0,
785 on: Overflow::Wrap,
786 };
787 assert!(db.bitfield(b"s", &[sub]).is_err());
788 }
789
790 #[test]
791 fn an_offset_past_the_end_of_the_world_is_refused() {
792 let mut db = db();
793 assert!(db.setbit(b"k", BIT_OFFSET_MAX + 1, true).is_err());
794 assert!(db.getbit(b"k", BIT_OFFSET_MAX + 1).is_err());
795 // And one inside Redis's limit but outside ours is refused too, with the
796 // other sentence. This is the divergence [`STRING_MAX`] is about.
797 assert!(db.setbit(b"k", BIT_OFFSET_MAX, true).is_err());
798 assert!(max_bits() < BIT_OFFSET_MAX);
799 }
800}