tether_map/linked_hash_map/
cursor.rs

1use core::hash::BuildHasher;
2use core::hash::Hash;
3
4use crate::Ptr;
5use crate::arena::ActiveSlotRef;
6use crate::linked_hash_map::Entry;
7use crate::linked_hash_map::Iter;
8use crate::linked_hash_map::LinkedHashMap;
9use crate::linked_hash_map::RemovedEntry;
10
11#[derive(Debug)]
12/// A cursor for navigating and modifying a linked hash map.
13///
14/// A `CursorMut` is like an iterator, except that it can freely seek
15/// back-and-forth and can safely mutate the map during iteration. This is
16/// because the lifetime is tied to the map, not the cursor itself.
17///
18/// Cursors always point to an element in the map. The `CursorMut` is positioned
19/// at a specific entry and allows for insertion and removal operations relative
20/// to that position.
21///
22/// # Examples
23///
24/// ```
25/// use tether_map::LinkedHashMap;
26///
27/// let mut map = LinkedHashMap::new();
28/// map.insert("a", 1);
29/// map.insert("b", 2);
30/// map.insert("c", 3);
31///
32/// let mut cursor = map.head_cursor_mut();
33/// if let Some((key, value)) = cursor.current_mut() {
34///     *value *= 10;
35/// }
36/// assert_eq!(map.get(&"a"), Some(&10));
37/// ```
38pub struct CursorMut<'m, K, T, S> {
39    pub(crate) ptr: Option<ActiveSlotRef<K, T>>,
40    pub(crate) map: &'m mut LinkedHashMap<K, T, S>,
41}
42
43impl<'m, K: Hash + Eq, T, S: BuildHasher> CursorMut<'m, K, T, S> {
44    /// Inserts a key-value pair after the cursor's current position and
45    /// moves the cursor to the inserted or updated entry.
46    pub fn insert_after_move_to(&mut self, key: K, value: T) -> Option<T> {
47        let ptr = if self.ptr.is_none() {
48            self.map.head_tail.as_ref().map(|ht| ht.tail)
49        } else {
50            self.ptr
51        };
52
53        match self.map.entry(key) {
54            Entry::Occupied(occupied_entry) => {
55                let mut map_ptr = *occupied_entry.entry.get();
56                if Some(map_ptr) != ptr {
57                    self.map.move_after_internal(map_ptr, ptr.unwrap());
58                }
59                self.ptr = Some(map_ptr);
60                Some(core::mem::replace(
61                    &mut map_ptr.data_mut(&mut self.map.nodes).value,
62                    value,
63                ))
64            }
65            Entry::Vacant(vacant_entry) => {
66                self.ptr = Some(vacant_entry.insert_after_internal(value, ptr).0);
67                None
68            }
69        }
70    }
71
72    /// Inserts a key-value pair before the cursor's current position and
73    /// moves the cursor to the inserted or updated entry.
74    pub fn insert_before_move_to(&mut self, key: K, value: T) -> Option<T> {
75        let ptr = if self.ptr.is_none() {
76            self.map.head_tail.as_ref().map(|ht| ht.head)
77        } else {
78            self.ptr
79        };
80
81        match self.map.entry(key) {
82            Entry::Occupied(occupied_entry) => {
83                let mut map_ptr = *occupied_entry.entry.get();
84                if Some(map_ptr) != ptr {
85                    self.map.move_before_internal(map_ptr, ptr.unwrap());
86                }
87                self.ptr = Some(map_ptr);
88                Some(core::mem::replace(
89                    &mut map_ptr.data_mut(&mut self.map.nodes).value,
90                    value,
91                ))
92            }
93            Entry::Vacant(vacant_entry) => {
94                self.ptr = Some(vacant_entry.insert_before_internal(value, ptr).0);
95                None
96            }
97        }
98    }
99
100    /// Returns the pointer to the entry with the given key.
101    ///
102    /// This is a convenience method that delegates to the underlying map's
103    /// `get_ptr` method.
104    ///
105    /// # Arguments
106    ///
107    /// * `key` - The key to search for
108    ///
109    /// # Returns
110    ///
111    /// * `Some(ptr)` if the key exists in the map
112    /// * `None` if the key is not found
113    pub fn get_ptr(&self, key: &K) -> Option<Ptr> {
114        self.map.get_ptr(key)
115    }
116}
117
118impl<'m, K: Hash + Eq, T, S: BuildHasher> CursorMut<'m, K, T, S> {
119    /// Removes the entry before the cursor's current position and returns it.
120    pub fn remove_prev(&mut self) -> Option<(Ptr, RemovedEntry<K, T>)> {
121        let prev = self.ptr.map(|slot| slot.prev(&self.map.nodes))?;
122        Some(self.map.remove_ptr_internal(prev))
123    }
124
125    /// Removes the entry after the cursor's current position and returns it.
126    pub fn remove_next(&mut self) -> Option<(Ptr, RemovedEntry<K, T>)> {
127        let next = self.ptr.map(|slot| slot.next(&self.map.nodes))?;
128        Some(self.map.remove_ptr_internal(next))
129    }
130
131    /// Removes the entry at the cursor's current position and returns it.
132    pub fn remove(self) -> Option<(Ptr, RemovedEntry<K, T>)> {
133        let ptr = self.ptr?;
134        Some(self.map.remove_ptr_internal(ptr))
135    }
136}
137
138impl<'m, K, T, S> CursorMut<'m, K, T, S> {
139    /// Returns an iterator starting from the cursor's current position.
140    pub fn iter(&self) -> Iter<'_, K, T> {
141        Iter {
142            forward_ptr: self.ptr,
143            reverse_ptr: self.ptr.map(|slot| slot.prev(&self.map.nodes)),
144            nodes: &self.map.nodes,
145        }
146    }
147
148    /// Moves the cursor to the next entry in the linked list. The internal
149    /// linked list is **circular**, so moving next from the tail wraps around
150    /// to the head.
151    pub fn move_next(&mut self) {
152        self.ptr = self.ptr.map(|slot| slot.next(&self.map.nodes));
153    }
154
155    /// Moves the cursor to the previous entry in the linked list. The internal
156    /// linked list is **circular**, so moving previous from the head wraps
157    /// around to the tail.
158    pub fn move_prev(&mut self) {
159        self.ptr = self.ptr.map(|slot| slot.prev(&self.map.nodes));
160    }
161
162    /// Gets the current pointer of the cursor.
163    pub fn ptr(&self) -> Option<Ptr> {
164        self.ptr.map(|slot| slot.this(&self.map.nodes))
165    }
166
167    /// Checks if the cursor is currently at the tail of the linked list.
168    pub fn at_tail(&self) -> bool {
169        self.ptr == self.map.head_tail.as_ref().map(|ht| ht.tail)
170    }
171
172    /// Checks if the cursor is currently at the head of the linked list.
173    pub fn at_head(&self) -> bool {
174        self.ptr == self.map.head_tail.as_ref().map(|ht| ht.head)
175    }
176
177    /// Returns the entry at the cursor's current position.
178    pub fn current(&self) -> Option<(&K, &T)> {
179        let ptr = self.ptr?;
180        let data = ptr.data(&self.map.nodes);
181        Some((&data.key, &data.value))
182    }
183
184    /// Returns a mutable reference to the key-value pair at the cursor's
185    /// current position.
186    ///
187    /// The key reference is immutable while the value reference is mutable,
188    /// allowing modification of the value while preserving the key's
189    /// integrity.
190    ///
191    /// # Returns
192    ///
193    /// * `Some((&K, &mut T))` if the cursor is positioned at a valid entry
194    /// * `None` if the cursor is positioned at a null entry
195    ///
196    /// # Examples
197    ///
198    /// ```
199    /// use tether_map::LinkedHashMap;
200    ///
201    /// let mut map = LinkedHashMap::new();
202    /// map.insert("key", 42);
203    ///
204    /// let mut cursor = map.head_cursor_mut();
205    /// if let Some((key, value)) = cursor.current_mut() {
206    ///     assert_eq!(key, &"key");
207    ///     *value = 100;
208    /// }
209    /// assert_eq!(map.get(&"key"), Some(&100));
210    /// ```
211    pub fn current_mut(&mut self) -> Option<(&K, &mut T)> {
212        let mut ptr = self.ptr?;
213        let data = ptr.data_mut(&mut self.map.nodes);
214        Some((&data.key, &mut data.value))
215    }
216
217    /// Returns the pointer to the next entry in the linked list from the
218    /// cursor's position.
219    ///
220    /// # Returns
221    ///
222    /// * `Some(next_ptr)` if there is a next entry
223    /// * `None` if the cursor is at the last entry or positioned at a null
224    ///   entry
225    ///
226    /// # Examples
227    ///
228    /// ```
229    /// use tether_map::LinkedHashMap;
230    ///
231    /// let mut map = LinkedHashMap::new();
232    /// map.insert_tail("a", 1);
233    /// map.insert_tail("b", 2);
234    ///
235    /// let cursor = map.head_cursor_mut();
236    /// if let Some(next_ptr) = cursor.next_ptr() {
237    ///     assert_eq!(map.ptr_get(next_ptr), Some(&2));
238    /// }
239    /// ```
240    pub fn next_ptr(&self) -> Option<Ptr> {
241        self.ptr
242            .map(|slot| slot.next(&self.map.nodes).this(&self.map.nodes))
243    }
244
245    /// Returns a reference to the key-value pair of the next entry in the
246    /// linked list.
247    ///
248    /// This is a convenience method that combines `next_ptr()` and accessing
249    /// the entry.
250    ///
251    /// # Returns
252    ///
253    /// * `Some((&K, &T))` if there is a next entry
254    /// * `None` if the cursor is at the last entry or positioned at a null
255    ///   entry
256    ///
257    /// # Examples
258    ///
259    /// ```
260    /// use tether_map::LinkedHashMap;
261    ///
262    /// let mut map = LinkedHashMap::new();
263    /// map.insert_tail("a", 1);
264    /// map.insert_tail("b", 2);
265    ///
266    /// let cursor = map.head_cursor_mut();
267    /// if let Some((key, value)) = cursor.next() {
268    ///     assert_eq!(key, &"b");
269    ///     assert_eq!(value, &2);
270    /// }
271    /// ```
272    pub fn next(&self) -> Option<(&K, &T)> {
273        let ptr = self.next_ptr()?;
274        self.map.ptr_get_entry(ptr)
275    }
276
277    /// Returns a mutable reference to the key-value pair of the next entry in
278    /// the linked list.
279    ///
280    /// This is a convenience method that combines `next_ptr()` and accessing
281    /// the entry mutably. The key reference is immutable while the value
282    /// reference is mutable.
283    ///
284    /// # Returns
285    ///
286    /// * `Some((&K, &mut T))` if there is a next entry
287    /// * `None` if the cursor is at the last entry or positioned at a null
288    ///   entry
289    ///
290    /// # Examples
291    ///
292    /// ```
293    /// use tether_map::LinkedHashMap;
294    ///
295    /// let mut map = LinkedHashMap::new();
296    /// map.insert_tail("a", 1);
297    /// map.insert_tail("b", 2);
298    ///
299    /// let mut cursor = map.head_cursor_mut();
300    /// if let Some((key, value)) = cursor.next_mut() {
301    ///     assert_eq!(key, &"b");
302    ///     *value = 20;
303    /// }
304    /// assert_eq!(map.get(&"b"), Some(&20));
305    /// ```
306    pub fn next_mut(&mut self) -> Option<(&K, &mut T)> {
307        let ptr = self.next_ptr()?;
308        self.map.ptr_get_entry_mut(ptr)
309    }
310
311    /// Returns the pointer to the previous entry in the linked list from the
312    /// cursor's position.
313    ///
314    /// # Returns
315    ///
316    /// * `Some(prev_ptr)` if there is a previous entry
317    /// * `None` if the cursor is at the first entry or positioned at a null
318    ///   entry
319    ///
320    /// # Examples
321    ///
322    /// ```
323    /// use tether_map::LinkedHashMap;
324    ///
325    /// let mut map = LinkedHashMap::new();
326    /// map.insert_tail("a", 1);
327    /// map.insert_tail("b", 2);
328    ///
329    /// let cursor = map.tail_cursor_mut();
330    /// if let Some(prev_ptr) = cursor.prev_ptr() {
331    ///     assert_eq!(map.ptr_get(prev_ptr), Some(&1));
332    /// }
333    /// ```
334    pub fn prev_ptr(&self) -> Option<Ptr> {
335        self.ptr
336            .map(|slot| slot.prev(&self.map.nodes).this(&self.map.nodes))
337    }
338
339    /// Returns a reference to the key-value pair of the previous entry in the
340    /// linked list.
341    ///
342    /// This is a convenience method that combines `prev_ptr()` and accessing
343    /// the entry.
344    ///
345    /// # Returns
346    ///
347    /// * `Some((&K, &T))` if there is a previous entry
348    /// * `None` if the cursor is at the first entry or positioned at a null
349    ///   entry
350    ///
351    /// # Examples
352    ///
353    /// ```
354    /// use tether_map::LinkedHashMap;
355    ///
356    /// let mut map = LinkedHashMap::new();
357    /// map.insert_tail("a", 1);
358    /// map.insert_tail("b", 2);
359    ///
360    /// let cursor = map.tail_cursor_mut();
361    /// if let Some((key, value)) = cursor.prev() {
362    ///     assert_eq!(key, &"a");
363    ///     assert_eq!(value, &1);
364    /// }
365    /// ```
366    pub fn prev(&self) -> Option<(&K, &T)> {
367        let ptr = self.prev_ptr()?;
368        self.map.ptr_get_entry(ptr)
369    }
370
371    /// Returns a mutable reference to the key-value pair of the previous entry
372    /// in the linked list.
373    ///
374    /// This is a convenience method that combines `prev_ptr()` and accessing
375    /// the entry mutably. The key reference is immutable while the value
376    /// reference is mutable.
377    ///
378    /// # Returns
379    ///
380    /// * `Some((&K, &mut T))` if there is a previous entry
381    /// * `None` if the cursor is at the first entry or positioned at a null
382    ///   entry
383    ///
384    /// # Examples
385    ///
386    /// ```
387    /// use tether_map::LinkedHashMap;
388    ///
389    /// let mut map = LinkedHashMap::new();
390    /// map.insert_tail("a", 1);
391    /// map.insert_tail("b", 2);
392    ///
393    /// let mut cursor = map.tail_cursor_mut();
394    /// if let Some((key, value)) = cursor.prev_mut() {
395    ///     assert_eq!(key, &"a");
396    ///     *value = 10;
397    /// }
398    /// assert_eq!(map.get(&"a"), Some(&10));
399    /// ```
400    pub fn prev_mut(&mut self) -> Option<(&K, &mut T)> {
401        let ptr = self.prev_ptr()?;
402        self.map.ptr_get_entry_mut(ptr)
403    }
404}