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