1use super::*;
2
3impl Keyspace {
4 pub fn sadd(&mut self, key: &str, members: &[String]) -> Result<usize, WriteError> {
9 if members.is_empty() {
10 return Ok(0);
11 }
12
13 self.remove_if_expired(key);
14
15 let is_new = self.ensure_collection_type(key, |v| matches!(v, Value::Set(_)))?;
16
17 let member_increase: usize = members
18 .iter()
19 .map(|m| m.len() + memory::HASHSET_MEMBER_OVERHEAD)
20 .sum();
21 self.reserve_memory(is_new, key, memory::HASHSET_BASE_OVERHEAD, member_increase)?;
22
23 if is_new {
24 self.insert_empty(key, Value::Set(Box::default()));
25 }
26
27 let track_access = self.track_access;
28 let added = self
29 .track_size(key, |entry| {
30 let Value::Set(ref mut set) = entry.value else {
31 unreachable!("type verified by ensure_collection_type");
32 };
33 let mut added = 0;
34 for member in members {
35 if set.insert(member.clone()) {
36 added += 1;
37 }
38 }
39 entry.touch(track_access);
40 added
41 })
42 .unwrap_or(0);
43
44 Ok(added)
45 }
46
47 pub fn srem(&mut self, key: &str, members: &[String]) -> Result<usize, WrongType> {
51 if self.remove_if_expired(key) {
52 return Ok(0);
53 }
54
55 let Some(entry) = self.entries.get_mut(key) else {
56 return Ok(0);
57 };
58 if !matches!(entry.value, Value::Set(_)) {
59 return Err(WrongType);
60 }
61
62 let old_entry_size = entry.entry_size(key);
63
64 let mut removed = 0;
65 let mut removed_bytes: usize = 0;
66 let is_empty = if let Value::Set(ref mut set) = entry.value {
67 for member in members {
68 if set.remove(member) {
69 removed_bytes += member.len() + memory::HASHSET_MEMBER_OVERHEAD;
70 removed += 1;
71 }
72 }
73 set.is_empty()
74 } else {
75 false
76 };
77 if removed > 0 {
78 self.bump_version(key);
79 }
80
81 self.cleanup_after_remove(key, old_entry_size, is_empty, removed_bytes);
82
83 Ok(removed)
84 }
85
86 pub fn smembers(&mut self, key: &str) -> Result<Vec<String>, WrongType> {
88 let Some(entry) = self.get_live_entry(key) else {
89 return Ok(vec![]);
90 };
91 match &entry.value {
92 Value::Set(set) => Ok(set.iter().cloned().collect()),
93 _ => Err(WrongType),
94 }
95 }
96
97 pub fn sismember(&mut self, key: &str, member: &str) -> Result<bool, WrongType> {
99 let Some(entry) = self.get_live_entry(key) else {
100 return Ok(false);
101 };
102 match &entry.value {
103 Value::Set(set) => Ok(set.contains(member)),
104 _ => Err(WrongType),
105 }
106 }
107
108 pub fn scan_set(
114 &mut self,
115 key: &str,
116 cursor: u64,
117 count: usize,
118 pattern: Option<&str>,
119 ) -> Result<(u64, Vec<String>), WrongType> {
120 let Some(entry) = self.get_live_entry(key) else {
121 return Ok((0, vec![]));
122 };
123 let Value::Set(ref set) = entry.value else {
124 return Err(WrongType);
125 };
126
127 let target = if count == 0 { 10 } else { count };
128 let compiled = pattern.map(GlobPattern::new);
129 let mut result = Vec::with_capacity(target);
130 let mut pos = 0u64;
131 let mut done = true;
132
133 for member in set.iter() {
134 if pos < cursor {
135 pos += 1;
136 continue;
137 }
138 if let Some(ref pat) = compiled {
139 if !pat.matches(member) {
140 pos += 1;
141 continue;
142 }
143 }
144 result.push(member.clone());
145 pos += 1;
146 if result.len() >= target {
147 done = false;
148 break;
149 }
150 }
151
152 Ok(if done { (0, result) } else { (pos, result) })
153 }
154
155 pub fn sunion(&mut self, keys: &[String]) -> Result<Vec<String>, WrongType> {
160 let mut result = std::collections::HashSet::new();
161 for key in keys {
162 self.remove_if_expired(key);
163 match self.entries.get_mut(key.as_str()) {
164 None => {}
165 Some(entry) => match &entry.value {
166 Value::Set(set) => {
167 result.extend(set.iter().cloned());
168 entry.touch(self.track_access);
169 }
170 _ => return Err(WrongType),
171 },
172 }
173 }
174 Ok(result.into_iter().collect())
175 }
176
177 pub fn sinter(&mut self, keys: &[String]) -> Result<Vec<String>, WrongType> {
182 if keys.is_empty() {
183 return Ok(vec![]);
184 }
185
186 for key in keys {
188 self.remove_if_expired(key);
189 match self.entries.get(key.as_str()) {
190 None => return Ok(vec![]), Some(entry) => {
192 if !matches!(&entry.value, Value::Set(_)) {
193 return Err(WrongType);
194 }
195 }
196 }
197 }
198
199 let entry = self
201 .entries
202 .get_mut(keys[0].as_str())
203 .expect("checked above");
204 let Value::Set(ref base) = entry.value else {
205 unreachable!("type checked above");
206 };
207 let candidates: Vec<String> = base.iter().cloned().collect();
208 entry.touch(self.track_access);
209
210 let result: Vec<String> = candidates
211 .into_iter()
212 .filter(|member| {
213 keys[1..].iter().all(|key| {
214 self.entries
215 .get(key.as_str())
216 .and_then(|e| match &e.value {
217 Value::Set(s) => Some(s.contains(member)),
218 _ => None,
219 })
220 .unwrap_or(false)
221 })
222 })
223 .collect();
224
225 for key in &keys[1..] {
227 if let Some(entry) = self.entries.get_mut(key.as_str()) {
228 entry.touch(self.track_access);
229 }
230 }
231
232 Ok(result)
233 }
234
235 pub fn sdiff(&mut self, keys: &[String]) -> Result<Vec<String>, WrongType> {
240 if keys.is_empty() {
241 return Ok(vec![]);
242 }
243
244 for key in keys {
246 self.remove_if_expired(key);
247 if let Some(entry) = self.entries.get(key.as_str()) {
248 if !matches!(&entry.value, Value::Set(_)) {
249 return Err(WrongType);
250 }
251 }
252 }
253
254 let Some(first_entry) = self.entries.get_mut(keys[0].as_str()) else {
255 return Ok(vec![]);
256 };
257 let Value::Set(ref base) = first_entry.value else {
258 unreachable!("type checked above");
259 };
260 let candidates: Vec<String> = base.iter().cloned().collect();
261 first_entry.touch(self.track_access);
262
263 let result: Vec<String> = candidates
264 .into_iter()
265 .filter(|member| {
266 !keys[1..].iter().any(|key| {
267 self.entries
268 .get(key.as_str())
269 .and_then(|e| match &e.value {
270 Value::Set(s) => Some(s.contains(member)),
271 _ => None,
272 })
273 .unwrap_or(false)
274 })
275 })
276 .collect();
277
278 for key in &keys[1..] {
280 if let Some(entry) = self.entries.get_mut(key.as_str()) {
281 entry.touch(self.track_access);
282 }
283 }
284
285 Ok(result)
286 }
287
288 pub fn sunionstore(
293 &mut self,
294 dest: &str,
295 keys: &[String],
296 ) -> Result<(usize, Vec<String>), WriteError> {
297 let members = self.sunion(keys).map_err(|_| WriteError::WrongType)?;
298 self.store_set_result(dest, members)
299 }
300
301 pub fn sinterstore(
303 &mut self,
304 dest: &str,
305 keys: &[String],
306 ) -> Result<(usize, Vec<String>), WriteError> {
307 let members = self.sinter(keys).map_err(|_| WriteError::WrongType)?;
308 self.store_set_result(dest, members)
309 }
310
311 pub fn sdiffstore(
313 &mut self,
314 dest: &str,
315 keys: &[String],
316 ) -> Result<(usize, Vec<String>), WriteError> {
317 let members = self.sdiff(keys).map_err(|_| WriteError::WrongType)?;
318 self.store_set_result(dest, members)
319 }
320
321 fn store_set_result(
324 &mut self,
325 dest: &str,
326 members: Vec<String>,
327 ) -> Result<(usize, Vec<String>), WriteError> {
328 self.remove_if_expired(dest);
330 if let Some(old) = self.entries.remove(dest) {
331 self.memory.remove(dest, &old.value);
332 self.decrement_expiry_if_set(&old);
333 self.defer_drop(old.value);
334 }
335
336 let count = members.len();
337 if count == 0 {
338 return Ok((0, vec![]));
339 }
340
341 let member_bytes: usize = members
342 .iter()
343 .map(|m| m.len() + memory::HASHSET_MEMBER_OVERHEAD)
344 .sum();
345 self.reserve_memory(true, dest, memory::HASHSET_BASE_OVERHEAD, member_bytes)?;
346
347 let stored = members.clone();
348 let set: std::collections::HashSet<String> = members.into_iter().collect();
349 let value = Value::Set(Box::new(set));
350 self.memory.add(dest, &value);
351 let entry = Entry::new(value, None);
352 self.entries.insert(CompactString::from(dest), entry);
353 self.bump_version(dest);
354
355 Ok((count, stored))
356 }
357
358 pub fn srandmember(&mut self, key: &str, count: i64) -> Result<Vec<String>, WrongType> {
364 if count == 0 {
365 return Ok(vec![]);
366 }
367 let Some(entry) = self.get_live_entry(key) else {
368 return Ok(vec![]);
369 };
370 let Value::Set(ref set) = entry.value else {
371 return Err(WrongType);
372 };
373 if set.is_empty() {
374 return Ok(vec![]);
375 }
376
377 let mut rng = rand::rng();
378 let result = if count > 0 {
379 let n = (count as usize).min(set.len());
381 set.iter()
382 .choose_multiple(&mut rng, n)
383 .into_iter()
384 .cloned()
385 .collect()
386 } else {
387 let n = count.unsigned_abs() as usize;
389 let members: Vec<&String> = set.iter().collect();
390 use rand::Rng;
391 (0..n)
392 .map(|_| members[rng.random_range(0..members.len())].clone())
393 .collect()
394 };
395
396 Ok(result)
397 }
398
399 pub fn spop(&mut self, key: &str, count: usize) -> Result<Vec<String>, WrongType> {
401 if self.remove_if_expired(key) || count == 0 {
402 return Ok(vec![]);
403 }
404
405 let Some(entry) = self.entries.get_mut(key) else {
406 return Ok(vec![]);
407 };
408 if !matches!(entry.value, Value::Set(_)) {
409 return Err(WrongType);
410 }
411
412 let old_entry_size = entry.entry_size(key);
413
414 let Value::Set(ref mut set) = entry.value else {
416 unreachable!("type checked above");
417 };
418 if set.is_empty() {
419 return Ok(vec![]);
420 }
421
422 let n = count.min(set.len());
423 let mut rng = rand::rng();
424 let chosen: Vec<String> = set
425 .iter()
426 .choose_multiple(&mut rng, n)
427 .into_iter()
428 .cloned()
429 .collect();
430
431 let mut removed_bytes = 0usize;
432 for member in &chosen {
433 set.remove(member);
434 removed_bytes += member.len() + memory::HASHSET_MEMBER_OVERHEAD;
435 }
436 let is_empty = set.is_empty();
437
438 if !chosen.is_empty() {
439 self.bump_version(key);
440 }
441
442 self.cleanup_after_remove(key, old_entry_size, is_empty, removed_bytes);
443
444 Ok(chosen)
445 }
446
447 pub fn smismember(&mut self, key: &str, members: &[String]) -> Result<Vec<bool>, WrongType> {
451 let Some(entry) = self.get_live_entry(key) else {
452 return Ok(vec![false; members.len()]);
453 };
454 match &entry.value {
455 Value::Set(set) => Ok(members.iter().map(|m| set.contains(m)).collect()),
456 _ => Err(WrongType),
457 }
458 }
459
460 pub fn smove(
468 &mut self,
469 source: &str,
470 destination: &str,
471 member: &str,
472 ) -> Result<bool, WriteError> {
473 self.remove_if_expired(source);
474 self.remove_if_expired(destination);
475
476 match self.entries.get(source) {
478 None => return Ok(false),
479 Some(entry) => {
480 if !matches!(&entry.value, Value::Set(_)) {
481 return Err(WriteError::WrongType);
482 }
483 }
484 }
485
486 if let Some(entry) = self.entries.get(destination) {
488 if !matches!(&entry.value, Value::Set(_)) {
489 return Err(WriteError::WrongType);
490 }
491 }
492
493 let old_src_size = self
494 .entries
495 .get(source)
496 .map(|e| e.entry_size(source))
497 .unwrap_or(0);
498
499 let removed = if let Some(entry) = self.entries.get_mut(source) {
501 if let Value::Set(ref mut set) = entry.value {
502 set.remove(member)
503 } else {
504 false
505 }
506 } else {
507 false
508 };
509
510 if !removed {
511 return Ok(false);
512 }
513
514 let member_bytes = member.len() + memory::HASHSET_MEMBER_OVERHEAD;
515
516 let src_empty = self
517 .entries
518 .get(source)
519 .map(|e| matches!(&e.value, Value::Set(s) if s.is_empty()))
520 .unwrap_or(false);
521
522 self.cleanup_after_remove(source, old_src_size, src_empty, member_bytes);
523 self.bump_version(source);
524
525 self.sadd(destination, &[member.to_string()])?;
527
528 Ok(true)
529 }
530
531 pub fn sintercard(&mut self, keys: &[String], limit: usize) -> Result<usize, WrongType> {
537 let members = self.sinter(keys)?;
538 let count = if limit > 0 {
539 members.len().min(limit)
540 } else {
541 members.len()
542 };
543 Ok(count)
544 }
545
546 pub fn scard(&mut self, key: &str) -> Result<usize, WrongType> {
548 if self.remove_if_expired(key) {
549 return Ok(0);
550 }
551 match self.entries.get(key) {
552 None => Ok(0),
553 Some(entry) => match &entry.value {
554 Value::Set(set) => Ok(set.len()),
555 _ => Err(WrongType),
556 },
557 }
558 }
559}
560
561#[cfg(test)]
562mod tests {
563 use super::*;
564
565 #[test]
566 fn sadd_creates_set() {
567 let mut ks = Keyspace::new();
568 let added = ks.sadd("s", &["a".into(), "b".into()]).unwrap();
569 assert_eq!(added, 2);
570 assert_eq!(ks.value_type("s"), "set");
571 }
572
573 #[test]
574 fn sadd_returns_new_member_count() {
575 let mut ks = Keyspace::new();
576 ks.sadd("s", &["a".into(), "b".into()]).unwrap();
577 let added = ks.sadd("s", &["b".into(), "c".into()]).unwrap();
579 assert_eq!(added, 1); }
581
582 #[test]
583 fn srem_removes_members() {
584 let mut ks = Keyspace::new();
585 ks.sadd("s", &["a".into(), "b".into(), "c".into()]).unwrap();
586 let removed = ks.srem("s", &["a".into(), "c".into()]).unwrap();
587 assert_eq!(removed, 2);
588 assert_eq!(ks.scard("s").unwrap(), 1);
589 }
590
591 #[test]
592 fn srem_auto_deletes_empty_set() {
593 let mut ks = Keyspace::new();
594 ks.sadd("s", &["only".into()]).unwrap();
595 ks.srem("s", &["only".into()]).unwrap();
596 assert_eq!(ks.value_type("s"), "none");
597 }
598
599 #[test]
600 fn smembers_returns_all_members() {
601 let mut ks = Keyspace::new();
602 ks.sadd("s", &["a".into(), "b".into(), "c".into()]).unwrap();
603 let mut members = ks.smembers("s").unwrap();
604 members.sort();
605 assert_eq!(members, vec!["a", "b", "c"]);
606 }
607
608 #[test]
609 fn smembers_missing_key_returns_empty() {
610 let mut ks = Keyspace::new();
611 assert_eq!(ks.smembers("missing").unwrap(), Vec::<String>::new());
612 }
613
614 #[test]
615 fn sismember_returns_true_for_existing() {
616 let mut ks = Keyspace::new();
617 ks.sadd("s", &["member".into()]).unwrap();
618 assert!(ks.sismember("s", "member").unwrap());
619 }
620
621 #[test]
622 fn sismember_returns_false_for_missing() {
623 let mut ks = Keyspace::new();
624 ks.sadd("s", &["a".into()]).unwrap();
625 assert!(!ks.sismember("s", "missing").unwrap());
626 }
627
628 #[test]
629 fn scard_returns_count() {
630 let mut ks = Keyspace::new();
631 ks.sadd("s", &["a".into(), "b".into(), "c".into()]).unwrap();
632 assert_eq!(ks.scard("s").unwrap(), 3);
633 }
634
635 #[test]
636 fn scard_missing_key_returns_zero() {
637 let mut ks = Keyspace::new();
638 assert_eq!(ks.scard("missing").unwrap(), 0);
639 }
640
641 #[test]
642 fn set_on_string_key_returns_wrongtype() {
643 let mut ks = Keyspace::new();
644 ks.set("s".into(), Bytes::from("string"), None, false, false);
645 assert!(ks.sadd("s", &["m".into()]).is_err());
646 assert!(ks.srem("s", &["m".into()]).is_err());
647 assert!(ks.smembers("s").is_err());
648 assert!(ks.sismember("s", "m").is_err());
649 assert!(ks.scard("s").is_err());
650 }
651
652 #[test]
653 fn sadd_duplicate_members_counted_once() {
654 let mut ks = Keyspace::new();
655 let count = ks.sadd("s", &["a".into(), "a".into()]).unwrap();
657 assert_eq!(count, 1);
659 assert_eq!(ks.scard("s").unwrap(), 1);
660 }
661
662 #[test]
663 fn srem_non_existent_member_returns_zero() {
664 let mut ks = Keyspace::new();
665 ks.sadd("s", &["a".into()]).unwrap();
666 let removed = ks.srem("s", &["nonexistent".into()]).unwrap();
667 assert_eq!(removed, 0);
668 }
669
670 #[test]
673 fn scan_set_returns_all() {
674 let mut ks = Keyspace::new();
675 ks.sadd("s", &["a".into(), "b".into(), "c".into()]).unwrap();
676 let (cursor, members) = ks.scan_set("s", 0, 100, None).unwrap();
677 assert_eq!(cursor, 0);
678 assert_eq!(members.len(), 3);
679 }
680
681 #[test]
682 fn scan_set_missing_key() {
683 let mut ks = Keyspace::new();
684 let (cursor, members) = ks.scan_set("missing", 0, 10, None).unwrap();
685 assert_eq!(cursor, 0);
686 assert!(members.is_empty());
687 }
688
689 #[test]
690 fn scan_set_wrong_type() {
691 let mut ks = Keyspace::new();
692 ks.set("s".into(), Bytes::from("string"), None, false, false);
693 assert!(ks.scan_set("s", 0, 10, None).is_err());
694 }
695
696 #[test]
697 fn scan_set_with_pattern() {
698 let mut ks = Keyspace::new();
699 ks.sadd("s", &["user:1".into(), "user:2".into(), "item:1".into()])
700 .unwrap();
701 let (_, members) = ks.scan_set("s", 0, 100, Some("user:*")).unwrap();
702 assert_eq!(members.len(), 2);
703 assert!(members.iter().all(|m| m.starts_with("user:")));
704 }
705
706 #[test]
707 fn scan_set_pagination() {
708 let mut ks = Keyspace::new();
709 let items: Vec<String> = (0..20).map(|i| format!("m{i}")).collect();
710 ks.sadd("s", &items).unwrap();
711
712 let mut collected = Vec::new();
713 let mut cursor = 0u64;
714 loop {
715 let (next, batch) = ks.scan_set("s", cursor, 5, None).unwrap();
716 collected.extend(batch);
717 if next == 0 {
718 break;
719 }
720 cursor = next;
721 }
722 assert_eq!(collected.len(), 20);
724 }
725
726 #[test]
729 fn sunion_basic() {
730 let mut ks = Keyspace::new();
731 ks.sadd("s1", &["a".into(), "b".into()]).unwrap();
732 ks.sadd("s2", &["b".into(), "c".into()]).unwrap();
733 let mut result = ks.sunion(&["s1".into(), "s2".into()]).unwrap();
734 result.sort();
735 assert_eq!(result, vec!["a", "b", "c"]);
736 }
737
738 #[test]
739 fn sunion_with_missing_key() {
740 let mut ks = Keyspace::new();
741 ks.sadd("s1", &["a".into()]).unwrap();
742 let mut result = ks.sunion(&["s1".into(), "missing".into()]).unwrap();
743 result.sort();
744 assert_eq!(result, vec!["a"]);
745 }
746
747 #[test]
748 fn sunion_empty_keys() {
749 let mut ks = Keyspace::new();
750 assert!(ks.sunion(&[]).unwrap().is_empty());
751 }
752
753 #[test]
754 fn sunion_wrong_type() {
755 let mut ks = Keyspace::new();
756 ks.sadd("s1", &["a".into()]).unwrap();
757 ks.set("str".into(), Bytes::from("val"), None, false, false);
758 assert!(ks.sunion(&["s1".into(), "str".into()]).is_err());
759 }
760
761 #[test]
764 fn sinter_basic() {
765 let mut ks = Keyspace::new();
766 ks.sadd("s1", &["a".into(), "b".into(), "c".into()])
767 .unwrap();
768 ks.sadd("s2", &["b".into(), "c".into(), "d".into()])
769 .unwrap();
770 let mut result = ks.sinter(&["s1".into(), "s2".into()]).unwrap();
771 result.sort();
772 assert_eq!(result, vec!["b", "c"]);
773 }
774
775 #[test]
776 fn sinter_missing_key_returns_empty() {
777 let mut ks = Keyspace::new();
778 ks.sadd("s1", &["a".into()]).unwrap();
779 let result = ks.sinter(&["s1".into(), "missing".into()]).unwrap();
780 assert!(result.is_empty());
781 }
782
783 #[test]
784 fn sinter_disjoint_sets() {
785 let mut ks = Keyspace::new();
786 ks.sadd("s1", &["a".into()]).unwrap();
787 ks.sadd("s2", &["b".into()]).unwrap();
788 let result = ks.sinter(&["s1".into(), "s2".into()]).unwrap();
789 assert!(result.is_empty());
790 }
791
792 #[test]
793 fn sinter_wrong_type() {
794 let mut ks = Keyspace::new();
795 ks.set("str".into(), Bytes::from("val"), None, false, false);
796 assert!(ks.sinter(&["str".into()]).is_err());
797 }
798
799 #[test]
802 fn sdiff_basic() {
803 let mut ks = Keyspace::new();
804 ks.sadd("s1", &["a".into(), "b".into(), "c".into()])
805 .unwrap();
806 ks.sadd("s2", &["b".into(), "d".into()]).unwrap();
807 let mut result = ks.sdiff(&["s1".into(), "s2".into()]).unwrap();
808 result.sort();
809 assert_eq!(result, vec!["a", "c"]);
810 }
811
812 #[test]
813 fn sdiff_missing_first_key() {
814 let mut ks = Keyspace::new();
815 ks.sadd("s2", &["a".into()]).unwrap();
816 let result = ks.sdiff(&["missing".into(), "s2".into()]).unwrap();
817 assert!(result.is_empty());
818 }
819
820 #[test]
821 fn sdiff_missing_second_key() {
822 let mut ks = Keyspace::new();
823 ks.sadd("s1", &["a".into(), "b".into()]).unwrap();
824 let mut result = ks.sdiff(&["s1".into(), "missing".into()]).unwrap();
825 result.sort();
826 assert_eq!(result, vec!["a", "b"]);
827 }
828
829 #[test]
832 fn sunionstore_basic() {
833 let mut ks = Keyspace::new();
834 ks.sadd("s1", &["a".into(), "b".into()]).unwrap();
835 ks.sadd("s2", &["b".into(), "c".into()]).unwrap();
836 let (count, _) = ks.sunionstore("dest", &["s1".into(), "s2".into()]).unwrap();
837 assert_eq!(count, 3);
838 let mut members = ks.smembers("dest").unwrap();
839 members.sort();
840 assert_eq!(members, vec!["a", "b", "c"]);
841 }
842
843 #[test]
844 fn sinterstore_basic() {
845 let mut ks = Keyspace::new();
846 ks.sadd("s1", &["a".into(), "b".into(), "c".into()])
847 .unwrap();
848 ks.sadd("s2", &["b".into(), "c".into(), "d".into()])
849 .unwrap();
850 let (count, _) = ks.sinterstore("dest", &["s1".into(), "s2".into()]).unwrap();
851 assert_eq!(count, 2);
852 let mut members = ks.smembers("dest").unwrap();
853 members.sort();
854 assert_eq!(members, vec!["b", "c"]);
855 }
856
857 #[test]
858 fn sdiffstore_basic() {
859 let mut ks = Keyspace::new();
860 ks.sadd("s1", &["a".into(), "b".into(), "c".into()])
861 .unwrap();
862 ks.sadd("s2", &["b".into()]).unwrap();
863 let (count, _) = ks.sdiffstore("dest", &["s1".into(), "s2".into()]).unwrap();
864 assert_eq!(count, 2);
865 }
866
867 #[test]
868 fn store_overwrites_destination() {
869 let mut ks = Keyspace::new();
870 ks.sadd("dest", &["old".into()]).unwrap();
871 ks.sadd("s1", &["new".into()]).unwrap();
872 ks.sunionstore("dest", &["s1".into()]).unwrap();
873 let members = ks.smembers("dest").unwrap();
874 assert_eq!(members, vec!["new"]);
875 }
876
877 #[test]
878 fn store_empty_result_deletes_dest() {
879 let mut ks = Keyspace::new();
880 ks.sadd("dest", &["old".into()]).unwrap();
881 ks.sinterstore("dest", &["missing".into()]).unwrap();
883 assert_eq!(ks.value_type("dest"), "none");
884 }
885
886 #[test]
889 fn srandmember_positive_count() {
890 let mut ks = Keyspace::new();
891 ks.sadd("s", &["a".into(), "b".into(), "c".into()]).unwrap();
892 let result = ks.srandmember("s", 2).unwrap();
893 assert_eq!(result.len(), 2);
894 for m in &result {
896 assert!(["a", "b", "c"].contains(&m.as_str()));
897 }
898 let unique: std::collections::HashSet<_> = result.iter().collect();
900 assert_eq!(unique.len(), 2);
901 }
902
903 #[test]
904 fn srandmember_count_larger_than_set() {
905 let mut ks = Keyspace::new();
906 ks.sadd("s", &["a".into(), "b".into()]).unwrap();
907 let result = ks.srandmember("s", 10).unwrap();
908 assert_eq!(result.len(), 2); }
910
911 #[test]
912 fn srandmember_negative_count_allows_duplicates() {
913 let mut ks = Keyspace::new();
914 ks.sadd("s", &["only".into()]).unwrap();
915 let result = ks.srandmember("s", -5).unwrap();
916 assert_eq!(result.len(), 5);
917 assert!(result.iter().all(|m| m == "only"));
918 }
919
920 #[test]
921 fn srandmember_zero_returns_empty() {
922 let mut ks = Keyspace::new();
923 ks.sadd("s", &["a".into()]).unwrap();
924 assert!(ks.srandmember("s", 0).unwrap().is_empty());
925 }
926
927 #[test]
928 fn srandmember_missing_key() {
929 let mut ks = Keyspace::new();
930 assert!(ks.srandmember("missing", 1).unwrap().is_empty());
931 }
932
933 #[test]
934 fn srandmember_wrong_type() {
935 let mut ks = Keyspace::new();
936 ks.set("str".into(), Bytes::from("val"), None, false, false);
937 assert!(ks.srandmember("str", 1).is_err());
938 }
939
940 #[test]
943 fn spop_basic() {
944 let mut ks = Keyspace::new();
945 ks.sadd("s", &["a".into(), "b".into(), "c".into()]).unwrap();
946 let result = ks.spop("s", 1).unwrap();
947 assert_eq!(result.len(), 1);
948 assert_eq!(ks.scard("s").unwrap(), 2);
949 }
950
951 #[test]
952 fn spop_all_members() {
953 let mut ks = Keyspace::new();
954 ks.sadd("s", &["a".into(), "b".into()]).unwrap();
955 let result = ks.spop("s", 10).unwrap();
956 assert_eq!(result.len(), 2);
957 assert_eq!(ks.value_type("s"), "none"); }
959
960 #[test]
961 fn spop_missing_key() {
962 let mut ks = Keyspace::new();
963 assert!(ks.spop("missing", 1).unwrap().is_empty());
964 }
965
966 #[test]
967 fn spop_wrong_type() {
968 let mut ks = Keyspace::new();
969 ks.set("str".into(), Bytes::from("val"), None, false, false);
970 assert!(ks.spop("str", 1).is_err());
971 }
972
973 #[test]
974 fn spop_zero_count() {
975 let mut ks = Keyspace::new();
976 ks.sadd("s", &["a".into()]).unwrap();
977 assert!(ks.spop("s", 0).unwrap().is_empty());
978 assert_eq!(ks.scard("s").unwrap(), 1);
979 }
980
981 #[test]
984 fn smismember_basic() {
985 let mut ks = Keyspace::new();
986 ks.sadd("s", &["a".into(), "c".into()]).unwrap();
987 let result = ks
988 .smismember("s", &["a".into(), "b".into(), "c".into()])
989 .unwrap();
990 assert_eq!(result, vec![true, false, true]);
991 }
992
993 #[test]
994 fn smismember_missing_key() {
995 let mut ks = Keyspace::new();
996 let result = ks.smismember("missing", &["a".into()]).unwrap();
997 assert_eq!(result, vec![false]);
998 }
999
1000 #[test]
1001 fn smismember_wrong_type() {
1002 let mut ks = Keyspace::new();
1003 ks.set("str".into(), Bytes::from("val"), None, false, false);
1004 assert!(ks.smismember("str", &["a".into()]).is_err());
1005 }
1006
1007 #[test]
1008 fn set_auto_deleted_when_empty() {
1009 let mut ks = Keyspace::new();
1010 ks.sadd("s", &["a".into(), "b".into()]).unwrap();
1011 assert_eq!(ks.len(), 1);
1012
1013 ks.srem("s", &["a".into(), "b".into()]).unwrap();
1015
1016 assert_eq!(ks.len(), 0);
1018 assert!(!ks.exists("s"));
1019 }
1020
1021 #[test]
1024 fn smove_moves_member() {
1025 let mut ks = Keyspace::new();
1026 ks.sadd("src", &["a".into(), "b".into()]).unwrap();
1027
1028 let moved = ks.smove("src", "dst", "a").unwrap();
1029 assert!(moved);
1030 assert!(!ks.sismember("src", "a").unwrap());
1031 assert!(ks.sismember("dst", "a").unwrap());
1032 assert_eq!(ks.scard("src").unwrap(), 1);
1033 assert_eq!(ks.scard("dst").unwrap(), 1);
1034 }
1035
1036 #[test]
1037 fn smove_missing_member_returns_false() {
1038 let mut ks = Keyspace::new();
1039 ks.sadd("src", &["x".into()]).unwrap();
1040
1041 let moved = ks.smove("src", "dst", "missing").unwrap();
1042 assert!(!moved);
1043 assert_eq!(ks.scard("src").unwrap(), 1);
1044 assert!(!ks.exists("dst"));
1045 }
1046
1047 #[test]
1048 fn smove_missing_source_returns_false() {
1049 let mut ks = Keyspace::new();
1050 let moved = ks.smove("nosrc", "dst", "m").unwrap();
1051 assert!(!moved);
1052 }
1053
1054 #[test]
1055 fn smove_removes_empty_source() {
1056 let mut ks = Keyspace::new();
1057 ks.sadd("src", &["only".into()]).unwrap();
1058
1059 ks.smove("src", "dst", "only").unwrap();
1060 assert!(!ks.exists("src"));
1062 assert_eq!(ks.scard("dst").unwrap(), 1);
1063 }
1064
1065 #[test]
1066 fn smove_wrong_type_source_returns_error() {
1067 let mut ks = Keyspace::new();
1068 ks.set("src".into(), Bytes::from("string"), None, false, false);
1069 assert!(ks.smove("src", "dst", "m").is_err());
1070 }
1071
1072 #[test]
1073 fn smove_wrong_type_destination_returns_error() {
1074 let mut ks = Keyspace::new();
1075 ks.sadd("src", &["m".into()]).unwrap();
1076 ks.set("dst".into(), Bytes::from("string"), None, false, false);
1077 assert!(ks.smove("src", "dst", "m").is_err());
1078 }
1079
1080 #[test]
1083 fn sintercard_basic() {
1084 let mut ks = Keyspace::new();
1085 ks.sadd("s1", &["a".into(), "b".into(), "c".into()])
1086 .unwrap();
1087 ks.sadd("s2", &["b".into(), "c".into(), "d".into()])
1088 .unwrap();
1089
1090 assert_eq!(ks.sintercard(&["s1".into(), "s2".into()], 0).unwrap(), 2);
1091 }
1092
1093 #[test]
1094 fn sintercard_with_limit() {
1095 let mut ks = Keyspace::new();
1096 ks.sadd("s1", &["a".into(), "b".into(), "c".into()])
1097 .unwrap();
1098 ks.sadd("s2", &["a".into(), "b".into(), "c".into()])
1099 .unwrap();
1100
1101 assert_eq!(ks.sintercard(&["s1".into(), "s2".into()], 2).unwrap(), 2);
1103 assert_eq!(ks.sintercard(&["s1".into(), "s2".into()], 0).unwrap(), 3);
1105 }
1106
1107 #[test]
1108 fn sintercard_missing_key_returns_zero() {
1109 let mut ks = Keyspace::new();
1110 ks.sadd("s1", &["a".into()]).unwrap();
1111
1112 assert_eq!(
1113 ks.sintercard(&["s1".into(), "missing".into()], 0).unwrap(),
1114 0
1115 );
1116 }
1117
1118 #[test]
1119 fn sintercard_wrong_type_returns_error() {
1120 let mut ks = Keyspace::new();
1121 ks.set("str".into(), Bytes::from("val"), None, false, false);
1122 assert!(ks.sintercard(&["str".into()], 0).is_err());
1123 }
1124}