Skip to main content

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}