1mod entry;
2mod impls;
3
4use std::borrow::Borrow;
5use std::fmt;
6
7use borsh::{BorshDeserialize, BorshSerialize};
8use once_cell::unsync::OnceCell;
9use unc_sdk_macros::unc;
10
11use super::ERR_NOT_EXIST;
12use crate::store::key::{Identity, ToKey};
13use crate::utils::{EntryState, StableMap};
14use crate::{env, CacheEntry, IntoStorageKey};
15
16pub use entry::{Entry, OccupiedEntry, VacantEntry};
17
18const ERR_ELEMENT_DESERIALIZATION: &str = "Cannot deserialize element";
19const ERR_ELEMENT_SERIALIZATION: &str = "Cannot serialize element";
20
21#[unc(inside_uncsdk)]
81pub struct LookupMap<K, V, H = Identity>
82where
83 K: BorshSerialize + Ord,
84 V: BorshSerialize,
85 H: ToKey,
86{
87 prefix: Box<[u8]>,
88 #[borsh(skip, bound(deserialize = ""))] cache: StableMap<K, EntryAndHash<V, H::KeyType>>,
93}
94
95struct EntryAndHash<V, T> {
96 value: OnceCell<CacheEntry<V>>,
97 hash: OnceCell<T>,
98}
99
100impl<V, T> Default for EntryAndHash<V, T> {
101 fn default() -> Self {
102 Self { value: Default::default(), hash: Default::default() }
103 }
104}
105
106impl<K, V, H> Drop for LookupMap<K, V, H>
107where
108 K: BorshSerialize + Ord,
109 V: BorshSerialize,
110 H: ToKey,
111{
112 fn drop(&mut self) {
113 self.flush()
114 }
115}
116
117impl<K, V, H> fmt::Debug for LookupMap<K, V, H>
118where
119 K: BorshSerialize + Ord,
120 V: BorshSerialize,
121 H: ToKey,
122{
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 f.debug_struct("LookupMap").field("prefix", &self.prefix).finish()
125 }
126}
127
128impl<K, V> LookupMap<K, V, Identity>
129where
130 K: BorshSerialize + Ord,
131 V: BorshSerialize,
132{
133 #[inline]
146 pub fn new<S>(prefix: S) -> Self
147 where
148 S: IntoStorageKey,
149 {
150 Self::with_hasher(prefix)
151 }
152}
153
154impl<K, V, H> LookupMap<K, V, H>
155where
156 K: BorshSerialize + Ord,
157 V: BorshSerialize,
158 H: ToKey,
159{
160 pub fn with_hasher<S>(prefix: S) -> Self
169 where
170 S: IntoStorageKey,
171 {
172 Self { prefix: prefix.into_storage_key().into_boxed_slice(), cache: Default::default() }
173 }
174
175 pub fn set(&mut self, key: K, value: Option<V>) {
196 let entry = self.cache.get_mut(key);
197 match entry.value.get_mut() {
198 Some(entry) => *entry.value_mut() = value,
199 None => {
200 let _ = entry.value.set(CacheEntry::new_modified(value));
201 }
202 }
203 }
204}
205
206impl<K, V, H> LookupMap<K, V, H>
207where
208 K: BorshSerialize + Ord,
209 V: BorshSerialize + BorshDeserialize,
210 H: ToKey,
211{
212 fn deserialize_element(bytes: &[u8]) -> V {
213 V::try_from_slice(bytes).unwrap_or_else(|_| env::panic_str(ERR_ELEMENT_DESERIALIZATION))
214 }
215
216 fn load_element<Q: ?Sized>(prefix: &[u8], key: &Q) -> (H::KeyType, Option<V>)
217 where
218 Q: BorshSerialize,
219 K: Borrow<Q>,
220 {
221 let key = H::to_key(prefix, key, &mut Vec::new());
222 let storage_bytes = env::storage_read(key.as_ref());
223 (key, storage_bytes.as_deref().map(Self::deserialize_element))
224 }
225
226 pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
243 where
244 K: Borrow<Q>,
245 Q: BorshSerialize + ToOwned<Owned = K>,
246 {
247 let cached = self.cache.get(k.to_owned());
249 let entry = cached.value.get_or_init(|| {
250 let (key, element) = Self::load_element(&self.prefix, k);
251 let _ = cached.hash.set(key);
252 CacheEntry::new_cached(element)
253 });
254 entry.value().as_ref()
255 }
256
257 pub(crate) fn get_mut_inner<Q: ?Sized>(&mut self, k: &Q) -> &mut CacheEntry<V>
258 where
259 K: Borrow<Q>,
260 Q: BorshSerialize + ToOwned<Owned = K>,
261 {
262 let prefix = &self.prefix;
263 let entry = self.cache.get_mut(k.to_owned());
265 entry.value.get_or_init(|| {
266 let (key, value) = Self::load_element(prefix, k);
267 let _ = entry.hash.set(key);
268 CacheEntry::new_cached(value)
269 });
270 let entry = entry.value.get_mut().unwrap_or_else(|| env::abort());
271 entry
272 }
273
274 pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
292 where
293 K: Borrow<Q>,
294 Q: BorshSerialize + ToOwned<Owned = K>,
295 {
296 self.get_mut_inner(k).value_mut().as_mut()
297 }
298
299 pub fn insert(&mut self, k: K, v: V) -> Option<V>
320 where
321 K: Clone,
322 {
323 self.get_mut_inner(&k).replace(Some(v))
324 }
325
326 pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
342 where
343 K: Borrow<Q>,
344 Q: BorshSerialize + ToOwned<Owned = K> + Ord,
345 {
346 let contains = self
348 .cache
349 .map_value_ref(k, |v| v.value.get().and_then(|s| s.value().as_ref()).is_some());
350 if let Some(is_some) = contains {
351 return is_some;
352 }
353
354 let storage_key = H::to_key(&self.prefix, k, &mut Vec::new());
356 let contains = env::storage_has_key(storage_key.as_ref());
357
358 if !contains {
359 let cache = self.cache.get(k.to_owned());
361 let _ = cache.value.set(CacheEntry::new_cached(None));
362 let _ = cache.hash.set(storage_key);
363 }
364 contains
365 }
366
367 pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
384 where
385 K: Borrow<Q>,
386 Q: BorshSerialize + ToOwned<Owned = K>,
387 {
388 self.get_mut_inner(k).replace(None)
389 }
390
391 pub fn entry(&mut self, key: K) -> Entry<K, V>
408 where
409 K: Clone,
410 {
411 let entry = self.get_mut_inner(&key);
412 if entry.value().is_some() {
413 Entry::Occupied(OccupiedEntry { key, entry })
415 } else {
416 Entry::Vacant(VacantEntry { key, entry })
418 }
419 }
420}
421
422impl<K, V, H> LookupMap<K, V, H>
423where
424 K: BorshSerialize + Ord,
425 V: BorshSerialize,
426 H: ToKey,
427{
428 pub fn flush(&mut self) {
432 let mut buf = Vec::new();
433 for (k, v) in self.cache.inner().iter_mut() {
434 if let Some(val) = v.value.get_mut() {
435 if val.is_modified() {
436 let prefix = &self.prefix;
437 let key = v.hash.get_or_init(|| {
438 buf.clear();
439 H::to_key(prefix, k, &mut buf)
440 });
441 match val.value().as_ref() {
442 Some(modified) => {
443 buf.clear();
444 BorshSerialize::serialize(modified, &mut buf)
445 .unwrap_or_else(|_| env::panic_str(ERR_ELEMENT_SERIALIZATION));
446 env::storage_write(key.as_ref(), &buf);
447 }
448 None => {
449 env::storage_remove(key.as_ref());
451 }
452 }
453
454 val.replace_state(EntryState::Cached);
457 }
458 }
459 }
460 }
461}
462
463#[cfg(not(target_arch = "wasm32"))]
464#[cfg(test)]
465mod tests {
466 use super::LookupMap;
467 use crate::env;
468 use crate::store::key::{Keccak256, ToKey};
469 use crate::test_utils::test_env::setup_free;
470 use arbitrary::{Arbitrary, Unstructured};
471 use rand::seq::SliceRandom;
472 use rand::RngCore;
473 use rand::{Rng, SeedableRng};
474 use std::collections::HashMap;
475
476 #[test]
477 fn test_insert() {
478 let mut map = LookupMap::new(b"m");
479 let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(0);
480 for _ in 0..100 {
481 let key = rng.gen::<u64>();
482 let value = rng.gen::<u64>();
483 map.insert(key, value);
484 assert_eq!(*map.get(&key).unwrap(), value);
485 }
486 }
487
488 #[test]
489 fn test_insert_has_key() {
490 let mut map = LookupMap::new(b"m");
491 let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(0);
492 let mut key_to_value = HashMap::new();
493 for _ in 0..100 {
494 let key = rng.gen::<u64>();
495 let value = rng.gen::<u64>();
496 map.insert(key, value);
497 key_to_value.insert(key, value);
498 }
499 for _ in 0..100 {
501 let key = rng.gen::<u64>();
502 assert_eq!(map.contains_key(&key), key_to_value.contains_key(&key));
503 }
504 for (key, _) in key_to_value.iter() {
506 assert!(map.contains_key(key));
507 }
508 }
509
510 #[test]
511 fn test_insert_remove() {
512 let mut map = LookupMap::new(b"m");
513 let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(1);
514 let mut keys = vec![];
515 let mut key_to_value = HashMap::new();
516 for _ in 0..100 {
517 let key = rng.gen::<u64>();
518 let value = rng.gen::<u64>();
519 keys.push(key);
520 key_to_value.insert(key, value);
521 map.insert(key, value);
522 }
523 keys.shuffle(&mut rng);
524 for key in keys {
525 let actual = map.remove(&key).unwrap();
526 assert_eq!(actual, key_to_value[&key]);
527 }
528 }
529
530 #[test]
531 fn test_remove_last_reinsert() {
532 let mut map = LookupMap::new(b"m");
533 let key1 = 1u64;
534 let value1 = 2u64;
535 map.insert(key1, value1);
536 let key2 = 3u64;
537 let value2 = 4u64;
538 map.insert(key2, value2);
539
540 let actual_value2 = map.remove(&key2).unwrap();
541 assert_eq!(actual_value2, value2);
542
543 let actual_insert_value2 = map.insert(key2, value2);
544 assert_eq!(actual_insert_value2, None);
545 }
546
547 #[test]
548 fn test_insert_override_remove() {
549 let mut map = LookupMap::new(b"m");
550 let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(2);
551 let mut keys = vec![];
552 let mut key_to_value = HashMap::new();
553 for _ in 0..100 {
554 let key = rng.gen::<u64>();
555 let value = rng.gen::<u64>();
556 keys.push(key);
557 key_to_value.insert(key, value);
558 map.insert(key, value);
559 }
560 keys.shuffle(&mut rng);
561 for key in &keys {
562 let value = rng.gen::<u64>();
563 let actual = map.insert(*key, value).unwrap();
564 assert_eq!(actual, key_to_value[key]);
565 key_to_value.insert(*key, value);
566 }
567 keys.shuffle(&mut rng);
568 for key in keys {
569 let actual = map.remove(&key).unwrap();
570 assert_eq!(actual, key_to_value[&key]);
571 }
572 }
573
574 #[test]
575 fn test_get_non_existent() {
576 let mut map = LookupMap::new(b"m");
577 let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(3);
578 let mut key_to_value = HashMap::new();
579 for _ in 0..500 {
580 let key = rng.gen::<u64>() % 20_000;
581 let value = rng.gen::<u64>();
582 key_to_value.insert(key, value);
583 map.insert(key, value);
584 }
585 for _ in 0..500 {
586 let key = rng.gen::<u64>() % 20_000;
587 assert_eq!(map.get(&key), key_to_value.get(&key));
588 }
589 }
590
591 #[test]
592 fn size_of_map() {
593 assert_eq!(core::mem::size_of::<LookupMap<u8, u8>>(), 48);
594 }
595
596 #[test]
597 fn identity_compat_v1() {
598 use crate::collections::LookupMap as LM1;
599
600 let mut lm1 = LM1::new(b"m");
601 lm1.insert(&8u8, &"Some value".to_string());
602 lm1.insert(&0, &"Other".to_string());
603 assert_eq!(lm1.get(&8), Some("Some value".to_string()));
604
605 let mut lm2 = LookupMap::new(b"m");
606 assert_eq!(lm2.get(&8u8), Some(&"Some value".to_string()));
607 assert_eq!(lm2.remove(&0), Some("Other".to_string()));
608 *lm2.get_mut(&8).unwrap() = "New".to_string();
609 lm2.flush();
610
611 assert!(!lm1.contains_key(&0));
612 assert_eq!(lm1.get(&8), Some("New".to_string()));
613 }
614
615 #[test]
616 fn test_extend() {
617 let mut map = LookupMap::new(b"m");
618 let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(4);
619 let mut key_to_value = HashMap::new();
620 for _ in 0..100 {
621 let key = rng.gen::<u64>();
622 let value = rng.gen::<u64>();
623 key_to_value.insert(key, value);
624 map.insert(key, value);
625 }
626 for _ in 0..10 {
627 let mut tmp = vec![];
628 for _ in 0..=(rng.gen::<u64>() % 20 + 1) {
629 let key = rng.gen::<u64>();
630 let value = rng.gen::<u64>();
631 tmp.push((key, value));
632 }
633 key_to_value.extend(tmp.iter().cloned());
634 map.extend(tmp.iter().cloned());
635 }
636
637 for (key, value) in key_to_value {
638 assert_eq!(*map.get(&key).unwrap(), value);
639 }
640 }
641
642 #[test]
643 fn flush_on_drop() {
644 let mut map = LookupMap::<_, _, Keccak256>::with_hasher(b"m");
645
646 map.set(5u8, Some(8u8));
648
649 assert_eq!(map[&5], 8);
651
652 let storage_key = Keccak256::to_key(b"m", &5, &mut Vec::new());
653 assert!(!env::storage_has_key(&storage_key));
654
655 drop(map);
656
657 let dup_map = LookupMap::<u8, u8, Keccak256>::with_hasher(b"m");
658
659 assert_eq!(dup_map[&5], 8);
661 }
662
663 #[derive(Arbitrary, Debug)]
664 enum Op {
665 Insert(u8, u8),
666 Set(u8, Option<u8>),
667 Remove(u8),
668 Flush,
669 Restore,
670 Get(u8),
671 }
672
673 #[test]
674 fn arbitrary() {
675 setup_free();
676
677 let mut rng = rand_xorshift::XorShiftRng::seed_from_u64(0);
678 let mut buf = vec![0; 4096];
679 for _ in 0..512 {
680 crate::mock::with_mocked_blockchain(|b| b.take_storage());
682 rng.fill_bytes(&mut buf);
683
684 let mut lm = LookupMap::new(b"l");
685 let mut hm = HashMap::new();
686 let u = Unstructured::new(&buf);
687 if let Ok(ops) = Vec::<Op>::arbitrary_take_rest(u) {
688 for op in ops {
689 match op {
690 Op::Insert(k, v) => {
691 let r1 = lm.insert(k, v);
692 let r2 = hm.insert(k, v);
693 assert_eq!(r1, r2)
694 }
695 Op::Set(k, v) => {
696 lm.set(k, v);
697
698 if let Some(val) = v {
699 hm.insert(k, val);
700 } else {
701 hm.remove(&k);
702 }
703
704 assert_eq!(lm.get(&k), hm.get(&k));
706 }
707 Op::Remove(k) => {
708 let r1 = lm.remove(&k);
709 let r2 = hm.remove(&k);
710 assert_eq!(r1, r2)
711 }
712 Op::Flush => {
713 lm.flush();
714 }
715 Op::Restore => {
716 lm = LookupMap::new(b"l");
717 }
718 Op::Get(k) => {
719 let r1 = lm.get(&k);
720 let r2 = hm.get(&k);
721 assert_eq!(r1, r2)
722 }
723 }
724 }
725 }
726 }
727 }
728}
729
730#[cfg(test)]
732mod test_map {
733 use super::Entry::{Occupied, Vacant};
734 use crate::store::LookupMap;
735 use borsh::{BorshDeserialize, BorshSerialize};
736 use std::cell::RefCell;
737 use std::usize;
738 use std::vec::Vec;
739
740 #[test]
741 fn test_insert() {
742 let mut m = LookupMap::new(b"b");
743 assert!(m.insert(1, 2).is_none());
744 assert!(m.insert(2, 4).is_none());
745 assert_eq!(*m.get(&1).unwrap(), 2);
746 assert_eq!(*m.get(&2).unwrap(), 4);
747 }
748
749 thread_local! { static DROP_VECTOR: RefCell<Vec<i32>> = const { RefCell::new(Vec::new()) }}
750
751 #[derive(Hash, PartialEq, Eq, BorshSerialize, BorshDeserialize, PartialOrd, Ord)]
752 struct Droppable {
753 k: usize,
754 }
755
756 impl Droppable {
757 fn new(k: usize) -> Droppable {
758 DROP_VECTOR.with(|slot| {
759 slot.borrow_mut()[k] += 1;
760 });
761
762 Droppable { k }
763 }
764 }
765
766 impl Drop for Droppable {
767 fn drop(&mut self) {
768 DROP_VECTOR.with(|slot| {
769 slot.borrow_mut()[self.k] -= 1;
770 });
771 }
772 }
773
774 impl Clone for Droppable {
775 fn clone(&self) -> Self {
776 Droppable::new(self.k)
777 }
778 }
779
780 #[test]
781 fn test_drops() {
782 DROP_VECTOR.with(|slot| {
783 *slot.borrow_mut() = vec![0; 200];
784 });
785
786 {
787 let mut m = LookupMap::new(b"b");
788
789 DROP_VECTOR.with(|v| {
790 for i in 0..200 {
791 assert_eq!(v.borrow()[i], 0);
792 }
793 });
794
795 for i in 0..100 {
796 let d1 = Droppable::new(i);
797 let d2 = Droppable::new(i + 100);
798 m.insert(d1, d2);
799 }
800
801 DROP_VECTOR.with(|v| {
802 for i in 0..100 {
803 assert_eq!(v.borrow()[i], 1);
804 }
805 });
806
807 for i in 0..50 {
808 let k = Droppable::new(i);
809 let v = m.remove(&k);
810
811 assert!(v.is_some());
812
813 DROP_VECTOR.with(|v| {
814 assert_eq!(v.borrow()[i], 2);
815 assert_eq!(v.borrow()[i + 100], 1);
816 });
817 }
818
819 DROP_VECTOR.with(|v| {
820 for i in 0..50 {
821 assert_eq!(v.borrow()[i], 1);
822 assert_eq!(v.borrow()[i + 100], 0);
823 }
824
825 for i in 50..100 {
826 assert_eq!(v.borrow()[i], 1);
827 assert_eq!(v.borrow()[i + 100], 1);
828 }
829 });
830 }
831
832 DROP_VECTOR.with(|v| {
833 for i in 0..200 {
834 assert_eq!(v.borrow()[i], 0);
835 }
836 });
837 }
838
839 #[test]
840 fn test_empty_remove() {
841 let mut m: LookupMap<i32, bool> = LookupMap::new(b"b");
842 assert_eq!(m.remove(&0), None);
843 }
844
845 #[test]
846 fn test_empty_entry() {
847 let mut m: LookupMap<i32, bool> = LookupMap::new(b"b");
848 match m.entry(0) {
849 Occupied(_) => panic!(),
850 Vacant(_) => {}
851 }
852 assert!(*m.entry(0).or_insert(true));
853 }
854
855 #[test]
856 #[cfg_attr(miri, ignore)] fn test_lots_of_insertions() {
858 let mut m = LookupMap::new(b"b");
859
860 for _ in 0..10 {
863 for i in 1..1001 {
864 assert!(m.insert(i, i).is_none());
865
866 for j in 1..=i {
867 let r = m.get(&j);
868 assert_eq!(r, Some(&j));
869 }
870
871 for j in i + 1..1001 {
872 let r = m.get(&j);
873 assert_eq!(r, None);
874 }
875 }
876
877 for i in 1001..2001 {
878 assert!(!m.contains_key(&i));
879 }
880
881 for i in 1..1001 {
883 assert!(m.remove(&i).is_some());
884
885 for j in 1..=i {
886 assert!(!m.contains_key(&j));
887 }
888
889 for j in i + 1..1001 {
890 assert!(m.contains_key(&j));
891 }
892 }
893
894 for i in 1..1001 {
895 assert!(!m.contains_key(&i));
896 }
897
898 for i in 1..1001 {
899 assert!(m.insert(i, i).is_none());
900 }
901
902 for i in (1..1001).rev() {
904 assert!(m.remove(&i).is_some());
905
906 for j in i..1001 {
907 assert!(!m.contains_key(&j));
908 }
909
910 for j in 1..i {
911 assert!(m.contains_key(&j));
912 }
913 }
914 }
915 }
916
917 #[test]
918 fn test_find_mut() {
919 let mut m = LookupMap::new(b"b");
920 assert!(m.insert(1, 12).is_none());
921 assert!(m.insert(2, 8).is_none());
922 assert!(m.insert(5, 14).is_none());
923 let new = 100;
924 match m.get_mut(&5) {
925 None => panic!(),
926 Some(x) => *x = new,
927 }
928 assert_eq!(m.get(&5), Some(&new));
929 }
930
931 #[test]
932 fn test_insert_overwrite() {
933 let mut m = LookupMap::new(b"b");
934 assert!(m.insert(1, 2).is_none());
935 assert_eq!(*m.get(&1).unwrap(), 2);
936 assert!(m.insert(1, 3).is_some());
937 assert_eq!(*m.get(&1).unwrap(), 3);
938 }
939
940 #[test]
941 fn test_remove() {
942 let mut m = LookupMap::new(b"b");
943 m.insert(1, 2);
944 assert_eq!(m.remove(&1), Some(2));
945 assert_eq!(m.remove(&1), None);
946 }
947
948 #[test]
949 fn test_find() {
950 let mut m = LookupMap::new(b"b");
951 assert!(m.get(&1).is_none());
952 m.insert(1, 2);
953 match m.get(&1) {
954 None => panic!(),
955 Some(v) => assert_eq!(*v, 2),
956 }
957 }
958
959 #[test]
960 fn test_show() {
961 let mut map = LookupMap::new(b"b");
962 let empty: LookupMap<i32, i32> = LookupMap::new(b"c");
963
964 map.insert(1, 2);
965 map.insert(3, 4);
966
967 let map_str = format!("{:?}", map);
968
969 assert_eq!(map_str, "LookupMap { prefix: [98] }");
970 assert_eq!(format!("{:?}", empty), "LookupMap { prefix: [99] }");
971 }
972
973 #[test]
974 fn test_index() {
975 let mut map = LookupMap::new(b"b");
976
977 map.insert(1, 2);
978 map.insert(2, 1);
979 map.insert(3, 4);
980
981 assert_eq!(map[&2], 1);
982 }
983
984 #[test]
985 #[should_panic]
986 #[allow(clippy::unnecessary_operation)]
987 fn test_index_nonexistent() {
988 let mut map = LookupMap::new(b"b");
989
990 map.insert(1, 2);
991 map.insert(2, 1);
992 map.insert(3, 4);
993
994 #[allow(clippy::no_effect)] map[&4];
996 }
997
998 #[test]
999 fn test_entry() {
1000 let mut map = LookupMap::new(b"b");
1001
1002 let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
1003
1004 for v in xs {
1005 map.insert(v.0, v.1);
1006 }
1007
1008 match map.entry(1) {
1010 Vacant(_) => unreachable!(),
1011 Occupied(mut view) => {
1012 assert_eq!(view.get(), &10);
1013 assert_eq!(view.insert(100), 10);
1014 }
1015 }
1016 assert_eq!(map.get(&1).unwrap(), &100);
1017
1018 match map.entry(2) {
1020 Vacant(_) => unreachable!(),
1021 Occupied(mut view) => {
1022 let v = view.get_mut();
1023 let new_v = (*v) * 10;
1024 *v = new_v;
1025 }
1026 }
1027 assert_eq!(map.get(&2).unwrap(), &200);
1028
1029 match map.entry(3) {
1031 Vacant(_) => unreachable!(),
1032 Occupied(view) => {
1033 assert_eq!(view.remove(), 30);
1034 }
1035 }
1036 assert_eq!(map.get(&3), None);
1037
1038 match map.entry(10) {
1040 Occupied(_) => unreachable!(),
1041 Vacant(view) => {
1042 assert_eq!(*view.insert(1000), 1000);
1043 }
1044 }
1045 assert_eq!(map.get(&10).unwrap(), &1000);
1046 }
1047
1048 #[test]
1049 fn test_extend_ref_kv_tuple() {
1050 let mut a = LookupMap::new(b"b");
1051 a.insert(0, 0);
1052
1053 let for_iter: Vec<(i32, i32)> = (0..100).map(|i| (i, i)).collect();
1054 a.extend(for_iter);
1055
1056 for item in 0..100 {
1057 assert_eq!(a[&item], item);
1058 }
1059 }
1060
1061 #[test]
1062 fn test_occupied_entry_key() {
1063 let mut a = LookupMap::new(b"b");
1064 let key = "hello there";
1065 let value = "value goes here";
1066 a.insert(key.to_string(), value.to_string());
1067 assert_eq!(a[key], value);
1068
1069 match a.entry(key.to_string()) {
1070 Vacant(_) => panic!(),
1071 Occupied(e) => assert_eq!(key, *e.key()),
1072 }
1073 assert_eq!(a[key], value);
1074 }
1075
1076 #[test]
1077 fn test_vacant_entry_key() {
1078 let mut a = LookupMap::new(b"b");
1079 let key = "hello there";
1080 let value = "value goes here".to_string();
1081
1082 match a.entry(key.to_string()) {
1083 Occupied(_) => panic!(),
1084 Vacant(e) => {
1085 assert_eq!(key, *e.key());
1086 e.insert(value.clone());
1087 }
1088 }
1089 assert_eq!(a[key], value);
1090 }
1091}