yo/sets.rs
1//! Sets, from the embedded side.
2//!
3//! The same store `SADD` off a socket reaches (Y23), through two doors. [`Sets`]
4//! is the keyspace shape, one method per Redis command with the key as the first
5//! argument, which is what a program porting off a Redis client wants. [`Set`] is
6//! one key with a handle around it, which is what a program that was never going
7//! to use Redis wants: a set is a set, and the name of it gets spelled once
8//! rather than at every call site.
9//!
10//! A [`Set`] holds the [`Sets`] it goes through rather than building one per
11//! call, so reaching a set by its handle costs the key it already had and
12//! nothing else. There is no door here that is the slow one.
13//!
14//! # Owned or borrowed, per call
15//!
16//! Every read that hands back members comes in two forms. [`Set::members`]
17//! allocates a `Vec` per member, which is what most code wants and what every
18//! other embedded database gives you. [`Set::for_each`] hands each member over
19//! where it lies and allocates nothing, which is Y29's rule that zero copy is
20//! available and never mandatory.
21//!
22//! The difference is not decoration. A set stored as integers holds them as
23//! integers, so walking a million member set with `members` formats a million
24//! numbers into a million `Vec`s, and walking it with `for_each` formats none of
25//! them unless the closure asks. That is why the borrowed form hands over a
26//! [`Member`] and not a `&[u8]`: the choice of whether to spend the digits is
27//! the caller's.
28
29use yo_common::{Code, Error, Result};
30use yo_kv::Member;
31
32use crate::db::Handle;
33
34/// Every Redis set command, with the key as the first argument.
35///
36/// Keys and members are byte strings the way Redis's are, so anything that is
37/// bytes will do.
38///
39/// ```
40/// let db = yo::open(yo::MEMORY)?;
41/// let sets = db.sets();
42///
43/// sets.add_many("online", &["alice", "bob"])?;
44/// assert!(sets.contains("online", "alice")?);
45/// assert_eq!(sets.len_of("online")?, 2);
46/// # Ok::<(), yo::Error>(())
47/// ```
48#[derive(Clone)]
49pub struct Sets {
50 pub(crate) db: Handle,
51}
52
53impl core::fmt::Debug for Sets {
54 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55 f.debug_struct("Sets").finish_non_exhaustive()
56 }
57}
58
59impl Sets {
60 /// Add one member, and say whether it was new. `SADD`.
61 ///
62 /// The key is created by the first member that goes into it, so there is no
63 /// step before this one.
64 ///
65 /// # Errors
66 ///
67 /// [`Code::WrongType`] when the key holds something that is not a set,
68 /// [`Code::Full`] for a member past the size limit, and [`Code::Invalid`] if
69 /// called from inside a callback that is already holding this database.
70 pub fn add(&self, key: impl AsRef<[u8]>, member: impl AsRef<[u8]>) -> Result<bool> {
71 self.add_many(key, &[member]).map(|n| n == 1)
72 }
73
74 /// Add several members, and say how many were new. `SADD` with a list.
75 ///
76 /// One key lookup for the whole call rather than one per member, which is
77 /// the only reason to prefer it over calling [`Sets::add`] in a loop.
78 ///
79 /// # Errors
80 ///
81 /// As [`Sets::add`]. Nothing is added if any member is too long, because the
82 /// lengths are all checked before the first one goes in.
83 pub fn add_many<M: AsRef<[u8]>>(&self, key: impl AsRef<[u8]>, members: &[M]) -> Result<usize> {
84 self.db.run(|inner| {
85 inner
86 .strings
87 .sadd(key.as_ref(), members.iter().map(AsRef::as_ref))
88 })
89 }
90
91 /// Remove one member, and say whether it was there. `SREM`.
92 ///
93 /// A set that loses its last member loses its key too, which is Redis's rule
94 /// and is why there is no such thing as an empty set in the keyspace.
95 ///
96 /// # Errors
97 ///
98 /// As [`Sets::add`].
99 pub fn remove(&self, key: impl AsRef<[u8]>, member: impl AsRef<[u8]>) -> Result<bool> {
100 self.remove_many(key, &[member]).map(|n| n == 1)
101 }
102
103 /// Remove several members, and say how many were there. `SREM` with a list.
104 ///
105 /// # Errors
106 ///
107 /// As [`Sets::add`].
108 pub fn remove_many<M: AsRef<[u8]>>(
109 &self,
110 key: impl AsRef<[u8]>,
111 members: &[M],
112 ) -> Result<usize> {
113 self.db.run(|inner| {
114 inner
115 .strings
116 .srem(key.as_ref(), members.iter().map(AsRef::as_ref))
117 })
118 }
119
120 /// Whether a member is in the set. `SISMEMBER`.
121 ///
122 /// False for a key that is not there, which is the same answer as an empty
123 /// set and is deliberate: a set nobody has added to and a set somebody
124 /// emptied are the same set.
125 ///
126 /// # Errors
127 ///
128 /// As [`Sets::add`].
129 pub fn contains(&self, key: impl AsRef<[u8]>, member: impl AsRef<[u8]>) -> Result<bool> {
130 self.db
131 .run(|inner| inner.strings.sismember(key.as_ref(), member.as_ref()))
132 }
133
134 /// Whether each of several members is in the set, in the order asked.
135 /// `SMISMEMBER`.
136 ///
137 /// # Errors
138 ///
139 /// As [`Sets::add`].
140 pub fn contains_many<M: AsRef<[u8]>>(
141 &self,
142 key: impl AsRef<[u8]>,
143 members: &[M],
144 ) -> Result<Vec<bool>> {
145 self.db.run(|inner| {
146 inner
147 .strings
148 .smismember(key.as_ref(), members.iter().map(AsRef::as_ref))
149 })
150 }
151
152 /// How many members the set holds, which is zero for a key that is not
153 /// there. `SCARD`.
154 ///
155 /// # Errors
156 ///
157 /// As [`Sets::add`].
158 pub fn len_of(&self, key: impl AsRef<[u8]>) -> Result<usize> {
159 self.db.run(|inner| inner.strings.scard(key.as_ref()))
160 }
161
162 /// Every member, owned. `SMEMBERS`.
163 ///
164 /// `None` for a key that is not there, which a caller who wants to tell that
165 /// apart from an empty answer can use. [`Sets::for_each`] is the same walk
166 /// without the allocations.
167 ///
168 /// # Errors
169 ///
170 /// As [`Sets::add`].
171 pub fn members(&self, key: impl AsRef<[u8]>) -> Result<Option<Vec<Vec<u8>>>> {
172 self.db.run(|inner| {
173 Ok(inner
174 .strings
175 .smembers(key.as_ref())?
176 .map(|it| it.map(|m| m.to_vec()).collect()))
177 })
178 }
179
180 /// Hand every member to `f` where it lies, and say whether the key was
181 /// there.
182 ///
183 /// Nothing is allocated and nothing is formatted. A set stored as integers
184 /// hands over [`Member::Int`] and the digits are only written if the closure
185 /// writes them.
186 ///
187 /// ```
188 /// let db = yo::open(yo::MEMORY)?;
189 /// let sets = db.sets();
190 /// sets.add_many("ids", &["1", "2", "3"])?;
191 ///
192 /// let mut total = 0i64;
193 /// sets.for_each("ids", |m| {
194 /// if let yo::Member::Int(n) = m {
195 /// total += n;
196 /// }
197 /// })?;
198 /// assert_eq!(total, 6);
199 /// # Ok::<(), yo::Error>(())
200 /// ```
201 ///
202 /// # Errors
203 ///
204 /// As [`Sets::add`].
205 pub fn for_each(&self, key: impl AsRef<[u8]>, mut f: impl FnMut(Member<'_>)) -> Result<bool> {
206 self.db.run(|inner| {
207 inner.strings.with_set(key.as_ref(), |set| match set {
208 Some(set) => {
209 for m in set.iter() {
210 f(m);
211 }
212 true
213 }
214 None => false,
215 })
216 })
217 }
218
219 /// Take one member out at random and hand it back. `SPOP`.
220 ///
221 /// `None` for a key that is not there. The key goes when the last member
222 /// does.
223 ///
224 /// # Errors
225 ///
226 /// As [`Sets::add`].
227 pub fn pop(&self, key: impl AsRef<[u8]>) -> Result<Option<Vec<u8>>> {
228 self.db.run(|inner| inner.strings.spop(key.as_ref()))
229 }
230
231 /// Take up to `count` members out at random. `SPOP key count`.
232 ///
233 /// The members are distinct, and fewer than `count` come back when the set
234 /// holds fewer than that.
235 ///
236 /// # Errors
237 ///
238 /// As [`Sets::add`].
239 pub fn pop_n(&self, key: impl AsRef<[u8]>, count: usize) -> Result<Vec<Vec<u8>>> {
240 self.db
241 .run(|inner| inner.strings.spop_n(key.as_ref(), count))
242 }
243
244 /// Draw one member at random and leave it in the set. `SRANDMEMBER`.
245 ///
246 /// # Errors
247 ///
248 /// As [`Sets::add`].
249 pub fn pick(&self, key: impl AsRef<[u8]>) -> Result<Option<Vec<u8>>> {
250 self.db.run(|inner| {
251 inner
252 .strings
253 .srandmember(key.as_ref(), |m| m.map(|m| m.to_vec()))
254 })
255 }
256
257 /// Draw `count` members and leave them in the set. `SRANDMEMBER key count`.
258 ///
259 /// A positive `count` is distinct members, at most as many as the set holds.
260 /// A negative one is the with repeats form, which answers exactly that many
261 /// and can answer more members than the set has. That is one command with
262 /// two meanings in Redis and it stays one method here, because splitting it
263 /// would mean a caller holding a count from somewhere else has to branch on
264 /// its sign before choosing which method to call.
265 ///
266 /// # Errors
267 ///
268 /// As [`Sets::add`].
269 pub fn pick_n(&self, key: impl AsRef<[u8]>, count: i64) -> Result<Vec<Vec<u8>>> {
270 self.db.run(|inner| {
271 let mut out = Vec::new();
272 inner
273 .strings
274 .srandmember_n(key.as_ref(), count, |m| out.push(m.to_vec()))?;
275 Ok(out)
276 })
277 }
278
279 /// Move one member from one set to another, and say whether it moved.
280 /// `SMOVE`.
281 ///
282 /// False when the member was not in `from`, in which case `to` is untouched.
283 ///
284 /// # Errors
285 ///
286 /// As [`Sets::add`], for either key.
287 pub fn move_member(
288 &self,
289 from: impl AsRef<[u8]>,
290 to: impl AsRef<[u8]>,
291 member: impl AsRef<[u8]>,
292 ) -> Result<bool> {
293 self.db.run(|inner| {
294 inner
295 .strings
296 .smove(from.as_ref(), to.as_ref(), member.as_ref())
297 })
298 }
299
300 /// Everything in all of the sets. `SINTER`.
301 ///
302 /// A key that is not there is an empty set, and an empty set anywhere empties
303 /// the intersection.
304 ///
305 /// # Errors
306 ///
307 /// As [`Sets::add`], for any of the keys.
308 pub fn intersect<K: AsRef<[u8]>>(&self, keys: &[K]) -> Result<Vec<Vec<u8>>> {
309 self.collect(keys, Op::Intersect)
310 }
311
312 /// How big the intersection is, without building it. `SINTERCARD`.
313 ///
314 /// A `limit` of zero means no limit. Any other limit stops the walk once it
315 /// has counted that many, which is what makes "do these two sets share at
316 /// least one member" cost one member and not the whole intersection.
317 ///
318 /// # Errors
319 ///
320 /// As [`Sets::add`], for any of the keys.
321 pub fn intersect_len<K: AsRef<[u8]>>(&self, keys: &[K], limit: usize) -> Result<usize> {
322 self.db.run(|inner| {
323 inner
324 .strings
325 .sintercard(keys.iter().map(AsRef::as_ref), limit)
326 })
327 }
328
329 /// Everything in any of the sets. `SUNION`.
330 ///
331 /// A key that is not there contributes nothing and is dropped, which is the
332 /// opposite of what it does to an intersection and is right for the same
333 /// reason: an empty set adds no members and removes none.
334 ///
335 /// # Errors
336 ///
337 /// As [`Sets::add`], for any of the keys.
338 pub fn union<K: AsRef<[u8]>>(&self, keys: &[K]) -> Result<Vec<Vec<u8>>> {
339 self.collect(keys, Op::Union)
340 }
341
342 /// Everything in the first set and in none of the others. `SDIFF`.
343 ///
344 /// # Errors
345 ///
346 /// As [`Sets::add`], for any of the keys.
347 pub fn difference<K: AsRef<[u8]>>(&self, keys: &[K]) -> Result<Vec<Vec<u8>>> {
348 self.collect(keys, Op::Difference)
349 }
350
351 /// Store the intersection under `destination` and say how big it is.
352 /// `SINTERSTORE`.
353 ///
354 /// An empty result removes `destination` rather than leaving an empty set
355 /// there, because there is no such thing as an empty set in the keyspace.
356 ///
357 /// # Errors
358 ///
359 /// As [`Sets::add`], for any of the keys.
360 pub fn intersect_into<K: AsRef<[u8]>>(
361 &self,
362 destination: impl AsRef<[u8]>,
363 keys: &[K],
364 ) -> Result<usize> {
365 self.db.run(|inner| {
366 inner
367 .strings
368 .sinterstore(destination.as_ref(), keys.iter().map(AsRef::as_ref))
369 })
370 }
371
372 /// Store the union under `destination` and say how big it is. `SUNIONSTORE`.
373 ///
374 /// # Errors
375 ///
376 /// As [`Sets::intersect_into`].
377 pub fn union_into<K: AsRef<[u8]>>(
378 &self,
379 destination: impl AsRef<[u8]>,
380 keys: &[K],
381 ) -> Result<usize> {
382 self.db.run(|inner| {
383 inner
384 .strings
385 .sunionstore(destination.as_ref(), keys.iter().map(AsRef::as_ref))
386 })
387 }
388
389 /// Store the difference under `destination` and say how big it is.
390 /// `SDIFFSTORE`.
391 ///
392 /// # Errors
393 ///
394 /// As [`Sets::intersect_into`].
395 pub fn difference_into<K: AsRef<[u8]>>(
396 &self,
397 destination: impl AsRef<[u8]>,
398 keys: &[K],
399 ) -> Result<usize> {
400 self.db.run(|inner| {
401 inner
402 .strings
403 .sdiffstore(destination.as_ref(), keys.iter().map(AsRef::as_ref))
404 })
405 }
406
407 /// The three algebra reads, which differ only in which one they call.
408 ///
409 /// They hand back owned members rather than borrowed ones, and that is not a
410 /// choice made here. An intersection has to compare members that are stored
411 /// three different ways, so by the time one is known to be in the answer it
412 /// has already been written out somewhere. There is nothing left to borrow.
413 fn collect<K: AsRef<[u8]>>(&self, keys: &[K], op: Op) -> Result<Vec<Vec<u8>>> {
414 self.db.run(|inner| {
415 let mut out = Vec::new();
416 let push = |m: &[u8]| out.push(m.to_vec());
417 let keys = keys.iter().map(AsRef::as_ref);
418 match op {
419 Op::Intersect => inner.strings.sinter(keys, 0, push)?,
420 Op::Union => inner.strings.sunion(keys, push)?,
421 Op::Difference => inner.strings.sdiff(keys, push)?,
422 };
423 Ok(out)
424 })
425 }
426}
427
428/// Which of the three set algebra reads [`Sets::collect`] is doing.
429#[derive(Clone, Copy)]
430enum Op {
431 Intersect,
432 Union,
433 Difference,
434}
435
436/// One set, with its key held for you.
437///
438/// This is `15` section 2's shape: the name is spelled where the handle is made
439/// and nowhere else, so a typo is one compile error at one line instead of a
440/// lookup that quietly misses at three call sites.
441///
442/// ```
443/// let db = yo::open(yo::MEMORY)?;
444/// let online = db.set("online");
445///
446/// online.add("alice")?;
447/// online.add("bob")?;
448/// assert!(online.contains("alice")?);
449/// assert_eq!(online.len()?, 2);
450///
451/// online.remove("alice")?;
452/// assert!(!online.contains("alice")?);
453/// # Ok::<(), yo::Error>(())
454/// ```
455#[derive(Clone)]
456pub struct Set {
457 pub(crate) sets: Sets,
458 pub(crate) key: Vec<u8>,
459}
460
461impl core::fmt::Debug for Set {
462 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
463 f.debug_struct("Set")
464 .field("key", &String::from_utf8_lossy(&self.key))
465 .field("len", &self.len().ok())
466 .finish()
467 }
468}
469
470impl Set {
471 /// The key this handle holds.
472 #[must_use]
473 pub fn key(&self) -> &[u8] {
474 &self.key
475 }
476
477 /// Add one member, and say whether it was new. `SADD`.
478 ///
479 /// # Errors
480 ///
481 /// As [`Sets::add`].
482 pub fn add(&self, member: impl AsRef<[u8]>) -> Result<bool> {
483 self.sets.add(&self.key, member)
484 }
485
486 /// Add several members, and say how many were new.
487 ///
488 /// # Errors
489 ///
490 /// As [`Sets::add`].
491 pub fn add_many<M: AsRef<[u8]>>(&self, members: &[M]) -> Result<usize> {
492 self.sets.add_many(&self.key, members)
493 }
494
495 /// Remove one member, and say whether it was there. `SREM`.
496 ///
497 /// # Errors
498 ///
499 /// As [`Sets::add`].
500 pub fn remove(&self, member: impl AsRef<[u8]>) -> Result<bool> {
501 self.sets.remove(&self.key, member)
502 }
503
504 /// Remove several members, and say how many were there.
505 ///
506 /// # Errors
507 ///
508 /// As [`Sets::add`].
509 pub fn remove_many<M: AsRef<[u8]>>(&self, members: &[M]) -> Result<usize> {
510 self.sets.remove_many(&self.key, members)
511 }
512
513 /// Whether a member is in the set. `SISMEMBER`.
514 ///
515 /// # Errors
516 ///
517 /// As [`Sets::add`].
518 pub fn contains(&self, member: impl AsRef<[u8]>) -> Result<bool> {
519 self.sets.contains(&self.key, member)
520 }
521
522 /// Whether each of several members is in the set, in the order asked.
523 /// `SMISMEMBER`.
524 ///
525 /// # Errors
526 ///
527 /// As [`Sets::add`].
528 pub fn contains_many<M: AsRef<[u8]>>(&self, members: &[M]) -> Result<Vec<bool>> {
529 self.sets.contains_many(&self.key, members)
530 }
531
532 /// How many members it holds. `SCARD`.
533 ///
534 /// # Errors
535 ///
536 /// As [`Sets::add`].
537 pub fn len(&self) -> Result<usize> {
538 self.sets.len_of(&self.key)
539 }
540
541 /// Whether it holds nothing, which is also true of a key that is not there.
542 ///
543 /// # Errors
544 ///
545 /// As [`Sets::add`].
546 pub fn is_empty(&self) -> Result<bool> {
547 self.len().map(|n| n == 0)
548 }
549
550 /// Every member, owned. `SMEMBERS`.
551 ///
552 /// An empty `Vec` for a key that is not there. [`Sets::members`] is the
553 /// version that tells the two apart, and this one does not because a handle
554 /// on a key that was never written to is the ordinary way to start.
555 ///
556 /// # Errors
557 ///
558 /// As [`Sets::add`].
559 pub fn members(&self) -> Result<Vec<Vec<u8>>> {
560 Ok(self.sets.members(&self.key)?.unwrap_or_default())
561 }
562
563 /// Hand every member to `f` where it lies, allocating nothing.
564 ///
565 /// # Errors
566 ///
567 /// As [`Sets::add`].
568 pub fn for_each(&self, f: impl FnMut(Member<'_>)) -> Result<()> {
569 self.sets.for_each(&self.key, f).map(|_| ())
570 }
571
572 /// Take one member out at random. `SPOP`.
573 ///
574 /// # Errors
575 ///
576 /// As [`Sets::add`].
577 pub fn pop(&self) -> Result<Option<Vec<u8>>> {
578 self.sets.pop(&self.key)
579 }
580
581 /// Take up to `count` distinct members out at random. `SPOP key count`.
582 ///
583 /// # Errors
584 ///
585 /// As [`Sets::add`].
586 pub fn pop_n(&self, count: usize) -> Result<Vec<Vec<u8>>> {
587 self.sets.pop_n(&self.key, count)
588 }
589
590 /// Draw one member and leave it in the set. `SRANDMEMBER`.
591 ///
592 /// # Errors
593 ///
594 /// As [`Sets::add`].
595 pub fn pick(&self) -> Result<Option<Vec<u8>>> {
596 self.sets.pick(&self.key)
597 }
598
599 /// Draw `count` members and leave them in the set. `SRANDMEMBER key count`.
600 ///
601 /// # Errors
602 ///
603 /// As [`Sets::add`].
604 pub fn pick_n(&self, count: i64) -> Result<Vec<Vec<u8>>> {
605 self.sets.pick_n(&self.key, count)
606 }
607
608 /// Move one member into another set, and say whether it moved. `SMOVE`.
609 ///
610 /// # Errors
611 ///
612 /// As [`Sets::add`], and [`Code::Invalid`] when `to` belongs to a different
613 /// database.
614 pub fn move_to(&self, to: &Set, member: impl AsRef<[u8]>) -> Result<bool> {
615 self.same_db(to)?;
616 self.sets.move_member(&self.key, &to.key, member)
617 }
618
619 /// Everything in this set and in all of `others`. `SINTER`.
620 ///
621 /// ```
622 /// let db = yo::open(yo::MEMORY)?;
623 /// let a = db.set("a");
624 /// let b = db.set("b");
625 /// a.add_many(&["x", "y"])?;
626 /// b.add_many(&["y", "z"])?;
627 ///
628 /// assert_eq!(a.intersect(&[&b])?, vec![b"y".to_vec()]);
629 /// # Ok::<(), yo::Error>(())
630 /// ```
631 ///
632 /// # Errors
633 ///
634 /// As [`Set::move_to`].
635 pub fn intersect(&self, others: &[&Set]) -> Result<Vec<Vec<u8>>> {
636 self.sets.intersect(&self.keys_with(others)?)
637 }
638
639 /// How many members this set shares with all of `others`. `SINTERCARD`.
640 ///
641 /// A `limit` of zero means no limit.
642 ///
643 /// # Errors
644 ///
645 /// As [`Set::move_to`].
646 pub fn intersect_len(&self, others: &[&Set], limit: usize) -> Result<usize> {
647 self.sets.intersect_len(&self.keys_with(others)?, limit)
648 }
649
650 /// Everything in this set or in any of `others`. `SUNION`.
651 ///
652 /// # Errors
653 ///
654 /// As [`Set::move_to`].
655 pub fn union(&self, others: &[&Set]) -> Result<Vec<Vec<u8>>> {
656 self.sets.union(&self.keys_with(others)?)
657 }
658
659 /// Everything in this set and in none of `others`. `SDIFF`.
660 ///
661 /// # Errors
662 ///
663 /// As [`Set::move_to`].
664 pub fn difference(&self, others: &[&Set]) -> Result<Vec<Vec<u8>>> {
665 self.sets.difference(&self.keys_with(others)?)
666 }
667
668 /// Store the intersection in `destination` and say how big it is.
669 /// `SINTERSTORE`.
670 ///
671 /// # Errors
672 ///
673 /// As [`Set::move_to`].
674 pub fn intersect_into(&self, destination: &Set, others: &[&Set]) -> Result<usize> {
675 self.same_db(destination)?;
676 self.sets
677 .intersect_into(&destination.key, &self.keys_with(others)?)
678 }
679
680 /// Store the union in `destination` and say how big it is. `SUNIONSTORE`.
681 ///
682 /// # Errors
683 ///
684 /// As [`Set::move_to`].
685 pub fn union_into(&self, destination: &Set, others: &[&Set]) -> Result<usize> {
686 self.same_db(destination)?;
687 self.sets
688 .union_into(&destination.key, &self.keys_with(others)?)
689 }
690
691 /// Store the difference in `destination` and say how big it is.
692 /// `SDIFFSTORE`.
693 ///
694 /// # Errors
695 ///
696 /// As [`Set::move_to`].
697 pub fn difference_into(&self, destination: &Set, others: &[&Set]) -> Result<usize> {
698 self.same_db(destination)?;
699 self.sets
700 .difference_into(&destination.key, &self.keys_with(others)?)
701 }
702
703 /// Remove the whole set, and say whether it was there. `DEL`.
704 ///
705 /// # Errors
706 ///
707 /// As [`Sets::add`].
708 pub fn clear(&self) -> Result<bool> {
709 self.sets.db.run(|inner| Ok(inner.strings.del(&self.key)))
710 }
711
712 /// This key followed by the others', once every one of them is checked to
713 /// belong here.
714 fn keys_with<'a>(&'a self, others: &[&'a Set]) -> Result<Vec<&'a [u8]>> {
715 let mut keys = Vec::with_capacity(others.len() + 1);
716 keys.push(&self.key[..]);
717 for other in others {
718 self.same_db(other)?;
719 keys.push(&other.key[..]);
720 }
721 Ok(keys)
722 }
723
724 /// The check that keeps two databases from being intersected with each
725 /// other.
726 ///
727 /// Without it, a handle from another database contributes its key and not
728 /// its contents, so the answer is computed against whatever this database
729 /// happens to hold under that name. That is not an empty answer or an error,
730 /// it is a plausible wrong one, and it would be a very hard afternoon.
731 fn same_db(&self, other: &Set) -> Result<()> {
732 if self.sets.db.is(&other.sets.db) {
733 return Ok(());
734 }
735 Err(Error::new(
736 Code::Invalid,
737 "those two sets are in different databases, and a set operation reads both of them out of one. Open both handles on the same Db",
738 ))
739 }
740}
741
742#[cfg(test)]
743mod tests {
744 use super::*;
745 use crate::{MEMORY, open};
746
747 #[test]
748 fn the_set_commands_are_the_ones_a_redis_client_would_send() {
749 let db = open(MEMORY).unwrap();
750 let sets = db.sets();
751
752 assert!(sets.add("online", "alice").unwrap());
753 assert!(!sets.add("online", "alice").unwrap());
754 assert_eq!(sets.add_many("online", &["bob", "carol"]).unwrap(), 2);
755
756 assert!(sets.contains("online", "bob").unwrap());
757 assert!(!sets.contains("online", "dave").unwrap());
758 assert_eq!(
759 sets.contains_many("online", &["alice", "dave"]).unwrap(),
760 vec![true, false]
761 );
762 assert_eq!(sets.len_of("online").unwrap(), 3);
763
764 assert!(sets.remove("online", "alice").unwrap());
765 assert_eq!(sets.remove_many("online", &["bob", "dave"]).unwrap(), 1);
766 assert_eq!(sets.len_of("online").unwrap(), 1);
767 }
768
769 /// A key that is not there answers the way an empty set answers, everywhere
770 /// it can, because a set nobody has added to and a set somebody emptied are
771 /// the same set.
772 #[test]
773 fn a_set_that_is_not_there_reads_as_an_empty_one() {
774 let db = open(MEMORY).unwrap();
775 let sets = db.sets();
776
777 assert_eq!(sets.len_of("nope").unwrap(), 0);
778 assert!(!sets.contains("nope", "x").unwrap());
779 assert_eq!(sets.pop("nope").unwrap(), None);
780 assert_eq!(sets.pick("nope").unwrap(), None);
781 assert!(sets.pop_n("nope", 5).unwrap().is_empty());
782 assert!(sets.pick_n("nope", 5).unwrap().is_empty());
783 // The one place it does not: SMEMBERS can say which it was.
784 assert_eq!(sets.members("nope").unwrap(), None);
785 assert!(!sets.for_each("nope", |_| {}).unwrap());
786 }
787
788 /// The point of the borrowed walk. A set of integers is stored as integers,
789 /// and this is the read that does not turn them back into text.
790 #[test]
791 fn walking_a_set_of_integers_never_formats_a_digit() {
792 let db = open(MEMORY).unwrap();
793 let ids = db.set("ids");
794 ids.add_many(&["1", "2", "3"]).unwrap();
795
796 let mut total = 0i64;
797 let mut ints = 0;
798 ids.for_each(|m| {
799 if let Member::Int(n) = m {
800 total += n;
801 ints += 1;
802 }
803 })
804 .unwrap();
805 assert_eq!(total, 6);
806 assert_eq!(ints, 3, "stored as integers, so handed over as integers");
807
808 // And the owned read gives back what a client would have seen.
809 let mut owned = ids.members().unwrap();
810 owned.sort();
811 assert_eq!(owned, vec![b"1".to_vec(), b"2".to_vec(), b"3".to_vec()]);
812 }
813
814 #[test]
815 fn a_handle_holds_the_key_so_the_caller_does_not() {
816 let db = open(MEMORY).unwrap();
817 let online = db.set("online");
818
819 online.add("alice").unwrap();
820 online.add_many(&["bob", "carol"]).unwrap();
821 assert_eq!(online.len().unwrap(), 3);
822 assert!(!online.is_empty().unwrap());
823 assert!(online.contains("bob").unwrap());
824 assert_eq!(online.key(), b"online");
825 assert!(format!("{online:?}").contains("online"));
826
827 // And it is the same key the keyspace door sees.
828 assert_eq!(db.sets().len_of("online").unwrap(), 3);
829 }
830
831 #[test]
832 fn a_set_that_loses_its_last_member_loses_its_key() {
833 let db = open(MEMORY).unwrap();
834 let only = db.set("only");
835
836 only.add("x").unwrap();
837 assert!(only.remove("x").unwrap());
838 assert!(only.is_empty().unwrap());
839 assert_eq!(db.sets().members("only").unwrap(), None);
840 }
841
842 #[test]
843 fn drawing_takes_members_out_and_picking_leaves_them() {
844 let db = open(MEMORY).unwrap();
845 let bag = db.set("bag");
846 bag.add_many(&["a", "b", "c", "d"]).unwrap();
847
848 assert!(bag.pick().unwrap().is_some());
849 assert_eq!(bag.len().unwrap(), 4, "picking leaves the set alone");
850 assert_eq!(bag.pick_n(3).unwrap().len(), 3);
851 assert_eq!(bag.len().unwrap(), 4);
852 // The with repeats form is the only one that can answer more members
853 // than the set holds.
854 assert_eq!(bag.pick_n(-9).unwrap().len(), 9);
855 assert_eq!(bag.len().unwrap(), 4);
856
857 assert!(bag.pop().unwrap().is_some());
858 assert_eq!(bag.len().unwrap(), 3, "popping takes one out");
859 assert_eq!(bag.pop_n(9).unwrap().len(), 3, "and never more than it has");
860 assert!(bag.is_empty().unwrap());
861 }
862
863 #[test]
864 fn the_three_set_operations_answer_what_they_are_named_after() {
865 let db = open(MEMORY).unwrap();
866 let a = db.set("a");
867 let b = db.set("b");
868 a.add_many(&["x", "y"]).unwrap();
869 b.add_many(&["y", "z"]).unwrap();
870
871 let sorted = |mut v: Vec<Vec<u8>>| {
872 v.sort();
873 v
874 };
875 assert_eq!(sorted(a.intersect(&[&b]).unwrap()), vec![b"y".to_vec()]);
876 assert_eq!(
877 sorted(a.union(&[&b]).unwrap()),
878 vec![b"x".to_vec(), b"y".to_vec(), b"z".to_vec()]
879 );
880 assert_eq!(sorted(a.difference(&[&b]).unwrap()), vec![b"x".to_vec()]);
881 assert_eq!(a.intersect_len(&[&b], 0).unwrap(), 1);
882
883 let out = db.set("out");
884 assert_eq!(a.union_into(&out, &[&b]).unwrap(), 3);
885 assert_eq!(out.len().unwrap(), 3);
886 assert_eq!(a.intersect_into(&out, &[&b]).unwrap(), 1);
887 assert_eq!(out.len().unwrap(), 1);
888 assert_eq!(a.difference_into(&out, &[&b]).unwrap(), 1);
889 assert_eq!(out.members().unwrap(), vec![b"x".to_vec()]);
890 }
891
892 /// An empty result removes the destination rather than leaving an empty set
893 /// behind, because there is no such thing as an empty set in the keyspace.
894 #[test]
895 fn storing_an_empty_result_removes_the_destination() {
896 let db = open(MEMORY).unwrap();
897 let a = db.set("a");
898 let b = db.set("b");
899 a.add("x").unwrap();
900 b.add("y").unwrap();
901
902 let out = db.set("out");
903 out.add("stale").unwrap();
904 assert_eq!(a.intersect_into(&out, &[&b]).unwrap(), 0);
905 assert_eq!(db.sets().members("out").unwrap(), None);
906 }
907
908 #[test]
909 fn a_member_moves_between_two_sets() {
910 let db = open(MEMORY).unwrap();
911 let from = db.set("from");
912 let to = db.set("to");
913 from.add_many(&["x", "y"]).unwrap();
914
915 assert!(from.move_to(&to, "x").unwrap());
916 assert!(!from.contains("x").unwrap());
917 assert!(to.contains("x").unwrap());
918 // A member that was not there does not move and does not create one.
919 assert!(!from.move_to(&to, "nope").unwrap());
920 assert_eq!(to.len().unwrap(), 1);
921 }
922
923 /// The failure this refuses to have. Two databases, both with a key called
924 /// `b`, and an intersection that reads the wrong one. It would not error and
925 /// it would not come back empty, it would come back plausible.
926 #[test]
927 fn two_databases_cannot_be_intersected_with_each_other() {
928 let one = open(MEMORY).unwrap();
929 let two = open(MEMORY).unwrap();
930
931 let a = one.set("a");
932 a.add_many(&["x", "y"]).unwrap();
933 // The decoy: `two` has a `b` that shares a member with `a`, so an
934 // unchecked intersection would answer `x` rather than fail.
935 one.set("b").add("z").unwrap();
936 let elsewhere = two.set("b");
937 elsewhere.add("x").unwrap();
938
939 let e = a.intersect(&[&elsewhere]).expect_err("different databases");
940 assert_eq!(e.code(), Code::Invalid);
941 assert!(e.message().contains("different databases"), "{e}");
942
943 // Every other door into another database is shut the same way.
944 assert!(a.union(&[&elsewhere]).is_err());
945 assert!(a.difference(&[&elsewhere]).is_err());
946 assert!(a.intersect_len(&[&elsewhere], 0).is_err());
947 assert!(a.move_to(&elsewhere, "x").is_err());
948 assert!(a.intersect_into(&elsewhere, &[]).is_err());
949 assert!(a.union_into(&elsewhere, &[]).is_err());
950 assert!(a.difference_into(&elsewhere, &[]).is_err());
951 }
952
953 /// The embedded door and the wire door are one store (Y23), so a set added
954 /// here is a set the keyspace holds and a `DEL` here removes it.
955 #[test]
956 fn a_set_and_the_keyspace_are_the_same_store() {
957 let db = open(MEMORY).unwrap();
958 let tags = db.set("tags");
959 tags.add("rust").unwrap();
960
961 // A string command on a key holding a set is the same WRONGTYPE a
962 // client would get.
963 let e = db.strings().get("tags").expect_err("that is a set");
964 assert_eq!(e.code(), Code::WrongType);
965 // And the other way round.
966 db.strings().set("word", "nope").unwrap();
967 assert_eq!(db.set("word").add("x").unwrap_err().code(), Code::WrongType);
968
969 assert!(tags.clear().unwrap());
970 assert!(tags.is_empty().unwrap());
971 assert!(!tags.clear().unwrap());
972 }
973
974 #[test]
975 fn a_member_is_bytes_and_not_only_text() {
976 let db = open(MEMORY).unwrap();
977 let raw = db.set("raw");
978
979 raw.add(vec![0u8, 0xff]).unwrap();
980 assert!(raw.contains(b"\x00\xff").unwrap());
981 assert_eq!(raw.members().unwrap(), vec![vec![0u8, 0xff]]);
982 }
983}