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 /// How big the union is, without building it. `SUNIONCARD`.
343 ///
344 /// A `limit` of zero means no limit, and is [`Sets::intersect_len`]'s in
345 /// every respect.
346 ///
347 /// # Errors
348 ///
349 /// As [`Sets::add`], for any of the keys.
350 pub fn union_len<K: AsRef<[u8]>>(&self, keys: &[K], limit: usize) -> Result<usize> {
351 self.db.run(|inner| {
352 inner
353 .strings
354 .sunioncard(keys.iter().map(AsRef::as_ref), limit)
355 })
356 }
357
358 /// Everything in the first set and in none of the others. `SDIFF`.
359 ///
360 /// # Errors
361 ///
362 /// As [`Sets::add`], for any of the keys.
363 pub fn difference<K: AsRef<[u8]>>(&self, keys: &[K]) -> Result<Vec<Vec<u8>>> {
364 self.collect(keys, Op::Difference)
365 }
366
367 /// How big the difference is, without building it. `SDIFFCARD`.
368 ///
369 /// A `limit` of zero means no limit, and is [`Sets::intersect_len`]'s in
370 /// every respect.
371 ///
372 /// # Errors
373 ///
374 /// As [`Sets::add`], for any of the keys.
375 pub fn difference_len<K: AsRef<[u8]>>(&self, keys: &[K], limit: usize) -> Result<usize> {
376 self.db.run(|inner| {
377 inner
378 .strings
379 .sdiffcard(keys.iter().map(AsRef::as_ref), limit)
380 })
381 }
382
383 /// Store the intersection under `destination` and say how big it is.
384 /// `SINTERSTORE`.
385 ///
386 /// An empty result removes `destination` rather than leaving an empty set
387 /// there, because there is no such thing as an empty set in the keyspace.
388 ///
389 /// # Errors
390 ///
391 /// As [`Sets::add`], for any of the keys.
392 pub fn intersect_into<K: AsRef<[u8]>>(
393 &self,
394 destination: impl AsRef<[u8]>,
395 keys: &[K],
396 ) -> Result<usize> {
397 self.db.run(|inner| {
398 inner
399 .strings
400 .sinterstore(destination.as_ref(), keys.iter().map(AsRef::as_ref))
401 })
402 }
403
404 /// Store the union under `destination` and say how big it is. `SUNIONSTORE`.
405 ///
406 /// # Errors
407 ///
408 /// As [`Sets::intersect_into`].
409 pub fn union_into<K: AsRef<[u8]>>(
410 &self,
411 destination: impl AsRef<[u8]>,
412 keys: &[K],
413 ) -> Result<usize> {
414 self.db.run(|inner| {
415 inner
416 .strings
417 .sunionstore(destination.as_ref(), keys.iter().map(AsRef::as_ref))
418 })
419 }
420
421 /// Store the difference under `destination` and say how big it is.
422 /// `SDIFFSTORE`.
423 ///
424 /// # Errors
425 ///
426 /// As [`Sets::intersect_into`].
427 pub fn difference_into<K: AsRef<[u8]>>(
428 &self,
429 destination: impl AsRef<[u8]>,
430 keys: &[K],
431 ) -> Result<usize> {
432 self.db.run(|inner| {
433 inner
434 .strings
435 .sdiffstore(destination.as_ref(), keys.iter().map(AsRef::as_ref))
436 })
437 }
438
439 /// The three algebra reads, which differ only in which one they call.
440 ///
441 /// They hand back owned members rather than borrowed ones, and that is not a
442 /// choice made here. An intersection has to compare members that are stored
443 /// three different ways, so by the time one is known to be in the answer it
444 /// has already been written out somewhere. There is nothing left to borrow.
445 fn collect<K: AsRef<[u8]>>(&self, keys: &[K], op: Op) -> Result<Vec<Vec<u8>>> {
446 self.db.run(|inner| {
447 let mut out = Vec::new();
448 let push = |m: &[u8]| out.push(m.to_vec());
449 let keys = keys.iter().map(AsRef::as_ref);
450 match op {
451 Op::Intersect => inner.strings.sinter(keys, 0, push)?,
452 Op::Union => inner.strings.sunion(keys, 0, push)?,
453 Op::Difference => inner.strings.sdiff(keys, 0, push)?,
454 };
455 Ok(out)
456 })
457 }
458}
459
460/// Which of the three set algebra reads [`Sets::collect`] is doing.
461#[derive(Clone, Copy)]
462enum Op {
463 Intersect,
464 Union,
465 Difference,
466}
467
468/// One set, with its key held for you.
469///
470/// This is `15` section 2's shape: the name is spelled where the handle is made
471/// and nowhere else, so a typo is one compile error at one line instead of a
472/// lookup that quietly misses at three call sites.
473///
474/// ```
475/// let db = yo::open(yo::MEMORY)?;
476/// let online = db.set("online");
477///
478/// online.add("alice")?;
479/// online.add("bob")?;
480/// assert!(online.contains("alice")?);
481/// assert_eq!(online.len()?, 2);
482///
483/// online.remove("alice")?;
484/// assert!(!online.contains("alice")?);
485/// # Ok::<(), yo::Error>(())
486/// ```
487#[derive(Clone)]
488pub struct Set {
489 pub(crate) sets: Sets,
490 pub(crate) key: Vec<u8>,
491}
492
493impl core::fmt::Debug for Set {
494 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
495 f.debug_struct("Set")
496 .field("key", &String::from_utf8_lossy(&self.key))
497 .field("len", &self.len().ok())
498 .finish()
499 }
500}
501
502impl Set {
503 /// The key this handle holds.
504 #[must_use]
505 pub fn key(&self) -> &[u8] {
506 &self.key
507 }
508
509 /// Add one member, and say whether it was new. `SADD`.
510 ///
511 /// # Errors
512 ///
513 /// As [`Sets::add`].
514 pub fn add(&self, member: impl AsRef<[u8]>) -> Result<bool> {
515 self.sets.add(&self.key, member)
516 }
517
518 /// Add several members, and say how many were new.
519 ///
520 /// # Errors
521 ///
522 /// As [`Sets::add`].
523 pub fn add_many<M: AsRef<[u8]>>(&self, members: &[M]) -> Result<usize> {
524 self.sets.add_many(&self.key, members)
525 }
526
527 /// Remove one member, and say whether it was there. `SREM`.
528 ///
529 /// # Errors
530 ///
531 /// As [`Sets::add`].
532 pub fn remove(&self, member: impl AsRef<[u8]>) -> Result<bool> {
533 self.sets.remove(&self.key, member)
534 }
535
536 /// Remove several members, and say how many were there.
537 ///
538 /// # Errors
539 ///
540 /// As [`Sets::add`].
541 pub fn remove_many<M: AsRef<[u8]>>(&self, members: &[M]) -> Result<usize> {
542 self.sets.remove_many(&self.key, members)
543 }
544
545 /// Whether a member is in the set. `SISMEMBER`.
546 ///
547 /// # Errors
548 ///
549 /// As [`Sets::add`].
550 pub fn contains(&self, member: impl AsRef<[u8]>) -> Result<bool> {
551 self.sets.contains(&self.key, member)
552 }
553
554 /// Whether each of several members is in the set, in the order asked.
555 /// `SMISMEMBER`.
556 ///
557 /// # Errors
558 ///
559 /// As [`Sets::add`].
560 pub fn contains_many<M: AsRef<[u8]>>(&self, members: &[M]) -> Result<Vec<bool>> {
561 self.sets.contains_many(&self.key, members)
562 }
563
564 /// How many members it holds. `SCARD`.
565 ///
566 /// # Errors
567 ///
568 /// As [`Sets::add`].
569 pub fn len(&self) -> Result<usize> {
570 self.sets.len_of(&self.key)
571 }
572
573 /// Whether it holds nothing, which is also true of a key that is not there.
574 ///
575 /// # Errors
576 ///
577 /// As [`Sets::add`].
578 pub fn is_empty(&self) -> Result<bool> {
579 self.len().map(|n| n == 0)
580 }
581
582 /// Every member, owned. `SMEMBERS`.
583 ///
584 /// An empty `Vec` for a key that is not there. [`Sets::members`] is the
585 /// version that tells the two apart, and this one does not because a handle
586 /// on a key that was never written to is the ordinary way to start.
587 ///
588 /// # Errors
589 ///
590 /// As [`Sets::add`].
591 pub fn members(&self) -> Result<Vec<Vec<u8>>> {
592 Ok(self.sets.members(&self.key)?.unwrap_or_default())
593 }
594
595 /// Hand every member to `f` where it lies, allocating nothing.
596 ///
597 /// # Errors
598 ///
599 /// As [`Sets::add`].
600 pub fn for_each(&self, f: impl FnMut(Member<'_>)) -> Result<()> {
601 self.sets.for_each(&self.key, f).map(|_| ())
602 }
603
604 /// Take one member out at random. `SPOP`.
605 ///
606 /// # Errors
607 ///
608 /// As [`Sets::add`].
609 pub fn pop(&self) -> Result<Option<Vec<u8>>> {
610 self.sets.pop(&self.key)
611 }
612
613 /// Take up to `count` distinct members out at random. `SPOP key count`.
614 ///
615 /// # Errors
616 ///
617 /// As [`Sets::add`].
618 pub fn pop_n(&self, count: usize) -> Result<Vec<Vec<u8>>> {
619 self.sets.pop_n(&self.key, count)
620 }
621
622 /// Draw one member and leave it in the set. `SRANDMEMBER`.
623 ///
624 /// # Errors
625 ///
626 /// As [`Sets::add`].
627 pub fn pick(&self) -> Result<Option<Vec<u8>>> {
628 self.sets.pick(&self.key)
629 }
630
631 /// Draw `count` members and leave them in the set. `SRANDMEMBER key count`.
632 ///
633 /// # Errors
634 ///
635 /// As [`Sets::add`].
636 pub fn pick_n(&self, count: i64) -> Result<Vec<Vec<u8>>> {
637 self.sets.pick_n(&self.key, count)
638 }
639
640 /// Move one member into another set, and say whether it moved. `SMOVE`.
641 ///
642 /// # Errors
643 ///
644 /// As [`Sets::add`], and [`Code::Invalid`] when `to` belongs to a different
645 /// database.
646 pub fn move_to(&self, to: &Set, member: impl AsRef<[u8]>) -> Result<bool> {
647 self.same_db(to)?;
648 self.sets.move_member(&self.key, &to.key, member)
649 }
650
651 /// Everything in this set and in all of `others`. `SINTER`.
652 ///
653 /// ```
654 /// let db = yo::open(yo::MEMORY)?;
655 /// let a = db.set("a");
656 /// let b = db.set("b");
657 /// a.add_many(&["x", "y"])?;
658 /// b.add_many(&["y", "z"])?;
659 ///
660 /// assert_eq!(a.intersect(&[&b])?, vec![b"y".to_vec()]);
661 /// # Ok::<(), yo::Error>(())
662 /// ```
663 ///
664 /// # Errors
665 ///
666 /// As [`Set::move_to`].
667 pub fn intersect(&self, others: &[&Set]) -> Result<Vec<Vec<u8>>> {
668 self.sets.intersect(&self.keys_with(others)?)
669 }
670
671 /// How many members this set shares with all of `others`. `SINTERCARD`.
672 ///
673 /// A `limit` of zero means no limit.
674 ///
675 /// # Errors
676 ///
677 /// As [`Set::move_to`].
678 pub fn intersect_len(&self, others: &[&Set], limit: usize) -> Result<usize> {
679 self.sets.intersect_len(&self.keys_with(others)?, limit)
680 }
681
682 /// Everything in this set or in any of `others`. `SUNION`.
683 ///
684 /// # Errors
685 ///
686 /// As [`Set::move_to`].
687 pub fn union(&self, others: &[&Set]) -> Result<Vec<Vec<u8>>> {
688 self.sets.union(&self.keys_with(others)?)
689 }
690
691 /// How many members this set and `others` have between them. `SUNIONCARD`.
692 ///
693 /// A `limit` of zero means no limit.
694 ///
695 /// # Errors
696 ///
697 /// As [`Set::move_to`].
698 pub fn union_len(&self, others: &[&Set], limit: usize) -> Result<usize> {
699 self.sets.union_len(&self.keys_with(others)?, limit)
700 }
701
702 /// Everything in this set and in none of `others`. `SDIFF`.
703 ///
704 /// # Errors
705 ///
706 /// As [`Set::move_to`].
707 pub fn difference(&self, others: &[&Set]) -> Result<Vec<Vec<u8>>> {
708 self.sets.difference(&self.keys_with(others)?)
709 }
710
711 /// How many members this set has that no set in `others` has. `SDIFFCARD`.
712 ///
713 /// A `limit` of zero means no limit.
714 ///
715 /// # Errors
716 ///
717 /// As [`Set::move_to`].
718 pub fn difference_len(&self, others: &[&Set], limit: usize) -> Result<usize> {
719 self.sets.difference_len(&self.keys_with(others)?, limit)
720 }
721
722 /// Store the intersection in `destination` and say how big it is.
723 /// `SINTERSTORE`.
724 ///
725 /// # Errors
726 ///
727 /// As [`Set::move_to`].
728 pub fn intersect_into(&self, destination: &Set, others: &[&Set]) -> Result<usize> {
729 self.same_db(destination)?;
730 self.sets
731 .intersect_into(&destination.key, &self.keys_with(others)?)
732 }
733
734 /// Store the union in `destination` and say how big it is. `SUNIONSTORE`.
735 ///
736 /// # Errors
737 ///
738 /// As [`Set::move_to`].
739 pub fn union_into(&self, destination: &Set, others: &[&Set]) -> Result<usize> {
740 self.same_db(destination)?;
741 self.sets
742 .union_into(&destination.key, &self.keys_with(others)?)
743 }
744
745 /// Store the difference in `destination` and say how big it is.
746 /// `SDIFFSTORE`.
747 ///
748 /// # Errors
749 ///
750 /// As [`Set::move_to`].
751 pub fn difference_into(&self, destination: &Set, others: &[&Set]) -> Result<usize> {
752 self.same_db(destination)?;
753 self.sets
754 .difference_into(&destination.key, &self.keys_with(others)?)
755 }
756
757 /// Remove the whole set, and say whether it was there. `DEL`.
758 ///
759 /// # Errors
760 ///
761 /// As [`Sets::add`].
762 pub fn clear(&self) -> Result<bool> {
763 self.sets.db.run(|inner| Ok(inner.strings.del(&self.key)))
764 }
765
766 /// This key followed by the others', once every one of them is checked to
767 /// belong here.
768 fn keys_with<'a>(&'a self, others: &[&'a Set]) -> Result<Vec<&'a [u8]>> {
769 let mut keys = Vec::with_capacity(others.len() + 1);
770 keys.push(&self.key[..]);
771 for other in others {
772 self.same_db(other)?;
773 keys.push(&other.key[..]);
774 }
775 Ok(keys)
776 }
777
778 /// The check that keeps two databases from being intersected with each
779 /// other.
780 ///
781 /// Without it, a handle from another database contributes its key and not
782 /// its contents, so the answer is computed against whatever this database
783 /// happens to hold under that name. That is not an empty answer or an error,
784 /// it is a plausible wrong one, and it would be a very hard afternoon.
785 fn same_db(&self, other: &Set) -> Result<()> {
786 if self.sets.db.is(&other.sets.db) {
787 return Ok(());
788 }
789 Err(Error::new(
790 Code::Invalid,
791 "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",
792 ))
793 }
794}
795
796#[cfg(test)]
797mod tests {
798 use super::*;
799 use crate::{MEMORY, open};
800
801 #[test]
802 fn the_set_commands_are_the_ones_a_redis_client_would_send() {
803 let db = open(MEMORY).unwrap();
804 let sets = db.sets();
805
806 assert!(sets.add("online", "alice").unwrap());
807 assert!(!sets.add("online", "alice").unwrap());
808 assert_eq!(sets.add_many("online", &["bob", "carol"]).unwrap(), 2);
809
810 assert!(sets.contains("online", "bob").unwrap());
811 assert!(!sets.contains("online", "dave").unwrap());
812 assert_eq!(
813 sets.contains_many("online", &["alice", "dave"]).unwrap(),
814 vec![true, false]
815 );
816 assert_eq!(sets.len_of("online").unwrap(), 3);
817
818 assert!(sets.remove("online", "alice").unwrap());
819 assert_eq!(sets.remove_many("online", &["bob", "dave"]).unwrap(), 1);
820 assert_eq!(sets.len_of("online").unwrap(), 1);
821 }
822
823 /// A key that is not there answers the way an empty set answers, everywhere
824 /// it can, because a set nobody has added to and a set somebody emptied are
825 /// the same set.
826 #[test]
827 fn a_set_that_is_not_there_reads_as_an_empty_one() {
828 let db = open(MEMORY).unwrap();
829 let sets = db.sets();
830
831 assert_eq!(sets.len_of("nope").unwrap(), 0);
832 assert!(!sets.contains("nope", "x").unwrap());
833 assert_eq!(sets.pop("nope").unwrap(), None);
834 assert_eq!(sets.pick("nope").unwrap(), None);
835 assert!(sets.pop_n("nope", 5).unwrap().is_empty());
836 assert!(sets.pick_n("nope", 5).unwrap().is_empty());
837 // The one place it does not: SMEMBERS can say which it was.
838 assert_eq!(sets.members("nope").unwrap(), None);
839 assert!(!sets.for_each("nope", |_| {}).unwrap());
840 }
841
842 /// The point of the borrowed walk. A set of integers is stored as integers,
843 /// and this is the read that does not turn them back into text.
844 #[test]
845 fn walking_a_set_of_integers_never_formats_a_digit() {
846 let db = open(MEMORY).unwrap();
847 let ids = db.set("ids");
848 ids.add_many(&["1", "2", "3"]).unwrap();
849
850 let mut total = 0i64;
851 let mut ints = 0;
852 ids.for_each(|m| {
853 if let Member::Int(n) = m {
854 total += n;
855 ints += 1;
856 }
857 })
858 .unwrap();
859 assert_eq!(total, 6);
860 assert_eq!(ints, 3, "stored as integers, so handed over as integers");
861
862 // And the owned read gives back what a client would have seen.
863 let mut owned = ids.members().unwrap();
864 owned.sort();
865 assert_eq!(owned, vec![b"1".to_vec(), b"2".to_vec(), b"3".to_vec()]);
866 }
867
868 #[test]
869 fn a_handle_holds_the_key_so_the_caller_does_not() {
870 let db = open(MEMORY).unwrap();
871 let online = db.set("online");
872
873 online.add("alice").unwrap();
874 online.add_many(&["bob", "carol"]).unwrap();
875 assert_eq!(online.len().unwrap(), 3);
876 assert!(!online.is_empty().unwrap());
877 assert!(online.contains("bob").unwrap());
878 assert_eq!(online.key(), b"online");
879 assert!(format!("{online:?}").contains("online"));
880
881 // And it is the same key the keyspace door sees.
882 assert_eq!(db.sets().len_of("online").unwrap(), 3);
883 }
884
885 #[test]
886 fn a_set_that_loses_its_last_member_loses_its_key() {
887 let db = open(MEMORY).unwrap();
888 let only = db.set("only");
889
890 only.add("x").unwrap();
891 assert!(only.remove("x").unwrap());
892 assert!(only.is_empty().unwrap());
893 assert_eq!(db.sets().members("only").unwrap(), None);
894 }
895
896 #[test]
897 fn drawing_takes_members_out_and_picking_leaves_them() {
898 let db = open(MEMORY).unwrap();
899 let bag = db.set("bag");
900 bag.add_many(&["a", "b", "c", "d"]).unwrap();
901
902 assert!(bag.pick().unwrap().is_some());
903 assert_eq!(bag.len().unwrap(), 4, "picking leaves the set alone");
904 assert_eq!(bag.pick_n(3).unwrap().len(), 3);
905 assert_eq!(bag.len().unwrap(), 4);
906 // The with repeats form is the only one that can answer more members
907 // than the set holds.
908 assert_eq!(bag.pick_n(-9).unwrap().len(), 9);
909 assert_eq!(bag.len().unwrap(), 4);
910
911 assert!(bag.pop().unwrap().is_some());
912 assert_eq!(bag.len().unwrap(), 3, "popping takes one out");
913 assert_eq!(bag.pop_n(9).unwrap().len(), 3, "and never more than it has");
914 assert!(bag.is_empty().unwrap());
915 }
916
917 #[test]
918 fn the_three_set_operations_answer_what_they_are_named_after() {
919 let db = open(MEMORY).unwrap();
920 let a = db.set("a");
921 let b = db.set("b");
922 a.add_many(&["x", "y"]).unwrap();
923 b.add_many(&["y", "z"]).unwrap();
924
925 let sorted = |mut v: Vec<Vec<u8>>| {
926 v.sort();
927 v
928 };
929 assert_eq!(sorted(a.intersect(&[&b]).unwrap()), vec![b"y".to_vec()]);
930 assert_eq!(
931 sorted(a.union(&[&b]).unwrap()),
932 vec![b"x".to_vec(), b"y".to_vec(), b"z".to_vec()]
933 );
934 assert_eq!(sorted(a.difference(&[&b]).unwrap()), vec![b"x".to_vec()]);
935 assert_eq!(a.intersect_len(&[&b], 0).unwrap(), 1);
936 assert_eq!(a.union_len(&[&b], 0).unwrap(), 3);
937 assert_eq!(a.union_len(&[&b], 2).unwrap(), 2, "the limit stops it");
938 assert_eq!(a.difference_len(&[&b], 0).unwrap(), 1);
939 assert_eq!(b.difference_len(&[&a], 0).unwrap(), 1);
940
941 let out = db.set("out");
942 assert_eq!(a.union_into(&out, &[&b]).unwrap(), 3);
943 assert_eq!(out.len().unwrap(), 3);
944 assert_eq!(a.intersect_into(&out, &[&b]).unwrap(), 1);
945 assert_eq!(out.len().unwrap(), 1);
946 assert_eq!(a.difference_into(&out, &[&b]).unwrap(), 1);
947 assert_eq!(out.members().unwrap(), vec![b"x".to_vec()]);
948 }
949
950 /// An empty result removes the destination rather than leaving an empty set
951 /// behind, because there is no such thing as an empty set in the keyspace.
952 #[test]
953 fn storing_an_empty_result_removes_the_destination() {
954 let db = open(MEMORY).unwrap();
955 let a = db.set("a");
956 let b = db.set("b");
957 a.add("x").unwrap();
958 b.add("y").unwrap();
959
960 let out = db.set("out");
961 out.add("stale").unwrap();
962 assert_eq!(a.intersect_into(&out, &[&b]).unwrap(), 0);
963 assert_eq!(db.sets().members("out").unwrap(), None);
964 }
965
966 #[test]
967 fn a_member_moves_between_two_sets() {
968 let db = open(MEMORY).unwrap();
969 let from = db.set("from");
970 let to = db.set("to");
971 from.add_many(&["x", "y"]).unwrap();
972
973 assert!(from.move_to(&to, "x").unwrap());
974 assert!(!from.contains("x").unwrap());
975 assert!(to.contains("x").unwrap());
976 // A member that was not there does not move and does not create one.
977 assert!(!from.move_to(&to, "nope").unwrap());
978 assert_eq!(to.len().unwrap(), 1);
979 }
980
981 /// The failure this refuses to have. Two databases, both with a key called
982 /// `b`, and an intersection that reads the wrong one. It would not error and
983 /// it would not come back empty, it would come back plausible.
984 #[test]
985 fn two_databases_cannot_be_intersected_with_each_other() {
986 let one = open(MEMORY).unwrap();
987 let two = open(MEMORY).unwrap();
988
989 let a = one.set("a");
990 a.add_many(&["x", "y"]).unwrap();
991 // The decoy: `two` has a `b` that shares a member with `a`, so an
992 // unchecked intersection would answer `x` rather than fail.
993 one.set("b").add("z").unwrap();
994 let elsewhere = two.set("b");
995 elsewhere.add("x").unwrap();
996
997 let e = a.intersect(&[&elsewhere]).expect_err("different databases");
998 assert_eq!(e.code(), Code::Invalid);
999 assert!(e.message().contains("different databases"), "{e}");
1000
1001 // Every other door into another database is shut the same way.
1002 assert!(a.union(&[&elsewhere]).is_err());
1003 assert!(a.difference(&[&elsewhere]).is_err());
1004 assert!(a.intersect_len(&[&elsewhere], 0).is_err());
1005 assert!(a.move_to(&elsewhere, "x").is_err());
1006 assert!(a.intersect_into(&elsewhere, &[]).is_err());
1007 assert!(a.union_into(&elsewhere, &[]).is_err());
1008 assert!(a.difference_into(&elsewhere, &[]).is_err());
1009 }
1010
1011 /// The embedded door and the wire door are one store (Y23), so a set added
1012 /// here is a set the keyspace holds and a `DEL` here removes it.
1013 #[test]
1014 fn a_set_and_the_keyspace_are_the_same_store() {
1015 let db = open(MEMORY).unwrap();
1016 let tags = db.set("tags");
1017 tags.add("rust").unwrap();
1018
1019 // A string command on a key holding a set is the same WRONGTYPE a
1020 // client would get.
1021 let e = db.strings().get("tags").expect_err("that is a set");
1022 assert_eq!(e.code(), Code::WrongType);
1023 // And the other way round.
1024 db.strings().set("word", "nope").unwrap();
1025 assert_eq!(db.set("word").add("x").unwrap_err().code(), Code::WrongType);
1026
1027 assert!(tags.clear().unwrap());
1028 assert!(tags.is_empty().unwrap());
1029 assert!(!tags.clear().unwrap());
1030 }
1031
1032 #[test]
1033 fn a_member_is_bytes_and_not_only_text() {
1034 let db = open(MEMORY).unwrap();
1035 let raw = db.set("raw");
1036
1037 raw.add(vec![0u8, 0xff]).unwrap();
1038 assert!(raw.contains(b"\x00\xff").unwrap());
1039 assert_eq!(raw.members().unwrap(), vec![vec![0u8, 0xff]]);
1040 }
1041}