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}