1#![allow(deprecated)]
3
4mod impls;
5mod iter;
6
7pub use self::iter::{Difference, Drain, Intersection, Iter, SymmetricDifference, Union};
8use super::{ERR_INCONSISTENT_STATE, LookupMap};
9use crate::store::Vector;
10use crate::store::key::{Sha256, ToKey};
11use crate::{IntoStorageKey, env};
12use borsh::{BorshDeserialize, BorshSerialize};
13use near_sdk_macros::near;
14use std::borrow::Borrow;
15use std::fmt;
16
17type VecIndex = u32;
18
19#[near(inside_nearsdk)]
88pub struct IterableSet<T, H = Sha256>
89where
90 T: BorshSerialize + Ord,
91 H: ToKey,
92{
93 #[cfg_attr(not(feature = "abi"), borsh(bound(serialize = "", deserialize = "")))]
95 #[cfg_attr(
96 feature = "abi",
97 borsh(bound(serialize = "", deserialize = ""), schema(params = ""))
98 )]
99 elements: Vector<T>,
100 #[cfg_attr(not(feature = "abi"), borsh(bound(serialize = "", deserialize = "")))]
102 #[cfg_attr(
103 feature = "abi",
104 borsh(bound(serialize = "", deserialize = ""), schema(params = ""))
105 )]
106 index: LookupMap<T, VecIndex, H>,
107}
108
109impl<T, H> Drop for IterableSet<T, H>
110where
111 T: BorshSerialize + Ord,
112 H: ToKey,
113{
114 fn drop(&mut self) {
115 self.flush()
116 }
117}
118
119impl<T, H> fmt::Debug for IterableSet<T, H>
120where
121 T: BorshSerialize + Ord + BorshDeserialize + fmt::Debug,
122 H: ToKey,
123{
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 f.debug_struct("IterableSet")
126 .field("elements", &self.elements)
127 .field("index", &self.index)
128 .finish()
129 }
130}
131
132impl<T> IterableSet<T, Sha256>
133where
134 T: BorshSerialize + Ord,
135{
136 #[inline]
149 pub fn new<S>(prefix: S) -> Self
150 where
151 S: IntoStorageKey,
152 {
153 Self::with_hasher(prefix)
154 }
155}
156
157impl<T, H> IterableSet<T, H>
158where
159 T: BorshSerialize + Ord,
160 H: ToKey,
161{
162 pub fn with_hasher<S>(prefix: S) -> Self
172 where
173 S: IntoStorageKey,
174 {
175 let mut vec_key = prefix.into_storage_key();
176 let map_key = [vec_key.as_slice(), b"m"].concat();
177 vec_key.push(b'v');
178 Self { elements: Vector::new(vec_key), index: LookupMap::with_hasher(map_key) }
179 }
180
181 pub fn len(&self) -> u32 {
183 self.elements.len()
184 }
185
186 pub fn is_empty(&self) -> bool {
188 self.elements.is_empty()
189 }
190
191 pub fn clear(&mut self)
193 where
194 T: BorshDeserialize + Clone,
195 {
196 for e in self.elements.drain(..) {
197 self.index.set(e, None);
198 }
199 }
200
201 pub fn difference<'a>(&'a self, other: &'a IterableSet<T, H>) -> Difference<'a, T, H>
225 where
226 T: BorshDeserialize,
227 {
228 Difference::new(self, other)
229 }
230
231 pub fn symmetric_difference<'a>(
255 &'a self,
256 other: &'a IterableSet<T, H>,
257 ) -> SymmetricDifference<'a, T, H>
258 where
259 T: BorshDeserialize + Clone,
260 {
261 SymmetricDifference::new(self, other)
262 }
263
264 pub fn intersection<'a>(&'a self, other: &'a IterableSet<T, H>) -> Intersection<'a, T, H>
288 where
289 T: BorshDeserialize,
290 {
291 Intersection::new(self, other)
292 }
293
294 pub fn union<'a>(&'a self, other: &'a IterableSet<T, H>) -> Union<'a, T, H>
318 where
319 T: BorshDeserialize + Clone,
320 {
321 Union::new(self, other)
322 }
323
324 pub fn is_disjoint(&self, other: &IterableSet<T, H>) -> bool
346 where
347 T: BorshDeserialize + Clone,
348 {
349 if self.len() <= other.len() {
350 self.iter().all(|v| !other.contains(v))
351 } else {
352 other.iter().all(|v| !self.contains(v))
353 }
354 }
355
356 pub fn is_subset(&self, other: &IterableSet<T, H>) -> bool
378 where
379 T: BorshDeserialize + Clone,
380 {
381 if self.len() <= other.len() { self.iter().all(|v| other.contains(v)) } else { false }
382 }
383
384 pub fn is_superset(&self, other: &IterableSet<T, H>) -> bool
406 where
407 T: BorshDeserialize + Clone,
408 {
409 other.is_subset(self)
410 }
411
412 pub fn iter(&self) -> Iter<'_, T>
430 where
431 T: BorshDeserialize,
432 {
433 Iter::new(self)
434 }
435
436 pub fn drain(&mut self) -> Drain<'_, T, H>
456 where
457 T: BorshDeserialize,
458 {
459 Drain::new(self)
460 }
461
462 pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool
468 where
469 T: Borrow<Q>,
470 Q: BorshSerialize + ToOwned<Owned = T> + Ord,
471 {
472 self.index.contains_key(value)
473 }
474
475 pub fn insert(&mut self, value: T) -> bool
481 where
482 T: Clone + BorshDeserialize,
483 {
484 let entry = self.index.get_mut_inner(&value);
485 if entry.value_mut().is_some() {
486 false
487 } else {
488 self.elements.push(value);
489 let element_index = self.elements.len() - 1;
490 entry.replace(Some(element_index));
491 true
492 }
493 }
494
495 pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool
507 where
508 T: Borrow<Q> + BorshDeserialize + Clone,
509 Q: BorshSerialize + ToOwned<Owned = T> + Ord,
510 {
511 match self.index.remove(value) {
512 Some(element_index) => {
513 let last_index = self.elements.len() - 1;
514 let _ = self.elements.swap_remove(element_index);
515
516 match element_index {
517 x if x == last_index => {}
519 _ => {
521 let element = self
522 .elements
523 .get(element_index)
524 .unwrap_or_else(|| env::panic_str(ERR_INCONSISTENT_STATE));
525 self.index.set(element.clone(), Some(element_index));
526 }
527 }
528
529 true
530 }
531 None => false,
532 }
533 }
534
535 pub fn flush(&mut self) {
539 self.elements.flush();
540 self.index.flush();
541 }
542}
543
544#[cfg(not(target_arch = "wasm32"))]
545#[cfg(test)]
546mod tests {
547 use crate::store::IterableSet;
548 use crate::test_utils::test_env::setup_free;
549 use arbitrary::{Arbitrary, Unstructured};
550 use borsh::{BorshDeserialize, to_vec};
551 use rand::RngCore;
552 use rand::SeedableRng;
553 use std::collections::HashSet;
554
555 #[test]
556 fn basic_functionality() {
557 let mut set = IterableSet::new(b"b");
558 assert!(set.is_empty());
559 assert!(set.insert("test".to_string()));
560 assert!(set.contains("test"));
561 assert_eq!(set.len(), 1);
562
563 assert!(set.remove("test"));
564 assert_eq!(set.len(), 0);
565 }
566
567 #[test]
568 fn set_iterator() {
569 let mut set = IterableSet::new(b"b");
570
571 set.insert(0u8);
572 set.insert(1);
573 set.insert(2);
574 set.insert(3);
575 set.remove(&1);
576 let iter = set.iter();
577 assert_eq!(iter.len(), 3);
578 assert_eq!(iter.collect::<Vec<_>>(), [(&0), (&3), (&2)]);
579
580 let mut iter = set.iter();
581 assert_eq!(iter.nth(2), Some(&2));
582 assert_eq!(iter.next(), None);
584
585 assert_eq!(set.drain().collect::<Vec<_>>(), [0, 3, 2]);
587 assert!(set.is_empty());
588 }
589
590 #[test]
591 fn test_drain() {
592 let mut s = IterableSet::new(b"m");
593 s.extend(1..100);
594
595 for _ in 0..20 {
597 assert_eq!(s.len(), 99);
598
599 for _ in s.drain() {}
600
601 #[allow(clippy::never_loop)]
602 for _ in &s {
603 panic!("s should be empty!");
604 }
605
606 assert_eq!(s.len(), 0);
607 assert!(s.is_empty());
608
609 s.extend(1..100);
610 }
611 }
612
613 #[test]
614 fn test_extend() {
615 let mut a = IterableSet::<u64>::new(b"m");
616 a.insert(1);
617
618 a.extend([2, 3, 4]);
619
620 assert_eq!(a.len(), 4);
621 assert!(a.contains(&1));
622 assert!(a.contains(&2));
623 assert!(a.contains(&3));
624 assert!(a.contains(&4));
625 }
626
627 #[test]
628 fn test_difference() {
629 let mut set1 = IterableSet::new(b"m");
630 set1.insert("a".to_string());
631 set1.insert("b".to_string());
632 set1.insert("c".to_string());
633 set1.insert("d".to_string());
634
635 let mut set2 = IterableSet::new(b"n");
636 set2.insert("b".to_string());
637 set2.insert("c".to_string());
638 set2.insert("e".to_string());
639
640 assert_eq!(
641 set1.difference(&set2).collect::<HashSet<_>>(),
642 ["a".to_string(), "d".to_string()].iter().collect::<HashSet<_>>()
643 );
644 assert_eq!(
645 set2.difference(&set1).collect::<HashSet<_>>(),
646 ["e".to_string()].iter().collect::<HashSet<_>>()
647 );
648 assert!(set1.difference(&set2).nth(1).is_some());
649 assert!(set1.difference(&set2).nth(2).is_none());
650 }
651
652 #[test]
653 fn test_difference_empty() {
654 let mut set1 = IterableSet::new(b"m");
655 set1.insert(1);
656 set1.insert(2);
657 set1.insert(3);
658
659 let mut set2 = IterableSet::new(b"n");
660 set2.insert(3);
661 set2.insert(1);
662 set2.insert(2);
663 set2.insert(4);
664
665 assert_eq!(set1.difference(&set2).collect::<HashSet<_>>(), HashSet::new());
666 }
667
668 #[test]
669 fn test_symmetric_difference() {
670 let mut set1 = IterableSet::new(b"m");
671 set1.insert("a".to_string());
672 set1.insert("b".to_string());
673 set1.insert("c".to_string());
674
675 let mut set2 = IterableSet::new(b"n");
676 set2.insert("b".to_string());
677 set2.insert("c".to_string());
678 set2.insert("d".to_string());
679
680 assert_eq!(
681 set1.symmetric_difference(&set2).collect::<HashSet<_>>(),
682 ["a".to_string(), "d".to_string()].iter().collect::<HashSet<_>>()
683 );
684 assert_eq!(
685 set2.symmetric_difference(&set1).collect::<HashSet<_>>(),
686 ["a".to_string(), "d".to_string()].iter().collect::<HashSet<_>>()
687 );
688 }
689
690 #[test]
691 fn test_symmetric_difference_empty() {
692 let mut set1 = IterableSet::new(b"m");
693 set1.insert(1);
694 set1.insert(2);
695 set1.insert(3);
696
697 let mut set2 = IterableSet::new(b"n");
698 set2.insert(3);
699 set2.insert(1);
700 set2.insert(2);
701
702 assert_eq!(set1.symmetric_difference(&set2).collect::<HashSet<_>>(), HashSet::new());
703 }
704
705 #[test]
706 fn test_intersection() {
707 let mut set1 = IterableSet::new(b"m");
708 set1.insert("a".to_string());
709 set1.insert("b".to_string());
710 set1.insert("c".to_string());
711
712 let mut set2 = IterableSet::new(b"n");
713 set2.insert("b".to_string());
714 set2.insert("c".to_string());
715 set2.insert("d".to_string());
716
717 assert_eq!(
718 set1.intersection(&set2).collect::<HashSet<_>>(),
719 ["b".to_string(), "c".to_string()].iter().collect::<HashSet<_>>()
720 );
721 assert_eq!(
722 set2.intersection(&set1).collect::<HashSet<_>>(),
723 ["b".to_string(), "c".to_string()].iter().collect::<HashSet<_>>()
724 );
725 assert!(set1.intersection(&set2).nth(1).is_some());
726 assert!(set1.intersection(&set2).nth(2).is_none());
727 }
728
729 #[test]
730 fn test_intersection_empty() {
731 let mut set1 = IterableSet::new(b"m");
732 set1.insert(1);
733 set1.insert(2);
734 set1.insert(3);
735
736 let mut set2 = IterableSet::new(b"n");
737 set2.insert(4);
738 set2.insert(6);
739 set2.insert(5);
740
741 assert_eq!(set1.intersection(&set2).collect::<HashSet<_>>(), HashSet::new());
742 }
743
744 #[test]
745 fn test_union() {
746 let mut set1 = IterableSet::new(b"m");
747 set1.insert("a".to_string());
748 set1.insert("b".to_string());
749 set1.insert("c".to_string());
750
751 let mut set2 = IterableSet::new(b"n");
752 set2.insert("b".to_string());
753 set2.insert("c".to_string());
754 set2.insert("d".to_string());
755
756 assert_eq!(
757 set1.union(&set2).collect::<HashSet<_>>(),
758 ["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string()]
759 .iter()
760 .collect::<HashSet<_>>()
761 );
762 assert_eq!(
763 set2.union(&set1).collect::<HashSet<_>>(),
764 ["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string()]
765 .iter()
766 .collect::<HashSet<_>>()
767 );
768 }
769
770 #[test]
771 fn test_union_empty() {
772 let set1 = IterableSet::<u64>::new(b"m");
773 let set2 = IterableSet::<u64>::new(b"n");
774
775 assert_eq!(set1.union(&set2).collect::<HashSet<_>>(), HashSet::new());
776 }
777
778 #[test]
779 fn test_subset_and_superset() {
780 let mut a = IterableSet::new(b"m");
781 assert!(a.insert(0));
782 assert!(a.insert(50));
783 assert!(a.insert(110));
784 assert!(a.insert(70));
785
786 let mut b = IterableSet::new(b"n");
787 assert!(b.insert(0));
788 assert!(b.insert(70));
789 assert!(b.insert(190));
790 assert!(b.insert(2500));
791 assert!(b.insert(110));
792 assert!(b.insert(2000));
793
794 assert!(!a.is_subset(&b));
795 assert!(!a.is_superset(&b));
796 assert!(!b.is_subset(&a));
797 assert!(!b.is_superset(&a));
798
799 assert!(b.insert(50));
800
801 assert!(a.is_subset(&b));
802 assert!(!a.is_superset(&b));
803 assert!(!b.is_subset(&a));
804 assert!(b.is_superset(&a));
805 }
806
807 #[test]
808 fn test_disjoint() {
809 let mut xs = IterableSet::new(b"m");
810 let mut ys = IterableSet::new(b"n");
811
812 assert!(xs.is_disjoint(&ys));
813 assert!(ys.is_disjoint(&xs));
814
815 assert!(xs.insert(50));
816 assert!(ys.insert(110));
817 assert!(xs.is_disjoint(&ys));
818 assert!(ys.is_disjoint(&xs));
819
820 assert!(xs.insert(70));
821 assert!(xs.insert(190));
822 assert!(xs.insert(40));
823 assert!(ys.insert(20));
824 assert!(ys.insert(-110));
825 assert!(xs.is_disjoint(&ys));
826 assert!(ys.is_disjoint(&xs));
827
828 assert!(ys.insert(70));
829 assert!(!xs.is_disjoint(&ys));
830 assert!(!ys.is_disjoint(&xs));
831 }
832
833 #[derive(Arbitrary, Debug)]
834 enum Op {
835 Insert(u8),
836 Remove(u8),
837 Flush,
838 Restore,
839 Contains(u8),
840 }
841
842 #[test]
843 fn arbitrary() {
844 setup_free();
845
846 let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(0);
847 let mut buf = vec![0; 4096];
848 for _ in 0..512 {
849 crate::mock::with_mocked_blockchain(|b| b.take_storage());
851 rng.fill_bytes(&mut buf);
852
853 let mut us = IterableSet::new(b"l");
854 let mut hs = HashSet::new();
855 let u = Unstructured::new(&buf);
856 if let Ok(ops) = Vec::<Op>::arbitrary_take_rest(u) {
857 for op in ops {
858 match op {
859 Op::Insert(v) => {
860 let r1 = us.insert(v);
861 let r2 = hs.insert(v);
862 assert_eq!(r1, r2)
863 }
864 Op::Remove(v) => {
865 let r1 = us.remove(&v);
866 let r2 = hs.remove(&v);
867 assert_eq!(r1, r2)
868 }
869 Op::Flush => {
870 us.flush();
871 }
872 Op::Restore => {
873 let serialized = to_vec(&us).unwrap();
874 us = IterableSet::deserialize(&mut serialized.as_slice()).unwrap();
875 }
876 Op::Contains(v) => {
877 let r1 = us.contains(&v);
878 let r2 = hs.contains(&v);
879 assert_eq!(r1, r2)
880 }
881 }
882 }
883 }
884 }
885 }
886
887 #[cfg(feature = "abi")]
888 #[test]
889 fn test_borsh_schema() {
890 #[derive(
891 borsh::BorshSerialize, borsh::BorshDeserialize, PartialEq, Eq, PartialOrd, Ord,
892 )]
893 struct NoSchemaStruct;
894
895 assert_eq!(
896 "IterableSet".to_string(),
897 <IterableSet<NoSchemaStruct> as borsh::BorshSchema>::declaration()
898 );
899 let mut defs = Default::default();
900 <IterableSet<NoSchemaStruct> as borsh::BorshSchema>::add_definitions_recursively(&mut defs);
901
902 insta::assert_snapshot!(format!("{:#?}", defs));
903 }
904
905 #[test]
906 fn test_drain_next_back_removes_from_index() {
907 let mut set = IterableSet::new(b"t");
908
909 for i in 0..10 {
911 set.insert(i);
912 }
913
914 let mut drain = set.drain();
916 let last = drain.next_back().unwrap();
917 drop(drain);
918
919 assert!(
922 !set.contains(&last),
923 "Element {} was drained but contains() returns true (stale index)",
924 last
925 );
926
927 assert!(
930 set.insert(last),
931 "Cannot re-insert element {} after draining it (stale index)",
932 last
933 );
934 }
935
936 #[test]
937 fn test_drain_bidirectional() {
938 let mut set = IterableSet::new(b"t");
939 for i in 0..10 {
940 set.insert(i);
941 }
942
943 let mut drain = set.drain();
944 let first = drain.next().unwrap();
945 let last = drain.next_back().unwrap();
946 drop(drain);
947
948 assert!(!set.contains(&first), "Element {} from next() still in index", first);
950 assert!(!set.contains(&last), "Element {} from next_back() still in index", last);
951
952 assert!(set.insert(first));
954 assert!(set.insert(last));
955 }
956
957 #[test]
958 fn test_drain_partial_consumption_clears_index() {
959 let mut set = IterableSet::new(b"t");
960 for i in 1..=3 {
961 set.insert(i);
962 }
963
964 {
965 let mut drain = set.drain();
966 drain.next().unwrap();
967 }
969
970 assert_eq!(set.len(), 0);
971 assert!(set.is_empty());
972
973 for i in 1..=3 {
974 assert!(!set.contains(&i), "stale index entry for {} after partial drain", i);
975 assert!(!set.remove(&i), "remove({}) should be a no-op on an empty set", i);
976 assert!(set.insert(i), "re-insert of {} should succeed after drain", i);
977 }
978 assert_eq!(set.len(), 3);
979 }
980
981 #[test]
982 fn test_drain_unconsumed_clears_index() {
983 let mut set = IterableSet::new(b"t");
984 for i in 1..=3 {
985 set.insert(i);
986 }
987
988 set.drain(); assert!(set.is_empty());
991 for i in 1..=3 {
992 assert!(!set.contains(&i), "stale index entry for {} after unconsumed drain", i);
993 }
994 }
995
996 #[test]
997 fn test_drain_mixed_direction_partial_consumption() {
998 let mut set = IterableSet::new(b"t");
999 for i in 1..=5 {
1000 set.insert(i);
1001 }
1002
1003 {
1004 let mut drain = set.drain();
1005 drain.next().unwrap();
1006 drain.next_back().unwrap();
1007 }
1009
1010 assert!(set.is_empty());
1011 for i in 1..=5 {
1012 assert!(!set.contains(&i), "stale index entry for {} after mixed-direction drain", i);
1013 assert!(set.insert(i), "re-insert of {} should succeed after drain", i);
1014 }
1015 assert_eq!(set.len(), 5);
1016 }
1017}