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}