tether_map/linked_hash_map/entry.rs
1use core::hash::Hash;
2
3use hashbrown::hash_table;
4
5use crate::Ptr;
6use crate::arena::ActiveSlotRef;
7use crate::arena::Arena;
8use crate::arena::FreedSlot;
9use crate::linked_hash_map::HeadTail;
10
11/// A view into a single entry in a map, which may either be vacant or occupied.
12///
13/// This enum is constructed from the [`entry`] method on [`LinkedHashMap`].
14///
15/// [`entry`]: LinkedHashMap::entry
16///
17/// # Examples
18///
19/// ```
20/// use tether_map::Entry;
21/// use tether_map::LinkedHashMap;
22///
23/// let mut map = LinkedHashMap::new();
24///
25/// match map.entry("key") {
26/// Entry::Vacant(entry) => {
27/// entry.insert_tail("value");
28/// }
29/// Entry::Occupied(entry) => {
30/// println!("Key already exists: {}", entry.get());
31/// }
32/// }
33/// ```
34pub enum Entry<'a, K, V> {
35 /// An occupied entry.
36 Occupied(OccupiedEntry<'a, K, V>),
37
38 /// A vacant entry.
39 Vacant(VacantEntry<'a, K, V>),
40}
41
42impl<'a, K, V> Entry<'a, K, V>
43where
44 K: Hash + Eq,
45{
46 /// Ensures a value is in the entry by inserting the provided default if
47 /// vacant, and returns a mutable reference to the value in the entry.
48 ///
49 /// When inserting, the new entry is linked at the tail (end) of the list,
50 /// matching the behavior of `insert`/`insert_tail` for new keys.
51 pub fn or_insert(self, default: V) -> &'a mut V {
52 match self {
53 Entry::Occupied(e) => e.into_mut(),
54 Entry::Vacant(v) => v.insert_tail(default).1,
55 }
56 }
57
58 /// If the entry is occupied, applies the provided function to the value in
59 /// place. Returns the entry for further chaining.
60 pub fn and_modify<F>(self, f: F) -> Self
61 where
62 F: FnOnce(&mut V),
63 {
64 if let Entry::Occupied(mut e) = self {
65 f(e.get_mut());
66 Entry::Occupied(e)
67 } else {
68 self
69 }
70 }
71}
72
73/// A view into an occupied entry in a `LinkedHashMap`.
74///
75/// It is part of the [`Entry`] enum.
76///
77/// # Examples
78///
79/// ```
80/// use tether_map::Entry;
81/// use tether_map::LinkedHashMap;
82///
83/// let mut map = LinkedHashMap::new();
84/// map.insert("key", "value");
85///
86/// if let Entry::Occupied(entry) = map.entry("key") {
87/// println!("Found key: {}, value: {}", entry.key(), entry.get());
88/// }
89/// ```
90pub struct OccupiedEntry<'a, K, T> {
91 pub(crate) entry: hash_table::OccupiedEntry<'a, ActiveSlotRef<K, T>>,
92 pub(crate) head_tail: &'a mut Option<HeadTail<K, T>>,
93 pub(crate) arena: &'a mut Arena<K, T>,
94}
95
96impl<'a, K, T> OccupiedEntry<'a, K, T> {
97 /// Returns a reference to the value in the entry.
98 ///
99 /// # Examples
100 ///
101 /// ```
102 /// use tether_map::Entry;
103 /// use tether_map::LinkedHashMap;
104 ///
105 /// let mut map = LinkedHashMap::new();
106 /// map.insert("key", 42);
107 ///
108 /// match map.entry("key") {
109 /// Entry::Occupied(entry) => {
110 /// assert_eq!(entry.get(), &42);
111 /// }
112 /// Entry::Vacant(_) => unreachable!(),
113 /// }
114 /// ```
115 pub fn get(&self) -> &T {
116 &self.entry.get().data(self.arena).value
117 }
118
119 /// Returns a mutable reference to the value in the entry.
120 ///
121 /// # Examples
122 ///
123 /// ```
124 /// use tether_map::Entry;
125 /// use tether_map::LinkedHashMap;
126 ///
127 /// let mut map = LinkedHashMap::new();
128 /// map.insert("key", 42);
129 ///
130 /// match map.entry("key") {
131 /// Entry::Occupied(mut entry) => {
132 /// *entry.get_mut() = 100;
133 /// }
134 /// Entry::Vacant(_) => unreachable!(),
135 /// }
136 /// assert_eq!(map.get(&"key"), Some(&100));
137 /// ```
138 pub fn get_mut(&mut self) -> &mut T {
139 &mut self.entry.get_mut().data_mut(self.arena).value
140 }
141
142 /// Consumes the occupied entry and returns a mutable reference to the
143 /// value.
144 ///
145 /// The returned reference is tied to the lifetime of the original map
146 /// borrow.
147 pub fn into_mut(self) -> &'a mut T {
148 let OccupiedEntry { entry, .. } = self;
149 &mut entry.into_mut().data_mut(self.arena).value
150 }
151
152 /// Replaces the entry's value and returns the old value without moving the
153 /// entry's position.
154 ///
155 /// Unlike `insert()`, this method does not affect the entry's position in
156 /// the linked list.
157 ///
158 /// # Arguments
159 ///
160 /// * `value` - The new value to insert
161 ///
162 /// # Returns
163 ///
164 /// The previous value that was replaced
165 ///
166 /// # Examples
167 ///
168 /// ```
169 /// use tether_map::Entry;
170 /// use tether_map::LinkedHashMap;
171 ///
172 /// let mut map = LinkedHashMap::new();
173 /// map.insert("a", 1);
174 /// map.insert("b", 2);
175 ///
176 /// match map.entry("a") {
177 /// Entry::Occupied(entry) => {
178 /// let old = entry.insert_no_move(10);
179 /// assert_eq!(old, 1);
180 /// }
181 /// Entry::Vacant(_) => unreachable!(),
182 /// }
183 ///
184 /// // Order remains: a, b ("a" was not moved)
185 /// let entries: Vec<_> = map.iter().collect();
186 /// assert_eq!(entries, [(&"a", &10), (&"b", &2)]);
187 /// ```
188 pub fn insert_no_move(mut self, value: T) -> T {
189 core::mem::replace(&mut self.entry.get_mut().data_mut(self.arena).value, value)
190 }
191
192 /// Returns the pointer to this entry.
193 ///
194 /// The pointer can be used for direct access operations or cursor
195 /// positioning.
196 ///
197 /// # Returns
198 ///
199 /// The pointer to the entry
200 ///
201 /// # Examples
202 ///
203 /// ```
204 /// use tether_map::Entry;
205 /// use tether_map::LinkedHashMap;
206 ///
207 /// let mut map = LinkedHashMap::new();
208 /// map.insert("key", 42);
209 ///
210 /// match map.entry("key") {
211 /// Entry::Occupied(entry) => {
212 /// let ptr = entry.ptr();
213 /// assert_eq!(map.ptr_get(ptr), Some(&42));
214 /// }
215 /// Entry::Vacant(_) => unreachable!(),
216 /// }
217 /// ```
218 pub fn ptr(&self) -> Ptr {
219 self.entry.get().this(self.arena)
220 }
221
222 /// Returns a reference to the key in the entry.
223 ///
224 /// # Examples
225 ///
226 /// ```
227 /// use tether_map::Entry;
228 /// use tether_map::LinkedHashMap;
229 ///
230 /// let mut map = LinkedHashMap::new();
231 /// map.insert("key", 42);
232 ///
233 /// match map.entry("key") {
234 /// Entry::Occupied(entry) => {
235 /// assert_eq!(entry.key(), &"key");
236 /// }
237 /// Entry::Vacant(_) => unreachable!(),
238 /// }
239 /// ```
240 pub fn key(&self) -> &K {
241 &self.entry.get().data(self.arena).key
242 }
243
244 /// Replaces the entry's value and returns the old value.
245 ///
246 /// This is equivalent to `insert_no_move()` and does not move the entry's
247 /// position.
248 ///
249 /// # Arguments
250 ///
251 /// * `value` - The new value to insert
252 ///
253 /// # Returns
254 ///
255 /// The previous value that was replaced
256 ///
257 /// # Examples
258 ///
259 /// ```
260 /// use tether_map::Entry;
261 /// use tether_map::LinkedHashMap;
262 ///
263 /// let mut map = LinkedHashMap::new();
264 /// map.insert("key", 42);
265 ///
266 /// match map.entry("key") {
267 /// Entry::Occupied(entry) => {
268 /// let old = entry.insert(100);
269 /// assert_eq!(old, 42);
270 /// }
271 /// Entry::Vacant(_) => unreachable!(),
272 /// }
273 /// assert_eq!(map.get(&"key"), Some(&100));
274 /// ```
275 pub fn insert(self, value: T) -> T {
276 self.insert_no_move(value)
277 }
278
279 /// Removes the entry from the map and returns the key-value pair.
280 ///
281 /// This consumes the occupied entry and requires that both the key and
282 /// value types implement `Default` for safe removal from the underlying
283 /// storage.
284 ///
285 /// # Returns
286 ///
287 /// A tuple containing the key and value that were removed
288 ///
289 /// # Examples
290 ///
291 /// ```
292 /// use tether_map::Entry;
293 /// use tether_map::LinkedHashMap;
294 ///
295 /// let mut map = LinkedHashMap::new();
296 /// map.insert("key", 42);
297 ///
298 /// match map.entry("key") {
299 /// Entry::Occupied(entry) => {
300 /// let (key, value) = entry.remove_entry();
301 /// assert_eq!(key, "key");
302 /// assert_eq!(value, 42);
303 /// }
304 /// Entry::Vacant(_) => unreachable!(),
305 /// }
306 /// assert_eq!(map.len(), 0);
307 /// ```
308 pub fn remove_entry(self) -> (K, T) {
309 let entry = self.entry.remove().0;
310 // SAFETY: We just removed `entry` from the hash table, and we don't deref it
311 // after this.
312 let FreedSlot {
313 data, prev_next, ..
314 } = unsafe { self.arena.free_and_unlink(entry) };
315
316 if let Some((prev, next)) = prev_next {
317 if let Some(head_tail) = self.head_tail {
318 if head_tail.head == entry {
319 head_tail.head = next;
320 }
321 if head_tail.tail == entry {
322 head_tail.tail = prev;
323 }
324 }
325 } else if self
326 .head_tail
327 .as_ref()
328 .is_some_and(|ht| ht.head == entry || ht.tail == entry)
329 {
330 *self.head_tail = None;
331 }
332
333 (data.key, data.value)
334 }
335
336 /// Removes the entry from the map and returns the value.
337 ///
338 /// This consumes the occupied entry and requires that both the key and
339 /// value types implement `Default` for safe removal from the underlying
340 /// storage.
341 ///
342 /// # Returns
343 ///
344 /// The value that was removed
345 ///
346 /// # Examples
347 ///
348 /// ```
349 /// use tether_map::Entry;
350 /// use tether_map::LinkedHashMap;
351 ///
352 /// let mut map = LinkedHashMap::new();
353 /// map.insert("key", 42);
354 ///
355 /// match map.entry("key") {
356 /// Entry::Occupied(entry) => {
357 /// let value = entry.remove();
358 /// assert_eq!(value, 42);
359 /// }
360 /// Entry::Vacant(_) => unreachable!(),
361 /// }
362 /// assert_eq!(map.len(), 0);
363 /// ```
364 pub fn remove(self) -> T {
365 self.remove_entry().1
366 }
367}
368
369/// A view into a vacant entry in a `LinkedHashMap`.
370///
371/// It is part of the [`Entry`] enum.
372///
373/// # Examples
374///
375/// ```
376/// use tether_map::Entry;
377/// use tether_map::LinkedHashMap;
378///
379/// let mut map = LinkedHashMap::new();
380///
381/// if let Entry::Vacant(entry) = map.entry("key") {
382/// entry.insert_tail("value");
383/// }
384/// assert_eq!(map.get(&"key"), Some(&"value"));
385/// ```
386pub struct VacantEntry<'a, K, T> {
387 pub(crate) key: K,
388 pub(crate) entry: hash_table::VacantEntry<'a, ActiveSlotRef<K, T>>,
389 pub(crate) nodes: &'a mut Arena<K, T>,
390 pub(crate) head_tail: &'a mut Option<HeadTail<K, T>>,
391}
392
393impl<'a, K: Hash + Eq, T> VacantEntry<'a, K, T> {
394 /// Inserts a new entry at the tail (end) of the linked list.
395 ///
396 /// # Arguments
397 ///
398 /// * `value` - The value to insert
399 ///
400 /// # Returns
401 ///
402 /// The pointer to the newly inserted entry
403 ///
404 /// # Examples
405 ///
406 /// ```
407 /// use tether_map::Entry;
408 /// use tether_map::LinkedHashMap;
409 ///
410 /// let mut map = LinkedHashMap::new();
411 ///
412 /// match map.entry("new_key") {
413 /// Entry::Vacant(entry) => {
414 /// let value = entry.insert_tail(42).1;
415 /// assert_eq!(*value, 42);
416 /// }
417 /// Entry::Occupied(_) => unreachable!(),
418 /// }
419 /// ```
420 pub fn insert_tail(self, value: T) -> (Ptr, &'a mut T) {
421 let after = self.head_tail.as_ref().map(|ht| ht.tail);
422 let (_, ptr, data) = self.insert_after_internal(value, after);
423 (ptr, data)
424 }
425
426 /// Inserts a new entry without linking it to the doubly-linked list.
427 ///
428 /// This is a low-level method that creates an entry in the hash table but
429 /// does not link it into the ordered list. The entry will exist in the
430 /// map but won't appear in iteration order until it's properly linked. It
431 /// can still be accessed either by the returned pointer or by its key.
432 ///
433 /// # Arguments
434 ///
435 /// * `value` - The value to insert
436 ///
437 /// # Returns
438 ///
439 /// The pointer to the newly created but unlinked entry
440 ///
441 /// # Note
442 ///
443 /// This method is primarily for advanced usage. Most users should use
444 /// `insert_tail()`, `insert_head()`, or similar methods instead. This is
445 /// most useful when you have an entry and want to store data in the map,
446 /// but also need to operate on the linked list structure separately without
447 /// including the new entry in the list yet. In that case, you can create
448 /// the entry with `push_unlinked()` and then later link it in using
449 /// methods like `link_as_head()`, or `link_as_tail()`.
450 pub fn insert_unlinked(self, value: T) -> (Ptr, &'a mut T) {
451 let mut ptr = self.nodes.alloc_circular(self.key, value);
452 self.entry.insert(ptr);
453 (ptr.this(self.nodes), &mut ptr.data_mut(self.nodes).value)
454 }
455
456 /// Inserts a new entry immediately after the specified entry.
457 ///
458 /// # Arguments
459 ///
460 /// * `value` - The value to insert
461 /// * `after` - The pointer to the entry after which to insert
462 ///
463 /// # Returns
464 ///
465 /// The pointer to the newly inserted entry
466 ///
467 /// # Examples
468 ///
469 /// ```
470 /// use tether_map::Entry;
471 /// use tether_map::LinkedHashMap;
472 ///
473 /// let mut map = LinkedHashMap::new();
474 /// let (ptr1, _) = map.insert_tail_full("first", 1);
475 /// map.insert_tail("third", 3);
476 ///
477 /// match map.entry("second") {
478 /// Entry::Vacant(entry) => {
479 /// entry.insert_after(2, ptr1);
480 /// }
481 /// Entry::Occupied(_) => unreachable!(),
482 /// }
483 ///
484 /// // Order is now: first, second, third
485 /// let entries: Vec<_> = map.iter().collect();
486 /// assert_eq!(entries, [(&"first", &1), (&"second", &2), (&"third", &3)]);
487 /// ```
488 pub fn insert_after(self, value: T, after: Ptr) -> (Ptr, &'a mut T) {
489 let after = self
490 .nodes
491 .map_ptr(after)
492 .or(self.head_tail.as_ref().map(|ht| ht.tail));
493
494 let (_, ptr, data) = self.insert_after_internal(value, after);
495 (ptr, data)
496 }
497
498 pub(crate) fn insert_after_internal(
499 self,
500 value: T,
501 after: Option<ActiveSlotRef<K, T>>,
502 ) -> (ActiveSlotRef<K, T>, Ptr, &'a mut T) {
503 if let Some(mut after) = after {
504 let mut after_next = after.next(self.nodes);
505 let mut ptr = self.nodes.alloc(self.key, value, after, after_next);
506
507 *after.next_mut(self.nodes) = ptr;
508 *after_next.prev_mut(self.nodes) = ptr;
509 self.entry.insert(ptr);
510
511 if let Some(head_tail) = self.head_tail.as_mut()
512 && head_tail.tail == after
513 {
514 head_tail.tail = ptr;
515 }
516
517 (
518 ptr,
519 ptr.this(self.nodes),
520 &mut ptr.data_mut(self.nodes).value,
521 )
522 } else {
523 debug_assert_eq!(*self.head_tail, None);
524 let mut ptr = self.nodes.alloc_circular(self.key, value);
525
526 *self.head_tail = Some(HeadTail {
527 head: ptr,
528 tail: ptr,
529 });
530 self.entry.insert(ptr);
531 (
532 ptr,
533 ptr.this(self.nodes),
534 &mut ptr.data_mut(self.nodes).value,
535 )
536 }
537 }
538
539 /// Inserts a new entry at the head (beginning) of the linked list.
540 ///
541 /// # Arguments
542 ///
543 /// * `value` - The value to insert
544 ///
545 /// # Returns
546 ///
547 /// The pointer to the newly inserted entry
548 ///
549 /// # Examples
550 ///
551 /// ```
552 /// use tether_map::Entry;
553 /// use tether_map::LinkedHashMap;
554 ///
555 /// let mut map = LinkedHashMap::new();
556 /// map.insert_tail("second", 2);
557 ///
558 /// match map.entry("first") {
559 /// Entry::Vacant(entry) => {
560 /// let ptr = entry.insert_head(1).0;
561 /// assert_eq!(map.ptr_get(ptr), Some(&1));
562 /// }
563 /// Entry::Occupied(_) => unreachable!(),
564 /// }
565 ///
566 /// // Order is now: first, second
567 /// let entries: Vec<_> = map.iter().collect();
568 /// assert_eq!(entries, [(&"first", &1), (&"second", &2)]);
569 /// ```
570 pub fn insert_head(self, value: T) -> (Ptr, &'a mut T) {
571 let ptr = self.head_tail.as_ref().map(|ht| ht.head);
572 let (_, ptr, data) = self.insert_before_internal(value, ptr);
573 (ptr, data)
574 }
575
576 /// Inserts a new entry immediately before the specified entry.
577 ///
578 /// # Arguments
579 ///
580 /// * `value` - The value to insert
581 /// * `before` - The pointer to the entry before which to insert
582 ///
583 /// # Returns
584 ///
585 /// The pointer to the newly inserted entry
586 ///
587 /// # Examples
588 ///
589 /// ```
590 /// use tether_map::Entry;
591 /// use tether_map::LinkedHashMap;
592 ///
593 /// let mut map = LinkedHashMap::new();
594 /// map.insert_tail("first", 1);
595 /// let (ptr3, _) = map.insert_tail_full("third", 3);
596 ///
597 /// match map.entry("second") {
598 /// Entry::Vacant(entry) => {
599 /// entry.insert_before(2, ptr3);
600 /// }
601 /// Entry::Occupied(_) => unreachable!(),
602 /// }
603 ///
604 /// // Order is now: first, second, third
605 /// let entries: Vec<_> = map.iter().collect();
606 /// assert_eq!(entries, [(&"first", &1), (&"second", &2), (&"third", &3)]);
607 /// ```
608 pub fn insert_before(self, value: T, before: Ptr) -> (Ptr, &'a mut T) {
609 let before = self
610 .nodes
611 .map_ptr(before)
612 .or(self.head_tail.as_ref().map(|ht| ht.head));
613
614 let (_, ptr, data) = self.insert_before_internal(value, before);
615 (ptr, data)
616 }
617
618 /// # Safety
619 ///
620 /// `before` must be either null or a valid pointer into self.nodes.
621 pub(crate) fn insert_before_internal(
622 self,
623 value: T,
624 before: Option<ActiveSlotRef<K, T>>,
625 ) -> (ActiveSlotRef<K, T>, Ptr, &'a mut T) {
626 if let Some(mut before) = before {
627 let mut before_prev = before.prev(self.nodes);
628 let mut ptr = self.nodes.alloc(self.key, value, before_prev, before);
629
630 *before.prev_mut(self.nodes) = ptr;
631 *before_prev.next_mut(self.nodes) = ptr;
632 self.entry.insert(ptr);
633
634 if let Some(head_tail) = self.head_tail.as_mut()
635 && head_tail.head == before
636 {
637 head_tail.head = ptr;
638 }
639
640 (
641 ptr,
642 ptr.this(self.nodes),
643 &mut ptr.data_mut(self.nodes).value,
644 )
645 } else {
646 debug_assert_eq!(*self.head_tail, None);
647 let mut ptr = self.nodes.alloc_circular(self.key, value);
648
649 *self.head_tail = Some(HeadTail {
650 head: ptr,
651 tail: ptr,
652 });
653 self.entry.insert(ptr);
654 (
655 ptr,
656 ptr.this(self.nodes),
657 &mut ptr.data_mut(self.nodes).value,
658 )
659 }
660 }
661
662 /// Consumes this vacant entry and returns the key.
663 ///
664 /// This method allows you to retrieve the key without inserting a value,
665 /// which can be useful when the insertion is conditional.
666 ///
667 /// # Returns
668 ///
669 /// The key that would have been inserted
670 ///
671 /// # Examples
672 ///
673 /// ```
674 /// use tether_map::Entry;
675 /// use tether_map::LinkedHashMap;
676 ///
677 /// let mut map: LinkedHashMap<&str, i32> = LinkedHashMap::new();
678 ///
679 /// match map.entry("key") {
680 /// Entry::Vacant(entry) => {
681 /// let key = entry.into_key();
682 /// assert_eq!(key, "key");
683 /// // Entry was not inserted
684 /// }
685 /// Entry::Occupied(_) => unreachable!(),
686 /// }
687 /// assert_eq!(map.len(), 0);
688 /// ```
689 pub fn into_key(self) -> K {
690 self.key
691 }
692
693 /// Returns a reference to the key that would be inserted.
694 ///
695 /// # Examples
696 ///
697 /// ```
698 /// use tether_map::Entry;
699 /// use tether_map::LinkedHashMap;
700 ///
701 /// let mut map = LinkedHashMap::new();
702 ///
703 /// match map.entry("key") {
704 /// Entry::Vacant(entry) => {
705 /// assert_eq!(entry.key(), &"key");
706 /// entry.insert_tail(42);
707 /// }
708 /// Entry::Occupied(_) => unreachable!(),
709 /// }
710 /// ```
711 pub fn key(&self) -> &K {
712 &self.key
713 }
714}