casper_contract_sdk/collections/
iterable_map.rs

1use core::marker::PhantomData;
2
3use borsh::{BorshDeserialize, BorshSerialize};
4use bytes::BufMut;
5use casper_executor_wasm_common::keyspace::Keyspace;
6use const_fnv1a_hash::fnv1a_hash_64;
7
8use crate::casper::{self, read_into_vec};
9
10/// A pointer that uniquely identifies a value written into the map.
11#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, Copy, PartialEq)]
12pub struct IterableMapPtr {
13    /// The key hash
14    pub(crate) hash: u64,
15    /// In case of a collision, signifies the index of this element
16    /// in a bucket
17    pub(crate) index: u64,
18}
19
20/// Trait for types that can be used as keys in [IterableMap].
21/// Must produce a deterministic hash.
22///
23/// A blanket implementation is provided for all types that implement
24/// [BorshSerialize].
25pub trait IterableMapHash: PartialEq + BorshSerialize + BorshDeserialize {
26    fn compute_hash(&self) -> u64 {
27        let mut bytes = Vec::new();
28        self.serialize(&mut bytes).unwrap();
29        fnv1a_hash_64(&bytes, None)
30    }
31}
32
33// No blanket IterableMapKey implementation. Explicit impls prevent conflicts with
34// user‑provided implementations; a blanket impl would forbid custom hashes.
35impl IterableMapHash for u8 {}
36impl IterableMapHash for u16 {}
37impl IterableMapHash for u32 {}
38impl IterableMapHash for u64 {}
39impl IterableMapHash for u128 {}
40impl IterableMapHash for i8 {}
41impl IterableMapHash for i16 {}
42impl IterableMapHash for i32 {}
43impl IterableMapHash for i64 {}
44impl IterableMapHash for i128 {}
45impl IterableMapHash for String {}
46
47/// A map over global state that allows iteration. Each entry at key `K_n` stores `(K_{n}, V,
48/// K_{n-1})`, where `V` is the value and `K_{n-1}` is the key hash of the previous entry.
49///
50/// This creates a constant spatial overhead; every entry stores a pointer
51/// to the one inserted before it.
52///
53/// Enables iteration without a guaranteed ordering; updating an existing
54/// key does not affect position.
55///
56/// Under the hood, this is a singly-linked HashMap with linear probing for collision resolution.
57/// Supports full traversal, typically in reverse-insertion order.
58#[derive(BorshSerialize, BorshDeserialize, Debug, Clone)]
59#[borsh(crate = "crate::serializers::borsh")]
60pub struct IterableMap<K, V> {
61    pub(crate) prefix: String,
62
63    // Keys are hashed to u128 internally, but K is preserved to enforce type safety.
64    // While this map could accept arbitrary u128 keys, requiring a concrete K prevents
65    // misuse and clarifies intent at the type level.
66    pub(crate) tail_key_hash: Option<IterableMapPtr>,
67    _marker: PhantomData<(K, V)>,
68}
69
70/// Single entry in `IterableMap`. Stores the value and the hash of the previous entry's key.
71#[derive(BorshSerialize, BorshDeserialize, Debug, Clone)]
72#[borsh(crate = "crate::serializers::borsh")]
73pub struct IterableMapEntry<K, V> {
74    pub(crate) key: K,
75    pub(crate) value: Option<V>,
76    pub(crate) previous: Option<IterableMapPtr>,
77}
78
79impl<K, V> IterableMap<K, V>
80where
81    K: IterableMapHash,
82    V: BorshSerialize + BorshDeserialize,
83{
84    /// Creates an empty [IterableMap] with the given prefix.
85    pub fn new<S: Into<String>>(prefix: S) -> Self {
86        Self {
87            prefix: prefix.into(),
88            tail_key_hash: None,
89            _marker: PhantomData,
90        }
91    }
92
93    /// Inserts a key-value pair into the map.
94    ///
95    /// If the map did not have this key present, `None` is returned.
96    ///
97    /// If the map did have this key present, the value is updated, and the old value is returned.
98    ///
99    /// This has an amortized complexity of O(1), with a worst-case of O(n) when running into
100    /// collisions.
101    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
102        // Find an address we can write to
103        let (ptr, at_ptr) = self.get_writable_slot(&key);
104
105        // Either overwrite an existing entry, or create a new one.
106        let (entry_to_write, previous) = match at_ptr {
107            Some(mut entry) => {
108                if entry.value.is_none() {
109                    // Reuse tombstone as a new insertion
110                    entry.key = key;
111                    entry.previous = self.tail_key_hash;
112                    entry.value = Some(value);
113                    self.tail_key_hash = Some(ptr);
114                    (entry, None)
115                } else {
116                    // Overwrite an existing value
117                    let old = entry.value;
118                    entry.value = Some(value);
119                    (entry, old)
120                }
121            }
122            None => {
123                let entry = IterableMapEntry {
124                    key,
125                    value: Some(value),
126                    previous: self.tail_key_hash,
127                };
128
129                // Additionally, since this is a new entry, we need to update the tail
130                self.tail_key_hash = Some(ptr);
131
132                (entry, None)
133            }
134        };
135
136        // Write the entry and return previous value if it exists
137        let mut entry_bytes = Vec::new();
138        entry_to_write.serialize(&mut entry_bytes).unwrap();
139
140        let prefix = self.create_prefix_from_ptr(&ptr);
141        let keyspace = Keyspace::Context(&prefix);
142        casper::write(keyspace, &entry_bytes).unwrap();
143
144        previous
145    }
146
147    /// Returns a value corresponding to the key.
148    pub fn get(&self, key: &K) -> Option<V> {
149        // If a slot is writable, it implicitly belongs the key
150        let (_, at_ptr) = self.get_writable_slot(key);
151        at_ptr.and_then(|entry| entry.value)
152    }
153
154    /// Removes a key from the map. Returns the associated value if the key exists.
155    ///
156    /// Has a worst-case runtime of O(n).
157    pub fn remove(&mut self, key: &K) -> Option<V> {
158        // Find the entry for the key that we're about to remove.
159        let (to_remove_ptr, at_remove_ptr) = self.find_slot(key)?;
160
161        let to_remove_prefix = self.create_prefix_from_ptr(&to_remove_ptr);
162        let to_remove_context_key = Keyspace::Context(&to_remove_prefix);
163
164        // See if the removed entry is a part of a collision resolution chain
165        // by investigating its potential child.
166        let to_remove_ptr_child_prefix = self.create_prefix_from_ptr(&IterableMapPtr {
167            index: to_remove_ptr.index + 1,
168            ..to_remove_ptr
169        });
170        let to_remove_ptr_child_keyspace = Keyspace::Context(&to_remove_ptr_child_prefix);
171
172        if self.get_entry(to_remove_ptr_child_keyspace).is_some() {
173            // A child exists, so we need to retain this element to maintain
174            // collision resolution soundness. Instead of purging, mark as
175            // tombstone.
176            let tombstone = IterableMapEntry {
177                value: None,
178                ..at_remove_ptr
179            };
180
181            // Write the updated value
182            let mut entry_bytes = Vec::new();
183            tombstone.serialize(&mut entry_bytes).unwrap();
184            casper::write(to_remove_context_key, &entry_bytes).unwrap();
185        } else {
186            // There is no child, so we can safely purge this entry entirely.
187            casper::remove(to_remove_context_key).unwrap();
188        }
189
190        // Edge case when removing tail
191        if self.tail_key_hash == Some(to_remove_ptr) {
192            self.tail_key_hash = at_remove_ptr.previous;
193            return at_remove_ptr.value;
194        }
195
196        // Scan the map, find entry to remove, join adjacent entries
197        let mut current_hash = self.tail_key_hash;
198        while let Some(key) = current_hash {
199            let current_prefix = self.create_prefix_from_ptr(&key);
200            let current_context_key = Keyspace::Context(&current_prefix);
201            let mut current_entry = self.get_entry(current_context_key).unwrap();
202
203            // If there is no previous entry, then we've finished iterating.
204            //
205            // This shouldn't happen, as the outer logic prevents from running
206            // into such case, ie. we early exit if the entry to remove doesn't
207            // exist.
208            let Some(next_hash) = current_entry.previous else {
209                panic!("Unexpected end of IterableMap");
210            };
211
212            // If the next entry is the one to be removed, repoint the current
213            // one to the one preceeding the one to remove.
214            if next_hash == to_remove_ptr {
215                // Advance current past the element to remove
216                current_entry.previous = at_remove_ptr.previous;
217
218                // Re-write the updated current entry
219                let mut entry_bytes = Vec::new();
220                current_entry.serialize(&mut entry_bytes).unwrap();
221                casper::write(current_context_key, &entry_bytes).unwrap();
222
223                return at_remove_ptr.value;
224            }
225
226            // Advance backwards
227            current_hash = current_entry.previous;
228        }
229
230        None
231    }
232
233    /// Clears the map, removing all key-value pairs.
234    pub fn clear(&mut self) {
235        for key in self.keys() {
236            let prefix = self.create_prefix_from_key(&key);
237            {
238                let key = Keyspace::Context(&prefix);
239                casper::remove(key).unwrap()
240            };
241        }
242
243        self.tail_key_hash = None;
244    }
245
246    /// Returns true if the map contains a value for the specified key.
247    pub fn contains_key(&self, key: &K) -> bool {
248        self.get(key).is_some()
249    }
250
251    /// Creates an iterator visiting all the values in arbitrary order.
252    pub fn keys(&self) -> impl Iterator<Item = K> + '_ {
253        self.iter().map(|(key, _)| key)
254    }
255
256    /// Creates an iterator visiting all the values in arbitrary order.
257    pub fn values(&self) -> impl Iterator<Item = V> + '_ {
258        self.iter().map(|(_, value)| value)
259    }
260
261    // Returns true if the map contains no elements.
262    pub fn is_empty(&self) -> bool {
263        self.tail_key_hash.is_none()
264    }
265
266    /// Returns an iterator over the entries in the map.
267    ///
268    /// Traverses entries in reverse-insertion order.
269    /// Each item is a tuple of the hashed key and the value.
270    pub fn iter(&self) -> IterableMapIter<K, V> {
271        IterableMapIter {
272            prefix: &self.prefix,
273            current: self.tail_key_hash,
274            _marker: PhantomData,
275        }
276    }
277
278    /// Returns the number of entries in the map.
279    ///
280    /// This is an O(n) operation.
281    pub fn len(&self) -> usize {
282        self.iter().count()
283    }
284
285    /// Find the slot containing key, if any.
286    fn find_slot(&self, key: &K) -> Option<(IterableMapPtr, IterableMapEntry<K, V>)> {
287        let mut bucket_ptr = self.create_root_ptr_from_key(key);
288
289        // Probe until we find either an existing slot, a tombstone or empty space.
290        // This should rarely iterate more than once assuming a solid hashing algorithm.
291        loop {
292            let prefix = self.create_prefix_from_ptr(&bucket_ptr);
293            let keyspace = Keyspace::Context(&prefix);
294
295            if let Some(entry) = self.get_entry(keyspace) {
296                // Existing value, check if the keys match
297                if entry.key == *key && entry.value.is_some() {
298                    // We have found a slot where this key lives, return it
299                    return Some((bucket_ptr, entry));
300                } else {
301                    // We found a slot for this key hash, but either the keys mismatch,
302                    // or it's vacant, so we need to probe further.
303                    bucket_ptr.index += 1;
304                    continue;
305                }
306            } else {
307                // We've reached empty address space, so the slot doesn't actually exist.
308                return None;
309            }
310        }
311    }
312
313    /// Find the next slot we can safely write to. This is either a slot already owned and
314    /// assigned to the key, a vacant tombstone, or empty memory.
315    fn get_writable_slot(&self, key: &K) -> (IterableMapPtr, Option<IterableMapEntry<K, V>>) {
316        let mut bucket_ptr = self.create_root_ptr_from_key(key);
317
318        // Probe until we find either an existing slot, a tombstone or empty space.
319        // This should rarely iterate more than once assuming a solid hashing algorithm.
320        loop {
321            let prefix = self.create_prefix_from_ptr(&bucket_ptr);
322            let keyspace = Keyspace::Context(&prefix);
323
324            if let Some(entry) = self.get_entry(keyspace) {
325                // Existing value, check if the keys match
326                if entry.key == *key {
327                    // We have found an existing slot for that key, return it
328                    return (bucket_ptr, Some(entry));
329                } else if entry.value.is_none() {
330                    // If the value is None, then this is a tombstone, and we
331                    // can write over it.
332                    return (bucket_ptr, Some(entry));
333                } else {
334                    // We found a slot for this key hash, but the keys mismatch,
335                    // and it's not vacant, so this is a collision and we need to
336                    // probe further.
337                    bucket_ptr.index += 1;
338                    continue;
339                }
340            } else {
341                // We've reached empty address space, so we can write here
342                return (bucket_ptr, None);
343            }
344        }
345    }
346
347    fn get_entry(&self, keyspace: Keyspace) -> Option<IterableMapEntry<K, V>> {
348        match read_into_vec(keyspace) {
349            Ok(Some(vec)) => {
350                let entry: IterableMapEntry<K, V> = borsh::from_slice(&vec).unwrap();
351                Some(entry)
352            }
353            Ok(None) => None,
354            Err(_) => None,
355        }
356    }
357
358    fn create_prefix_from_key(&self, key: &K) -> Vec<u8> {
359        let ptr = self.create_root_ptr_from_key(key);
360        self.create_prefix_from_ptr(&ptr)
361    }
362
363    fn create_root_ptr_from_key(&self, key: &K) -> IterableMapPtr {
364        IterableMapPtr {
365            hash: key.compute_hash(),
366            index: 0,
367        }
368    }
369
370    fn create_prefix_from_ptr(&self, hash: &IterableMapPtr) -> Vec<u8> {
371        let mut context_key = Vec::new();
372        context_key.extend(self.prefix.as_bytes());
373        context_key.extend(b"_");
374        context_key.put_u64_le(hash.hash);
375        context_key.extend(b"_");
376        context_key.put_u64_le(hash.index);
377        context_key
378    }
379}
380
381/// Iterator over entries in an [`IterableMap`].
382///
383/// Traverses the map in reverse-insertion order, following the internal
384/// linked structure via hashed key references [`u128`].
385///
386/// Yields a tuple (K, V), where the key is the hashed
387/// representation of the original key. The original key type `K` is not recoverable.
388///
389/// Each iteration step deserializes a single entry from storage.
390///
391/// This iterator performs no allocation beyond internal buffers,
392/// and deserialization errors are treated as iteration termination.
393pub struct IterableMapIter<'a, K, V> {
394    prefix: &'a str,
395    current: Option<IterableMapPtr>,
396    _marker: PhantomData<(K, V)>,
397}
398
399impl<'a, K, V> IntoIterator for &'a IterableMap<K, V>
400where
401    K: BorshDeserialize,
402    V: BorshDeserialize,
403{
404    type Item = (K, V);
405    type IntoIter = IterableMapIter<'a, K, V>;
406
407    fn into_iter(self) -> Self::IntoIter {
408        IterableMapIter {
409            prefix: &self.prefix,
410            current: self.tail_key_hash,
411            _marker: PhantomData,
412        }
413    }
414}
415
416impl<K, V> Iterator for IterableMapIter<'_, K, V>
417where
418    K: BorshDeserialize,
419    V: BorshDeserialize,
420{
421    type Item = (K, V);
422
423    fn next(&mut self) -> Option<Self::Item> {
424        let current_hash = self.current?;
425        let mut key_bytes = Vec::new();
426        key_bytes.extend(self.prefix.as_bytes());
427        key_bytes.extend(b"_");
428        key_bytes.put_u64_le(current_hash.hash);
429        key_bytes.extend(b"_");
430        key_bytes.put_u64_le(current_hash.index);
431
432        let context_key = Keyspace::Context(&key_bytes);
433
434        match read_into_vec(context_key) {
435            Ok(Some(vec)) => {
436                let entry: IterableMapEntry<K, V> = borsh::from_slice(&vec).unwrap();
437                self.current = entry.previous;
438                Some((
439                    entry.key,
440                    entry
441                        .value
442                        .expect("Tombstone values should be unlinked on removal"),
443                ))
444            }
445            Ok(None) => None,
446            Err(_) => None,
447        }
448    }
449}
450
451#[cfg(test)]
452mod tests {
453    use super::*;
454    use crate::casper::native::dispatch;
455
456    const TEST_MAP_PREFIX: &str = "test_map";
457
458    #[test]
459    fn insert_and_get() {
460        dispatch(|| {
461            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
462            assert_eq!(map.len(), 0);
463
464            assert_eq!(map.get(&1), None);
465
466            map.insert(1, "a".to_string());
467            assert_eq!(map.len(), 1);
468
469            assert_eq!(map.get(&1), Some("a".to_string()));
470
471            map.insert(2, "b".to_string());
472            assert_eq!(map.len(), 2);
473
474            assert_eq!(map.get(&2), Some("b".to_string()));
475        })
476        .unwrap();
477    }
478
479    #[test]
480    fn overwrite_existing_key() {
481        dispatch(|| {
482            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
483
484            assert_eq!(map.insert(1, "a".to_string()), None);
485            assert_eq!(map.insert(1, "b".to_string()), Some("a".to_string()));
486            assert_eq!(map.get(&1), Some("b".to_string()));
487        })
488        .unwrap();
489    }
490
491    #[test]
492    fn remove_tail_entry() {
493        dispatch(|| {
494            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
495            assert_eq!(map.len(), 0);
496            map.insert(1, "a".to_string());
497            assert_eq!(map.len(), 1);
498            map.insert(2, "b".to_string());
499            assert_eq!(map.len(), 2);
500            assert_eq!(map.remove(&2), Some("b".to_string()));
501            assert_eq!(map.len(), 1);
502            assert_eq!(map.get(&2), None);
503            assert_eq!(map.get(&1), Some("a".to_string()));
504        })
505        .unwrap();
506    }
507
508    #[test]
509    fn remove_middle_entry() {
510        dispatch(|| {
511            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
512            assert_eq!(map.len(), 0);
513
514            map.insert(1, "a".to_string());
515            assert_eq!(map.len(), 1);
516
517            map.insert(2, "b".to_string());
518            assert_eq!(map.len(), 2);
519
520            map.insert(3, "c".to_string());
521            assert_eq!(map.len(), 3);
522
523            assert_eq!(map.remove(&2), Some("b".to_string()));
524            assert_eq!(map.len(), 2);
525
526            assert_eq!(map.get(&2), None);
527            assert_eq!(map.get(&1), Some("a".to_string()));
528            assert_eq!(map.get(&3), Some("c".to_string()));
529
530            assert_eq!(map.len(), 2);
531        })
532        .unwrap();
533    }
534
535    #[test]
536    fn remove_nonexistent_key_does_nothing() {
537        dispatch(|| {
538            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
539
540            map.insert(1, "a".to_string());
541
542            assert_eq!(map.remove(&999), None);
543            assert_eq!(map.get(&1), Some("a".to_string()));
544        })
545        .unwrap();
546    }
547
548    #[test]
549    fn iterates_all_entries_in_reverse_insertion_order() {
550        dispatch(|| {
551            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
552
553            map.insert(1, "a".to_string());
554            map.insert(2, "b".to_string());
555            map.insert(3, "c".to_string());
556
557            let values: Vec<_> = map.values().collect();
558            assert_eq!(
559                values,
560                vec!["c".to_string(), "b".to_string(), "a".to_string(),]
561            );
562        })
563        .unwrap();
564    }
565
566    #[test]
567    fn iteration_skips_deleted_entries() {
568        dispatch(|| {
569            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
570
571            map.insert(1, "a".to_string());
572            map.insert(2, "b".to_string());
573            map.insert(3, "c".to_string());
574
575            map.remove(&2);
576
577            let values: Vec<_> = map.values().collect();
578            assert_eq!(values, vec!["c".to_string(), "a".to_string(),]);
579        })
580        .unwrap();
581    }
582
583    #[test]
584    fn empty_map_behaves_sanely() {
585        dispatch(|| {
586            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
587
588            assert_eq!(map.get(&1), None);
589            assert_eq!(map.remove(&1), None);
590            assert_eq!(map.iter().count(), 0);
591        })
592        .unwrap();
593    }
594
595    #[test]
596    fn separate_maps_do_not_conflict() {
597        dispatch(|| {
598            let mut map1 = IterableMap::<u64, String>::new("map1");
599            let mut map2 = IterableMap::<u64, String>::new("map2");
600
601            map1.insert(1, "a".to_string());
602            map2.insert(1, "b".to_string());
603
604            assert_eq!(map1.get(&1), Some("a".to_string()));
605            assert_eq!(map2.get(&1), Some("b".to_string()));
606        })
607        .unwrap();
608    }
609
610    #[test]
611    fn insert_same_value_under_different_keys() {
612        dispatch(|| {
613            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
614
615            map.insert(1, "shared".to_string());
616            map.insert(2, "shared".to_string());
617
618            assert_eq!(map.get(&1), Some("shared".to_string()));
619            assert_eq!(map.get(&2), Some("shared".to_string()));
620        })
621        .unwrap();
622    }
623
624    #[test]
625    fn clear_removes_all_entries() {
626        dispatch(|| {
627            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
628            map.insert(1, "a".to_string());
629            map.insert(2, "b".to_string());
630            map.clear();
631            assert!(map.is_empty());
632            assert_eq!(map.iter().count(), 0);
633        })
634        .unwrap();
635    }
636
637    #[test]
638    fn keys_returns_reverse_insertion_order() {
639        dispatch(|| {
640            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
641            map.insert(1, "a".to_string());
642            map.insert(2, "b".to_string());
643            let hashes: Vec<_> = map.keys().collect();
644            assert_eq!(hashes, vec![2, 1]);
645        })
646        .unwrap();
647    }
648
649    #[test]
650    fn values_returns_values_in_reverse_insertion_order() {
651        dispatch(|| {
652            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
653            map.insert(1, "a".to_string());
654            map.insert(2, "b".to_string());
655            let values: Vec<_> = map.values().collect();
656            assert_eq!(values, vec!["b".to_string(), "a".to_string()]);
657        })
658        .unwrap();
659    }
660
661    #[test]
662    fn contains_key_returns_correctly() {
663        dispatch(|| {
664            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
665            assert!(!map.contains_key(&1));
666            map.insert(1, "a".to_string());
667            assert!(map.contains_key(&1));
668            map.remove(&1);
669            assert!(!map.contains_key(&1));
670        })
671        .unwrap();
672    }
673
674    #[test]
675    fn multiple_removals_and_insertions() {
676        dispatch(|| {
677            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
678            map.insert(1, "a".to_string());
679            map.insert(2, "b".to_string());
680            map.insert(3, "c".to_string());
681            map.remove(&2);
682            assert_eq!(map.get(&2), None);
683            assert_eq!(map.get(&1), Some("a".to_string()));
684            assert_eq!(map.get(&3), Some("c".to_string()));
685
686            map.insert(4, "d".to_string());
687            let values: Vec<_> = map.values().collect();
688            assert_eq!(values, vec!["d", "c", "a"]);
689        })
690        .unwrap();
691    }
692
693    #[test]
694    fn struct_as_key() {
695        #[derive(BorshSerialize, BorshDeserialize, Debug, Clone, PartialEq, Eq)]
696        struct TestKey {
697            id: u64,
698            name: String,
699        }
700
701        impl IterableMapHash for TestKey {}
702
703        dispatch(|| {
704            let key1 = TestKey {
705                id: 1,
706                name: "Key1".to_string(),
707            };
708            let key2 = TestKey {
709                id: 2,
710                name: "Key2".to_string(),
711            };
712            let mut map = IterableMap::<TestKey, String>::new(TEST_MAP_PREFIX);
713
714            map.insert(key1.clone(), "a".to_string());
715            map.insert(key2.clone(), "b".to_string());
716
717            assert_eq!(map.get(&key1), Some("a".to_string()));
718            assert_eq!(map.get(&key2), Some("b".to_string()));
719        })
720        .unwrap();
721    }
722
723    #[test]
724    fn remove_middle_of_long_chain() {
725        dispatch(|| {
726            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
727            map.insert(1, "a".to_string());
728            map.insert(2, "b".to_string());
729            map.insert(3, "c".to_string());
730            map.insert(4, "d".to_string());
731            map.insert(5, "e".to_string());
732
733            // The order is 5,4,3,2,1
734            map.remove(&3); // Remove the middle entry
735
736            let values: Vec<_> = map.values().collect();
737            assert_eq!(values, vec!["e", "d", "b", "a"]);
738
739            // Check that entry 4's previous is now 2's hash
740            let ptr4 = map.create_root_ptr_from_key(&4u64);
741            let prefix = map.create_prefix_from_ptr(&ptr4);
742            let entry = map.get_entry(Keyspace::Context(&prefix)).unwrap();
743            assert_eq!(entry.previous, Some(map.create_root_ptr_from_key(&2u64)));
744        })
745        .unwrap();
746    }
747
748    #[test]
749    fn insert_after_remove_updates_head() {
750        dispatch(|| {
751            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
752            map.insert(1, "a".to_string());
753            map.insert(2, "b".to_string());
754            map.remove(&2);
755            map.insert(3, "c".to_string());
756
757            let values: Vec<_> = map.values().collect();
758            assert_eq!(values, vec!["c", "a"]);
759        })
760        .unwrap();
761    }
762
763    #[test]
764    fn reinsert_removed_key() {
765        dispatch(|| {
766            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
767            map.insert(1, "a".to_string());
768            map.remove(&1);
769            map.insert(1, "b".to_string());
770
771            assert_eq!(map.get(&1), Some("b".to_string()));
772            assert_eq!(map.iter().next().unwrap().1, "b".to_string());
773        })
774        .unwrap();
775    }
776
777    #[test]
778    fn iteration_reflects_modifications() {
779        dispatch(|| {
780            let mut map = IterableMap::<u64, String>::new(TEST_MAP_PREFIX);
781            map.insert(1, "a".to_string());
782            map.insert(2, "b".to_string());
783            let mut iter = map.iter();
784            assert_eq!(iter.next().unwrap().1, "b".to_string());
785
786            map.remove(&2);
787            map.insert(3, "c".to_string());
788            let values: Vec<_> = map.values().collect();
789            assert_eq!(values, vec!["c", "a"]);
790        })
791        .unwrap();
792    }
793
794    #[test]
795    fn unit_struct_as_key() {
796        #[derive(BorshSerialize, BorshDeserialize, PartialEq)]
797        struct UnitKey;
798
799        impl IterableMapHash for UnitKey {}
800
801        dispatch(|| {
802            let mut map = IterableMap::<UnitKey, String>::new(TEST_MAP_PREFIX);
803            map.insert(UnitKey, "value".to_string());
804            assert_eq!(map.get(&UnitKey), Some("value".to_string()));
805        })
806        .unwrap();
807    }
808
809    #[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
810    struct CollidingKey(u64, u64);
811
812    impl IterableMapHash for CollidingKey {
813        fn compute_hash(&self) -> u64 {
814            let mut bytes = Vec::new();
815            // Only serialize first field for hash computation
816            self.0.serialize(&mut bytes).unwrap();
817            fnv1a_hash_64(&bytes, None)
818        }
819    }
820
821    #[test]
822    fn basic_collision_handling() {
823        dispatch(|| {
824            let mut map = IterableMap::<CollidingKey, String>::new(TEST_MAP_PREFIX);
825
826            // Both keys will have same hash but different actual keys
827            let k1 = CollidingKey(42, 1);
828            let k2 = CollidingKey(42, 2);
829
830            map.insert(k1.clone(), "first".to_string());
831            map.insert(k2.clone(), "second".to_string());
832
833            assert_eq!(map.get(&k1), Some("first".to_string()));
834            assert_eq!(map.get(&k2), Some("second".to_string()));
835        })
836        .unwrap();
837    }
838
839    #[test]
840    fn tombstone_handling() {
841        dispatch(|| {
842            let mut map = IterableMap::<CollidingKey, String>::new(TEST_MAP_PREFIX);
843
844            let k1 = CollidingKey(42, 1);
845            let k2 = CollidingKey(42, 2);
846            let k3 = CollidingKey(42, 3);
847
848            map.insert(k1.clone(), "first".to_string());
849            map.insert(k2.clone(), "second".to_string());
850            map.insert(k3.clone(), "third".to_string());
851
852            // Remove middle entry
853            assert_eq!(map.remove(&k2), Some("second".to_string()));
854
855            // Verify tombstone state
856            let (_, entry) = map.get_writable_slot(&k2);
857            assert!(entry.unwrap().value.is_none());
858
859            // Verify chain integrity
860            let values: Vec<_> = map.values().collect();
861            assert_eq!(values, vec!["third", "first"]);
862        })
863        .unwrap();
864    }
865
866    #[test]
867    fn tombstone_reuse() {
868        dispatch(|| {
869            let mut map = IterableMap::<CollidingKey, String>::new(TEST_MAP_PREFIX);
870
871            let k1 = CollidingKey(42, 1);
872            let k2 = CollidingKey(42, 2);
873
874            map.insert(k1.clone(), "first".to_string());
875            map.insert(k2.clone(), "second".to_string());
876
877            // Removing k1 while k2 exists guarantees k1 turns into
878            // a tombstone
879            map.remove(&k1);
880
881            // Reinsert into tombstone slot
882            map.insert(k1.clone(), "reused".to_string());
883
884            assert_eq!(map.get(&k1), Some("reused".to_string()));
885            assert_eq!(map.get(&k2), Some("second".to_string()));
886        })
887        .unwrap();
888    }
889
890    #[test]
891    fn full_deletion_handling() {
892        dispatch(|| {
893            let mut map = IterableMap::<CollidingKey, String>::new(TEST_MAP_PREFIX);
894
895            let k1 = CollidingKey(42, 1);
896            map.insert(k1.clone(), "lonely".to_string());
897
898            assert_eq!(map.remove(&k1), Some("lonely".to_string()));
899
900            // Verify complete removal
901            let (_, entry) = map.get_writable_slot(&k1);
902            assert!(entry.is_none());
903        })
904        .unwrap();
905    }
906
907    #[test]
908    fn collision_chain_iteration() {
909        dispatch(|| {
910            let mut map = IterableMap::<CollidingKey, String>::new(TEST_MAP_PREFIX);
911
912            let keys = [
913                CollidingKey(42, 1),
914                CollidingKey(42, 2),
915                CollidingKey(42, 3),
916            ];
917
918            for (i, k) in keys.iter().enumerate() {
919                map.insert(k.clone(), format!("value-{}", i));
920            }
921
922            // Remove middle entry
923            map.remove(&keys[1]);
924
925            let values: Vec<_> = map.values().collect();
926            assert_eq!(values, vec!["value-2", "value-0"]);
927        })
928        .unwrap();
929    }
930
931    #[test]
932    fn complex_collision_chain() {
933        dispatch(|| {
934            let mut map = IterableMap::<CollidingKey, String>::new(TEST_MAP_PREFIX);
935
936            // Create 5 colliding keys
937            let keys: Vec<_> = (0..5).map(|i| CollidingKey(42, i)).collect();
938
939            // Insert all
940            for k in &keys {
941                map.insert(k.clone(), format!("{}", k.1));
942            }
943
944            // Remove even indexes
945            for k in keys.iter().step_by(2) {
946                map.remove(k);
947            }
948
949            // Insert new values
950            map.insert(keys[0].clone(), "reinserted".to_string());
951            map.insert(CollidingKey(42, 5), "new".to_string());
952
953            // Verify final state
954            let expected = vec![
955                ("new".to_string(), 5),
956                ("reinserted".to_string(), 0),
957                ("3".to_string(), 3),
958                ("1".to_string(), 1),
959            ];
960
961            let results: Vec<_> = map.iter().map(|(k, v)| (v, k.1)).collect();
962
963            assert_eq!(results, expected);
964        })
965        .unwrap();
966    }
967
968    #[test]
969    fn cross_bucket_reference() {
970        dispatch(|| {
971            let mut map = IterableMap::<CollidingKey, String>::new(TEST_MAP_PREFIX);
972
973            // Create keys with different hashes but chained references
974            let k1 = CollidingKey(1, 0);
975            let k2 = CollidingKey(2, 0);
976            let k3 = CollidingKey(1, 1); // Collides with k1
977
978            map.insert(k1.clone(), "first".to_string());
979            map.insert(k2.clone(), "second".to_string());
980            map.insert(k3.clone(), "third".to_string());
981
982            // Remove k2 which is referenced by k3
983            map.remove(&k2);
984
985            // Verify iteration skips removed entry
986            let values: Vec<_> = map.values().collect();
987            assert_eq!(values, vec!["third", "first"]);
988        })
989        .unwrap();
990    }
991}