Skip to main content

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}